diff --git a/AUTHORS b/AUTHORS
index 7cb43b9..30c9988 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -584,6 +584,7 @@
 Li Yin <li.yin@intel.com>
 Lidwine Genevet <lgenevet@cisco.com>
 Lin Sun <lin.sun@intel.com>
+Lingqi Chi <someway.bit@gmail.com>
 Lingyun Cai <lingyun.cai@intel.com>
 Lionel Landwerlin <lionel.g.landwerlin@intel.com>
 Lizhi Fan <lizhi.fan@samsung.com>
diff --git a/DEPS b/DEPS
index 153d72ea..d372052 100644
--- a/DEPS
+++ b/DEPS
@@ -175,11 +175,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': 'afbf2aa737c8f0b48dfa28c88c51f56a46d32843',
+  'skia_revision': '852ebea2d55dc3f41992ba25cb2f25fdff11875b',
   # 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': '1f44ca7be02a46d01e0958142c3b4f11e08a2a69',
+  'v8_revision': '6ae4715e52340389b57cad8b761f31c191e189ec',
   # 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.
@@ -187,15 +187,15 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '84323449dfafc97e5b18dcfa6c91602faf7920d6',
+  'angle_revision': 'd14735b25df3359bcc895673307d93ca97cb3df0',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': 'bdb6807825ac8479b9dc3fe5fdc58caae294f21b',
+  'swiftshader_revision': 'b4a27407e2be535f44b960929e7c4e6c0532f862',
   # 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': '5540fdbe74510620b27fc3cc29a720e766584189',
+  'pdfium_revision': '55cc5f2199b1f074c36019a7dd7e70223994eb30',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -238,7 +238,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': 'eda150cb220866746a5d3dbd6ea7ce1186a6e264',
+  'catapult_revision': 'bc1001ace1ff6b701688b30823a079e07a164a1d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -246,7 +246,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': '029854ebc99733c84af62356e4d5e408f8ebd127',
+  'devtools_frontend_revision': 'e29095b1961e7b087b8d3f60a45e855f7c991641',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -286,7 +286,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'spv_tools_revision': 'e95fbfb1f509ad7a7fdfb72ac35fe412d72fc4a4',
+  'spv_tools_revision': '4af38c49bfeeac536b9bf9b25be2d4bbec356972',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -302,7 +302,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': 'f526d777e0b378392c0666f4c414072cf64c1007',
+  'dawn_revision': 'c3c6694d8f0f57f1df49ffd4a63d7083b1d81c85',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -867,7 +867,7 @@
 
   # For Linux and Chromium OS.
   'src/third_party/cros_system_api': {
-      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '2e5dab7c2630fe3be32711bdd0b42aca5015b517',
+      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '9c6bf7207bfe1e3e07ee6d42846a0fe20cb55b10',
       'condition': 'checkout_linux',
   },
 
@@ -1306,7 +1306,7 @@
       'packages': [
           {
               'package': 'fuchsia/third_party/aemu/linux-amd64',
-              'version': 'lSCFQ4UGjipxIuu1PuSjqToisv4f2egofcYsRJ4_5wsC'
+              'version': 'PanIUxGAhJjJ7ZNere-l6Bgp8nRJbkRFU-2ZV-nU8BwC'
           },
       ],
       'condition': 'host_os == "linux" and checkout_fuchsia',
@@ -1533,7 +1533,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@3549e2d6063ca84322e1ab969baa637714b955c7',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@e89877724abaec4aae785c44fe3e1f082e956484',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/base/BUILD.gn b/base/BUILD.gn
index c2245a9e..e868138a 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -2493,6 +2493,7 @@
     "callback_list_unittest.cc",
     "callback_unittest.cc",
     "cancelable_callback_unittest.cc",
+    "check_unittest.cc",
     "command_line_unittest.cc",
     "component_export_unittest.cc",
     "containers/adapters_unittest.cc",
diff --git a/base/check_unittest.cc b/base/check_unittest.cc
new file mode 100644
index 0000000..b613b9a
--- /dev/null
+++ b/base/check_unittest.cc
@@ -0,0 +1,385 @@
+// Copyright (c) 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/strings/string_piece.h"
+#include "build/build_config.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Helper class which expects a check to fire with a certain location and
+// message before the end of the current scope.
+class ScopedCheckExpectation {
+ public:
+  ScopedCheckExpectation(const char* file, int line, std::string msg)
+      : file_(file),
+        line_(line),
+        msg_(msg),
+        assert_handler_(base::BindRepeating(&ScopedCheckExpectation::Check,
+                                            base::Unretained(this))),
+        fired_(false) {}
+  ~ScopedCheckExpectation() {
+    EXPECT_TRUE(fired_) << "CHECK at " << file_ << ":" << line_
+                        << " never fired!";
+  }
+
+ private:
+  void Check(const char* file,
+             int line,
+             const base::StringPiece msg,
+             const base::StringPiece stack) {
+    fired_ = true;
+    EXPECT_EQ(file, file_);
+    EXPECT_EQ(line, line_);
+    if (msg_.find("=~") == 0) {
+      EXPECT_THAT(std::string(msg), testing::MatchesRegex(msg_.substr(2)));
+    } else {
+      EXPECT_EQ(std::string(msg), msg_);
+    }
+  }
+
+  std::string file_;
+  int line_;
+  std::string msg_;
+  logging::ScopedLogAssertHandler assert_handler_;
+  bool fired_;
+};
+
+// Macro which expects a CHECK to fire with a certain message. If msg starts
+// with "=~", it's interpreted as a regular expression.
+// Example: EXPECT_CHECK("Check failed: false.", CHECK(false));
+#if defined(OFFICIAL_BUILD) && defined(NDEBUG)
+#define EXPECT_CHECK(msg, check_expr) \
+  do {                                \
+    EXPECT_DEATH(check_expr, "");     \
+  } while (0)
+#else
+#define EXPECT_CHECK(msg, check_expr)                          \
+  do {                                                         \
+    ScopedCheckExpectation check_exp(__FILE__, __LINE__, msg); \
+    check_expr;                                                \
+  } while (0)
+#endif
+
+// Macro which expects a DCHECK to fire if DCHECKs are enabled.
+#define EXPECT_DCHECK(msg, check_expr)                                 \
+  do {                                                                 \
+    if (DCHECK_IS_ON() && logging::LOG_DCHECK == logging::LOG_FATAL) { \
+      ScopedCheckExpectation check_exp(__FILE__, __LINE__, msg);       \
+      check_expr;                                                      \
+    } else {                                                           \
+      check_expr;                                                      \
+    }                                                                  \
+  } while (0)
+
+class CheckTest : public testing::Test {};
+
+TEST_F(CheckTest, Basics) {
+  EXPECT_CHECK("Check failed: false. ", CHECK(false));
+
+  EXPECT_CHECK("Check failed: false. foo", CHECK(false) << "foo");
+
+  double a = 2, b = 1;
+  EXPECT_CHECK("Check failed: a < b (2 vs. 1)", CHECK_LT(a, b));
+
+  EXPECT_CHECK("Check failed: a < b (2 vs. 1)foo", CHECK_LT(a, b) << "foo");
+}
+
+TEST_F(CheckTest, PCheck) {
+  const char file[] = "/nonexistentfile123";
+  ignore_result(fopen(file, "r"));
+  std::string err =
+      logging::SystemErrorCodeToString(logging::GetLastSystemErrorCode());
+
+  EXPECT_CHECK(
+      "Check failed: fopen(file, \"r\") != nullptr."
+      " : " +
+          err,
+      PCHECK(fopen(file, "r") != nullptr));
+
+  EXPECT_CHECK(
+      "Check failed: fopen(file, \"r\") != nullptr."
+      " foo: " +
+          err,
+      PCHECK(fopen(file, "r") != nullptr) << "foo");
+
+  EXPECT_DCHECK(
+      "Check failed: fopen(file, \"r\") != nullptr."
+      " : " +
+          err,
+      DPCHECK(fopen(file, "r") != nullptr));
+
+  EXPECT_DCHECK(
+      "Check failed: fopen(file, \"r\") != nullptr."
+      " foo: " +
+          err,
+      DPCHECK(fopen(file, "r") != nullptr) << "foo");
+}
+
+TEST_F(CheckTest, CheckOp) {
+  int a = 1, b = 2;
+  // clang-format off
+  EXPECT_CHECK("Check failed: a == b (1 vs. 2)", CHECK_EQ(a, b));
+  EXPECT_CHECK("Check failed: a != a (1 vs. 1)", CHECK_NE(a, a));
+  EXPECT_CHECK("Check failed: b <= a (2 vs. 1)", CHECK_LE(b, a));
+  EXPECT_CHECK("Check failed: b < a (2 vs. 1)",  CHECK_LT(b, a));
+  EXPECT_CHECK("Check failed: a >= b (1 vs. 2)", CHECK_GE(a, b));
+  EXPECT_CHECK("Check failed: a > b (1 vs. 2)",  CHECK_GT(a, b));
+
+  EXPECT_DCHECK("Check failed: a == b (1 vs. 2)", DCHECK_EQ(a, b));
+  EXPECT_DCHECK("Check failed: a != a (1 vs. 1)", DCHECK_NE(a, a));
+  EXPECT_DCHECK("Check failed: b <= a (2 vs. 1)", DCHECK_LE(b, a));
+  EXPECT_DCHECK("Check failed: b < a (2 vs. 1)",  DCHECK_LT(b, a));
+  EXPECT_DCHECK("Check failed: a >= b (1 vs. 2)", DCHECK_GE(a, b));
+  EXPECT_DCHECK("Check failed: a > b (1 vs. 2)",  DCHECK_GT(a, b));
+  // clang-format on
+}
+
+TEST_F(CheckTest, CheckStreamsAreLazy) {
+  int called_count = 0;
+  int not_called_count = 0;
+
+  auto Called = [&]() {
+    ++called_count;
+    return 42;
+  };
+  auto NotCalled = [&]() {
+    ++not_called_count;
+    return 42;
+  };
+
+  CHECK(Called()) << NotCalled();
+  CHECK_EQ(Called(), Called()) << NotCalled();
+  PCHECK(Called()) << NotCalled();
+
+  DCHECK(Called()) << NotCalled();
+  DCHECK_EQ(Called(), Called()) << NotCalled();
+  DPCHECK(Called()) << NotCalled();
+
+  EXPECT_EQ(not_called_count, 0);
+#if DCHECK_IS_ON()
+  EXPECT_EQ(called_count, 8);
+#else
+  EXPECT_EQ(called_count, 4);
+#endif
+}
+
+void DcheckEmptyFunction1() {
+  // Provide a body so that Release builds do not cause the compiler to
+  // optimize DcheckEmptyFunction1 and DcheckEmptyFunction2 as a single
+  // function, which breaks the Dcheck tests below.
+  LOG(INFO) << "DcheckEmptyFunction1";
+}
+void DcheckEmptyFunction2() {}
+
+#if defined(DCHECK_IS_CONFIGURABLE)
+class ScopedDcheckSeverity {
+ public:
+  ScopedDcheckSeverity(LogSeverity new_severity) : old_severity_(LOG_DCHECK) {
+    LOG_DCHECK = new_severity;
+  }
+
+  ~ScopedDcheckSeverity() { LOG_DCHECK = old_severity_; }
+
+ private:
+  LogSeverity old_severity_;
+};
+#endif  // defined(DCHECK_IS_CONFIGURABLE)
+
+// https://crbug.com/709067 tracks test flakiness on iOS.
+#if defined(OS_IOS)
+#define MAYBE_Dcheck DISABLED_Dcheck
+#else
+#define MAYBE_Dcheck Dcheck
+#endif
+TEST_F(CheckTest, MAYBE_Dcheck) {
+#if defined(DCHECK_IS_CONFIGURABLE)
+  // DCHECKs are enabled, and LOG_DCHECK is mutable, but defaults to non-fatal.
+  // Set it to LOG_FATAL to get the expected behavior from the rest of this
+  // test.
+  ScopedDcheckSeverity dcheck_severity(LOG_FATAL);
+#endif  // defined(DCHECK_IS_CONFIGURABLE)
+
+#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+  // Release build.
+  EXPECT_FALSE(DCHECK_IS_ON());
+  EXPECT_FALSE(DLOG_IS_ON(DCHECK));
+#elif defined(NDEBUG) && defined(DCHECK_ALWAYS_ON)
+  // Release build with real DCHECKS.
+  EXPECT_TRUE(DCHECK_IS_ON());
+  EXPECT_TRUE(DLOG_IS_ON(DCHECK));
+#else
+  // Debug build.
+  EXPECT_TRUE(DCHECK_IS_ON());
+  EXPECT_TRUE(DLOG_IS_ON(DCHECK));
+#endif
+
+  EXPECT_DCHECK("Check failed: false. ", DCHECK(false));
+  std::string err =
+      logging::SystemErrorCodeToString(logging::GetLastSystemErrorCode());
+  EXPECT_DCHECK("Check failed: false. : " + err, DPCHECK(false));
+  EXPECT_DCHECK("Check failed: 0 == 1 (0 vs. 1)", DCHECK_EQ(0, 1));
+
+  // Test DCHECK on std::nullptr_t
+  const void* p_null = nullptr;
+  const void* p_not_null = &p_null;
+  DCHECK_EQ(p_null, nullptr);
+  DCHECK_EQ(nullptr, p_null);
+  DCHECK_NE(p_not_null, nullptr);
+  DCHECK_NE(nullptr, p_not_null);
+
+  // Test DCHECK on a scoped enum.
+  enum class Animal { DOG, CAT };
+  DCHECK_EQ(Animal::DOG, Animal::DOG);
+  EXPECT_DCHECK("Check failed: Animal::DOG == Animal::CAT (0 vs. 1)",
+                DCHECK_EQ(Animal::DOG, Animal::CAT));
+
+  // Test DCHECK on functions and function pointers.
+  struct MemberFunctions {
+    void MemberFunction1() {
+      // See the comment in DcheckEmptyFunction1().
+      LOG(INFO) << "Do not merge with MemberFunction2.";
+    }
+    void MemberFunction2() {}
+  };
+  void (MemberFunctions::*mp1)() = &MemberFunctions::MemberFunction1;
+  void (MemberFunctions::*mp2)() = &MemberFunctions::MemberFunction2;
+  void (*fp1)() = DcheckEmptyFunction1;
+  void (*fp2)() = DcheckEmptyFunction2;
+  void (*fp3)() = DcheckEmptyFunction1;
+  DCHECK_EQ(fp1, fp3);
+  DCHECK_EQ(mp1, &MemberFunctions::MemberFunction1);
+  DCHECK_EQ(mp2, &MemberFunctions::MemberFunction2);
+  EXPECT_DCHECK("=~Check failed: fp1 == fp2 \\(\\w+ vs. \\w+\\)",
+                DCHECK_EQ(fp1, fp2));
+  EXPECT_DCHECK(
+      "Check failed: mp2 == &MemberFunctions::MemberFunction1 (1 vs. 1)",
+      DCHECK_EQ(mp2, &MemberFunctions::MemberFunction1));
+}
+
+TEST_F(CheckTest, DcheckReleaseBehavior) {
+  int var1 = 1;
+  int var2 = 2;
+  int var3 = 3;
+  int var4 = 4;
+
+  // No warnings about unused variables even though no check fires and DCHECK
+  // may or may not be enabled.
+  DCHECK(var1) << var2;
+  DPCHECK(var1) << var3;
+  DCHECK_EQ(var1, 1) << var4;
+}
+
+TEST_F(CheckTest, DCheckEqStatements) {
+  bool reached = false;
+  if (false)
+    DCHECK_EQ(false, true);  // Unreached.
+  else
+    DCHECK_EQ(true, reached = true);  // Reached, passed.
+  ASSERT_EQ(DCHECK_IS_ON() ? true : false, reached);
+
+  if (false)
+    DCHECK_EQ(false, true);  // Unreached.
+}
+
+TEST_F(CheckTest, CheckEqStatements) {
+  bool reached = false;
+  if (false)
+    CHECK_EQ(false, true);  // Unreached.
+  else
+    CHECK_EQ(true, reached = true);  // Reached, passed.
+  ASSERT_TRUE(reached);
+
+  if (false)
+    CHECK_EQ(false, true);  // Unreached.
+}
+
+#if defined(DCHECK_IS_CONFIGURABLE)
+TEST_F(CheckTest, ConfigurableDCheck) {
+  // Verify that DCHECKs default to non-fatal in configurable-DCHECK builds.
+  // Note that we require only that DCHECK is non-fatal by default, rather
+  // than requiring that it be exactly INFO, ERROR, etc level.
+  EXPECT_LT(LOG_DCHECK, LOG_FATAL);
+  DCHECK(false);
+
+  // Verify that DCHECK* aren't hard-wired to crash on failure.
+  LOG_DCHECK = LOG_INFO;
+  DCHECK(false);
+  DCHECK_EQ(1, 2);
+
+  // Verify that DCHECK does crash if LOG_DCHECK is set to LOG_FATAL.
+  LOG_DCHECK = LOG_FATAL;
+  EXPECT_CHECK("Check failed: false. ", DCHECK(false));
+  EXPECT_CHECK("Check failed: 1 == 2 (1 vs. 2)", DCHECK_EQ(1, 2));
+}
+
+TEST_F(CheckTest, ConfigurableDCheckFeature) {
+  // Initialize FeatureList with and without DcheckIsFatal, and verify the
+  // value of LOG_DCHECK. Note that we don't require that DCHECK take a
+  // specific value when the feature is off, only that it is non-fatal.
+
+  {
+    base::test::ScopedFeatureList feature_list;
+    feature_list.InitFromCommandLine("DcheckIsFatal", "");
+    EXPECT_EQ(LOG_DCHECK, LOG_FATAL);
+  }
+
+  {
+    base::test::ScopedFeatureList feature_list;
+    feature_list.InitFromCommandLine("", "DcheckIsFatal");
+    EXPECT_LT(LOG_DCHECK, LOG_FATAL);
+  }
+
+  // The default case is last, so we leave LOG_DCHECK in the default state.
+  {
+    base::test::ScopedFeatureList feature_list;
+    feature_list.InitFromCommandLine("", "");
+    EXPECT_LT(LOG_DCHECK, LOG_FATAL);
+  }
+}
+#endif  // defined(DCHECK_IS_CONFIGURABLE)
+
+struct StructWithOstream {
+  bool operator==(const StructWithOstream& o) const { return &o == this; }
+};
+#if !(defined(OFFICIAL_BUILD) && defined(NDEBUG))
+std::ostream& operator<<(std::ostream& out, const StructWithOstream&) {
+  return out << "ostream";
+}
+#endif
+
+struct StructWithToString {
+  bool operator==(const StructWithToString& o) const { return &o == this; }
+  std::string ToString() const { return "ToString"; }
+};
+
+struct StructWithToStringAndOstream {
+  bool operator==(const StructWithToStringAndOstream& o) const {
+    return &o == this;
+  }
+  std::string ToString() const { return "ToString"; }
+};
+#if !(defined(OFFICIAL_BUILD) && defined(NDEBUG))
+std::ostream& operator<<(std::ostream& out,
+                         const StructWithToStringAndOstream&) {
+  return out << "ostream";
+}
+#endif
+
+TEST_F(CheckTest, OstreamVsToString) {
+  StructWithOstream a, b;
+  EXPECT_CHECK("Check failed: a == b (ostream vs. ostream)", CHECK_EQ(a, b));
+
+  StructWithToString c, d;
+  EXPECT_CHECK("Check failed: c == d (ToString vs. ToString)", CHECK_EQ(c, d));
+
+  StructWithToStringAndOstream e, f;
+  EXPECT_CHECK("Check failed: e == f (ostream vs. ostream)", CHECK_EQ(e, f));
+}
+
+}  // namespace
diff --git a/base/logging_unittest.cc b/base/logging_unittest.cc
index 5b2581a..19d42eb9 100644
--- a/base/logging_unittest.cc
+++ b/base/logging_unittest.cc
@@ -63,71 +63,6 @@
 using ::testing::Return;
 using ::testing::_;
 
-// Helper class which expects a check to fire with a certain location and
-// message before the end of the current scope.
-class ScopedCheckExpectation {
- public:
-  ScopedCheckExpectation(const char* file, int line, std::string msg)
-      : file_(file),
-        line_(line),
-        msg_(msg),
-        assert_handler_(base::BindRepeating(&ScopedCheckExpectation::Check,
-                                            base::Unretained(this))),
-        fired_(false) {}
-  ~ScopedCheckExpectation() {
-    EXPECT_TRUE(fired_) << "CHECK at " << file_ << ":" << line_
-                        << " never fired!";
-  }
-
- private:
-  void Check(const char* file,
-             int line,
-             const base::StringPiece msg,
-             const base::StringPiece stack) {
-    fired_ = true;
-    EXPECT_EQ(file, file_);
-    EXPECT_EQ(line, line_);
-    if (msg_.find("=~") == 0) {
-      EXPECT_THAT(std::string(msg), testing::MatchesRegex(msg_.substr(2)));
-    } else {
-      EXPECT_EQ(std::string(msg), msg_);
-    }
-  }
-
-  std::string file_;
-  int line_;
-  std::string msg_;
-  logging::ScopedLogAssertHandler assert_handler_;
-  bool fired_;
-};
-
-// Macro which expects a CHECK to fire with a certain message. If msg starts
-// with "=~", it's interpreted as a regular expression.
-// Example: EXPECT_CHECK("Check failed: false.", CHECK(false));
-#if defined(OFFICIAL_BUILD) && defined(NDEBUG)
-#define EXPECT_CHECK(msg, check_expr) \
-  do {                                \
-    EXPECT_DEATH(check_expr, "");     \
-  } while (0)
-#else
-#define EXPECT_CHECK(msg, check_expr)                          \
-  do {                                                         \
-    ScopedCheckExpectation check_exp(__FILE__, __LINE__, msg); \
-    check_expr;                                                \
-  } while (0)
-#endif
-
-// Macro which expects a DCHECK to fire if DCHECKs are enabled.
-#define EXPECT_DCHECK(msg, check_expr)                                 \
-  do {                                                                 \
-    if (DCHECK_IS_ON() && logging::LOG_DCHECK == logging::LOG_FATAL) { \
-      ScopedCheckExpectation check_exp(__FILE__, __LINE__, msg);       \
-      check_expr;                                                      \
-    } else {                                                           \
-      check_expr;                                                      \
-    }                                                                  \
-  } while (0)
-
 // Class to make sure any manipulations we do to the min log level are
 // contained (i.e., do not affect other unit tests).
 class LogStateSaver {
@@ -427,96 +362,6 @@
 }
 #endif  // defined(OS_CHROMEOS)
 
-TEST_F(LoggingTest, CheckBasics) {
-  EXPECT_CHECK("Check failed: false. ", CHECK(false));
-
-  EXPECT_CHECK("Check failed: false. foo", CHECK(false) << "foo");
-
-  double a = 2, b = 1;
-  EXPECT_CHECK("Check failed: a < b (2 vs. 1)", CHECK_LT(a, b));
-
-  EXPECT_CHECK("Check failed: a < b (2 vs. 1)foo", CHECK_LT(a, b) << "foo");
-}
-
-TEST_F(LoggingTest, PCheck) {
-  const char file[] = "/nonexistentfile123";
-  ignore_result(fopen(file, "r"));
-  std::string err =
-      logging::SystemErrorCodeToString(logging::GetLastSystemErrorCode());
-
-  EXPECT_CHECK(
-      "Check failed: fopen(file, \"r\") != nullptr."
-      " : " +
-          err,
-      PCHECK(fopen(file, "r") != nullptr));
-
-  EXPECT_CHECK(
-      "Check failed: fopen(file, \"r\") != nullptr."
-      " foo: " +
-          err,
-      PCHECK(fopen(file, "r") != nullptr) << "foo");
-
-  EXPECT_DCHECK(
-      "Check failed: fopen(file, \"r\") != nullptr."
-      " : " +
-          err,
-      DPCHECK(fopen(file, "r") != nullptr));
-
-  EXPECT_DCHECK(
-      "Check failed: fopen(file, \"r\") != nullptr."
-      " foo: " +
-          err,
-      DPCHECK(fopen(file, "r") != nullptr) << "foo");
-}
-
-TEST_F(LoggingTest, CheckOp) {
-  int a = 1, b = 2;
-  // clang-format off
-  EXPECT_CHECK("Check failed: a == b (1 vs. 2)", CHECK_EQ(a, b));
-  EXPECT_CHECK("Check failed: a != a (1 vs. 1)", CHECK_NE(a, a));
-  EXPECT_CHECK("Check failed: b <= a (2 vs. 1)", CHECK_LE(b, a));
-  EXPECT_CHECK("Check failed: b < a (2 vs. 1)",  CHECK_LT(b, a));
-  EXPECT_CHECK("Check failed: a >= b (1 vs. 2)", CHECK_GE(a, b));
-  EXPECT_CHECK("Check failed: a > b (1 vs. 2)",  CHECK_GT(a, b));
-
-  EXPECT_DCHECK("Check failed: a == b (1 vs. 2)", DCHECK_EQ(a, b));
-  EXPECT_DCHECK("Check failed: a != a (1 vs. 1)", DCHECK_NE(a, a));
-  EXPECT_DCHECK("Check failed: b <= a (2 vs. 1)", DCHECK_LE(b, a));
-  EXPECT_DCHECK("Check failed: b < a (2 vs. 1)",  DCHECK_LT(b, a));
-  EXPECT_DCHECK("Check failed: a >= b (1 vs. 2)", DCHECK_GE(a, b));
-  EXPECT_DCHECK("Check failed: a > b (1 vs. 2)",  DCHECK_GT(a, b));
-  // clang-format on
-}
-
-TEST_F(LoggingTest, CheckStreamsAreLazy) {
-  int called_count = 0;
-  int not_called_count = 0;
-
-  auto Called = [&]() {
-    ++called_count;
-    return 42;
-  };
-  auto NotCalled = [&]() {
-    ++not_called_count;
-    return 42;
-  };
-
-  CHECK(Called()) << NotCalled();
-  CHECK_EQ(Called(), Called()) << NotCalled();
-  PCHECK(Called()) << NotCalled();
-
-  DCHECK(Called()) << NotCalled();
-  DCHECK_EQ(Called(), Called()) << NotCalled();
-  DPCHECK(Called()) << NotCalled();
-
-  EXPECT_EQ(not_called_count, 0);
-#if DCHECK_IS_ON()
-  EXPECT_EQ(called_count, 8);
-#else
-  EXPECT_EQ(called_count, 4);
-#endif
-}
-
 #if defined(OFFICIAL_BUILD) && defined(OS_WIN)
 NOINLINE void CheckContainingFunc(int death_location) {
   CHECK(death_location != 1);
@@ -803,136 +648,6 @@
   DVLOG_IF(1, debug_only_variable) << "test";
 }
 
-void DcheckEmptyFunction1() {
-  // Provide a body so that Release builds do not cause the compiler to
-  // optimize DcheckEmptyFunction1 and DcheckEmptyFunction2 as a single
-  // function, which breaks the Dcheck tests below.
-  LOG(INFO) << "DcheckEmptyFunction1";
-}
-void DcheckEmptyFunction2() {}
-
-#if defined(DCHECK_IS_CONFIGURABLE)
-class ScopedDcheckSeverity {
- public:
-  ScopedDcheckSeverity(LogSeverity new_severity) : old_severity_(LOG_DCHECK) {
-    LOG_DCHECK = new_severity;
-  }
-
-  ~ScopedDcheckSeverity() { LOG_DCHECK = old_severity_; }
-
- private:
-  LogSeverity old_severity_;
-};
-#endif  // defined(DCHECK_IS_CONFIGURABLE)
-
-// https://crbug.com/709067 tracks test flakiness on iOS.
-#if defined(OS_IOS)
-#define MAYBE_Dcheck DISABLED_Dcheck
-#else
-#define MAYBE_Dcheck Dcheck
-#endif
-TEST_F(LoggingTest, MAYBE_Dcheck) {
-#if defined(DCHECK_IS_CONFIGURABLE)
-  // DCHECKs are enabled, and LOG_DCHECK is mutable, but defaults to non-fatal.
-  // Set it to LOG_FATAL to get the expected behavior from the rest of this
-  // test.
-  ScopedDcheckSeverity dcheck_severity(LOG_FATAL);
-#endif  // defined(DCHECK_IS_CONFIGURABLE)
-
-#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
-  // Release build.
-  EXPECT_FALSE(DCHECK_IS_ON());
-  EXPECT_FALSE(DLOG_IS_ON(DCHECK));
-#elif defined(NDEBUG) && defined(DCHECK_ALWAYS_ON)
-  // Release build with real DCHECKS.
-  EXPECT_TRUE(DCHECK_IS_ON());
-  EXPECT_TRUE(DLOG_IS_ON(DCHECK));
-#else
-  // Debug build.
-  EXPECT_TRUE(DCHECK_IS_ON());
-  EXPECT_TRUE(DLOG_IS_ON(DCHECK));
-#endif
-
-  EXPECT_DCHECK("Check failed: false. ", DCHECK(false));
-  std::string err =
-      logging::SystemErrorCodeToString(logging::GetLastSystemErrorCode());
-  EXPECT_DCHECK("Check failed: false. : " + err, DPCHECK(false));
-  EXPECT_DCHECK("Check failed: 0 == 1 (0 vs. 1)", DCHECK_EQ(0, 1));
-
-  // Test DCHECK on std::nullptr_t
-  const void* p_null = nullptr;
-  const void* p_not_null = &p_null;
-  DCHECK_EQ(p_null, nullptr);
-  DCHECK_EQ(nullptr, p_null);
-  DCHECK_NE(p_not_null, nullptr);
-  DCHECK_NE(nullptr, p_not_null);
-
-  // Test DCHECK on a scoped enum.
-  enum class Animal { DOG, CAT };
-  DCHECK_EQ(Animal::DOG, Animal::DOG);
-  EXPECT_DCHECK("Check failed: Animal::DOG == Animal::CAT (0 vs. 1)",
-                DCHECK_EQ(Animal::DOG, Animal::CAT));
-
-  // Test DCHECK on functions and function pointers.
-  struct MemberFunctions {
-    void MemberFunction1() {
-      // See the comment in DcheckEmptyFunction1().
-      LOG(INFO) << "Do not merge with MemberFunction2.";
-    }
-    void MemberFunction2() {}
-  };
-  void (MemberFunctions::*mp1)() = &MemberFunctions::MemberFunction1;
-  void (MemberFunctions::*mp2)() = &MemberFunctions::MemberFunction2;
-  void (*fp1)() = DcheckEmptyFunction1;
-  void (*fp2)() = DcheckEmptyFunction2;
-  void (*fp3)() = DcheckEmptyFunction1;
-  DCHECK_EQ(fp1, fp3);
-  DCHECK_EQ(mp1, &MemberFunctions::MemberFunction1);
-  DCHECK_EQ(mp2, &MemberFunctions::MemberFunction2);
-  EXPECT_DCHECK("=~Check failed: fp1 == fp2 \\(\\w+ vs. \\w+\\)",
-                DCHECK_EQ(fp1, fp2));
-  EXPECT_DCHECK(
-      "Check failed: mp2 == &MemberFunctions::MemberFunction1 (1 vs. 1)",
-      DCHECK_EQ(mp2, &MemberFunctions::MemberFunction1));
-}
-
-TEST_F(LoggingTest, DcheckReleaseBehavior) {
-  int var1 = 1;
-  int var2 = 2;
-  int var3 = 3;
-  int var4 = 4;
-
-  // No warnings about unused variables even though no check fires and DCHECK
-  // may or may not be enabled.
-  DCHECK(var1) << var2;
-  DPCHECK(var1) << var3;
-  DCHECK_EQ(var1, 1) << var4;
-}
-
-TEST_F(LoggingTest, DCheckEqStatements) {
-  bool reached = false;
-  if (false)
-    DCHECK_EQ(false, true);  // Unreached.
-  else
-    DCHECK_EQ(true, reached = true);  // Reached, passed.
-  ASSERT_EQ(DCHECK_IS_ON() ? true : false, reached);
-
-  if (false)
-    DCHECK_EQ(false, true);  // Unreached.
-}
-
-TEST_F(LoggingTest, CheckEqStatements) {
-  bool reached = false;
-  if (false)
-    CHECK_EQ(false, true);  // Unreached.
-  else
-    CHECK_EQ(true, reached = true);  // Reached, passed.
-  ASSERT_TRUE(reached);
-
-  if (false)
-    CHECK_EQ(false, true);  // Unreached.
-}
-
 TEST_F(LoggingTest, NestedLogAssertHandlers) {
   ::testing::InSequence dummy;
   ::testing::StrictMock<MockLogAssertHandler> handler_a, handler_b;
@@ -989,51 +704,6 @@
   }
 }  // namespace nested_test
 
-#if defined(DCHECK_IS_CONFIGURABLE)
-TEST_F(LoggingTest, ConfigurableDCheck) {
-  // Verify that DCHECKs default to non-fatal in configurable-DCHECK builds.
-  // Note that we require only that DCHECK is non-fatal by default, rather
-  // than requiring that it be exactly INFO, ERROR, etc level.
-  EXPECT_LT(LOG_DCHECK, LOG_FATAL);
-  DCHECK(false);
-
-  // Verify that DCHECK* aren't hard-wired to crash on failure.
-  LOG_DCHECK = LOG_INFO;
-  DCHECK(false);
-  DCHECK_EQ(1, 2);
-
-  // Verify that DCHECK does crash if LOG_DCHECK is set to LOG_FATAL.
-  LOG_DCHECK = LOG_FATAL;
-  EXPECT_CHECK("Check failed: false. ", DCHECK(false));
-  EXPECT_CHECK("Check failed: 1 == 2 (1 vs. 2)", DCHECK_EQ(1, 2));
-}
-
-TEST_F(LoggingTest, ConfigurableDCheckFeature) {
-  // Initialize FeatureList with and without DcheckIsFatal, and verify the
-  // value of LOG_DCHECK. Note that we don't require that DCHECK take a
-  // specific value when the feature is off, only that it is non-fatal.
-
-  {
-    base::test::ScopedFeatureList feature_list;
-    feature_list.InitFromCommandLine("DcheckIsFatal", "");
-    EXPECT_EQ(LOG_DCHECK, LOG_FATAL);
-  }
-
-  {
-    base::test::ScopedFeatureList feature_list;
-    feature_list.InitFromCommandLine("", "DcheckIsFatal");
-    EXPECT_LT(LOG_DCHECK, LOG_FATAL);
-  }
-
-  // The default case is last, so we leave LOG_DCHECK in the default state.
-  {
-    base::test::ScopedFeatureList feature_list;
-    feature_list.InitFromCommandLine("", "");
-    EXPECT_LT(LOG_DCHECK, LOG_FATAL);
-  }
-}
-#endif  // defined(DCHECK_IS_CONFIGURABLE)
-
 #if defined(OS_FUCHSIA)
 
 class TestLogListener : public fuchsia::logger::testing::LogListener_TestBase {
@@ -1209,44 +879,6 @@
 }
 #endif  // !defined(ADDRESS_SANITIZER)
 
-struct StructWithOstream {
-  bool operator==(const StructWithOstream& o) const { return &o == this; }
-};
-#if !(defined(OFFICIAL_BUILD) && defined(NDEBUG))
-std::ostream& operator<<(std::ostream& out, const StructWithOstream&) {
-  return out << "ostream";
-}
-#endif
-
-struct StructWithToString {
-  bool operator==(const StructWithToString& o) const { return &o == this; }
-  std::string ToString() const { return "ToString"; }
-};
-
-struct StructWithToStringAndOstream {
-  bool operator==(const StructWithToStringAndOstream& o) const {
-    return &o == this;
-  }
-  std::string ToString() const { return "ToString"; }
-};
-#if !(defined(OFFICIAL_BUILD) && defined(NDEBUG))
-std::ostream& operator<<(std::ostream& out,
-                         const StructWithToStringAndOstream&) {
-  return out << "ostream";
-}
-#endif
-
-TEST_F(LoggingTest, OstreamVsToString) {
-  StructWithOstream a, b;
-  EXPECT_CHECK("Check failed: a == b (ostream vs. ostream)", CHECK_EQ(a, b));
-
-  StructWithToString c, d;
-  EXPECT_CHECK("Check failed: c == d (ToString vs. ToString)", CHECK_EQ(c, d));
-
-  StructWithToStringAndOstream e, f;
-  EXPECT_CHECK("Check failed: e == f (ostream vs. ostream)", CHECK_EQ(e, f));
-}
-
 }  // namespace
 
 }  // namespace logging
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h
index 08aca46..7fde9d5 100644
--- a/base/threading/thread_restrictions.h
+++ b/base/threading/thread_restrictions.h
@@ -147,6 +147,7 @@
 class DesktopCaptureDevice;
 class InProcessUtilityThread;
 class NestedMessagePumpAndroid;
+class PepperPrintSettingsManagerImpl;
 class RenderProcessHostImpl;
 class RenderWidgetHostViewMac;
 class RTCVideoDecoder;
@@ -365,6 +366,7 @@
   friend class android_webview::ScopedAllowInitGLBindings;
   friend class chromeos::MojoUtils;  // http://crbug.com/1055467
   friend class content::BrowserProcessSubThread;
+  friend class content::PepperPrintSettingsManagerImpl;
   friend class content::RenderProcessHostImpl;
   friend class content::RenderWidgetHostViewMac;  // http://crbug.com/121917
   friend class content::WebContentsViewMac;
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 8fa0aae..618d5f6 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-0.20200406.2.3
\ No newline at end of file
+0.20200407.0.1
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 8fa0aae..618d5f6 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-0.20200406.2.3
\ No newline at end of file
+0.20200407.0.1
\ No newline at end of file
diff --git a/build/toolchain/win/setup_toolchain.py b/build/toolchain/win/setup_toolchain.py
index 2ab240da..9c936c6 100644
--- a/build/toolchain/win/setup_toolchain.py
+++ b/build/toolchain/win/setup_toolchain.py
@@ -185,6 +185,16 @@
   return {k.lower(): d[k].lower() for k in d}
 
 
+def FindFileInEnvList(env, env_name, separator, file_name, optional=False):
+  parts = env[env_name].split(separator)
+  for path in parts:
+    if os.path.exists(os.path.join(path, file_name)):
+      return os.path.realpath(path)
+  assert optional, "%s is not found in %s:\n%s\nCheck if it is installed." % (
+      file_name, env_name, '\n'.join(parts))
+  return ''
+
+
 def main():
   if len(sys.argv) != 7:
     print('Usage setup_toolchain.py '
@@ -223,34 +233,11 @@
       env = _LoadToolchainEnv(cpu, win_sdk_path, target_store)
       env['PATH'] = runtime_dirs + os.pathsep + env['PATH']
 
-      for path in env['PATH'].split(os.pathsep):
-        if os.path.exists(os.path.join(path, 'cl.exe')):
-          vc_bin_dir = os.path.realpath(path)
-          break
-      assert vc_bin_dir, "cl.exe is not found, check if it is installed."
-
-      for path in env['LIB'].split(';'):
-        if os.path.exists(os.path.join(path, 'msvcrt.lib')):
-          vc_lib_path = os.path.realpath(path)
-          break
-      assert vc_lib_path, "msvcrt.lib is not found, check if it is installed."
-
-      for path in env['LIB'].split(';'):
-        if os.path.exists(os.path.join(path, 'atls.lib')):
-          vc_lib_atlmfc_path = os.path.realpath(path)
-          break
-      if (target_store != True):
-        # Path is assumed to exist for desktop applications.
-        assert vc_lib_atlmfc_path, (
-            "Microsoft.VisualStudio.Component.VC.ATLMFC " +
-            "is not found, check if it is installed.")
-
-      for path in env['LIB'].split(';'):
-        if os.path.exists(os.path.join(path, 'User32.Lib')):
-          vc_lib_um_path = os.path.realpath(path)
-          break
-      assert vc_lib_um_path, (
-          "User32.lib is not found, check if it is installed.")
+      vc_bin_dir = FindFileInEnvList(env, 'PATH', os.pathsep, 'cl.exe')
+      vc_lib_path = FindFileInEnvList(env, 'LIB', ';', 'msvcrt.lib')
+      vc_lib_atlmfc_path = FindFileInEnvList(
+          env, 'LIB', ';', 'atls.lib', optional=True)
+      vc_lib_um_path = FindFileInEnvList(env, 'LIB', ';', 'user32.lib')
 
       # The separator for INCLUDE here must match the one used in
       # _LoadToolchainEnv() above.
diff --git a/chrome/VERSION b/chrome/VERSION
index 62539f5..e8e7182 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=84
 MINOR=0
-BUILD=4107
+BUILD=4108
 PATCH=0
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index 704c540..d5eefd8 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -1573,6 +1573,7 @@
   "java/src/org/chromium/chrome/browser/tab/AuthenticatorNavigationInterceptor.java",
   "java/src/org/chromium/chrome/browser/tab/EmptyTabObserver.java",
   "java/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateImpl.java",
+  "java/src/org/chromium/chrome/browser/tab/RedirectHandlerTabHelper.java",
   "java/src/org/chromium/chrome/browser/tab/SadTab.java",
   "java/src/org/chromium/chrome/browser/tab/SadTabView.java",
   "java/src/org/chromium/chrome/browser/tab/Tab.java",
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/additional_sections/AssistantTextInputSection.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/additional_sections/AssistantTextInputSection.java
index 9e57302..222e30f9 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/additional_sections/AssistantTextInputSection.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/additional_sections/AssistantTextInputSection.java
@@ -141,7 +141,7 @@
                 mDelegate.onValueChanged(
                         result.first, new AssistantValue(new String[] {result.second}));
             });
-            inputView.getInputLayout().addEditTextOnFocusChangeListener((unusedView, hasFocus) -> {
+            inputView.getEditText().setOnFocusChangeListener((unusedView, hasFocus) -> {
                 if (!hasFocus && mDelegate != null) {
                     mDelegate.onTextFocusLost();
                 }
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantChromeTabIntegrationTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantChromeTabIntegrationTest.java
index 026461af..5dcfa07d 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantChromeTabIntegrationTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantChromeTabIntegrationTest.java
@@ -4,14 +4,24 @@
 
 package org.chromium.chrome.browser.autofill_assistant;
 
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
 import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
 import static android.support.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withClassName;
+import static android.support.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
 import static android.support.test.espresso.matcher.ViewMatchers.withText;
 
+import static org.hamcrest.Matchers.is;
+
 import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntilViewAssertionTrue;
 import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntilViewMatchesCondition;
 
 import android.support.test.InstrumentationRegistry;
+import android.support.test.espresso.Espresso;
+import android.support.test.espresso.matcher.ViewMatchers.Visibility;
 import android.support.test.filters.MediumTest;
 
 import org.junit.After;
@@ -28,6 +38,7 @@
 import org.chromium.chrome.browser.autofill_assistant.proto.SupportedScriptProto.PresentationProto;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.tabmodel.TabModelUtils;
+import org.chromium.chrome.browser.widget.ScrimView;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.util.ChromeTabUtils;
@@ -83,6 +94,42 @@
 
     @Test
     @MediumTest
+    public void newTabButtonHidesAndRecoversAutofillAssistant() throws Exception {
+        ArrayList<ActionProto> list = new ArrayList<>();
+        list.add((ActionProto) ActionProto.newBuilder()
+                         .setPrompt(PromptProto.newBuilder()
+                                            .setMessage("Prompt")
+                                            .setDisableForceExpandSheet(true)
+                                            .addChoices(PromptProto.Choice.newBuilder()))
+                         .build());
+
+        AutofillAssistantTestScript script = new AutofillAssistantTestScript(
+                (SupportedScriptProto) SupportedScriptProto.newBuilder()
+                        .setPath(TEST_PAGE_A)
+                        .setPresentation(PresentationProto.newBuilder().setAutostart(true).setChip(
+                                ChipProto.newBuilder().setText("Done")))
+                        .build(),
+                list);
+
+        setupScripts(script);
+        startAutofillAssistantOnTab(TEST_PAGE_A);
+
+        waitUntilViewMatchesCondition(withText("Prompt"), isCompletelyDisplayed());
+        onView(withClassName(is(ScrimView.class.getName())))
+                .check(matches(withEffectiveVisibility(Visibility.VISIBLE)));
+
+        onView(withId(org.chromium.chrome.R.id.tab_switcher_button)).perform(click());
+        waitUntilViewAssertionTrue(withText("Prompt"), doesNotExist(), 3000L);
+        onView(withClassName(is(ScrimView.class.getName()))).check(doesNotExist());
+
+        Espresso.pressBack();
+        waitUntilViewMatchesCondition(withText("Prompt"), isCompletelyDisplayed());
+        onView(withClassName(is(ScrimView.class.getName())))
+                .check(matches(withEffectiveVisibility(Visibility.VISIBLE)));
+    }
+
+    @Test
+    @MediumTest
     public void switchingTabHidesAutofillAssistant() throws Exception {
         ArrayList<ActionProto> list = new ArrayList<>();
         list.add((ActionProto) ActionProto.newBuilder()
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutTest.java
index 6256197..1bfdc221 100644
--- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutTest.java
+++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutTest.java
@@ -96,7 +96,6 @@
 import org.chromium.chrome.tab_ui.R;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
-import org.chromium.chrome.test.util.ApplicationTestUtils;
 import org.chromium.chrome.test.util.ChromeRenderTestRule;
 import org.chromium.chrome.test.util.ChromeTabUtils;
 import org.chromium.chrome.test.util.MenuUtils;
@@ -462,7 +461,7 @@
             // Although we're destroying the activity, the Application will still live on since its
             // in the same process as this test.
             TestThreadUtils.runOnUiThreadBlocking(() -> cta.getTabModelSelector().closeAllTabs());
-            ApplicationTestUtils.finishActivity(cta);
+            TabUiTestHelper.finishActivity(cta);
             mActivityTestRule.startMainActivityOnBlankPage();
             assertEquals(1, mActivityTestRule.tabsCount(false));
         }
@@ -572,7 +571,7 @@
         // Restart Chrome.
         // Although we're destroying the activity, the Application will still live on since its in
         // the same process as this test.
-        ApplicationTestUtils.finishActivity(mActivityTestRule.getActivity());
+        TabUiTestHelper.finishActivity(mActivityTestRule.getActivity());
         mActivityTestRule.startMainActivityOnBlankPage();
         assertEquals(3, mActivityTestRule.tabsCount(false));
 
@@ -1065,7 +1064,7 @@
         enterTabSwitcher(mActivityTestRule.getActivity());
         onView(withId(R.id.tab_list_view))
                 .check(ThumbnailAspectRatioAssertion.havingAspectRatio(2.0));
-        ApplicationTestUtils.finishActivity(mActivityTestRule.getActivity());
+        TabUiTestHelper.finishActivity(mActivityTestRule.getActivity());
     }
 
     @Test
@@ -1117,7 +1116,7 @@
             TabUiTestHelper.checkThumbnailsExist(currentTabModel.getTabAt(i));
         }
 
-        ApplicationTestUtils.finishActivity(mActivityTestRule.getActivity());
+        TabUiTestHelper.finishActivity(mActivityTestRule.getActivity());
         mActivityTestRule.startMainActivityFromLauncher();
 
         enterTabSwitcher(mActivityTestRule.getActivity());
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/pseudotab/PseudoTab.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/pseudotab/PseudoTab.java
index 6dac66fd..eb6d63c 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/pseudotab/PseudoTab.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/pseudotab/PseudoTab.java
@@ -6,6 +6,7 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
 
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabImpl;
@@ -195,6 +196,16 @@
     }
 
     /**
+     * Clear the internal static storage as if the app is restarted.
+     * This should/can be called when emulating restarting in instrumented tests, or between
+     * Robolectric tests.
+     */
+    @VisibleForTesting
+    public static void clearForTesting() {
+        sAllTabs.clear();
+    }
+
+    /**
      * Get related tabs of a certain {@link PseudoTab}, through {@link TabModelFilter}s if
      * available.
      * @param member The {@link PseudoTab} related to
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/pseudotab/TabAttributeCache.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/pseudotab/TabAttributeCache.java
index 39b4a7f..626a14d 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/pseudotab/TabAttributeCache.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/pseudotab/TabAttributeCache.java
@@ -150,7 +150,8 @@
      * @param id The ID of the {@link PseudoTab}.
      * @param title The title
      */
-    static void setTitleForTesting(int id, String title) {
+    @VisibleForTesting
+    public static void setTitleForTesting(int id, String title) {
         cacheTitle(id, title);
     }
 
@@ -202,7 +203,8 @@
      * @param id The ID of the {@link PseudoTab}.
      * @param rootId The root ID
      */
-    static void setRootIdForTesting(int id, int rootId) {
+    @VisibleForTesting
+    public static void setRootIdForTesting(int id, int rootId) {
         cacheRootId(id, rootId);
     }
 
@@ -318,8 +320,11 @@
      */
     public void destroy() {
         mTabModelSelectorTabObserver.destroy();
-        mTabModelSelector.getTabModelFilterProvider().getTabModelFilter(false).removeObserver(
-                mTabModelObserver);
+        TabModelFilter tabModelFilter =
+                mTabModelSelector.getTabModelFilterProvider().getTabModelFilter(false);
+        if (tabModelFilter != null) {
+            tabModelFilter.removeObserver(mTabModelObserver);
+        }
         mTabModelSelector.removeObserver(mTabModelSelectorObserver);
     }
 }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupUtils.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupUtils.java
index fefd30d6..9f8c0b8 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupUtils.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupUtils.java
@@ -17,12 +17,12 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver;
+import org.chromium.chrome.browser.tasks.tab_management.TabUiFeatureUtilities;
 import org.chromium.chrome.browser.util.AccessibilityUtil;
 import org.chromium.chrome.tab_ui.R;
 import org.chromium.components.browser_ui.widget.textbubble.TextBubble;
@@ -42,7 +42,7 @@
     private static final String TAB_GROUP_TITLES_FILE_NAME = "tab_group_titles";
 
     public static void maybeShowIPH(@FeatureConstants String featureName, View view) {
-        if (!ChromeFeatureList.isEnabled(ChromeFeatureList.TAB_GROUPS_ANDROID)) return;
+        if (!TabUiFeatureUtilities.isTabGroupsAndroidEnabled()) return;
 
         @StringRes
         int textId;
@@ -69,6 +69,7 @@
 
         final Tracker tracker =
                 TrackerFactory.getTrackerForProfile(Profile.getLastUsedRegularProfile());
+        if (!tracker.isInitialized()) return;
         if (!tracker.shouldTriggerHelpUI(featureName)) return;
 
         ViewRectProvider rectProvider = new ViewRectProvider(view);
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MultiThumbnailCardProvider.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MultiThumbnailCardProvider.java
index b917801..f816b19 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MultiThumbnailCardProvider.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MultiThumbnailCardProvider.java
@@ -21,11 +21,11 @@
 import org.chromium.base.task.PostTask;
 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver;
+import org.chromium.chrome.browser.tasks.pseudotab.PseudoTab;
 import org.chromium.chrome.tab_ui.R;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
 
@@ -57,11 +57,11 @@
     private TabListFaviconProvider mTabListFaviconProvider;
 
     private class MultiThumbnailFetcher {
-        private final Tab mInitialTab;
+        private final PseudoTab mInitialTab;
         private final Callback<Bitmap> mFinalCallback;
         private final boolean mForceUpdate;
         private final boolean mWriteToCache;
-        private final List<Tab> mTabs = new ArrayList<>(4);
+        private final List<PseudoTab> mTabs = new ArrayList<>(4);
         private final AtomicInteger mThumbnailsToFetch = new AtomicInteger();
 
         private Canvas mCanvas;
@@ -71,15 +71,15 @@
         /**
          * @see TabContentManager#getTabThumbnailWithCallback
          */
-        MultiThumbnailFetcher(Tab initialTab, Callback<Bitmap> finalCallback, boolean forceUpdate,
-                boolean writeToCache) {
+        MultiThumbnailFetcher(PseudoTab initialTab, Callback<Bitmap> finalCallback,
+                boolean forceUpdate, boolean writeToCache) {
             mFinalCallback = finalCallback;
             mInitialTab = initialTab;
             mForceUpdate = forceUpdate;
             mWriteToCache = writeToCache;
         }
 
-        private void initializeAndStartFetching(Tab tab) {
+        private void initializeAndStartFetching(PseudoTab tab) {
             // Initialize mMultiThumbnailBitmap.
             int width = mSize;
             int height = mSize;
@@ -88,10 +88,8 @@
             mCanvas.drawColor(Color.TRANSPARENT);
 
             // Initialize Tabs.
-            List<Tab> relatedTabList = new ArrayList<>();
-            relatedTabList.addAll(mTabModelSelector.getTabModelFilterProvider()
-                                          .getCurrentTabModelFilter()
-                                          .getRelatedTabList(tab.getId()));
+            List<PseudoTab> relatedTabList =
+                    PseudoTab.getRelatedTabs(tab, mTabModelSelector.getTabModelFilterProvider());
             if (relatedTabList.size() <= 4) {
                 mThumbnailsToFetch.set(relatedTabList.size());
 
@@ -117,7 +115,7 @@
             for (int i = 0; i < 4; i++) {
                 if (mTabs.get(i) != null) {
                     final int index = i;
-                    final String url = mTabs.get(i).getUrlString();
+                    final String url = mTabs.get(i).getUrl();
                     final boolean isIncognito = mTabs.get(i).isIncognito();
                     // getTabThumbnailWithCallback() might call the callback up to twice,
                     // so use |lastFavicon| to avoid fetching the favicon the second time.
@@ -307,19 +305,16 @@
     @Override
     public void getTabThumbnailWithCallback(
             int tabId, Callback<Bitmap> finalCallback, boolean forceUpdate, boolean writeToCache) {
-        if (mTabModelSelector.getTabModelFilterProvider()
-                        .getCurrentTabModelFilter()
-                        .getRelatedTabList(tabId)
-                        .size()
-                == 1) {
+        PseudoTab tab = PseudoTab.fromTabId(tabId);
+        if (tab == null
+                || PseudoTab.getRelatedTabs(tab, mTabModelSelector.getTabModelFilterProvider())
+                                .size()
+                        == 1) {
             mTabContentManager.getTabThumbnailWithCallback(
                     tabId, finalCallback, forceUpdate, writeToCache);
             return;
         }
 
-        Tab tab = mTabModelSelector.getTabById(tabId);
-        if (tab == null) return;
-
         new MultiThumbnailFetcher(tab, finalCallback, forceUpdate, writeToCache).fetch();
     }
 }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java
index ace2b658a..3f64cdc5 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java
@@ -133,6 +133,11 @@
             @Override
             public void didAddTab(
                     Tab tab, @TabLaunchType int type, @TabCreationState int creationState) {
+                if (!mTabModelSelector.getTabModelFilterProvider()
+                                .getCurrentTabModelFilter()
+                                .isTabModelRestored()) {
+                    return;
+                }
                 hideDialog(false);
             }
 
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewBinder.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewBinder.java
index cd7387f..c3203d2 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewBinder.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewBinder.java
@@ -151,15 +151,23 @@
     private static void bindClosableTabProperties(
             PropertyModel model, ViewLookupCachingFrameLayout view, PropertyKey propertyKey) {
         if (TabProperties.TAB_CLOSED_LISTENER == propertyKey) {
-            view.fastFindViewById(R.id.action_button).setOnClickListener(v -> {
-                int tabId = model.get(TabProperties.TAB_ID);
-                model.get(TabProperties.TAB_CLOSED_LISTENER).run(tabId);
-            });
+            if (model.get(TabProperties.TAB_CLOSED_LISTENER) == null) {
+                view.fastFindViewById(R.id.action_button).setOnClickListener(null);
+            } else {
+                view.fastFindViewById(R.id.action_button).setOnClickListener(v -> {
+                    int tabId = model.get(TabProperties.TAB_ID);
+                    model.get(TabProperties.TAB_CLOSED_LISTENER).run(tabId);
+                });
+            }
         } else if (TabProperties.TAB_SELECTED_LISTENER == propertyKey) {
-            view.setOnClickListener(v -> {
-                int tabId = model.get(TabProperties.TAB_ID);
-                model.get(TabProperties.TAB_SELECTED_LISTENER).run(tabId);
-            });
+            if (model.get(TabProperties.TAB_SELECTED_LISTENER) == null) {
+                view.setOnClickListener(null);
+            } else {
+                view.setOnClickListener(v -> {
+                    int tabId = model.get(TabProperties.TAB_ID);
+                    model.get(TabProperties.TAB_SELECTED_LISTENER).run(tabId);
+                });
+            }
         } else if (TabProperties.CREATE_GROUP_LISTENER == propertyKey) {
             TabListMediator.TabActionListener listener =
                     model.get(TabProperties.CREATE_GROUP_LISTENER);
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java
index 50fda101..1fefcb7 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java
@@ -29,6 +29,7 @@
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
+import org.chromium.chrome.browser.tasks.pseudotab.PseudoTab;
 import org.chromium.chrome.browser.tasks.tab_groups.TabGroupUtils;
 import org.chromium.chrome.browser.tasks.tab_management.TabProperties.UiType;
 import org.chromium.chrome.browser.toolbar.bottom.BottomToolbarConfiguration;
@@ -105,7 +106,7 @@
      */
     TabListCoordinator(@TabListMode int mode, Context context, TabModelSelector tabModelSelector,
             @Nullable TabListMediator.ThumbnailProvider thumbnailProvider,
-            @Nullable TabListMediator.TitleProvider titleProvider, boolean actionOnRelatedTabs,
+            @Nullable PseudoTab.TitleProvider titleProvider, boolean actionOnRelatedTabs,
             @Nullable TabListMediator
                     .GridCardOnClickListenerProvider gridCardOnClickListenerProvider,
             @Nullable TabListMediator.TabGridDialogHandler dialogHandler, @UiType int itemType,
@@ -343,7 +344,8 @@
     /**
      * @see TabListMediator#resetWithListOfTabs(List, boolean, boolean)
      */
-    boolean resetWithListOfTabs(@Nullable List<Tab> tabs, boolean quickMode, boolean mruMode) {
+    boolean resetWithListOfTabs(
+            @Nullable List<PseudoTab> tabs, boolean quickMode, boolean mruMode) {
         if (mMode == TabListMode.STRIP && tabs != null && tabs.size() > 1) {
             TabGroupUtils.maybeShowIPH(
                     FeatureConstants.TAB_GROUPS_TAP_TO_SEE_ANOTHER_TAB_FEATURE, mRecyclerView);
@@ -352,7 +354,7 @@
     }
 
     boolean resetWithListOfTabs(@Nullable List<Tab> tabs) {
-        return resetWithListOfTabs(tabs, false, false);
+        return resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false, false);
     }
 
     int indexOfTab(int tabId) {
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListFaviconProvider.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListFaviconProvider.java
index 27037a5..7000dc1 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListFaviconProvider.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListFaviconProvider.java
@@ -108,7 +108,7 @@
      */
     public void getFaviconForUrlAsync(
             String url, boolean isIncognito, Callback<Drawable> faviconCallback) {
-        if (NativePageFactory.isNativePageUrl(url, isIncognito)) {
+        if (mFaviconHelper == null || NativePageFactory.isNativePageUrl(url, isIncognito)) {
             faviconCallback.onResult(getRoundedChromeDrawable(isIncognito));
         } else {
             mFaviconHelper.getLocalFaviconImageForURL(
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
index d67b2831..154ec136 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
@@ -26,6 +26,7 @@
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 
 import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 import androidx.appcompat.content.res.AppCompatResources;
@@ -45,7 +46,6 @@
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabCreationState;
-import org.chromium.chrome.browser.tab.TabImpl;
 import org.chromium.chrome.browser.tab.TabLaunchType;
 import org.chromium.chrome.browser.tab.TabObserver;
 import org.chromium.chrome.browser.tab.TabSelectionType;
@@ -57,6 +57,7 @@
 import org.chromium.chrome.browser.tabmodel.TabModelObserver;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tabmodel.TabModelUtils;
+import org.chromium.chrome.browser.tasks.pseudotab.PseudoTab;
 import org.chromium.chrome.browser.tasks.pseudotab.TabAttributeCache;
 import org.chromium.chrome.browser.tasks.tab_groups.EmptyTabGroupModelFilterObserver;
 import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilter;
@@ -93,7 +94,7 @@
  */
 class TabListMediator {
     // Comparator to sort Tabs in descending order of the last shown time.
-    private static final Comparator<Tab> LAST_SHOWN_COMPARATOR =
+    private static final Comparator<PseudoTab> LAST_SHOWN_COMPARATOR =
             (a, b) -> (Long.compare(b.getTimestampMillis(), a.getTimestampMillis()));
 
     private boolean mVisible;
@@ -111,11 +112,6 @@
     }
 
     /**
-     * An interface to get the title to be used for a tab.
-     */
-    public interface TitleProvider { String getTitle(Tab tab); }
-
-    /**
      * An interface to handle requests about updating TabGridDialog.
      */
     public interface TabGridDialogHandler {
@@ -175,14 +171,14 @@
         static Callback<Bitmap> sBitmapCallbackForTesting;
         static int sFetchCountForTesting;
         private ThumbnailProvider mThumbnailProvider;
-        private Tab mTab;
+        private int mId;
         private boolean mForceUpdate;
         private boolean mWriteToCache;
 
         ThumbnailFetcher(
-                ThumbnailProvider provider, Tab tab, boolean forceUpdate, boolean writeToCache) {
+                ThumbnailProvider provider, int id, boolean forceUpdate, boolean writeToCache) {
             mThumbnailProvider = provider;
-            mTab = tab;
+            mId = id;
             mForceUpdate = forceUpdate;
             mWriteToCache = writeToCache;
         }
@@ -193,9 +189,8 @@
                 callback.onResult(bitmap);
             };
             sFetchCountForTesting++;
-            int tabId = mTab != null ? mTab.getId() : Tab.INVALID_TAB_ID;
             mThumbnailProvider.getTabThumbnailWithCallback(
-                    tabId, forking, mForceUpdate, mWriteToCache);
+                    mId, forking, mForceUpdate, mWriteToCache);
         }
     }
 
@@ -236,7 +231,7 @@
          * If the given {@link Tab} is not able to create group, return null;
          */
         @Nullable
-        TabActionListener openTabGridDialog(Tab tab);
+        TabActionListener openTabGridDialog(@NonNull Tab tab);
 
         /**
          * Run additional actions on tab selection.
@@ -262,15 +257,15 @@
     private final Context mContext;
     private final TabListModel mModel;
     private final TabModelSelector mTabModelSelector;
-    private final ThumbnailProvider mThumbnailProvider;
     private final TabActionListener mTabClosedListener;
-    private final TitleProvider mTitleProvider;
+    private final PseudoTab.TitleProvider mTitleProvider;
     private final SelectionDelegateProvider mSelectionDelegateProvider;
     private final GridCardOnClickListenerProvider mGridCardOnClickListenerProvider;
     private final TabGridDialogHandler mTabGridDialogHandler;
     private final String mComponentName;
+    private final TabListFaviconProvider mTabListFaviconProvider;
 
-    private TabListFaviconProvider mTabListFaviconProvider;
+    private ThumbnailProvider mThumbnailProvider;
     private boolean mActionsOnAllRelatedTabs;
     private ComponentCallbacks mComponentCallbacks;
     private TabGridItemTouchHelperCallback mTabGridItemTouchHelperCallback;
@@ -371,12 +366,13 @@
         public void onTitleUpdated(Tab updatedTab) {
             int index = mModel.indexFromId(updatedTab.getId());
             if (index == TabModel.INVALID_TAB_INDEX) return;
-            mModel.get(index).model.set(TabProperties.TITLE, getLatestTitleForTab(updatedTab));
+            mModel.get(index).model.set(
+                    TabProperties.TITLE, getLatestTitleForTab(PseudoTab.fromTab(updatedTab)));
         }
 
         @Override
         public void onFaviconUpdated(Tab updatedTab, Bitmap icon) {
-            updateFaviconForTab(updatedTab, icon);
+            updateFaviconForTab(PseudoTab.fromTab(updatedTab), icon);
         }
 
         @Override
@@ -392,7 +388,7 @@
             }
 
             if (index == TabModel.INVALID_TAB_INDEX) return;
-            mModel.get(index).model.set(TabProperties.URL, getUrlForTab(tab));
+            mModel.get(index).model.set(TabProperties.URL_DOMAIN, getDomainForTab(tab));
         }
     };
 
@@ -419,7 +415,7 @@
      * @param tabModelSelector {@link TabModelSelector} that will provide and receive signals about
      *                                                 the tabs concerned.
      * @param thumbnailProvider {@link ThumbnailProvider} to provide screenshot related details.
-     * @param titleProvider {@link TitleProvider} for a given tab's title to show.
+     * @param titleProvider {@link PseudoTab.TitleProvider} for a given tab's title to show.
      * @param tabListFaviconProvider Provider for all favicon related drawables.
      * @param actionOnRelatedTabs Whether tab-related actions should be operated on all related
      *                            tabs.
@@ -432,7 +428,8 @@
      * @param uiType The type of UI this mediator should be building.
      */
     public TabListMediator(Context context, TabListModel model, TabModelSelector tabModelSelector,
-            @Nullable ThumbnailProvider thumbnailProvider, @Nullable TitleProvider titleProvider,
+            @Nullable ThumbnailProvider thumbnailProvider,
+            @Nullable PseudoTab.TitleProvider titleProvider,
             TabListFaviconProvider tabListFaviconProvider, boolean actionOnRelatedTabs,
             @Nullable SelectionDelegateProvider selectionDelegateProvider,
             @Nullable GridCardOnClickListenerProvider gridCardOnClickListenerProvider,
@@ -444,7 +441,7 @@
         mModel = model;
         mTabListFaviconProvider = tabListFaviconProvider;
         mComponentName = componentName;
-        mTitleProvider = titleProvider != null ? titleProvider : Tab::getTitle;
+        mTitleProvider = titleProvider;
         mSelectionDelegateProvider = selectionDelegateProvider;
         mGridCardOnClickListenerProvider = gridCardOnClickListenerProvider;
         mTabGridDialogHandler = dialogHandler;
@@ -502,7 +499,7 @@
 
                     assert mModel.indexFromId(currentGroupSelectedTab.getId()) == index;
 
-                    updateTab(index, currentGroupSelectedTab,
+                    updateTab(index, PseudoTab.fromTab(currentGroupSelectedTab),
                             mModel.get(index).model.get(TabProperties.IS_SELECTED), false, false);
                 }
             }
@@ -530,7 +527,7 @@
                     if (mModel.indexFromId(currentGroupSelectedTab.getId()) != index) {
                         return;
                     }
-                    updateTab(index, currentGroupSelectedTab,
+                    updateTab(index, PseudoTab.fromTab(currentGroupSelectedTab),
                             mModel.get(index).model.get(TabProperties.IS_SELECTED), false, false);
                 }
             }
@@ -599,11 +596,12 @@
                                 mTabModelSelector.getTabModelFilterProvider()
                                         .getCurrentTabModelFilter(),
                                 movedTab.getId());
-                        addTabInfoToModel(
-                                movedTab, index, currentSelectedTab.getId() == movedTab.getId());
+                        addTabInfoToModel(PseudoTab.fromTab(movedTab), index,
+                                currentSelectedTab.getId() == movedTab.getId());
                         boolean isSelected = mTabModelSelector.getCurrentTabId()
                                 == filter.getTabAt(prevFilterIndex).getId();
-                        updateTab(prevFilterIndex, filter.getTabAt(prevFilterIndex), isSelected,
+                        updateTab(prevFilterIndex,
+                                PseudoTab.fromTab(filter.getTabAt(prevFilterIndex)), isSelected,
                                 true, false);
                     } else {
                         int curIndex = mModel.indexFromId(movedTab.getId());
@@ -640,7 +638,7 @@
                                                  .getCurrentTabModelFilter()
                                                  .getTabAt(desIndex);
                     boolean isSelected = mTabModelSelector.getCurrentTab() == newSelectedTab;
-                    updateTab(desIndex, newSelectedTab, isSelected, true, false);
+                    updateTab(desIndex, PseudoTab.fromTab(newSelectedTab), isSelected, true, false);
                 }
 
                 @Override
@@ -704,6 +702,9 @@
             public void run(int tabId) {
                 // TODO(crbug.com/990698): Consider disabling all touch events during animation.
                 if (mModel.indexFromId(tabId) == TabModel.INVALID_TAB_INDEX) return;
+                Tab closingTab =
+                        TabModelUtils.getTabById(mTabModelSelector.getCurrentModel(), tabId);
+                if (closingTab == null) return;
 
                 RecordUserAction.record("MobileTabClosed." + mComponentName);
 
@@ -718,8 +719,6 @@
                 onTabClosedFrom(tabId, mComponentName);
 
                 Tab currentTab = mTabModelSelector.getCurrentTab();
-                Tab closingTab =
-                        TabModelUtils.getTabById(mTabModelSelector.getCurrentModel(), tabId);
                 Tab nextTab = currentTab == closingTab ? getNextTab(tabId) : null;
 
                 mTabModelSelector.getCurrentModel().closeTab(
@@ -822,9 +821,9 @@
     }
 
     private List<Tab> getRelatedTabsForId(int id) {
-        return mTabModelSelector.getTabModelFilterProvider()
-                .getCurrentTabModelFilter()
-                .getRelatedTabList(id);
+        TabModelFilter filter =
+                mTabModelSelector.getTabModelFilterProvider().getCurrentTabModelFilter();
+        return filter == null ? new ArrayList<>() : filter.getRelatedTabList(id);
     }
 
     private int getIndexOfTab(Tab tab, boolean onlyShowRelatedTabs) {
@@ -848,7 +847,7 @@
         int index = getIndexOfTab(tab, onlyShowRelatedTabs);
         if (index == TabList.INVALID_TAB_INDEX) return;
 
-        addTabInfoToModel(tab, index, mTabModelSelector.getCurrentTab() == tab);
+        addTabInfoToModel(PseudoTab.fromTab(tab), index, mTabModelSelector.getCurrentTab() == tab);
     }
 
     private void onTabMoved(int newIndex, int curIndex) {
@@ -891,7 +890,7 @@
               + "TabListMediator.prepareOverview()";
     }
 
-    private boolean areTabsUnchanged(@Nullable List<Tab> tabs) {
+    private boolean areTabsUnchanged(@Nullable List<PseudoTab> tabs) {
         int tabsCount = 0;
         for (int i = 0; i < mModel.size(); i++) {
             if (mModel.get(i).model.get(CARD_TYPE) == TAB) {
@@ -902,7 +901,6 @@
             return tabsCount == 0;
         }
         if (tabs.size() != tabsCount) return false;
-
         for (int i = 0; i < tabs.size(); i++) {
             if (mModel.get(i).model.get(CARD_TYPE) == TAB
                     && mModel.get(i).model.get(TabProperties.TAB_ID) != tabs.get(i).getId()) {
@@ -919,8 +917,9 @@
      * @param mruMode Whether to sort the Tabs in MRU order.
      * @return Whether the {@link TabListRecyclerView} can be shown quickly.
      */
-    boolean resetWithListOfTabs(@Nullable List<Tab> tabs, boolean quickMode, boolean mruMode) {
-        List<Tab> tabsList = tabs;
+    boolean resetWithListOfTabs(
+            @Nullable List<PseudoTab> tabs, boolean quickMode, boolean mruMode) {
+        List<PseudoTab> tabsList = tabs;
         if (tabs != null && mruMode) {
             // Make a copy to sort since the input may be unmodifiable.
             tabsList = new ArrayList<>(tabs);
@@ -932,8 +931,8 @@
             if (tabsList == null) return true;
 
             for (int i = 0; i < tabsList.size(); i++) {
-                Tab tab = tabsList.get(i);
-                boolean isSelected = mTabModelSelector.getCurrentTab() == tab;
+                PseudoTab tab = tabsList.get(i);
+                boolean isSelected = mTabModelSelector.getCurrentTabId() == tab.getId();
                 updateTab(i, tab, isSelected, false, quickMode);
             }
             return true;
@@ -942,13 +941,13 @@
         if (tabsList == null) {
             return true;
         }
-        Tab currentTab = mTabModelSelector.getCurrentTab();
-        if (currentTab == null) return false;
+        int currentTabId = mTabModelSelector.getCurrentTabId();
 
         for (int i = 0; i < tabsList.size(); i++) {
-            addTabInfoToModel(
-                    tabsList.get(i), i, isSelectedTab(tabsList.get(i).getId(), currentTab.getId()));
+            PseudoTab tab = tabsList.get(i);
+            addTabInfoToModel(tab, i, isSelectedTab(tab, currentTabId));
         }
+
         return false;
     }
 
@@ -956,12 +955,12 @@
         mVisible = false;
     }
 
-    private boolean isSelectedTab(int tabId, int tabModelSelectedTabId) {
+    private boolean isSelectedTab(PseudoTab tab, int tabModelSelectedTabId) {
         SelectionDelegate<Integer> selectionDelegate = getTabSelectionDelegate();
         if (selectionDelegate == null) {
-            return tabId == tabModelSelectedTabId;
+            return tab.getId() == tabModelSelectedTabId;
         } else {
-            return selectionDelegate.isItemSelected(tabId);
+            return selectionDelegate.isItemSelected(tab.getId());
         }
     }
 
@@ -977,21 +976,27 @@
         }
     }
 
-    private void updateTab(
-            int index, Tab tab, boolean isSelected, boolean isUpdatingId, boolean quickMode) {
+    private void updateTab(int index, PseudoTab pseudoTab, boolean isSelected, boolean isUpdatingId,
+            boolean quickMode) {
         if (index < 0 || index >= mModel.size()) return;
         if (isUpdatingId) {
-            mModel.get(index).model.set(TabProperties.TAB_ID, tab.getId());
+            mModel.get(index).model.set(TabProperties.TAB_ID, pseudoTab.getId());
         } else {
-            assert mModel.get(index).model.get(TabProperties.TAB_ID) == tab.getId();
+            assert mModel.get(index).model.get(TabProperties.TAB_ID) == pseudoTab.getId();
         }
 
+        // TODO(wychen): refactor this.
+        boolean isRealTab = pseudoTab.hasRealTab();
         TabActionListener tabSelectedListener;
-        if (mGridCardOnClickListenerProvider == null || getRelatedTabsForId(tab.getId()).size() == 1
+        if (!isRealTab) {
+            tabSelectedListener = null;
+        } else if (mGridCardOnClickListenerProvider == null
+                || getRelatedTabsForId(pseudoTab.getId()).size() == 1
                 || !mActionsOnAllRelatedTabs) {
             tabSelectedListener = mTabSelectedListener;
         } else {
-            tabSelectedListener = mGridCardOnClickListenerProvider.openTabGridDialog(tab);
+            tabSelectedListener =
+                    mGridCardOnClickListenerProvider.openTabGridDialog(pseudoTab.getTab());
 
             if (tabSelectedListener == null) {
                 tabSelectedListener = mTabSelectedListener;
@@ -999,24 +1004,30 @@
         }
         mModel.get(index).model.set(TabProperties.TAB_SELECTED_LISTENER, tabSelectedListener);
         mModel.get(index).model.set(TabProperties.IS_SELECTED, isSelected);
-        mModel.get(index).model.set(TabProperties.TITLE, getLatestTitleForTab(tab));
-        mModel.get(index).model.set(TabProperties.URL, getUrlForTab(tab));
-
-        if (TabUiFeatureUtilities.ENABLE_SEARCH_CHIP.getValue() && mUiType == UiType.CLOSABLE) {
-            mModel.get(index).model.set(TabProperties.SEARCH_QUERY, getLastSearchTerm(tab));
+        mModel.get(index).model.set(TabProperties.TITLE, getLatestTitleForTab(pseudoTab));
+        if (isRealTab) {
+            mModel.get(index).model.set(
+                    TabProperties.URL_DOMAIN, getDomainForTab(pseudoTab.getTab()));
+        }
+        if (TabUiFeatureUtilities.ENABLE_SEARCH_CHIP.getValue() && mUiType == UiType.CLOSABLE
+                && isRealTab) {
+            mModel.get(index).model.set(
+                    TabProperties.SEARCH_QUERY, getLastSearchTerm(pseudoTab.getTab()));
             mModel.get(index).model.set(TabProperties.SEARCH_LISTENER,
-                    SearchTermChipUtils.getSearchQueryListener(tab, mTabSelectedListener));
+                    SearchTermChipUtils.getSearchQueryListener(
+                            pseudoTab.getTab(), mTabSelectedListener));
             mModel.get(index).model.set(
                     TabProperties.SEARCH_CHIP_ICON_DRAWABLE_ID, mSearchChipIconDrawableId);
         }
 
-        updateFaviconForTab(tab, null);
+        updateFaviconForTab(pseudoTab, null);
         boolean forceUpdate = isSelected && !quickMode;
         if (mThumbnailProvider != null && mVisible
                 && (mModel.get(index).model.get(TabProperties.THUMBNAIL_FETCHER) == null
                         || forceUpdate || isUpdatingId)) {
-            ThumbnailFetcher callback = new ThumbnailFetcher(mThumbnailProvider, tab, forceUpdate,
-                    forceUpdate && !TabUiFeatureUtilities.isTabToGtsAnimationEnabled());
+            ThumbnailFetcher callback =
+                    new ThumbnailFetcher(mThumbnailProvider, pseudoTab.getId(), forceUpdate,
+                            forceUpdate && !TabUiFeatureUtilities.isTabToGtsAnimationEnabled());
             mModel.get(index).model.set(TabProperties.THUMBNAIL_FETCHER, callback);
         }
     }
@@ -1153,46 +1164,53 @@
         }
     }
 
-    private void addTabInfoToModel(final Tab tab, int index, boolean isSelected) {
+    private void addTabInfoToModel(final PseudoTab pseudoTab, int index, boolean isSelected) {
         boolean showIPH = false;
-        if (mActionsOnAllRelatedTabs && !mShownIPH) {
-            showIPH = getRelatedTabsForId(tab.getId()).size() > 1;
+        boolean isRealTab = pseudoTab.hasRealTab();
+        if (mActionsOnAllRelatedTabs && !mShownIPH && isRealTab) {
+            showIPH = getRelatedTabsForId(pseudoTab.getId()).size() > 1;
         }
         TabActionListener tabSelectedListener;
-        if (mGridCardOnClickListenerProvider == null || getRelatedTabsForId(tab.getId()).size() == 1
+        if (!isRealTab) {
+            tabSelectedListener = null;
+        } else if (mGridCardOnClickListenerProvider == null
+                || getRelatedTabsForId(pseudoTab.getId()).size() == 1
                 || !mActionsOnAllRelatedTabs) {
             tabSelectedListener = mTabSelectedListener;
         } else {
-            tabSelectedListener = mGridCardOnClickListenerProvider.openTabGridDialog(tab);
-
+            tabSelectedListener =
+                    mGridCardOnClickListenerProvider.openTabGridDialog(pseudoTab.getTab());
             if (tabSelectedListener == null) {
                 tabSelectedListener = mTabSelectedListener;
             }
         }
 
-        int selectedTabBackgroundDrawableId = tab.isIncognito()
+        int selectedTabBackgroundDrawableId = pseudoTab.isIncognito()
                 ? R.drawable.selected_tab_background_incognito
                 : R.drawable.selected_tab_background;
 
-        int tabstripFaviconBackgroundDrawableId = tab.isIncognito()
+        int tabstripFaviconBackgroundDrawableId = pseudoTab.isIncognito()
                 ? R.color.favicon_background_color_incognito
                 : R.color.favicon_background_color;
-
         PropertyModel tabInfo =
                 new PropertyModel.Builder(TabProperties.ALL_KEYS_TAB_GRID)
-                        .with(TabProperties.TAB_ID, tab.getId())
-                        .with(TabProperties.TITLE, getLatestTitleForTab(tab))
-                        .with(TabProperties.URL, getUrlForTab(tab))
+                        .with(TabProperties.TAB_ID, pseudoTab.getId())
+                        .with(TabProperties.TITLE, getLatestTitleForTab(pseudoTab))
+                        .with(TabProperties.URL_DOMAIN,
+                                isRealTab ? getDomainForTab(pseudoTab.getTab()) : null)
                         .with(TabProperties.FAVICON,
                                 mTabListFaviconProvider.getDefaultFaviconDrawable(
-                                        tab.isIncognito()))
+                                        pseudoTab.isIncognito()))
                         .with(TabProperties.IS_SELECTED, isSelected)
                         .with(TabProperties.IPH_PROVIDER, showIPH ? mIphProvider : null)
                         .with(CARD_ALPHA, 1f)
+                        .with(TabProperties.TAB_CLOSED_LISTENER,
+                                isRealTab ? mTabClosedListener : null)
                         .with(TabProperties.CARD_ANIMATION_STATUS,
                                 ClosableTabGridView.AnimationStatus.CARD_RESTORE)
-                        .with(TabProperties.TAB_SELECTION_DELEGATE, getTabSelectionDelegate())
-                        .with(TabProperties.IS_INCOGNITO, tab.isIncognito())
+                        .with(TabProperties.TAB_SELECTION_DELEGATE,
+                                isRealTab ? getTabSelectionDelegate() : null)
+                        .with(TabProperties.IS_INCOGNITO, pseudoTab.isIncognito())
                         .with(TabProperties.SELECTED_TAB_BACKGROUND_DRAWABLE_ID,
                                 selectedTabBackgroundDrawableId)
                         .with(TabProperties.TABSTRIP_FAVICON_BACKGROUND_COLOR_ID,
@@ -1201,10 +1219,12 @@
                         .with(CARD_TYPE, TAB)
                         .build();
 
-        if (TabUiFeatureUtilities.ENABLE_SEARCH_CHIP.getValue() && mUiType == UiType.CLOSABLE) {
-            tabInfo.set(TabProperties.SEARCH_QUERY, getLastSearchTerm(tab));
+        if (TabUiFeatureUtilities.ENABLE_SEARCH_CHIP.getValue() && mUiType == UiType.CLOSABLE
+                && isRealTab) {
+            tabInfo.set(TabProperties.SEARCH_QUERY, getLastSearchTerm(pseudoTab.getTab()));
             tabInfo.set(TabProperties.SEARCH_LISTENER,
-                    SearchTermChipUtils.getSearchQueryListener(tab, mTabSelectedListener));
+                    SearchTermChipUtils.getSearchQueryListener(
+                            pseudoTab.getTab(), mTabSelectedListener));
             tabInfo.set(TabProperties.SEARCH_CHIP_ICON_DRAWABLE_ID, mSearchChipIconDrawableId);
         }
 
@@ -1213,18 +1233,18 @@
             // Non-incognito mode and incognito in both light/dark themes in dark theme all look
             // dark.
             ColorStateList checkedDrawableColorList = AppCompatResources.getColorStateList(mContext,
-                    tab.isIncognito() ? R.color.default_icon_color_dark
-                                      : R.color.default_icon_color_inverse);
+                    pseudoTab.isIncognito() ? R.color.default_icon_color_dark
+                                            : R.color.default_icon_color_inverse);
             ColorStateList actionButtonBackgroundColorList =
                     AppCompatResources.getColorStateList(mContext,
-                            tab.isIncognito() ? R.color.default_icon_color_light
-                                              : R.color.default_icon_color);
+                            pseudoTab.isIncognito() ? R.color.default_icon_color_light
+                                                    : R.color.default_icon_color);
             // TODO(995876): Update color modern_blue_300 to active_color_dark when the associated
             // bug is landed.
             ColorStateList actionbuttonSelectedBackgroundColorList =
                     AppCompatResources.getColorStateList(mContext,
-                            tab.isIncognito() ? R.color.modern_blue_300
-                                              : R.color.light_active_color);
+                            pseudoTab.isIncognito() ? R.color.modern_blue_300
+                                                    : R.color.light_active_color);
 
             tabInfo.set(TabProperties.CHECKED_DRAWABLE_STATE_LIST, checkedDrawableColorList);
             tabInfo.set(TabProperties.SELECTABLE_TAB_ACTION_BUTTON_BACKGROUND,
@@ -1244,16 +1264,17 @@
             mModel.add(index, new SimpleRecyclerViewAdapter.ListItem(mUiType, tabInfo));
         }
 
-        updateFaviconForTab(tab, null);
+        updateFaviconForTab(pseudoTab, null);
 
         if (mThumbnailProvider != null && mVisible) {
-            ThumbnailFetcher callback = new ThumbnailFetcher(mThumbnailProvider, tab, isSelected,
-                    isSelected && !TabUiFeatureUtilities.isTabToGtsAnimationEnabled());
+            ThumbnailFetcher callback = new ThumbnailFetcher(mThumbnailProvider, pseudoTab.getId(),
+                    isSelected, isSelected && !TabUiFeatureUtilities.isTabToGtsAnimationEnabled());
             tabInfo.set(TabProperties.THUMBNAIL_FETCHER, callback);
         }
-        tab.addObserver(mTabObserver);
+        if (pseudoTab.getTab() != null) pseudoTab.getTab().addObserver(mTabObserver);
     }
 
+    // TODO(wychen): make this work with PseudoTab.
     private String getLastSearchTerm(Tab tab) {
         assert TabUiFeatureUtilities.ENABLE_SEARCH_CHIP.getValue();
         if (mActionsOnAllRelatedTabs && TabUiFeatureUtilities.isTabGroupsAndroidEnabled()
@@ -1275,26 +1296,28 @@
         return iconDrawableId;
     }
 
-    private String getUrlForTab(Tab tab) {
+    // TODO(wychen): make this work with PseudoTab.
+    private String getDomainForTab(Tab tab) {
         if (!TabUiFeatureUtilities.isTabGroupsAndroidContinuationEnabled()) return "";
-        if (!mActionsOnAllRelatedTabs) return tab.getUrlString();
+        if (!mActionsOnAllRelatedTabs) return getDomain(tab);
 
         List<Tab> relatedTabs = getRelatedTabsForId(tab.getId());
-        if (relatedTabs.size() == 1) return tab.getUrlString();
 
-        StringBuilder builder = new StringBuilder();
-        // TODO(1024925): Address i18n issue for the list separator.
-        String separator = ", ";
+        List<String> domainNames = new ArrayList<>();
+
         for (int i = 0; i < relatedTabs.size(); i++) {
-            String domain =
-                    UrlUtilities.getDomainAndRegistry(relatedTabs.get(i).getUrlString(), false);
-            if (!domain.isEmpty()) {
-                builder.append(domain);
-
-                if (i < relatedTabs.size() - 1) builder.append(separator);
-            }
+            String domain = getDomain(relatedTabs.get(i));
+            domainNames.add(domain);
         }
-        return builder.toString();
+        // TODO(1024925): Address i18n issue for the list delimiter.
+        return TextUtils.join(", ", domainNames);
+    }
+
+    private String getDomain(Tab tab) {
+        String domain = UrlUtilities.getDomainAndRegistry(tab.getUrlString(), false);
+
+        if (domain.isEmpty()) return tab.getUrlString();
+        return domain;
     }
 
     @Nullable
@@ -1305,14 +1328,14 @@
     }
 
     @VisibleForTesting
-    String getLatestTitleForTab(Tab tab) {
-        String originalTitle = mTitleProvider.getTitle(tab);
+    String getLatestTitleForTab(PseudoTab pseudoTab) {
+        String originalTitle = pseudoTab.getTitle(mTitleProvider);
         if (!mActionsOnAllRelatedTabs || mTabGroupTitleEditor == null) return originalTitle;
         // If the group degrades to a single tab, delete the stored title.
-        if (getRelatedTabsForId(tab.getId()).size() <= 1) {
+        if (getRelatedTabsForId(pseudoTab.getId()).size() <= 1) {
             return originalTitle;
         }
-        String storedTitle = mTabGroupTitleEditor.getTabGroupTitle(((TabImpl) tab).getRootId());
+        String storedTitle = mTabGroupTitleEditor.getTabGroupTitle(pseudoTab.getRootId());
         return storedTitle == null ? originalTitle : storedTitle;
     }
 
@@ -1337,10 +1360,10 @@
     }
 
     @VisibleForTesting
-    void updateFaviconForTab(Tab tab, @Nullable Bitmap icon) {
-        int modelIndex = mModel.indexFromId(tab.getId());
+    void updateFaviconForTab(PseudoTab pseudoTab, @Nullable Bitmap icon) {
+        int modelIndex = mModel.indexFromId(pseudoTab.getId());
         if (modelIndex == Tab.INVALID_TAB_ID) return;
-        List<Tab> relatedTabList = getRelatedTabsForId(tab.getId());
+        List<Tab> relatedTabList = getRelatedTabsForId(pseudoTab.getId());
 
         if (mActionsOnAllRelatedTabs && relatedTabList.size() > 1) {
             if (!TabUiFeatureUtilities.isTabGroupsAndroidContinuationEnabled()) {
@@ -1351,22 +1374,21 @@
 
             // The order of the url list matches the multi-thumbnail.
             List<String> urls = new ArrayList<>();
-            urls.add(tab.getUrlString());
+            urls.add(pseudoTab.getUrl());
             for (int i = 0; urls.size() < 4 && i < relatedTabList.size(); i++) {
-                if (tab.getId() == relatedTabList.get(i).getId()) continue;
+                if (pseudoTab.getId() == relatedTabList.get(i).getId()) continue;
                 urls.add(relatedTabList.get(i).getUrlString());
             }
 
             // For tab group card in grid tab switcher, the favicon is the composed favicon.
             mTabListFaviconProvider.getComposedFaviconImageAsync(
-                    urls, tab.isIncognito(), (drawable) -> {
+                    urls, pseudoTab.isIncognito(), (drawable) -> {
                         assert drawable != null;
                         mModel.get(modelIndex).model.set(TabProperties.FAVICON, drawable);
                     });
 
             return;
         }
-
         if (!mTabListFaviconProvider.isInitialized()) {
             return;
         }
@@ -1374,7 +1396,7 @@
         // If there is an available icon, we fetch favicon synchronously; otherwise asynchronously.
         if (icon != null) {
             Drawable drawable = mTabListFaviconProvider.getFaviconForUrlSync(
-                    tab.getUrlString(), tab.isIncognito(), icon);
+                    pseudoTab.getUrl(), pseudoTab.isIncognito(), icon);
             mModel.get(modelIndex).model.set(TabProperties.FAVICON, drawable);
             return;
         }
@@ -1382,13 +1404,13 @@
             assert drawable != null;
             // Need to re-get the index because the original index can be stale when callback is
             // triggered.
-            int index = mModel.indexFromId(tab.getId());
+            int index = mModel.indexFromId(pseudoTab.getId());
             if (index != Tab.INVALID_TAB_ID && drawable != null) {
                 mModel.get(index).model.set(TabProperties.FAVICON, drawable);
             }
         };
         mTabListFaviconProvider.getFaviconForUrlAsync(
-                tab.getUrlString(), tab.isIncognito(), faviconCallback);
+                pseudoTab.getUrl(), pseudoTab.isIncognito(), faviconCallback);
     }
 
     /**
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewBinder.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewBinder.java
index 7ff5293..eaa3706 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewBinder.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewBinder.java
@@ -71,9 +71,9 @@
                 int tabId = model.get(TabProperties.TAB_ID);
                 model.get(TabProperties.TAB_SELECTED_LISTENER).run(tabId);
             });
-        } else if (TabProperties.URL == propertyKey) {
-            String title = model.get(TabProperties.URL);
-            ((TextView) fastView.findViewById(R.id.description)).setText(title);
+        } else if (TabProperties.URL_DOMAIN == propertyKey) {
+            String domain = model.get(TabProperties.URL_DOMAIN);
+            ((TextView) fastView.findViewById(R.id.description)).setText(domain);
         }
     }
 
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabProperties.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabProperties.java
index 810a88de..62b3f25 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabProperties.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabProperties.java
@@ -93,7 +93,8 @@
             SELECTABLE_TAB_ACTION_BUTTON_SELECTED_BACKGROUND =
             new PropertyModel.WritableObjectPropertyKey<>();
 
-    public static final WritableObjectPropertyKey<String> URL = new WritableObjectPropertyKey<>();
+    public static final WritableObjectPropertyKey<String> URL_DOMAIN =
+            new WritableObjectPropertyKey<>();
 
     public static final PropertyModel
             .WritableObjectPropertyKey<AccessibilityDelegate> ACCESSIBILITY_DELEGATE =
@@ -114,7 +115,7 @@
             CARD_ANIMATION_STATUS, SELECTABLE_TAB_CLICKED_LISTENER, TAB_SELECTION_DELEGATE,
             IS_INCOGNITO, SELECTED_TAB_BACKGROUND_DRAWABLE_ID, TABSTRIP_FAVICON_BACKGROUND_COLOR_ID,
             SELECTABLE_TAB_ACTION_BUTTON_BACKGROUND,
-            SELECTABLE_TAB_ACTION_BUTTON_SELECTED_BACKGROUND, URL, ACCESSIBILITY_DELEGATE,
+            SELECTABLE_TAB_ACTION_BUTTON_SELECTED_BACKGROUND, URL_DOMAIN, ACCESSIBILITY_DELEGATE,
             SEARCH_QUERY, SEARCH_LISTENER, SEARCH_CHIP_ICON_DRAWABLE_ID, CARD_TYPE};
 
     public static final PropertyKey[] ALL_KEYS_TAB_STRIP =
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java
index 216dde8..4ef3e00a 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java
@@ -27,10 +27,10 @@
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.lifecycle.Destroyable;
 import org.chromium.chrome.browser.share.ShareDelegate;
-import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
 import org.chromium.chrome.browser.tabmodel.TabList;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
+import org.chromium.chrome.browser.tasks.pseudotab.PseudoTab;
 import org.chromium.chrome.browser.tasks.pseudotab.TabAttributeCache;
 import org.chromium.chrome.browser.tasks.tab_management.suggestions.TabSuggestionsOrchestrator;
 import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
@@ -41,7 +41,6 @@
 import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
 import org.chromium.ui.resources.dynamics.DynamicResourceLoader;
 
-import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -112,11 +111,10 @@
         mMultiThumbnailCardProvider =
                 new MultiThumbnailCardProvider(context, tabContentManager, tabModelSelector);
 
-        TabListMediator.TitleProvider titleProvider = tab -> {
-            int numRelatedTabs = tabModelSelector.getTabModelFilterProvider()
-                                         .getCurrentTabModelFilter()
-                                         .getRelatedTabList(tab.getId())
-                                         .size();
+        PseudoTab.TitleProvider titleProvider = tab -> {
+            int numRelatedTabs =
+                    PseudoTab.getRelatedTabs(tab, tabModelSelector.getTabModelFilterProvider())
+                            .size();
             if (numRelatedTabs == 1) return tab.getTitle();
             return context.getResources().getQuantityString(
                     R.plurals.bottom_tab_grid_title_placeholder, numRelatedTabs, numRelatedTabs);
@@ -158,8 +156,9 @@
             }
         }
 
-        if (TabUiFeatureUtilities.ENABLE_SEARCH_CHIP.getValue()
-                && mode != TabListCoordinator.TabListMode.CAROUSEL) {
+        if (CachedFeatureFlags.isEnabled(ChromeFeatureList.INSTANT_START)
+                || TabUiFeatureUtilities.ENABLE_SEARCH_CHIP.getValue()
+                        && mode != TabListCoordinator.TabListMode.CAROUSEL) {
             mTabAttributeCache = new TabAttributeCache(mTabModelSelector);
         }
 
@@ -334,14 +333,12 @@
     // ResetHandler implementation.
     @Override
     public boolean resetWithTabList(@Nullable TabList tabList, boolean quickMode, boolean mruMode) {
-        List<Tab> tabs = null;
-        if (tabList != null) {
-            tabs = new ArrayList<>();
-            for (int i = 0; i < tabList.getCount(); i++) {
-                tabs.add(tabList.getTabAt(i));
-            }
-        }
+        return resetWithTabs(PseudoTab.getListOfPseudoTab(tabList), quickMode, mruMode);
+    }
 
+    @Override
+    public boolean resetWithTabs(
+            @Nullable List<PseudoTab> tabs, boolean quickMode, boolean mruMode) {
         mMediator.registerFirstMeaningfulPaintRecorder();
         boolean showQuickly = mTabListCoordinator.resetWithListOfTabs(tabs, quickMode, mruMode);
         if (showQuickly) {
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java
index 570fb92..9fac07d8 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java
@@ -24,16 +24,20 @@
 
 import org.chromium.base.Log;
 import org.chromium.base.ObserverList;
+import org.chromium.base.StreamUtil;
+import org.chromium.base.StrictModeContext;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.base.task.PostTask;
 import org.chromium.chrome.browser.compositor.layouts.LayoutManager;
 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
+import org.chromium.chrome.browser.flags.CachedFeatureFlags;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
 import org.chromium.chrome.browser.fullscreen.FullscreenManager;
 import org.chromium.chrome.browser.init.FirstDrawDetector;
+import org.chromium.chrome.browser.ntp.NewTabPage;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabCreationState;
 import org.chromium.chrome.browser.tab.TabSelectionType;
@@ -46,13 +50,24 @@
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver;
 import org.chromium.chrome.browser.tabmodel.TabModelUtils;
+import org.chromium.chrome.browser.tabmodel.TabPersistentStore;
+import org.chromium.chrome.browser.tabmodel.TabbedModeTabPersistencePolicy;
 import org.chromium.chrome.browser.tasks.ReturnToChromeExperimentsUtil;
+import org.chromium.chrome.browser.tasks.pseudotab.PseudoTab;
 import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilter;
 import org.chromium.chrome.features.start_surface.StartSurfaceConfiguration;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
 import org.chromium.ui.modelutil.PropertyModel;
 
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 /**
  * The Mediator that is responsible for resetting the tab grid or carousel based on visibility and
@@ -146,6 +161,15 @@
         boolean resetWithTabList(@Nullable TabList tabList, boolean quickMode, boolean mruMode);
 
         /**
+         * Reset the tab grid with the given {@link List<PseudoTab>}, which can be null.
+         * @param tabs The {@link List<PseudoTab>} to show the tabs for in the grid.
+         * @param quickMode Whether to skip capturing the selected live tab for the thumbnail.
+         * @param mruMode Whether order the Tabs by MRU.
+         * @return Whether the {@link TabListRecyclerView} can be shown quickly.
+         */
+        boolean resetWithTabs(@Nullable List<PseudoTab> tabs, boolean quickMode, boolean mruMode);
+
+        /**
          * Release the thumbnail {@link Bitmap} but keep the {@link TabGridView}.
          */
         void softCleanup();
@@ -210,11 +234,23 @@
         mTabModelObserver = new EmptyTabModelObserver() {
             @Override
             public void didAddTab(Tab tab, int type, @TabCreationState int creationState) {
+                // TODO(wychen): move didAddTab and didSelectTab to another observer and inject
+                //  after restoreCompleted.
+                if (!mTabModelSelector.getTabModelFilterProvider()
+                                .getCurrentTabModelFilter()
+                                .isTabModelRestored()) {
+                    return;
+                }
                 mShouldIgnoreNextSelect = false;
             }
 
             @Override
             public void didSelectTab(Tab tab, int type, int lastId) {
+                if (!mTabModelSelector.getTabModelFilterProvider()
+                                .getCurrentTabModelFilter()
+                                .isTabModelRestored()) {
+                    return;
+                }
                 if (type == TabSelectionType.FROM_CLOSE || mShouldIgnoreNextSelect) {
                     mShouldIgnoreNextSelect = false;
                     return;
@@ -243,6 +279,7 @@
                 mResetHandler.resetWithTabList(
                         mTabModelSelector.getTabModelFilterProvider().getCurrentTabModelFilter(),
                         false, mShowTabsInMruOrder);
+                recordTabCounts();
                 setInitialScrollIndexOffset();
             }
 
@@ -285,7 +322,11 @@
         };
 
         mFullscreenManager.addListener(mFullscreenListener);
-        mTabModelSelector.getTabModelFilterProvider().addTabModelFilterObserver(mTabModelObserver);
+
+        if (!mTabModelSelector.getModels().isEmpty()) {
+            mTabModelSelector.getTabModelFilterProvider().addTabModelFilterObserver(
+                    mTabModelObserver);
+        }
 
         mContainerViewModel.set(VISIBILITY_LISTENER, this);
         TabModelFilter tabModelFilter =
@@ -529,20 +570,81 @@
 
     @Override
     public void showOverview(boolean animate) {
-        if (mTabModelSelector.getTabModelFilterProvider()
-                        .getCurrentTabModelFilter()
-                        .isTabModelRestored()) {
+        if (mTabModelSelector.getTabModelFilterProvider().getCurrentTabModelFilter() != null
+                && mTabModelSelector.getTabModelFilterProvider()
+                           .getCurrentTabModelFilter()
+                           .isTabModelRestored()) {
             mResetHandler.resetWithTabList(
                     mTabModelSelector.getTabModelFilterProvider().getCurrentTabModelFilter(),
                     TabUiFeatureUtilities.isTabToGtsAnimationEnabled(), mShowTabsInMruOrder);
+            recordTabCounts();
+        } else if (CachedFeatureFlags.isEnabled(ChromeFeatureList.INSTANT_START)) {
+            List<PseudoTab> allRootTabs;
+            try (StrictModeContext ignored = StrictModeContext.allowDiskReads()) {
+                allRootTabs = getAllPseudoTabsFromStateFile();
+            }
+            mResetHandler.resetWithTabs(allRootTabs,
+                    TabUiFeatureUtilities.isTabToGtsAnimationEnabled(), mShowTabsInMruOrder);
         }
+
         if (!animate) mContainerViewModel.set(ANIMATE_VISIBILITY_CHANGES, false);
         setVisibility(true);
         mModelIndexWhenShown = mTabModelSelector.getCurrentModelIndex();
         mTabIdWhenShown = mTabModelSelector.getCurrentTabId();
         mContainerViewModel.set(ANIMATE_VISIBILITY_CHANGES, true);
+    }
 
-        recordTabCounts();
+    private static List<PseudoTab> getAllPseudoTabsFromStateFile() {
+        long startMs = SystemClock.elapsedRealtime();
+        File stateFile =
+                new File(TabbedModeTabPersistencePolicy.getOrCreateTabbedModeStateDirectory(),
+                        TabbedModeTabPersistencePolicy.getStateFileName(0));
+        if (!stateFile.exists()) {
+            Log.i(TAG, "State file does not exist.");
+            return null;
+        }
+        FileInputStream stream = null;
+        byte[] data;
+        try {
+            stream = new FileInputStream(stateFile);
+            data = new byte[(int) stateFile.length()];
+            stream.read(data);
+        } catch (IOException exception) {
+            Log.e(TAG, "Could not read state file.", exception);
+            return null;
+        } finally {
+            StreamUtil.closeQuietly(stream);
+        }
+        Log.i(TAG, "Finished fetching tab list.");
+        DataInputStream dataStream = new DataInputStream(new ByteArrayInputStream(data));
+
+        Set<Integer> seenRootId = new HashSet<>();
+        List<PseudoTab> allTabs = new ArrayList<>();
+        try {
+            TabPersistentStore.readSavedStateFile(dataStream,
+                    (index, id, url, isIncognito, isStandardActiveIndex, isIncognitoActiveIndex)
+                            -> {
+                        // Skip restoring of non-selected NTP to match the real restoration logic.
+                        if (NewTabPage.isNTPUrl(url) && !isStandardActiveIndex) return;
+                        PseudoTab tab = PseudoTab.fromTabId(id);
+                        int rootId = tab.getRootId();
+                        if (TabUiFeatureUtilities.isTabGroupsAndroidEnabled()
+                                && seenRootId.contains(rootId)) {
+                            return;
+                        }
+                        allTabs.add(tab);
+                        seenRootId.add(rootId);
+                    },
+                    null, false);
+        } catch (IOException exception) {
+            Log.e(TAG, "Could not read state file.", exception);
+            return null;
+        }
+
+        Log.d(TAG, "All pre-native tabs: " + allTabs);
+        Log.d(TAG, "getAllPseudoTabsFromStateFile() took %dms",
+                SystemClock.elapsedRealtime() - startMs);
+        return allTabs;
     }
 
     @Override
@@ -665,7 +767,9 @@
     @Override
     public void onTabSelecting(int tabId) {
         mIsSelectingInTabSwitcher = true;
-        mOnTabSelectingListener.onTabSelecting(LayoutManager.time(), tabId);
+        if (mOnTabSelectingListener != null) {
+            mOnTabSelectingListener.onTabSelecting(LayoutManager.time(), tabId);
+        }
     }
 
     private boolean ableToOpenDialog(Tab tab) {
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphTest.java
index 3c77338..27da5c99 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphTest.java
@@ -54,7 +54,6 @@
 import org.chromium.chrome.tab_ui.R;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
-import org.chromium.chrome.test.util.ApplicationTestUtils;
 import org.chromium.chrome.test.util.ChromeRenderTestRule;
 import org.chromium.chrome.test.util.ChromeTabUtils;
 import org.chromium.chrome.test.util.browser.Features;
@@ -139,7 +138,7 @@
         onView(withId(R.id.tab_grid_message_item)).check(matches(isDisplayed()));
 
         // Restart chrome to verify that IPH message card is still there.
-        ApplicationTestUtils.finishActivity(mActivityTestRule.getActivity());
+        TabUiTestHelper.finishActivity(mActivityTestRule.getActivity());
         mActivityTestRule.startMainActivityFromLauncher();
         cta = mActivityTestRule.getActivity();
         enterTabSwitcher(cta);
@@ -153,7 +152,7 @@
         onView(withId(R.id.tab_grid_message_item)).check(doesNotExist());
 
         // Restart chrome to verify that IPH message card no longer shows.
-        ApplicationTestUtils.finishActivity(mActivityTestRule.getActivity());
+        TabUiTestHelper.finishActivity(mActivityTestRule.getActivity());
         mActivityTestRule.startMainActivityFromLauncher();
         cta = mActivityTestRule.getActivity();
         enterTabSwitcher(cta);
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java
index be94c862..c891de6 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java
@@ -79,7 +79,7 @@
                     callback.onResult(bitmap);
                     mThumbnailFetchedCount.incrementAndGet();
                 }
-            }, null, false, false);
+            }, Tab.INVALID_TAB_ID, false, false);
     private AtomicInteger mThumbnailFetchedCount = new AtomicInteger();
 
     private TabListMediator.TabActionListener mMockCloseListener =
@@ -463,6 +463,7 @@
     public void testClickToClose() {
         ImageView actionButton = mTabGridView.findViewById(R.id.action_button);
         ImageButton button = mTabStripView.findViewById(R.id.tab_strip_item_button);
+
         Assert.assertFalse(mCloseClicked.get());
         actionButton.performClick();
         Assert.assertTrue(mCloseClicked.get());
@@ -479,6 +480,10 @@
         Assert.assertEquals(TAB2_ID, secondClosed);
         Assert.assertNotEquals(firstCloseId, secondClosed);
 
+        mGridModel.set(TabProperties.TAB_CLOSED_LISTENER, null);
+        actionButton.performClick();
+        Assert.assertFalse(mCloseClicked.get());
+
         mStripModel.set(TabProperties.IS_SELECTED, true);
         button.performClick();
         Assert.assertTrue(mCloseClicked.get());
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabUiTestHelper.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabUiTestHelper.java
index 97e31b4..1333a57 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabUiTestHelper.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabUiTestHelper.java
@@ -24,6 +24,7 @@
 import static org.chromium.content_public.browser.test.util.CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL;
 import static org.chromium.content_public.browser.test.util.CriteriaHelper.DEFAULT_POLLING_INTERVAL;
 
+import android.app.Activity;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.os.Build;
@@ -56,10 +57,12 @@
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabSelectionType;
 import org.chromium.chrome.browser.tabmodel.TabModel;
+import org.chromium.chrome.browser.tasks.pseudotab.PseudoTab;
 import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilter;
 import org.chromium.chrome.browser.widget.ScrimView;
 import org.chromium.chrome.tab_ui.R;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.chrome.test.util.ApplicationTestUtils;
 import org.chromium.chrome.test.util.ChromeTabUtils;
 import org.chromium.chrome.test.util.OverviewModeBehaviorWatcher;
 import org.chromium.content_public.browser.test.util.Criteria;
@@ -579,6 +582,12 @@
         }
     }
 
+    /** Finishes the given activity and do tab_ui-specific cleanup. */
+    public static void finishActivity(final Activity activity) throws Exception {
+        ApplicationTestUtils.finishActivity(activity);
+        PseudoTab.clearForTesting();
+    }
+
     /**
      * Implementation of {@link ViewAssertion} to verify the {@link RecyclerView} has correct number
      * of children.
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediatorUnitTest.java
index 2f78a6d54..6f25506 100644
--- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediatorUnitTest.java
+++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediatorUnitTest.java
@@ -433,6 +433,7 @@
         // Mock that the animation source view is not null.
         mModel.set(TabGridPanelProperties.ANIMATION_SOURCE_VIEW, mView);
 
+        doReturn(true).when(mTabGroupModelFilter).isTabModelRestored();
         mTabModelObserverCaptor.getValue().didAddTab(
                 newTab, TabLaunchType.FROM_CHROME_UI, TabCreationState.LIVE_IN_FOREGROUND);
 
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java
index e747f54..e3a4061 100644
--- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java
+++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java
@@ -97,6 +97,7 @@
 import org.chromium.chrome.browser.tabmodel.TabModelFilterProvider;
 import org.chromium.chrome.browser.tabmodel.TabModelObserver;
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl;
+import org.chromium.chrome.browser.tasks.pseudotab.PseudoTab;
 import org.chromium.chrome.browser.tasks.pseudotab.TabAttributeCache;
 import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilter;
 import org.chromium.chrome.browser.tasks.tab_management.TabProperties.UiType;
@@ -209,7 +210,7 @@
     @Mock
     Tracker mTracker;
     @Mock
-    TabListMediator.TitleProvider mTitleProvider;
+    PseudoTab.TitleProvider mTitleProvider;
     @Mock
     UrlUtilities.Natives mUrlUtilitiesJniMock;
     @Mock
@@ -330,6 +331,7 @@
     public void tearDown() {
         RecordHistogram.setDisabledForTests(false);
         CachedFeatureFlags.setForTesting(ChromeFeatureList.START_SURFACE_ANDROID, null);
+        PseudoTab.clearForTesting();
         TabAttributeCache.clearAllForTesting();
         getGroupTitleSharedPreferences().edit().clear();
     }
@@ -350,7 +352,7 @@
 
         assertThat(mModel.get(0).model.get(TabProperties.TITLE), equalTo(TAB1_TITLE));
 
-        doReturn(NEW_TITLE).when(mTitleProvider).getTitle(mTab1);
+        when(mTitleProvider.getTitle(PseudoTab.fromTab(mTab1))).thenReturn(NEW_TITLE);
         mTabObserverCaptor.getValue().onTitleUpdated(mTab1);
 
         assertThat(mModel.get(0).model.get(TabProperties.TITLE), equalTo(NEW_TITLE));
@@ -424,7 +426,7 @@
         mModel.get(0).model.set(TabProperties.FAVICON, null);
         mModel.get(1).model.set(TabProperties.FAVICON, null);
 
-        mMediator.updateFaviconForTab(mTab2, null);
+        mMediator.updateFaviconForTab(PseudoTab.fromTab(mTab2), null);
         assertThat(mModel.indexFromId(TAB2_ID), equalTo(1));
         // Before executing callback, there is a deletion in tab list model which makes the index
         // stale.
@@ -846,7 +848,7 @@
 
         // Assume that two tabs are in the same group before ungroup.
         List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab2));
-        mMediator.resetWithListOfTabs(tabs, false, false);
+        mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false, false);
 
         assertThat(mModel.size(), equalTo(1));
         assertThat(mModel.get(0).model.get(TabProperties.TAB_ID), equalTo(TAB2_ID));
@@ -874,7 +876,7 @@
 
         // Assume that two tabs are in the same group before ungroup.
         List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1));
-        mMediator.resetWithListOfTabs(tabs, false, false);
+        mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false, false);
 
         assertThat(mModel.size(), equalTo(1));
         assertThat(mModel.get(0).model.get(TabProperties.TAB_ID), equalTo(TAB1_ID));
@@ -902,7 +904,7 @@
 
         // Assume that tab1 is a single tab.
         List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1));
-        mMediator.resetWithListOfTabs(tabs, false, false);
+        mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false, false);
         doReturn(1).when(mTabGroupModelFilter).getCount();
         doReturn(mTab1).when(mTabGroupModelFilter).getTabAt(POSITION1);
         doReturn(tabs).when(mTabGroupModelFilter).getRelatedTabList(TAB1_ID);
@@ -942,7 +944,7 @@
 
         // Assume that tab1 is a single tab.
         List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1));
-        mMediator.resetWithListOfTabs(tabs, false, false);
+        mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false, false);
         doReturn(1).when(mTabGroupModelFilter).getCount();
         doReturn(mTab1).when(mTabGroupModelFilter).getTabAt(POSITION1);
         doReturn(tabs).when(mTabGroupModelFilter).getRelatedTabList(TAB1_ID);
@@ -1099,7 +1101,7 @@
         // Assume there are 3 tabs in TabModel, mTab2 just grouped with mTab1;
         Tab tab3 = prepareTab(TAB3_ID, TAB3_TITLE, TAB3_URL);
         List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1, tab3));
-        mMediator.resetWithListOfTabs(tabs, false, false);
+        mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false, false);
         assertThat(mModel.size(), equalTo(2));
 
         // Assume undo grouping mTab2 with mTab1.
@@ -1123,7 +1125,7 @@
         // Assume there are 3 tabs in TabModel, tab3 just grouped with mTab1;
         Tab tab3 = prepareTab(TAB3_ID, TAB3_TITLE, TAB3_URL);
         List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1, mTab2));
-        mMediator.resetWithListOfTabs(tabs, false, false);
+        mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false, false);
         assertThat(mModel.size(), equalTo(2));
 
         // Assume undo grouping tab3 with mTab1.
@@ -1147,7 +1149,7 @@
         // Assume there are 3 tabs in TabModel, mTab1 just grouped with mTab2;
         Tab tab3 = prepareTab(TAB3_ID, TAB3_TITLE, TAB3_URL);
         List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab2, tab3));
-        mMediator.resetWithListOfTabs(tabs, false, false);
+        mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false, false);
         assertThat(mModel.size(), equalTo(2));
 
         // Assume undo grouping tab3 with mTab1.
@@ -1224,7 +1226,8 @@
         long timestamp2 = 2;
         doReturn(timestamp1).when(mTab1).getTimestampMillis();
         doReturn(timestamp2).when(mTab2).getTimestampMillis();
-        mMediator.resetWithListOfTabs(tabs, /*quickMode =*/false, /*mruMode =*/true);
+        mMediator.resetWithListOfTabs(
+                PseudoTab.getListOfPseudoTab(tabs), /*quickMode =*/false, /*mruMode =*/true);
 
         assertThat(mModel.size(), equalTo(2));
         assertThat(mModel.get(0).model.get(TabProperties.TAB_ID), equalTo(TAB2_ID));
@@ -1234,7 +1237,8 @@
 
         doReturn(timestamp2).when(mTab1).getTimestampMillis();
         doReturn(timestamp1).when(mTab2).getTimestampMillis();
-        mMediator.resetWithListOfTabs(tabs, /*quickMode =*/false, /*mruMode =*/true);
+        mMediator.resetWithListOfTabs(
+                PseudoTab.getListOfPseudoTab(tabs), /*quickMode =*/false, /*mruMode =*/true);
 
         assertThat(mModel.size(), equalTo(2));
         assertThat(mModel.get(0).model.get(TabProperties.TAB_ID), equalTo(TAB1_ID));
@@ -1260,7 +1264,7 @@
         createTabGroup(tabs, TAB1_ID);
 
         // Even if we have a stored title, we only show it in tab switcher.
-        assertThat(mMediator.getLatestTitleForTab(mTab1), equalTo(TAB1_TITLE));
+        assertThat(mMediator.getLatestTitleForTab(PseudoTab.fromTab(mTab1)), equalTo(TAB1_TITLE));
     }
 
     @Test
@@ -1280,7 +1284,7 @@
         createTabGroup(tabs, TAB1_ID);
 
         // We never show stored title for single tab.
-        assertThat(mMediator.getLatestTitleForTab(mTab1), equalTo(TAB1_TITLE));
+        assertThat(mMediator.getLatestTitleForTab(PseudoTab.fromTab(mTab1)), equalTo(TAB1_TITLE));
     }
 
     @Test
@@ -1299,7 +1303,8 @@
         List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1, mTab2));
         createTabGroup(tabs, TAB1_ID);
 
-        assertThat(mMediator.getLatestTitleForTab(mTab1), equalTo(CUSTOMIZED_DIALOG_TITLE1));
+        assertThat(mMediator.getLatestTitleForTab(PseudoTab.fromTab(mTab1)),
+                equalTo(CUSTOMIZED_DIALOG_TITLE1));
     }
 
     @Test
@@ -1373,7 +1378,8 @@
         assertEquals(TabProperties.UiType.DIVIDER, mModel.get(0).type);
 
         List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1, mTab2));
-        mMediator.resetWithListOfTabs(tabs, false, false);
+        mMediator.resetWithListOfTabs(
+                PseudoTab.getListOfPseudoTab(tabs), /*quickMode =*/false, /*mruMode =*/false);
         assertThat(mModel.size(), equalTo(2));
         assertNotEquals(TabProperties.UiType.DIVIDER, mModel.get(0).type);
         assertNotEquals(TabProperties.UiType.DIVIDER, mModel.get(1).type);
@@ -1409,27 +1415,31 @@
     @Features.DisableFeatures({TAB_GROUPS_ANDROID})
     public void testUrlUpdated_forSingleTab_GTS_GroupNotEnabled() {
         initAndAssertAllProperties();
-        assertNotEquals(NEW_URL, mModel.get(POSITION1).model.get(TabProperties.URL));
+        assertNotEquals(NEW_DOMAIN, mModel.get(POSITION1).model.get(TabProperties.URL_DOMAIN));
 
         doReturn(NEW_URL).when(mTab1).getUrlString();
         mTabObserverCaptor.getValue().onUrlUpdated(mTab1);
 
-        // TabProperties.URL is empty string if TabGroupsAndroidContinuationEnabled is false.
-        assertEquals("", mModel.get(POSITION1).model.get(TabProperties.URL));
-        assertEquals("", mModel.get(POSITION2).model.get(TabProperties.URL));
+        // TabProperties.URL_DOMAIN is empty string if TabGroupsAndroidContinuationEnabled is false.
+        assertEquals("", mModel.get(POSITION1).model.get(TabProperties.URL_DOMAIN));
+        assertEquals("", mModel.get(POSITION2).model.get(TabProperties.URL_DOMAIN));
     }
 
     @Test
     @Features.EnableFeatures({TAB_GROUPS_CONTINUATION_ANDROID})
     public void testUrlUpdated_forSingleTab_GTS() {
         setUpForTabGroupOperation(TabListMediatorType.TAB_SWITCHER);
-        assertNotEquals(NEW_URL, mModel.get(POSITION1).model.get(TabProperties.URL));
+        assertNotEquals(NEW_DOMAIN, mModel.get(POSITION1).model.get(TabProperties.URL_DOMAIN));
+
+        doReturn(NEW_DOMAIN)
+                .when(mUrlUtilitiesJniMock)
+                .getDomainAndRegistry(eq(NEW_URL), anyBoolean());
 
         doReturn(NEW_URL).when(mTab1).getUrlString();
         mTabObserverCaptor.getValue().onUrlUpdated(mTab1);
 
-        assertEquals(NEW_URL, mModel.get(POSITION1).model.get(TabProperties.URL));
-        assertEquals(TAB2_URL, mModel.get(POSITION2).model.get(TabProperties.URL));
+        assertEquals(NEW_DOMAIN, mModel.get(POSITION1).model.get(TabProperties.URL_DOMAIN));
+        assertEquals(TAB2_DOMAIN, mModel.get(POSITION2).model.get(TabProperties.URL_DOMAIN));
     }
 
     @Test
@@ -1443,25 +1453,25 @@
 
         mMediatorTabGroupModelFilterObserver.didMergeTabToGroup(mTab2, TAB1_ID);
         assertEquals(TAB1_DOMAIN + ", " + TAB2_DOMAIN,
-                mModel.get(POSITION1).model.get(TabProperties.URL));
+                mModel.get(POSITION1).model.get(TabProperties.URL_DOMAIN));
 
         doReturn(NEW_DOMAIN)
                 .when(mUrlUtilitiesJniMock)
                 .getDomainAndRegistry(eq(NEW_URL), anyBoolean());
 
-        // Update URL for mTab1.
+        // Update URL_DOMAIN for mTab1.
         doReturn(NEW_URL).when(mTab1).getUrlString();
         mTabObserverCaptor.getValue().onUrlUpdated(mTab1);
 
         assertEquals(NEW_DOMAIN + ", " + TAB2_DOMAIN,
-                mModel.get(POSITION1).model.get(TabProperties.URL));
+                mModel.get(POSITION1).model.get(TabProperties.URL_DOMAIN));
 
-        // Update URL for mTab2.
+        // Update URL_DOMAIN for mTab2.
         doReturn(NEW_URL).when(mTab2).getUrlString();
         mTabObserverCaptor.getValue().onUrlUpdated(mTab2);
 
-        assertEquals(
-                NEW_DOMAIN + ", " + NEW_DOMAIN, mModel.get(POSITION1).model.get(TabProperties.URL));
+        assertEquals(NEW_DOMAIN + ", " + NEW_DOMAIN,
+                mModel.get(POSITION1).model.get(TabProperties.URL_DOMAIN));
     }
 
     @Test
@@ -1474,26 +1484,26 @@
         doReturn(POSITION1).when(mTabGroupModelFilter).indexOf(mTab2);
 
         mMediatorTabGroupModelFilterObserver.didMergeTabToGroup(mTab2, TAB1_ID);
-        assertEquals(TAB1_URL, mModel.get(POSITION1).model.get(TabProperties.URL));
-        assertEquals(TAB2_URL, mModel.get(POSITION2).model.get(TabProperties.URL));
+        assertEquals(TAB1_DOMAIN, mModel.get(POSITION1).model.get(TabProperties.URL_DOMAIN));
+        assertEquals(TAB2_DOMAIN, mModel.get(POSITION2).model.get(TabProperties.URL_DOMAIN));
 
         doReturn(NEW_DOMAIN)
                 .when(mUrlUtilitiesJniMock)
                 .getDomainAndRegistry(eq(NEW_URL), anyBoolean());
 
-        // Update URL for mTab1.
+        // Update URL_DOMAIN for mTab1.
         doReturn(NEW_URL).when(mTab1).getUrlString();
         mTabObserverCaptor.getValue().onUrlUpdated(mTab1);
 
-        assertEquals(NEW_URL, mModel.get(POSITION1).model.get(TabProperties.URL));
-        assertEquals(TAB2_URL, mModel.get(POSITION2).model.get(TabProperties.URL));
+        assertEquals(NEW_DOMAIN, mModel.get(POSITION1).model.get(TabProperties.URL_DOMAIN));
+        assertEquals(TAB2_DOMAIN, mModel.get(POSITION2).model.get(TabProperties.URL_DOMAIN));
 
-        // Update URL for mTab2.
+        // Update URL_DOMAIN for mTab2.
         doReturn(NEW_URL).when(mTab2).getUrlString();
         mTabObserverCaptor.getValue().onUrlUpdated(mTab2);
 
-        assertEquals(NEW_URL, mModel.get(POSITION1).model.get(TabProperties.URL));
-        assertEquals(NEW_URL, mModel.get(POSITION2).model.get(TabProperties.URL));
+        assertEquals(NEW_DOMAIN, mModel.get(POSITION1).model.get(TabProperties.URL_DOMAIN));
+        assertEquals(NEW_DOMAIN, mModel.get(POSITION2).model.get(TabProperties.URL_DOMAIN));
     }
 
     @Test
@@ -1505,7 +1515,7 @@
 
         mMediatorTabGroupModelFilterObserver.didMergeTabToGroup(mTab2, TAB1_ID);
         assertEquals(TAB1_DOMAIN + ", " + TAB2_DOMAIN,
-                mModel.get(POSITION1).model.get(TabProperties.URL));
+                mModel.get(POSITION1).model.get(TabProperties.URL_DOMAIN));
 
         // Assume that TabGroupModelFilter is already updated.
         when(mTabGroupModelFilter.getRelatedTabList(TAB1_ID)).thenReturn(Arrays.asList(mTab1));
@@ -1515,8 +1525,8 @@
         doReturn(2).when(mTabGroupModelFilter).getCount();
 
         mMediatorTabGroupModelFilterObserver.didMoveTabOutOfGroup(mTab2, POSITION1);
-        assertEquals(TAB1_URL, mModel.get(POSITION1).model.get(TabProperties.URL));
-        assertEquals(TAB2_URL, mModel.get(POSITION2).model.get(TabProperties.URL));
+        assertEquals(TAB1_DOMAIN, mModel.get(POSITION1).model.get(TabProperties.URL_DOMAIN));
+        assertEquals(TAB2_DOMAIN, mModel.get(POSITION2).model.get(TabProperties.URL_DOMAIN));
     }
 
     @Test
@@ -1662,7 +1672,8 @@
             tabs.add(mTabModel.getTabAt(i));
         }
 
-        boolean showQuickly = mMediator.resetWithListOfTabs(tabs, false, false);
+        boolean showQuickly = mMediator.resetWithListOfTabs(
+                PseudoTab.getListOfPseudoTab(tabs), /*quickMode =*/false, /*mruMode =*/false);
         assertThat(showQuickly, equalTo(true));
 
         // Create a PropertyModel that is not a tab and add it to the existing TabListModel.
@@ -1674,7 +1685,8 @@
         assertThat(mModel.size(), equalTo(tabs.size() + 1));
 
         // TabListModel unchange check should ignore the non-Tab item.
-        showQuickly = mMediator.resetWithListOfTabs(tabs, false, false);
+        showQuickly = mMediator.resetWithListOfTabs(
+                PseudoTab.getListOfPseudoTab(tabs), /*quickMode =*/false, /*mruMode =*/false);
         assertThat(showQuickly, equalTo(true));
     }
 
@@ -1686,7 +1698,8 @@
             tabs.add(mTabModel.getTabAt(i));
         }
         // The fast path to trigger updateTab().
-        boolean showQuickly = mMediator.resetWithListOfTabs(tabs, false, false);
+        boolean showQuickly = mMediator.resetWithListOfTabs(
+                PseudoTab.getListOfPseudoTab(tabs), /*quickMode =*/false, /*mruMode =*/false);
         assertThat(showQuickly, equalTo(true));
 
         assertThat(mModel.size(), equalTo(2));
@@ -1697,14 +1710,16 @@
         String searchTerm2 = "y'all";
         TabAttributeCache.setLastSearchTermForTesting(TAB1_ID, searchTerm1);
         TabAttributeCache.setLastSearchTermForTesting(TAB2_ID, searchTerm2);
-        showQuickly = mMediator.resetWithListOfTabs(tabs, false, false);
+        showQuickly = mMediator.resetWithListOfTabs(
+                PseudoTab.getListOfPseudoTab(tabs), /*quickMode =*/false, /*mruMode =*/false);
         assertThat(showQuickly, equalTo(true));
         assertThat(mModel.get(0).model.get(TabProperties.SEARCH_QUERY), equalTo(searchTerm1));
         assertThat(mModel.get(1).model.get(TabProperties.SEARCH_QUERY), equalTo(searchTerm2));
 
         TabAttributeCache.setLastSearchTermForTesting(TAB1_ID, null);
         TabAttributeCache.setLastSearchTermForTesting(TAB2_ID, null);
-        showQuickly = mMediator.resetWithListOfTabs(tabs, false, false);
+        showQuickly = mMediator.resetWithListOfTabs(
+                PseudoTab.getListOfPseudoTab(tabs), /*quickMode =*/false, /*mruMode =*/false);
         assertThat(showQuickly, equalTo(true));
         assertThat(mModel.get(0).model.get(TabProperties.SEARCH_QUERY), equalTo(null));
         assertThat(mModel.get(1).model.get(TabProperties.SEARCH_QUERY), equalTo(null));
@@ -1712,7 +1727,8 @@
         // The slow path to trigger addTabInfoToModel().
         tabs = new ArrayList<>(Arrays.asList(mTab1));
         TabAttributeCache.setLastSearchTermForTesting(TAB1_ID, searchTerm1);
-        showQuickly = mMediator.resetWithListOfTabs(tabs, false, false);
+        showQuickly = mMediator.resetWithListOfTabs(
+                PseudoTab.getListOfPseudoTab(tabs), /*quickMode =*/false, /*mruMode =*/false);
         assertThat(showQuickly, equalTo(false));
         assertThat(mModel.size(), equalTo(1));
         assertThat(mModel.get(0).model.get(TabProperties.SEARCH_QUERY), equalTo(searchTerm1));
@@ -1724,12 +1740,14 @@
         String searchTerm1 = "hello world";
         TabAttributeCache.setLastSearchTermForTesting(TAB1_ID, searchTerm1);
 
-        mMediator.resetWithListOfTabs(new ArrayList<>(Arrays.asList(mTab1)), false, false);
+        mMediator.resetWithListOfTabs(
+                PseudoTab.getListOfPseudoTab(Arrays.asList(mTab1)), false, false);
         assertThat(mModel.size(), equalTo(1));
         assertThat(mModel.get(0).model.get(TabProperties.SEARCH_QUERY), equalTo(searchTerm1));
 
         createTabGroup(new ArrayList<>(Arrays.asList(mTab1, mTab2)), TAB1_ID);
-        mMediator.resetWithListOfTabs(new ArrayList<>(Arrays.asList(mTab1)), false, false);
+        mMediator.resetWithListOfTabs(
+                PseudoTab.getListOfPseudoTab(Arrays.asList(mTab1)), false, false);
         assertThat(mModel.size(), equalTo(1));
         assertThat(mModel.get(0).model.get(TabProperties.SEARCH_QUERY), equalTo(null));
     }
@@ -1741,7 +1759,8 @@
         String searchTerm1 = "hello world";
         TabAttributeCache.setLastSearchTermForTesting(TAB1_ID, searchTerm1);
 
-        mMediator.resetWithListOfTabs(new ArrayList<>(Arrays.asList(mTab1)), false, false);
+        mMediator.resetWithListOfTabs(
+                PseudoTab.getListOfPseudoTab(Arrays.asList(mTab1)), false, false);
         assertThat(mModel.size(), equalTo(1));
         assertThat(mModel.get(0).model.get(TabProperties.SEARCH_QUERY), equalTo(searchTerm1));
     }
@@ -1753,7 +1772,8 @@
         String searchTerm1 = "hello world";
         TabAttributeCache.setLastSearchTermForTesting(TAB1_ID, searchTerm1);
 
-        mMediator.resetWithListOfTabs(new ArrayList<>(Arrays.asList(mTab1)), false, false);
+        mMediator.resetWithListOfTabs(
+                PseudoTab.getListOfPseudoTab(Arrays.asList(mTab1)), false, false);
         assertThat(mModel.size(), equalTo(1));
         assertThat(mModel.get(0).model.get(TabProperties.SEARCH_QUERY), equalTo(null));
     }
@@ -2010,7 +2030,7 @@
         for (int i = 0; i < mTabModel.getCount(); i++) {
             tabs.add(mTabModel.getTabAt(i));
         }
-        mMediator.resetWithListOfTabs(tabs, false, false);
+        mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false, false);
         for (Callback<Drawable> callback : mCallbackCaptor.getAllValues()) {
             callback.onResult(new ColorDrawable(Color.RED));
         }
@@ -2054,7 +2074,7 @@
         doReturn(url).when(tab).getUrlString();
         doReturn(title).when(tab).getTitle();
         doReturn(true).when(tab).isIncognito();
-        doReturn(title).when(mTitleProvider).getTitle(tab);
+        when(mTitleProvider.getTitle(PseudoTab.fromTab(tab))).thenReturn(title);
         return tab;
     }
 
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediatorUnitTest.java
index d24dccf..35c751e7 100644
--- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediatorUnitTest.java
+++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediatorUnitTest.java
@@ -216,6 +216,7 @@
 
     @Test
     public void showsWithoutAnimation() {
+        doReturn(true).when(mTabModelFilter).isTabModelRestored();
         initAndAssertAllProperties();
         mMediator.showOverview(false);
 
@@ -243,6 +244,7 @@
     @Test
     public void showsWithoutAnimation_withTabGroups() {
         doReturn(2).when(mTabModelFilter).getCount();
+        doReturn(true).when(mTabModelFilter).isTabModelRestored();
 
         initAndAssertAllProperties();
         mMediator.showOverview(false);
@@ -421,6 +423,7 @@
         initAndAssertAllProperties();
         mMediator.showOverview(true);
         assertThat(mModel.get(TabListContainerProperties.IS_VISIBLE), equalTo(true));
+        doReturn(true).when(mTabModelFilter).isTabModelRestored();
 
         mTabModelObserverCaptor.getValue().didSelectTab(mTab1, TabSelectionType.FROM_USER, TAB3_ID);
 
@@ -429,6 +432,7 @@
 
     @Test
     public void doesNotHideWhenSelectedTabChangedDueToTabClosure() {
+        doReturn(true).when(mTabModelFilter).isTabModelRestored();
         initAndAssertAllProperties();
         mMediator.showOverview(true);
         assertThat(mModel.get(TabListContainerProperties.IS_VISIBLE), equalTo(true));
@@ -444,6 +448,7 @@
 
     @Test
     public void doesNotHideWhenSelectedTabChangedDueToModelChange() {
+        doReturn(true).when(mTabModelFilter).isTabModelRestored();
         initAndAssertAllProperties();
         mMediator.showOverview(true);
         assertThat(mModel.get(TabListContainerProperties.IS_VISIBLE), equalTo(true));
diff --git a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShell.java b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShell.java
index af6a2b2..39a42eb4 100644
--- a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShell.java
+++ b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShell.java
@@ -42,6 +42,7 @@
 import org.chromium.chrome.browser.offlinepages.OfflinePageUtils;
 import org.chromium.chrome.browser.page_info.PageInfoController;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
+import org.chromium.chrome.browser.tab.RedirectHandlerTabHelper;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabAssociatedApp;
 import org.chromium.chrome.browser.tab.TabBrowserControlsConstraintsHelper;
@@ -510,14 +511,15 @@
     private void initializeTabForVR() {
         if (mTab == null) return;
         // Make sure we are not redirecting to another app, i.e. out of VR mode.
-        mNonVrTabRedirectHandler = TabRedirectHandler.swapFor(mTab, mTabRedirectHandler);
+        mNonVrTabRedirectHandler =
+                RedirectHandlerTabHelper.swapHandlerFor(mTab, mTabRedirectHandler);
         assert mTab.getWindowAndroid() == mContentVrWindowAndroid;
         configWebContentsImeForVr(mTab.getWebContents());
     }
 
     private void restoreTabFromVR() {
         if (mTab == null) return;
-        TabRedirectHandler.swapFor(mTab, mNonVrTabRedirectHandler);
+        RedirectHandlerTabHelper.swapHandlerFor(mTab, mNonVrTabRedirectHandler);
         mNonVrTabRedirectHandler = null;
         restoreWebContentsImeFromVr(mTab.getWebContents());
     }
diff --git a/chrome/android/java/res/layout/autofill_local_card_editor.xml b/chrome/android/java/res/layout/autofill_local_card_editor.xml
index 7286635..a5cc399 100644
--- a/chrome/android/java/res/layout/autofill_local_card_editor.xml
+++ b/chrome/android/java/res/layout/autofill_local_card_editor.xml
@@ -9,7 +9,7 @@
     xmlns:tools="http://schemas.android.com/tools">
 
     <!-- Name -->
-    <org.chromium.components.browser_ui.widget.text.ChromeTextInputLayout
+    <com.google.android.material.textfield.TextInputLayout
         android:id="@+id/credit_card_name_label"
         android:labelFor="@+id/credit_card_name_edit"
         android:layout_width="match_parent"
@@ -27,10 +27,10 @@
             android:inputType="textCapWords"
             android:hint="@string/autofill_credit_card_editor_name" />
 
-    </org.chromium.components.browser_ui.widget.text.ChromeTextInputLayout>
+    </com.google.android.material.textfield.TextInputLayout>
 
     <!-- Credit card number -->
-    <org.chromium.components.browser_ui.widget.text.ChromeTextInputLayout
+    <com.google.android.material.textfield.TextInputLayout
         android:id="@+id/credit_card_number_label"
         android:labelFor="@+id/credit_card_number_edit"
         android:layout_width="match_parent"
@@ -49,7 +49,7 @@
             android:digits="0123456789- "
             android:hint="@string/autofill_credit_card_editor_number" />
 
-    </org.chromium.components.browser_ui.widget.text.ChromeTextInputLayout>
+    </com.google.android.material.textfield.TextInputLayout>
 
     <!-- Expiration date -->
     <TextView
diff --git a/chrome/android/java/res/layout/autofill_name_fixflow.xml b/chrome/android/java/res/layout/autofill_name_fixflow.xml
index 34e0b0d..f13c46b0 100644
--- a/chrome/android/java/res/layout/autofill_name_fixflow.xml
+++ b/chrome/android/java/res/layout/autofill_name_fixflow.xml
@@ -18,7 +18,7 @@
     android:orientation="horizontal"
     android:gravity="center_vertical">
 
-    <org.chromium.components.browser_ui.widget.text.ChromeTextInputLayout
+    <com.google.android.material.textfield.TextInputLayout
         android:id="@+id/cc_name"
         android:labelFor="@+id/cc_name_edit"
         android:layout_width="0dp"
@@ -36,7 +36,7 @@
             android:imeActionLabel="@string/autofill_fix_flow_prompt_save_card_label"
             android:inputType="textCapWords"/>
 
-    </org.chromium.components.browser_ui.widget.text.ChromeTextInputLayout>
+    </com.google.android.material.textfield.TextInputLayout>
 
     <ImageView
         android:id="@+id/cc_name_tooltip_icon"
diff --git a/chrome/android/java/res/layout/bookmark_add_edit_folder_activity.xml b/chrome/android/java/res/layout/bookmark_add_edit_folder_activity.xml
index 014a7f1..3861dee 100644
--- a/chrome/android/java/res/layout/bookmark_add_edit_folder_activity.xml
+++ b/chrome/android/java/res/layout/bookmark_add_edit_folder_activity.xml
@@ -28,7 +28,7 @@
                 android:layout_marginEnd="12dp"
                 android:layout_marginStart="12dp"
                 android:layout_marginTop="24dp"
-                app:hint="@string/title"
+                android:hint="@string/title"
                 app:emptyErrorMessage="@string/bookmark_missing_title">
 
                 <com.google.android.material.textfield.TextInputEditText
diff --git a/chrome/android/java/res/layout/bookmark_edit.xml b/chrome/android/java/res/layout/bookmark_edit.xml
index 4ccd659..d639ccd 100644
--- a/chrome/android/java/res/layout/bookmark_edit.xml
+++ b/chrome/android/java/res/layout/bookmark_edit.xml
@@ -26,7 +26,7 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:layout_marginTop="22dp"
-                app:hint="@string/bookmark_name"
+                android:hint="@string/bookmark_name"
                 app:emptyErrorMessage="@string/bookmark_missing_title">
                 <com.google.android.material.textfield.TextInputEditText
                     android:layout_width="match_parent"
@@ -59,7 +59,7 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:layout_marginTop="24dp"
-                app:hint="@string/bookmark_url"
+                android:hint="@string/bookmark_url"
                 app:emptyErrorMessage="@string/bookmark_missing_url">
 
                 <com.google.android.material.textfield.TextInputEditText
diff --git a/chrome/android/java/res/layout/homepage_editor.xml b/chrome/android/java/res/layout/homepage_editor.xml
index 5f67af6..df599531 100644
--- a/chrome/android/java/res/layout/homepage_editor.xml
+++ b/chrome/android/java/res/layout/homepage_editor.xml
@@ -22,7 +22,7 @@
             android:orientation="vertical"
             android:focusableInTouchMode="true" >
 
-            <org.chromium.components.browser_ui.widget.text.ChromeTextInputLayout
+            <com.google.android.material.textfield.TextInputLayout
                 android:id="@+id/homepage_url"
                 style="@style/PreferenceScreenLayout"
                 android:layout_width="match_parent"
@@ -36,7 +36,7 @@
                     android:inputType="textUri"
                     android:singleLine="true"
                     android:hint="@string/options_homepage_edit_label" />
-            </org.chromium.components.browser_ui.widget.text.ChromeTextInputLayout>
+            </com.google.android.material.textfield.TextInputLayout>
 
             <Space style="@style/ButtonBarTopSpacer" />
             <View style="@style/ButtonBarTopDivider" />
diff --git a/chrome/android/java/res/layout/http_auth_dialog.xml b/chrome/android/java/res/layout/http_auth_dialog.xml
index 99ad86b2..29e5a0b2 100644
--- a/chrome/android/java/res/layout/http_auth_dialog.xml
+++ b/chrome/android/java/res/layout/http_auth_dialog.xml
@@ -17,7 +17,7 @@
           android:layout_width="match_parent"
           android:layout_height="wrap_content" />
 
-      <org.chromium.components.browser_ui.widget.text.ChromeTextInputLayout
+      <com.google.android.material.textfield.TextInputLayout
           android:id="@+id/username_label"
           android:layout_width="match_parent"
           android:layout_height="wrap_content" >
@@ -29,9 +29,9 @@
               android:inputType="textNoSuggestions"
               android:imeOptions="flagNoExtractUi"
               android:importantForAutofill="no" />
-      </org.chromium.components.browser_ui.widget.text.ChromeTextInputLayout>
+      </com.google.android.material.textfield.TextInputLayout>
 
-      <org.chromium.components.browser_ui.widget.text.ChromeTextInputLayout
+      <com.google.android.material.textfield.TextInputLayout
           android:id="@+id/password_label"
           android:layout_width="match_parent"
           android:layout_height="wrap_content" >
@@ -43,7 +43,7 @@
               android:inputType="textPassword"
               android:imeOptions="flagNoExtractUi"
               android:importantForAutofill="no" />
-      </org.chromium.components.browser_ui.widget.text.ChromeTextInputLayout>
+      </com.google.android.material.textfield.TextInputLayout>
 
     </LinearLayout>
 
diff --git a/chrome/android/java/res/layout/password_entry_editor.xml b/chrome/android/java/res/layout/password_entry_editor.xml
index e086dd6..3441242 100644
--- a/chrome/android/java/res/layout/password_entry_editor.xml
+++ b/chrome/android/java/res/layout/password_entry_editor.xml
@@ -16,7 +16,7 @@
     android:paddingRight="@dimen/password_entry_editor_content_spacing">
 
     <!-- Site -->
-    <org.chromium.components.browser_ui.widget.text.ChromeTextInputLayout
+    <com.google.android.material.textfield.TextInputLayout
         android:id="@+id/site_label"
         android:labelFor="@+id/site_edit"
         android:layout_width="match_parent"
@@ -33,10 +33,10 @@
             android:inputType="text"
             android:hint="@string/password_entry_viewer_site_title"
             android:enabled="false"/>
-    </org.chromium.components.browser_ui.widget.text.ChromeTextInputLayout>
+    </com.google.android.material.textfield.TextInputLayout>
 
     <!-- Username -->
-    <org.chromium.components.browser_ui.widget.text.ChromeTextInputLayout
+    <com.google.android.material.textfield.TextInputLayout
         android:id="@+id/username_label"
         android:labelFor="@+id/username_edit"
         android:layout_width="match_parent"
@@ -52,7 +52,7 @@
             android:imeOptions="flagNoExtractUi"
             android:inputType="text"
             android:hint="@string/password_entry_viewer_username_title"/>
-    </org.chromium.components.browser_ui.widget.text.ChromeTextInputLayout>
+    </com.google.android.material.textfield.TextInputLayout>
 
     <!-- Password -->
     <LinearLayout
@@ -61,7 +61,7 @@
         android:orientation="horizontal"
         android:gravity="center">
 
-        <org.chromium.components.browser_ui.widget.text.ChromeTextInputLayout
+        <com.google.android.material.textfield.TextInputLayout
             android:id="@+id/password_label"
             android:labelFor="@+id/password_edit"
             android:layout_height="wrap_content"
@@ -78,7 +78,7 @@
             android:imeOptions="flagNoExtractUi"
             android:inputType="textPassword"
             android:hint="@string/password_entry_viewer_password"/>
-        </org.chromium.components.browser_ui.widget.text.ChromeTextInputLayout>
+        </com.google.android.material.textfield.TextInputLayout>
 
 
         <org.chromium.ui.widget.ChromeImageButton
diff --git a/chrome/android/java/res/layout/payment_request_editor_dropdown.xml b/chrome/android/java/res/layout/payment_request_editor_dropdown.xml
index 71d88c1..4dd75f2b 100644
--- a/chrome/android/java/res/layout/payment_request_editor_dropdown.xml
+++ b/chrome/android/java/res/layout/payment_request_editor_dropdown.xml
@@ -17,8 +17,7 @@
             android:id="@+id/spinner_label"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:textAppearance="@style/TextAppearance.TextSmall.Secondary"
-            android:layout_marginTop="5dp"/>
+            android:textAppearance="@style/TextAppearance.TextSmall.Secondary" />
 
     <androidx.appcompat.widget.AppCompatSpinner
             android:id="@+id/spinner"
diff --git a/chrome/android/java/res/layout/payments_request_editor_textview.xml b/chrome/android/java/res/layout/payments_request_editor_textview.xml
index a78149c..fb9ec39b7 100644
--- a/chrome/android/java/res/layout/payments_request_editor_textview.xml
+++ b/chrome/android/java/res/layout/payments_request_editor_textview.xml
@@ -12,7 +12,7 @@
     android:layout_marginTop="@dimen/editor_dialog_section_small_spacing"
     android:layout_marginBottom="@dimen/editor_dialog_section_small_spacing">
 
-    <org.chromium.components.browser_ui.widget.text.ChromeTextInputLayout
+    <com.google.android.material.textfield.TextInputLayout
         android:id="@+id/text_input_layout"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
@@ -26,7 +26,7 @@
             android:layout_height="wrap_content"
             android:singleLine="true"
             android:imeOptions="flagNoExtractUi" />
-    </org.chromium.components.browser_ui.widget.text.ChromeTextInputLayout>
+    </com.google.android.material.textfield.TextInputLayout>
 
     <LinearLayout
         android:id="@+id/icons_layer"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/AppHooks.java b/chrome/android/java/src/org/chromium/chrome/browser/AppHooks.java
index e5afa6dd..5fd8764e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/AppHooks.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/AppHooks.java
@@ -375,6 +375,6 @@
      * Returns the URL to the WebAPK creation/update server.
      */
     public String getWebApkServerUrl() {
-        return "https://webapk.googleapis.com/v1/webApks/?alt=proto&key=AIzaSyAoI6v-F31-3t9NunLYEiKcPIqgTJIUZBw";
+        return "";
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index eef57955..f617bb5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -116,12 +116,12 @@
 import org.chromium.chrome.browser.suggestions.SuggestionsEventReporterBridge;
 import org.chromium.chrome.browser.suggestions.SuggestionsMetrics;
 import org.chromium.chrome.browser.survey.ChromeSurveyController;
+import org.chromium.chrome.browser.tab.RedirectHandlerTabHelper;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabAssociatedApp;
 import org.chromium.chrome.browser.tab.TabCreationState;
 import org.chromium.chrome.browser.tab.TabDelegateFactory;
 import org.chromium.chrome.browser.tab.TabLaunchType;
-import org.chromium.chrome.browser.tab.TabRedirectHandler;
 import org.chromium.chrome.browser.tab.TabSelectionType;
 import org.chromium.chrome.browser.tabbed_mode.TabbedAppMenuPropertiesDelegate;
 import org.chromium.chrome.browser.tabbed_mode.TabbedRootUiCoordinator;
@@ -1330,7 +1330,7 @@
                     // can be handled by other applications (e.g. www.youtube.com links).
                     Tab currentTab = getActivityTab();
                     if (currentTab != null) {
-                        TabRedirectHandler.from(currentTab).updateIntent(intent);
+                        RedirectHandlerTabHelper.updateIntentInTab(currentTab, intent);
                         currentTab.loadUrl(ChromeTabbedActivity.createLoadUrlParamsForIntent(
                                 url, referer, hasUserGesture, mIntentHandlingTimeMs, intent));
                     } else {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/prefeditor/EditorTextField.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/prefeditor/EditorTextField.java
index 972d14df..c7f4205 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/prefeditor/EditorTextField.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/prefeditor/EditorTextField.java
@@ -27,9 +27,10 @@
 import androidx.appcompat.content.res.AppCompatResources;
 import androidx.core.view.ViewCompat;
 
+import com.google.android.material.textfield.TextInputLayout;
+
 import org.chromium.chrome.R;
 import org.chromium.components.browser_ui.widget.TintedDrawable;
-import org.chromium.components.browser_ui.widget.text.ChromeTextInputLayout;
 
 /** Handles validation and display of one field from the {@link EditorFieldModel}. */
 @VisibleForTesting
@@ -39,7 +40,7 @@
 
     private EditorFieldModel mEditorFieldModel;
     private OnEditorActionListener mEditorActionListener;
-    private ChromeTextInputLayout mInputLayout;
+    private TextInputLayout mInputLayout;
     private AutoCompleteTextView mInput;
     private View mIconsLayer;
     private ImageView mActionIcon;
@@ -56,7 +57,7 @@
         mEditorActionListener = actionListener;
 
         LayoutInflater.from(context).inflate(R.layout.payments_request_editor_textview, this, true);
-        mInputLayout = (ChromeTextInputLayout) findViewById(R.id.text_input_layout);
+        mInputLayout = (TextInputLayout) findViewById(R.id.text_input_layout);
 
         // Build up the label.  Required fields are indicated by appending a '*'.
         CharSequence label = fieldModel.getLabel();
@@ -108,12 +109,15 @@
         }
 
         // Validate the field when the user de-focuses it.
-        mInputLayout.addEditTextOnFocusChangeListener((v, hasFocus) -> {
-            if (hasFocus) {
-                mHasFocusedAtLeastOnce = true;
-            } else if (mHasFocusedAtLeastOnce) {
-                // Show no errors until the user has already tried to edit the field once.
-                updateDisplayedError(!mEditorFieldModel.isValid());
+        mInput.setOnFocusChangeListener(new OnFocusChangeListener() {
+            @Override
+            public void onFocusChange(View v, boolean hasFocus) {
+                if (hasFocus) {
+                    mHasFocusedAtLeastOnce = true;
+                } else if (mHasFocusedAtLeastOnce) {
+                    // Show no errors until the user has already tried to edit the field once.
+                    updateDisplayedError(!mEditorFieldModel.isValid());
+                }
             }
         });
 
@@ -284,10 +288,6 @@
         }
     }
 
-    public ChromeTextInputLayout getInputLayout() {
-        return mInputLayout;
-    }
-
     @VisibleForTesting
     public static void setEditorObserverForTest(EditorObserverForTest observerForTest) {
         sObserverForTest = observerForTest;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillLocalCardEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillLocalCardEditor.java
index 8aee099..59fbdfdc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillLocalCardEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillLocalCardEditor.java
@@ -17,6 +17,8 @@
 import android.widget.EditText;
 import android.widget.Spinner;
 
+import com.google.android.material.textfield.TextInputLayout;
+
 import org.chromium.base.annotations.UsedByReflection;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.R;
@@ -25,7 +27,6 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.SettingsAutofillAndPaymentsObserver;
-import org.chromium.components.browser_ui.widget.text.ChromeTextInputLayout;
 
 import java.text.SimpleDateFormat;
 import java.util.Calendar;
@@ -35,9 +36,9 @@
  * Local credit card settings.
  */
 public class AutofillLocalCardEditor extends AutofillCreditCardEditor {
-    private ChromeTextInputLayout mNameLabel;
+    private TextInputLayout mNameLabel;
     private EditText mNameText;
-    private ChromeTextInputLayout mNumberLabel;
+    private TextInputLayout mNumberLabel;
     private EditText mNumberText;
     private Spinner mExpirationMonth;
     private Spinner mExpirationYear;
@@ -60,9 +61,9 @@
 
         View v = super.onCreateView(inflater, container, savedInstanceState);
 
-        mNameLabel = (ChromeTextInputLayout) v.findViewById(R.id.credit_card_name_label);
+        mNameLabel = (TextInputLayout) v.findViewById(R.id.credit_card_name_label);
         mNameText = (EditText) v.findViewById(R.id.credit_card_name_edit);
-        mNumberLabel = (ChromeTextInputLayout) v.findViewById(R.id.credit_card_number_label);
+        mNumberLabel = (TextInputLayout) v.findViewById(R.id.credit_card_number_label);
         mNumberText = (EditText) v.findViewById(R.id.credit_card_number_edit);
 
         // Set text watcher to format credit card number
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkTextInputLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkTextInputLayout.java
index e2f00cf4..437c2e0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkTextInputLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkTextInputLayout.java
@@ -11,14 +11,15 @@
 import android.text.TextWatcher;
 import android.util.AttributeSet;
 
+import com.google.android.material.textfield.TextInputLayout;
+
 import org.chromium.chrome.R;
-import org.chromium.components.browser_ui.widget.text.ChromeTextInputLayout;
 
 /**
- * Wraps around {@link ChromeTextInputLayout} to implement a basic empty field error behavior
+ * Wraps around {@link TextInputLayout} to implement a basic empty field error behavior
  * for the Bookmark related TextInputLayouts.
  */
-public class BookmarkTextInputLayout extends ChromeTextInputLayout {
+public class BookmarkTextInputLayout extends TextInputLayout {
     private String mEmptyErrorMessage;
 
     public BookmarkTextInputLayout(Context context, AttributeSet attrs) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java
index b29fcadc5..732b4afc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java
@@ -42,11 +42,11 @@
 import org.chromium.chrome.browser.lifecycle.InflationObserver;
 import org.chromium.chrome.browser.lifecycle.NativeInitObserver;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
+import org.chromium.chrome.browser.tab.RedirectHandlerTabHelper;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabAssociatedApp;
 import org.chromium.chrome.browser.tab.TabCreationState;
 import org.chromium.chrome.browser.tab.TabLaunchType;
-import org.chromium.chrome.browser.tab.TabRedirectHandler;
 import org.chromium.chrome.browser.tab_activity_glue.ReparentingDelegateFactory;
 import org.chromium.chrome.browser.tabmodel.AsyncTabParams;
 import org.chromium.chrome.browser.tabmodel.AsyncTabParamsManager;
@@ -416,7 +416,7 @@
     }
 
     private void initializeTab(Tab tab) {
-        TabRedirectHandler.from(tab).updateIntent(mIntent);
+        RedirectHandlerTabHelper.updateIntentInTab(tab, mIntent);
         tab.getView().requestFocus();
 
         // TODO(pshmakov): invert these dependencies.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java
index 4543eeb..2752ebc3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java
@@ -45,6 +45,7 @@
 import org.chromium.chrome.browser.instantapps.AuthenticatedProxyActivity;
 import org.chromium.chrome.browser.instantapps.InstantAppsHandler;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
+import org.chromium.chrome.browser.tab.RedirectHandlerTabHelper;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabImpl;
 import org.chromium.chrome.browser.tab.TabObserver;
@@ -634,7 +635,7 @@
         if (!hasValidTab() || mTab.getWebContents() == null) return false;
 
         InstantAppsHandler handler = InstantAppsHandler.getInstance();
-        TabRedirectHandler redirect = TabRedirectHandler.get(mTab);
+        TabRedirectHandler redirect = RedirectHandlerTabHelper.getHandlerFor(mTab);
         Intent intent = redirect != null ? redirect.getInitialIntent() : null;
         // TODO(mariakhomenko): consider also handling NDEF_DISCOVER action redirects.
         if (isIncomingRedirect && intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/AutoFetchNotifier.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/AutoFetchNotifier.java
index e6df8ca..b4ac7b8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/AutoFetchNotifier.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/AutoFetchNotifier.java
@@ -361,7 +361,10 @@
     }
 
     private static void cancelInProgress() {
-        AutoFetchNotifierJni.get().cancelInProgress(Profile.getLastUsedProfile());
+        // TODO(https://crbug.com/1067314): Use the current profile (i.e., regular profile or
+        // incognito profile) instead of always using regular profile. It is wrong and need to be
+        // fixed.
+        AutoFetchNotifierJni.get().cancelInProgress(Profile.getLastUsedRegularProfile());
     }
 
     @NativeMethods
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java
index 563eb425..1cd420e3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java
@@ -639,7 +639,7 @@
      */
     public static void getLoadUrlParamsForOpeningOfflineVersion(final String url, long offlineId,
             final @LaunchLocation int location, Callback<LoadUrlParams> callback) {
-        // TODO(https://crbug.com/1041781): Use the current profile (i.e., regular profile or
+        // TODO(https://crbug.com/1067314): Use the current profile (i.e., regular profile or
         // incognito profile) instead of always using regular profile. It is wrong and need to be
         // fixed.
         OfflinePageBridge offlinePageBridge =
@@ -662,7 +662,7 @@
      */
     public static void getLoadUrlParamsForOpeningMhtmlFileOrContent(
             final String intentUrl, Callback<LoadUrlParams> callback) {
-        // TODO(https://crbug.com/1041781): Use the current profile (i.e., regular profile or
+        // TODO(https://crbug.com/1067314): Use the current profile (i.e., regular profile or
         // incognito profile) instead of always using regular profile. It is wrong and need to be
         // fixed.
         OfflinePageBridge offlinePageBridge =
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/prefetch/OfflineNotificationBackgroundTask.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/prefetch/OfflineNotificationBackgroundTask.java
index b6e8ef4..94ceb0c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/prefetch/OfflineNotificationBackgroundTask.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/prefetch/OfflineNotificationBackgroundTask.java
@@ -271,7 +271,10 @@
         if (sOfflinePageBridgeForTesting != null) {
             return sOfflinePageBridgeForTesting;
         }
-        return OfflinePageBridge.getForProfile(Profile.getLastUsedProfile());
+        // TODO(https://crbug.com/1067314): Use the current profile (i.e., regular profile or
+        // incognito profile) instead of always using regular profile. It is wrong and need to be
+        // fixed.
+        return OfflinePageBridge.getForProfile(Profile.getLastUsedRegularProfile());
     }
 
     @VisibleForTesting
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchConfiguration.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchConfiguration.java
index 345d11ef..acb516b7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchConfiguration.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchConfiguration.java
@@ -41,15 +41,22 @@
      * user setting to be true. If the current browser Profile is null this method returns false.
      */
     public static boolean isPrefetchingEnabled() {
+        // TODO(https://crbug.com/1067314): Use the current profile (i.e., regular profile or
+        // incognito profile) instead of always using regular profile. It is wrong and need to be
+        // fixed.
         return PrefetchConfigurationJni.get().isPrefetchingEnabled(
-                ProfileKey.getLastUsedProfileKey());
+                ProfileKey.getLastUsedRegularProfileKey());
     }
 
     /**
      * Return the value of offline_pages.enabled_by_server pref.
      */
     public static boolean isPrefetchingEnabledByServer() {
-        return PrefetchConfigurationJni.get().isEnabledByServer(ProfileKey.getLastUsedProfileKey());
+        // TODO(https://crbug.com/1067314): Use the current profile (i.e., regular profile or
+        // incognito profile) instead of always using regular profile. It is wrong and need to be
+        // fixed.
+        return PrefetchConfigurationJni.get().isEnabledByServer(
+                ProfileKey.getLastUsedRegularProfileKey());
     }
 
     /**
@@ -58,16 +65,22 @@
      * since the last check.
      */
     public static boolean isForbiddenCheckDue() {
+        // TODO(https://crbug.com/1067314): Use the current profile (i.e., regular profile or
+        // incognito profile) instead of always using regular profile. It is wrong and need to be
+        // fixed.
         return PrefetchConfigurationJni.get().isForbiddenCheckDue(
-                ProfileKey.getLastUsedProfileKey());
+                ProfileKey.getLastUsedRegularProfileKey());
     }
 
     /**
      * Returns true if the GeneratePageBundle-forbidden check has never run and is due to run.
      */
     public static boolean isEnabledByServerUnknown() {
+        // TODO(https://crbug.com/1067314): Use the current profile (i.e., regular profile or
+        // incognito profile) instead of always using regular profile. It is wrong and need to be
+        // fixed.
         return PrefetchConfigurationJni.get().isEnabledByServerUnknown(
-                ProfileKey.getLastUsedProfileKey());
+                ProfileKey.getLastUsedRegularProfileKey());
     }
 
     /**
@@ -75,8 +88,11 @@
      * enabled or disabled. If the current browser Profile is null the setting will not be changed.
      */
     public static void setPrefetchingEnabledInSettings(boolean enabled) {
+        // TODO(https://crbug.com/1067314): Use the current profile (i.e., regular profile or
+        // incognito profile) instead of always using regular profile. It is wrong and need to be
+        // fixed.
         PrefetchConfigurationJni.get().setPrefetchingEnabledInSettings(
-                ProfileKey.getLastUsedProfileKey(), enabled);
+                ProfileKey.getLastUsedRegularProfileKey(), enabled);
     }
 
     /**
@@ -84,8 +100,11 @@
      * enabled or disabled.
      */
     public static boolean isPrefetchingEnabledInSettings() {
+        // TODO(https://crbug.com/1067314): Use the current profile (i.e., regular profile or
+        // incognito profile) instead of always using regular profile. It is wrong and need to be
+        // fixed.
         return PrefetchConfigurationJni.get().isPrefetchingEnabledInSettings(
-                ProfileKey.getLastUsedProfileKey());
+                ProfileKey.getLastUsedRegularProfileKey());
     }
 
     @NativeMethods
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordEntryEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordEntryEditor.java
index a6750fc5..39ff09d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordEntryEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordEntryEditor.java
@@ -19,8 +19,9 @@
 
 import androidx.fragment.app.Fragment;
 
+import com.google.android.material.textfield.TextInputLayout;
+
 import org.chromium.chrome.R;
-import org.chromium.components.browser_ui.widget.text.ChromeTextInputLayout;
 import org.chromium.ui.widget.Toast;
 
 /**
@@ -32,7 +33,7 @@
     private EditText mUsernameText;
     private EditText mPasswordText;
     private ImageButton mViewPasswordButton;
-    private ChromeTextInputLayout mPasswordLabel;
+    private TextInputLayout mPasswordLabel;
     private boolean mViewButtonPressed;
     static final String VIEW_BUTTON_PRESSED = "viewButtonPressed";
     public static final String CREDENTIAL_URL = "credentialUrl";
@@ -53,7 +54,7 @@
         mSiteText = (EditText) view.findViewById(R.id.site_edit);
         mUsernameText = (EditText) view.findViewById(R.id.username_edit);
         mPasswordText = (EditText) view.findViewById(R.id.password_edit);
-        mPasswordLabel = (ChromeTextInputLayout) view.findViewById(R.id.password_label);
+        mPasswordLabel = (TextInputLayout) view.findViewById(R.id.password_label);
         mViewPasswordButton = view.findViewById(R.id.password_entry_editor_view_password);
         mSiteText.setText(getArguments().getString(CREDENTIAL_URL));
         mUsernameText.setText(getArguments().getString(CREDENTIAL_NAME));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderService.java b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderService.java
index b01d49aa..fbaa76f0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderService.java
@@ -50,6 +50,8 @@
 
     @Override
     public void onCreate() {
+        Log.i(TAG, "Decoder service process started");
+
         // DecoderService does not require flags, but LibraryLoader.ensureInitialized() checks for
         // --enable-low-end-device-mode. Rather than forwarding the flags from the browser process,
         // just assume no flags.
@@ -69,10 +71,13 @@
         mNativeLibraryAndSandboxInitialized = true;
 
         super.onCreate();
+
+        Log.i(TAG, "Decoder service process initialized");
     }
 
     @Override
     public IBinder onBind(Intent intent) {
+        Log.i(TAG, "Decoder process binding");
         return mBinder;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS b/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS
index 4172edd2..fceea841 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS
@@ -26,6 +26,10 @@
 ]
 
 specific_include_rules = {
+  'RedirectHandlerTabHelper\.java': [
+    "+chrome/android/java/src/org/chromium/chrome/browser/LaunchIntentDispatcher.java",
+    "+chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java",
+  ],
   'TabImpl\.java': [
     "+chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrModuleProvider.java",
     "+chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateImpl.java
index b3e1ffa1..6058a35d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateImpl.java
@@ -151,7 +151,7 @@
 
         TabRedirectHandler tabRedirectHandler = null;
         if (navigationParams.isMainFrame) {
-            tabRedirectHandler = TabRedirectHandler.from(mTab);
+            tabRedirectHandler = RedirectHandlerTabHelper.getOrCreateHandlerFor(mTab);
         } else if (navigationParams.isExternalProtocol) {
             // Only external protocol navigations are intercepted for iframe navigations.  Since
             // we do not see all previous navigations for the iframe, we can not build a complete
@@ -248,7 +248,7 @@
             NavigationController navigationController =
                     webContents.getNavigationController();
             int indexBeforeRedirection =
-                    TabRedirectHandler.from(mTab)
+                    RedirectHandlerTabHelper.getOrCreateHandlerFor(mTab)
                             .getLastCommittedEntryIndexBeforeStartingNavigation();
             int lastCommittedEntryIndex = getLastCommittedEntryIndex();
             for (int i = lastCommittedEntryIndex - 1; i > indexBeforeRedirection; --i) {
@@ -278,8 +278,8 @@
         // navigation is invalid, it means that this navigation is the first one since this tab was
         // created.
         // In such case, we would like to close this tab.
-        if (TabRedirectHandler.from(mTab).isOnNavigation()) {
-            return TabRedirectHandler.from(mTab)
+        if (RedirectHandlerTabHelper.getOrCreateHandlerFor(mTab).isOnNavigation()) {
+            return RedirectHandlerTabHelper.getOrCreateHandlerFor(mTab)
                            .getLastCommittedEntryIndexBeforeStartingNavigation()
                     == TabRedirectHandler.INVALID_ENTRY_INDEX;
         }
@@ -313,9 +313,9 @@
                     TabModelSelector.from(mTab).closeTab(mTab);
                 }
             });
-        } else if (TabRedirectHandler.from(mTab).isOnNavigation()) {
+        } else if (RedirectHandlerTabHelper.getOrCreateHandlerFor(mTab).isOnNavigation()) {
             int lastCommittedEntryIndexBeforeNavigation =
-                    TabRedirectHandler.from(mTab)
+                    RedirectHandlerTabHelper.getOrCreateHandlerFor(mTab)
                             .getLastCommittedEntryIndexBeforeStartingNavigation();
             if (getLastCommittedEntryIndex() > lastCommittedEntryIndexBeforeNavigation) {
                 // http://crbug/426679 : we want to go back to the last committed entry index which
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/RedirectHandlerTabHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/RedirectHandlerTabHelper.java
new file mode 100644
index 0000000..61d3966a
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/RedirectHandlerTabHelper.java
@@ -0,0 +1,98 @@
+// Copyright 2020 The Chromium 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.tab;
+
+import android.content.Intent;
+
+import androidx.annotation.Nullable;
+
+import org.chromium.base.IntentUtils;
+import org.chromium.base.UserData;
+import org.chromium.base.UserDataHost;
+import org.chromium.chrome.browser.LaunchIntentDispatcher;
+import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
+
+/**
+ * This class glues RedirectHandler instances to Tabs.
+ */
+public class RedirectHandlerTabHelper extends EmptyTabObserver implements UserData {
+    private static final Class<RedirectHandlerTabHelper> USER_DATA_KEY =
+            RedirectHandlerTabHelper.class;
+
+    private TabRedirectHandler mRedirectHandler;
+
+    /**
+     * Returns {@link TabRedirectHandler} that hangs on to a given {@link Tab}.
+     * If not present, creates a new instance and associate it with the {@link UserDataHost}
+     * that the {@link Tab} manages.
+     * @param tab Tab instance that the TabRedirectHandler hangs on to.
+     * @return TabRedirectHandler for a given Tab.
+     */
+    public static TabRedirectHandler getOrCreateHandlerFor(Tab tab) {
+        UserDataHost host = tab.getUserDataHost();
+        RedirectHandlerTabHelper helper = host.getUserData(USER_DATA_KEY);
+        if (helper == null) {
+            helper = new RedirectHandlerTabHelper();
+            host.setUserData(USER_DATA_KEY, helper);
+            tab.addObserver(helper);
+        }
+        return helper.mRedirectHandler;
+    }
+
+    /**
+     * @return {@link TabRedirectHandler} hanging to the given {@link Tab},
+     *     or {@code null} if there is no instance available.
+     */
+    @Nullable
+    public static TabRedirectHandler getHandlerFor(Tab tab) {
+        RedirectHandlerTabHelper helper = tab.getUserDataHost().getUserData(USER_DATA_KEY);
+        if (helper == null) return null;
+        return helper.mRedirectHandler;
+    }
+
+    /**
+     * Replace {@link TabRedirectHandler} instance for the Tab with the new one.
+     * @return Old {@link TabRedirectHandler} associated with the Tab. Could be {@code null}.
+     */
+    public static TabRedirectHandler swapHandlerFor(
+            Tab tab, @Nullable TabRedirectHandler newHandler) {
+        UserDataHost host = tab.getUserDataHost();
+        RedirectHandlerTabHelper oldHelper = host.getUserData(USER_DATA_KEY);
+        if (newHandler != null) {
+            RedirectHandlerTabHelper newHelper = new RedirectHandlerTabHelper(newHandler);
+            host.setUserData(USER_DATA_KEY, newHelper);
+        } else {
+            host.removeUserData(USER_DATA_KEY);
+        }
+
+        if (oldHelper == null) return null;
+        return oldHelper.mRedirectHandler;
+    }
+
+    private RedirectHandlerTabHelper() {
+        mRedirectHandler = new TabRedirectHandler();
+    }
+
+    private RedirectHandlerTabHelper(TabRedirectHandler handler) {
+        mRedirectHandler = handler;
+    }
+
+    @Override
+    public void onHidden(Tab tab, @TabHidingType int type) {
+        mRedirectHandler.clear();
+    }
+
+    /**
+     * Wrapper around TabRedirectHandler#updateIntent() that supplies //chrome-level params.
+     */
+    public static void updateIntentInTab(Tab tab, Intent intent) {
+        RedirectHandlerTabHelper.getOrCreateHandlerFor(tab).updateIntent(intent,
+                LaunchIntentDispatcher.isCustomTabIntent(intent),
+                IntentUtils.safeGetBooleanExtra(intent,
+                        CustomTabIntentDataProvider.EXTRA_SEND_TO_EXTERNAL_DEFAULT_HANDLER, false),
+                ChromeFeatureList.isEnabled(ChromeFeatureList.CCT_EXTERNAL_LINK_HANDLING));
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabRedirectHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabRedirectHandler.java
index c8df1b7..6b17c24 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabRedirectHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabRedirectHandler.java
@@ -11,16 +11,9 @@
 import android.provider.Browser;
 import android.text.TextUtils;
 
-import androidx.annotation.Nullable;
-
 import org.chromium.base.ContextUtils;
 import org.chromium.base.IntentUtils;
 import org.chromium.base.PackageManagerUtils;
-import org.chromium.base.UserData;
-import org.chromium.base.UserDataHost;
-import org.chromium.chrome.browser.LaunchIntentDispatcher;
-import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.components.external_intents.RedirectHandler;
 import org.chromium.ui.base.PageTransition;
 
@@ -30,8 +23,7 @@
 /**
  * This class contains the logic to determine effective navigation/redirect.
  */
-public class TabRedirectHandler extends EmptyTabObserver implements UserData, RedirectHandler {
-    private static final Class<TabRedirectHandler> USER_DATA_KEY = TabRedirectHandler.class;
+public class TabRedirectHandler implements RedirectHandler {
     /**
      * An invalid entry index.
      */
@@ -58,59 +50,12 @@
 
     private boolean mShouldNotOverrideUrlLoadingOnCurrentRedirectChain;
 
-    /**
-     * Returns {@link TabRedirectHandler} that hangs on to a given {@link Tab}.
-     * If not present, creates a new instance and associate it with the {@link UserDataHost}
-     * that the {@link Tab} manages.
-     * @param tab Tab instance that the TabRedirectHandler hangs on to.
-     * @return TabRedirectHandler for a given Tab.
-     */
-    public static TabRedirectHandler from(Tab tab) {
-        UserDataHost host = tab.getUserDataHost();
-        TabRedirectHandler handler = host.getUserData(USER_DATA_KEY);
-        if (handler == null) {
-            handler = new TabRedirectHandler();
-            host.setUserData(USER_DATA_KEY, handler);
-            tab.addObserver(handler);
-        }
-        return handler;
-    }
-
-    /**
-     * @return {@link TabRedirectHandler} hanging to the given {@link Tab},
-     *     or {@code null} if there is no instance available.
-     */
-    @Nullable
-    public static TabRedirectHandler get(Tab tab) {
-        return tab.getUserDataHost().getUserData(USER_DATA_KEY);
-    }
-
-    /**
-     * Replace {@link TabRedirectHandler} instance for the Tab with the new one.
-     * @return Old {@link TabRedirectHandler} associated with the Tab. Could be {@code null}.
-     */
-    public static TabRedirectHandler swapFor(Tab tab, @Nullable TabRedirectHandler newHandler) {
-        UserDataHost host = tab.getUserDataHost();
-        TabRedirectHandler oldHandler = host.getUserData(USER_DATA_KEY);
-        if (newHandler != null) {
-            host.setUserData(USER_DATA_KEY, newHandler);
-        } else {
-            host.removeUserData(USER_DATA_KEY);
-        }
-        return oldHandler;
-    }
-
     public static TabRedirectHandler create() {
         return new TabRedirectHandler();
     }
 
     protected TabRedirectHandler() {}
 
-    @Override
-    public void onHidden(Tab tab, @TabHidingType int type) {
-        clear();
-    }
-
     /**
      * Updates |mIntentHistory| and |mLastIntentUpdatedTime|. If |intent| comes from chrome and
      * currently |mIsOnEffectiveIntentRedirectChain| is true, that means |intent| was sent from
@@ -119,23 +64,21 @@
      * Otherwise, |mIntentHistory| and |mPreviousResolvers| are cleared, and then |intent| is put
      * into |mIntentHistory|.
      */
-    public void updateIntent(Intent intent) {
+    public void updateIntent(Intent intent, boolean isCustomTabIntent, boolean sendToExternalApps,
+            boolean isCCTExternalLinkHandlingEnabled) {
         clear();
 
         if (intent == null || !Intent.ACTION_VIEW.equals(intent.getAction())) {
             return;
         }
 
-        mIsCustomTabIntent = LaunchIntentDispatcher.isCustomTabIntent(intent);
+        mIsCustomTabIntent = isCustomTabIntent;
         boolean checkIsToChrome = true;
         // All custom tabs VIEW intents are by design explicit intents, so the presence of package
         // name doesn't imply they have to be handled by Chrome explicitly. Check if external apps
         // should be checked for handling the initial redirect chain.
         if (mIsCustomTabIntent) {
-            boolean sendToExternalApps = IntentUtils.safeGetBooleanExtra(intent,
-                    CustomTabIntentDataProvider.EXTRA_SEND_TO_EXTERNAL_DEFAULT_HANDLER, false);
-            checkIsToChrome = !(sendToExternalApps
-                    && ChromeFeatureList.isEnabled(ChromeFeatureList.CCT_EXTERNAL_LINK_HANDLING));
+            checkIsToChrome = !(sendToExternalApps && isCCTExternalLinkHandlingEnabled);
         }
 
         if (checkIsToChrome) mIsInitialIntentHeadingToChrome = isIntentToChrome(intent);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java
index 46a0ad23..c226b3f1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java
@@ -18,6 +18,7 @@
 import org.chromium.chrome.browser.ServiceTabLauncher;
 import org.chromium.chrome.browser.init.StartupTabPreloader;
 import org.chromium.chrome.browser.ntp.NewTabPage;
+import org.chromium.chrome.browser.tab.RedirectHandlerTabHelper;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabAssociatedApp;
 import org.chromium.chrome.browser.tab.TabBuilder;
@@ -25,7 +26,6 @@
 import org.chromium.chrome.browser.tab.TabDelegateFactory;
 import org.chromium.chrome.browser.tab.TabLaunchType;
 import org.chromium.chrome.browser.tab.TabParentIntent;
-import org.chromium.chrome.browser.tab.TabRedirectHandler;
 import org.chromium.chrome.browser.tab.TabState;
 import org.chromium.chrome.browser.tab_activity_glue.ReparentingDelegateFactory;
 import org.chromium.chrome.browser.tab_activity_glue.ReparentingTask;
@@ -214,7 +214,7 @@
                     TraceEvent.end("ChromeTabCreator.loadUrl");
                 }
             }
-            TabRedirectHandler.from(tab).updateIntent(intent);
+            RedirectHandlerTabHelper.updateIntentInTab(tab, intent);
             if (intent != null && intent.hasExtra(ServiceTabLauncher.LAUNCH_REQUEST_ID_EXTRA)) {
                 ServiceTabLauncher.onWebContentsForRequestAvailable(
                         intent.getIntExtra(ServiceTabLauncher.LAUNCH_REQUEST_ID_EXTRA, 0),
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
index 7c3034e..96dbe50 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
@@ -141,7 +141,8 @@
         public final List<Integer> ids;
         public final List<String> urls;
 
-        TabModelMetadata(int selectedIndex) {
+        @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+        public TabModelMetadata(int selectedIndex) {
             index = selectedIndex;
             ids = new ArrayList<>();
             urls = new ArrayList<>();
@@ -862,8 +863,6 @@
     public static byte[] serializeMetadata(TabModelMetadata standardInfo,
             TabModelMetadata incognitoInfo, @Nullable List<TabRestoreDetails> tabsBeingRestored)
             throws IOException {
-        ThreadUtils.assertOnUiThread();
-
         int standardCount = standardInfo.ids.size();
         int incognitoCount = incognitoInfo.ids.size();
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/InstantStartTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/InstantStartTest.java
index b8a64f5..e1b9524 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/InstantStartTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/InstantStartTest.java
@@ -8,7 +8,11 @@
 
 import android.content.Intent;
 import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
 import android.support.test.filters.SmallTest;
+import android.widget.ImageView;
+
+import androidx.recyclerview.widget.RecyclerView;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -20,6 +24,7 @@
 import org.chromium.base.Callback;
 import org.chromium.base.library_loader.LibraryLoader;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.Matchers;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.browser.compositor.layouts.LayoutManagerChromePhone;
@@ -28,19 +33,32 @@
 import org.chromium.chrome.browser.flags.CachedFeatureFlags;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.browser.tabmodel.TabPersistentStore;
+import org.chromium.chrome.browser.tabmodel.TabPersistentStore.TabModelMetadata;
+import org.chromium.chrome.browser.tabmodel.TabbedModeTabPersistencePolicy;
 import org.chromium.chrome.browser.tasks.ReturnToChromeExperimentsUtil;
+import org.chromium.chrome.browser.tasks.pseudotab.TabAttributeCache;
+import org.chromium.chrome.browser.tasks.tab_management.TabManagementDelegate;
+import org.chromium.chrome.browser.tasks.tab_management.TabManagementModuleProvider;
+import org.chromium.chrome.features.start_surface.StartSurface;
 import org.chromium.chrome.features.start_surface.StartSurfaceLayout;
+import org.chromium.chrome.tab_ui.R;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.chrome.test.util.ChromeRenderTestRule;
 import org.chromium.chrome.test.util.browser.Features;
+import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
+import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
+import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.ui.test.util.UiRestriction;
 
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * Integration tests of Instant Start which requires 2-stage initialization for Clank startup.
@@ -48,7 +66,7 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 // clang-format off
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
-@Features.EnableFeatures({ChromeFeatureList.TAB_GRID_LAYOUT_ANDROID,
+@EnableFeatures({ChromeFeatureList.TAB_GRID_LAYOUT_ANDROID,
         ChromeFeatureList.START_SURFACE_ANDROID, ChromeFeatureList.INSTANT_START})
 public class InstantStartTest {
     // clang-format on
@@ -63,6 +81,9 @@
     @Rule
     public TestRule mProcessor = new Features.InstrumentationProcessor();
 
+    @Rule
+    public ChromeRenderTestRule mRenderTestRule = new ChromeRenderTestRule();
+
     @Before
     public void setUp() {
         startMainActivityFromLauncher();
@@ -100,6 +121,33 @@
         return thumbnailBitmap;
     }
 
+    private void createCorruptedTabStateFile() throws IOException {
+        File stateFile =
+                new File(TabbedModeTabPersistencePolicy.getOrCreateTabbedModeStateDirectory(),
+                        TabbedModeTabPersistencePolicy.getStateFileName(0));
+        FileOutputStream output = new FileOutputStream(stateFile);
+        output.write(0);
+        output.close();
+    }
+
+    private void createTabStateFile(int[] tabIds) throws IOException {
+        TabModelMetadata normalInfo = new TabModelMetadata(0);
+        for (int tabId : tabIds) {
+            normalInfo.ids.add(tabId);
+            normalInfo.urls.add("");
+        }
+        TabModelMetadata incognitoInfo = new TabModelMetadata(0);
+
+        byte[] listData = TabPersistentStore.serializeMetadata(normalInfo, incognitoInfo, null);
+
+        File stateFile =
+                new File(TabbedModeTabPersistencePolicy.getOrCreateTabbedModeStateDirectory(),
+                        TabbedModeTabPersistencePolicy.getStateFileName(0));
+        FileOutputStream output = new FileOutputStream(stateFile);
+        output.write(listData);
+        output.close();
+    }
+
     /**
      * Test TabContentManager is able to fetch thumbnail jpeg files before native is initialized.
      */
@@ -141,11 +189,11 @@
 
     @Test
     @SmallTest
+    @Restriction({UiRestriction.RESTRICTION_TYPE_PHONE})
     // clang-format off
     @CommandLineFlags.Add({ChromeSwitches.DISABLE_NATIVE_INITIALIZATION,
             "enable-features=" + ChromeFeatureList.TAB_SWITCHER_ON_RETURN + "<Study",
             "force-fieldtrials=Study/Group", IMMEDIATE_RETURN_PARAMS})
-    @Restriction({UiRestriction.RESTRICTION_TYPE_PHONE})
     public void layoutManagerChromePhonePreNativeTest() {
         // clang-format on
         Assert.assertFalse(mActivityTestRule.getActivity().isTablet());
@@ -176,4 +224,116 @@
         assertThat(mActivityTestRule.getActivity().getLayoutManager())
                 .isInstanceOf(LayoutManagerChromeTablet.class);
     }
-}
\ No newline at end of file
+
+    private void showOverview() {
+        AtomicReference<StartSurface> startSurface = new AtomicReference<>();
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            TabManagementDelegate tabManagementDelegate = TabManagementModuleProvider.getDelegate();
+            startSurface.set(
+                    tabManagementDelegate.createStartSurface(mActivityTestRule.getActivity()));
+            startSurface.get().getController().showOverview(false);
+        });
+        Assert.assertTrue(startSurface.get().getController().overviewVisible());
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"RenderTest"})
+    @Restriction({UiRestriction.RESTRICTION_TYPE_PHONE})
+    @CommandLineFlags.Add({ChromeSwitches.DISABLE_NATIVE_INITIALIZATION})
+    // TODO(crbug/1065314): make showOverview() work with START_SURFACE_ANDROID.
+    @DisableFeatures({ChromeFeatureList.START_SURFACE_ANDROID})
+    public void renderTabSwitcher_NoStateFile() throws IOException {
+        showOverview();
+
+        mRenderTestRule.render(mActivityTestRule.getActivity().findViewById(R.id.tab_list_view),
+                "tabSwitcher_empty");
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"RenderTest"})
+    @Restriction({UiRestriction.RESTRICTION_TYPE_PHONE})
+    @CommandLineFlags.Add({ChromeSwitches.DISABLE_NATIVE_INITIALIZATION})
+    // TODO(crbug/1065314): make showOverview() work with START_SURFACE_ANDROID.
+    @DisableFeatures({ChromeFeatureList.START_SURFACE_ANDROID})
+    public void renderTabSwitcher_CorruptedStateFile() throws IOException {
+        createCorruptedTabStateFile();
+        showOverview();
+
+        mRenderTestRule.render(mActivityTestRule.getActivity().findViewById(R.id.tab_list_view),
+                "tabSwitcher_empty");
+    }
+
+    private boolean allCardsHaveThumbnail(RecyclerView recyclerView) {
+        RecyclerView.Adapter adapter = recyclerView.getAdapter();
+        assert adapter != null;
+        for (int i = 0; i < adapter.getItemCount(); i++) {
+            RecyclerView.ViewHolder viewHolder = recyclerView.findViewHolderForAdapterPosition(i);
+            if (viewHolder != null) {
+                ImageView thumbnail = viewHolder.itemView.findViewById(R.id.tab_thumbnail);
+                BitmapDrawable drawable = (BitmapDrawable) thumbnail.getDrawable();
+                Bitmap bitmap = drawable.getBitmap();
+                if (bitmap == null) return false;
+            }
+        }
+        return true;
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"RenderTest"})
+    @Restriction({UiRestriction.RESTRICTION_TYPE_PHONE})
+    @CommandLineFlags.Add({ChromeSwitches.DISABLE_NATIVE_INITIALIZATION})
+    // TODO(crbug/1065314): make showOverview() work with START_SURFACE_ANDROID.
+    @DisableFeatures({ChromeFeatureList.START_SURFACE_ANDROID})
+    public void renderTabSwitcher() throws IOException {
+        createTabStateFile(new int[] {0, 1, 2});
+        createThumbnailBitmapAndWriteToFile(0);
+        createThumbnailBitmapAndWriteToFile(1);
+        createThumbnailBitmapAndWriteToFile(2);
+        TabAttributeCache.setTitleForTesting(0, "title");
+        TabAttributeCache.setTitleForTesting(1, "漢字");
+        TabAttributeCache.setTitleForTesting(2, "اَلْعَرَبِيَّةُ");
+
+        showOverview();
+
+        RecyclerView recyclerView =
+                mActivityTestRule.getActivity().findViewById(R.id.tab_list_view);
+        CriteriaHelper.pollUiThread(
+                Criteria.equals(true, () -> allCardsHaveThumbnail(recyclerView)));
+        mRenderTestRule.render(mActivityTestRule.getActivity().findViewById(R.id.tab_list_view),
+                "tabSwitcher_3tabs");
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"RenderTest"})
+    @Restriction({UiRestriction.RESTRICTION_TYPE_PHONE})
+    @CommandLineFlags.Add({ChromeSwitches.DISABLE_NATIVE_INITIALIZATION})
+    @EnableFeatures(ChromeFeatureList.TAB_GROUPS_ANDROID)
+    // TODO(crbug/1065314): make showOverview() work with START_SURFACE_ANDROID.
+    @DisableFeatures({ChromeFeatureList.START_SURFACE_ANDROID})
+    public void renderTabGroups() throws IOException {
+        createTabStateFile(new int[] {0, 1, 2, 3, 4});
+        createThumbnailBitmapAndWriteToFile(0);
+        createThumbnailBitmapAndWriteToFile(1);
+        createThumbnailBitmapAndWriteToFile(2);
+        createThumbnailBitmapAndWriteToFile(3);
+        createThumbnailBitmapAndWriteToFile(4);
+        TabAttributeCache.setRootIdForTesting(0, 0);
+        TabAttributeCache.setRootIdForTesting(1, 0);
+        TabAttributeCache.setRootIdForTesting(2, 0);
+        TabAttributeCache.setRootIdForTesting(3, 3);
+        TabAttributeCache.setRootIdForTesting(4, 3);
+
+        showOverview();
+
+        RecyclerView recyclerView =
+                mActivityTestRule.getActivity().findViewById(R.id.tab_list_view);
+        CriteriaHelper.pollUiThread(
+                Criteria.equals(true, () -> allCardsHaveThumbnail(recyclerView)));
+        mRenderTestRule.render(mActivityTestRule.getActivity().findViewById(R.id.tab_list_view),
+                "tabSwitcher_tabGroups");
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java
index 27f2020..f369239 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java
@@ -50,11 +50,11 @@
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tabmodel.TabModelUtils;
 import org.chromium.chrome.browser.tasks.tab_management.TabListCoordinator;
+import org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper;
 import org.chromium.chrome.browser.util.AccessibilityUtil;
 import org.chromium.chrome.features.start_surface.StartSurfaceLayout;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
-import org.chromium.chrome.test.util.ApplicationTestUtils;
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.chrome.test.util.browser.tabmodel.MockTabModel.MockTabModelDelegate;
 import org.chromium.chrome.test.util.browser.tabmodel.MockTabModelSelector;
@@ -535,12 +535,12 @@
         CachedFeatureFlags.setForTesting(ChromeFeatureList.TAB_GRID_LAYOUT_ANDROID, true);
         verifyOverviewListLayoutEnabled();
 
-        ApplicationTestUtils.finishActivity(mActivityTestRule.getActivity());
+        TabUiTestHelper.finishActivity(mActivityTestRule.getActivity());
         CachedFeatureFlags.setForTesting(ChromeFeatureList.TAB_GROUPS_ANDROID, false);
         verifyOverviewListLayoutEnabled();
 
         // Test accessibility
-        ApplicationTestUtils.finishActivity(mActivityTestRule.getActivity());
+        TabUiTestHelper.finishActivity(mActivityTestRule.getActivity());
         AccessibilityUtil.setAccessibilityEnabledForTesting(true);
         verifyOverviewListLayoutEnabled();
     }
@@ -559,7 +559,7 @@
         verifyStackLayoutEnabled();
 
         // Verify accessibility
-        ApplicationTestUtils.finishActivity(mActivityTestRule.getActivity());
+        TabUiTestHelper.finishActivity(mActivityTestRule.getActivity());
         enableAccessibility(true);
         verifyOverviewListLayoutEnabled();
     }
@@ -591,12 +591,12 @@
         CachedFeatureFlags.setForTesting(ChromeFeatureList.TAB_GRID_LAYOUT_ANDROID, true);
         verifyStartSurfaceLayoutEnable(TabListCoordinator.TabListMode.GRID);
 
-        ApplicationTestUtils.finishActivity(mActivityTestRule.getActivity());
+        TabUiTestHelper.finishActivity(mActivityTestRule.getActivity());
         CachedFeatureFlags.setForTesting(ChromeFeatureList.TAB_GRID_LAYOUT_ANDROID, false);
         verifyStartSurfaceLayoutEnable(TabListCoordinator.TabListMode.GRID);
 
         // Verify accessibility
-        ApplicationTestUtils.finishActivity(mActivityTestRule.getActivity());
+        TabUiTestHelper.finishActivity(mActivityTestRule.getActivity());
         AccessibilityUtil.setAccessibilityEnabledForTesting(true);
         verifyStartSurfaceLayoutEnable(TabListCoordinator.TabListMode.GRID);
     }
@@ -615,7 +615,7 @@
         verifyStartSurfaceLayoutEnable(TabListCoordinator.TabListMode.LIST);
 
         // Test Accessibility
-        ApplicationTestUtils.finishActivity(mActivityTestRule.getActivity());
+        TabUiTestHelper.finishActivity(mActivityTestRule.getActivity());
         AccessibilityUtil.setAccessibilityEnabledForTesting(true);
         verifyStartSurfaceLayoutEnable(TabListCoordinator.TabListMode.LIST);
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
index 37c69b6..4e96e19 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
@@ -33,10 +33,7 @@
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.DisableIf;
-import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.tab.TabRedirectHandler;
-import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.components.external_intents.ExternalNavigationDelegate;
 import org.chromium.components.external_intents.ExternalNavigationHandler;
 import org.chromium.components.external_intents.ExternalNavigationHandler.OverrideUrlLoadingResult;
@@ -57,15 +54,11 @@
 // clang-format off
 @DisableIf.Build(message = "Flaky on K - see https://crbug.com/851444",
         sdk_is_less_than = Build.VERSION_CODES.LOLLIPOP)
-@Features.EnableFeatures({ChromeFeatureList.CCT_EXTERNAL_LINK_HANDLING})
 public class ExternalNavigationHandlerTest {
     // clang-format on
     @Rule
     public final NativeLibraryTestRule mNativeLibraryTestRule = new NativeLibraryTestRule();
 
-    @Rule
-    public Features.JUnitProcessor processor = new Features.JUnitProcessor();
-
     // Expectations
     private static final int IGNORE = 0x0;
     private static final int START_INCOGNITO = 0x1;
@@ -75,6 +68,10 @@
     private static final int INTENT_SANITIZATION_EXCEPTION = 0x20;
     private static final int PROXY_FOR_INSTANT_APPS = 0x40;
 
+    private static final boolean IS_CUSTOM_TAB_INTENT = true;
+    private static final boolean SEND_TO_EXTERNAL_APPS = true;
+    private static final boolean IS_CCT_EXTERNAL_LINK_HANDLING_ENABLED = true;
+
     private static final String SEARCH_RESULT_URL_FOR_TOM_HANKS =
             "https://www.google.com/search?q=tom+hanks";
     private static final String IMDB_WEBPAGE_FOR_TOM_HANKS = "http://m.imdb.com/name/nm0000158";
@@ -549,7 +546,8 @@
 
         // Ignore if url is redirected, transition type is IncomingIntent and a new intent doesn't
         // have any new resolver.
-        redirectHandler.updateIntent(ytIntent);
+        redirectHandler.updateIntent(ytIntent, !IS_CUSTOM_TAB_INTENT, !SEND_TO_EXTERNAL_APPS,
+                IS_CCT_EXTERNAL_LINK_HANDLING_ENABLED);
         redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0);
         redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, true, false, 0, 0);
         checkUrl(YOUTUBE_MOBILE_URL)
@@ -559,7 +557,8 @@
                 .expecting(OverrideUrlLoadingResult.NO_OVERRIDE, IGNORE);
 
         // Do not ignore if a new intent has any new resolver.
-        redirectHandler.updateIntent(fooIntent);
+        redirectHandler.updateIntent(fooIntent, !IS_CUSTOM_TAB_INTENT, !SEND_TO_EXTERNAL_APPS,
+                IS_CCT_EXTERNAL_LINK_HANDLING_ENABLED);
         redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0);
         redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, true, false, 0, 0);
         checkUrl(YOUTUBE_MOBILE_URL)
@@ -570,7 +569,8 @@
                         START_OTHER_ACTIVITY);
 
         // Do not ignore if a new intent cannot be handled by Chrome.
-        redirectHandler.updateIntent(fooIntent);
+        redirectHandler.updateIntent(fooIntent, !IS_CUSTOM_TAB_INTENT, !SEND_TO_EXTERNAL_APPS,
+                IS_CCT_EXTERNAL_LINK_HANDLING_ENABLED);
         redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0);
         redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, true, false, 0, 0);
         checkUrl("intent://myownurl")
@@ -594,7 +594,8 @@
                 | PageTransition.FROM_API;
 
         // Ignore if an initial Intent was heading to Chrome.
-        redirectHandler.updateIntent(fooIntent);
+        redirectHandler.updateIntent(fooIntent, !IS_CUSTOM_TAB_INTENT, !SEND_TO_EXTERNAL_APPS,
+                IS_CCT_EXTERNAL_LINK_HANDLING_ENABLED);
         redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0);
         redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, true, false, 0, 0);
         checkUrl(YOUTUBE_MOBILE_URL)
@@ -604,7 +605,8 @@
                 .expecting(OverrideUrlLoadingResult.NO_OVERRIDE, IGNORE);
 
         // Do not ignore if the URI has an external protocol.
-        redirectHandler.updateIntent(fooIntent);
+        redirectHandler.updateIntent(fooIntent, !IS_CUSTOM_TAB_INTENT, !SEND_TO_EXTERNAL_APPS,
+                IS_CCT_EXTERNAL_LINK_HANDLING_ENABLED);
         redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0);
         redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, true, false, 0, 0);
         checkUrl("market://1234")
@@ -626,9 +628,9 @@
 
         // In Custom Tabs, if the first url is not a redirect, stay in chrome.
         Intent barIntent = Intent.parseUri(YOUTUBE_URL, Intent.URI_INTENT_SCHEME);
-        barIntent.putExtra(CustomTabsIntent.EXTRA_SESSION, "");
         barIntent.setPackage(mContext.getPackageName());
-        redirectHandler.updateIntent(barIntent);
+        redirectHandler.updateIntent(barIntent, IS_CUSTOM_TAB_INTENT, !SEND_TO_EXTERNAL_APPS,
+                IS_CCT_EXTERNAL_LINK_HANDLING_ENABLED);
         redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0);
         checkUrl(YOUTUBE_URL)
                 .withPageTransition(transTypeLinkFromIntent)
@@ -637,9 +639,9 @@
 
         // In Custom Tabs, if the first url is a redirect, don't allow it to intent out.
         Intent fooIntent = Intent.parseUri("http://foo.com/", Intent.URI_INTENT_SCHEME);
-        fooIntent.putExtra(CustomTabsIntent.EXTRA_SESSION, "");
         fooIntent.setPackage(mContext.getPackageName());
-        redirectHandler.updateIntent(fooIntent);
+        redirectHandler.updateIntent(fooIntent, IS_CUSTOM_TAB_INTENT, !SEND_TO_EXTERNAL_APPS,
+                IS_CCT_EXTERNAL_LINK_HANDLING_ENABLED);
         redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0);
         redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, true, false, 0, 0);
         checkUrl(YOUTUBE_URL)
@@ -651,11 +653,9 @@
         // In Custom Tabs, if the external handler extra is present, intent out if the first
         // url is a redirect.
         Intent extraIntent2 = Intent.parseUri(YOUTUBE_URL, Intent.URI_INTENT_SCHEME);
-        extraIntent2.putExtra(CustomTabsIntent.EXTRA_SESSION, "");
-        extraIntent2.putExtra(
-                CustomTabIntentDataProvider.EXTRA_SEND_TO_EXTERNAL_DEFAULT_HANDLER, true);
         extraIntent2.setPackage(mContext.getPackageName());
-        redirectHandler.updateIntent(extraIntent2);
+        redirectHandler.updateIntent(extraIntent2, IS_CUSTOM_TAB_INTENT, SEND_TO_EXTERNAL_APPS,
+                IS_CCT_EXTERNAL_LINK_HANDLING_ENABLED);
         redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0);
         redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, true, false, 0, 0);
         checkUrl(YOUTUBE_URL)
@@ -666,11 +666,9 @@
                         START_OTHER_ACTIVITY);
 
         Intent extraIntent3 = Intent.parseUri(YOUTUBE_URL, Intent.URI_INTENT_SCHEME);
-        extraIntent3.putExtra(CustomTabsIntent.EXTRA_SESSION, "");
-        extraIntent3.putExtra(
-                CustomTabIntentDataProvider.EXTRA_SEND_TO_EXTERNAL_DEFAULT_HANDLER, true);
         extraIntent3.setPackage(mContext.getPackageName());
-        redirectHandler.updateIntent(extraIntent3);
+        redirectHandler.updateIntent(extraIntent3, IS_CUSTOM_TAB_INTENT, SEND_TO_EXTERNAL_APPS,
+                IS_CCT_EXTERNAL_LINK_HANDLING_ENABLED);
         redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0);
         redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0);
         checkUrl(YOUTUBE_URL)
@@ -681,7 +679,8 @@
                         START_OTHER_ACTIVITY);
 
         // External intent for a user-initiated navigation should always be allowed.
-        redirectHandler.updateIntent(fooIntent);
+        redirectHandler.updateIntent(fooIntent, IS_CUSTOM_TAB_INTENT, !SEND_TO_EXTERNAL_APPS,
+                IS_CCT_EXTERNAL_LINK_HANDLING_ENABLED);
         redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0);
         // Simulate a real user navigation.
         redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, true,
@@ -703,10 +702,10 @@
         // In Custom Tabs, if the first url is a redirect, don't allow it to intent out, unless
         // the redirect is going to Instant Apps.
         Intent fooIntent = Intent.parseUri("http://foo.com/", Intent.URI_INTENT_SCHEME);
-        fooIntent.putExtra(CustomTabsIntent.EXTRA_SESSION, "");
         fooIntent.putExtra(CustomTabsIntent.EXTRA_ENABLE_INSTANT_APPS, true);
         fooIntent.setPackage(mContext.getPackageName());
-        redirectHandler.updateIntent(fooIntent);
+        redirectHandler.updateIntent(fooIntent, IS_CUSTOM_TAB_INTENT, !SEND_TO_EXTERNAL_APPS,
+                IS_CCT_EXTERNAL_LINK_HANDLING_ENABLED);
         redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0);
         redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, true, false, 0, 0);
 
@@ -726,7 +725,8 @@
         TabRedirectHandler redirectHandler = TabRedirectHandler.create();
         Intent fooIntent = Intent.parseUri("http://instantappenabled.com",
                 Intent.URI_INTENT_SCHEME);
-        redirectHandler.updateIntent(fooIntent);
+        redirectHandler.updateIntent(fooIntent, !IS_CUSTOM_TAB_INTENT, !SEND_TO_EXTERNAL_APPS,
+                IS_CCT_EXTERNAL_LINK_HANDLING_ENABLED);
         redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0);
         redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, true, false, 0, 0);
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabRedirectHandlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabRedirectHandlerTest.java
index 23c4f4f..027de0e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabRedirectHandlerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabRedirectHandlerTest.java
@@ -68,7 +68,7 @@
     @Feature({"IntentHandling"})
     public void testRealIntentRedirect() {
         TabRedirectHandler handler = TabRedirectHandler.create();
-        handler.updateIntent(sYtIntent);
+        handler.updateIntent(sYtIntent, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
 
         handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, false, false, 0, 0);
@@ -88,7 +88,7 @@
     @Feature({"IntentHandling"})
     public void testEffectiveIntentRedirect_linkNavigation() {
         TabRedirectHandler handler = TabRedirectHandler.create();
-        handler.updateIntent(sYtIntent);
+        handler.updateIntent(sYtIntent, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
 
         handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, false, false, 0, 0);
@@ -108,7 +108,7 @@
     @Feature({"IntentHandling"})
     public void testEffectiveIntentRedirect_formSubmit() {
         TabRedirectHandler handler = TabRedirectHandler.create();
-        handler.updateIntent(sYtIntent);
+        handler.updateIntent(sYtIntent, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
 
         handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, false, false, 0, 0);
@@ -128,7 +128,7 @@
     @Feature({"IntentHandling"})
     public void testNoIntent() {
         TabRedirectHandler handler = TabRedirectHandler.create();
-        handler.updateIntent(null);
+        handler.updateIntent(null, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
 
         handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, false, false, 0, 0);
@@ -148,7 +148,7 @@
     @Feature({"IntentHandling"})
     public void testClear() {
         TabRedirectHandler handler = TabRedirectHandler.create();
-        handler.updateIntent(sYtIntent);
+        handler.updateIntent(sYtIntent, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
 
         handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, false, false, 0, 0);
@@ -173,7 +173,7 @@
     @Feature({"IntentHandling"})
     public void testNonLinkFromIntent() {
         TabRedirectHandler handler = TabRedirectHandler.create();
-        handler.updateIntent(sYtIntent);
+        handler.updateIntent(sYtIntent, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
 
         handler.updateNewUrlLoading(PageTransition.TYPED, false, false, 0, 0);
@@ -193,7 +193,7 @@
     @Feature({"IntentHandling"})
     public void testUserInteraction() {
         TabRedirectHandler handler = TabRedirectHandler.create();
-        handler.updateIntent(sYtIntent);
+        handler.updateIntent(sYtIntent, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
 
         handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, false, false, 0, 0);
@@ -224,7 +224,7 @@
         TabRedirectHandler handler = TabRedirectHandler.create();
         Intent fooIntent = new Intent(sFooIntent);
         fooIntent.putExtra(Browser.EXTRA_APPLICATION_ID, TEST_PACKAGE_NAME);
-        handler.updateIntent(fooIntent);
+        handler.updateIntent(fooIntent, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
         Assert.assertTrue(handler.shouldStayInApp(false));
         Assert.assertFalse(handler.shouldStayInApp(true));
@@ -254,7 +254,7 @@
     @Feature({"IntentHandling"})
     public void testNavigationFromUserTyping() {
         TabRedirectHandler handler = TabRedirectHandler.create();
-        handler.updateIntent(sYtIntent);
+        handler.updateIntent(sYtIntent, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
         Assert.assertFalse(handler.isNavigationFromUserTyping());
 
@@ -282,7 +282,7 @@
         TabRedirectHandler handler = TabRedirectHandler.create();
         Intent fooIntent = new Intent(sFooIntent);
         fooIntent.setPackage(TEST_PACKAGE_NAME);
-        handler.updateIntent(fooIntent);
+        handler.updateIntent(fooIntent, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
         Assert.assertTrue(handler.shouldStayInApp(false));
         Assert.assertFalse(handler.shouldStayInApp(true));
@@ -315,7 +315,7 @@
         // 1. 3XX redirection should not override URL loading.
         /////////////////////////////////////////////////////
         TabRedirectHandler handler = TabRedirectHandler.create();
-        handler.updateIntent(sYtIntent);
+        handler.updateIntent(sYtIntent, false, false, false);
         Assert.assertFalse(handler.shouldNotOverrideUrlLoading());
 
         handler.updateNewUrlLoading(PageTransition.LINK, false, true, 0, 0);
@@ -329,7 +329,7 @@
         // 2. Effective redirection should not override URL loading.
         /////////////////////////////////////////////////////
         handler = TabRedirectHandler.create();
-        handler.updateIntent(sYtIntent);
+        handler.updateIntent(sYtIntent, false, false, false);
         Assert.assertFalse(handler.shouldNotOverrideUrlLoading());
 
         handler.updateNewUrlLoading(PageTransition.LINK, false, true, 0, 0);
@@ -356,7 +356,7 @@
     @RetryOnFailure
     public void testNavigationFromLinkWithoutUserGesture() {
         TabRedirectHandler handler = TabRedirectHandler.create();
-        handler.updateIntent(sYtIntent);
+        handler.updateIntent(sYtIntent, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
         Assert.assertFalse(handler.shouldStayInApp(false));
         Assert.assertFalse(handler.shouldStayInApp(true));
@@ -389,7 +389,7 @@
     @RetryOnFailure
     public void testNavigationFromReload() {
         TabRedirectHandler handler = TabRedirectHandler.create();
-        handler.updateIntent(sYtIntent);
+        handler.updateIntent(sYtIntent, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
         Assert.assertFalse(handler.shouldStayInApp(false));
         Assert.assertFalse(handler.shouldStayInApp(true));
@@ -422,7 +422,7 @@
     @RetryOnFailure
     public void testNavigationWithForwardBack() {
         TabRedirectHandler handler = TabRedirectHandler.create();
-        handler.updateIntent(sYtIntent);
+        handler.updateIntent(sYtIntent, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
         Assert.assertFalse(handler.shouldStayInApp(false));
         Assert.assertFalse(handler.shouldStayInApp(true));
@@ -475,7 +475,7 @@
     @Feature({"IntentHandling"})
     public void testClientRedirectWithoutUserGesture() {
         TabRedirectHandler handler = TabRedirectHandler.create();
-        handler.updateIntent(sFooIntent);
+        handler.updateIntent(sFooIntent, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
 
         handler.updateNewUrlLoading(PageTransition.CLIENT_REDIRECT, false, false, 0, 0);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tasks/ReturnToChromeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tasks/ReturnToChromeTest.java
index 9b67f392..550dde8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tasks/ReturnToChromeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tasks/ReturnToChromeTest.java
@@ -31,7 +31,6 @@
 import org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
-import org.chromium.chrome.test.util.ApplicationTestUtils;
 import org.chromium.chrome.test.util.ChromeRenderTestRule;
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.content_public.browser.test.util.Criteria;
@@ -81,7 +80,7 @@
     @CommandLineFlags.Add({BASE_PARAMS + "/" + TAB_SWITCHER_ON_RETURN_MS + "/100000"})
     public void testTabSwitcherModeNotTriggeredWithinThreshold() throws Exception {
         TabUiTestHelper.prepareTabsWithThumbnail(mActivityTestRule, 2, 0, mUrl);
-        ApplicationTestUtils.finishActivity(mActivityTestRule.getActivity());
+        TabUiTestHelper.finishActivity(mActivityTestRule.getActivity());
 
         mActivityTestRule.startMainActivityFromLauncher();
 
@@ -102,7 +101,7 @@
     @FlakyTest(message = "crbug.com/1040895")
     public void testTabSwitcherModeTriggeredBeyondThreshold() throws Exception {
         TabUiTestHelper.prepareTabsWithThumbnail(mActivityTestRule, 2, 0, mUrl);
-        ApplicationTestUtils.finishActivity(mActivityTestRule.getActivity());
+        TabUiTestHelper.finishActivity(mActivityTestRule.getActivity());
 
         assertEquals(0,
                 RecordHistogram.getHistogramTotalCountForTesting(
@@ -156,7 +155,7 @@
         testTabSwitcherModeTriggeredBeyondThreshold();
 
         // Redo to trigger warm startup UMA.
-        ApplicationTestUtils.finishActivity(mActivityTestRule.getActivity());
+        TabUiTestHelper.finishActivity(mActivityTestRule.getActivity());
         mActivityTestRule.startMainActivityFromLauncher();
 
         if (!mActivityTestRule.getActivity().isTablet()) {
@@ -216,7 +215,7 @@
     public void testTabSwitcherModeTriggeredBeyondThreshold_NoTabs() throws Exception {
         TestThreadUtils.runOnUiThreadBlocking(
                 () -> mActivityTestRule.getActivity().getTabModelSelector().closeAllTabs());
-        ApplicationTestUtils.finishActivity(mActivityTestRule.getActivity());
+        TabUiTestHelper.finishActivity(mActivityTestRule.getActivity());
 
         assertEquals(0,
                 RecordHistogram.getHistogramTotalCountForTesting(
@@ -275,7 +274,7 @@
         TabUiTestHelper.verifyAllTabsHaveThumbnail(
                 mActivityTestRule.getActivity().getCurrentTabModel());
 
-        ApplicationTestUtils.finishActivity(mActivityTestRule.getActivity());
+        TabUiTestHelper.finishActivity(mActivityTestRule.getActivity());
 
         mActivityTestRule.startMainActivityFromLauncher();
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabControllerTest.java
index 1e2e37c..cd2de30 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabControllerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabControllerTest.java
@@ -26,7 +26,9 @@
 import org.junit.runner.RunWith;
 import org.robolectric.annotation.Config;
 
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.components.embedder_support.util.ShadowUrlUtilities;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.testing.local.LocalRobolectricTestRunner;
@@ -36,12 +38,15 @@
  */
 @RunWith(LocalRobolectricTestRunner.class)
 @Config(manifest = Config.NONE, shadows = {ShadowUrlUtilities.class})
+@Features.DisableFeatures({ChromeFeatureList.CCT_EXTERNAL_LINK_HANDLING})
 public class CustomTabActivityTabControllerTest {
-
     @Rule
     public final CustomTabActivityContentTestEnvironment env =
             new CustomTabActivityContentTestEnvironment();
 
+    @Rule
+    public Features.JUnitProcessor processor = new Features.JUnitProcessor();
+
     private CustomTabActivityTabController mTabController;
 
     @Before
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityUrlLoadingTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityUrlLoadingTest.java
index f6ce104c..09398abc 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityUrlLoadingTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityUrlLoadingTest.java
@@ -32,7 +32,9 @@
 
 import org.chromium.base.test.util.JniMocker;
 import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.components.embedder_support.util.UrlUtilities;
 import org.chromium.components.embedder_support.util.UrlUtilitiesJni;
 import org.chromium.content_public.browser.LoadUrlParams;
@@ -44,11 +46,15 @@
  */
 @RunWith(LocalRobolectricTestRunner.class)
 @Config(manifest = Config.NONE)
+@Features.DisableFeatures({ChromeFeatureList.CCT_EXTERNAL_LINK_HANDLING})
 public class CustomTabActivityUrlLoadingTest {
     @Rule
     public final CustomTabActivityContentTestEnvironment env =
             new CustomTabActivityContentTestEnvironment();
 
+    @Rule
+    public Features.JUnitProcessor processor = new Features.JUnitProcessor();
+
     private CustomTabActivityTabController mTabController;
     private CustomTabActivityNavigationController mNavigationController;
     private CustomTabIntentHandler mIntentHandler;
diff --git a/chrome/app/os_settings_strings.grdp b/chrome/app/os_settings_strings.grdp
index a9eb75c..e8ed41d 100644
--- a/chrome/app/os_settings_strings.grdp
+++ b/chrome/app/os_settings_strings.grdp
@@ -964,6 +964,9 @@
   <message name="IDS_SETTINGS_CROSTINI_DISK_RESIZE_SHOW_BUTTON" desc="The label of the button/link the user clicks to open the disk resizing dialogue." meaning="The label of the button/link the user clicks to open the disk resizing dialogue.">
     Change
   </message>
+  <message name="IDS_SETTINGS_CROSTINI_DISK_RESIZE_SHOW_BUTTON_ARIA_LABEL" desc="The aria label for the button to show the disk resize dialog i.e. the text that screen readers will read out for the button.">
+    Change disk size
+  </message>
   <message name="IDS_SETTINGS_CROSTINI_DISK_RESIZE_LABEL" desc="The label on the row in settings for managing Crostini's disk size.">
     Disk size
   </message>
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_CROSTINI_DISK_RESIZE_SHOW_BUTTON_ARIA_LABEL.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_CROSTINI_DISK_RESIZE_SHOW_BUTTON_ARIA_LABEL.png.sha1
new file mode 100644
index 0000000..7d09c7e98
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_CROSTINI_DISK_RESIZE_SHOW_BUTTON_ARIA_LABEL.png.sha1
@@ -0,0 +1 @@
+2046be897f9f41f531d6d3c4d1487befb11ad631
\ No newline at end of file
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 8a29057..ea761b7 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -1732,6 +1732,9 @@
   <message name="IDS_SETTINGS_NETWORK_PREDICTION_ENABLED_DESC" desc="In the advanced options tab, the secondary text next to the checkbox that enables prediction of network actions.">
     Uses cookies to remember your preferences, even if you don’t visit those pages
   </message>
+  <message name="IDS_SETTINGS_NETWORK_PREDICTION_ENABLED_DESC_COOKIES_PAGE" desc="On the cookies page, the secondary text next to the checkbox that enables prediction of network actions.">
+    Pre-fetches information from pages, including pages you have not yet visited. Information fetched may include cookies, if you allow cookies.
+  </message>
   <message name="IDS_SETTINGS_SAFEBROWSING_ENABLEPROTECTION" desc="The section title of 'Protects you and your device from dangerous sites'">
     Safe Browsing (protects you and your device from dangerous sites)
   </message>
@@ -2693,8 +2696,8 @@
   <message name="IDS_SETTINGS_SITE_SETTINGS_ORIGIN_DELETE_CONFIRMATION" desc="Text for the dialog that warns about clearing all storage data for an origin.">
     This will clear all data and cookies stored by <ph name="ORIGIN_NAME">$1<ex>www.example.com</ex></ph>.
   </message>
-  <message name="IDS_SETTINGS_SITE_SETTINGS_ORIGIN_DELETE_CONFIRMATION_INSTALLED" desc="Text for the dialog that warns about clearing all storage data for an origin that has an installed app.">
-    This will clear all data and cookies stored by <ph name="ORIGIN_NAME">$1<ex>www.example.com</ex></ph> and its installed app.
+  <message name="IDS_SETTINGS_SITE_SETTINGS_ORIGIN_DELETE_CONFIRMATION_INSTALLED" desc="Text for the dialog that warns about clearing all storage data for an origin that has one or more installed apps.">
+    This will clear all data and cookies stored by <ph name="ORIGIN_NAME">$1<ex>www.example.com</ex></ph> and its installed apps.
   </message>
   <message name="IDS_SETTINGS_SITE_SETTINGS_COOKIE_REMOVE_MULTIPLE" desc="Text for the dialog that warns about deleting all site data.">
     This will delete any data stored on your device for all the sites shown. Do you want to continue?
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 011016a2..575188d 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2043,6 +2043,10 @@
      kOsCrOS,
      FEATURE_VALUE_TYPE(
          chromeos::features::kBluetoothAggressiveAppearanceFilter)},
+    {"bluetooth-fix-a2dp-packet-size",
+     flag_descriptions::kBluetoothFixA2dpPacketSizeName,
+     flag_descriptions::kBluetoothFixA2dpPacketSizeDescription, kOsCrOS,
+     FEATURE_VALUE_TYPE(chromeos::features::kBluetoothFixA2dpPacketSize)},
     {"bluetooth-kernel-suspend-notifier",
      flag_descriptions::kBluetoothKernelSuspendNotifierName,
      flag_descriptions::kBluetoothKernelSuspendNotifierDescription, kOsCrOS,
diff --git a/chrome/browser/android/webapk/webapk_installer.cc b/chrome/browser/android/webapk/webapk_installer.cc
index c0e681b..37be7ea 100644
--- a/chrome/browser/android/webapk/webapk_installer.cc
+++ b/chrome/browser/android/webapk/webapk_installer.cc
@@ -538,6 +538,11 @@
   finish_callback_ = std::move(finish_callback);
   task_type_ = INSTALL;
 
+  if (!server_url_.is_valid()) {
+    OnResult(WebApkInstallResult::FAILURE);
+    return;
+  }
+
   CheckFreeSpace();
 }
 
@@ -574,6 +579,11 @@
   finish_callback_ = std::move(finish_callback);
   task_type_ = UPDATE;
 
+  if (!server_url_.is_valid()) {
+    OnResult(WebApkInstallResult::FAILURE);
+    return;
+  }
+
   base::PostTaskAndReplyWithResult(
       GetBackgroundTaskRunner().get(), FROM_HERE,
       base::BindOnce(&ReadFileInBackground, update_request_path),
@@ -692,6 +702,8 @@
 
 void WebApkInstaller::SendRequest(
     std::unique_ptr<std::string> serialized_proto) {
+  DCHECK(server_url_.is_valid());
+
   timer_.Start(
       FROM_HERE, base::TimeDelta::FromMilliseconds(webapk_server_timeout_ms_),
       base::Bind(&WebApkInstaller::OnResult, weak_ptr_factory_.GetWeakPtr(),
diff --git a/chrome/browser/chromeos/android_sms/android_sms_pairing_state_tracker_impl.cc b/chrome/browser/chromeos/android_sms/android_sms_pairing_state_tracker_impl.cc
index 39cf00e..2c91d28c 100644
--- a/chrome/browser/chromeos/android_sms/android_sms_pairing_state_tracker_impl.cc
+++ b/chrome/browser/chromeos/android_sms/android_sms_pairing_state_tracker_impl.cc
@@ -69,6 +69,7 @@
     }
   }
 
+  PA_LOG(INFO) << "No Pairing cookie found";
   was_paired_on_last_update_ = false;
   if (was_previously_paired != was_paired_on_last_update_)
     NotifyPairingStateChanged();
@@ -88,6 +89,8 @@
 void AndroidSmsPairingStateTrackerImpl::OnInstalledAppUrlChanged() {
   // If the app URL changed, stop any ongoing cookie monitoring and attempt to
   // add a new change listener.
+  PA_LOG(INFO) << "Installed app url changed to " << GetPairingUrl()
+               << ". Updating cookie listeners.";
   cookie_listener_receiver_.reset();
   AddCookieChangeListener();
 }
diff --git a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.cc b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.cc
index 6bc7cbb..a37e3e2 100644
--- a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.cc
+++ b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.cc
@@ -46,6 +46,28 @@
 
 namespace {
 
+constexpr char kToastEventSource[] = "android.widget.Toast$TN";
+
+bool ShouldAnnounceEvent(arc::mojom::AccessibilityEventData* event_data) {
+  if (event_data->event_type ==
+      arc::mojom::AccessibilityEventType::ANNOUNCEMENT) {
+    return true;
+  } else if (event_data->event_type ==
+             arc::mojom::AccessibilityEventType::NOTIFICATION_STATE_CHANGED) {
+    // Only announce the event from toast (event is from its inner class TN).
+    if (!event_data->string_properties)
+      return false;
+
+    auto it = event_data->string_properties->find(
+        arc::mojom::AccessibilityEventStringProperty::CLASS_NAME);
+    if (it == event_data->string_properties->end())
+      return false;
+
+    return it->second == kToastEventSource;
+  }
+  return false;
+}
+
 float DeviceScaleFactorFromWindow(aura::Window* window) {
   if (!window || !window->GetToplevelWindow())
     return 1.0;
@@ -776,24 +798,8 @@
 
 void ArcAccessibilityHelperBridge::HandleFilterTypeAllEvent(
     mojom::AccessibilityEventDataPtr event_data) {
-  if (event_data->event_type ==
-          arc::mojom::AccessibilityEventType::ANNOUNCEMENT ||
-      event_data->event_type ==
-          arc::mojom::AccessibilityEventType::NOTIFICATION_STATE_CHANGED) {
-    if (!event_data->event_text.has_value())
-      return;
-
-    extensions::EventRouter* event_router = GetEventRouter();
-    // OnAnnounceForAccessibility is used to force speech output.
-    std::unique_ptr<base::ListValue> event_args(
-        extensions::api::accessibility_private::OnAnnounceForAccessibility::
-            Create(*(event_data->event_text)));
-    std::unique_ptr<extensions::Event> event(new extensions::Event(
-        extensions::events::ACCESSIBILITY_PRIVATE_ON_ANNOUNCE_FOR_ACCESSIBILITY,
-        extensions::api::accessibility_private::OnAnnounceForAccessibility::
-            kEventName,
-        std::move(event_args)));
-    event_router->BroadcastEvent(std::move(event));
+  if (ShouldAnnounceEvent(event_data.get())) {
+    DispatchEventTextAnnouncement(event_data.get());
     return;
   }
 
@@ -885,6 +891,22 @@
   }
 }
 
+void ArcAccessibilityHelperBridge::DispatchEventTextAnnouncement(
+    mojom::AccessibilityEventData* event_data) const {
+  if (!event_data->event_text.has_value())
+    return;
+
+  std::unique_ptr<base::ListValue> event_args(
+      extensions::api::accessibility_private::OnAnnounceForAccessibility::
+          Create(*(event_data->event_text)));
+  std::unique_ptr<extensions::Event> event(new extensions::Event(
+      extensions::events::ACCESSIBILITY_PRIVATE_ON_ANNOUNCE_FOR_ACCESSIBILITY,
+      extensions::api::accessibility_private::OnAnnounceForAccessibility::
+          kEventName,
+      std::move(event_args)));
+  GetEventRouter()->BroadcastEvent(std::move(event));
+}
+
 void ArcAccessibilityHelperBridge::DispatchCustomSpokenFeedbackToggled(
     bool enabled) const {
   std::unique_ptr<base::ListValue> event_args(
diff --git a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h
index f76a79f5..83f3251 100644
--- a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h
+++ b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h
@@ -156,6 +156,8 @@
   void HandleFilterTypeFocusEvent(mojom::AccessibilityEventDataPtr event_data);
   void HandleFilterTypeAllEvent(mojom::AccessibilityEventDataPtr event_data);
 
+  void DispatchEventTextAnnouncement(
+      mojom::AccessibilityEventData* event_data) const;
   void DispatchCustomSpokenFeedbackToggled(bool enabled) const;
 
   AXTreeSourceArc* CreateFromKey(TreeKey, aura::Window* window);
diff --git a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc
index 09d66f6b0..4f859ed09 100644
--- a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc
+++ b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc
@@ -315,7 +315,7 @@
   ASSERT_EQ(0U, key_to_tree.size());
 }
 
-TEST_F(ArcAccessibilityHelperBridgeTest, EventAnnouncement) {
+TEST_F(ArcAccessibilityHelperBridgeTest, AnnouncementEvent) {
   const char* const event_name = extensions::api::accessibility_private::
       OnAnnounceForAccessibility::kEventName;
 
@@ -338,6 +338,47 @@
   ASSERT_EQ(announce_text, arg[0].GetString());
 }
 
+TEST_F(ArcAccessibilityHelperBridgeTest, NotificationStateChangedEvent) {
+  const char* const event_name = extensions::api::accessibility_private::
+      OnAnnounceForAccessibility::kEventName;
+
+  TestArcAccessibilityHelperBridge* helper_bridge =
+      accessibility_helper_bridge();
+  const std::string toast_text = "announcement text.";
+  std::vector<std::string> text({toast_text});
+  auto event = arc::mojom::AccessibilityEventData::New();
+  event->event_type =
+      arc::mojom::AccessibilityEventType::NOTIFICATION_STATE_CHANGED;
+  event->event_text =
+      base::make_optional<std::vector<std::string>>(std::move(text));
+  event->string_properties =
+      base::flat_map<arc::mojom::AccessibilityEventStringProperty,
+                     std::string>();
+  event->string_properties.value().insert(
+      std::make_pair(arc::mojom::AccessibilityEventStringProperty::CLASS_NAME,
+                     "android.widget.Toast$TN"));
+
+  helper_bridge->OnAccessibilityEvent(event.Clone());
+
+  ASSERT_EQ(1, helper_bridge->GetEventCount(event_name));
+  ASSERT_EQ(event_name, helper_bridge->last_event->event_name);
+  base::Value::ConstListView arg =
+      helper_bridge->last_event->event_args->GetList()[0].GetList();
+  ASSERT_EQ(1U, arg.size());
+  ASSERT_EQ(toast_text, arg[0].GetString());
+
+  // Do not announce for non-toast event.
+  event->string_properties->clear();
+  event->string_properties.value().insert(
+      std::make_pair(arc::mojom::AccessibilityEventStringProperty::CLASS_NAME,
+                     "com.android.vending"));
+
+  helper_bridge->OnAccessibilityEvent(event.Clone());
+
+  // Announce event is not dispatched. The event count is not changed.
+  ASSERT_EQ(1, helper_bridge->GetEventCount(event_name));
+}
+
 TEST_F(ArcAccessibilityHelperBridgeTest, ToggleTalkBack) {
   const char* const event_name = extensions::api::accessibility_private::
       OnCustomSpokenFeedbackToggled::kEventName;
@@ -393,23 +434,6 @@
   ASSERT_FALSE(helper_bridge->last_event->event_args->GetList()[0].GetBool());
 }
 
-TEST_F(ArcAccessibilityHelperBridgeTest, Toast) {
-  TestArcAccessibilityHelperBridge* helper_bridge =
-      accessibility_helper_bridge();
-  std::vector<std::string> text({"Toast text"});
-  auto event = arc::mojom::AccessibilityEventData::New();
-  event->event_type =
-      arc::mojom::AccessibilityEventType::NOTIFICATION_STATE_CHANGED;
-  event->event_text =
-      base::make_optional<std::vector<std::string>>(std::move(text));
-
-  helper_bridge->OnAccessibilityEvent(event.Clone());
-
-  ASSERT_EQ(1, helper_bridge->GetEventCount(
-                   extensions::api::accessibility_private::
-                       OnAnnounceForAccessibility::kEventName));
-}
-
 // Accessibility event and surface creation/removal are sent in different
 // channels, mojo and wayland. Order of those events can be changed. This is the
 // case where mojo events arrive earlier than surface creation/removal.
diff --git a/chrome/browser/chromeos/file_manager/file_manager_jstest_base.cc b/chrome/browser/chromeos/file_manager/file_manager_jstest_base.cc
index cc5c08c..59b99ee 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_jstest_base.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_jstest_base.cc
@@ -73,9 +73,10 @@
     // Do some basic validation of the file extension.
     CHECK(src_file_path.Extension() == ".html" ||
           src_file_path.Extension() == ".js" ||
-          src_file_path.Extension() == ".css")
-        << "chrome://file_manager_test/ only supports .html/.js/.css extension "
-           "files";
+          src_file_path.Extension() == ".css" ||
+          src_file_path.Extension() == ".svg")
+        << "chrome://file_manager_test/ only supports .html/.js/.css/.svg "
+           "extension files";
 
     CHECK(base::PathExists(src_file_path) || base::PathExists(gen_file_path))
         << src_file_path << " or: " << gen_file_path << " input path: " << path;
@@ -88,7 +89,7 @@
     std::move(callback).Run(response.get());
   }
 
-  // It currently only serves HTML/JS/CSS.
+  // It currently only serves HTML/JS/CSS/SVG.
   std::string GetMimeType(const std::string& path) override {
     if (base::EndsWith(path, ".html", base::CompareCase::INSENSITIVE_ASCII)) {
       return "text/html";
@@ -98,8 +99,16 @@
       return "text/css";
     }
 
-    CHECK(base::EndsWith(path, ".js", base::CompareCase::INSENSITIVE_ASCII));
-    return "application/javascript";
+    if (base::EndsWith(path, ".js", base::CompareCase::INSENSITIVE_ASCII)) {
+      return "application/javascript";
+    }
+
+    if (base::EndsWith(path, ".svg", base::CompareCase::INSENSITIVE_ASCII)) {
+      return "image/svg+xml";
+    }
+
+    LOG(FATAL) << "unsupported file type: " << path;
+    return {};
   }
 
   std::string GetContentSecurityPolicyScriptSrc() override {
diff --git a/chrome/browser/chromeos/input_method/input_method_engine.cc b/chrome/browser/chromeos/input_method/input_method_engine.cc
index bffaefc8..8ca7977e 100644
--- a/chrome/browser/chromeos/input_method/input_method_engine.cc
+++ b/chrome/browser/chromeos/input_method/input_method_engine.cc
@@ -224,6 +224,8 @@
 
 bool InputMethodEngine::SetSuggestion(int context_id,
                                       const base::string16& text,
+                                      const base::string16& confirmed_text,
+                                      const bool show_tab,
                                       std::string* error) {
   if (!IsActive()) {
     *error = kErrorNotActive;
@@ -237,7 +239,7 @@
   IMESuggestionWindowHandlerInterface* sw_handler =
       ui::IMEBridge::Get()->GetSuggestionWindowHandler();
   if (sw_handler)
-    sw_handler->Show(text);
+    sw_handler->Show(text, confirmed_text, show_tab);
   return true;
 }
 
diff --git a/chrome/browser/chromeos/input_method/input_method_engine.h b/chrome/browser/chromeos/input_method/input_method_engine.h
index ef7ecb2..1cbf523 100644
--- a/chrome/browser/chromeos/input_method/input_method_engine.h
+++ b/chrome/browser/chromeos/input_method/input_method_engine.h
@@ -119,9 +119,14 @@
   // Dismiss suggestion window.
   bool DismissSuggestion(int context_id, std::string* error);
 
-  // Set and show suggestion window.
+  // Sets text and show suggestion window.
+  // text - the full suggestion text.
+  // confirmed_text - the confirmed text that the user has typed so far.
+  // show_tab - whether to show "tab" in the suggestion window.
   bool SetSuggestion(int context_id,
                      const base::string16& text,
+                     const base::string16& confirmed_text,
+                     const bool show_tab,
                      std::string* error);
 
   // Commit the suggestion and hide the window.
diff --git a/chrome/browser/chromeos/input_method/personal_info_suggester.cc b/chrome/browser/chromeos/input_method/personal_info_suggester.cc
index eaf6d29..2829fe7 100644
--- a/chrome/browser/chromeos/input_method/personal_info_suggester.cc
+++ b/chrome/browser/chromeos/input_method/personal_info_suggester.cc
@@ -119,7 +119,8 @@
 
 void PersonalInfoSuggester::ShowSuggestion(const base::string16& text) {
   std::string error;
-  engine_->SetSuggestion(context_id_, text, &error);
+  engine_->SetSuggestion(context_id_, text, base::EmptyString16(), true,
+                         &error);
   if (!error.empty()) {
     LOG(ERROR) << "Fail to show suggestion. " << error;
   }
diff --git a/chrome/browser/chromeos/input_method/suggestion_window_controller_impl.cc b/chrome/browser/chromeos/input_method/suggestion_window_controller_impl.cc
index ad59512e..8a02fe3 100644
--- a/chrome/browser/chromeos/input_method/suggestion_window_controller_impl.cc
+++ b/chrome/browser/chromeos/input_method/suggestion_window_controller_impl.cc
@@ -73,11 +73,13 @@
     Hide();
 }
 
-void SuggestionWindowControllerImpl::Show(const base::string16& text) {
+void SuggestionWindowControllerImpl::Show(const base::string16& text,
+                                          const base::string16& confirmed_text,
+                                          const bool show_tab) {
   if (!suggestion_window_view_)
     Init();
   suggestion_text_ = text;
-  suggestion_window_view_->Show(text);
+  suggestion_window_view_->Show(text, confirmed_text, show_tab);
 }
 
 base::string16 SuggestionWindowControllerImpl::GetText() const {
diff --git a/chrome/browser/chromeos/input_method/suggestion_window_controller_impl.h b/chrome/browser/chromeos/input_method/suggestion_window_controller_impl.h
index 2261d9a..066f40d 100644
--- a/chrome/browser/chromeos/input_method/suggestion_window_controller_impl.h
+++ b/chrome/browser/chromeos/input_method/suggestion_window_controller_impl.h
@@ -31,7 +31,9 @@
 
   // IMESuggestionWindowHandlerInterface implementation.
   void SetBounds(const gfx::Rect& cursor_bounds) override;
-  void Show(const base::string16& text) override;
+  void Show(const base::string16& text,
+            const base::string16& confirmed_text,
+            const bool show_tab) override;
   void Hide() override;
   base::string16 GetText() const override;
   void FocusStateChanged() override;
diff --git a/chrome/browser/chromeos/logging_browsertest.cc b/chrome/browser/chromeos/logging_browsertest.cc
index fa98e6b..d0e76c5 100644
--- a/chrome/browser/chromeos/logging_browsertest.cc
+++ b/chrome/browser/chromeos/logging_browsertest.cc
@@ -11,7 +11,7 @@
 #include "base/threading/thread_restrictions.h"
 #include "chrome/browser/chromeos/logging.h"
 #include "chrome/browser/chromeos/login/login_manager_test.h"
-#include "chrome/browser/chromeos/login/startup_utils.h"
+#include "chrome/browser/chromeos/login/test/login_manager_mixin.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/env_vars.h"
 #include "chrome/common/logging_chrome.h"
@@ -29,8 +29,6 @@
 namespace chromeos {
 
 namespace {
-constexpr char kTestUser[] = "test-user@gmail.com";
-constexpr char kTestUserGaiaId[] = "1234567890";
 constexpr char kLogFileName[] = "chrome.log";
 constexpr char kLogMessageBrowser[] = "browser log before logging in";
 constexpr char kLogMessageBrowserRedirected[] = "browser log after logging in";
@@ -59,7 +57,8 @@
 
 class LoggingBrowserTest : public LoginManagerTest {
  public:
-  LoggingBrowserTest() : LoginManagerTest(true, true) {
+  LoggingBrowserTest() : LoginManagerTest() {
+    login_mixin_.AppendRegularUsers(1);
     CHECK(system_temp_dir_.CreateUniqueTempDir());
     CHECK(user_temp_dir_.CreateUniqueTempDir());
     logging::ForceLogRedirectionForTesting();
@@ -87,15 +86,9 @@
  protected:
   base::ScopedTempDir system_temp_dir_;
   base::ScopedTempDir user_temp_dir_;
+  LoginManagerMixin login_mixin_{&mixin_host_};
 };
 
-IN_PROC_BROWSER_TEST_F(LoggingBrowserTest, PRE_NetworkServiceLogsRedirect) {
-  RegisterUser(AccountId::FromUserEmailGaiaId(kTestUser, kTestUserGaiaId));
-  EXPECT_EQ(session_manager::SessionState::OOBE,
-            session_manager::SessionManager::Get()->session_state());
-  chromeos::StartupUtils::MarkOobeCompleted();
-}
-
 IN_PROC_BROWSER_TEST_F(LoggingBrowserTest, NetworkServiceLogsRedirect) {
   // Log some messages pre-redirect.
   LOG(ERROR) << kLogMessageBrowser;
@@ -104,7 +97,7 @@
   // Log the user in which will redirect the logs.
   EXPECT_EQ(session_manager::SessionState::LOGIN_PRIMARY,
             session_manager::SessionManager::Get()->session_state());
-  LoginUser(AccountId::FromUserEmailGaiaId(kTestUser, kTestUserGaiaId));
+  LoginUser(login_mixin_.users()[0].account_id);
   EXPECT_EQ(session_manager::SessionState::ACTIVE,
             session_manager::SessionManager::Get()->session_state());
 
diff --git a/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc b/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
index 21862bc..eeceb6a3 100644
--- a/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
+++ b/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/chromeos/login/test/enrollment_helper_mixin.h"
 #include "chrome/browser/chromeos/login/test/enrollment_ui_mixin.h"
 #include "chrome/browser/chromeos/login/test/js_checker.h"
+#include "chrome/browser/chromeos/login/test/oobe_base_test.h"
 #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
@@ -138,11 +139,9 @@
 
 }  // namespace
 
-class EnterpriseEnrollmentTestBase : public LoginManagerTest {
+class EnterpriseEnrollmentTestBase : public OobeBaseTest {
  public:
-  explicit EnterpriseEnrollmentTestBase(bool should_initialize_webui)
-      : LoginManagerTest(true /*should_launch_browser*/,
-                         should_initialize_webui) {}
+  EnterpriseEnrollmentTestBase() = default;
 
   // Submits regular enrollment credentials.
   void SubmitEnrollmentCredentials() {
@@ -193,8 +192,7 @@
 
 class EnterpriseEnrollmentTest : public EnterpriseEnrollmentTestBase {
  public:
-  EnterpriseEnrollmentTest()
-      : EnterpriseEnrollmentTestBase(true /* should_initialize_webui */) {}
+  EnterpriseEnrollmentTest() = default;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(EnterpriseEnrollmentTest);
diff --git a/chrome/browser/chromeos/login/login_manager_test.cc b/chrome/browser/chromeos/login/login_manager_test.cc
index f6c00143..dfc2c68 100644
--- a/chrome/browser/chromeos/login/login_manager_test.cc
+++ b/chrome/browser/chromeos/login/login_manager_test.cc
@@ -6,12 +6,10 @@
 
 #include <string>
 
-#include "ash/public/cpp/ash_switches.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/login/existing_user_controller.h"
 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
 #include "chrome/browser/chromeos/login/session/user_session_manager_test_api.h"
@@ -26,27 +24,19 @@
 #include "components/user_manager/known_user.h"
 #include "components/user_manager/user.h"
 #include "components/user_manager/user_manager.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/test/test_utils.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace chromeos {
 
-LoginManagerTest::LoginManagerTest(bool should_launch_browser,
-                                   bool should_initialize_webui)
-    : should_launch_browser_(should_launch_browser),
-      should_initialize_webui_(should_initialize_webui) {
+LoginManagerTest::LoginManagerTest() {
   set_exit_when_last_browser_closes(false);
 }
 
 LoginManagerTest::~LoginManagerTest() {}
 
 void LoginManagerTest::SetUpCommandLine(base::CommandLine* command_line) {
-  if (force_webui_login_) {
-    command_line->AppendSwitch(ash::switches::kShowWebUiLogin);
-  }
   command_line->AppendSwitch(chromeos::switches::kLoginManager);
   command_line->AppendSwitch(chromeos::switches::kForceLoginManagerInTests);
 
@@ -58,12 +48,6 @@
 
   host_resolver()->AddRule("*", "127.0.0.1");
 
-  if (should_initialize_webui_) {
-    content::WindowedNotificationObserver(
-        chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
-        content::NotificationService::AllSources())
-        .Wait();
-  }
   test::UserSessionManagerTestApi session_manager_test_api(
       UserSessionManager::GetInstance());
   session_manager_test_api.SetShouldLaunchBrowserInTests(
diff --git a/chrome/browser/chromeos/login/login_manager_test.h b/chrome/browser/chromeos/login/login_manager_test.h
index b9b8f8bd..0d95643 100644
--- a/chrome/browser/chromeos/login/login_manager_test.h
+++ b/chrome/browser/chromeos/login/login_manager_test.h
@@ -17,24 +17,21 @@
 
 class UserContext;
 
-// Base class for Chrome OS out-of-box/login WebUI tests.
-// If no special configuration is done launches out-of-box WebUI.
-// To launch login UI use PRE_* test that will register user(s) and mark
-// out-of-box as completed.
-// Guarantees that WebUI has been initialized by waiting for
-// NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE notification.
+// Base class for Chrome OS Login tests. Should be used if you need to start at
+// the Chrome OS Login screen (especially with existing users). For the tests
+// that are focused more on OOBE - prefer OobeBaseTest. Use LoginManagerMixin to
+// configure users for tests.
 class LoginManagerTest : public MixinBasedInProcessBrowserTest {
  public:
-  LoginManagerTest(bool should_launch_browser,
-                   bool should_initialize_webui);
+  LoginManagerTest();
   ~LoginManagerTest() override;
 
   void SetUpCommandLine(base::CommandLine* command_line) override;
   void SetUpOnMainThread() override;
 
-  // Registers the user with the given |user_id| on the device.
-  // This method should be called in PRE_* test.
-  // TODO(dzhioev): Add the ability to register users without a PRE_* test.
+  // Could be used to registers the user with the given |account_id| on the
+  // device. This method should be called in PRE_* test. Use only if necessary,
+  // prefer LoginManagerMixin instead.
   void RegisterUser(const AccountId& account_id);
 
   static const char kPassword[];
@@ -60,17 +57,14 @@
   // Add user with |user_id| to session.
   void AddUser(const AccountId& user_id);
 
-  void set_force_webui_login(bool force) { force_webui_login_ = force; }
+  void set_should_launch_browser(bool launch) {
+    should_launch_browser_ = launch;
+  }
 
  private:
-  // If set, the tests will use deprecated webui login.
-  // TODO(tbarzic): Migrate all tests to work with views login implementation.
-  bool force_webui_login_ = true;
-  const bool should_launch_browser_;
-  const bool should_initialize_webui_;
+  bool should_launch_browser_ = false;
   EmbeddedTestServerSetupMixin embedded_test_server_{&mixin_host_,
                                                      embedded_test_server()};
-
   DISALLOW_COPY_AND_ASSIGN(LoginManagerTest);
 };
 
diff --git a/chrome/browser/chromeos/login/login_ui_browsertest.cc b/chrome/browser/chromeos/login/login_ui_browsertest.cc
index d7f35c43..bd4caf3 100644
--- a/chrome/browser/chromeos/login/login_ui_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_ui_browsertest.cc
@@ -48,15 +48,12 @@
 
 class LoginUITestBase : public LoginManagerTest {
  public:
-  LoginUITestBase()
-      : LoginManagerTest(false, false /* should_initialize_webui */) {
-    set_force_webui_login(false);
+  LoginUITestBase() : LoginManagerTest() {
+    login_manager_mixin_.AppendRegularUsers(10);
   }
 
  protected:
-  std::vector<LoginManagerMixin::TestUserInfo> test_users_{
-      LoginManagerMixin::CreateRegularUsers(10)};
-  LoginManagerMixin login_manager_mixin_{&mixin_host_, test_users_};
+  LoginManagerMixin login_manager_mixin_{&mixin_host_};
 };
 
 class LoginUIEnrolledTest : public LoginUITestBase {
@@ -81,7 +78,7 @@
   }
 
  protected:
-  LoginManagerMixin::TestUserInfo owner_{test_users_[3]};
+  LoginManagerMixin::TestUserInfo owner_{login_manager_mixin_.users()[3]};
   DeviceStateMixin device_state_{
       &mixin_host_, DeviceStateMixin::State::OOBE_COMPLETED_CONSUMER_OWNED};
   ScopedTestingCrosSettings scoped_testing_cros_settings_;
@@ -89,18 +86,19 @@
 
 // Verifies basic login UI properties.
 IN_PROC_BROWSER_TEST_F(LoginUIConsumerTest, LoginUIVisible) {
-  const int users_count = test_users_.size();
+  const auto& test_users = login_manager_mixin_.users();
+  const int users_count = test_users.size();
   EXPECT_EQ(users_count, ash::LoginScreenTestApi::GetUsersCount());
   EXPECT_FALSE(ash::LoginScreenTestApi::IsOobeDialogVisible());
 
   for (int i = 0; i < users_count; ++i) {
-    EXPECT_TRUE(ash::LoginScreenTestApi::FocusUser(test_users_[i].account_id));
+    EXPECT_TRUE(ash::LoginScreenTestApi::FocusUser(test_users[i].account_id));
   }
 
   for (int i = 0; i < users_count; ++i) {
     // Can't remove the owner.
-    EXPECT_EQ(ash::LoginScreenTestApi::RemoveUser(test_users_[i].account_id),
-              test_users_[i].account_id != owner_.account_id);
+    EXPECT_EQ(ash::LoginScreenTestApi::RemoveUser(test_users[i].account_id),
+              test_users[i].account_id != owner_.account_id);
   }
 
   EXPECT_EQ(1, ash::LoginScreenTestApi::GetUsersCount());
@@ -109,20 +107,21 @@
 }
 
 IN_PROC_BROWSER_TEST_F(LoginUIEnrolledTest, UserRemoval) {
-  const int users_count = test_users_.size();
+  const auto& test_users = login_manager_mixin_.users();
+  const int users_count = test_users.size();
   EXPECT_EQ(users_count, ash::LoginScreenTestApi::GetUsersCount());
   EXPECT_FALSE(ash::LoginScreenTestApi::IsOobeDialogVisible());
 
   // Remove the first user.
-  EXPECT_TRUE(ash::LoginScreenTestApi::RemoveUser(test_users_[0].account_id));
+  EXPECT_TRUE(ash::LoginScreenTestApi::RemoveUser(test_users[0].account_id));
   EXPECT_EQ(users_count - 1, ash::LoginScreenTestApi::GetUsersCount());
 
   // Can not remove twice.
-  EXPECT_FALSE(ash::LoginScreenTestApi::RemoveUser(test_users_[0].account_id));
+  EXPECT_FALSE(ash::LoginScreenTestApi::RemoveUser(test_users[0].account_id));
   EXPECT_EQ(users_count - 1, ash::LoginScreenTestApi::GetUsersCount());
 
   for (int i = 1; i < users_count; ++i) {
-    EXPECT_TRUE(ash::LoginScreenTestApi::RemoveUser(test_users_[i].account_id));
+    EXPECT_TRUE(ash::LoginScreenTestApi::RemoveUser(test_users[i].account_id));
     EXPECT_EQ(users_count - i - 1, ash::LoginScreenTestApi::GetUsersCount());
   }
 
@@ -131,12 +130,13 @@
 }
 
 IN_PROC_BROWSER_TEST_F(LoginUIEnrolledTest, UserReverseRemoval) {
-  const int users_count = test_users_.size();
+  const auto& test_users = login_manager_mixin_.users();
+  const int users_count = test_users.size();
   EXPECT_EQ(users_count, ash::LoginScreenTestApi::GetUsersCount());
   EXPECT_FALSE(ash::LoginScreenTestApi::IsOobeDialogVisible());
 
   for (int i = users_count - 1; i >= 0; --i) {
-    EXPECT_TRUE(ash::LoginScreenTestApi::RemoveUser(test_users_[i].account_id));
+    EXPECT_TRUE(ash::LoginScreenTestApi::RemoveUser(test_users[i].account_id));
     EXPECT_EQ(i, ash::LoginScreenTestApi::GetUsersCount());
   }
 
diff --git a/chrome/browser/chromeos/login/login_ui_hide_supervised_users_browsertest.cc b/chrome/browser/chromeos/login/login_ui_hide_supervised_users_browsertest.cc
index 4587f206..f528f05b 100644
--- a/chrome/browser/chromeos/login/login_ui_hide_supervised_users_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_ui_hide_supervised_users_browsertest.cc
@@ -8,42 +8,21 @@
 #include "base/stl_util.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/chromeos/login/login_manager_test.h"
-#include "chrome/browser/chromeos/login/startup_utils.h"
+#include "chrome/browser/chromeos/login/test/login_manager_mixin.h"
 #include "components/account_id/account_id.h"
 #include "components/user_manager/user_manager_base.h"
 
 namespace chromeos {
 
-namespace {
-
-struct {
-  const char* email;
-  const char* gaia_id;
-} const kTestUsers[] = {
-    {"test-user1@gmail.com", "1111111111"},
-    {"test-user2@gmail.com", "2222222222"},
-    // Test Supervised User.
-    // The user's domain is defined in user_manager::kSupervisedUserDomain.
-    // That const isn't directly referenced here to keep this code readable by
-    // avoiding std::string concatenations.
-    {"test-superviseduser@locally-managed.localhost", "3333333333"},
-};
-
-}  // namespace
-
 class LoginUIHideSupervisedUsersTest : public LoginManagerTest {
  public:
-  LoginUIHideSupervisedUsersTest()
-      : LoginManagerTest(false, false /* should_initialize_webui */) {
-    set_force_webui_login(false);
-    for (size_t i = 0; i < base::size(kTestUsers); ++i) {
-      test_users_.emplace_back(AccountId::FromUserEmailGaiaId(
-          kTestUsers[i].email, kTestUsers[i].gaia_id));
-    }
+  LoginUIHideSupervisedUsersTest() : LoginManagerTest() {
+    login_mixin_.AppendRegularUsers(2);
+    login_mixin_.AppendSupervisedUsers(1);
   }
 
  protected:
-  std::vector<AccountId> test_users_;
+  LoginManagerMixin login_mixin_{&mixin_host_};
 };
 
 // The flag is "HideSupervisedUsers", so this test class
@@ -76,40 +55,26 @@
   base::test::ScopedFeatureList scoped_feature_list_;
 };
 
-IN_PROC_BROWSER_TEST_F(LoginUIHideSupervisedUsersEnabledTest,
-                       PRE_SupervisedUserHidden) {
-  RegisterUser(test_users_[0]);
-  RegisterUser(test_users_[1]);
-  RegisterUser(test_users_[2]);  // The test Supervised User.
-  StartupUtils::MarkOobeCompleted();
-}
-
 // Verifies that Supervised Users are *not* displayed on the login screen when
 // the HideSupervisedUsers feature flag *is* enabled.
 IN_PROC_BROWSER_TEST_F(LoginUIHideSupervisedUsersEnabledTest,
                        SupervisedUserHidden) {
+  const auto& test_users = login_mixin_.users();
   // Only the regular users should be displayed on the login screen.
   EXPECT_EQ(2, ash::LoginScreenTestApi::GetUsersCount());
-  EXPECT_TRUE(ash::LoginScreenTestApi::FocusUser(test_users_[0]));
-  EXPECT_TRUE(ash::LoginScreenTestApi::FocusUser(test_users_[1]));
-}
-
-IN_PROC_BROWSER_TEST_F(LoginUIHideSupervisedUsersDisabledTest,
-                       PRE_SupervisedUserDisplayed) {
-  RegisterUser(test_users_[0]);
-  RegisterUser(test_users_[1]);
-  RegisterUser(test_users_[2]);  // The test Supervised User.
-  StartupUtils::MarkOobeCompleted();
+  EXPECT_TRUE(ash::LoginScreenTestApi::FocusUser(test_users[0].account_id));
+  EXPECT_TRUE(ash::LoginScreenTestApi::FocusUser(test_users[1].account_id));
 }
 
 // Verifies that Supervised Users *are* displayed on the login screen when the
 // HideSupervisedUsers feature flag is *not* enabled.
 IN_PROC_BROWSER_TEST_F(LoginUIHideSupervisedUsersDisabledTest,
                        SupervisedUserDisplayed) {
+  const auto& test_users = login_mixin_.users();
   EXPECT_EQ(3, ash::LoginScreenTestApi::GetUsersCount());
-  EXPECT_TRUE(ash::LoginScreenTestApi::FocusUser(test_users_[0]));
-  EXPECT_TRUE(ash::LoginScreenTestApi::FocusUser(test_users_[1]));
-  EXPECT_TRUE(ash::LoginScreenTestApi::FocusUser(test_users_[2]));
+  EXPECT_TRUE(ash::LoginScreenTestApi::FocusUser(test_users[0].account_id));
+  EXPECT_TRUE(ash::LoginScreenTestApi::FocusUser(test_users[1].account_id));
+  EXPECT_TRUE(ash::LoginScreenTestApi::FocusUser(test_users[2].account_id));
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc b/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc
index 5cd4fdf..e46636d 100644
--- a/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc
@@ -53,9 +53,7 @@
 
 class LoginUIKeyboardTest : public chromeos::LoginManagerTest {
  public:
-  LoginUIKeyboardTest()
-      : LoginManagerTest(false, false /* should_initialize_webui */) {
-    set_force_webui_login(false);
+  LoginUIKeyboardTest() : LoginManagerTest() {
     test_users_.push_back(
         AccountId::FromUserEmailGaiaId(kTestUser1, kTestUser1GaiaId));
     test_users_.push_back(
@@ -147,10 +145,7 @@
 
 class LoginUIKeyboardTestWithUsersAndOwner : public chromeos::LoginManagerTest {
  public:
-  LoginUIKeyboardTestWithUsersAndOwner()
-      : LoginManagerTest(false, false /* should_initialize_webui */) {
-    set_force_webui_login(false);
-  }
+  LoginUIKeyboardTestWithUsersAndOwner() = default;
   ~LoginUIKeyboardTestWithUsersAndOwner() override {}
 
   void SetUpOnMainThread() override {
diff --git a/chrome/browser/chromeos/login/oobe_localization_browsertest.cc b/chrome/browser/chromeos/login/oobe_localization_browsertest.cc
index bc38759..5ece58e 100644
--- a/chrome/browser/chromeos/login/oobe_localization_browsertest.cc
+++ b/chrome/browser/chromeos/login/oobe_localization_browsertest.cc
@@ -14,10 +14,10 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/customization/customization_document.h"
-#include "chrome/browser/chromeos/login/login_manager_test.h"
 #include "chrome/browser/chromeos/login/login_wizard.h"
 #include "chrome/browser/chromeos/login/screens/welcome_screen.h"
 #include "chrome/browser/chromeos/login/test/js_checker.h"
+#include "chrome/browser/chromeos/login/test/oobe_base_test.h"
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
@@ -185,7 +185,7 @@
 };
 
 class OobeLocalizationTest
-    : public LoginManagerTest,
+    : public OobeBaseTest,
       public testing::WithParamInterface<const LocalizationTestParams*> {
  public:
   OobeLocalizationTest();
@@ -226,7 +226,7 @@
   DISALLOW_COPY_AND_ASSIGN(OobeLocalizationTest);
 };
 
-OobeLocalizationTest::OobeLocalizationTest() : LoginManagerTest(false, true) {
+OobeLocalizationTest::OobeLocalizationTest() : OobeBaseTest() {
   fake_statistics_provider_.SetMachineStatistic("initial_locale",
                                                 GetParam()->initial_locale);
   fake_statistics_provider_.SetMachineStatistic("keyboard_layout",
diff --git a/chrome/browser/chromeos/login/password_change_browsertest.cc b/chrome/browser/chromeos/login/password_change_browsertest.cc
index c287572..7144f46a 100644
--- a/chrome/browser/chromeos/login/password_change_browsertest.cc
+++ b/chrome/browser/chromeos/login/password_change_browsertest.cc
@@ -17,8 +17,8 @@
 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
 #include "chrome/browser/chromeos/login/session/user_session_manager_test_api.h"
 #include "chrome/browser/chromeos/login/signin_specifics.h"
-#include "chrome/browser/chromeos/login/startup_utils.h"
 #include "chrome/browser/chromeos/login/test/js_checker.h"
+#include "chrome/browser/chromeos/login/test/login_manager_mixin.h"
 #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
 #include "chrome/browser/chromeos/login/test/oobe_window_visibility_waiter.h"
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
@@ -34,10 +34,6 @@
 
 namespace {
 
-constexpr char kTestUser[] = "test-user1@gmail.com";
-constexpr char kTestUserGaiaId[] = "test-user1@gmail.com";
-
-
 // Used to wait for session manager to become active.
 class SessionStartWaiter : public session_manager::SessionManagerObserver {
  public:
@@ -77,11 +73,9 @@
 
 class PasswordChangeTest : public LoginManagerTest {
  public:
-  PasswordChangeTest()
-      : LoginManagerTest(false, false),
-        test_account_id_(
-            AccountId::FromUserEmailGaiaId(kTestUser, kTestUserGaiaId)) {
-    set_force_webui_login(false);
+  PasswordChangeTest() : LoginManagerTest() {
+    login_mixin_.AppendRegularUsers(1);
+    test_account_id_ = login_mixin_.users()[0].account_id;
   }
   ~PasswordChangeTest() override = default;
 
@@ -128,6 +122,7 @@
   AccountId test_account_id_;
   StubAuthenticator::DataRecoveryStatus data_recovery_status_ =
       StubAuthenticator::DataRecoveryStatus::kNone;
+  LoginManagerMixin login_mixin_{&mixin_host_};
 
  private:
   void HandleDataRecoveryStatusChange(
@@ -138,11 +133,6 @@
   }
 };
 
-IN_PROC_BROWSER_TEST_F(PasswordChangeTest, PRE_MigrateOldCryptohome) {
-  RegisterUser(test_account_id_);
-  StartupUtils::MarkOobeCompleted();
-}
-
 IN_PROC_BROWSER_TEST_F(PasswordChangeTest, MigrateOldCryptohome) {
   SetUpStubAuthentcatorAndAttemptLogin("old user password");
   WaitForPasswordChangeScreen();
@@ -166,11 +156,6 @@
   SessionStartWaiter().Wait();
 }
 
-IN_PROC_BROWSER_TEST_F(PasswordChangeTest, PRE_RetryOnWrongPassword) {
-  RegisterUser(test_account_id_);
-  StartupUtils::MarkOobeCompleted();
-}
-
 IN_PROC_BROWSER_TEST_F(PasswordChangeTest, RetryOnWrongPassword) {
   SetUpStubAuthentcatorAndAttemptLogin("old user password");
   WaitForPasswordChangeScreen();
@@ -213,11 +198,6 @@
   SessionStartWaiter().Wait();
 }
 
-IN_PROC_BROWSER_TEST_F(PasswordChangeTest, PRE_SkipDataRecovery) {
-  RegisterUser(test_account_id_);
-  StartupUtils::MarkOobeCompleted();
-}
-
 IN_PROC_BROWSER_TEST_F(PasswordChangeTest, SkipDataRecovery) {
   SetUpStubAuthentcatorAndAttemptLogin("old user password");
   WaitForPasswordChangeScreen();
@@ -249,11 +229,6 @@
   SessionStartWaiter().Wait();
 }
 
-IN_PROC_BROWSER_TEST_F(PasswordChangeTest, PRE_TryAgainAfterForgetLinkClick) {
-  RegisterUser(test_account_id_);
-  StartupUtils::MarkOobeCompleted();
-}
-
 IN_PROC_BROWSER_TEST_F(PasswordChangeTest, TryAgainAfterForgetLinkClick) {
   SetUpStubAuthentcatorAndAttemptLogin("old user password");
   WaitForPasswordChangeScreen();
@@ -294,11 +269,6 @@
   SessionStartWaiter().Wait();
 }
 
-IN_PROC_BROWSER_TEST_F(PasswordChangeTest, PRE_ClosePasswordChangedDialog) {
-  RegisterUser(test_account_id_);
-  StartupUtils::MarkOobeCompleted();
-}
-
 IN_PROC_BROWSER_TEST_F(PasswordChangeTest, ClosePasswordChangedDialog) {
   SetUpStubAuthentcatorAndAttemptLogin("old user password");
   WaitForPasswordChangeScreen();
diff --git a/chrome/browser/chromeos/login/proxy_auth_dialog_browsertest.cc b/chrome/browser/chromeos/login/proxy_auth_dialog_browsertest.cc
index 5f0115e..ab9ed97 100644
--- a/chrome/browser/chromeos/login/proxy_auth_dialog_browsertest.cc
+++ b/chrome/browser/chromeos/login/proxy_auth_dialog_browsertest.cc
@@ -64,8 +64,7 @@
 class ProxyAuthOnUserBoardScreenTest : public LoginManagerTest {
  public:
   ProxyAuthOnUserBoardScreenTest()
-      : LoginManagerTest(true /* should_launch_browser */,
-                         true /* should_initialize_webui */),
+      : LoginManagerTest(),
         proxy_server_(net::SpawnedTestServer::TYPE_BASIC_AUTH_PROXY,
                       base::FilePath()) {}
 
diff --git a/chrome/browser/chromeos/login/quick_unlock/pin_migration_browsertest.cc b/chrome/browser/chromeos/login/quick_unlock/pin_migration_browsertest.cc
index 7db404a..c714776 100644
--- a/chrome/browser/chromeos/login/quick_unlock/pin_migration_browsertest.cc
+++ b/chrome/browser/chromeos/login/quick_unlock/pin_migration_browsertest.cc
@@ -24,9 +24,7 @@
 
 class PinMigrationTest : public LoginManagerTest {
  public:
-  PinMigrationTest()
-      : LoginManagerTest(false /*should_launch_browser*/,
-                         true /* should_initialize_webui */) {}
+  PinMigrationTest() = default;
   ~PinMigrationTest() override = default;
 
   void SetUp() override {
diff --git a/chrome/browser/chromeos/login/screens/user_selection_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/user_selection_screen_browsertest.cc
index 381333d..70a78ee 100644
--- a/chrome/browser/chromeos/login/screens/user_selection_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/user_selection_screen_browsertest.cc
@@ -17,20 +17,11 @@
 
 namespace chromeos {
 
-namespace {
-
-// No consumer user according to BrowserPolicyConnector::IsNonEnterpriseUser.
-constexpr char kManagedTestUser[] = "manager@example.com";
-constexpr char kManagedTestUserGaiaId[] = "3333333333";
-
-}  // namespace
-
 class UserSelectionScreenTest : public LoginManagerTest {
  public:
-  UserSelectionScreenTest()
-      : LoginManagerTest(false /* should_launch_browser */,
-                         false /* should_initialize_webui */) {
-    set_force_webui_login(false);
+  UserSelectionScreenTest() : LoginManagerTest() {
+    login_manager_mixin_.AppendRegularUsers(3);
+    login_manager_mixin_.AppendManagedUsers(1);
   }
   ~UserSelectionScreenTest() override = default;
 
@@ -42,23 +33,15 @@
   }
 
  protected:
-  std::vector<LoginManagerMixin::TestUserInfo> test_users_{CreateUsers()};
-  LoginManagerMixin login_manager_mixin_{&mixin_host_, test_users_};
+  LoginManagerMixin login_manager_mixin_{&mixin_host_};
 
- private:
-  static std::vector<LoginManagerMixin::TestUserInfo> CreateUsers() {
-    auto users = LoginManagerMixin::CreateRegularUsers(3);
-    users.push_back(
-        LoginManagerMixin::TestUserInfo(AccountId::FromUserEmailGaiaId(
-            kManagedTestUser, kManagedTestUserGaiaId)));
-    return users;
-  }
   DISALLOW_COPY_AND_ASSIGN(UserSelectionScreenTest);
 };
 
 // Test that a banner shows up for known-unmanaged users that need dircrypto
 // migration. Also test that no banner shows up for users that may be managed.
 IN_PROC_BROWSER_TEST_F(UserSelectionScreenTest, ShowDircryptoMigrationBanner) {
+  const auto& users = login_manager_mixin_.users();
   // No banner for the first user since default is no migration.
   EXPECT_FALSE(ash::LoginScreenTestApi::IsWarningBubbleShown());
 
@@ -68,7 +51,7 @@
   FakeCryptohomeClient::Get()->set_needs_dircrypto_migration(true);
 
   // Focus the 2nd user pod (consumer).
-  ASSERT_TRUE(ash::LoginScreenTestApi::FocusUser(test_users_[1].account_id));
+  ASSERT_TRUE(ash::LoginScreenTestApi::FocusUser(users[1].account_id));
 
   // Wait for FakeCryptohomeClient to send back the check result.
   test::TestPredicateWaiter(base::BindRepeating([]() {
@@ -82,7 +65,7 @@
   FakeCryptohomeClient::Get()->set_needs_dircrypto_migration(false);
   histogram_tester = std::make_unique<base::HistogramTester>();
   // Focus the 3rd user pod (consumer).
-  ASSERT_TRUE(ash::LoginScreenTestApi::FocusUser(test_users_[2].account_id));
+  ASSERT_TRUE(ash::LoginScreenTestApi::FocusUser(users[2].account_id));
 
   // Wait for FakeCryptohomeClient to send back the check result.
   test::TestPredicateWaiter(base::BindRepeating([]() {
@@ -97,7 +80,7 @@
   histogram_tester = std::make_unique<base::HistogramTester>();
 
   // Focus to the 4th user pod (enterprise).
-  ASSERT_TRUE(ash::LoginScreenTestApi::FocusUser(test_users_[3].account_id));
+  ASSERT_TRUE(ash::LoginScreenTestApi::FocusUser(users[3].account_id));
 
   // Wait for FakeCryptohomeClient to send back the check result.
   test::TestPredicateWaiter(base::BindRepeating([]() {
diff --git a/chrome/browser/chromeos/login/session/chrome_session_manager_browsertest.cc b/chrome/browser/chromeos/login/session/chrome_session_manager_browsertest.cc
index 2d9249f3..ea0f2f7 100644
--- a/chrome/browser/chromeos/login/session/chrome_session_manager_browsertest.cc
+++ b/chrome/browser/chromeos/login/session/chrome_session_manager_browsertest.cc
@@ -74,8 +74,7 @@
 class ChromeSessionManagerTest : public LoginManagerTest {
  public:
   ChromeSessionManagerTest()
-      : LoginManagerTest(true, true),
-        fake_gaia_{&mixin_host_, embedded_test_server()} {}
+      : LoginManagerTest(), fake_gaia_{&mixin_host_, embedded_test_server()} {}
   ~ChromeSessionManagerTest() override {}
 
   // LoginManagerTest:
diff --git a/chrome/browser/chromeos/login/session_login_browsertest.cc b/chrome/browser/chromeos/login/session_login_browsertest.cc
index 5eced2b..ff2c5b7 100644
--- a/chrome/browser/chromeos/login/session_login_browsertest.cc
+++ b/chrome/browser/chromeos/login/session_login_browsertest.cc
@@ -28,7 +28,8 @@
 
 class BrowserLoginTest : public chromeos::LoginManagerTest {
  public:
-  BrowserLoginTest() : LoginManagerTest(true, true) {}
+  BrowserLoginTest() : LoginManagerTest() { set_should_launch_browser(true); }
+
   ~BrowserLoginTest() override {}
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
diff --git a/chrome/browser/chromeos/login/test/login_manager_mixin.cc b/chrome/browser/chromeos/login/test/login_manager_mixin.cc
index 7670368..f8f68c1 100644
--- a/chrome/browser/chromeos/login/test/login_manager_mixin.cc
+++ b/chrome/browser/chromeos/login/test/login_manager_mixin.cc
@@ -94,6 +94,18 @@
   DISALLOW_COPY_AND_ASSIGN(TestUserRegistrationMainExtra);
 };
 
+void AppendUsers(LoginManagerMixin::UserList* users,
+                 const std::string& domain,
+                 int n) {
+  int num = users->size();
+  for (int i = 0; i < n; ++i, ++num) {
+    const std::string email = "test_user_" + base::NumberToString(num) + domain;
+    const std::string gaia_id = base::NumberToString(num) + "111111111";
+    users->push_back(LoginManagerMixin::TestUserInfo(
+        AccountId::FromUserEmailGaiaId(email, gaia_id)));
+  }
+}
+
 }  // namespace
 
 // static
@@ -104,22 +116,25 @@
   return user_context;
 }
 
-std::vector<LoginManagerMixin::TestUserInfo>
-LoginManagerMixin::CreateRegularUsers(int n) {
-  std::vector<LoginManagerMixin::TestUserInfo> users;
-  for (int i = 0; i < n; ++i) {
-    const std::string email =
-        "test_user_" + base::NumberToString(i) + "@gmail.com";
-    const std::string gaia_id = base::NumberToString(i) + "111111111";
-    users.push_back(LoginManagerMixin::TestUserInfo(
-        AccountId::FromUserEmailGaiaId(email, gaia_id)));
-  }
-  return users;
+void LoginManagerMixin::AppendRegularUsers(int n) {
+  AppendUsers(&initial_users_, "@gmail.com", n);
 }
 
-LoginManagerMixin::LoginManagerMixin(
-    InProcessBrowserTestMixinHost* host,
-    const std::vector<TestUserInfo>& initial_users)
+void LoginManagerMixin::AppendManagedUsers(int n) {
+  AppendUsers(&initial_users_, "@example.com", n);
+}
+
+void LoginManagerMixin::AppendSupervisedUsers(int n) {
+  AppendUsers(&initial_users_, "@locally-managed.localhost", n);
+}
+
+LoginManagerMixin::LoginManagerMixin(InProcessBrowserTestMixinHost* host)
+    : InProcessBrowserTestMixin(host) {
+  g_instance_created = true;
+}
+
+LoginManagerMixin::LoginManagerMixin(InProcessBrowserTestMixinHost* host,
+                                     const UserList& initial_users)
     : InProcessBrowserTestMixin(host), initial_users_(initial_users) {
   DCHECK(!g_instance_created);
   g_instance_created = true;
diff --git a/chrome/browser/chromeos/login/test/login_manager_mixin.h b/chrome/browser/chromeos/login/test/login_manager_mixin.h
index 4772934..39fd7e9 100644
--- a/chrome/browser/chromeos/login/test/login_manager_mixin.h
+++ b/chrome/browser/chromeos/login/test/login_manager_mixin.h
@@ -51,14 +51,20 @@
     const user_manager::User::OAuthTokenStatus token_status;
   };
 
+  using UserList = std::vector<TestUserInfo>;
+
   // Convenience method for creating default UserContext for an account ID. The
   // result can be used with Login* methods below.
   static UserContext CreateDefaultUserContext(const TestUserInfo& account_id);
 
-  static std::vector<TestUserInfo> CreateRegularUsers(int n);
+  // Should be called before any InProcessBrowserTestMixin functions.
+  void AppendRegularUsers(int n);
+  void AppendManagedUsers(int n);
+  void AppendSupervisedUsers(int n);
 
+  explicit LoginManagerMixin(InProcessBrowserTestMixinHost* host);
   LoginManagerMixin(InProcessBrowserTestMixinHost* host,
-                    const std::vector<TestUserInfo>& initial_users);
+                    const UserList& initial_users);
 
   ~LoginManagerMixin() override;
 
@@ -72,6 +78,8 @@
   // behavior.
   void set_should_launch_browser(bool value) { should_launch_browser_ = value; }
 
+  const UserList& users() const { return initial_users_; }
+
   // Sets the list of default policy switches to be added to command line on the
   // login screen.
   void SetDefaultLoginSwitches(
@@ -106,7 +114,7 @@
   bool LoginAndWaitForActiveSession(const UserContext& user_context);
 
  private:
-  const std::vector<TestUserInfo> initial_users_;
+  UserList initial_users_;
 
   // If set, session_flags_manager_ will be set up with session restore logic
   // enabled (it will restore session state between test runs for multi-step
diff --git a/chrome/browser/chromeos/login/ui/captive_portal_window_browsertest.cc b/chrome/browser/chromeos/login/ui/captive_portal_window_browsertest.cc
index 1fa7f73..5c20d9c 100644
--- a/chrome/browser/chromeos/login/ui/captive_portal_window_browsertest.cc
+++ b/chrome/browser/chromeos/login/ui/captive_portal_window_browsertest.cc
@@ -177,8 +177,7 @@
 
 class CaptivePortalWindowCtorDtorTest : public LoginManagerTest {
  public:
-  CaptivePortalWindowCtorDtorTest()
-      : LoginManagerTest(false, true /* should_initialize_webui */) {}
+  CaptivePortalWindowCtorDtorTest() = default;
   ~CaptivePortalWindowCtorDtorTest() override {}
 
   void SetUpInProcessBrowserTestFixture() override {
diff --git a/chrome/browser/chromeos/login/ui/login_feedback_browsertest.cc b/chrome/browser/chromeos/login/ui/login_feedback_browsertest.cc
index e1fb02f9..997abf40 100644
--- a/chrome/browser/chromeos/login/ui/login_feedback_browsertest.cc
+++ b/chrome/browser/chromeos/login/ui/login_feedback_browsertest.cc
@@ -10,6 +10,8 @@
 #include "base/macros.h"
 #include "base/run_loop.h"
 #include "chrome/browser/chromeos/login/login_manager_test.h"
+#include "chrome/browser/chromeos/login/test/login_manager_mixin.h"
+#include "chrome/browser/chromeos/login/test/oobe_base_test.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/extensions/extension_constants.h"
@@ -23,15 +25,17 @@
 
 class LoginFeedbackTest : public LoginManagerTest {
  public:
-  LoginFeedbackTest() : LoginManagerTest(true, true) {}
+  LoginFeedbackTest() : LoginManagerTest() {
+    login_mixin_.AppendRegularUsers(2);
+  }
   ~LoginFeedbackTest() override {}
 
  private:
+  LoginManagerMixin login_mixin_{&mixin_host_};
   DISALLOW_COPY_AND_ASSIGN(LoginFeedbackTest);
 };
 
-// Test feedback UI shows up and is active.
-IN_PROC_BROWSER_TEST_F(LoginFeedbackTest, Basic) {
+void TestFeedback() {
   Profile* const profile = ProfileHelper::GetSigninProfile();
   std::unique_ptr<LoginFeedback> login_feedback(new LoginFeedback(profile));
 
@@ -51,4 +55,14 @@
   run_loop.Run();
 }
 
+// Test feedback UI shows up and is active on the Login Screen
+IN_PROC_BROWSER_TEST_F(LoginFeedbackTest, Basic) {
+  TestFeedback();
+}
+
+// Test feedback UI shows up and is active in OOBE
+IN_PROC_BROWSER_TEST_F(OobeBaseTest, FeedbackBasic) {
+  TestFeedback();
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/ui/simple_web_view_dialog_browsertest.cc b/chrome/browser/chromeos/login/ui/simple_web_view_dialog_browsertest.cc
index bfa89bd7..025dafe 100644
--- a/chrome/browser/chromeos/login/ui/simple_web_view_dialog_browsertest.cc
+++ b/chrome/browser/chromeos/login/ui/simple_web_view_dialog_browsertest.cc
@@ -5,7 +5,7 @@
 #include "base/compiler_specific.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "chrome/browser/chromeos/login/login_manager_test.h"
+#include "chrome/browser/chromeos/login/test/oobe_base_test.h"
 #include "chrome/browser/chromeos/login/ui/captive_portal_view.h"
 #include "chrome/browser/chromeos/login/ui/captive_portal_window_proxy.h"
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
@@ -48,10 +48,9 @@
 
 }  // namespace
 
-class SimpleWebViewDialogTest : public LoginManagerTest {
+class SimpleWebViewDialogTest : public OobeBaseTest {
  public:
-  SimpleWebViewDialogTest()
-      : LoginManagerTest(false, true /* should_initialize_webui */) {}
+  SimpleWebViewDialogTest() = default;
   ~SimpleWebViewDialogTest() override {}
 
   InterstitialPageDelegate* CreateDelegate(CaptivePortalWindowProxy* proxy) {
diff --git a/chrome/browser/chromeos/login/ui/user_adding_screen_browsertest.cc b/chrome/browser/chromeos/login/ui/user_adding_screen_browsertest.cc
index babbab7..be795fc 100644
--- a/chrome/browser/chromeos/login/ui/user_adding_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/ui/user_adding_screen_browsertest.cc
@@ -11,8 +11,8 @@
 #include "chrome/browser/chromeos/login/lock/screen_locker.h"
 #include "chrome/browser/chromeos/login/lock/screen_locker_tester.h"
 #include "chrome/browser/chromeos/login/login_manager_test.h"
-#include "chrome/browser/chromeos/login/startup_utils.h"
 #include "chrome/browser/chromeos/login/test/js_checker.h"
+#include "chrome/browser/chromeos/login/test/login_manager_mixin.h"
 #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
 #include "chrome/browser/chromeos/login/test/session_manager_state_waiter.h"
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
@@ -47,18 +47,8 @@
 class UserAddingScreenTest : public LoginManagerTest,
                              public UserAddingScreen::Observer {
  public:
-  UserAddingScreenTest()
-      : LoginManagerTest(false, true /* should_initialize_webui */) {
-    struct {
-      const char* email;
-      const char* gaia_id;
-    } const kTestUsers[] = {{"test-user1@gmail.com", "1111111111"},
-                            {"test-user2@gmail.com", "2222222222"},
-                            {"test-user3@gmail.com", "3333333333"}};
-    for (size_t i = 0; i < base::size(kTestUsers); ++i) {
-      test_users_.emplace_back(AccountId::FromUserEmailGaiaId(
-          kTestUsers[i].email, kTestUsers[i].gaia_id));
-    }
+  UserAddingScreenTest() : LoginManagerTest() {
+    login_mixin_.AppendRegularUsers(3);
   }
 
   void SetUpInProcessBrowserTestFixture() override {
@@ -107,8 +97,8 @@
 
   int user_adding_finished() { return user_adding_finished_; }
 
-  std::vector<AccountId> test_users_;
   std::vector<AccountId> users_in_session_order_;
+  LoginManagerMixin login_mixin_{&mixin_host_};
 
  private:
   int user_adding_started_ = 0;
@@ -120,20 +110,14 @@
   DISALLOW_COPY_AND_ASSIGN(UserAddingScreenTest);
 };
 
-IN_PROC_BROWSER_TEST_F(UserAddingScreenTest, PRE_CancelAdding) {
-  RegisterUser(test_users_[0]);
-  RegisterUser(test_users_[1]);
-  RegisterUser(test_users_[2]);
-  StartupUtils::MarkOobeCompleted();
-}
-
 IN_PROC_BROWSER_TEST_F(UserAddingScreenTest, CancelAdding) {
-  EXPECT_EQ(3u, user_manager::UserManager::Get()->GetUsers().size());
+  const auto& users = login_mixin_.users();
+  EXPECT_EQ(users.size(), user_manager::UserManager::Get()->GetUsers().size());
   EXPECT_EQ(0u, user_manager::UserManager::Get()->GetLoggedInUsers().size());
   EXPECT_EQ(session_manager::SessionState::LOGIN_PRIMARY,
             session_manager::SessionManager::Get()->session_state());
 
-  LoginUser(test_users_[0]);
+  LoginUser(users[0].account_id);
   EXPECT_EQ(1u, user_manager::UserManager::Get()->GetLoggedInUsers().size());
   EXPECT_EQ(session_manager::SessionState::ACTIVE,
             session_manager::SessionManager::Get()->session_state());
@@ -155,17 +139,10 @@
 
   EXPECT_TRUE(LoginDisplayHost::default_host() == nullptr);
   EXPECT_EQ(1u, user_manager::UserManager::Get()->GetLoggedInUsers().size());
-  EXPECT_EQ(test_users_[0],
+  EXPECT_EQ(users[0].account_id,
             user_manager::UserManager::Get()->GetActiveUser()->GetAccountId());
 }
 
-IN_PROC_BROWSER_TEST_F(UserAddingScreenTest, PRE_AddingSeveralUsers) {
-  RegisterUser(test_users_[0]);
-  RegisterUser(test_users_[1]);
-  RegisterUser(test_users_[2]);
-  StartupUtils::MarkOobeCompleted();
-}
-
 // TODO(crbug.com/1067461): Flakes on ASAN and MSAN
 #if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER)
 #define MAYBE_AddingSeveralUsers DISABLED_AddingSeveralUsers
@@ -173,18 +150,19 @@
 #define MAYBE_AddingSeveralUsers AddingSeveralUsers
 #endif
 IN_PROC_BROWSER_TEST_F(UserAddingScreenTest, MAYBE_AddingSeveralUsers) {
+  const auto& users = login_mixin_.users();
   EXPECT_EQ(session_manager::SessionState::LOGIN_PRIMARY,
             session_manager::SessionManager::Get()->session_state());
 
-  LoginUser(test_users_[0]);
-  users_in_session_order_.push_back(test_users_[0]);
+  LoginUser(users[0].account_id);
+  users_in_session_order_.push_back(users[0].account_id);
   EXPECT_EQ(session_manager::SessionState::ACTIVE,
             session_manager::SessionManager::Get()->session_state());
 
   user_manager::UserManager* user_manager = user_manager::UserManager::Get();
 
   base::HistogramTester histogram_tester;
-  const int n = test_users_.size();
+  const int n = users.size();
   for (int i = 1; i < n; ++i) {
     UserAddingScreen::Get()->Start();
     OobeScreenWaiter(OobeScreen::SCREEN_ACCOUNT_PICKER).Wait();
@@ -193,8 +171,8 @@
               session_manager::SessionManager::Get()->session_state());
     EXPECT_TRUE(ash::LoginScreenTestApi::IsCancelButtonShown());
 
-    UILoginUser(test_users_[n - i], kPassword);
-    users_in_session_order_.push_back(test_users_[n - i]);
+    UILoginUser(users[n - i].account_id, kPassword);
+    users_in_session_order_.push_back(users[n - i].account_id);
 
     EXPECT_EQ(i, user_adding_finished());
     EXPECT_EQ(session_manager::SessionState::ACTIVE,
@@ -239,12 +217,12 @@
                     MultiProfileUserController::kBehaviorUnrestricted);
   user_manager::UserList unlock_users = user_manager->GetUnlockUsers();
   ASSERT_EQ(1UL, unlock_users.size());
-  EXPECT_EQ(test_users_[0], unlock_users[0]->GetAccountId());
+  EXPECT_EQ(users[0].account_id, unlock_users[0]->GetAccountId());
 
   prefs1->SetBoolean(ash::prefs::kEnableAutoScreenLock, false);
   unlock_users = user_manager->GetUnlockUsers();
   ASSERT_EQ(1UL, unlock_users.size());
-  EXPECT_EQ(test_users_[0], unlock_users[0]->GetAccountId());
+  EXPECT_EQ(users[0].account_id, unlock_users[0]->GetAccountId());
 
   // If all users have unrestricted policy then anyone can perform unlock.
   prefs1->SetString(prefs::kMultiProfileUserBehavior,
@@ -281,12 +259,6 @@
     EXPECT_EQ(users_in_session_order_[i], unlock_users[i]->GetAccountId());
 }
 
-IN_PROC_BROWSER_TEST_F(UserAddingScreenTest, PRE_ScreenVisibility) {
-  RegisterUser(test_users_[0]);
-  RegisterUser(test_users_[1]);
-  StartupUtils::MarkOobeCompleted();
-}
-
 // crbug.com/1067461: Flakes on ASAN and MSAN
 #if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER)
 #define MAYBE_ScreenVisibility DISABLED_ScreenVisibility
@@ -294,7 +266,8 @@
 #define MAYBE_ScreenVisibility ScreenVisibility
 #endif
 IN_PROC_BROWSER_TEST_F(UserAddingScreenTest, MAYBE_ScreenVisibility) {
-  LoginUser(test_users_[0]);
+  const auto& users = login_mixin_.users();
+  LoginUser(users[0].account_id);
 
   UserAddingScreen::Get()->Start();
   OobeScreenWaiter(OobeScreen::SCREEN_ACCOUNT_PICKER).Wait();
diff --git a/chrome/browser/chromeos/login/users/avatar/user_image_manager_browsertest.cc b/chrome/browser/chromeos/login/users/avatar/user_image_manager_browsertest.cc
index 739acb3..ed2470f 100644
--- a/chrome/browser/chromeos/login/users/avatar/user_image_manager_browsertest.cc
+++ b/chrome/browser/chromeos/login/users/avatar/user_image_manager_browsertest.cc
@@ -169,7 +169,7 @@
   }
 
  protected:
-  UserImageManagerTest() : LoginManagerTest(true, true) {}
+  UserImageManagerTest() = default;
 
   // LoginManagerTest overrides:
   void SetUpInProcessBrowserTestFixture() override {
diff --git a/chrome/browser/chromeos/login/users/remove_supervised_users_browsertest.cc b/chrome/browser/chromeos/login/users/remove_supervised_users_browsertest.cc
index 6ffdd1c..4effcff 100644
--- a/chrome/browser/chromeos/login/users/remove_supervised_users_browsertest.cc
+++ b/chrome/browser/chromeos/login/users/remove_supervised_users_browsertest.cc
@@ -8,79 +8,34 @@
 #include "base/macros.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/chromeos/login/login_manager_test.h"
-#include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
-#include "chrome/browser/chromeos/login/users/chrome_user_manager_impl.h"
+#include "chrome/browser/chromeos/login/test/login_manager_mixin.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
-#include "chrome/browser/chromeos/settings/scoped_testing_cros_settings.h"
 #include "chrome/common/chrome_features.h"
-#include "components/account_id/account_id.h"
-#include "components/user_manager/scoped_user_manager.h"
 #include "components/user_manager/user_manager.h"
 #include "components/user_manager/user_manager_base.h"
 
 namespace chromeos {
 
-namespace {
-
-struct {
-  const char* email;
-  const char* gaia_id;
-} const kTestUsers[] = {
-    {"test-user1@gmail.com", "1111111111"},
-    {"test-user2@gmail.com", "2222222222"},
-    // Test Supervised User.
-    // The domain is defined in user_manager::kSupervisedUserDomain.
-    // That const isn't directly referenced here to keep this code readable by
-    // avoiding std::string concatenations.
-    {"test-superviseduser@locally-managed.localhost", "3333333333"},
-};
-
-}  // namespace
-
 class RemoveSupervisedUsersBrowserTest : public LoginManagerTest {
  public:
-  RemoveSupervisedUsersBrowserTest() : LoginManagerTest(false, false) {}
+  RemoveSupervisedUsersBrowserTest() : LoginManagerTest() {
+    login_mixin_.AppendRegularUsers(2);
+    login_mixin_.AppendSupervisedUsers(1);
+  }
 
   ~RemoveSupervisedUsersBrowserTest() override = default;
 
-  void SetUpOnMainThread() override {
-    LoginManagerTest::SetUpOnMainThread();
-    InitializeTestUsers();
-  }
-
-  void TearDownOnMainThread() override {
-    LoginManagerTest::TearDownOnMainThread();
-    scoped_user_manager_.reset();
-  }
-
  protected:
-  std::vector<AccountId> test_users_;
-
- private:
-  void InitializeTestUsers() {
-    for (size_t i = 0; i < base::size(kTestUsers); ++i) {
-      test_users_.emplace_back(AccountId::FromUserEmailGaiaId(
-          kTestUsers[i].email, kTestUsers[i].gaia_id));
-      RegisterUser(test_users_[i]);
-    }
-
-    // Setup a scoped real ChromeUserManager, since this is an end-to-end
-    // test.  This will read the users registered to the local state just
-    // before this in RegisterUser.
-    scoped_user_manager_ = std::make_unique<user_manager::ScopedUserManager>(
-        chromeos::ChromeUserManagerImpl::CreateChromeUserManager());
-  }
-
-  std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_;
-  ScopedTestingCrosSettings scoped_testing_cros_settings_;
+  LoginManagerMixin login_mixin_{&mixin_host_};
 
   DISALLOW_COPY_AND_ASSIGN(RemoveSupervisedUsersBrowserTest);
 };
 
 class RemoveSupervisedUsersBrowserEnabledTest
     : public RemoveSupervisedUsersBrowserTest {
- protected:
-  void SetUpInProcessBrowserTestFixture() override {
+ public:
+  RemoveSupervisedUsersBrowserEnabledTest()
+      : RemoveSupervisedUsersBrowserTest() {
     scoped_feature_list_.InitWithFeatures(
         {features::kRemoveSupervisedUsersOnStartup},
         {user_manager::kHideSupervisedUsers});
@@ -92,8 +47,9 @@
 
 class RemoveSupervisedUsersBrowserDisabledTest
     : public RemoveSupervisedUsersBrowserTest {
- protected:
-  void SetUpInProcessBrowserTestFixture() override {
+ public:
+  RemoveSupervisedUsersBrowserDisabledTest()
+      : RemoveSupervisedUsersBrowserTest() {
     scoped_feature_list_.InitWithFeatures(
         {}, {user_manager::kHideSupervisedUsers,
              features::kRemoveSupervisedUsersOnStartup});
diff --git a/chrome/browser/chromeos/login/users/user_manager_hide_supervised_users_browsertest.cc b/chrome/browser/chromeos/login/users/user_manager_hide_supervised_users_browsertest.cc
index 7a4b588..8c9bf32 100644
--- a/chrome/browser/chromeos/login/users/user_manager_hide_supervised_users_browsertest.cc
+++ b/chrome/browser/chromeos/login/users/user_manager_hide_supervised_users_browsertest.cc
@@ -38,8 +38,7 @@
 
 class UserManagerHideSupervisedUsersBrowserTest : public LoginManagerTest {
  public:
-  UserManagerHideSupervisedUsersBrowserTest()
-      : LoginManagerTest(false, false) {}
+  UserManagerHideSupervisedUsersBrowserTest() = default;
 
   ~UserManagerHideSupervisedUsersBrowserTest() override = default;
 
diff --git a/chrome/browser/chromeos/login/users/wallpaper_policy_browsertest.cc b/chrome/browser/chromeos/login/users/wallpaper_policy_browsertest.cc
index 3f7ad74..ab4767f 100644
--- a/chrome/browser/chromeos/login/users/wallpaper_policy_browsertest.cc
+++ b/chrome/browser/chromeos/login/users/wallpaper_policy_browsertest.cc
@@ -132,8 +132,7 @@
                             public ash::WallpaperControllerObserver {
  protected:
   WallpaperPolicyTest()
-      : LoginManagerTest(true, true),
-        owner_key_util_(new ownership::MockOwnerKeyUtil()) {
+      : LoginManagerTest(), owner_key_util_(new ownership::MockOwnerKeyUtil()) {
     testUsers_.push_back(
         AccountId::FromUserEmailGaiaId(FakeGaiaMixin::kEnterpriseUser1,
                                        FakeGaiaMixin::kEnterpriseUser1GaiaId));
diff --git a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
index a842c27..59ee08f 100644
--- a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
+++ b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
@@ -2014,10 +2014,8 @@
 
 class WizardControllerScreenPriorityTest : public LoginManagerTest {
  protected:
-  WizardControllerScreenPriorityTest()
-      : LoginManagerTest(false /* should_launch_browser */,
-                         false /* should_initialize_webui */) {
-    set_force_webui_login(false);
+  WizardControllerScreenPriorityTest() {
+    login_manager_mixin_.AppendRegularUsers(1);
     feature_list_.InitAndEnableFeature(
         chromeos::features::kOobeScreensPriority);
   }
@@ -2030,9 +2028,7 @@
 
  private:
   base::test::ScopedFeatureList feature_list_;
-  std::vector<LoginManagerMixin::TestUserInfo> test_users_{
-      LoginManagerMixin::CreateRegularUsers(1)};
-  LoginManagerMixin login_manager_mixin_{&mixin_host_, test_users_};
+  LoginManagerMixin login_manager_mixin_{&mixin_host_};
 };
 
 // TODO(https://crbug.com/1064271) Replace this PRE test with adding adding a
diff --git a/chrome/browser/chromeos/net/network_portal_detector_impl_browsertest.cc b/chrome/browser/chromeos/net/network_portal_detector_impl_browsertest.cc
index e0f9af8..7acdbab 100644
--- a/chrome/browser/chromeos/net/network_portal_detector_impl_browsertest.cc
+++ b/chrome/browser/chromeos/net/network_portal_detector_impl_browsertest.cc
@@ -76,7 +76,7 @@
       public captive_portal::CaptivePortalDetectorTestBase {
  public:
   NetworkPortalDetectorImplBrowserTest()
-      : LoginManagerTest(false, true),
+      : LoginManagerTest(),
         test_account_id_(
             AccountId::FromUserEmailGaiaId(kTestUser, kTestUserGaiaId)),
         network_portal_detector_(nullptr) {}
diff --git a/chrome/browser/chromeos/policy/network_policy_application_browsertest.cc b/chrome/browser/chromeos/policy/network_policy_application_browsertest.cc
index 7cdfcc4..3095e0f 100644
--- a/chrome/browser/chromeos/policy/network_policy_application_browsertest.cc
+++ b/chrome/browser/chromeos/policy/network_policy_application_browsertest.cc
@@ -9,7 +9,7 @@
 #include "base/macros.h"
 #include "base/test/values_test_util.h"
 #include "chrome/browser/chromeos/login/login_manager_test.h"
-#include "chrome/browser/chromeos/login/startup_utils.h"
+#include "chrome/browser/chromeos/login/test/login_manager_mixin.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/shill/shill_device_client.h"
@@ -125,12 +125,10 @@
 // application across sign-in screen and/or user session.
 class NetworkPolicyApplicationTest : public LoginManagerTest {
  public:
-  NetworkPolicyApplicationTest()
-      : LoginManagerTest(true /* should_launch_browser */,
-                         true /* should_initialize_webui */),
-        test_account_id_(AccountId::FromUserEmailGaiaId(
-            policy::PolicyBuilder::kFakeUsername,
-            policy::PolicyBuilder::kFakeGaiaId)) {}
+  NetworkPolicyApplicationTest() : LoginManagerTest() {
+    login_mixin_.AppendRegularUsers(1);
+    test_account_id_ = login_mixin_.users()[0].account_id;
+  }
 
  protected:
   // InProcessBrowserTest:
@@ -217,6 +215,7 @@
   ShillProfileClient::TestInterface* shill_profile_client_test_ = nullptr;
   ShillDeviceClient::TestInterface* shill_device_client_test_ = nullptr;
 
+  LoginManagerMixin login_mixin_{&mixin_host_};
   AccountId test_account_id_;
 
  private:
@@ -226,12 +225,6 @@
   DISALLOW_COPY_AND_ASSIGN(NetworkPolicyApplicationTest);
 };
 
-IN_PROC_BROWSER_TEST_F(NetworkPolicyApplicationTest,
-                       PRE_OnlyPolicyAutoconnectWithSlowUserPolicyApplication) {
-  RegisterUser(test_account_id_);
-  StartupUtils::MarkOobeCompleted();
-}
-
 // This test applies a global network policy with
 // AllowOnlyPolicyNetworksToAutoconnect set to true. It then performs a user
 // log-in and simulates that user policy application is slow. This is a
diff --git a/chrome/browser/chromeos/preferences_chromeos_browsertest.cc b/chrome/browser/chromeos/preferences_chromeos_browsertest.cc
index 8a7b4cfe..c55f1b19 100644
--- a/chrome/browser/chromeos/preferences_chromeos_browsertest.cc
+++ b/chrome/browser/chromeos/preferences_chromeos_browsertest.cc
@@ -12,7 +12,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/input_method/input_method_manager_impl.h"
 #include "chrome/browser/chromeos/login/login_manager_test.h"
-#include "chrome/browser/chromeos/login/startup_utils.h"
+#include "chrome/browser/chromeos/login/test/login_manager_mixin.h"
 #include "chrome/browser/chromeos/login/ui/user_adding_screen.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
@@ -34,21 +34,11 @@
 class PreferencesTest : public LoginManagerTest {
  public:
   PreferencesTest()
-      : LoginManagerTest(true, true),
-        input_settings_(nullptr),
-        keyboard_(nullptr) {
-    struct {
-      const char* email;
-      const char* gaia_id;
-    } const kTestUsers[] = {{"test-user1@gmail.com", "1111111111"},
-                            {"test-user2@gmail.com", "2222222222"}};
-    for (size_t i = 0; i < base::size(kTestUsers); ++i) {
-      test_users_.push_back(AccountId::FromUserEmailGaiaId(
-          kTestUsers[i].email, kTestUsers[i].gaia_id));
-    }
-
+      : LoginManagerTest(), input_settings_(nullptr), keyboard_(nullptr) {
+    login_mixin_.AppendRegularUsers(2);
     scoped_testing_cros_settings_.device_settings()->Set(
-        kDeviceOwner, base::Value(test_users_[0].GetUserEmail()));
+        kDeviceOwner,
+        base::Value(login_mixin_.users()[0].account_id.GetUserEmail()));
 
     feature_list_.InitAndEnableFeature(features::kAllowScrollSettings);
   }
@@ -140,7 +130,7 @@
               prefs->GetBoolean(prefs::kPrimaryMouseButtonRight));
   }
 
-  std::vector<AccountId> test_users_;
+  LoginManagerMixin login_mixin_{&mixin_host_};
   ScopedTestingCrosSettings scoped_testing_cros_settings_;
 
  private:
@@ -151,19 +141,14 @@
   DISALLOW_COPY_AND_ASSIGN(PreferencesTest);
 };
 
-IN_PROC_BROWSER_TEST_F(PreferencesTest, PRE_MultiProfiles) {
-  RegisterUser(test_users_[0]);
-  RegisterUser(test_users_[1]);
-  StartupUtils::MarkOobeCompleted();
-}
-
 IN_PROC_BROWSER_TEST_F(PreferencesTest, MultiProfiles) {
   user_manager::UserManager* user_manager = user_manager::UserManager::Get();
 
+  const auto& users = login_mixin_.users();
   // Add first user and init its preferences. Check that corresponding
   // settings has been changed.
-  LoginUser(test_users_[0]);
-  const user_manager::User* user1 = user_manager->FindUser(test_users_[0]);
+  LoginUser(users[0].account_id);
+  const user_manager::User* user1 = user_manager->FindUser(users[0].account_id);
   PrefService* prefs1 =
       ProfileHelper::Get()->GetProfileByUserUnsafe(user1)->GetPrefs();
   SetPrefs(prefs1, false);
@@ -173,9 +158,9 @@
   // Add second user and init its prefs with different values.
   UserAddingScreen::Get()->Start();
   content::RunAllPendingInMessageLoop();
-  AddUser(test_users_[1]);
+  AddUser(users[1].account_id);
   content::RunAllPendingInMessageLoop();
-  const user_manager::User* user2 = user_manager->FindUser(test_users_[1]);
+  const user_manager::User* user2 = user_manager->FindUser(users[1].account_id);
   EXPECT_TRUE(user2->is_active());
   PrefService* prefs2 =
       ProfileHelper::Get()->GetProfileByUserUnsafe(user2)->GetPrefs();
@@ -212,7 +197,7 @@
 
   // Check that changing non-owner prefs doesn't change corresponding local
   // state prefs and vice versa.
-  EXPECT_EQ(user_manager->GetOwnerAccountId(), test_users_[0]);
+  EXPECT_EQ(user_manager->GetOwnerAccountId(), users[0].account_id);
   CheckLocalStateCorrespondsToPrefs(prefs1);
   prefs2->SetBoolean(prefs::kTapToClickEnabled,
                      !prefs1->GetBoolean(prefs::kTapToClickEnabled));
@@ -222,7 +207,7 @@
   CheckLocalStateCorrespondsToPrefs(prefs1);
 
   // Switch user back.
-  user_manager->SwitchActiveUser(test_users_[0]);
+  user_manager->SwitchActiveUser(users[0].account_id);
   CheckSettingsCorrespondToPrefs(prefs1);
   CheckLocalStateCorrespondsToPrefs(prefs1);
 }
diff --git a/chrome/browser/chromeos/web_applications/chrome_media_app_ui_delegate.cc b/chrome/browser/chromeos/web_applications/chrome_media_app_ui_delegate.cc
index 42b71b1..d1fa5cb 100644
--- a/chrome/browser/chromeos/web_applications/chrome_media_app_ui_delegate.cc
+++ b/chrome/browser/chromeos/web_applications/chrome_media_app_ui_delegate.cc
@@ -14,15 +14,18 @@
 
 base::Optional<std::string> ChromeMediaAppUIDelegate::OpenFeedbackDialog() {
   Profile* profile = Profile::FromWebUI(web_ui_);
+  constexpr char kMediaAppFeedbackCategoryTag[] = "FromMediaApp";
+
   // TODO(crbug/1045222): Additional strings are blank right now while we decide
   // on the language and relevant information we want feedback to include.
   // Note that category_tag is the name of the listnr bucket we want our
-  // reports to end up in. I.e DESKTOP_TAB_GROUPS.
-  chrome::ShowFeedbackPage(
-      GURL(chromeos::kChromeUIMediaAppURL), profile,
-      chrome::kFeedbackSourceMediaApp, std::string() /* description_template */,
-      std::string() /* description_placeholder_text */,
-      std::string() /* category_tag */, std::string() /* extra_diagnostics */);
+  // reports to end up in.
+  chrome::ShowFeedbackPage(GURL(chromeos::kChromeUIMediaAppURL), profile,
+                           chrome::kFeedbackSourceMediaApp,
+                           std::string() /* description_template */,
+                           std::string() /* description_placeholder_text */,
+                           kMediaAppFeedbackCategoryTag /* category_tag */,
+                           std::string() /* extra_diagnostics */);
 
   // TODO(crbug/1048368): Showing the feedback dialog can fail, communicate this
   // back to the client with an error string. For now assume dialog opened.
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 0832798..6f47b5a9 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -394,6 +394,11 @@
     "expiry_milestone": 85
   },
   {
+    "name": "bluetooth-fix-a2dp-packet-size",
+    "owners": [ "michaelfsun", "chromeos-bluetooth@google.com" ],
+    "expiry_milestone": 86
+  },
+  {
     "name": "bluetooth-kernel-suspend-notifier",
     "owners": [ "abhishekpandit", "chromeos-bluetooth@google.com" ],
     "expiry_milestone": 84
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index bd02ee2..834f4de 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -3105,6 +3105,11 @@
     "Enables a more aggressive Bluetooth filter in the UI to hide devices that "
     "likely cannot be connected to.";
 
+const char kBluetoothFixA2dpPacketSizeName[] = "Bluetooth fix A2DP packet size";
+const char kBluetoothFixA2dpPacketSizeDescription[] =
+    "Fixes Bluetooth A2DP packet size to a smaller default value to improve "
+    "audio quality and may fix audio stutter.";
+
 const char kBluetoothKernelSuspendNotifierName[] =
     "Bluetooth kernel suspend notifier handler";
 const char kBluetoothKernelSuspendNotifierDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 44ac8c98f..f9ef6fd1 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1790,6 +1790,9 @@
 extern const char kBluetoothAggressiveAppearanceFilterName[];
 extern const char kBluetoothAggressiveAppearanceFilterDescription[];
 
+extern const char kBluetoothFixA2dpPacketSizeName[];
+extern const char kBluetoothFixA2dpPacketSizeDescription[];
+
 extern const char kBluetoothKernelSuspendNotifierName[];
 extern const char kBluetoothKernelSuspendNotifierDescription[];
 
diff --git a/chrome/browser/net/nss_context_chromeos_browsertest.cc b/chrome/browser/net/nss_context_chromeos_browsertest.cc
index 67db177..543cc8c7 100644
--- a/chrome/browser/net/nss_context_chromeos_browsertest.cc
+++ b/chrome/browser/net/nss_context_chromeos_browsertest.cc
@@ -10,7 +10,7 @@
 #include "base/run_loop.h"
 #include "base/task/post_task.h"
 #include "chrome/browser/chromeos/login/login_manager_test.h"
-#include "chrome/browser/chromeos/login/startup_utils.h"
+#include "chrome/browser/chromeos/login/test/login_manager_mixin.h"
 #include "chrome/browser/chromeos/login/ui/user_adding_screen.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
@@ -22,11 +22,6 @@
 
 namespace {
 
-constexpr char kTestUser1[] = "test-user1@gmail.com";
-constexpr char kTestUser1GaiaId[] = "1111111111";
-constexpr char kTestUser2[] = "test-user2@gmail.com";
-constexpr char kTestUser2GaiaId[] = "2222222222";
-
 void NotCalledDbCallback(net::NSSCertDatabase* db) { ASSERT_TRUE(false); }
 
 // DBTester handles retrieving the NSSCertDatabase for a given profile, and
@@ -156,25 +151,20 @@
 
 class NSSContextChromeOSBrowserTest : public chromeos::LoginManagerTest {
  public:
-  NSSContextChromeOSBrowserTest()
-      : LoginManagerTest(true /* should_launch_browser */,
-                         true /* should_initialize_webui */) {}
+  NSSContextChromeOSBrowserTest() : LoginManagerTest() {
+    login_mixin_.AppendRegularUsers(2);
+  }
   ~NSSContextChromeOSBrowserTest() override {}
-};
 
-IN_PROC_BROWSER_TEST_F(NSSContextChromeOSBrowserTest, PRE_TwoUsers) {
-  // Initialization for ChromeOS multi-profile test infrastructure.
-  RegisterUser(AccountId::FromUserEmailGaiaId(kTestUser1, kTestUser1GaiaId));
-  RegisterUser(AccountId::FromUserEmailGaiaId(kTestUser2, kTestUser2GaiaId));
-  chromeos::StartupUtils::MarkOobeCompleted();
-}
+ protected:
+  chromeos::LoginManagerMixin login_mixin_{&mixin_host_};
+};
 
 IN_PROC_BROWSER_TEST_F(NSSContextChromeOSBrowserTest, TwoUsers) {
   user_manager::UserManager* user_manager = user_manager::UserManager::Get();
 
   // Log in first user and get their DB.
-  const AccountId account_id1(
-      AccountId::FromUserEmailGaiaId(kTestUser1, kTestUser1GaiaId));
+  const AccountId account_id1(login_mixin_.users()[0].account_id);
   LoginUser(account_id1);
   Profile* profile1 = chromeos::ProfileHelper::Get()->GetProfileByUserUnsafe(
       user_manager->FindUser(account_id1));
@@ -188,8 +178,7 @@
   chromeos::UserAddingScreen::Get()->Start();
   base::RunLoop().RunUntilIdle();
 
-  const AccountId account_id2(
-      AccountId::FromUserEmailGaiaId(kTestUser2, kTestUser2GaiaId));
+  const AccountId account_id2(login_mixin_.users()[1].account_id);
   AddUser(account_id2);
   observer.WaitUntilUserAddingFinishedOrCancelled();
 
diff --git a/chrome/browser/printing/print_job_worker.cc b/chrome/browser/printing/print_job_worker.cc
index 33e17f0..2f43eab 100644
--- a/chrome/browser/printing/print_job_worker.cc
+++ b/chrome/browser/printing/print_job_worker.cc
@@ -222,8 +222,15 @@
         print_backend->GetPrinterDriverInfo(printer_name));
   }
 
-  PrintingContext::Result result =
-      printing_context_->UpdatePrintSettings(std::move(new_settings));
+  PrintingContext::Result result;
+  {
+#if defined(OS_WIN)
+    // Blocking is needed here because Windows printer drivers are oftentimes
+    // not thread-safe and have to be accessed on the UI thread.
+    base::ScopedAllowBlocking allow_blocking;
+#endif
+    result = printing_context_->UpdatePrintSettings(std::move(new_settings));
+  }
   GetSettingsDone(std::move(callback), result);
 }
 
diff --git a/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.cc b/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.cc
index 7aabf2a..bd788da 100644
--- a/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.cc
@@ -347,7 +347,9 @@
     TabManager::TabDiscardDoneCB tab_discard_done) {
   arc::ArcProcessService* arc_process_service = arc::ArcProcessService::Get();
   base::TimeTicks now = base::TimeTicks::Now();
-  if (arc_process_service) {
+  // ARCVM defers to Android's LMK to kill apps in low memory situations because
+  // memory can't be reclaimed directly to ChromeOS.
+  if (arc_process_service && !arc::IsArcVmEnabled()) {
     arc_process_service->RequestAppProcessList(base::BindOnce(
         &TabManagerDelegate::LowMemoryKillImpl, weak_ptr_factory_.GetWeakPtr(),
         now, reason, std::move(tab_discard_done)));
@@ -487,7 +489,8 @@
     return;
 
   arc::ArcProcessService* arc_process_service = arc::ArcProcessService::Get();
-  // TODO(b/135633925): Design and implement OOM handling for ARCVM.
+  // ARCVM defers to Android's LMK to manage low memory situations, so don't
+  // adjust OOM scores for VM processes.
   if (arc_process_service && !arc::IsArcVmEnabled()) {
     arc_process_service->RequestAppProcessList(
         base::BindOnce(&TabManagerDelegate::AdjustOomPrioritiesImpl,
diff --git a/chrome/browser/resources/chromeos/camera/src/js/device/constraints_preferrer.js b/chrome/browser/resources/chromeos/camera/src/js/device/constraints_preferrer.js
index 94bbc21..50cb9b6a 100644
--- a/chrome/browser/resources/chromeos/camera/src/js/device/constraints_preferrer.js
+++ b/chrome/browser/resources/chromeos/camera/src/js/device/constraints_preferrer.js
@@ -501,17 +501,26 @@
    * @private
    */
   pairCapturePreviewResolutions_(captureResolutions, previewResolutions) {
+    const toSupportedPreviewRatio = (r) => {
+      // Special aspect ratio mapping rule, see http://b/147986763.
+      if (r.width === 848 && r.height === 480) {
+        return (new Resolution(16, 9)).aspectRatio;
+      }
+      return r.aspectRatio;
+    };
     /** @type {!Object<string, !ResolutionList>} */
     const previewRatios = previewResolutions.reduce((rs, r) => {
-      rs[r.aspectRatio] = rs[r.aspectRatio] || [];
-      rs[r.aspectRatio].push(r);
+      const ratio = toSupportedPreviewRatio(r);
+      rs[ratio] = rs[ratio] || [];
+      rs[ratio].push(r);
       return rs;
     }, {});
     /** @type {!Object<string, !ResolutionList>} */
     const captureRatios = captureResolutions.reduce((rs, r) => {
-      if (r.aspectRatio in previewRatios) {
-        rs[r.aspectRatio] = rs[r.aspectRatio] || [];
-        rs[r.aspectRatio].push(r);
+      const ratio = toSupportedPreviewRatio(r);
+      if (ratio in previewRatios) {
+        rs[ratio] = rs[ratio] || [];
+        rs[ratio].push(r);
       }
       return rs;
     }, {});
diff --git a/chrome/browser/resources/settings/a11y_page/a11y_page.html b/chrome/browser/resources/settings/a11y_page/a11y_page.html
index 4f76468..fe60d86 100644
--- a/chrome/browser/resources/settings/a11y_page/a11y_page.html
+++ b/chrome/browser/resources/settings/a11y_page/a11y_page.html
@@ -48,27 +48,27 @@
             sub-label="$i18n{accessibleImageLabelsSubtitle}">
         </settings-toggle-button>
 </if>
+<if expr="not is_macosx and not chromeos">
+        <template is="dom-if" route-path="/captions">
+          <settings-subpage
+              associated-control="[[$$('#captions')]]"
+              page-title="$i18n{captionsTitle}">
+            <settings-captions prefs="{{prefs}}"></settings-captions>
+          </settings-subpage>
+        </template>
+</if>
+        <template is="dom-if" if="[[enableLiveCaption_]]">
+          <settings-toggle-button
+              pref="{{prefs.accessibility.captions.live_caption_enabled}}"
+              label="$i18n{captionsEnableLiveCaptionTitle}"
+              sub-label="$i18n{captionsEnableLiveCaptionSubtitle}">
+          </settings-toggle-button>
+        </template>
         <cr-link-row class="hr" label="$i18n{moreFeaturesLink}"
             on-click="onMoreFeaturesLinkClick_" sub-label="$i18n{a11yWebStore}"
             external>
         </cr-link-row>
       </div>
-<if expr="not is_macosx and not chromeos">
-      <template is="dom-if" route-path="/captions">
-        <settings-subpage
-            associated-control="[[$$('#captions')]]"
-            page-title="$i18n{captionsTitle}">
-          <settings-captions prefs="{{prefs}}"></settings-captions>
-        </settings-subpage>
-      </template>
-      <template is="dom-if" if="[[enableLiveCaption_]]">
-        <settings-toggle-button
-            pref="{{prefs.accessibility.captions.live_caption_enabled}}"
-            label="$i18n{captionsEnableLiveCaptionTitle}"
-            sub-label="$i18n{captionsEnableLiveCaptionSubtitle}">
-        </settings-toggle-button>
-      </template>
-</if>
     </settings-animated-pages>
   </template>
   <script src="a11y_page.js"></script>
diff --git a/chrome/browser/resources/settings/chromeos/crostini_page/crostini_subpage.html b/chrome/browser/resources/settings/chromeos/crostini_page/crostini_subpage.html
index d9d92cf..0c7dc4c 100644
--- a/chrome/browser/resources/settings/chromeos/crostini_page/crostini_subpage.html
+++ b/chrome/browser/resources/settings/chromeos/crostini_page/crostini_subpage.html
@@ -80,12 +80,13 @@
     </template>
     <template is="dom-if" if="[[showCrostiniDiskResize_]]">
       <div class="settings-box hr" id="crostini-disk-resize">
-        <div class="start">
+        <div class="start" aria-hidden="true">
           $i18n{crostiniDiskResizeLabel}
         </div>
         <cr-button on-click="onDiskResizeClick_"
-            aria-labelledby="diskResizeLabel" id="showDiskResizeButton">
-            $i18n{crostiniDiskResizeShowButton}
+            aria-label="$i18n{crostiniDiskResizeShowButtonAriaLabel}"
+            id="showDiskResizeButton">
+          $i18n{crostiniDiskResizeShowButton}
         </cr-button>
       </div>
       <template is="dom-if" if="[[showDiskResizeDialog_]]" restamp>
diff --git a/chrome/browser/resources/settings/metrics_browser_proxy.js b/chrome/browser/resources/settings/metrics_browser_proxy.js
index 86f22be..a3a67599 100644
--- a/chrome/browser/resources/settings/metrics_browser_proxy.js
+++ b/chrome/browser/resources/settings/metrics_browser_proxy.js
@@ -39,12 +39,12 @@
    * These values are persisted to logs. Entries should not be renumbered and
    * numeric values should never be reused.
    *
-   * Must be kept in sync with the SafetyCheckElementInteractions enum in
+   * Must be kept in sync with the SafetyCheckInteractions enum in
    * histograms/enums.xml
    * @enum {number}
    */
-  /* #export */ const SafetyCheckElementInteractions = {
-    SAFETY_CHECK_STARTED: 0,
+  /* #export */ const SafetyCheckInteractions = {
+    SAFETY_CHECK_START: 0,
     SAFETY_CHECK_UPDATES_RELAUNCH: 1,
     SAFETY_CHECK_PASSWORDS_MANAGE: 2,
     SAFETY_CHECK_SAFE_BROWSING_MANAGE: 3,
@@ -64,10 +64,10 @@
 
     /**
      * Helper function that calls recordHistogram for the
-     * SettingsPage.SafetyCheckElementInteractions histogram
-     * @param {!settings.SafetyCheckElementInteractions} interaction
+     * Settings.SafetyCheck.Interactions histogram
+     * @param {!settings.SafetyCheckInteractions} interaction
      */
-    recordSafetyCheckPageHistogram(interaction) {}
+    recordSafetyCheckInteractionHistogram(interaction) {}
 
     /**
      * Helper function that calls recordHistogram for the
@@ -87,10 +87,10 @@
     }
 
     /** @override*/
-    recordSafetyCheckPageHistogram(interaction) {
+    recordSafetyCheckInteractionHistogram(interaction) {
       chrome.send('metricsHandler:recordInHistogram', [
-        'SettingsPage.SafetyCheckElementInteractions', interaction,
-        settings.SafetyCheckElementInteractions.COUNT
+        'Settings.SafetyCheck.Interactions', interaction,
+        settings.SafetyCheckInteractions.COUNT
       ]);
     }
 
@@ -110,6 +110,6 @@
     MetricsBrowserProxy,
     MetricsBrowserProxyImpl,
     PrivacyElementInteractions,
-    SafetyCheckElementInteractions,
+    SafetyCheckInteractions,
   };
 });
diff --git a/chrome/browser/resources/settings/privacy_page/cookies_page.html b/chrome/browser/resources/settings/privacy_page/cookies_page.html
index 412fab2..9f860f51 100644
--- a/chrome/browser/resources/settings/privacy_page/cookies_page.html
+++ b/chrome/browser/resources/settings/privacy_page/cookies_page.html
@@ -164,9 +164,9 @@
     </settings-do-not-track-toggle>
     <settings-toggle-button id="networkPrediction"
         hidden="[[!pageVisibility.networkPrediction]]"
-        pref="{{prefs.net.network_prediction_options}}"
         label="$i18n{networkPredictionEnabled}"
-        sub-label="$i18n{networkPredictionEnabledDesc}"
+        sub-label="$i18n{networkPredictionEnabledDescCookiesPage}"
+        pref="{{prefs.net.network_prediction_options}}"
         numeric-unchecked-value="[[networkPredictionUncheckedValue_]]"
         on-settings-boolean-control-change="onNetworkPredictionChange_">
     </settings-toggle-button>
diff --git a/chrome/browser/resources/settings/safety_check_page/BUILD.gn b/chrome/browser/resources/settings/safety_check_page/BUILD.gn
index e0b26ce3..539f64f 100644
--- a/chrome/browser/resources/settings/safety_check_page/BUILD.gn
+++ b/chrome/browser/resources/settings/safety_check_page/BUILD.gn
@@ -90,7 +90,7 @@
                    "chrome/browser/resources/settings/autofill_page/password_manager_proxy.html|PasswordManagerImpl,PasswordManagerProxy",
                    "chrome/browser/resources/settings/lifetime_browser_proxy.html|LifetimeBrowserProxy,LifetimeBrowserProxyImpl",
                    "chrome/browser/resources/settings/hats_browser_proxy.html|HatsBrowserProxyImpl",
-                   "chrome/browser/resources/settings/metrics_browser_proxy.html|SafetyCheckElementInteractions,MetricsBrowserProxy,MetricsBrowserProxyImpl",
+                   "chrome/browser/resources/settings/metrics_browser_proxy.html|SafetyCheckInteractions,MetricsBrowserProxy,MetricsBrowserProxyImpl",
                    "chrome/browser/resources/settings/open_window_proxy.html|OpenWindowProxyImpl",
                    "chrome/browser/resources/settings/safety_check_page/safety_check_browser_proxy.html|SafetyCheckBrowserProxy,SafetyCheckBrowserProxyImpl,SafetyCheckExtensionsStatus,SafetyCheckPasswordsStatus,SafetyCheckUpdatesStatus,SafetyCheckSafeBrowsingStatus,SafetyCheckCallbackConstants",
                    "ui/webui/resources/html/assert.html|assertNotReached",
diff --git a/chrome/browser/resources/settings/safety_check_page/safety_check_page.js b/chrome/browser/resources/settings/safety_check_page/safety_check_page.js
index a779075..fe8c0f1 100644
--- a/chrome/browser/resources/settings/safety_check_page/safety_check_page.js
+++ b/chrome/browser/resources/settings/safety_check_page/safety_check_page.js
@@ -202,6 +202,11 @@
    * @private
    */
   runSafetyCheck_: function() {
+    // Log click both in action and histogram.
+    this.metricsBrowserProxy_.recordSafetyCheckInteractionHistogram(
+        settings.SafetyCheckInteractions.SAFETY_CHECK_START);
+    this.metricsBrowserProxy_.recordAction('Settings.SafetyCheck.Start');
+
     // Update UI.
     this.parentDisplayString_ = this.i18n('safetyCheckRunning');
     this.parentStatus_ = ParentStatus.CHECKING;
@@ -429,9 +434,10 @@
   /** @private */
   onSafetyCheckUpdatesButtonClick_: function() {
     // Log click both in action and histogram.
-    this.metricsBrowserProxy_.recordSafetyCheckPageHistogram(
-        settings.SafetyCheckElementInteractions.SAFETY_CHECK_UPDATES_RELAUNCH);
-    this.metricsBrowserProxy_.recordAction('SafetyCheck.Updates.Relaunch');
+    this.metricsBrowserProxy_.recordSafetyCheckInteractionHistogram(
+        settings.SafetyCheckInteractions.SAFETY_CHECK_UPDATES_RELAUNCH);
+    this.metricsBrowserProxy_.recordAction(
+        'Settings.SafetyCheck.RelaunchAfterUpdates');
 
     this.lifetimeBrowserProxy_.relaunch();
   },
@@ -557,9 +563,10 @@
   /** @private */
   onPasswordsButtonClick_: function() {
     // Log click both in action and histogram.
-    this.metricsBrowserProxy_.recordSafetyCheckPageHistogram(
-        settings.SafetyCheckElementInteractions.SAFETY_CHECK_PASSWORDS_MANAGE);
-    this.metricsBrowserProxy_.recordAction('SafetyCheck.Passwords.Manage');
+    this.metricsBrowserProxy_.recordSafetyCheckInteractionHistogram(
+        settings.SafetyCheckInteractions.SAFETY_CHECK_PASSWORDS_MANAGE);
+    this.metricsBrowserProxy_.recordAction(
+        'Settings.SafetyCheck.ManagePasswords');
 
     settings.Router.getInstance().navigateTo(settings.routes.CHECK_PASSWORDS);
     PasswordManagerImpl.getInstance().recordPasswordCheckReferrer(
@@ -652,10 +659,10 @@
   /** @private */
   onSafeBrowsingButtonClick_: function() {
     // Log click both in action and histogram.
-    this.metricsBrowserProxy_.recordSafetyCheckPageHistogram(
-        settings.SafetyCheckElementInteractions
-            .SAFETY_CHECK_SAFE_BROWSING_MANAGE);
-    this.metricsBrowserProxy_.recordAction('SafetyCheck.SafeBrowsing.Manage');
+    this.metricsBrowserProxy_.recordSafetyCheckInteractionHistogram(
+        settings.SafetyCheckInteractions.SAFETY_CHECK_SAFE_BROWSING_MANAGE);
+    this.metricsBrowserProxy_.recordAction(
+        'Settings.SafetyCheck.ManageSafeBrowsing');
 
     settings.Router.getInstance().navigateTo(settings.routes.SECURITY);
   },
@@ -689,9 +696,10 @@
   /** @private */
   onSafetyCheckExtensionsButtonClick_: function() {
     // Log click both in action and histogram.
-    this.metricsBrowserProxy_.recordSafetyCheckPageHistogram(
-        settings.SafetyCheckElementInteractions.SAFETY_CHECK_EXTENSIONS_REVIEW);
-    this.metricsBrowserProxy_.recordAction('SafetyCheck.Extensions.Review');
+    this.metricsBrowserProxy_.recordSafetyCheckInteractionHistogram(
+        settings.SafetyCheckInteractions.SAFETY_CHECK_EXTENSIONS_REVIEW);
+    this.metricsBrowserProxy_.recordAction(
+        'Settings.SafetyCheck.ReviewExtensions');
 
     settings.OpenWindowProxyImpl.getInstance().openURL('chrome://extensions');
   },
diff --git a/chrome/browser/resources/settings/settings.gni b/chrome/browser/resources/settings/settings.gni
index aa901400..e3ba931f 100644
--- a/chrome/browser/resources/settings/settings.gni
+++ b/chrome/browser/resources/settings/settings.gni
@@ -73,7 +73,7 @@
   "settings.routes|routes",
   "settings.SafeBrowsingBrowserProxy|SafeBrowsingBrowserProxy",
   "settings.SafeBrowsingRadioManagedState|SafeBrowsingRadioManagedState",
-  "settings.SafetyCheckElementInteractions|SafetyCheckElementInteractions",
+  "settings.SafetyCheckInteractions|SafetyCheckInteractions",
   "settings.SearchEnginesBrowserProxy|SearchEnginesBrowserProxy",
   "settings.SearchRequest|SearchRequest",
   "settings.SearchResult|SearchResult",
diff --git a/chrome/browser/resources/settings/settings.js b/chrome/browser/resources/settings/settings.js
index 79840efe..6081f77f 100644
--- a/chrome/browser/resources/settings/settings.js
+++ b/chrome/browser/resources/settings/settings.js
@@ -20,7 +20,7 @@
 export {getSearchManager, SearchRequest, setSearchManagerForTesting} from './search_settings.m.js';
 export {HatsBrowserProxyImpl} from './hats_browser_proxy.m.js';
 export {LifetimeBrowserProxyImpl} from './lifetime_browser_proxy.m.js';
-export {MetricsBrowserProxyImpl, PrivacyElementInteractions, SafetyCheckElementInteractions} from './metrics_browser_proxy.m.js';
+export {MetricsBrowserProxyImpl, PrivacyElementInteractions, SafetyCheckInteractions} from './metrics_browser_proxy.m.js';
 export {OnStartupBrowserProxy, OnStartupBrowserProxyImpl} from './on_startup_page/on_startup_browser_proxy.m.js';
 export {EDIT_STARTUP_URL_EVENT} from './on_startup_page/startup_url_entry.m.js';
 export {StartupUrlsPageBrowserProxy, StartupUrlsPageBrowserProxyImpl} from './on_startup_page/startup_urls_page_browser_proxy.m.js';
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
index 1b2e4e9..ef10dac7 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
@@ -10,6 +10,7 @@
 
 #include "base/feature_list.h"
 #include "base/lazy_instance.h"
+#include "base/metrics/histogram_macros.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/interstitials/enterprise_util.h"
@@ -246,6 +247,8 @@
     const GURL& main_frame_url,
     const UnsafeResource& unsafe_resource,
     bool should_trigger_reporting) {
+  UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.BlockingPage.ResourceType",
+                            unsafe_resource.resource_type);
   const UnsafeResourceList resources{unsafe_resource};
   // Set up the factory if this has not been done already (tests do that
   // before this method is called).
diff --git a/chrome/browser/signin/chromeos_mirror_account_consistency_browsertest.cc b/chrome/browser/signin/chromeos_mirror_account_consistency_browsertest.cc
index e36b93c..8504a6b 100644
--- a/chrome/browser/signin/chromeos_mirror_account_consistency_browsertest.cc
+++ b/chrome/browser/signin/chromeos_mirror_account_consistency_browsertest.cc
@@ -4,7 +4,7 @@
 
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/chromeos/login/login_manager_test.h"
-#include "chrome/browser/chromeos/login/startup_utils.h"
+#include "chrome/browser/chromeos/login/test/login_manager_mixin.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/prefs/incognito_mode_prefs.h"
 #include "chrome/browser/profiles/profile.h"
@@ -35,8 +35,6 @@
 namespace {
 
 constexpr char kGaiaDomain[] = "accounts.google.com";
-constexpr char kUserEmail[] = "user@gmail.com";
-constexpr char kUserGaiaId[] = "1234567890";
 
 // Checks whether the "X-Chrome-Connected" header of a new request to Google
 // contains |expected_header_value|.
@@ -70,9 +68,10 @@
  protected:
   ~ChromeOsMirrorAccountConsistencyTest() override {}
 
-  ChromeOsMirrorAccountConsistencyTest()
-      : LoginManagerTest(false, true /* should_initialize_webui */),
-        account_id_(AccountId::FromUserEmailGaiaId(kUserEmail, kUserGaiaId)) {}
+  ChromeOsMirrorAccountConsistencyTest() : LoginManagerTest() {
+    login_mixin_.AppendRegularUsers(1);
+    account_id_ = login_mixin_.users()[0].account_id;
+  }
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
     chromeos::LoginManagerTest::SetUpCommandLine(command_line);
@@ -97,7 +96,8 @@
     chromeos::LoginManagerTest::SetUpOnMainThread();
   }
 
-  const AccountId account_id_;
+  AccountId account_id_;
+  chromeos::LoginManagerMixin login_mixin_{&mixin_host_};
 
  protected:
   std::unique_ptr<net::EmbeddedTestServer> test_server_;
@@ -106,12 +106,6 @@
   DISALLOW_COPY_AND_ASSIGN(ChromeOsMirrorAccountConsistencyTest);
 };
 
-IN_PROC_BROWSER_TEST_F(ChromeOsMirrorAccountConsistencyTest,
-                       PRE_TestMirrorRequestChromeOsChildAccount) {
-  RegisterUser(account_id_);
-  chromeos::StartupUtils::MarkOobeCompleted();
-}
-
 // Mirror is enabled for child accounts.
 IN_PROC_BROWSER_TEST_F(ChromeOsMirrorAccountConsistencyTest,
                        TestMirrorRequestChromeOsChildAccount) {
@@ -144,12 +138,6 @@
                               "consistency_enabled_by_default=false");
 }
 
-IN_PROC_BROWSER_TEST_F(ChromeOsMirrorAccountConsistencyTest,
-                       PRE_TestMirrorRequestChromeOsNotChildAccount) {
-  RegisterUser(account_id_);
-  chromeos::StartupUtils::MarkOobeCompleted();
-}
-
 // Mirror is enabled for non-child accounts.
 IN_PROC_BROWSER_TEST_F(ChromeOsMirrorAccountConsistencyTest,
                        TestMirrorRequestChromeOsNotChildAccount) {
diff --git a/chrome/browser/ui/app_list/chrome_app_list_model_updater_browsertest.cc b/chrome/browser/ui/app_list/chrome_app_list_model_updater_browsertest.cc
index 4a60446..b7563ef 100644
--- a/chrome/browser/ui/app_list/chrome_app_list_model_updater_browsertest.cc
+++ b/chrome/browser/ui/app_list/chrome_app_list_model_updater_browsertest.cc
@@ -7,7 +7,7 @@
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
 #include "chrome/browser/chromeos/login/login_manager_test.h"
-#include "chrome/browser/chromeos/login/startup_utils.h"
+#include "chrome/browser/chromeos/login/test/login_manager_mixin.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -24,17 +24,15 @@
 
 namespace {
 
-constexpr char kTestUser[] = "test-user@gmail.com";
-constexpr char kTestUserGaiaId[] = "1234567890";
 constexpr char kOemAppId[] = "emfkafnhnpcmabnnkckkchdilgeoekbo";
 
 }  // namespace
 
 class OemAppPositionTest : public chromeos::LoginManagerTest {
  public:
-  OemAppPositionTest()
-      : LoginManagerTest(true /* should_launch_browser */,
-                         true /* should_initialize_webui */) {}
+  OemAppPositionTest() : LoginManagerTest() {
+    login_mixin_.AppendRegularUsers(1);
+  }
   ~OemAppPositionTest() override = default;
 
   // LoginManagerTest:
@@ -43,8 +41,10 @@
     // from the test data directory to it.
     base::FilePath user_data_dir;
     base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
+    const std::string& email =
+        login_mixin_.users()[0].account_id.GetUserEmail();
     const std::string user_id_hash =
-        chromeos::ProfileHelper::GetUserIdHashByUserIdForTesting(kTestUser);
+        chromeos::ProfileHelper::GetUserIdHashByUserIdForTesting(email);
     const base::FilePath user_profile_path = user_data_dir.Append(
         chromeos::ProfileHelper::GetUserProfileDir(user_id_hash));
     base::CreateDirectory(user_profile_path);
@@ -60,19 +60,16 @@
     return true;
   }
 
+  chromeos::LoginManagerMixin login_mixin_{&mixin_host_};
+
  private:
   DISALLOW_COPY_AND_ASSIGN(OemAppPositionTest);
 };
 
-IN_PROC_BROWSER_TEST_F(OemAppPositionTest, PRE_ValidOemAppPosition) {
-  RegisterUser(AccountId::FromUserEmailGaiaId(kTestUser, kTestUserGaiaId));
-  chromeos::StartupUtils::MarkOobeCompleted();
-}
-
 // Tests that an Oem app and its folder are created with valid positions after
 // sign-in.
 IN_PROC_BROWSER_TEST_F(OemAppPositionTest, ValidOemAppPosition) {
-  LoginUser(AccountId::FromUserEmailGaiaId(kTestUser, kTestUserGaiaId));
+  LoginUser(login_mixin_.users()[0].account_id);
 
   // Ensure apps that are installed upon sign-in are registered with the App
   // Service, resolving any pending messages as a result of running async
diff --git a/chrome/browser/ui/ash/system_tray_client_browsertest.cc b/chrome/browser/ui/ash/system_tray_client_browsertest.cc
index e65fd01..1534905 100644
--- a/chrome/browser/ui/ash/system_tray_client_browsertest.cc
+++ b/chrome/browser/ui/ash/system_tray_client_browsertest.cc
@@ -7,7 +7,7 @@
 #include "ash/public/cpp/ash_view_ids.h"
 #include "ash/public/cpp/system_tray_test_api.h"
 #include "chrome/browser/chromeos/login/login_manager_test.h"
-#include "chrome/browser/chromeos/login/startup_utils.h"
+#include "chrome/browser/chromeos/login/test/login_manager_mixin.h"
 #include "chrome/browser/chromeos/login/ui/user_adding_screen.h"
 #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
@@ -51,14 +51,12 @@
 
 class SystemTrayClientClockTest : public chromeos::LoginManagerTest {
  public:
-  SystemTrayClientClockTest()
-      : LoginManagerTest(false /* should_launch_browser */,
-                         true /* should_initialize_webui */),
-        // Use consumer emails to avoid having to fake a policy fetch.
-        account_id1_(
-            AccountId::FromUserEmailGaiaId("user1@gmail.com", "1111111111")),
-        account_id2_(
-            AccountId::FromUserEmailGaiaId("user2@gmail.com", "2222222222")) {}
+  SystemTrayClientClockTest() : LoginManagerTest() {
+    // Use consumer emails to avoid having to fake a policy fetch.
+    login_mixin_.AppendRegularUsers(2);
+    account_id1_ = login_mixin_.users()[0].account_id;
+    account_id2_ = login_mixin_.users()[1].account_id;
+  }
 
   ~SystemTrayClientClockTest() override = default;
 
@@ -71,20 +69,14 @@
   }
 
  protected:
-  const AccountId account_id1_;
-  const AccountId account_id2_;
+  AccountId account_id1_;
+  AccountId account_id2_;
+  chromeos::LoginManagerMixin login_mixin_{&mixin_host_};
 
  private:
   DISALLOW_COPY_AND_ASSIGN(SystemTrayClientClockTest);
 };
 
-IN_PROC_BROWSER_TEST_F(SystemTrayClientClockTest,
-                       PRE_TestMultiProfile24HourClock) {
-  RegisterUser(account_id1_);
-  RegisterUser(account_id2_);
-  chromeos::StartupUtils::MarkOobeCompleted();
-}
-
 // Test that clock type is taken from user profile for current active user.
 IN_PROC_BROWSER_TEST_F(SystemTrayClientClockTest, TestMultiProfile24HourClock) {
   auto tray_test_api = ash::SystemTrayTestApi::Create();
diff --git a/chrome/browser/ui/ui_features.cc b/chrome/browser/ui/ui_features.cc
index efadfee..06d8bd8d 100644
--- a/chrome/browser/ui/ui_features.cc
+++ b/chrome/browser/ui/ui_features.cc
@@ -90,6 +90,11 @@
 const base::Feature kWebUITabStripDemoOptions{
     "WebUITabStripDemoOptions", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Makes chrome://settings serve the Polymer 3 version of that page.
+// https://crbug.com/1026426.
+const base::Feature kSettingsPolymer3{"SettingsPolymer3",
+                                      base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enables friendly settings for the |chrome://settings/syncSetup| page.
 // https://crbug.com/1035421.
 const base::Feature kSyncSetupFriendlySettings{
diff --git a/chrome/browser/ui/ui_features.h b/chrome/browser/ui/ui_features.h
index 434d4c1..b3696ff 100644
--- a/chrome/browser/ui/ui_features.h
+++ b/chrome/browser/ui/ui_features.h
@@ -50,6 +50,8 @@
 
 extern const base::Feature kWebUITabStripDemoOptions;
 
+extern const base::Feature kSettingsPolymer3;
+
 extern const base::Feature kSyncSetupFriendlySettings;
 
 #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/ui/views/frame/system_menu_model_builder_browsertest_chromeos.cc b/chrome/browser/ui/views/frame/system_menu_model_builder_browsertest_chromeos.cc
index 91d46b5..6cdd2e8 100644
--- a/chrome/browser/ui/views/frame/system_menu_model_builder_browsertest_chromeos.cc
+++ b/chrome/browser/ui/views/frame/system_menu_model_builder_browsertest_chromeos.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/chromeos/login/login_manager_test.h"
-#include "chrome/browser/chromeos/login/startup_utils.h"
+#include "chrome/browser/chromeos/login/test/login_manager_mixin.h"
 #include "chrome/browser/chromeos/login/ui/user_adding_screen.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/ui/settings_window_manager_chromeos.h"
@@ -28,13 +28,11 @@
     : public chromeos::LoginManagerTest,
       public SettingsWindowManagerObserver {
  public:
-  SystemMenuModelBuilderMultiUserTest()
-      : LoginManagerTest(/*should_launch_browser=*/false,
-                         /*should_initialize_webui=*/false),
-        account_id1_(
-            AccountId::FromUserEmailGaiaId("user1@gmail.com", "1111111111")),
-        account_id2_(
-            AccountId::FromUserEmailGaiaId("user2@gmail.com", "2222222222")) {}
+  SystemMenuModelBuilderMultiUserTest() : LoginManagerTest() {
+    login_mixin_.AppendRegularUsers(2);
+    account_id1_ = login_mixin_.users()[0].account_id;
+    account_id2_ = login_mixin_.users()[1].account_id;
+  }
   ~SystemMenuModelBuilderMultiUserTest() override = default;
 
   // SettingsWindowManagerObserver:
@@ -43,18 +41,12 @@
   }
 
  protected:
-  const AccountId account_id1_;
-  const AccountId account_id2_;
+  AccountId account_id1_;
+  AccountId account_id2_;
+  chromeos::LoginManagerMixin login_mixin_{&mixin_host_};
   Browser* settings_browser_ = nullptr;
 };
 
-IN_PROC_BROWSER_TEST_F(SystemMenuModelBuilderMultiUserTest,
-                       PRE_MultiUserSettingsWindowFrameMenu) {
-  RegisterUser(account_id1_);
-  RegisterUser(account_id2_);
-  chromeos::StartupUtils::MarkOobeCompleted();
-}
-
 // Regression test for https://crbug.com/1023043
 IN_PROC_BROWSER_TEST_F(SystemMenuModelBuilderMultiUserTest,
                        MultiUserSettingsWindowFrameMenu) {
diff --git a/chrome/browser/ui/views/session_crashed_bubble_view_browsertest.cc b/chrome/browser/ui/views/session_crashed_bubble_view_browsertest.cc
index fcf0343..8a55865 100644
--- a/chrome/browser/ui/views/session_crashed_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/session_crashed_bubble_view_browsertest.cc
@@ -6,6 +6,7 @@
 
 #include <string>
 
+#include "build/build_config.h"
 #include "build/buildflag.h"
 #include "chrome/browser/ui/bubble_anchor_util.h"
 #include "chrome/browser/ui/test/test_browser_dialog.h"
@@ -14,6 +15,7 @@
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "ui/base/buildflags.h"
+#include "ui/views/focus/focus_manager.h"
 #include "ui/views/view.h"
 
 class SessionCrashedBubbleViewTest : public DialogBrowserTest {
@@ -29,12 +31,28 @@
                         ->toolbar_button_provider()
                         ->GetAppMenuButton();
     }
-    SessionCrashedBubbleView* crash_bubble =
+    crash_bubble_ =
         new SessionCrashedBubbleView(anchor_view, anchor_rect, browser(),
                                      name == "SessionCrashedBubbleOfferUma");
-    views::BubbleDialogDelegateView::CreateBubble(crash_bubble)->Show();
+    views::BubbleDialogDelegateView::CreateBubble(crash_bubble_)->Show();
   }
 
+  void SimulateKeyPress(ui::KeyboardCode key, ui::EventFlags flags) {
+    BrowserView* browser_view =
+        BrowserView::GetBrowserViewForBrowser(browser());
+
+    ui::KeyEvent press_event(ui::ET_KEY_PRESSED, key, flags);
+    if (browser_view->GetFocusManager()->OnKeyEvent(press_event))
+      browser_view->OnKeyEvent(&press_event);
+
+    ui::KeyEvent release_event(ui::ET_KEY_RELEASED, key, flags);
+    if (browser_view->GetFocusManager()->OnKeyEvent(release_event))
+      browser_view->OnKeyEvent(&release_event);
+  }
+
+ protected:
+  SessionCrashedBubbleView* crash_bubble_;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(SessionCrashedBubbleViewTest);
 };
@@ -48,3 +66,40 @@
                        InvokeUi_SessionCrashedBubbleOfferUma) {
   ShowAndVerifyUi();
 }
+
+#if defined(OS_LINUX)
+// Regression test for https://crbug.com/1042010, it should be possible to focus
+// the bubble with the "focus dialog" hotkey combination (Alt+Shift+A).
+IN_PROC_BROWSER_TEST_F(SessionCrashedBubbleViewTest,
+                       CanFocusBubbleWithFocusDialogHotkey) {
+  ShowUi("SessionCrashedBubble");
+
+  views::FocusManager* focus_manager = crash_bubble_->GetFocusManager();
+  views::View* bubble_focused_view = crash_bubble_->GetInitiallyFocusedView();
+
+  focus_manager->ClearFocus();
+  EXPECT_FALSE(bubble_focused_view->HasFocus());
+
+  SimulateKeyPress(ui::VKEY_A, static_cast<ui::EventFlags>(ui::EF_ALT_DOWN |
+                                                           ui::EF_SHIFT_DOWN));
+  EXPECT_TRUE(bubble_focused_view->HasFocus());
+}
+
+// Regression test for https://crbug.com/1042010, it should be possible to focus
+// the bubble with the "rotate pane focus" (F6) hotkey.
+IN_PROC_BROWSER_TEST_F(SessionCrashedBubbleViewTest,
+                       CanFocusBubbleWithRotatePaneFocusHotkey) {
+  ShowUi("SessionCrashedBubble");
+  views::FocusManager* focus_manager = crash_bubble_->GetFocusManager();
+  views::View* bubble_focused_view = crash_bubble_->GetInitiallyFocusedView();
+
+  focus_manager->ClearFocus();
+  EXPECT_FALSE(bubble_focused_view->HasFocus());
+
+  SimulateKeyPress(ui::VKEY_F6, ui::EF_NONE);
+  // Rotate pane focus is expected to keep the bubble focused until the user
+  // deals with it, so a second call should have no effect.
+  SimulateKeyPress(ui::VKEY_F6, ui::EF_NONE);
+  EXPECT_TRUE(bubble_focused_view->HasFocus());
+}
+#endif
diff --git a/chrome/browser/ui/views/toolbar/toolbar_button_interactive_uitest.cc b/chrome/browser/ui/views/toolbar/toolbar_button_interactive_uitest.cc
deleted file mode 100644
index 5184b275..0000000
--- a/chrome/browser/ui/views/toolbar/toolbar_button_interactive_uitest.cc
+++ /dev/null
@@ -1,144 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/views/toolbar/toolbar_button.h"
-
-#include "chrome/browser/ui/layout_constants.h"
-#include "chrome/browser/ui/views/test/view_event_test_base.h"
-#include "ui/base/models/simple_menu_model.h"
-#include "ui/views/controls/menu/menu_runner.h"
-#include "ui/views/view_class_properties.h"
-
-namespace test {
-
-// Friend of ToolbarButton to access private members.
-class ToolbarButtonTestApi {
- public:
-  explicit ToolbarButtonTestApi(ToolbarButton* button) : button_(button) {}
-  ToolbarButtonTestApi(const ToolbarButtonTestApi&) = delete;
-  ToolbarButtonTestApi& operator=(const ToolbarButtonTestApi&) = delete;
-
-  views::MenuRunner* menu_runner() { return button_->menu_runner_.get(); }
-  bool menu_showing() const { return button_->menu_showing_; }
-  const gfx::Insets last_paint_insets() const {
-    return button_->last_paint_insets_;
-  }
-  const gfx::Insets layout_inset_delta() const {
-    return button_->layout_inset_delta_;
-  }
-  const base::Optional<SkColor> last_border_color() const {
-    return button_->last_border_color_;
-  }
-  void SetAnimationTimingForTesting() {
-    button_->highlight_color_animation_.highlight_color_animation_
-        .SetSlideDuration(base::TimeDelta());
-  }
-
- private:
-  ToolbarButton* button_;
-};
-
-}  // namespace test
-
-class TestToolbarButton : public ToolbarButton {
- public:
-  using ToolbarButton::ToolbarButton;
-
-  void ResetBorderUpdateFlag() { did_border_update_ = false; }
-  bool did_border_update() const { return did_border_update_; }
-
-  // views::ToolbarButton
-  void SetBorder(std::unique_ptr<views::Border> b) override {
-    ToolbarButton::SetBorder(std::move(b));
-    did_border_update_ = true;
-  }
-
- private:
-  bool did_border_update_ = false;
-};
-
-class ToolbarButtonUITest : public ViewEventTestBase {
- public:
-  ToolbarButtonUITest() = default;
-  ToolbarButtonUITest(const ToolbarButtonUITest&) = delete;
-  ToolbarButtonUITest& operator=(const ToolbarButtonUITest&) = delete;
-
-  // ViewEventTestBase:
-  views::View* CreateContentsView() override {
-    // Usually a BackForwardMenuModel is used, but that needs a Browser*. Make
-    // something simple with at least one item so a menu gets shown. Note that
-    // ToolbarButton takes ownership of the |model|.
-    auto model = std::make_unique<ui::SimpleMenuModel>(nullptr);
-    model->AddItem(0, base::string16());
-    button_ = new TestToolbarButton(nullptr, std::move(model), nullptr);
-    return button_;
-  }
-  void DoTestOnMessageLoop() override {}
-
- protected:
-  TestToolbarButton* button_ = nullptr;
-};
-
-// Test showing and dismissing a menu to verify menu delegate lifetime.
-TEST_F(ToolbarButtonUITest, ShowMenu) {
-  test::ToolbarButtonTestApi test_api(button_);
-
-  EXPECT_FALSE(test_api.menu_showing());
-  EXPECT_FALSE(test_api.menu_runner());
-  EXPECT_EQ(views::Button::STATE_NORMAL, button_->state());
-
-  // Show the menu. Note that it is asynchronous.
-  button_->ShowContextMenuForView(nullptr, gfx::Point(), ui::MENU_SOURCE_MOUSE);
-
-  EXPECT_TRUE(test_api.menu_showing());
-  EXPECT_TRUE(test_api.menu_runner());
-  EXPECT_TRUE(test_api.menu_runner()->IsRunning());
-
-  // Button should appear pressed when the menu is showing.
-  EXPECT_EQ(views::Button::STATE_PRESSED, button_->state());
-
-  test_api.menu_runner()->Cancel();
-
-  // Ensure the ToolbarButton's |menu_runner_| member is reset to null.
-  EXPECT_FALSE(test_api.menu_showing());
-  EXPECT_FALSE(test_api.menu_runner());
-  EXPECT_EQ(views::Button::STATE_NORMAL, button_->state());
-}
-
-// Test deleting a ToolbarButton while its menu is showing.
-TEST_F(ToolbarButtonUITest, DeleteWithMenu) {
-  button_->ShowContextMenuForView(nullptr, gfx::Point(), ui::MENU_SOURCE_MOUSE);
-  EXPECT_TRUE(test::ToolbarButtonTestApi(button_).menu_runner());
-  delete button_;
-}
-
-// Tests to make sure the button's border is updated as its height changes.
-TEST_F(ToolbarButtonUITest, TestBorderUpdateHeightChange) {
-  const gfx::Insets toolbar_padding = GetLayoutInsets(TOOLBAR_BUTTON);
-
-  button_->ResetBorderUpdateFlag();
-  for (int bounds_height : {8, 12, 20}) {
-    EXPECT_FALSE(button_->did_border_update());
-    button_->SetBoundsRect({bounds_height, bounds_height});
-    EXPECT_TRUE(button_->did_border_update());
-    EXPECT_EQ(button_->border()->GetInsets(), gfx::Insets(toolbar_padding));
-    button_->ResetBorderUpdateFlag();
-  }
-}
-
-// Tests to make sure the button's border color is updated as its animation
-// color changes.
-TEST_F(ToolbarButtonUITest, TestBorderUpdateColorChange) {
-  test::ToolbarButtonTestApi test_api(button_);
-  test_api.SetAnimationTimingForTesting();
-
-  button_->ResetBorderUpdateFlag();
-  for (SkColor border_color : {SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE}) {
-    EXPECT_FALSE(button_->did_border_update());
-    button_->SetHighlight(base::string16(), border_color);
-    EXPECT_EQ(button_->border()->color(), border_color);
-    EXPECT_TRUE(button_->did_border_update());
-    button_->ResetBorderUpdateFlag();
-  }
-}
diff --git a/chrome/browser/ui/views/toolbar/toolbar_button_unittest.cc b/chrome/browser/ui/views/toolbar/toolbar_button_unittest.cc
index deb0d387..bbc03db 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_button_unittest.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_button_unittest.cc
@@ -6,20 +6,53 @@
 
 #include <utility>
 
+#include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/test_tab_strip_model_delegate.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/views/chrome_views_test_base.h"
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/models/menu_model.h"
+#include "ui/base/models/simple_menu_model.h"
+#include "ui/views/controls/menu/menu_runner.h"
+
+namespace test {
+
+// Friend of ToolbarButton to access private members.
+class ToolbarButtonTestApi {
+ public:
+  explicit ToolbarButtonTestApi(ToolbarButton* button) : button_(button) {}
+  ToolbarButtonTestApi(const ToolbarButtonTestApi&) = delete;
+  ToolbarButtonTestApi& operator=(const ToolbarButtonTestApi&) = delete;
+
+  views::MenuRunner* menu_runner() { return button_->menu_runner_.get(); }
+  bool menu_showing() const { return button_->menu_showing_; }
+  const gfx::Insets last_paint_insets() const {
+    return button_->last_paint_insets_;
+  }
+  const gfx::Insets layout_inset_delta() const {
+    return button_->layout_inset_delta_;
+  }
+  const base::Optional<SkColor> last_border_color() const {
+    return button_->last_border_color_;
+  }
+  void SetAnimationTimingForTesting() {
+    button_->highlight_color_animation_.highlight_color_animation_
+        .SetSlideDuration(base::TimeDelta());
+  }
+
+ private:
+  ToolbarButton* button_;
+};
+
+}  // namespace test
 
 namespace {
 
-class CheckActiveWebContentsMenuModel : public ui::MenuModel {
+class CheckActiveWebContentsMenuModel : public ui::SimpleMenuModel {
  public:
   explicit CheckActiveWebContentsMenuModel(TabStripModel* tab_strip_model)
-      : tab_strip_model_(tab_strip_model) {
+      : SimpleMenuModel(nullptr), tab_strip_model_(tab_strip_model) {
     DCHECK(tab_strip_model_);
   }
   CheckActiveWebContentsMenuModel(const CheckActiveWebContentsMenuModel&) =
@@ -28,82 +61,50 @@
       const CheckActiveWebContentsMenuModel&) = delete;
   ~CheckActiveWebContentsMenuModel() override = default;
 
-  // ui::MenuModel:
-  bool HasIcons() const override { return false; }
+  // ui::SimpleMenuModel:
   int GetItemCount() const override {
     EXPECT_TRUE(tab_strip_model_->GetActiveWebContents());
     return 0;
   }
-  ItemType GetTypeAt(int index) const override { return TYPE_COMMAND; }
-  int GetCommandIdAt(int index) const override { return 0; }
-  base::string16 GetLabelAt(int index) const override {
-    return base::string16();
-  }
-  bool IsItemDynamicAt(int index) const override { return false; }
-  bool GetAcceleratorAt(int index,
-                        ui::Accelerator* accelerator) const override {
-    return false;
-  }
-  ui::MenuSeparatorType GetSeparatorTypeAt(int index) const override {
-    return ui::NORMAL_SEPARATOR;
-  }
-  bool IsItemCheckedAt(int index) const override { return false; }
-  int GetGroupIdAt(int index) const override { return 0; }
-  bool GetIconAt(int index, gfx::Image* icon) const override { return false; }
-  ui::ButtonMenuItemModel* GetButtonMenuItemAt(int index) const override {
-    return nullptr;
-  }
-  bool IsEnabledAt(int index) const override { return false; }
-  ui::MenuModel* GetSubmenuModelAt(int index) const override { return nullptr; }
-  void ActivatedAt(int index) override {}
 
  private:
   TabStripModel* const tab_strip_model_;
 };
 
-class TestParentView : public views::View {
+class TestToolbarButton : public ToolbarButton {
  public:
-  explicit TestParentView(gfx::NativeWindow context) {
-    views::Widget::InitParams params;
-    params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
-    params.context = context;
-    widget_ = std::make_unique<views::Widget>();
-    widget_->Init(std::move(params));
-  }
-  TestParentView(const TestParentView&) = delete;
-  TestParentView& operator=(const TestParentView&) = delete;
-  ~TestParentView() override = default;
+  using ToolbarButton::ToolbarButton;
 
-  views::Widget* GetWidget() override { return widget_.get(); }
-  const views::Widget* GetWidget() const override { return widget_.get(); }
+  void ResetBorderUpdateFlag() { did_border_update_ = false; }
+  bool did_border_update() const { return did_border_update_; }
+
+  // ToolbarButton:
+  void SetBorder(std::unique_ptr<views::Border> b) override {
+    ToolbarButton::SetBorder(std::move(b));
+    did_border_update_ = true;
+  }
 
  private:
-  std::unique_ptr<views::Widget> widget_;
+  bool did_border_update_ = false;
 };
 
 }  // namespace
 
-class ToolbarButtonViewsTest : public ChromeViewsTestBase {
- public:
-  ToolbarButtonViewsTest() {}
-  ToolbarButtonViewsTest(const ToolbarButtonViewsTest&) = delete;
-  ToolbarButtonViewsTest& operator=(const ToolbarButtonViewsTest&) = delete;
-};
+using ToolbarButtonViewsTest = ChromeViewsTestBase;
 
 TEST_F(ToolbarButtonViewsTest, MenuDoesNotShowWhenTabStripIsEmpty) {
   TestTabStripModelDelegate delegate;
   TestingProfile profile;
   TabStripModel tab_strip(&delegate, &profile);
   EXPECT_FALSE(tab_strip.GetActiveWebContents());
-
   auto model = std::make_unique<CheckActiveWebContentsMenuModel>(&tab_strip);
-  ToolbarButton* button =
-      new ToolbarButton(nullptr, std::move(model), &tab_strip);
 
-  // ToolbarButton needs a parent view on some platforms. |parent_view| takes
-  // ownership of |button|.
-  TestParentView parent_view(GetContext());
-  parent_view.AddChildView(button);
+  // ToolbarButton needs a parent view on some platforms.
+  auto parent_view = std::make_unique<views::View>();
+  ToolbarButton* button = parent_view->AddChildView(
+      std::make_unique<ToolbarButton>(nullptr, std::move(model), &tab_strip));
+  std::unique_ptr<views::Widget> widget_ = CreateTestWidget();
+  widget_->SetContentsView(parent_view.release());
 
   // Since |tab_strip| is empty, calling this does not do anything. This is the
   // expected result. If it actually tries to show the menu, then
@@ -111,3 +112,102 @@
   // EXPECT_TRUE() call inside will fail.
   button->ShowContextMenuForView(nullptr, gfx::Point(), ui::MENU_SOURCE_MOUSE);
 }
+
+class ToolbarButtonUITest : public ChromeViewsTestBase {
+ public:
+  ToolbarButtonUITest() = default;
+  ToolbarButtonUITest(const ToolbarButtonUITest&) = delete;
+  ToolbarButtonUITest& operator=(const ToolbarButtonUITest&) = delete;
+
+  void SetUp() override {
+    ChromeViewsTestBase::SetUp();
+
+    // Usually a BackForwardMenuModel is used, but that needs a Browser*. Make
+    // something simple with at least one item so a menu gets shown. Note that
+    // ToolbarButton takes ownership of the |model|.
+    auto model = std::make_unique<ui::SimpleMenuModel>(nullptr);
+    model->AddItem(0, base::string16());
+    auto button =
+        std::make_unique<TestToolbarButton>(nullptr, std::move(model), nullptr);
+    button_ = button.get();
+
+    widget_ = CreateTestWidget();
+    widget_->SetContentsView(button.release());
+  }
+
+  void TearDown() override {
+    widget_.reset();
+    ChromeViewsTestBase::TearDown();
+  }
+
+  views::Widget* widget() { return widget_.get(); }
+
+ protected:
+  TestToolbarButton* button_ = nullptr;
+
+ private:
+  std::unique_ptr<views::Widget> widget_;
+};
+
+// Test showing and dismissing a menu to verify menu delegate lifetime.
+TEST_F(ToolbarButtonUITest, ShowMenu) {
+  test::ToolbarButtonTestApi test_api(button_);
+
+  EXPECT_FALSE(test_api.menu_showing());
+  EXPECT_FALSE(test_api.menu_runner());
+  EXPECT_EQ(views::Button::STATE_NORMAL, button_->state());
+
+  // Show the menu. Note that it is asynchronous.
+  button_->ShowContextMenuForView(nullptr, gfx::Point(), ui::MENU_SOURCE_MOUSE);
+
+  EXPECT_TRUE(test_api.menu_showing());
+  EXPECT_TRUE(test_api.menu_runner());
+  EXPECT_TRUE(test_api.menu_runner()->IsRunning());
+
+  // Button should appear pressed when the menu is showing.
+  EXPECT_EQ(views::Button::STATE_PRESSED, button_->state());
+
+  test_api.menu_runner()->Cancel();
+
+  // Ensure the ToolbarButton's |menu_runner_| member is reset to null.
+  EXPECT_FALSE(test_api.menu_showing());
+  EXPECT_FALSE(test_api.menu_runner());
+  EXPECT_EQ(views::Button::STATE_NORMAL, button_->state());
+}
+
+// Test deleting a ToolbarButton while its menu is showing.
+TEST_F(ToolbarButtonUITest, DeleteWithMenu) {
+  button_->ShowContextMenuForView(nullptr, gfx::Point(), ui::MENU_SOURCE_MOUSE);
+  EXPECT_TRUE(test::ToolbarButtonTestApi(button_).menu_runner());
+  widget()->SetContentsView(new views::View());  // Deletes |button_|.
+}
+
+// Tests to make sure the button's border is updated as its height changes.
+TEST_F(ToolbarButtonUITest, TestBorderUpdateHeightChange) {
+  const gfx::Insets toolbar_padding = GetLayoutInsets(TOOLBAR_BUTTON);
+
+  button_->ResetBorderUpdateFlag();
+  for (int bounds_height : {8, 12, 20}) {
+    EXPECT_FALSE(button_->did_border_update());
+    button_->SetBoundsRect({bounds_height, bounds_height});
+    EXPECT_TRUE(button_->did_border_update());
+    EXPECT_EQ(button_->border()->GetInsets(), gfx::Insets(toolbar_padding));
+    button_->ResetBorderUpdateFlag();
+  }
+}
+
+// Tests to make sure the button's border color is updated as its animation
+// color changes.
+TEST_F(ToolbarButtonUITest, TestBorderUpdateColorChange) {
+  test::ToolbarButtonTestApi test_api(button_);
+  test_api.SetAnimationTimingForTesting();
+
+  button_->ResetBorderUpdateFlag();
+  for (SkColor border_color : {SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE}) {
+    EXPECT_FALSE(button_->did_border_update());
+    button_->SetHighlight(base::string16(), border_color);
+    EXPECT_EQ(button_->border()->color(), border_color);
+    EXPECT_TRUE(button_->did_border_update());
+    button_->ResetBorderUpdateFlag();
+  }
+}
diff --git a/chrome/browser/ui/webui/chromeos/system_web_dialog_browsertest.cc b/chrome/browser/ui/webui/chromeos/system_web_dialog_browsertest.cc
index e90675f..baa9dcd 100644
--- a/chrome/browser/ui/webui/chromeos/system_web_dialog_browsertest.cc
+++ b/chrome/browser/ui/webui/chromeos/system_web_dialog_browsertest.cc
@@ -7,7 +7,8 @@
 #include "ash/public/cpp/test/shell_test_api.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/chromeos/login/login_manager_test.h"
-#include "chrome/browser/chromeos/login/startup_utils.h"
+#include "chrome/browser/chromeos/login/test/login_manager_mixin.h"
+#include "chrome/browser/chromeos/login/test/oobe_base_test.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/zoom/chrome_zoom_level_prefs.h"
@@ -30,9 +31,6 @@
 
 namespace {
 
-constexpr char kTestUser[] = "test-user@gmail.com";
-constexpr char kTestUserGaiaId[] = "1234567890";
-
 class MockSystemWebDialog : public SystemWebDialogDelegate {
  public:
   explicit MockSystemWebDialog(const char* id = nullptr)
@@ -55,29 +53,30 @@
 
 class SystemWebDialogLoginTest : public LoginManagerTest {
  public:
-  SystemWebDialogLoginTest()
-      : LoginManagerTest(false, true /* should_initialize_webui */) {}
+  SystemWebDialogLoginTest() : LoginManagerTest() {
+    login_mixin_.AppendRegularUsers(1);
+  }
   ~SystemWebDialogLoginTest() override = default;
 
+ protected:
+  LoginManagerMixin login_mixin_{&mixin_host_};
+
  private:
   DISALLOW_COPY_AND_ASSIGN(SystemWebDialogLoginTest);
 };
 
+using SystemWebDialogOobeTest = OobeBaseTest;
+
 // Verifies that system dialogs are modal before login (e.g. during OOBE).
-IN_PROC_BROWSER_TEST_F(SystemWebDialogLoginTest, ModalTest) {
+IN_PROC_BROWSER_TEST_F(SystemWebDialogOobeTest, ModalTest) {
   auto* dialog = new MockSystemWebDialog();
   dialog->ShowSystemDialog();
   EXPECT_TRUE(ash::ShellTestApi().IsSystemModalWindowOpen());
 }
 
-IN_PROC_BROWSER_TEST_F(SystemWebDialogLoginTest, PRE_NonModalTest) {
-  RegisterUser(AccountId::FromUserEmailGaiaId(kTestUser, kTestUserGaiaId));
-  StartupUtils::MarkOobeCompleted();
-}
-
 // Verifies that system dialogs are not modal and always-on-top after login.
 IN_PROC_BROWSER_TEST_F(SystemWebDialogLoginTest, NonModalTest) {
-  LoginUser(AccountId::FromUserEmailGaiaId(kTestUser, kTestUserGaiaId));
+  LoginUser(login_mixin_.users()[0].account_id);
   auto* dialog = new MockSystemWebDialog();
   dialog->ShowSystemDialog();
   EXPECT_FALSE(ash::ShellTestApi().IsSystemModalWindowOpen());
diff --git a/chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider.cc
index c7abe54..edaf7b31 100644
--- a/chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider.cc
@@ -702,6 +702,8 @@
       {"crostiniDiskResizeTitle", IDS_SETTINGS_CROSTINI_DISK_RESIZE_TITLE},
       {"crostiniDiskResizeShowButton",
        IDS_SETTINGS_CROSTINI_DISK_RESIZE_SHOW_BUTTON},
+      {"crostiniDiskResizeShowButtonAriaLabel",
+       IDS_SETTINGS_CROSTINI_DISK_RESIZE_SHOW_BUTTON_ARIA_LABEL},
       {"crostiniDiskResizeLabel", IDS_SETTINGS_CROSTINI_DISK_RESIZE_LABEL},
       {"crostiniDiskResizeUnsupported",
        IDS_SETTINGS_CROSTINI_DISK_RESIZE_UNSUPPORTED},
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
index 1da6113..0a2c4de 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -1217,6 +1217,8 @@
        IDS_SETTINGS_NETWORK_PREDICTION_ENABLED_LABEL},
       {"networkPredictionEnabledDesc",
        IDS_SETTINGS_NETWORK_PREDICTION_ENABLED_DESC},
+      {"networkPredictionEnabledDescCookiesPage",
+       IDS_SETTINGS_NETWORK_PREDICTION_ENABLED_DESC_COOKIES_PAGE},
       {"safetyCheckSectionTitle", IDS_SETTINGS_SAFETY_CHECK_SECTION_TITLE},
       {"safetyCheckParentPrimaryLabelBefore",
        IDS_SETTINGS_SAFETY_CHECK_PARENT_PRIMARY_LABEL_BEFORE},
diff --git a/chrome/browser/ui/webui/settings/settings_ui.cc b/chrome/browser/ui/webui/settings/settings_ui.cc
index bd6edc5..b37f1a1 100644
--- a/chrome/browser/ui/webui/settings/settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/settings_ui.cc
@@ -161,18 +161,6 @@
   content::WebUIDataSource* html_source =
       content::WebUIDataSource::Create(chrome::kChromeUISettingsHost);
 
-  // TODO(dpapad): Replace the following calls with
-  // SetupBundledWebUIDataSource() when Settings is migrated to Polymer3.
-  // Currently only used for testing the Polymer 3 version of
-  // certificate-manager.
-#if BUILDFLAG(OPTIMIZE_WEBUI)
-  html_source->EnableReplaceI18nInJS();
-  html_source->OverrideContentSecurityPolicyScriptSrc(
-      "script-src chrome://resources chrome://test 'self';");
-  html_source->AddResourcePath("test_loader.js", IDR_WEBUI_JS_TEST_LOADER);
-  html_source->AddResourcePath("test_loader.html", IDR_WEBUI_HTML_TEST_LOADER);
-#endif
-
   AddSettingsPageUIHandler(std::make_unique<AppearanceHandler>(web_ui));
 
 #if defined(USE_NSS_CERTS)
@@ -319,12 +307,22 @@
   web_ui->AddMessageHandler(std::make_unique<MetricsHandler>());
 
 #if BUILDFLAG(OPTIMIZE_WEBUI)
-  html_source->AddResourcePath("crisper.js", IDR_SETTINGS_CRISPER_JS);
-  html_source->AddResourcePath("lazy_load.crisper.js",
-                               IDR_SETTINGS_LAZY_LOAD_CRISPER_JS);
-  html_source->AddResourcePath("lazy_load.html",
-                               IDR_SETTINGS_LAZY_LOAD_VULCANIZED_HTML);
-  html_source->SetDefaultResource(IDR_SETTINGS_VULCANIZED_HTML);
+  if (base::FeatureList::IsEnabled(features::kSettingsPolymer3)) {
+    webui::SetupBundledWebUIDataSource(html_source, "settings.js",
+                                       IDR_SETTINGS_SETTINGS_ROLLUP_JS,
+                                       IDR_SETTINGS_SETTINGS_V3_HTML);
+    html_source->AddResourcePath("shared.rollup.js",
+                                 IDR_SETTINGS_SHARED_ROLLUP_JS);
+    html_source->AddResourcePath("lazy_load.js",
+                                 IDR_SETTINGS_LAZY_LOAD_ROLLUP_JS);
+  } else {
+    html_source->AddResourcePath("crisper.js", IDR_SETTINGS_CRISPER_JS);
+    html_source->AddResourcePath("lazy_load.crisper.js",
+                                 IDR_SETTINGS_LAZY_LOAD_CRISPER_JS);
+    html_source->AddResourcePath("lazy_load.html",
+                                 IDR_SETTINGS_LAZY_LOAD_VULCANIZED_HTML);
+    html_source->SetDefaultResource(IDR_SETTINGS_VULCANIZED_HTML);
+  }
 
   // Register SVG images that are purposefully not inlined in the HTML bundle
   // above.
@@ -356,18 +354,13 @@
       "images/password_check_positive_dark.svg",
       IDR_SETTINGS_IMAGES_PASSWORD_CHECK_POSITIVE_DARK_SVG);
 
-  // Only used in Polymer 3, see https://crbug.com/1026426.
-  html_source->AddResourcePath("settings.js", IDR_SETTINGS_SETTINGS_ROLLUP_JS);
-  html_source->AddResourcePath("shared.rollup.js",
-                               IDR_SETTINGS_SHARED_ROLLUP_JS);
-  html_source->AddResourcePath("lazy_load.js",
-                               IDR_SETTINGS_LAZY_LOAD_ROLLUP_JS);
-  html_source->AddResourcePath("settings_v3.html",
-                               IDR_SETTINGS_SETTINGS_V3_HTML);
 #else
   webui::SetupWebUIDataSource(
       html_source, base::make_span(kSettingsResources, kSettingsResourcesSize),
-      kGeneratedPath, IDR_SETTINGS_SETTINGS_HTML);
+      kGeneratedPath,
+      base::FeatureList::IsEnabled(features::kSettingsPolymer3)
+          ? IDR_SETTINGS_SETTINGS_V3_HTML
+          : IDR_SETTINGS_SETTINGS_HTML);
 #endif
 
   AddBrowserLocalizedStrings(html_source, profile, web_ui->GetWebContents());
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 7adf66b..2b74861 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -179,7 +179,7 @@
 // OS_CHROMEOS, but this flag must be defined for all platforms since
 // it is required for SystemWebApp tests.
 const base::Feature kTerminalSystemApp{"TerminalSystemApp",
-                                       base::FEATURE_DISABLED_BY_DEFAULT};
+                                       base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Use the Terminal System App legacy settings page.
 const base::Feature kTerminalSystemAppLegacySettings{
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 5a0890a..4f7b355 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -5896,7 +5896,6 @@
         "../browser/ui/views/test/view_event_test_platform_part_chromeos.cc",
         "../browser/ui/views/test/view_event_test_platform_part_default.cc",
         "../browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc",
-        "../browser/ui/views/toolbar/toolbar_button_interactive_uitest.cc",
         "../browser/ui/views/toolbar/toolbar_view_interactive_uitest.cc",
         "../browser/ui/views/translate/translate_bubble_test_utils_views.cc",
       ]
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-error.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-error.Nexus_5-19.png.sha1
deleted file mode 100644
index 356899b..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-error.Nexus_5-19.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-736cfa9bc0c19dccf3350add8a72c025437310fc
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-error.Nexus_5X-23.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-error.Nexus_5X-23.png.sha1
deleted file mode 100644
index 06a0e6f..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-error.Nexus_5X-23.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-ec45fc2f20da97cbd35a77377aca458aff080ad7
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-expanded.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-expanded.Nexus_5-19.png.sha1
deleted file mode 100644
index 1c21ce0..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-expanded.Nexus_5-19.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-0fa90ec5d41a071ef7252aab236ee082a12832ce
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-expanded.Nexus_5X-23.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-expanded.Nexus_5X-23.png.sha1
deleted file mode 100644
index 8736dab..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-expanded.Nexus_5X-23.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-cdd12e93cd8334dac1727d2b31de9d9760be41f8
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-expanded_rtl.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-expanded_rtl.Nexus_5-19.png.sha1
deleted file mode 100644
index 64eb7869..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-expanded_rtl.Nexus_5-19.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-1513841a90d07e884e161c7bd641272c2c535792
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-expanded_rtl.Nexus_5X-23.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-expanded_rtl.Nexus_5X-23.png.sha1
deleted file mode 100644
index d034409..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-expanded_rtl.Nexus_5X-23.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-a34970c4a5e5ae8e30d8bb2d563a4dea726bf596
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-filled.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-filled.Nexus_5-19.png.sha1
deleted file mode 100644
index 8d557c9..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-filled.Nexus_5-19.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-35b0a65fe1a9448c29fa7b1766e7e4a7ecadad1a
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-filled.Nexus_5X-23.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-filled.Nexus_5X-23.png.sha1
deleted file mode 100644
index 48c0acc..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-filled.Nexus_5X-23.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-ced712b28e69c969c9f867b9b5de606c3beb0fa7
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-focused.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-focused.Nexus_5-19.png.sha1
deleted file mode 100644
index 17beb46..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-focused.Nexus_5-19.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-c64a5fa335db00be96011aa5f00f11bec822fd92
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-focused.Nexus_5X-23.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-focused.Nexus_5X-23.png.sha1
deleted file mode 100644
index 0ec7d58..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-focused.Nexus_5X-23.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-a9d6bdc40e378f1908d9e17431c78009a8d68aa7
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-focused_rtl.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-focused_rtl.Nexus_5-19.png.sha1
deleted file mode 100644
index be3159e..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-focused_rtl.Nexus_5-19.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-3fa50ee480a8d71023017f5f522f0656693d3448
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-focused_rtl.Nexus_5X-23.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-focused_rtl.Nexus_5X-23.png.sha1
deleted file mode 100644
index 9a9e7cf9..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-focused_rtl.Nexus_5X-23.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-e7399d022a8e558a797872749a0f9ee2caa226ce
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-phone_expanded_rtl.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-phone_expanded_rtl.Nexus_5-19.png.sha1
deleted file mode 100644
index 64eb7869..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-phone_expanded_rtl.Nexus_5-19.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-1513841a90d07e884e161c7bd641272c2c535792
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-phone_expanded_rtl.Nexus_5X-23.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-phone_expanded_rtl.Nexus_5X-23.png.sha1
deleted file mode 100644
index d034409..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-phone_expanded_rtl.Nexus_5X-23.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-a34970c4a5e5ae8e30d8bb2d563a4dea726bf596
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-phone_rtl.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-phone_rtl.Nexus_5-19.png.sha1
deleted file mode 100644
index 43a6cf2f..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-phone_rtl.Nexus_5-19.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-f6365db616f95b919446b722a90fad6404b5694c
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-phone_rtl.Nexus_5X-23.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-phone_rtl.Nexus_5X-23.png.sha1
deleted file mode 100644
index 72dc29bb..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeDisabled-phone_rtl.Nexus_5X-23.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-321413bb1b6c727b3739b10198bfcd243d8e1f80
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-error.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-error.Nexus_5-19.png.sha1
deleted file mode 100644
index 0739b7e..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-error.Nexus_5-19.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-afbab2fd9471f7b8d9195348d84a696d4a8f92db
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-error.Nexus_5X-23.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-error.Nexus_5X-23.png.sha1
deleted file mode 100644
index 49abfa0..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-error.Nexus_5X-23.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-2d11603a9010b635302f29f46242b43d64eda8e5
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-expanded.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-expanded.Nexus_5-19.png.sha1
deleted file mode 100644
index 391f07b1..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-expanded.Nexus_5-19.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-70364a46298b7a4d1b39a3145313c55b46014466
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-expanded.Nexus_5X-23.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-expanded.Nexus_5X-23.png.sha1
deleted file mode 100644
index 19d4bac..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-expanded.Nexus_5X-23.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-c8a0bf3999b416f2e2b4e17d4c18c3298968b83c
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-expanded_rtl.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-expanded_rtl.Nexus_5-19.png.sha1
deleted file mode 100644
index dd39c78..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-expanded_rtl.Nexus_5-19.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-fd89a811ce9ff2cf6fc7fd48b27ddd6d22515ed5
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-expanded_rtl.Nexus_5X-23.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-expanded_rtl.Nexus_5X-23.png.sha1
deleted file mode 100644
index 8e64ce1..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-expanded_rtl.Nexus_5X-23.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-386c641d7ad2d1fd1065b84d5f96140d68f3ac79
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-filled.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-filled.Nexus_5-19.png.sha1
deleted file mode 100644
index 914b3cd5..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-filled.Nexus_5-19.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-83f20c248ba144d187b0dfb29aaa22f3f10508aa
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-filled.Nexus_5X-23.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-filled.Nexus_5X-23.png.sha1
deleted file mode 100644
index 67bbf854..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-filled.Nexus_5X-23.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-39212667d5f7a3f046cd83133c8fd39ae3b33f30
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-focused.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-focused.Nexus_5-19.png.sha1
deleted file mode 100644
index dfdddbf..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-focused.Nexus_5-19.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-eae77473b2208e18dd5a4d4bca6851ad7ff1fce1
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-focused.Nexus_5X-23.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-focused.Nexus_5X-23.png.sha1
deleted file mode 100644
index 9737aad..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-focused.Nexus_5X-23.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-a0ab4169784a2b77128f0f55d32a0db46add1ff5
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-focused_rtl.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-focused_rtl.Nexus_5-19.png.sha1
deleted file mode 100644
index fd2cd8f80..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-focused_rtl.Nexus_5-19.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-05d2b1a5c49cc1e50b671fc052834bd5586eeba0
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-focused_rtl.Nexus_5X-23.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-focused_rtl.Nexus_5X-23.png.sha1
deleted file mode 100644
index 7721999..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-focused_rtl.Nexus_5X-23.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-ab2f6bfc91f9db47c90340de4f8d7fe23db4663c
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-phone_expanded_rtl.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-phone_expanded_rtl.Nexus_5-19.png.sha1
deleted file mode 100644
index dd39c78..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-phone_expanded_rtl.Nexus_5-19.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-fd89a811ce9ff2cf6fc7fd48b27ddd6d22515ed5
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-phone_expanded_rtl.Nexus_5X-23.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-phone_expanded_rtl.Nexus_5X-23.png.sha1
deleted file mode 100644
index 8e64ce1..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-phone_expanded_rtl.Nexus_5X-23.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-386c641d7ad2d1fd1065b84d5f96140d68f3ac79
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-phone_rtl.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-phone_rtl.Nexus_5-19.png.sha1
deleted file mode 100644
index c7415a1..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-phone_rtl.Nexus_5-19.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-2fb8415214f398ea9682be6905dc1c93b22512ab
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-phone_rtl.Nexus_5X-23.png.sha1 b/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-phone_rtl.Nexus_5X-23.png.sha1
deleted file mode 100644
index 383b750..0000000
--- a/chrome/test/data/android/render_tests/ChromeTextInputLayoutRenderTest.NightModeEnabled-phone_rtl.Nexus_5X-23.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-92e46e5954095ec5712a37148fe4680e83b06186
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/InstantStartTest.tabSwitcher_3tabs.Nexus_5X-23.png.sha1 b/chrome/test/data/android/render_tests/InstantStartTest.tabSwitcher_3tabs.Nexus_5X-23.png.sha1
new file mode 100644
index 0000000..84edb39
--- /dev/null
+++ b/chrome/test/data/android/render_tests/InstantStartTest.tabSwitcher_3tabs.Nexus_5X-23.png.sha1
@@ -0,0 +1 @@
+447470455aa2afcb3c2f0abe8a86a69c4840b84d
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/InstantStartTest.tabSwitcher_empty.Nexus_5X-23.png.sha1 b/chrome/test/data/android/render_tests/InstantStartTest.tabSwitcher_empty.Nexus_5X-23.png.sha1
new file mode 100644
index 0000000..2c6646e
--- /dev/null
+++ b/chrome/test/data/android/render_tests/InstantStartTest.tabSwitcher_empty.Nexus_5X-23.png.sha1
@@ -0,0 +1 @@
+6b84e01daf77a9204a8225528f9eead72c2d6b84
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/InstantStartTest.tabSwitcher_tabGroups.Nexus_5X-23.png.sha1 b/chrome/test/data/android/render_tests/InstantStartTest.tabSwitcher_tabGroups.Nexus_5X-23.png.sha1
new file mode 100644
index 0000000..ebe8fa7d
--- /dev/null
+++ b/chrome/test/data/android/render_tests/InstantStartTest.tabSwitcher_tabGroups.Nexus_5X-23.png.sha1
@@ -0,0 +1 @@
+54a386119693dbee82caed78871a661927b535a5
\ No newline at end of file
diff --git a/chrome/test/data/webui/cr_components/cr_components_v3_browsertest.js b/chrome/test/data/webui/cr_components/cr_components_v3_browsertest.js
index 60fa7a8..939d698 100644
--- a/chrome/test/data/webui/cr_components/cr_components_v3_browsertest.js
+++ b/chrome/test/data/webui/cr_components/cr_components_v3_browsertest.js
@@ -6,6 +6,7 @@
 
 // Polymer BrowserTest fixture.
 GEN_INCLUDE(['//chrome/test/data/webui/polymer_browser_test_base.js']);
+GEN('#include "chrome/browser/ui/ui_features.h"');
 GEN('#include "services/network/public/cpp/features.h"');
 
 /** Test fixture for shared Polymer 3 components. */
@@ -59,7 +60,12 @@
 
   /** @override */
   get featureList() {
-    return {enabled: ['network::features::kOutOfBlinkCors']};
+    return {
+      enabled: [
+        'network::features::kOutOfBlinkCors',
+        'features::kSettingsPolymer3',
+      ]
+    };
   }
 };
 
diff --git a/chrome/test/data/webui/cr_elements/cr_elements_v3_browsertest.js b/chrome/test/data/webui/cr_elements/cr_elements_v3_browsertest.js
index 1e025439..5cd43a6d1 100644
--- a/chrome/test/data/webui/cr_elements/cr_elements_v3_browsertest.js
+++ b/chrome/test/data/webui/cr_elements/cr_elements_v3_browsertest.js
@@ -6,6 +6,7 @@
 
 // Polymer BrowserTest fixture.
 GEN_INCLUDE(['//chrome/test/data/webui/polymer_browser_test_base.js']);
+GEN('#include "chrome/browser/ui/ui_features.h"');
 GEN('#include "services/network/public/cpp/features.h"');
 
 /** Test fixture for shared Polymer 3 elements. */
@@ -318,7 +319,12 @@
 
   /** @override */
   get featureList() {
-    return {enabled: ['network::features::kOutOfBlinkCors']};
+    return {
+      enabled: [
+        'network::features::kOutOfBlinkCors',
+        'features::kSettingsPolymer3',
+      ]
+    };
   }
 };
 
diff --git a/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js b/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js
index 4b3ecb9..e2537ef 100644
--- a/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js
+++ b/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js
@@ -6,12 +6,13 @@
 
 // Polymer BrowserTest fixture.
 GEN_INCLUDE(['//chrome/test/data/webui/polymer_browser_test_base.js']);
-GEN('#include "services/network/public/cpp/features.h"');
 
 GEN('#include "build/branding_buildflags.h"');
+GEN('#include "chrome/browser/ui/ui_features.h"');
 GEN('#include "chrome/common/chrome_features.h"');
 GEN('#include "components/autofill/core/common/autofill_features.h"');
 GEN('#include "components/password_manager/core/common/password_manager_features.h"');
+GEN('#include "services/network/public/cpp/features.h"');
 
 /** Test fixture for shared Polymer 3 elements. */
 // eslint-disable-next-line no-var
@@ -31,7 +32,13 @@
 
   /** @override */
   get featureList() {
-    return {enabled: ['network::features::kOutOfBlinkCors'], disabled: []};
+    return {
+      enabled: [
+        'network::features::kOutOfBlinkCors',
+        'features::kSettingsPolymer3',
+      ],
+      disabled: [],
+    };
   }
 };
 
diff --git a/chrome/test/data/webui/settings/cr_settings_v3_interactive_ui_tests.js b/chrome/test/data/webui/settings/cr_settings_v3_interactive_ui_tests.js
index d53c85d..a46a107ad 100644
--- a/chrome/test/data/webui/settings/cr_settings_v3_interactive_ui_tests.js
+++ b/chrome/test/data/webui/settings/cr_settings_v3_interactive_ui_tests.js
@@ -7,6 +7,8 @@
 // Polymer BrowserTest fixture.
 GEN_INCLUDE(['//chrome/test/data/webui/polymer_interactive_ui_test.js']);
 
+GEN('#include "chrome/browser/ui/ui_features.h"');
+
 /** Test fixture for shared Polymer 3 elements. */
 // eslint-disable-next-line no-var
 var CrSettingsV3InteractiveUITest = class extends PolymerInteractiveUITest {
@@ -22,6 +24,11 @@
       '//chrome/test/data/webui/mocha_adapter.js',
     ];
   }
+
+  /** @override */
+  get featureList() {
+    return {enabled: ['features::kSettingsPolymer3'], disabled: []};
+  }
 };
 
 // eslint-disable-next-line no-var
diff --git a/chrome/test/data/webui/settings/safety_check_page_test.js b/chrome/test/data/webui/settings/safety_check_page_test.js
index 0ca5d27..7a119f46 100644
--- a/chrome/test/data/webui/settings/safety_check_page_test.js
+++ b/chrome/test/data/webui/settings/safety_check_page_test.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 // clang-format off
-// #import {HatsBrowserProxyImpl, LifetimeBrowserProxyImpl, MetricsBrowserProxyImpl, OpenWindowProxyImpl, PasswordManagerImpl, PasswordManagerProxy, Router, routes, SafetyCheckBrowserProxy, SafetyCheckBrowserProxyImpl, SafetyCheckCallbackConstants, SafetyCheckElementInteractions, SafetyCheckExtensionsStatus, SafetyCheckPasswordsStatus, SafetyCheckSafeBrowsingStatus, SafetyCheckUpdatesStatus} from 'chrome://settings/settings.js';
+// #import {HatsBrowserProxyImpl, LifetimeBrowserProxyImpl, MetricsBrowserProxyImpl, OpenWindowProxyImpl, PasswordManagerImpl, PasswordManagerProxy, Router, routes, SafetyCheckBrowserProxy, SafetyCheckBrowserProxyImpl, SafetyCheckCallbackConstants, SafetyCheckInteractions, SafetyCheckExtensionsStatus, SafetyCheckPasswordsStatus, SafetyCheckSafeBrowsingStatus, SafetyCheckUpdatesStatus} from 'chrome://settings/settings.js';
 // #import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 // #import {TestBrowserProxy} from 'chrome://test/test_browser_proxy.m.js';
 // #import {TestHatsBrowserProxy} from 'chrome://test/settings/test_hats_browser_proxy.m.js';
@@ -88,10 +88,11 @@
     page.$$('#safetyCheckExtensionsButton').click();
     // Ensure UMA is logged.
     assertEquals(
-        settings.SafetyCheckElementInteractions.SAFETY_CHECK_EXTENSIONS_REVIEW,
-        await metricsBrowserProxy.whenCalled('recordSafetyCheckPageHistogram'));
+        settings.SafetyCheckInteractions.SAFETY_CHECK_EXTENSIONS_REVIEW,
+        await metricsBrowserProxy.whenCalled(
+            'recordSafetyCheckInteractionHistogram'));
     assertEquals(
-        'SafetyCheck.Extensions.Review',
+        'Settings.SafetyCheck.ReviewExtensions',
         await metricsBrowserProxy.whenCalled('recordAction'));
     // Ensure the browser proxy call is done.
     assertEquals(
@@ -108,6 +109,14 @@
 
     // User starts check.
     page.$$('#safetyCheckParentButton').click();
+    // Ensure UMA is logged.
+    assertEquals(
+        settings.SafetyCheckInteractions.SAFETY_CHECK_START,
+        await metricsBrowserProxy.whenCalled(
+            'recordSafetyCheckInteractionHistogram'));
+    assertEquals(
+        'Settings.SafetyCheck.Start',
+        await metricsBrowserProxy.whenCalled('recordAction'));
     // Ensure the browser proxy call is done.
     await safetyCheckBrowserProxy.whenCalled('runSafetyCheck');
 
@@ -178,10 +187,11 @@
     page.$$('#safetyCheckUpdatesButton').click();
     // Ensure UMA is logged.
     assertEquals(
-        settings.SafetyCheckElementInteractions.SAFETY_CHECK_UPDATES_RELAUNCH,
-        await metricsBrowserProxy.whenCalled('recordSafetyCheckPageHistogram'));
+        settings.SafetyCheckInteractions.SAFETY_CHECK_UPDATES_RELAUNCH,
+        await metricsBrowserProxy.whenCalled(
+            'recordSafetyCheckInteractionHistogram'));
     assertEquals(
-        'SafetyCheck.Updates.Relaunch',
+        'Settings.SafetyCheck.RelaunchAfterUpdates',
         await metricsBrowserProxy.whenCalled('recordAction'));
     // Ensure the browser proxy call is done.
     return lifetimeBrowserProxy.whenCalled('relaunch');
@@ -237,10 +247,11 @@
     page.$$('#safetyCheckPasswordsButton').click();
     // Ensure UMA is logged.
     assertEquals(
-        settings.SafetyCheckElementInteractions.SAFETY_CHECK_PASSWORDS_MANAGE,
-        await metricsBrowserProxy.whenCalled('recordSafetyCheckPageHistogram'));
+        settings.SafetyCheckInteractions.SAFETY_CHECK_PASSWORDS_MANAGE,
+        await metricsBrowserProxy.whenCalled(
+            'recordSafetyCheckInteractionHistogram'));
     assertEquals(
-        'SafetyCheck.Passwords.Manage',
+        'Settings.SafetyCheck.ManagePasswords',
         await metricsBrowserProxy.whenCalled('recordAction'));
     // Ensure the correct Settings page is shown.
     assertEquals(
@@ -281,11 +292,11 @@
     page.$$('#safetyCheckSafeBrowsingButton').click();
     // Ensure UMA is logged.
     assertEquals(
-        settings.SafetyCheckElementInteractions
-            .SAFETY_CHECK_SAFE_BROWSING_MANAGE,
-        await metricsBrowserProxy.whenCalled('recordSafetyCheckPageHistogram'));
+        settings.SafetyCheckInteractions.SAFETY_CHECK_SAFE_BROWSING_MANAGE,
+        await metricsBrowserProxy.whenCalled(
+            'recordSafetyCheckInteractionHistogram'));
     assertEquals(
-        'SafetyCheck.SafeBrowsing.Manage',
+        'Settings.SafetyCheck.ManageSafeBrowsing',
         await metricsBrowserProxy.whenCalled('recordAction'));
     // Ensure the correct Settings page is shown.
     assertEquals(
diff --git a/chrome/test/data/webui/settings/settings_idle_load_v3_browsertest.js b/chrome/test/data/webui/settings/settings_idle_load_v3_browsertest.js
index 73af3b7..c865eab 100644
--- a/chrome/test/data/webui/settings/settings_idle_load_v3_browsertest.js
+++ b/chrome/test/data/webui/settings/settings_idle_load_v3_browsertest.js
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+GEN('#include "chrome/browser/ui/ui_features.h"');
 GEN('#include "services/network/public/cpp/features.h"');
 
 /**
@@ -27,7 +28,15 @@
   isAsync: true,
 
   /** @override */
-  featureList: {enabled: ['network::features::kOutOfBlinkCors']},
+  get featureList() {
+    return {
+      enabled: [
+        'network::features::kOutOfBlinkCors',
+        'features::kSettingsPolymer3',
+      ],
+      disabled: [],
+    };
+  },
 };
 
 TEST_F('SettingsIdleLoadV3BrowserTest', 'All', function() {
diff --git a/chrome/test/data/webui/settings/test_metrics_browser_proxy.js b/chrome/test/data/webui/settings/test_metrics_browser_proxy.js
index c6dfc4f..bfa2e22 100644
--- a/chrome/test/data/webui/settings/test_metrics_browser_proxy.js
+++ b/chrome/test/data/webui/settings/test_metrics_browser_proxy.js
@@ -9,7 +9,7 @@
   constructor() {
     super([
       'recordAction',
-      'recordSafetyCheckPageHistogram',
+      'recordSafetyCheckInteractionHistogram',
       'recordSettingsPageHistogram',
     ]);
   }
@@ -20,8 +20,8 @@
   }
 
   /** @override */
-  recordSafetyCheckPageHistogram(interaction) {
-    this.methodCalled('recordSafetyCheckPageHistogram', interaction);
+  recordSafetyCheckInteractionHistogram(interaction) {
+    this.methodCalled('recordSafetyCheckInteractionHistogram', interaction);
   }
 
   /** @override */
diff --git a/chromeos/audio/cras_audio_handler.cc b/chromeos/audio/cras_audio_handler.cc
index a66d97f..9aea2ea 100644
--- a/chromeos/audio/cras_audio_handler.cc
+++ b/chromeos/audio/cras_audio_handler.cc
@@ -982,6 +982,8 @@
   GetSystemAecGroupId();
   GetNodes();
   GetNumberOfOutputStreams();
+  CrasAudioClient::Get()->SetFixA2dpPacketSize(base::FeatureList::IsEnabled(
+      chromeos::features::kBluetoothFixA2dpPacketSize));
   CrasAudioClient::Get()->SetNextHandsfreeProfile(base::FeatureList::IsEnabled(
       chromeos::features::kBluetoothNextHandsfreeProfile));
 }
diff --git a/chromeos/constants/chromeos_features.cc b/chromeos/constants/chromeos_features.cc
index f24b60cf..7540c1f 100644
--- a/chromeos/constants/chromeos_features.cc
+++ b/chromeos/constants/chromeos_features.cc
@@ -57,6 +57,11 @@
 const base::Feature kBluetoothAggressiveAppearanceFilter{
     "BluetoothAggressiveAppearanceFilter", base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Enables or disables the usage of fixed Bluetooth A2DP packet size to improve
+// audio performance in noisy environment.
+const base::Feature kBluetoothFixA2dpPacketSize{
+    "BluetoothFixA2dpPacketSize", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enables or disables more filtering out of phones from the Bluetooth UI.
 const base::Feature kBluetoothPhoneFilter{"BluetoothPhoneFilter",
                                           base::FEATURE_ENABLED_BY_DEFAULT};
@@ -371,7 +376,7 @@
 
 // Enable or disable resizable floating virtual keyboard on Chrome OS.
 const base::Feature kVirtualKeyboardFloatingResizable{
-    "VirtualKeyboardFloatingResizable", base::FEATURE_DISABLED_BY_DEFAULT};
+    "VirtualKeyboardFloatingResizable", base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Enable or disable MOZC IME to use protobuf as interactive message format.
 const base::Feature kImeMozcProto{"ImeMozcProto",
diff --git a/chromeos/constants/chromeos_features.h b/chromeos/constants/chromeos_features.h
index 6a741cf..bfbef5a7 100644
--- a/chromeos/constants/chromeos_features.h
+++ b/chromeos/constants/chromeos_features.h
@@ -34,6 +34,8 @@
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
 extern const base::Feature kBluetoothAggressiveAppearanceFilter;
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
+extern const base::Feature kBluetoothFixA2dpPacketSize;
+COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
 extern const base::Feature kBluetoothPhoneFilter;
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
 extern const base::Feature kBluetoothKernelSuspendNotifier;
diff --git a/chromeos/dbus/audio/cras_audio_client.cc b/chromeos/dbus/audio/cras_audio_client.cc
index a077e52e..a1efe1b 100644
--- a/chromeos/dbus/audio/cras_audio_client.cc
+++ b/chromeos/dbus/audio/cras_audio_client.cc
@@ -262,6 +262,16 @@
                        weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
   }
 
+  void SetFixA2dpPacketSize(bool enabled) override {
+    dbus::MethodCall method_call(cras::kCrasControlInterface,
+                                 cras::kSetFixA2dpPacketSize);
+    dbus::MessageWriter writer(&method_call);
+    writer.AppendBool(enabled);
+    cras_proxy_->CallMethod(&method_call,
+                            dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+                            base::DoNothing());
+  }
+
   void SetNextHandsfreeProfile(bool enabled) override {
     dbus::MethodCall method_call(cras::kCrasControlInterface,
                                  cras::kSetNextHandsfreeProfile);
diff --git a/chromeos/dbus/audio/cras_audio_client.h b/chromeos/dbus/audio/cras_audio_client.h
index 6d911059..e2c4a5e 100644
--- a/chromeos/dbus/audio/cras_audio_client.h
+++ b/chromeos/dbus/audio/cras_audio_client.h
@@ -132,6 +132,8 @@
                                const std::string& hotword_model,
                                VoidDBusMethodCallback callback) = 0;
 
+  // Enables or disables the usage of fixed A2DP packet size in CRAS.
+  virtual void SetFixA2dpPacketSize(bool enabled) = 0;
   // Enables or disables the next Handsfree profile next version in CRAS.
   virtual void SetNextHandsfreeProfile(bool enabled) = 0;
 
diff --git a/chromeos/dbus/audio/fake_cras_audio_client.cc b/chromeos/dbus/audio/fake_cras_audio_client.cc
index 05e53166..00b6f265 100644
--- a/chromeos/dbus/audio/fake_cras_audio_client.cc
+++ b/chromeos/dbus/audio/fake_cras_audio_client.cc
@@ -192,6 +192,7 @@
                                           const std::string& hotword_model,
                                           VoidDBusMethodCallback callback) {}
 
+void FakeCrasAudioClient::SetFixA2dpPacketSize(bool enabled) {}
 void FakeCrasAudioClient::SetNextHandsfreeProfile(bool enabled) {}
 
 void FakeCrasAudioClient::AddActiveInputNode(uint64_t node_id) {
diff --git a/chromeos/dbus/audio/fake_cras_audio_client.h b/chromeos/dbus/audio/fake_cras_audio_client.h
index 16f8eb7..a505117e 100644
--- a/chromeos/dbus/audio/fake_cras_audio_client.h
+++ b/chromeos/dbus/audio/fake_cras_audio_client.h
@@ -44,6 +44,7 @@
   void SetHotwordModel(uint64_t node_id,
                        const std::string& hotword_model,
                        VoidDBusMethodCallback callback) override;
+  void SetFixA2dpPacketSize(bool enabled) override;
   void SetNextHandsfreeProfile(bool enabled) override;
   void AddActiveInputNode(uint64_t node_id) override;
   void RemoveActiveInputNode(uint64_t node_id) override;
diff --git a/chromeos/services/multidevice_setup/android_sms_app_installing_status_observer.cc b/chromeos/services/multidevice_setup/android_sms_app_installing_status_observer.cc
index 48ac4546..b791f74b 100644
--- a/chromeos/services/multidevice_setup/android_sms_app_installing_status_observer.cc
+++ b/chromeos/services/multidevice_setup/android_sms_app_installing_status_observer.cc
@@ -81,12 +81,15 @@
 
 void AndroidSmsAppInstallingStatusObserver::UpdatePwaInstallationState() {
   if (!DoesFeatureStateAllowInstallation()) {
+    PA_LOG(INFO)
+        << "Feature state does not allow installation, tearing down App.";
     // The feature is disabled, ensure that the integration cookie is removed.
     android_sms_app_helper_delegate_->TearDownAndroidSmsApp();
     return;
   }
 
   if (android_sms_app_helper_delegate_->HasAppBeenManuallyUninstalledByUser()) {
+    PA_LOG(INFO) << "App was manually uninstalled by user, tearing down App.";
     feature_state_manager_->SetFeatureEnabledState(mojom::Feature::kMessages,
                                                    false);
 
diff --git a/components/arc/session/arc_vm_client_adapter.cc b/components/arc/session/arc_vm_client_adapter.cc
index ac2a9bd5..b342cc8 100644
--- a/components/arc/session/arc_vm_client_adapter.cc
+++ b/components/arc/session/arc_vm_client_adapter.cc
@@ -47,6 +47,7 @@
 namespace arc {
 namespace {
 
+constexpr const char kArcCreateDataJobName[] = "arc_2dcreate_2ddata";
 constexpr const char kArcVmServerProxyJobName[] = "arcvm_2dserver_2dproxy";
 constexpr const char kArcVmPerBoardFeaturesJobName[] =
     "arcvm_2dper_2dboard_2dfeatures";
@@ -484,6 +485,26 @@
       std::move(callback).Run(false);
       return;
     }
+
+    VLOG(1) << "Starting arc-create-data";
+    const std::string account_id =
+        cryptohome::CreateAccountIdentifierFromIdentification(cryptohome_id_)
+            .account_id();
+    chromeos::UpstartClient::Get()->StartJob(
+        kArcCreateDataJobName, {"CHROMEOS_USER=" + account_id},
+        base::BindOnce(&ArcVmClientAdapter::OnArcCreateDataJobStarted,
+                       weak_factory_.GetWeakPtr(), std::move(params),
+                       std::move(callback)));
+  }
+
+  void OnArcCreateDataJobStarted(UpgradeParams params,
+                                 chromeos::VoidDBusMethodCallback callback,
+                                 bool result) {
+    if (!result) {
+      LOG(ERROR) << "Failed to start arc-create-data job";
+      std::move(callback).Run(false);
+      return;
+    }
     // TODO(pliard): Export host-side /data to the VM, and remove the call. Note
     // that ArcSessionImpl checks low disk conditions before calling UpgradeArc.
     base::ThreadPool::PostTaskAndReplyWithResult(
diff --git a/components/arc/session/arc_vm_client_adapter_unittest.cc b/components/arc/session/arc_vm_client_adapter_unittest.cc
index ba457b8..b659799 100644
--- a/components/arc/session/arc_vm_client_adapter_unittest.cc
+++ b/components/arc/session/arc_vm_client_adapter_unittest.cc
@@ -35,6 +35,7 @@
 namespace arc {
 namespace {
 
+constexpr const char kArcCreateDataJobName[] = "arc_2dcreate_2ddata";
 constexpr const char kArcVmServerProxyJobName[] = "arcvm_2dserver_2dproxy";
 constexpr const char kArcVmPerBoardFeaturesJobName[] =
     "arcvm_2dper_2dboard_2dfeatures";
@@ -452,6 +453,30 @@
   EXPECT_TRUE(arc_instance_stopped_called());
 }
 
+// Tests that UpgradeArc() handles arc-create-data startup failures properly.
+TEST_F(ArcVmClientAdapterTest, UpgradeArc_StartArcCreateDataFailure) {
+  SetValidUserInfo();
+  StartMiniArc();
+
+  // Inject failure to FakeUpstartClient.
+  InjectUpstartStartJobFailure(kArcCreateDataJobName);
+
+  UpgradeArc(false);
+  EXPECT_TRUE(GetStartConciergeCalled());
+  EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
+  EXPECT_FALSE(arc_instance_stopped_called());
+
+  // Try to stop the VM. StopVm will fail in this case because
+  // no VM is running.
+  vm_tools::concierge::StopVmResponse response;
+  response.set_success(false);
+  GetTestConciergeClient()->set_stop_vm_response(response);
+  adapter()->StopArcInstance(/*on_shutdown=*/false);
+  run_loop()->Run();
+  EXPECT_TRUE(GetTestConciergeClient()->stop_vm_called());
+  EXPECT_TRUE(arc_instance_stopped_called());
+}
+
 // Tests that UpgradeArc() handles StartConcierge() failures properly.
 TEST_F(ArcVmClientAdapterTest, UpgradeArc_StartConciergeFailure) {
   SetValidUserInfo();
diff --git a/components/browser_ui/widget/android/BUILD.gn b/components/browser_ui/widget/android/BUILD.gn
index 4c96ac5..32a49a3d 100644
--- a/components/browser_ui/widget/android/BUILD.gn
+++ b/components/browser_ui/widget/android/BUILD.gn
@@ -67,7 +67,6 @@
     "java/src/org/chromium/components/browser_ui/widget/selectable_list/SelectionDelegate.java",
     "java/src/org/chromium/components/browser_ui/widget/text/AccessibleTextView.java",
     "java/src/org/chromium/components/browser_ui/widget/text/AlertDialogEditText.java",
-    "java/src/org/chromium/components/browser_ui/widget/text/ChromeTextInputLayout.java",
     "java/src/org/chromium/components/browser_ui/widget/text/TemplatePreservingTextView.java",
     "java/src/org/chromium/components/browser_ui/widget/text/TextViewWithCompoundDrawables.java",
     "java/src/org/chromium/components/browser_ui/widget/text/VerticallyFixedEditText.java",
@@ -200,7 +199,6 @@
     "java/src/org/chromium/components/browser_ui/widget/highlight/ViewHighlighterTest.java",
     "java/src/org/chromium/components/browser_ui/widget/listmenu/ListMenuRenderTest.java",
     "java/src/org/chromium/components/browser_ui/widget/scrim/ScrimTest.java",
-    "java/src/org/chromium/components/browser_ui/widget/text/ChromeTextInputLayoutRenderTest.java",
   ]
   deps = [
     ":java",
@@ -236,7 +234,6 @@
     "test/java/res/layout/radio_button_with_description_layout_test.xml",
     "test/java/res/layout/radio_button_with_edit_text_test.xml",
     "test/java/res/values/strings.xml",
-    "test/java/res/values/styles.xml",
   ]
   deps = [
     ":java_resources",
diff --git a/components/browser_ui/widget/android/java/res/values/attrs.xml b/components/browser_ui/widget/android/java/res/values/attrs.xml
index add0c154..2b99cc7e 100644
--- a/components/browser_ui/widget/android/java/res/values/attrs.xml
+++ b/components/browser_ui/widget/android/java/res/values/attrs.xml
@@ -10,12 +10,6 @@
         <attr name="maxHeight" format="dimension" />
     </declare-styleable>
 
-    <declare-styleable name="ChromeTextInputLayout">
-        <attr name="errorTextAppearance" format="reference" />
-        <attr name="hint" format="reference|string" />
-        <attr name="hintTextAppearance" format="reference" />
-    </declare-styleable>
-
     <declare-styleable name="DualControlLayout">
         <attr name="stackedMargin" format="reference|dimension"/>
         <attr name="primaryButtonText" format="reference|string"/>
diff --git a/components/browser_ui/widget/android/java/res/values/dimens.xml b/components/browser_ui/widget/android/java/res/values/dimens.xml
index 19cfeaa..147b3d3b 100644
--- a/components/browser_ui/widget/android/java/res/values/dimens.xml
+++ b/components/browser_ui/widget/android/java/res/values/dimens.xml
@@ -13,9 +13,6 @@
     <!-- DualControlLayout -->
     <dimen name="dual_control_margin_between_items">8dp</dimen>
 
-    <!-- ChromeTextInputLayout -->
-    <dimen name="text_input_layout_padding_start">3dp</dimen>
-
     <!-- Dialogs -->
     <dimen name="dialog_max_width">600dp</dimen>
     <dimen name="dialog_header_margin">14dp</dimen>
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/text/ChromeTextInputLayout.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/text/ChromeTextInputLayout.java
deleted file mode 100644
index a9912d81..0000000
--- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/text/ChromeTextInputLayout.java
+++ /dev/null
@@ -1,486 +0,0 @@
-// Copyright 2019 The Chromium 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.components.browser_ui.widget.text;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.PorterDuff;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.DrawableContainer;
-import android.os.Build;
-import android.text.Editable;
-import android.text.TextUtils;
-import android.text.TextWatcher;
-import android.util.AttributeSet;
-import android.util.TypedValue;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-import android.widget.EditText;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import androidx.annotation.ColorInt;
-import androidx.annotation.IntDef;
-import androidx.appcompat.widget.AppCompatDrawableManager;
-import androidx.core.content.ContextCompat;
-import androidx.core.graphics.drawable.DrawableCompat;
-import androidx.core.view.AccessibilityDelegateCompat;
-import androidx.core.view.ViewCompat;
-import androidx.core.view.ViewPropertyAnimatorListenerAdapter;
-import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
-
-import com.google.android.material.internal.DrawableUtils;
-
-import org.chromium.base.ApiCompatibilityUtils;
-import org.chromium.components.browser_ui.widget.R;
-import org.chromium.components.browser_ui.widget.animation.Interpolators;
-import org.chromium.ui.base.LocalizationUtils;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.HashSet;
-
-/**
- * A custom LinearLayout similar to Android's TextInputLayout. This class implements only a small
- * subset of features provided by TextInputLayout (floating animated label and error text) since we
- * don't need everything for Chrome, for now, and helps us avoid the TextInputLayout's binary size
- * impact by removing the dependency on it.
- *
- * WARNING: The child EditText's setOnFocusChangeListener() method shouldn't be called directly
- * because this class depends on the child's focus events. Instead, use
- * {@link ChromeTextInputLayout#addEditTextOnFocusChangeListener}.
- */
-public class ChromeTextInputLayout extends LinearLayout {
-    @IntDef({LabelStatus.COLLAPSED, LabelStatus.EXPANDED, LabelStatus.ANIMATING})
-    @Retention(RetentionPolicy.SOURCE)
-    private @interface LabelStatus {
-        int COLLAPSED = 0;
-        int EXPANDED = 1;
-        int ANIMATING = 2;
-    }
-
-    /**
-     * Focus change listener interface to use with the {@link EditText} inside the
-     * {@link ChromeTextInputLayout}
-     */
-    public interface OnEditTextFocusChangeListener {
-        void onEditTextFocusChange(View v, boolean hasFocus);
-    }
-
-    private static final long ANIMATION_DURATION_MS = 150;
-
-    private EditText mEditText;
-    private TextView mLabel;
-    private TextView mErrorText;
-    private FrameLayout mFrame;
-    private HashSet<OnEditTextFocusChangeListener> mListeners = new HashSet<>();
-
-    private CharSequence mHint;
-
-    private boolean mShouldDisplayError;
-    private @LabelStatus int mLabelStatus;
-
-    private ColorStateList mDefaultLineColor;
-    private @ColorInt int mErrorColor;
-    private float mExpandedTextScale;
-    private float mCollapsedLabelTranslationY;
-    private float mExpandedLabelTranslationY;
-
-    // Needed for #ensureBackgroundDrawableStateWorkaround().
-    private boolean mHasReconstructedEditTextBackground;
-
-    public ChromeTextInputLayout(Context context) {
-        this(context, null);
-    }
-
-    public ChromeTextInputLayout(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public ChromeTextInputLayout(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-
-        setOrientation(VERTICAL);
-
-        final TypedArray a =
-                context.obtainStyledAttributes(attrs, R.styleable.ChromeTextInputLayout);
-        mHint = a.getText(R.styleable.ChromeTextInputLayout_hint);
-
-        mLabel = new TextView(context);
-        mLabel.setPaddingRelative(
-                getResources().getDimensionPixelSize(R.dimen.text_input_layout_padding_start), 0, 0,
-                0);
-        ApiCompatibilityUtils.setTextAppearance(mLabel,
-                a.getResourceId(R.styleable.ChromeTextInputLayout_hintTextAppearance,
-                        R.style.TextAppearance_TextSmall_Secondary));
-        mLabel.setPivotX(0f);
-        mLabel.setPivotY(mLabel.getPaint().getFontMetrics().bottom);
-        mLabelStatus = LabelStatus.COLLAPSED;
-        addView(mLabel, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
-        mCollapsedLabelTranslationY = mLabel.getPaint().getFontMetrics().descent;
-        mLabel.setTranslationY(mCollapsedLabelTranslationY);
-
-        // A FrameLayout is put in the place of the EditText when the class is first instantiated.
-        // When #addView is called with an EditText, whether because the layout is inflated from an
-        // xml or an EditText is added programmatically, this FrameLayout is replaced with the
-        // EditText.
-        mFrame = new FrameLayout(context);
-        addView(mFrame, -1);
-
-        mErrorText = new TextView(context);
-        mErrorText.setTextAppearance(getContext(),
-                a.getResourceId(R.styleable.ChromeTextInputLayout_errorTextAppearance,
-                        R.style.TextAppearance_ErrorCaption));
-        mErrorText.setVisibility(View.GONE);
-        mErrorText.setPaddingRelative(
-                getResources().getDimensionPixelSize(R.dimen.text_input_layout_padding_start), 0, 0,
-                0);
-        mErrorColor = mErrorText.getCurrentTextColor();
-        addView(mErrorText, -1);
-
-        a.recycle();
-
-        mDefaultLineColor = new ColorStateList(
-                new int[][] {new int[] {android.R.attr.state_focused}, new int[] {}},
-                new int[] {getColorAttribute(context, R.attr.colorControlActivated),
-                        getColorAttribute(context, R.attr.colorControlNormal)});
-
-        mLabel.setTextColor(new ColorStateList(
-                new int[][] {new int[] {android.R.attr.state_activated}, new int[] {}},
-                new int[] {getColorAttribute(context, R.attr.colorControlActivated),
-                        mLabel.getCurrentTextColor()}));
-
-        setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
-        ViewCompat.setAccessibilityDelegate(this, new AccessibilityDelegate());
-    }
-
-    /**
-     * Set the error to display below the EditText. Passing an empty {@link CharSequence} or null
-     * clears the error.
-     * @param error The error text.
-     */
-    public void setError(CharSequence error) {
-        if (TextUtils.isEmpty(error) && TextUtils.isEmpty(mErrorText.getText())) {
-            return;
-        }
-
-        assert mEditText != null;
-        mShouldDisplayError = !TextUtils.isEmpty(error);
-        mErrorText.setText(error);
-        mErrorText.setVisibility(mShouldDisplayError ? View.VISIBLE : View.GONE);
-
-        // Fixes issues with Android L where the line's error color wouldn't be cleared after
-        // leaving the activity; and KitKat where the line wouldn't get tinted when showing an
-        // error. crbug.com/1020077.
-        ensureBackgroundDrawableStateWorkaround();
-        if (mShouldDisplayError) {
-            // Tinting doesn't really work on KitKat, so use a color filter instead.
-            mEditText.getBackground().setColorFilter(
-                    AppCompatDrawableManager.getPorterDuffColorFilter(
-                            mErrorColor, PorterDuff.Mode.SRC_IN));
-        } else {
-            DrawableCompat.clearColorFilter(mEditText.getBackground());
-            mEditText.refreshDrawableState();
-        }
-
-        ViewCompat.setAccessibilityLiveRegion(
-                mErrorText, ViewCompat.ACCESSIBILITY_LIVE_REGION_POLITE);
-        updateLabelState(true);
-    }
-
-    /**
-     * @return The error text.
-     */
-    public CharSequence getError() {
-        return mErrorText.getText();
-    }
-
-    /**
-     * @return The {@link android.widget.EditText}.
-     */
-    public EditText getEditText() {
-        return mEditText;
-    }
-
-    /**
-     * Set the hint to be displayed in the floating label.
-     * @param hint The hint text.
-     */
-    public void setHint(CharSequence hint) {
-        mHint = hint;
-        updateLabel();
-        // TODO(sinansahin): We're mirroring the Android code here, but investigate if we need to
-        // send this event, probably after updating the support library.
-        sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
-        updateLabelState(false);
-    }
-
-    /**
-     * @return The hint text.
-     */
-    public CharSequence getHint() {
-        return mHint;
-    }
-
-    /**
-     * Add a {@link OnEditTextFocusChangeListener}. This method should be used instead of
-     * {@link EditText#setOnFocusChangeListener}.
-     * @param listener The {@link OnEditTextFocusChangeListener} to add.
-     */
-    public void addEditTextOnFocusChangeListener(OnEditTextFocusChangeListener listener) {
-        mListeners.add(listener);
-    }
-
-    /**
-     * Remove a {@link OnEditTextFocusChangeListener}.
-     * @param listener The {@link OnEditTextFocusChangeListener} to remove.
-     */
-    public void removeEditTextOnFocusChangeListener(OnEditTextFocusChangeListener listener) {
-        mListeners.remove(listener);
-    }
-
-    @Override
-    public final void addView(View child, int index, ViewGroup.LayoutParams params) {
-        if (child instanceof EditText) {
-            setEditText((EditText) child);
-
-            // Replace the placeholder FrameLayout with the real EditText.
-            ViewGroup parent = (ViewGroup) mFrame.getParent();
-            index = parent.indexOfChild(mFrame);
-            parent.removeView(mFrame);
-            mFrame = null;
-        }
-
-        // Carry on adding the View.
-        super.addView(child, index, params);
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        if (mExpandedLabelTranslationY == 0) {
-            mExpandedLabelTranslationY = mEditText.getBaseline();
-            if (mLabelStatus == LabelStatus.EXPANDED) {
-                mLabel.setTranslationY(mExpandedLabelTranslationY);
-            }
-        }
-    }
-
-    private void updateLabel() {
-        mLabel.setText(mHint);
-        final Rect bounds = new Rect();
-        mLabel.getPaint().getTextBounds(
-                mLabel.getText().toString(), 0, mLabel.getText().length(), bounds);
-        final float width = bounds.width();
-        mLabel.setPivotX(LocalizationUtils.isLayoutRtl() ? width : 0);
-    }
-
-    private void setEditText(EditText editText) {
-        // If we already have an EditText, throw an exception.
-        if (mEditText != null) {
-            throw new IllegalArgumentException("We already have an EditText, can only have one");
-        }
-        mEditText = editText;
-        DrawableCompat.setTintList(mEditText.getBackground().mutate(), mDefaultLineColor);
-        mExpandedTextScale = mEditText.getTextSize() / mLabel.getTextSize();
-        mEditText.setOnFocusChangeListener((v, hasFocus) -> {
-            notifyEditTextFocusChanged(v, hasFocus);
-            updateLabelState(true);
-        });
-        mEditText.addTextChangedListener(new TextWatcher() {
-            @Override
-            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
-
-            @Override
-            public void onTextChanged(CharSequence s, int start, int before, int count) {}
-
-            @Override
-            public void afterTextChanged(Editable s) {
-                updateLabelState(false);
-            }
-        });
-
-        // If we do not have a valid hint, try and retrieve it from the EditText.
-        if (TextUtils.isEmpty(mHint)) {
-            setHint(mEditText.getHint());
-            mEditText.setHint(null);
-        }
-
-        updateLabel();
-        updateLabelState(false);
-    }
-
-    private void updateLabelState(boolean animate) {
-        final boolean hasText = !TextUtils.isEmpty(mEditText.getText());
-        final boolean isFocused = mEditText.isFocused();
-
-        mLabel.setActivated(isFocused);
-
-        if (mLabelStatus == LabelStatus.ANIMATING) {
-            mLabel.clearAnimation();
-        }
-        if (hasText || isFocused || mShouldDisplayError) {
-            // The label should be collapsed.
-            collapseLabel(animate);
-        } else {
-            // The label should be expanded.
-            expandLabel(animate);
-        }
-    }
-
-    /**
-     * Collapse the label (shrink and move up).
-     * @param animate Whether we should animate the label collapsing.
-     */
-    private void collapseLabel(boolean animate) {
-        if (animate) {
-            ViewCompat.animate(mLabel)
-                    .translationY(mCollapsedLabelTranslationY)
-                    .scaleY(1f)
-                    .scaleX(1f)
-                    .setDuration(ANIMATION_DURATION_MS)
-                    .setListener(new ViewPropertyAnimatorListenerAdapter() {
-                        @Override
-                        public void onAnimationEnd(View view) {
-                            mLabelStatus = LabelStatus.COLLAPSED;
-                        }
-                    })
-                    .setInterpolator(Interpolators.FAST_OUT_SLOW_IN_INTERPOLATOR)
-                    .start();
-        } else {
-            mLabel.setTranslationY(mCollapsedLabelTranslationY);
-            mLabel.setScaleX(1f);
-            mLabel.setScaleY(1f);
-            mLabelStatus = LabelStatus.COLLAPSED;
-        }
-    }
-
-    /**
-     * Expand the label (move down where the hint should be).
-     * @param animate Whether we should animate the label expanding.
-     */
-    private void expandLabel(boolean animate) {
-        if (animate) {
-            ViewCompat.animate(mLabel)
-                    .translationY(mExpandedLabelTranslationY)
-                    .setDuration(ANIMATION_DURATION_MS)
-                    .scaleX(mExpandedTextScale)
-                    .scaleY(mExpandedTextScale)
-                    .setListener(new ViewPropertyAnimatorListenerAdapter() {
-                        @Override
-                        public void onAnimationEnd(View view) {
-                            mLabelStatus = LabelStatus.EXPANDED;
-                        }
-                    })
-                    .setInterpolator(Interpolators.FAST_OUT_SLOW_IN_INTERPOLATOR)
-                    .start();
-        } else {
-            mLabel.setScaleX(mExpandedTextScale);
-            mLabel.setScaleY(mExpandedTextScale);
-            mLabel.setTranslationY(mExpandedLabelTranslationY);
-            mLabelStatus = LabelStatus.EXPANDED;
-        }
-    }
-
-    private void notifyEditTextFocusChanged(View v, boolean hasFocus) {
-        for (OnEditTextFocusChangeListener listener : mListeners) {
-            listener.onEditTextFocusChange(v, hasFocus);
-        }
-    }
-
-    /**
-     * Returns a color from a theme attribute.
-     * @param context Context with resources to look up.
-     * @param attribute Attribute such as R.attr.colorControlNormal.
-     * @return Color value.
-     * @throws Resources.NotFoundException
-     */
-    private int getColorAttribute(Context context, int attribute) {
-        TypedValue typedValue = new TypedValue();
-        if (!context.getTheme().resolveAttribute(attribute, typedValue, true)) {
-            throw new Resources.NotFoundException("Attribute not found.");
-        }
-
-        if (typedValue.resourceId != 0) {
-            // Attribute is a resource.
-            return ContextCompat.getColor(context, typedValue.resourceId);
-        } else if (typedValue.type >= TypedValue.TYPE_FIRST_COLOR_INT
-                && typedValue.type <= TypedValue.TYPE_LAST_COLOR_INT) {
-            // Attribute is a raw color value.
-            return typedValue.data;
-        } else {
-            throw new Resources.NotFoundException("Attribute not a color.");
-        }
-    }
-
-    /**
-     * An AccessibilityDelegate intended to be set on an {@link EditText} to provide attributes for
-     * accessibility that are managed by {@link ChromeTextInputLayout}.
-     */
-    private class AccessibilityDelegate extends AccessibilityDelegateCompat {
-        AccessibilityDelegate() {}
-
-        @Override
-        public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
-            super.onInitializeAccessibilityNodeInfo(host, info);
-            // TODO(sinansahin): Update this method to use info.setHintText() and
-            // info.setShowingHintText() once we update the support library to version 28.
-            if (mEditText != null) {
-                setLabelFor(mEditText.getId());
-            }
-            if (mShouldDisplayError) {
-                info.setContentInvalid(true);
-                info.setError(getError());
-            }
-        }
-    }
-
-    /**
-     * Workaround for issues with Android K and L. Borrowed from the support library:
-     * https://android.googlesource.com/platform/frameworks/support/+/refs/heads/oreo-r6-release/
-     * design/src/android/support/design/widget/TextInputLayout.java
-     */
-    private void ensureBackgroundDrawableStateWorkaround() {
-        final int sdk = Build.VERSION.SDK_INT;
-        if (sdk > Build.VERSION_CODES.LOLLIPOP_MR1) {
-            // The workaround is only required on API 22 and below.
-            return;
-        }
-
-        final Drawable bg = mEditText.getBackground();
-        if (bg == null) {
-            return;
-        }
-
-        if (!mHasReconstructedEditTextBackground) {
-            // This is gross. There is an issue in the platform which affects container Drawables
-            // where the first drawable retrieved from resources will propagate any changes
-            // (like color filter) to all instances from the cache. We'll try to workaround it...
-
-            final Drawable newBg = bg.getConstantState().newDrawable();
-
-            if (bg instanceof DrawableContainer) {
-                // If we have a Drawable container, we can try and set it's constant state via
-                // reflection from the new Drawable
-                mHasReconstructedEditTextBackground = DrawableUtils.setContainerConstantState(
-                        (DrawableContainer) bg, newBg.getConstantState());
-            }
-
-            if (!mHasReconstructedEditTextBackground) {
-                // If we reach here then we just need to set a brand new instance of the Drawable
-                // as the background. This has the unfortunate side-effect of wiping out any
-                // user set padding, but I'd hope that use of custom padding on an EditText
-                // is limited.
-                ViewCompat.setBackground(mEditText, newBg);
-                mHasReconstructedEditTextBackground = true;
-            }
-        }
-    }
-}
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/text/ChromeTextInputLayoutRenderTest.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/text/ChromeTextInputLayoutRenderTest.java
deleted file mode 100644
index acb64bb1..0000000
--- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/text/ChromeTextInputLayoutRenderTest.java
+++ /dev/null
@@ -1,161 +0,0 @@
-// Copyright 2019 The Chromium 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.components.browser_ui.widget.text;
-
-import android.app.Activity;
-import android.graphics.Color;
-import android.support.test.filters.MediumTest;
-import android.text.InputType;
-import android.view.ContextThemeWrapper;
-import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.appcompat.widget.AppCompatEditText;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import org.chromium.base.test.params.BaseJUnit4RunnerDelegate;
-import org.chromium.base.test.params.ParameterAnnotations;
-import org.chromium.base.test.params.ParameterSet;
-import org.chromium.base.test.params.ParameterizedRunner;
-import org.chromium.base.test.util.Feature;
-import org.chromium.components.browser_ui.widget.test.R;
-import org.chromium.content_public.browser.test.util.TestThreadUtils;
-import org.chromium.ui.base.LocalizationUtils;
-import org.chromium.ui.test.util.DummyUiActivityTestCase;
-import org.chromium.ui.test.util.NightModeTestUtils;
-import org.chromium.ui.test.util.RenderTestRule;
-
-import java.io.IOException;
-import java.util.List;
-
-/**
- * Render tests for the ChromeTextInputLayout
- */
-@RunWith(ParameterizedRunner.class)
-@ParameterAnnotations.UseRunnerDelegate(BaseJUnit4RunnerDelegate.class)
-public class ChromeTextInputLayoutRenderTest extends DummyUiActivityTestCase {
-    @ParameterAnnotations.ClassParameter
-    private static List<ParameterSet> sClassParams =
-            new NightModeTestUtils.NightModeParams().getParameters();
-
-    @Rule
-    public RenderTestRule mRenderTestRule =
-            new RenderTestRule("chrome/test/data/android/render_tests");
-
-    private static final String LABEL = "Label";
-    private static final String TEXT = "Chrome's own TextInputLayout";
-    private static final String PHONE = "+1 555-555-5555";
-    private static final String ERROR = "Error";
-
-    private final int mFakeBgColor;
-
-    private ChromeTextInputLayout mInputLayout;
-    private AppCompatEditText mEditText;
-
-    public ChromeTextInputLayoutRenderTest(boolean nightModeEnabled) {
-        // Sets a fake background color to make the screenshots easier to compare with bare eyes.
-        mFakeBgColor = nightModeEnabled ? Color.BLACK : Color.WHITE;
-        NightModeTestUtils.setUpNightModeForDummyUiActivity(nightModeEnabled);
-        mRenderTestRule.setNightModeEnabled(nightModeEnabled);
-    }
-
-    @Override
-    public void setUpTest() throws Exception {
-        super.setUpTest();
-        final Activity activity = getActivity();
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            mInputLayout = new ChromeTextInputLayout(
-                    new ContextThemeWrapper(activity, R.style.Theme_Chromium_Settings));
-            ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(
-                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
-            mInputLayout.setLayoutParams(layoutParams);
-            mInputLayout.setBackgroundColor(mFakeBgColor);
-            ((ViewGroup) activity.findViewById(android.R.id.content)).addView(mInputLayout);
-            mEditText = new AppCompatEditText(
-                    new ContextThemeWrapper(activity, R.style.Theme_Chromium_Settings));
-            mInputLayout.addView(mEditText);
-            mInputLayout.setHint(LABEL);
-            RenderTestRule.sanitize(mEditText);
-        });
-    }
-
-    @Override
-    public void tearDownTest() throws Exception {
-        NightModeTestUtils.tearDownNightModeForDummyUiActivity();
-        super.tearDownTest();
-    }
-
-    @Test
-    @MediumTest
-    @Feature({"RenderTest"})
-    public void testExpanded() throws IOException {
-        mRenderTestRule.render(mInputLayout, "expanded");
-    }
-
-    @Test
-    @MediumTest
-    @Feature({"RenderTest"})
-    public void testFocused() throws Exception {
-        TestThreadUtils.runOnUiThreadBlocking(() -> mEditText.requestFocus());
-        mRenderTestRule.render(mInputLayout, "focused");
-    }
-
-    @Test
-    @MediumTest
-    @Feature({"RenderTest"})
-    public void testFilled() throws Exception {
-        TestThreadUtils.runOnUiThreadBlocking(() -> mEditText.setText(TEXT));
-        mRenderTestRule.render(mInputLayout, "filled");
-    }
-
-    @Test
-    @MediumTest
-    @Feature({"RenderTest"})
-    public void testError() throws Exception {
-        TestThreadUtils.runOnUiThreadBlocking(() -> mInputLayout.setError(ERROR));
-        mRenderTestRule.render(mInputLayout, "error");
-    }
-
-    @Test
-    @MediumTest
-    @Feature({"RenderTest"})
-    public void testFocusedRTL() throws IOException {
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            setLayoutDirectionRTL();
-            mEditText.requestFocus();
-        });
-        mRenderTestRule.render(mInputLayout, "focused_rtl");
-    }
-
-    @Test
-    @MediumTest
-    @Feature({"RenderTest"})
-    public void testExpandedRTL() throws IOException {
-        TestThreadUtils.runOnUiThreadBlocking(this::setLayoutDirectionRTL);
-        mRenderTestRule.render(mInputLayout, "expanded_rtl");
-    }
-
-    @Test
-    @MediumTest
-    @Feature({"RenderTest"})
-    public void testPhoneRTL() throws IOException {
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            setLayoutDirectionRTL();
-            mEditText.setInputType(InputType.TYPE_CLASS_PHONE);
-        });
-        mRenderTestRule.render(mInputLayout, "phone_expanded_rtl");
-        TestThreadUtils.runOnUiThreadBlocking(() -> mEditText.setText(PHONE));
-        mRenderTestRule.render(mInputLayout, "phone_rtl");
-    }
-
-    private void setLayoutDirectionRTL() {
-        LocalizationUtils.setRtlForTesting(true);
-        mInputLayout.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
-        mInputLayout.setHint(LABEL);
-    }
-}
diff --git a/components/browser_ui/widget/android/test/java/res/values/styles.xml b/components/browser_ui/widget/android/test/java/res/values/styles.xml
deleted file mode 100644
index 0526c6a..0000000
--- a/components/browser_ui/widget/android/test/java/res/values/styles.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2019 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<resources>
-    <!-- Settings theme and styles for ChromeTextInputLayoutRenderTest -->
-    <style name="TextAppearance.PreferenceMediumText">
-        <item name="android:textSize">18sp</item>
-        <item name="android:textColor">?android:attr/textColorPrimary</item>
-    </style>
-    <style name="Base.V17.Theme.Chromium" parent="Theme.AppCompat.DayNight.NoActionBar">
-        <!-- Window Properties -->
-        <item name="android:windowBackground">@color/default_bg_color</item>
-
-        <!-- Action bar color -->
-        <item name="colorPrimary">@color/default_bg_color</item>
-
-        <!-- Text colors -->
-        <item name="android:textColorLink">@color/default_text_color_link</item>
-        <item name="android:textColorHighlight">@color/text_highlight_color</item>
-
-        <!-- Color of checkboxes, switches, buttons, etc. -->
-        <item name="colorAccent">@color/light_active_color</item>
-        <item name="colorControlNormal">@color/control_normal_color</item>
-        <item name="colorControlActivated">@color/light_active_color</item>
-        <item name="colorControlHighlight">@color/control_highlight_color</item>
-    </style>
-    <style name="Base.Theme.Chromium" parent="Base.V17.Theme.Chromium" />
-    <style name="Base.Theme.Chromium.WithActionBar">
-        <!-- With ActionBar -->
-        <item name="windowActionBar">true</item>
-        <item name="windowNoTitle">false</item>
-    </style>
-    <style name="Theme.Chromium.WithActionBar" parent="Base.Theme.Chromium.WithActionBar" />
-    <style name="Base.Theme.Chromium.Settings" parent="Theme.Chromium.WithActionBar" />
-    <style name="Theme.Chromium.Settings" parent="Base.Theme.Chromium.Settings">
-        <!-- Theme attributes pre-v21 -->
-        <item name="android:textAppearanceMedium">@style/TextAppearance.PreferenceMediumText</item>
-        <item name="android:textAppearanceSmall">@style/TextAppearance.TextMedium.Secondary</item>
-        <item name="android:windowContentOverlay">@null</item>
-    </style>
-</resources>
diff --git a/components/leveldb_proto/internal/proto_database_impl_unittest.cc b/components/leveldb_proto/internal/proto_database_impl_unittest.cc
index 1e47c1f..b02aa9c 100644
--- a/components/leveldb_proto/internal/proto_database_impl_unittest.cc
+++ b/components/leveldb_proto/internal/proto_database_impl_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "components/leveldb_proto/internal/leveldb_proto_feature_list.h"
+#include "components/leveldb_proto/internal/proto_database_selector.h"
 #include "components/leveldb_proto/internal/shared_proto_database_provider.h"
 #include "components/leveldb_proto/public/proto_database_provider.h"
 #include "components/leveldb_proto/testing/proto/test_db.pb.h"
@@ -108,9 +109,11 @@
   using SharedProtoDatabaseClient::set_migration_status;
   using SharedProtoDatabaseClient::SharedProtoDatabaseClient;
 
-  TestSharedProtoDatabaseClient(scoped_refptr<SharedProtoDatabase> shared_db)
+  explicit TestSharedProtoDatabaseClient(
+      scoped_refptr<SharedProtoDatabase> shared_db)
       : SharedProtoDatabaseClient::SharedProtoDatabaseClient(
-            nullptr,
+            std::make_unique<ProtoLevelDBWrapper>(shared_db->task_runner_,
+                                                  shared_db->db_.get()),
             ProtoDbType::TEST_DATABASE1,
             shared_db) {}
 
@@ -118,11 +121,18 @@
       SharedDBMetadataProto::MigrationStatus migration_status) override {
     set_migration_status(migration_status);
   }
+
+  void UpdateEntriesWithRemoveFilter(
+      std::unique_ptr<KeyValueVector> entries_to_save,
+      const KeyFilter& delete_key_filter,
+      Callbacks::UpdateCallback callback) override {
+    std::move(callback).Run(true);
+  }
 };
 
 class TestProtoDatabaseProvider : public ProtoDatabaseProvider {
  public:
-  TestProtoDatabaseProvider(const base::FilePath& profile_dir)
+  explicit TestProtoDatabaseProvider(const base::FilePath& profile_dir)
       : ProtoDatabaseProvider(profile_dir) {}
   TestProtoDatabaseProvider(const base::FilePath& profile_dir,
                             const scoped_refptr<SharedProtoDatabase>& shared_db)
@@ -156,10 +166,9 @@
   void SetUp() override {
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     ASSERT_TRUE(shared_db_temp_dir_.CreateUniqueTempDir());
-    test_task_runner_ =
-        base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()});
     shared_db_ = base::WrapRefCounted(new SharedProtoDatabase(
         kDefaultClientName, shared_db_temp_dir_.GetPath()));
+    test_task_runner_ = shared_db_->database_task_runner_for_testing();
   }
 
   void TearDown() override { shared_db_->Shutdown(); }
@@ -275,16 +284,19 @@
     scoped_refptr<ProtoDatabaseSelector> selector(new ProtoDatabaseSelector(
         ProtoDbType::TEST_DATABASE1, GetTestThreadTaskRunner(), nullptr));
 
-    selector->OnGetSharedDBClient(
-        std::move(unique_db), unique_db_status, use_shared_db,
+    GetTestThreadTaskRunner()->PostTask(
+        FROM_HERE,
         base::BindOnce(
-            [](base::OnceClosure closure, Enums::InitStatus expect_status,
-               Enums::InitStatus status) {
-              ASSERT_EQ(status, expect_status);
-              std::move(closure).Run();
-            },
-            init_loop.QuitClosure(), expect_status),
-        std::move(shared_db_client), shared_db_status);
+            &ProtoDatabaseSelector::OnGetSharedDBClient, selector,
+            std::move(unique_db), unique_db_status, use_shared_db,
+            base::BindOnce(
+                [](base::OnceClosure closure, Enums::InitStatus expect_status,
+                   Enums::InitStatus status) {
+                  ASSERT_EQ(status, expect_status);
+                  std::move(closure).Run();
+                },
+                init_loop.QuitClosure(), expect_status),
+            std::move(shared_db_client), shared_db_status));
 
     init_loop.Run();
 
@@ -523,6 +535,42 @@
 }
 
 TYPED_TEST(ProtoDatabaseImplTest,
+           SucceedsWithShared_UseShared_HasSharedDB_MigratedUniqueWasDeleted) {
+  auto shared_db_client = this->GetSharedClient();
+
+  // Database has been migrated to Unique.
+  shared_db_client->set_migration_status(
+      SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SUCCESSFUL);
+
+  // If we request a shared DB, the unique DB fails does not exist and
+  // the data has been migrated to the unique DB then we return shared db.
+  this->CallOnGetSharedDBClientAndWait(
+      nullptr,                               // Unique DB fails to open.
+      Enums::InitStatus::kInvalidOperation,  // Unique DB missing.
+      true,                                  // We should be using a shared DB.
+      std::move(shared_db_client),           // Shared DB opens fine.
+      Enums::InitStatus::kOK,
+      Enums::InitStatus::kOK);  // Returns shared db.
+
+  shared_db_client = this->GetSharedClient();
+
+  // Data has been migrated to Unique, but data still exists in Shared DB that
+  // should be removed.
+  shared_db_client->set_migration_status(
+      SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SHARED_TO_BE_DELETED);
+
+  // This second scenario occurs when the Shared DB still contains data, we
+  // should still clear shared and return it.
+  this->CallOnGetSharedDBClientAndWait(
+      nullptr,                               // Unique DB fails to open.
+      Enums::InitStatus::kInvalidOperation,  // Unique DB missing.
+      true,                                  // We should be using a shared DB.
+      std::move(shared_db_client),           // Shared DB opens fine.
+      Enums::InitStatus::kOK,
+      Enums::InitStatus::kOK);  // Returns shared db
+}
+
+TYPED_TEST(ProtoDatabaseImplTest,
            Fails_UseShared_HasSharedDB_DataWasMigratedToUnique) {
   auto shared_db_client = this->GetSharedClient();
 
@@ -534,10 +582,10 @@
   // the data has been migrated to the unique DB then we throw an error, as the
   // unique database may contain data.
   this->CallOnGetSharedDBClientAndWait(
-      nullptr,                               // Unique DB fails to open.
-      Enums::InitStatus::kInvalidOperation,  // Unique DB doesn't exist.
-      true,                                  // We should be using a shared DB.
-      std::move(shared_db_client),           // Shared DB opens fine.
+      nullptr,                      // Unique DB fails to open.
+      Enums::InitStatus::kError,    // Unique DB failure.
+      true,                         // We should be using a shared DB.
+      std::move(shared_db_client),  // Shared DB opens fine.
       Enums::InitStatus::kOK,
       Enums::InitStatus::kError);  // Then the DB impl should throw an error.
 
diff --git a/components/leveldb_proto/internal/proto_database_selector.cc b/components/leveldb_proto/internal/proto_database_selector.cc
index beb2dc0..822da33 100644
--- a/components/leveldb_proto/internal/proto_database_selector.cc
+++ b/components/leveldb_proto/internal/proto_database_selector.cc
@@ -258,13 +258,24 @@
         break;
       case SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SUCCESSFUL:
       case SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SHARED_TO_BE_DELETED:
+        if (unique_db_status == Enums::kInvalidOperation) {
+          // If unique db does not exist and migration state expects it, reset
+          // the migration state since this is not recoverable, and return the
+          // shared db. Clear the shared db since it might contain stale data.
+          SharedProtoDatabaseClient* client_ptr = client.get();
+          client_ptr->UpdateEntriesWithRemoveFilter(
+              std::make_unique<KeyValueVector>(),
+              base::BindRepeating([](const std::string& key) { return true; }),
+              base::BindOnce(&ProtoDatabaseSelector::
+                                 InvokeInitUniqueDbMissingSharedCleared,
+                             this, std::move(client), std::move(callback)));
+          return;
+        }
         // If the unique DB failed to open, and the data is located on it then
-        // we throw an error. We ignore the deletion flag because we want both
-        // databases to be open before we delete the shared DB.
+        // we throw an error.
         std::move(callback).Run(Enums::InitStatus::kError);
         OnInitDone(ProtoDatabaseInitState::kUniqueDbOpenFailed);
         return;
-        break;
     }
   }
 
@@ -604,6 +615,24 @@
   db_->RemoveKeysForTesting(key_filter, target_prefix, std::move(callback));
 }
 
+void ProtoDatabaseSelector::InvokeInitUniqueDbMissingSharedCleared(
+    std::unique_ptr<SharedProtoDatabaseClient> client,
+    Callbacks::InitStatusCallback callback,
+    bool shared_cleared) {
+  if (!shared_cleared) {
+    OnInitDone(
+        ProtoDatabaseInitState::kFailureUniqueDbMissingClearSharedFailed);
+    std::move(callback).Run(Enums::InitStatus::kError);
+    return;
+  }
+  // Reset state to migrated to shared since unique db is missing.
+  client->UpdateClientInitMetadata(
+      SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL);
+  db_ = std::move(client);
+  OnInitDone(ProtoDatabaseInitState::kUniqueDbMissingSharedReturned);
+  std::move(callback).Run(Enums::InitStatus::kOK);
+}
+
 void ProtoDatabaseSelector::OnInitDone(
     ProtoDatabaseSelector::ProtoDatabaseInitState state) {
   RecordInitState(state);
diff --git a/components/leveldb_proto/internal/proto_database_selector.h b/components/leveldb_proto/internal/proto_database_selector.h
index 688ed33a9..a15954f 100644
--- a/components/leveldb_proto/internal/proto_database_selector.h
+++ b/components/leveldb_proto/internal/proto_database_selector.h
@@ -61,7 +61,8 @@
     kSharedDbClientMissing = 25,
     kFailureNoSharedDBProviderUniqueFailed = 26,
     kSuccessNoSharedDBProviderUniqueSucceeded = 27,
-    kMaxValue = kSuccessNoSharedDBProviderUniqueSucceeded,
+    kFailureUniqueDbMissingClearSharedFailed = 28,
+    kMaxValue = kFailureUniqueDbMissingClearSharedFailed,
   };
 
   static void RecordInitState(ProtoDatabaseInitState state);
@@ -185,6 +186,10 @@
       Callbacks::InitStatusCallback callback,
       bool success);
   void OnInitDone(ProtoDatabaseInitState state);
+  void InvokeInitUniqueDbMissingSharedCleared(
+      std::unique_ptr<SharedProtoDatabaseClient> client,
+      Callbacks::InitStatusCallback,
+      bool shared_cleared);
 
   ProtoDbType db_type_;
   const scoped_refptr<base::SequencedTaskRunner> task_runner_;
diff --git a/components/leveldb_proto/internal/shared_proto_database.h b/components/leveldb_proto/internal/shared_proto_database.h
index 11cbed6..8303ad0 100644
--- a/components/leveldb_proto/internal/shared_proto_database.h
+++ b/components/leveldb_proto/internal/shared_proto_database.h
@@ -68,6 +68,7 @@
   friend class SharedProtoDatabaseTest;
   friend class SharedProtoDatabaseClientTest;
   friend class TestSharedProtoDatabase;
+  friend class TestSharedProtoDatabaseClient;
   FRIEND_TEST_ALL_PREFIXES(SharedProtoDatabaseTest,
                            CancelDeleteObsoleteClients);
   FRIEND_TEST_ALL_PREFIXES(SharedProtoDatabaseTest, DeleteObsoleteClients);
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer.cc b/components/page_load_metrics/browser/metrics_web_contents_observer.cc
index 9340231..a95eacee 100644
--- a/components/page_load_metrics/browser/metrics_web_contents_observer.cc
+++ b/components/page_load_metrics/browser/metrics_web_contents_observer.cc
@@ -17,8 +17,10 @@
 #include "components/page_load_metrics/browser/page_load_metrics_util.h"
 #include "components/page_load_metrics/browser/page_load_tracker.h"
 #include "components/page_load_metrics/common/page_load_timing.h"
+#include "content/public/browser/back_forward_cache.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/global_request_id.h"
+#include "content/public/browser/global_routing_id.h"
 #include "content/public/browser/media_player_id.h"
 #include "content/public/browser/navigation_details.h"
 #include "content/public/browser/navigation_handle.h"
@@ -151,6 +153,14 @@
     committed_load_->FrameDeleted(rfh);
 }
 
+void MetricsWebContentsObserver::RenderFrameDeleted(
+    content::RenderFrameHost* rfh) {
+  // PageLoadTracker can be associated only with a main frame.
+  if (rfh->GetParent())
+    return;
+  back_forward_cached_pages_.erase(rfh);
+}
+
 void MetricsWebContentsObserver::MediaStartedPlaying(
     const content::WebContentsObserver::MediaPlayerInfo& video_type,
     const content::MediaPlayerId& id) {
@@ -443,7 +453,14 @@
     // the currently committed navigation.
     FinalizeCurrentlyCommittedLoad(navigation_handle,
                                    navigation_handle_tracker.get());
-    committed_load_.reset();
+    // Transfers the ownership of |committed_load_|. This |committed_load_|
+    // might be reused later when restoring the page from the cache.
+    MaybeStorePageLoadTrackerForBackForwardCache(navigation_handle,
+                                                 std::move(committed_load_));
+    // If |navigation_handle| is a back-forward cache navigation, an associated
+    // PageLoadTracker is restored into |committed_load_|.
+    if (MaybeRestorePageLoadTrackerForBackForwardCache(navigation_handle))
+      return;
   }
 
   if (!navigation_handle_tracker)
@@ -502,6 +519,54 @@
     observer.OnCommit(committed_load_.get());
 }
 
+void MetricsWebContentsObserver::MaybeStorePageLoadTrackerForBackForwardCache(
+    content::NavigationHandle* next_navigation_handle,
+    std::unique_ptr<PageLoadTracker> previously_committed_load) {
+  if (!previously_committed_load)
+    return;
+
+  content::RenderFrameHost* previous_frame = content::RenderFrameHost::FromID(
+      next_navigation_handle->GetPreviousRenderFrameHostId());
+
+  // The PageLoadTracker is associated with a bfcached document if:
+  bool is_back_forward_cache =
+      // 1. the frame being navigated away from was not already deleted
+      previous_frame &&
+      // 2. the previous frame is in the BFCache
+      previous_frame->IsInBackForwardCache();
+
+  if (!is_back_forward_cache)
+    return;
+
+  previously_committed_load->OnEnterBackForwardCache();
+
+  back_forward_cached_pages_.emplace(previous_frame,
+                                     std::move(previously_committed_load));
+}
+
+bool MetricsWebContentsObserver::MaybeRestorePageLoadTrackerForBackForwardCache(
+    content::NavigationHandle* navigation_handle) {
+  if (!navigation_handle->IsServedFromBackForwardCache())
+    return false;
+
+  auto it =
+      back_forward_cached_pages_.find(navigation_handle->GetRenderFrameHost());
+
+  // There are some cases that the PageLoadTracker does not exist. For example,
+  // if a page is put into the cache before MetricsWebContents is created,
+  // |back_forward_cached_pages_| is empty.
+  if (it == back_forward_cached_pages_.end())
+    return false;
+
+  committed_load_ = std::move(it->second);
+  back_forward_cached_pages_.erase(it);
+  // TODO(hajimehoshi): Add dedicated methods to PageLoadMetricsTracker to allow
+  // them to observe pages being restored from bfcache.
+  if (web_contents()->GetVisibility() == content::Visibility::VISIBLE)
+    committed_load_->PageShown();
+  return true;
+}
+
 void MetricsWebContentsObserver::FinalizeCurrentlyCommittedLoad(
     content::NavigationHandle* newly_committed_navigation,
     PageLoadTracker* newly_committed_navigation_tracker) {
@@ -527,11 +592,6 @@
     if (is_non_user_initiated_client_redirect) {
       committed_load_->NotifyClientRedirectTo(newly_committed_navigation);
     }
-
-    content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(
-        newly_committed_navigation->GetPreviousRenderFrameHostId());
-    if (rfh && rfh->IsInBackForwardCache())
-      committed_load_->OnEnterBackForwardCache();
   }
 }
 
@@ -777,6 +837,8 @@
   if (embedder_interface_->IsNewTabPageUrl(navigation_handle->GetURL()))
     return false;
 
+  // The navigation served from the back-forward cache will use the previously
+  // created tracker for the document.
   if (navigation_handle->IsServedFromBackForwardCache())
     return false;
 
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer.h b/components/page_load_metrics/browser/metrics_web_contents_observer.h
index 6e5b154..5156ed0 100644
--- a/components/page_load_metrics/browser/metrics_web_contents_observer.h
+++ b/components/page_load_metrics/browser/metrics_web_contents_observer.h
@@ -108,6 +108,7 @@
   void RenderViewHostChanged(content::RenderViewHost* old_host,
                              content::RenderViewHost* new_host) override;
   void FrameDeleted(content::RenderFrameHost* render_frame_host) override;
+  void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
   void MediaStartedPlaying(
       const content::WebContentsObserver::MediaPlayerInfo& video_type,
       const content::MediaPlayerId& id) override;
@@ -238,6 +239,20 @@
   void OnBrowserFeatureUsage(content::RenderFrameHost* render_frame_host,
                              const mojom::PageLoadFeatures& new_features);
 
+  // Before deleting PageLoadTracker, check if we need to keep it alive as the
+  // page is stored in back-forward cache. The page can either be restored later
+  // (we will be notified via DidFinishNavigation and NavigationHandle::
+  // IsServedFromBackForwardCache) or will be evicted from the cache (we will be
+  // notified via RenderFrameDeleted).
+  void MaybeStorePageLoadTrackerForBackForwardCache(
+      content::NavigationHandle* next_navigation_handle,
+      std::unique_ptr<PageLoadTracker> page_load_tracker);
+
+  // Try to restore a PageLoadTracker when a navigation restores corresponding
+  // page from back-forward cache. Returns true if the page was restored.
+  bool MaybeRestorePageLoadTrackerForBackForwardCache(
+      content::NavigationHandle* navigation_handle);
+
   // True if the web contents is currently in the foreground.
   bool in_foreground_;
 
@@ -261,6 +276,14 @@
 
   std::unique_ptr<PageLoadTracker> committed_load_;
 
+  // A page can be stored in back-forward cache - in this case its
+  // PageLoadTracker should be preserved as well. Here we store PageLoadTracker
+  // for each main frame that we navigated away from until we are notified that
+  // it is deleted (would happen almost immediately if back-forward cache is not
+  // enabled or page is not stored).
+  base::flat_map<content::RenderFrameHost*, std::unique_ptr<PageLoadTracker>>
+      back_forward_cached_pages_;
+
   // Has the MWCO observed at least one navigation?
   bool has_navigated_;
 
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc b/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
index c9d7574..e5898fa 100644
--- a/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
+++ b/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
@@ -1460,6 +1460,22 @@
 
 class MetricsWebContentsObserverBackForwardCacheTest
     : public MetricsWebContentsObserverTest {
+  class CreatedPageLoadTrackerObserver
+      : public MetricsWebContentsObserver::TestingObserver {
+   public:
+    explicit CreatedPageLoadTrackerObserver(content::WebContents* web_contents)
+        : MetricsWebContentsObserver::TestingObserver(web_contents) {}
+
+    int tracker_committed_count() const { return tracker_committed_count_; }
+
+    void OnCommit(PageLoadTracker* tracker) override {
+      tracker_committed_count_++;
+    }
+
+   private:
+    int tracker_committed_count_ = 0;
+  };
+
  public:
   MetricsWebContentsObserverBackForwardCacheTest() {
     feature_list_.InitWithFeaturesAndParameters(
@@ -1470,8 +1486,21 @@
 
   ~MetricsWebContentsObserverBackForwardCacheTest() override = default;
 
+  int tracker_committed_count() const {
+    return created_page_load_tracker_observer_->tracker_committed_count();
+  }
+
+  void SetUp() override {
+    MetricsWebContentsObserverTest::SetUp();
+    created_page_load_tracker_observer_ =
+        std::make_unique<CreatedPageLoadTrackerObserver>(web_contents());
+    observer()->AddTestingObserver(created_page_load_tracker_observer_.get());
+  }
+
  private:
   base::test::ScopedFeatureList feature_list_;
+  std::unique_ptr<CreatedPageLoadTrackerObserver>
+      created_page_load_tracker_observer_;
 };
 
 TEST_F(MetricsWebContentsObserverBackForwardCacheTest,
@@ -1514,24 +1543,36 @@
 
   ASSERT_EQ(0, CountCompleteTimingReported());
   EXPECT_EQ(0, CountOnBackForwardCacheEntered());
+  EXPECT_EQ(1, tracker_committed_count());
 
   // Go to the URL2.
   content::NavigationSimulator::NavigateAndCommitFromBrowser(
       web_contents(), GURL(kDefaultTestUrl2));
   ASSERT_EQ(main_rfh()->GetLastCommittedURL().spec(), GURL(kDefaultTestUrl2));
 
+  // With the default implementation of PageLoadMetricsObserver,
+  // OnEnteringBackForwardCache invokes OnComplete and returns STOP_OBSERVING.
   ASSERT_EQ(1, CountCompleteTimingReported());
   EXPECT_EQ(1, CountOnBackForwardCacheEntered());
+  EXPECT_EQ(2, tracker_committed_count());
 
   // Go back.
   content::NavigationSimulator::GoBack(web_contents());
   EXPECT_EQ(2, CountOnBackForwardCacheEntered());
 
-  // With the default implementation of PageLoadMetricsObserver,
-  // OnEnteringBackForwardCache invokes OnComplete and returns STOP_OBSERVING.
+  // Again, OnComplete is assured to be called.
   ASSERT_EQ(2, CountCompleteTimingReported());
+
+  // A new page load tracker is not created or committed. A page load tracker in
+  // the cache is used instead.
+  EXPECT_EQ(2, tracker_committed_count());
 }
 
+// TODO(hajimehoshi): Detect the document eviction so that PageLoadTracker in
+// the cache is destroyed. This would call PageLoadMetricsObserver::OnComplete.
+// This test can be implemented after a PageLoadMetricsObserver's
+// OnEnterBackForwardCache returns CONTINUE_OBSERVING.
+
 class MetricsWebContentsObserverBackForwardCacheDisabledTest
     : public MetricsWebContentsObserverTest {
  public:
diff --git a/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.cc b/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.cc
index 6a24cf43..10435487 100644
--- a/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.cc
+++ b/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.cc
@@ -154,6 +154,7 @@
   resource.is_subframe = resource_type_ == ResourceType::kSubFrame;
   resource.threat_type = threat_type;
   resource.threat_metadata = metadata;
+  resource.resource_type = resource_type_;
   resource.callback =
       base::BindRepeating(&SafeBrowsingUrlCheckerImpl::OnBlockingPageComplete,
                           weak_factory_.GetWeakPtr());
diff --git a/components/security_interstitials/DEPS b/components/security_interstitials/DEPS
index 459dc55..71b1307 100644
--- a/components/security_interstitials/DEPS
+++ b/components/security_interstitials/DEPS
@@ -4,6 +4,7 @@
   "+components/metrics",
   "+components/prefs",
   "+components/rappor",
+  "+components/safe_browsing/core/common",
   "+components/safe_browsing/core/db",
   "+components/ssl_errors",
   "+components/strings/grit/components_strings.h",
diff --git a/components/security_interstitials/core/BUILD.gn b/components/security_interstitials/core/BUILD.gn
index f899dd33..c4a453c4 100644
--- a/components/security_interstitials/core/BUILD.gn
+++ b/components/security_interstitials/core/BUILD.gn
@@ -72,6 +72,7 @@
 
   deps = [
     "//base",
+    "//components/safe_browsing/core/common:common",
     "//components/safe_browsing/core/db:hit_report",
     "//components/safe_browsing/core/db:util",
     "//net",
diff --git a/components/security_interstitials/core/unsafe_resource.cc b/components/security_interstitials/core/unsafe_resource.cc
index 2a75b2a..683b6c8 100644
--- a/components/security_interstitials/core/unsafe_resource.cc
+++ b/components/security_interstitials/core/unsafe_resource.cc
@@ -12,6 +12,7 @@
     : is_subresource(false),
       is_subframe(false),
       threat_type(safe_browsing::SB_THREAT_TYPE_SAFE),
+      resource_type(safe_browsing::ResourceType::kMainFrame),
       threat_source(safe_browsing::ThreatSource::UNKNOWN),
       is_delayed_warning(false) {}
 
diff --git a/components/security_interstitials/core/unsafe_resource.h b/components/security_interstitials/core/unsafe_resource.h
index 6283f90..c424dca 100644
--- a/components/security_interstitials/core/unsafe_resource.h
+++ b/components/security_interstitials/core/unsafe_resource.h
@@ -10,6 +10,7 @@
 #include "base/callback.h"
 #include "base/memory/ref_counted.h"
 #include "base/single_thread_task_runner.h"
+#include "components/safe_browsing/core/common/safebrowsing_constants.h"
 #include "components/safe_browsing/core/db/hit_report.h"
 #include "url/gurl.h"
 
@@ -52,6 +53,7 @@
   bool is_subframe;
   safe_browsing::SBThreatType threat_type;
   safe_browsing::ThreatMetadata threat_metadata;
+  safe_browsing::ResourceType resource_type;
   UrlCheckCallback callback;  // This is called back on |callback_thread|.
   scoped_refptr<base::SingleThreadTaskRunner> callback_thread;
   base::RepeatingCallback<content::WebContents*(void)> web_contents_getter;
diff --git a/components/signin/core/browser/chrome_connected_header_helper.cc b/components/signin/core/browser/chrome_connected_header_helper.cc
index c40f6c2..56e2f2bf 100644
--- a/components/signin/core/browser/chrome_connected_header_helper.cc
+++ b/components/signin/core/browser/chrome_connected_header_helper.cc
@@ -32,6 +32,10 @@
 const char kIsSamlAttrName[] = "is_saml";
 const char kProfileModeAttrName[] = "mode";
 const char kServiceTypeAttrName[] = "action";
+#if defined(OS_ANDROID)
+const char kEligibleForConsistency[] = "eligible_for_consistency";
+const char kShowConsistencyPromo[] = "show_consistency_promo";
+#endif
 
 // Determines the service type that has been passed from Gaia in the header.
 GAIAServiceType GetGAIAServiceTypeFromHeader(const std::string& header_value) {
@@ -90,6 +94,10 @@
       params.continue_url = value;
     } else if (key_name == kIsSameTabAttrName) {
       params.is_same_tab = value == "true";
+#if defined(OS_ANDROID)
+    } else if (key_name == kShowConsistencyPromo) {
+      params.show_consistency_promo = value == "true";
+#endif
     } else {
       DLOG(WARNING) << "Unexpected Gaia header attribute '" << key_name << "'.";
     }
@@ -177,8 +185,14 @@
 // filtered upstream and we want to enforce account consistency in Public
 // Sessions and Active Directory logins.
 #if !defined(OS_CHROMEOS)
-  if (gaia_id.empty())
+  if (gaia_id.empty()) {
+#if defined(OS_ANDROID)
+    if (base::FeatureList::IsEnabled(kMobileIdentityConsistency)) {
+      return base::StringPrintf("%s=%s", kEligibleForConsistency, "true");
+    }
+#endif  // defined(OS_ANDROID)
     return std::string();
+  }
 #endif  // !defined(OS_CHROMEOS)
 
   std::vector<std::string> parts;
diff --git a/components/signin/core/browser/signin_header_helper.h b/components/signin/core/browser/signin_header_helper.h
index 0c9cdf7..f83b288 100644
--- a/components/signin/core/browser/signin_header_helper.h
+++ b/components/signin/core/browser/signin_header_helper.h
@@ -9,6 +9,7 @@
 #include <string>
 #include <vector>
 
+#include "build/build_config.h"
 #include "components/prefs/pref_member.h"
 #include "components/signin/public/base/account_consistency_method.h"
 #include "components/signin/public/base/signin_buildflags.h"
@@ -75,6 +76,10 @@
   std::string continue_url;
   // Whether the continue URL should be loaded in the same tab.
   bool is_same_tab;
+#if defined(OS_ANDROID)
+  // Whether to show consistency promo.
+  bool show_consistency_promo;
+#endif
 
   ManageAccountsParams();
   ManageAccountsParams(const ManageAccountsParams& other);
diff --git a/components/signin/core/browser/signin_header_helper_unittest.cc b/components/signin/core/browser/signin_header_helper_unittest.cc
index 2f6e6a3..36553a5 100644
--- a/components/signin/core/browser/signin_header_helper_unittest.cc
+++ b/components/signin/core/browser/signin_header_helper_unittest.cc
@@ -139,6 +139,21 @@
                            "consistency_enabled_by_default=false");
 }
 #else  // !defined(OS_CHROMEOS)
+#if defined(OS_ANDROID)
+// Tests that Mirror request is returned on Android for Public Sessions (no
+// account id), when the Mobile Identity Consistency feature is enabled.
+TEST_F(SigninHeaderHelperTest, TestMirrorRequestNoAccountIdAndroid) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(kMobileIdentityConsistency);
+
+  account_consistency_ = AccountConsistencyMethod::kMirror;
+  CheckMirrorHeaderRequest(GURL("https://docs.google.com"), "",
+                           "eligible_for_consistency=true");
+  CheckMirrorCookieRequest(GURL("https://docs.google.com"), "",
+                           "eligible_for_consistency=true");
+}
+#endif  // defined(OS_ANDROID)
+
 // Tests that no Mirror request is returned when the user is not signed in (no
 // account id), for non Chrome OS platforms.
 TEST_F(SigninHeaderHelperTest, TestNoMirrorRequestNoAccountId) {
@@ -531,15 +546,23 @@
   const char kContinueURL[] = "https://www.example.com/continue";
   const char kEmail[] = "foo@example.com";
 
-  ManageAccountsParams params = BuildManageAccountsParams(
-      base::StringPrintf("action=ADDSESSION,email=%s,is_saml=true,is_same_tab="
-                         "true,continue_url=%s",
-                         kEmail, kContinueURL));
+  std::string header = base::StringPrintf(
+      "action=ADDSESSION,email=%s,is_saml=true,"
+      "is_same_tab=true,continue_url=%s",
+      kEmail, kContinueURL);
+#if defined(OS_ANDROID)
+  header += ",show_consistency_promo=true";
+#endif
+
+  ManageAccountsParams params = BuildManageAccountsParams(header);
   EXPECT_EQ(GAIA_SERVICE_TYPE_ADDSESSION, params.service_type);
   EXPECT_EQ(kEmail, params.email);
   EXPECT_EQ(true, params.is_saml);
   EXPECT_EQ(true, params.is_same_tab);
   EXPECT_EQ(GURL(kContinueURL), params.continue_url);
+#if defined(OS_ANDROID)
+  EXPECT_EQ(true, params.show_consistency_promo);
+#endif
 }
 
 }  // namespace signin
diff --git a/components/test/data/payments/render_tests/PaymentRequestRetryTest.retry_with_payer_errors.Nexus_5X-23.png.sha1 b/components/test/data/payments/render_tests/PaymentRequestRetryTest.retry_with_payer_errors.Nexus_5X-23.png.sha1
index 0f169d13..c251925 100644
--- a/components/test/data/payments/render_tests/PaymentRequestRetryTest.retry_with_payer_errors.Nexus_5X-23.png.sha1
+++ b/components/test/data/payments/render_tests/PaymentRequestRetryTest.retry_with_payer_errors.Nexus_5X-23.png.sha1
@@ -1 +1 @@
-b13e0773a76f3c3b8a1fb3f292d9e0710f80c18d
\ No newline at end of file
+4651790fa40a205088cff59450e163528f98efca
\ No newline at end of file
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
index 8fc40df..768746236 100644
--- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -271,6 +271,10 @@
   RunHtmlTest(FILE_PATH_LITERAL("list-markers.html"));
 }
 
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AccessibilityUl) {
+  RunHtmlTest(FILE_PATH_LITERAL("ul.html"));
+}
+
 // TODO(crbug.com/1063155): in process of refactoring all tests to enable the
 // kEnableAccessibilityExposeHTMLElement flag, without doing all at the
 // same time.
@@ -1993,9 +1997,6 @@
   RunHtmlTest(FILE_PATH_LITERAL("modal-dialog-stack.html"));
 }
 
-// TODO(crbug.com/1063155) - see TODO with the same bug number above.
-#undef DumpAccessibilityTreeTest
-
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AccessibilityNavigation) {
   RunHtmlTest(FILE_PATH_LITERAL("navigation.html"));
 }
@@ -2263,10 +2264,6 @@
   RunHtmlTest(FILE_PATH_LITERAL("truncate-label.html"));
 }
 
-IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AccessibilityUl) {
-  RunHtmlTest(FILE_PATH_LITERAL("ul.html"));
-}
-
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AccessibilityVar) {
   RunHtmlTest(FILE_PATH_LITERAL("var.html"));
 }
diff --git a/content/browser/accessibility/hit_testing_browsertest.cc b/content/browser/accessibility/hit_testing_browsertest.cc
index d8971de3f..4fe50c0 100644
--- a/content/browser/accessibility/hit_testing_browsertest.cc
+++ b/content/browser/accessibility/hit_testing_browsertest.cc
@@ -26,47 +26,12 @@
 
 namespace content {
 
-// First parameter of the tuple = device scale factor
-// Second parameter = whether use-zoom-for-dsf is enabled
-using AccessibilityZoomTestParam = std::tuple<double, bool>;
-
 class AccessibilityHitTestingBrowserTest
-    : public AccessibilityContentBrowserTest,
-      public ::testing::WithParamInterface<AccessibilityZoomTestParam> {
+    : public AccessibilityContentBrowserTest {
  public:
   AccessibilityHitTestingBrowserTest() = default;
   ~AccessibilityHitTestingBrowserTest() override = default;
 
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    double device_scale_factor;
-    bool use_zoom_for_dsf;
-    std::tie(device_scale_factor, use_zoom_for_dsf) = GetParam();
-    base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-        switches::kForceDeviceScaleFactor,
-        base::StringPrintf("%.2f", device_scale_factor));
-    base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-        switches::kEnableUseZoomForDSF, use_zoom_for_dsf ? "true" : "false");
-  }
-
-  struct TestPassToString {
-    std::string operator()(
-        const ::testing::TestParamInfo<AccessibilityZoomTestParam>& info)
-        const {
-      double device_scale_factor;
-      bool use_zoom_for_dsf;
-      std::tie(device_scale_factor, use_zoom_for_dsf) = info.param;
-      std::string name = base::StringPrintf("ZoomFactor%g_UseZoomForDSF%s",
-                                            device_scale_factor,
-                                            use_zoom_for_dsf ? "On" : "Off");
-
-      // The test harness only allows alphanumeric characters and underscores
-      // in param names.
-      std::string sanitized_name;
-      base::ReplaceChars(name, ".", "_", &sanitized_name);
-      return sanitized_name;
-    }
-  };
-
   BrowserAccessibilityManager* GetRootBrowserAccessibilityManager() {
     WebContentsImpl* web_contents =
         static_cast<WebContentsImpl*>(shell()->web_contents());
@@ -215,7 +180,6 @@
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
     IsolateAllSitesForTesting(command_line);
-    AccessibilityHitTestingBrowserTest::SetUpCommandLine(command_line);
   }
 
   void SetUpOnMainThread() override {
@@ -225,19 +189,47 @@
   }
 };
 
-INSTANTIATE_TEST_SUITE_P(
-    All,
-    AccessibilityHitTestingBrowserTest,
-    ::testing::Combine(::testing::Values(1, 1.25), ::testing::Bool()),
-    AccessibilityHitTestingBrowserTest::TestPassToString());
+using AccessibilityZoomTestParam = std::tuple<double, bool>;
+
+class AccessibilityHitTestingZoomBrowserTest
+    : public AccessibilityHitTestingBrowserTest,
+      public ::testing::WithParamInterface<AccessibilityZoomTestParam> {
+ public:
+  AccessibilityHitTestingZoomBrowserTest() = default;
+  ~AccessibilityHitTestingZoomBrowserTest() override = default;
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    double device_scale_factor;
+    bool use_zoom_for_dsf;
+    std::tie(device_scale_factor, use_zoom_for_dsf) = GetParam();
+    base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+        switches::kForceDeviceScaleFactor,
+        base::StringPrintf("%.2f", device_scale_factor));
+    base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+        switches::kEnableUseZoomForDSF, use_zoom_for_dsf ? "true" : "false");
+  }
+
+  struct TestPassToString {
+    std::string operator()(
+        const ::testing::TestParamInfo<AccessibilityZoomTestParam>& info)
+        const {
+      double device_scale_factor;
+      bool use_zoom_for_dsf;
+      std::tie(device_scale_factor, use_zoom_for_dsf) = info.param;
+      return base::StringPrintf("ZoomFactor%g_UseZoomForDSF%s",
+                                device_scale_factor,
+                                use_zoom_for_dsf ? "On" : "Off");
+    }
+  };
+};
 
 INSTANTIATE_TEST_SUITE_P(
     All,
-    AccessibilityHitTestingCrossProcessBrowserTest,
-    ::testing::Combine(::testing::Values(1, 1.25), ::testing::Bool()),
-    AccessibilityHitTestingBrowserTest::TestPassToString());
+    AccessibilityHitTestingZoomBrowserTest,
+    ::testing::Combine(::testing::Values(1, 2), ::testing::Bool()),
+    AccessibilityHitTestingZoomBrowserTest::TestPassToString());
 
-IN_PROC_BROWSER_TEST_P(AccessibilityHitTestingBrowserTest,
+IN_PROC_BROWSER_TEST_P(AccessibilityHitTestingZoomBrowserTest,
                        CachingAsyncHitTest) {
   ASSERT_TRUE(embedded_test_server()->Start());
 
@@ -280,7 +272,7 @@
             hit_node->GetClippedScreenBoundsRect());
 }
 
-IN_PROC_BROWSER_TEST_P(AccessibilityHitTestingBrowserTest, HitTest) {
+IN_PROC_BROWSER_TEST_P(AccessibilityHitTestingZoomBrowserTest, HitTest) {
   ASSERT_TRUE(embedded_test_server()->Start());
 
   EXPECT_TRUE(NavigateToURL(shell(), GURL(url::kAboutBlankURL)));
@@ -322,7 +314,7 @@
             hit_node->GetClippedScreenBoundsRect());
 }
 
-IN_PROC_BROWSER_TEST_P(AccessibilityHitTestingBrowserTest,
+IN_PROC_BROWSER_TEST_F(AccessibilityHitTestingBrowserTest,
                        HitTestOutsideDocumentBoundsReturnsRoot) {
   EXPECT_TRUE(NavigateToURL(shell(), GURL(url::kAboutBlankURL)));
 
@@ -348,7 +340,7 @@
   ASSERT_EQ(ax::mojom::Role::kRootWebArea, hit_node->GetRole());
 }
 
-IN_PROC_BROWSER_TEST_P(AccessibilityHitTestingBrowserTest,
+IN_PROC_BROWSER_TEST_F(AccessibilityHitTestingBrowserTest,
                        HitTestingInIframes) {
   ASSERT_TRUE(embedded_test_server()->Start());
 
@@ -405,20 +397,20 @@
   ASSERT_EQ("Scrolled Button",
             hit_node->GetStringAttribute(ax::mojom::StringAttribute::kName));
 
-  // (50, 478) -> div in second iframe
-  hit_node = HitTestAndWaitForResult(gfx::Point(50, 478));
+  // (50, 505) -> div in second iframe
+  hit_node = HitTestAndWaitForResult(gfx::Point(50, 505));
   ASSERT_TRUE(hit_node != nullptr);
   ASSERT_EQ(ax::mojom::Role::kGenericContainer, hit_node->GetRole());
 
-  // (50, 478) -> div in second iframe
+  // (50, 505) -> div in second iframe
   // but with a different event
-  hit_node = HitTestAndWaitForResultWithEvent(gfx::Point(50, 478),
+  hit_node = HitTestAndWaitForResultWithEvent(gfx::Point(50, 505),
                                               ax::mojom::Event::kAlert);
   ASSERT_NE(hit_node, nullptr);
   ASSERT_EQ(ax::mojom::Role::kGenericContainer, hit_node->GetRole());
 }
 
-IN_PROC_BROWSER_TEST_P(AccessibilityHitTestingCrossProcessBrowserTest,
+IN_PROC_BROWSER_TEST_F(AccessibilityHitTestingCrossProcessBrowserTest,
                        HitTestingInCrossProcessIframes) {
   GURL url_a(embedded_test_server()->GetURL(
       "a.com", "/accessibility/hit_testing/hit_testing_a.html"));
@@ -497,7 +489,7 @@
   }
 }
 
-IN_PROC_BROWSER_TEST_P(AccessibilityHitTestingCrossProcessBrowserTest,
+IN_PROC_BROWSER_TEST_F(AccessibilityHitTestingCrossProcessBrowserTest,
                        HitTestingInScrolledCrossProcessIframe) {
   GURL url_a(embedded_test_server()->GetURL(
       "a.com", "/accessibility/hit_testing/hit_testing_a.html"));
@@ -563,7 +555,7 @@
   }
 }
 
-IN_PROC_BROWSER_TEST_P(AccessibilityHitTestingBrowserTest,
+IN_PROC_BROWSER_TEST_F(AccessibilityHitTestingBrowserTest,
                        CachingAsyncHitTestingInIframes) {
   ASSERT_TRUE(embedded_test_server()->Start());
 
@@ -623,16 +615,16 @@
   EXPECT_EQ("Scrolled Button",
             hit_node->GetStringAttribute(ax::mojom::StringAttribute::kName));
 
-  // (50, 478) -> div in second iframe
-  hit_node = CallCachingAsyncHitTest(gfx::Point(50, 478));
+  // (50, 505) -> div in second iframe
+  hit_node = CallCachingAsyncHitTest(gfx::Point(50, 505));
   ASSERT_TRUE(hit_node != nullptr);
   EXPECT_NE(ax::mojom::Role::kGenericContainer, hit_node->GetRole());
-  hit_node = CallCachingAsyncHitTest(gfx::Point(50, 478));
+  hit_node = CallCachingAsyncHitTest(gfx::Point(50, 505));
   EXPECT_EQ(ax::mojom::Role::kGenericContainer, hit_node->GetRole());
 }
 
 #if !defined(OS_ANDROID) && !defined(OS_MACOSX)
-IN_PROC_BROWSER_TEST_P(AccessibilityHitTestingBrowserTest,
+IN_PROC_BROWSER_TEST_F(AccessibilityHitTestingBrowserTest,
                        HitTestingWithPinchZoom) {
   ASSERT_TRUE(embedded_test_server()->Start());
 
@@ -730,7 +722,7 @@
             hit_node->GetStringAttribute(ax::mojom::StringAttribute::kName));
 }
 
-IN_PROC_BROWSER_TEST_P(AccessibilityHitTestingBrowserTest,
+IN_PROC_BROWSER_TEST_F(AccessibilityHitTestingBrowserTest,
                        HitTestingWithPinchZoomAndIframes) {
   ASSERT_TRUE(embedded_test_server()->Start());
 
@@ -794,7 +786,7 @@
 // Chrome OS or Chromecast)
 #if defined(OS_WIN) || \
     (defined(OS_LINUX) && !defined(OS_CHROMEOS) && !BUILDFLAG(IS_CHROMECAST))
-IN_PROC_BROWSER_TEST_P(AccessibilityHitTestingBrowserTest,
+IN_PROC_BROWSER_TEST_F(AccessibilityHitTestingBrowserTest,
                        NearestLeafInIframes) {
   ASSERT_TRUE(embedded_test_server()->Start());
 
@@ -866,11 +858,11 @@
   EXPECT_EQ("Scrolled Button",
             hit_node->GetStringAttribute(ax::mojom::StringAttribute::kName));
 
-  // (50, 478) -> "Scrolled Button"
-  hit_node = CallNearestLeafNode(gfx::Point(50, 478));
+  // (50, 505) -> "Scrolled Button"
+  hit_node = CallNearestLeafNode(gfx::Point(50, 505));
   ASSERT_TRUE(hit_node != nullptr);
   EXPECT_NE(ax::mojom::Role::kButton, hit_node->GetData().role);
-  hit_node = CallNearestLeafNode(gfx::Point(50, 478));
+  hit_node = CallNearestLeafNode(gfx::Point(50, 505));
   ASSERT_TRUE(hit_node != nullptr);
   EXPECT_EQ(ax::mojom::Role::kButton, hit_node->GetData().role);
   EXPECT_EQ("Scrolled Button",
diff --git a/content/browser/back_forward_cache_browsertest.cc b/content/browser/back_forward_cache_browsertest.cc
index 39adf84..dd8b9871 100644
--- a/content/browser/back_forward_cache_browsertest.cc
+++ b/content/browser/back_forward_cache_browsertest.cc
@@ -3860,8 +3860,7 @@
   EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
 
   // 3) Navigate to B#2 (same document navigation).
-  EXPECT_TRUE(ExecJs(shell(), JsReplace("location = $1", url_b2.spec())));
-  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+  EXPECT_TRUE(NavigateToURLFromRenderer(shell(), url_b2));
 
   // 4) Go back to B.
   web_contents()->GetController().GoBack();
diff --git a/content/browser/frame_host/render_frame_host_impl_browsertest.cc b/content/browser/frame_host/render_frame_host_impl_browsertest.cc
index 06d7327..6f10b2b 100644
--- a/content/browser/frame_host/render_frame_host_impl_browsertest.cc
+++ b/content/browser/frame_host/render_frame_host_impl_browsertest.cc
@@ -3616,7 +3616,7 @@
 IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest,
                        CheckIsCurrentBeforeAndAfterUnload) {
   IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess());
-  std::string onunload_script = "window.onunload = function(){}";
+  std::string onunload_script = "window.onunload = function(){ while(1);}";
   GURL url_ab(embedded_test_server()->GetURL(
       "a.com", "/cross_site_iframe_factory.html?a(b)"));
   GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
@@ -3628,11 +3628,10 @@
   RenderFrameDeletedObserver delete_rfh_b(rfh_b);
   EXPECT_EQ(RenderFrameHostImpl::UnloadState::NotRun, rfh_b->unload_state_);
 
-  // 2) Set an arbitrarily long timeout to ensure the subframe unload timer
-  // doesn't fire before we call OnDetach(). Act as if there was a slow unload
-  // handler on rfh_b. The non navigating frames are waiting for
-  // FrameHostMsg_Detach.
-  rfh_b->SetSubframeUnloadTimeoutForTesting(base::TimeDelta::FromSeconds(30));
+  // 2) Disable the unload timer to ensure that the unload timer doesn't fire
+  // before we call OnDetach(). Act as if there was a slow unload handler on
+  // rfh_b. The non navigating frames are waiting for FrameHostMsg_Detach.
+  rfh_b->DisableUnloadTimerForTesting();
   auto detach_filter = base::MakeRefCounted<DropMessageFilter>(
       FrameMsgStart, FrameHostMsg_Detach::ID);
   rfh_b->GetProcess()->AddFilter(detach_filter.get());
diff --git a/content/browser/renderer_host/input/input_router_impl.cc b/content/browser/renderer_host/input/input_router_impl.cc
index 2d5fbd0..866862be 100644
--- a/content/browser/renderer_host/input/input_router_impl.cc
+++ b/content/browser/renderer_host/input/input_router_impl.cc
@@ -90,9 +90,7 @@
                            this,
                            fling_scheduler_client,
                            config.gesture_config),
-      device_scale_factor_(1.f),
-      compositor_touch_action_enabled_(
-          base::FeatureList::IsEnabled(features::kCompositorTouchAction)) {
+      device_scale_factor_(1.f) {
   weak_this_ = weak_ptr_factory_.GetWeakPtr();
 
   DCHECK(client);
@@ -154,8 +152,7 @@
 
   FilterGestureEventResult result =
       touch_action_filter_.FilterGestureEvent(&gesture_event.event);
-  if (compositor_touch_action_enabled_ &&
-      result == FilterGestureEventResult::kFilterGestureEventDelayed) {
+  if (result == FilterGestureEventResult::kFilterGestureEventDelayed) {
     TRACE_EVENT_INSTANT0("input", "DeferredForTouchAction",
                          TRACE_EVENT_SCOPE_THREAD);
     gesture_event_queue_.QueueDeferredEvents(gesture_event);
@@ -296,30 +293,19 @@
 void InputRouterImpl::SetTouchActionFromMain(cc::TouchAction touch_action) {
   TRACE_EVENT1("input", "InputRouterImpl::SetTouchActionFromMain",
                "touch_action", TouchActionToString(touch_action));
-  if (compositor_touch_action_enabled_) {
-    touch_action_filter_.OnSetTouchAction(touch_action);
-    touch_event_queue_.StopTimeoutMonitor();
-    ProcessDeferredGestureEventQueue();
-  }
+  touch_action_filter_.OnSetTouchAction(touch_action);
+  touch_event_queue_.StopTimeoutMonitor();
+  ProcessDeferredGestureEventQueue();
   UpdateTouchAckTimeoutEnabled();
 }
 
-void InputRouterImpl::SetWhiteListedTouchAction(cc::TouchAction touch_action,
-                                                uint32_t unique_touch_event_id,
-                                                InputEventAckState state) {
-  DCHECK(!compositor_touch_action_enabled_);
-  OnSetWhiteListedTouchAction(touch_action);
-}
-
 void InputRouterImpl::OnSetWhiteListedTouchAction(
     cc::TouchAction touch_action) {
   touch_action_filter_.OnSetWhiteListedTouchAction(touch_action);
   client_->OnSetWhiteListedTouchAction(touch_action);
-  if (compositor_touch_action_enabled_) {
-    if (touch_action == cc::TouchAction::kAuto)
-      FlushDeferredGestureQueue();
-    UpdateTouchAckTimeoutEnabled();
-  }
+  if (touch_action == cc::TouchAction::kAuto)
+    FlushDeferredGestureQueue();
+  UpdateTouchAckTimeoutEnabled();
 }
 
 void InputRouterImpl::DidOverscroll(const ui::DidOverscrollParams& params) {
@@ -430,15 +416,6 @@
     touch_action_filter_.AppendToGestureSequenceForDebugging(
         base::NumberToString(event.event.unique_touch_event_id).c_str());
     touch_action_filter_.IncreaseActiveTouches();
-    // In certain corner cases, the ack for the touch start may not come with a
-    // touch action, then we should set the touch actions to Auto.
-    if (!compositor_touch_action_enabled_ &&
-        !touch_action_filter_.allowed_touch_action().has_value()) {
-      touch_action_filter_.OnSetTouchAction(cc::TouchAction::kAuto);
-      if (compositor_touch_action_enabled_)
-        touch_event_queue_.StopTimeoutMonitor();
-      UpdateTouchAckTimeoutEnabled();
-    }
   }
   disposition_handler_->OnTouchEventAck(event, ack_source, ack_result);
 
@@ -653,16 +630,12 @@
   // send it in the input event ack to ensure it is available at the
   // time the ACK is handled.
   if (touch_action.has_value()) {
-    if (!compositor_touch_action_enabled_) {
+    if (source == InputEventAckSource::COMPOSITOR_THREAD)
+      OnSetWhiteListedTouchAction(touch_action.value());
+    else if (source == InputEventAckSource::MAIN_THREAD)
       OnSetTouchAction(touch_action.value());
-    } else {
-      if (source == InputEventAckSource::COMPOSITOR_THREAD)
-        OnSetWhiteListedTouchAction(touch_action.value());
-      else if (source == InputEventAckSource::MAIN_THREAD)
-        OnSetTouchAction(touch_action.value());
-      else
-        NOTREACHED();
-    }
+    else
+      NOTREACHED();
   }
 
   // TODO(crbug.com/953547): find a proper way to stop the timeout monitor.
@@ -741,11 +714,9 @@
 void InputRouterImpl::ForceSetTouchActionAuto() {
   touch_action_filter_.AppendToGestureSequenceForDebugging("F");
   touch_action_filter_.OnSetTouchAction(cc::TouchAction::kAuto);
-  if (compositor_touch_action_enabled_) {
-    // TODO(xidachen): Call FlushDeferredGestureQueue when this flag is enabled.
-    touch_event_queue_.StopTimeoutMonitor();
-    ProcessDeferredGestureEventQueue();
-  }
+  // TODO(xidachen): Call FlushDeferredGestureQueue when this flag is enabled.
+  touch_event_queue_.StopTimeoutMonitor();
+  ProcessDeferredGestureEventQueue();
 }
 
 void InputRouterImpl::ForceResetTouchActionForTest() {
@@ -769,8 +740,7 @@
   touch_action_filter_.AppendToGestureSequenceForDebugging(
       base::NumberToString(static_cast<int>(touch_action)).c_str());
   touch_action_filter_.OnSetTouchAction(touch_action);
-  if (compositor_touch_action_enabled_)
-    touch_event_queue_.StopTimeoutMonitor();
+  touch_event_queue_.StopTimeoutMonitor();
 
   // TouchAction::kNone should disable the touch ack timeout.
   UpdateTouchAckTimeoutEnabled();
diff --git a/content/browser/renderer_host/input/input_router_impl.h b/content/browser/renderer_host/input/input_router_impl.h
index 439b147..53349f64 100644
--- a/content/browser/renderer_host/input/input_router_impl.h
+++ b/content/browser/renderer_host/input/input_router_impl.h
@@ -100,9 +100,6 @@
   void FallbackCursorModeSetCursorVisibility(bool visible) override;
 #endif
   void SetTouchActionFromMain(cc::TouchAction touch_action) override;
-  void SetWhiteListedTouchAction(cc::TouchAction touch_action,
-                                 uint32_t unique_touch_event_id,
-                                 InputEventAckState state) override;
   void DidOverscroll(const ui::DidOverscrollParams& params) override;
   void ImeCancelComposition() override;
   void DidStartScrollingViewport() override;
@@ -265,8 +262,6 @@
 
   float device_scale_factor_;
 
-  bool compositor_touch_action_enabled_;
-
   // Last touch position relative to screen. Used to compute movementX/Y.
   base::flat_map<int, gfx::Point> global_touch_position_;
 
diff --git a/content/browser/renderer_host/input/input_router_impl_unittest.cc b/content/browser/renderer_host/input/input_router_impl_unittest.cc
index 64694ba9..c1b6a25f 100644
--- a/content/browser/renderer_host/input/input_router_impl_unittest.cc
+++ b/content/browser/renderer_host/input/input_router_impl_unittest.cc
@@ -426,13 +426,6 @@
     input_router_->SetTouchActionFromMain(cc::TouchAction::kNone);
   }
 
-  void OnSetWhiteListedTouchAction(cc::TouchAction white_listed_touch_action,
-                                   uint32_t unique_touch_event_id,
-                                   InputEventAckState ack_result) {
-    input_router_->SetWhiteListedTouchAction(white_listed_touch_action,
-                                             unique_touch_event_id, ack_result);
-  }
-
   void ResetTouchAction() {
     input_router_->touch_action_filter_.ResetTouchAction();
   }
@@ -473,7 +466,7 @@
     EXPECT_EQ(input_router_->touch_action_filter_.num_of_active_touches_, 0);
   }
 
-  void StopTimeoutMonitorTest(bool compositor_touch_action_enabled) {
+  void StopTimeoutMonitorTest() {
     ResetTouchAction();
     PressTouchPoint(1, 1);
     base::Optional<ui::DidOverscrollParams> overscroll;
@@ -482,20 +475,12 @@
     EXPECT_TRUE(input_router_->touch_event_queue_.IsTimeoutRunningForTesting());
     input_router_->TouchEventHandled(
         TouchEventWithLatencyInfo(touch_event_),
-        compositor_touch_action_enabled ? InputEventAckSource::COMPOSITOR_THREAD
-                                        : InputEventAckSource::MAIN_THREAD,
-        ui::LatencyInfo(), INPUT_EVENT_ACK_STATE_NOT_CONSUMED, overscroll,
-        touch_action);
-    if (compositor_touch_action_enabled) {
-      EXPECT_TRUE(
-          input_router_->touch_event_queue_.IsTimeoutRunningForTesting());
-      input_router_->SetTouchActionFromMain(cc::TouchAction::kPan);
-      EXPECT_FALSE(
-          input_router_->touch_event_queue_.IsTimeoutRunningForTesting());
-    } else {
-      EXPECT_FALSE(
-          input_router_->touch_event_queue_.IsTimeoutRunningForTesting());
-    }
+        InputEventAckSource::COMPOSITOR_THREAD, ui::LatencyInfo(),
+        INPUT_EVENT_ACK_STATE_NOT_CONSUMED, overscroll, touch_action);
+    EXPECT_TRUE(input_router_->touch_event_queue_.IsTimeoutRunningForTesting());
+    input_router_->SetTouchActionFromMain(cc::TouchAction::kPan);
+    EXPECT_FALSE(
+        input_router_->touch_event_queue_.IsTimeoutRunningForTesting());
   }
 
   void OnTouchEventAckWithAckState(
@@ -526,18 +511,9 @@
   SyntheticWebTouchEvent touch_event_;
 };
 
-class InputRouterImplTest : public InputRouterImplTestBase,
-                            public testing::WithParamInterface<bool> {
+class InputRouterImplTest : public InputRouterImplTestBase {
  public:
-  InputRouterImplTest() : compositor_touch_action_enabled_(GetParam()) {
-    if (GetParam()) {
-      touch_action_feature_list_.InitAndEnableFeature(
-          features::kCompositorTouchAction);
-    } else {
-      touch_action_feature_list_.InitAndDisableFeature(
-          features::kCompositorTouchAction);
-    }
-  }
+  InputRouterImplTest() = default;
 
   base::Optional<cc::TouchAction> AllowedTouchAction() {
     return input_router_->touch_action_filter_.allowed_touch_action_;
@@ -546,17 +522,9 @@
   cc::TouchAction WhiteListedTouchAction() {
     return input_router_->touch_action_filter_.white_listed_touch_action_;
   }
-
- protected:
-  const bool compositor_touch_action_enabled_;
-
- private:
-  base::test::ScopedFeatureList touch_action_feature_list_;
 };
 
-INSTANTIATE_TEST_SUITE_P(All, InputRouterImplTest, ::testing::Bool());
-
-TEST_P(InputRouterImplTest, HandledInputEvent) {
+TEST_F(InputRouterImplTest, HandledInputEvent) {
   client_->set_filter_state(INPUT_EVENT_ACK_STATE_CONSUMED);
 
   // Simulate a keyboard event.
@@ -570,7 +538,7 @@
   EXPECT_EQ(1U, disposition_handler_->GetAndResetAckCount());
 }
 
-TEST_P(InputRouterImplTest, ClientCanceledKeyboardEvent) {
+TEST_F(InputRouterImplTest, ClientCanceledKeyboardEvent) {
   client_->set_filter_state(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
 
   // Simulate a keyboard event that has no consumer.
@@ -593,7 +561,7 @@
 
 // Tests ported from RenderWidgetHostTest --------------------------------------
 
-TEST_P(InputRouterImplTest, HandleKeyEventsWeSent) {
+TEST_F(InputRouterImplTest, HandleKeyEventsWeSent) {
   // Simulate a keyboard event.
   SimulateKeyboardEvent(WebInputEvent::kRawKeyDown);
 
@@ -608,7 +576,7 @@
             disposition_handler_->acked_keyboard_event().GetType());
 }
 
-TEST_P(InputRouterImplTest, CoalescesWheelEvents) {
+TEST_F(InputRouterImplTest, CoalescesWheelEvents) {
   // Simulate wheel events.
   SimulateWheelEvent(0, 0, 0, -5, 0, false,
                      WebMouseWheelEvent::kPhaseBegan);  // sent directly
@@ -714,13 +682,13 @@
 
 // Test that the active touch sequence count increment when the touch start is
 // not ACKed from the main thread.
-TEST_P(InputRouterImplTest, ActiveTouchSequenceCountWithoutTouchAction) {
+TEST_F(InputRouterImplTest, ActiveTouchSequenceCountWithoutTouchAction) {
   base::Optional<cc::TouchAction> touch_action;
   ActiveTouchSequenceCountTest(touch_action,
                                INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
 }
 
-TEST_P(InputRouterImplTest,
+TEST_F(InputRouterImplTest,
        ActiveTouchSequenceCountWithoutTouchActionNoConsumer) {
   base::Optional<cc::TouchAction> touch_action;
   ActiveTouchSequenceCountTest(touch_action,
@@ -729,99 +697,71 @@
 
 // Test that the active touch sequence count increment when the touch start is
 // ACKed from the main thread.
-TEST_P(InputRouterImplTest, ActiveTouchSequenceCountWithTouchAction) {
+TEST_F(InputRouterImplTest, ActiveTouchSequenceCountWithTouchAction) {
   base::Optional<cc::TouchAction> touch_action(cc::TouchAction::kPanY);
   ActiveTouchSequenceCountTest(touch_action,
                                INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
 }
 
-TEST_P(InputRouterImplTest, ActiveTouchSequenceCountWithTouchActionNoConsumer) {
+TEST_F(InputRouterImplTest, ActiveTouchSequenceCountWithTouchActionNoConsumer) {
   base::Optional<cc::TouchAction> touch_action(cc::TouchAction::kPanY);
   ActiveTouchSequenceCountTest(touch_action,
                                INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
 }
 
-TEST_P(InputRouterImplTest, TouchActionAutoWithAckStateConsumed) {
-  InputEventAckSource source = compositor_touch_action_enabled_
-                                   ? InputEventAckSource::COMPOSITOR_THREAD
-                                   : InputEventAckSource::MAIN_THREAD;
+TEST_F(InputRouterImplTest, TouchActionAutoWithAckStateConsumed) {
+  InputEventAckSource source = InputEventAckSource::COMPOSITOR_THREAD;
   base::Optional<cc::TouchAction> expected_touch_action;
-  if (!compositor_touch_action_enabled_)
-    expected_touch_action = cc::TouchAction::kAuto;
   OnTouchEventAckWithAckState(source, INPUT_EVENT_ACK_STATE_CONSUMED,
                               expected_touch_action, cc::TouchAction::kAuto);
 }
 
-TEST_P(InputRouterImplTest, TouchActionAutoWithAckStateNotConsumed) {
-  InputEventAckSource source = compositor_touch_action_enabled_
-                                   ? InputEventAckSource::COMPOSITOR_THREAD
-                                   : InputEventAckSource::MAIN_THREAD;
+TEST_F(InputRouterImplTest, TouchActionAutoWithAckStateNotConsumed) {
+  InputEventAckSource source = InputEventAckSource::COMPOSITOR_THREAD;
   base::Optional<cc::TouchAction> expected_touch_action;
-  if (!compositor_touch_action_enabled_)
-    expected_touch_action = cc::TouchAction::kAuto;
   OnTouchEventAckWithAckState(source, INPUT_EVENT_ACK_STATE_NOT_CONSUMED,
                               expected_touch_action, cc::TouchAction::kAuto);
 }
 
-TEST_P(InputRouterImplTest, TouchActionAutoWithAckStateConsumedShouldBubble) {
-  InputEventAckSource source = compositor_touch_action_enabled_
-                                   ? InputEventAckSource::COMPOSITOR_THREAD
-                                   : InputEventAckSource::MAIN_THREAD;
+TEST_F(InputRouterImplTest, TouchActionAutoWithAckStateConsumedShouldBubble) {
+  InputEventAckSource source = InputEventAckSource::COMPOSITOR_THREAD;
   base::Optional<cc::TouchAction> expected_touch_action;
-  if (!compositor_touch_action_enabled_)
-    expected_touch_action = cc::TouchAction::kAuto;
   OnTouchEventAckWithAckState(source,
                               INPUT_EVENT_ACK_STATE_CONSUMED_SHOULD_BUBBLE,
                               expected_touch_action, cc::TouchAction::kAuto);
 }
 
-TEST_P(InputRouterImplTest, TouchActionAutoWithAckStateNoConsumerExists) {
-  InputEventAckSource source = compositor_touch_action_enabled_
-                                   ? InputEventAckSource::COMPOSITOR_THREAD
-                                   : InputEventAckSource::MAIN_THREAD;
+TEST_F(InputRouterImplTest, TouchActionAutoWithAckStateNoConsumerExists) {
+  InputEventAckSource source = InputEventAckSource::COMPOSITOR_THREAD;
   base::Optional<cc::TouchAction> expected_touch_action;
-  if (!compositor_touch_action_enabled_)
-    expected_touch_action = cc::TouchAction::kAuto;
   OnTouchEventAckWithAckState(source, INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS,
                               expected_touch_action, cc::TouchAction::kAuto);
 }
 
-TEST_P(InputRouterImplTest, TouchActionAutoWithAckStateIgnored) {
-  InputEventAckSource source = compositor_touch_action_enabled_
-                                   ? InputEventAckSource::COMPOSITOR_THREAD
-                                   : InputEventAckSource::MAIN_THREAD;
+TEST_F(InputRouterImplTest, TouchActionAutoWithAckStateIgnored) {
+  InputEventAckSource source = InputEventAckSource::COMPOSITOR_THREAD;
   base::Optional<cc::TouchAction> expected_touch_action;
-  if (!compositor_touch_action_enabled_)
-    expected_touch_action = cc::TouchAction::kAuto;
   OnTouchEventAckWithAckState(source, INPUT_EVENT_ACK_STATE_IGNORED,
                               expected_touch_action, cc::TouchAction::kAuto);
 }
 
-TEST_P(InputRouterImplTest, TouchActionAutoWithAckStateNonBlocking) {
-  InputEventAckSource source = compositor_touch_action_enabled_
-                                   ? InputEventAckSource::COMPOSITOR_THREAD
-                                   : InputEventAckSource::MAIN_THREAD;
+TEST_F(InputRouterImplTest, TouchActionAutoWithAckStateNonBlocking) {
+  InputEventAckSource source = InputEventAckSource::COMPOSITOR_THREAD;
   base::Optional<cc::TouchAction> expected_touch_action;
-  if (!compositor_touch_action_enabled_)
-    expected_touch_action = cc::TouchAction::kAuto;
   OnTouchEventAckWithAckState(source, INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING,
                               expected_touch_action, cc::TouchAction::kAuto);
 }
 
-TEST_P(InputRouterImplTest, TouchActionAutoWithAckStateNonBlockingDueToFling) {
-  InputEventAckSource source = compositor_touch_action_enabled_
-                                   ? InputEventAckSource::COMPOSITOR_THREAD
-                                   : InputEventAckSource::MAIN_THREAD;
+TEST_F(InputRouterImplTest, TouchActionAutoWithAckStateNonBlockingDueToFling) {
+  InputEventAckSource source = InputEventAckSource::COMPOSITOR_THREAD;
   base::Optional<cc::TouchAction> expected_touch_action;
-  if (!compositor_touch_action_enabled_)
-    expected_touch_action = cc::TouchAction::kAuto;
   OnTouchEventAckWithAckState(
       source, INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING_DUE_TO_FLING,
       expected_touch_action, cc::TouchAction::kAuto);
 }
 
 // Tests that touch-events are sent properly.
-TEST_P(InputRouterImplTest, TouchEventQueue) {
+TEST_F(InputRouterImplTest, TouchEventQueue) {
   OnHasTouchEventHandlers(true);
 
   PressTouchPoint(1, 1);
@@ -860,7 +800,7 @@
 
 // Tests that the touch-queue is emptied after a page stops listening for touch
 // events and the outstanding ack is received.
-TEST_P(InputRouterImplTest, TouchEventQueueFlush) {
+TEST_F(InputRouterImplTest, TouchEventQueueFlush) {
   OnHasTouchEventHandlers(true);
   EXPECT_EQ(0U, GetAndResetDispatchedMessages().size());
   EXPECT_TRUE(TouchEventQueueEmpty());
@@ -889,7 +829,7 @@
   EXPECT_TRUE(TouchEventQueueEmpty());
 }
 
-TEST_P(InputRouterImplTest, UnhandledWheelEvent) {
+TEST_F(InputRouterImplTest, UnhandledWheelEvent) {
   // Simulate wheel events.
   SimulateWheelEvent(0, 0, 0, -5, 0, false, WebMouseWheelEvent::kPhaseBegan);
   SimulateWheelEvent(0, 0, 0, -10, 0, false, WebMouseWheelEvent::kPhaseChanged);
@@ -955,7 +895,7 @@
   EXPECT_EQ(1U, disposition_handler_->GetAndResetAckCount());
 }
 
-TEST_P(InputRouterImplTest, TouchTypesIgnoringAck) {
+TEST_F(InputRouterImplTest, TouchTypesIgnoringAck) {
   OnHasTouchEventHandlers(true);
   // Only acks for TouchCancel should always be ignored.
   ASSERT_TRUE(
@@ -993,7 +933,7 @@
 }
 
 // TODO(https://crbug.com/866946): Test is flaky, especially on Mac & Fuchsia.
-TEST_P(InputRouterImplTest, DISABLED_GestureTypesIgnoringAck) {
+TEST_F(InputRouterImplTest, DISABLED_GestureTypesIgnoringAck) {
   // We test every gesture type, ensuring that the stream of gestures is valid.
 
 #if defined(OS_WIN)
@@ -1068,7 +1008,7 @@
   }
 }
 
-TEST_P(InputRouterImplTest, MouseTypesIgnoringAck) {
+TEST_F(InputRouterImplTest, MouseTypesIgnoringAck) {
   int start_type = static_cast<int>(WebInputEvent::kMouseDown);
   int end_type = static_cast<int>(WebInputEvent::kContextMenu);
   ASSERT_LT(start_type, end_type);
@@ -1100,7 +1040,7 @@
 
 // Guard against breaking changes to the list of ignored event ack types in
 // |WebInputEventTraits::ShouldBlockEventStream|.
-TEST_P(InputRouterImplTest, RequiredEventAckTypes) {
+TEST_F(InputRouterImplTest, RequiredEventAckTypes) {
   const WebInputEvent::Type kRequiredEventAckTypes[] = {
       WebInputEvent::kMouseMove,
       WebInputEvent::kMouseWheel,
@@ -1119,7 +1059,7 @@
   }
 }
 
-TEST_P(InputRouterImplTest, GestureTypesIgnoringAckInterleaved) {
+TEST_F(InputRouterImplTest, GestureTypesIgnoringAckInterleaved) {
   // Interleave a few events that do and do not ignore acks. All gesture events
   // should be dispatched immediately, but the acks will be blocked on blocking
   // events.
@@ -1216,7 +1156,7 @@
 
 // Test that GestureShowPress events don't get out of order due to
 // ignoring their acks.
-TEST_P(InputRouterImplTest, GestureShowPressIsInOrder) {
+TEST_F(InputRouterImplTest, GestureShowPressIsInOrder) {
   PressAndSetTouchActionAuto();
   SimulateGestureEvent(WebInputEvent::kGestureScrollBegin,
                        blink::WebGestureDevice::kTouchscreen);
@@ -1287,7 +1227,7 @@
 
 // Test that touch ack timeout behavior is properly configured for
 // mobile-optimized sites and allowed touch actions.
-TEST_P(InputRouterImplTest, TouchAckTimeoutConfigured) {
+TEST_F(InputRouterImplTest, TouchAckTimeoutConfigured) {
   const int kDesktopTimeoutMs = 1;
   const int kMobileTimeoutMs = 0;
   SetUpForTouchAckTimeoutTest(kDesktopTimeoutMs, kMobileTimeoutMs);
@@ -1375,7 +1315,7 @@
 
 // Test that a touch sequenced preceded by TouchAction::kNone is not affected by
 // the touch timeout.
-TEST_P(InputRouterImplTest,
+TEST_F(InputRouterImplTest,
        TouchAckTimeoutDisabledForTouchSequenceAfterTouchActionNone) {
   const int kDesktopTimeoutMs = 1;
   const int kMobileTimeoutMs = 2;
@@ -1439,7 +1379,7 @@
 
 // Test that TouchActionFilter::ResetTouchAction is called before the
 // first touch event for a touch sequence reaches the renderer.
-TEST_P(InputRouterImplTest, TouchActionResetBeforeEventReachesRenderer) {
+TEST_F(InputRouterImplTest, TouchActionResetBeforeEventReachesRenderer) {
   OnHasTouchEventHandlers(true);
 
   // Sequence 1.
@@ -1521,7 +1461,7 @@
 
 // Test that TouchActionFilter::ResetTouchAction is called when a new touch
 // sequence has no consumer.
-TEST_P(InputRouterImplTest, TouchActionResetWhenTouchHasNoConsumer) {
+TEST_F(InputRouterImplTest, TouchActionResetWhenTouchHasNoConsumer) {
   OnHasTouchEventHandlers(true);
 
   // Sequence 1.
@@ -1593,7 +1533,7 @@
 
 // Test that TouchActionFilter::ResetTouchAction is called when the touch
 // handler is removed.
-TEST_P(InputRouterImplTest, TouchActionResetWhenTouchHandlerRemoved) {
+TEST_F(InputRouterImplTest, TouchActionResetWhenTouchHandlerRemoved) {
   // Touch sequence with touch handler.
   OnHasTouchEventHandlers(true);
   PressTouchPoint(1, 1);
@@ -1649,7 +1589,7 @@
 }
 
 // Tests that async touch-moves are ack'd from the browser side.
-TEST_P(InputRouterImplTest, AsyncTouchMoveAckedImmediately) {
+TEST_F(InputRouterImplTest, AsyncTouchMoveAckedImmediately) {
   OnHasTouchEventHandlers(true);
 
   PressTouchPoint(1, 1);
@@ -1687,7 +1627,7 @@
 
 // Test that the double tap gesture depends on the touch action of the first
 // tap.
-TEST_P(InputRouterImplTest, DoubleTapGestureDependsOnFirstTap) {
+TEST_F(InputRouterImplTest, DoubleTapGestureDependsOnFirstTap) {
   OnHasTouchEventHandlers(true);
 
   // Sequence 1.
@@ -1957,7 +1897,7 @@
 }
 
 // Test proper handling of touchpad Gesture{Pinch,Scroll}Update sequences.
-TEST_P(InputRouterImplTest, TouchpadPinchAndScrollUpdate) {
+TEST_F(InputRouterImplTest, TouchpadPinchAndScrollUpdate) {
   // All gesture events should be sent immediately.
   SimulateGestureScrollUpdateEvent(1.5f, 0.f, 0,
                                    blink::WebGestureDevice::kTouchpad);
@@ -2031,7 +1971,7 @@
 
 // Test proper routing of overscroll notifications received either from
 // event acks or from |DidOverscroll| IPC messages.
-TEST_P(InputRouterImplTest, OverscrollDispatch) {
+TEST_F(InputRouterImplTest, OverscrollDispatch) {
   DidOverscrollParams overscroll;
   overscroll.accumulated_overscroll = gfx::Vector2dF(-14, 14);
   overscroll.latest_overscroll_delta = gfx::Vector2dF(-7, 0);
@@ -2076,23 +2016,9 @@
   EXPECT_EQ(gfx::Vector2dF(), client_overscroll.current_fling_velocity);
 }
 
-// Test proper routing of whitelisted touch action notifications received from
-// |SetWhiteListedTouchAction| IPC messages.
-TEST_P(InputRouterImplTest, OnSetWhiteListedTouchAction) {
-  // The white listed touch action is bundled in the ack.
-  if (compositor_touch_action_enabled_)
-    return;
-  cc::TouchAction touch_action = cc::TouchAction::kPanY;
-  OnSetWhiteListedTouchAction(touch_action, 0,
-                              INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
-  cc::TouchAction white_listed_touch_action =
-      client_->GetAndResetWhiteListedTouchAction();
-  EXPECT_EQ(touch_action, white_listed_touch_action);
-}
-
 // Tests that touch event stream validation passes when events are filtered
 // out. See https://crbug.com/581231 for details.
-TEST_P(InputRouterImplTest, TouchValidationPassesWithFilteredInputEvents) {
+TEST_F(InputRouterImplTest, TouchValidationPassesWithFilteredInputEvents) {
   // Touch sequence with touch handler.
   OnHasTouchEventHandlers(true);
   PressTouchPoint(1, 1);
@@ -2128,7 +2054,7 @@
       INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
 }
 
-TEST_P(InputRouterImplTest, TouchActionInCallback) {
+TEST_F(InputRouterImplTest, TouchActionInCallback) {
   OnHasTouchEventHandlers(true);
 
   // Send a touchstart
@@ -2139,30 +2065,23 @@
   ASSERT_TRUE(dispatched_messages[0]->ToEvent());
   InputEventAckSource source = InputEventAckSource::MAIN_THREAD;
   base::Optional<cc::TouchAction> expected_touch_action = cc::TouchAction::kPan;
-  if (compositor_touch_action_enabled_)
-    source = InputEventAckSource::COMPOSITOR_THREAD;
+  source = InputEventAckSource::COMPOSITOR_THREAD;
   dispatched_messages[0]->ToEvent()->CallCallback(
       source, ui::LatencyInfo(), INPUT_EVENT_ACK_STATE_CONSUMED, base::nullopt,
       expected_touch_action);
   ASSERT_EQ(1U, disposition_handler_->GetAndResetAckCount());
   base::Optional<cc::TouchAction> allowed_touch_action = AllowedTouchAction();
   cc::TouchAction white_listed_touch_action = WhiteListedTouchAction();
-  if (compositor_touch_action_enabled_) {
-    EXPECT_FALSE(allowed_touch_action.has_value());
-    EXPECT_EQ(expected_touch_action.value(), white_listed_touch_action);
-  } else {
-    EXPECT_EQ(expected_touch_action, allowed_touch_action);
-  }
+  EXPECT_FALSE(allowed_touch_action.has_value());
+  EXPECT_EQ(expected_touch_action.value(), white_listed_touch_action);
 }
 
-TEST_P(InputRouterImplTest, TimeoutMonitorStopWithMainThreadTouchAction) {
-  // TODO(crbug.com/953547): enable this when the bug is fixed.
-  if (compositor_touch_action_enabled_)
-    return;
+// TODO(crbug.com/953547): enable this when the bug is fixed.
+TEST_F(InputRouterImplTest,
+       DISABLED_TimeoutMonitorStopWithMainThreadTouchAction) {
   SetUpForTouchAckTimeoutTest(1, 1);
   OnHasTouchEventHandlers(true);
-
-  StopTimeoutMonitorTest(compositor_touch_action_enabled_);
+  StopTimeoutMonitorTest();
 }
 
 namespace {
diff --git a/content/browser/renderer_host/input/touch_action_browsertest.cc b/content/browser/renderer_host/input/touch_action_browsertest.cc
index aba71cc..900b121 100644
--- a/content/browser/renderer_host/input/touch_action_browsertest.cc
+++ b/content/browser/renderer_host/input/touch_action_browsertest.cc
@@ -134,16 +134,10 @@
 
 namespace content {
 
-class TouchActionBrowserTest : public ContentBrowserTest,
-                               public testing::WithParamInterface<bool> {
+class TouchActionBrowserTest : public ContentBrowserTest {
  public:
-  TouchActionBrowserTest() : compositor_touch_action_enabled_(GetParam()) {
-    if (compositor_touch_action_enabled_)
-      feature_list_.InitAndEnableFeature(features::kCompositorTouchAction);
-    else
-      feature_list_.InitAndDisableFeature(features::kCompositorTouchAction);
-  }
-  ~TouchActionBrowserTest() override {}
+  TouchActionBrowserTest() = default;
+  ~TouchActionBrowserTest() override = default;
 
   RenderWidgetHostImpl* GetWidgetHost() {
     return RenderWidgetHostImpl::From(
@@ -466,18 +460,13 @@
       EXPECT_GT(scroll_left, 0);
   }
 
-  const bool compositor_touch_action_enabled_;
-
  private:
   std::unique_ptr<RenderFrameSubmissionObserver> frame_observer_;
   std::unique_ptr<base::RunLoop> run_loop_;
-  base::test::ScopedFeatureList feature_list_;
 
   DISALLOW_COPY_AND_ASSIGN(TouchActionBrowserTest);
 };
 
-INSTANTIATE_TEST_SUITE_P(All, TouchActionBrowserTest, testing::Bool());
-
 #if !defined(NDEBUG) || defined(ADDRESS_SANITIZER) ||       \
     defined(MEMORY_SANITIZER) || defined(LEAK_SANITIZER) || \
     defined(THREAD_SANITIZER)
@@ -488,10 +477,10 @@
 //
 // Verify the test infrastructure works - we can touch-scroll the page and get a
 // touchcancel as expected.
-IN_PROC_BROWSER_TEST_P(TouchActionBrowserTest, MAYBE_DefaultAuto) {
+IN_PROC_BROWSER_TEST_F(TouchActionBrowserTest, MAYBE_DefaultAuto) {
   LoadURL(kTouchActionDataURL);
 
-  bool wait_until_scrolled = !compositor_touch_action_enabled_;
+  bool wait_until_scrolled = false;
   DoTouchScroll(gfx::Point(50, 50), gfx::Vector2d(0, 45), wait_until_scrolled,
                 10200, gfx::Vector2d(0, 45), kNoJankTime);
 
@@ -510,10 +499,10 @@
 #else
 #define MAYBE_TouchActionNone TouchActionNone
 #endif
-IN_PROC_BROWSER_TEST_P(TouchActionBrowserTest, MAYBE_TouchActionNone) {
+IN_PROC_BROWSER_TEST_F(TouchActionBrowserTest, MAYBE_TouchActionNone) {
   LoadURL(kTouchActionDataURL);
 
-  bool wait_until_scrolled = !compositor_touch_action_enabled_;
+  bool wait_until_scrolled = false;
   DoTouchScroll(gfx::Point(50, 150), gfx::Vector2d(0, 45), wait_until_scrolled,
                 10200, gfx::Vector2d(0, 0), kNoJankTime);
 
@@ -530,10 +519,10 @@
 #else
 #define MAYBE_PanYMainThreadJanky PanYMainThreadJanky
 #endif
-IN_PROC_BROWSER_TEST_P(TouchActionBrowserTest, MAYBE_PanYMainThreadJanky) {
+IN_PROC_BROWSER_TEST_F(TouchActionBrowserTest, MAYBE_PanYMainThreadJanky) {
   LoadURL(kTouchActionURLWithOverlapArea);
 
-  bool wait_until_scrolled = !compositor_touch_action_enabled_;
+  bool wait_until_scrolled = false;
   DoTouchScroll(gfx::Point(25, 125), gfx::Vector2d(0, 45), wait_until_scrolled,
                 10000, gfx::Vector2d(0, 45), kShortJankTime);
 }
@@ -545,10 +534,10 @@
 #else
 #define MAYBE_PanXMainThreadJanky PanXMainThreadJanky
 #endif
-IN_PROC_BROWSER_TEST_P(TouchActionBrowserTest, MAYBE_PanXMainThreadJanky) {
+IN_PROC_BROWSER_TEST_F(TouchActionBrowserTest, MAYBE_PanXMainThreadJanky) {
   LoadURL(kTouchActionURLWithOverlapArea);
 
-  bool wait_until_scrolled = !compositor_touch_action_enabled_;
+  bool wait_until_scrolled = false;
   DoTouchScroll(gfx::Point(125, 25), gfx::Vector2d(45, 0), wait_until_scrolled,
                 10000, gfx::Vector2d(45, 0), kShortJankTime);
 }
@@ -560,7 +549,7 @@
 #endif
 // When touch ack timeout is triggered, the panx gesture will be allowed even
 // though we touch the pany area.
-IN_PROC_BROWSER_TEST_P(TouchActionBrowserTest, MAYBE_PanXAtYAreaWithTimeout) {
+IN_PROC_BROWSER_TEST_F(TouchActionBrowserTest, MAYBE_PanXAtYAreaWithTimeout) {
   LoadURL(kTouchActionURLWithOverlapArea);
 
   DoTouchScroll(gfx::Point(25, 125), gfx::Vector2d(45, 0), true, 10000,
@@ -575,7 +564,7 @@
 #endif
 // When touch ack timeout is triggered, the panx gesture will be allowed even
 // though we touch the pany area.
-IN_PROC_BROWSER_TEST_P(TouchActionBrowserTest,
+IN_PROC_BROWSER_TEST_F(TouchActionBrowserTest,
                        MAYBE_TwoFingerPanXAtYAreaWithTimeout) {
   LoadURL(kTouchActionURLWithOverlapArea);
 
@@ -589,10 +578,10 @@
 #else
 #define MAYBE_PanXYMainThreadJanky PanXYMainThreadJanky
 #endif
-IN_PROC_BROWSER_TEST_P(TouchActionBrowserTest, MAYBE_PanXYMainThreadJanky) {
+IN_PROC_BROWSER_TEST_F(TouchActionBrowserTest, MAYBE_PanXYMainThreadJanky) {
   LoadURL(kTouchActionURLWithOverlapArea);
 
-  bool wait_until_scrolled = !compositor_touch_action_enabled_;
+  bool wait_until_scrolled = false;
   DoTouchScroll(gfx::Point(75, 60), gfx::Vector2d(45, 45), wait_until_scrolled,
                 10000, gfx::Vector2d(45, 45), kShortJankTime);
 }
@@ -604,7 +593,7 @@
 #else
 #define MAYBE_PanXYAtXAreaMainThreadJanky PanXYAtXAreaMainThreadJanky
 #endif
-IN_PROC_BROWSER_TEST_P(TouchActionBrowserTest,
+IN_PROC_BROWSER_TEST_F(TouchActionBrowserTest,
                        MAYBE_PanXYAtXAreaMainThreadJanky) {
   LoadURL(kTouchActionURLWithOverlapArea);
 
@@ -619,7 +608,7 @@
 #else
 #define MAYBE_PanXYAtYAreaMainThreadJanky PanXYAtYAreaMainThreadJanky
 #endif
-IN_PROC_BROWSER_TEST_P(TouchActionBrowserTest,
+IN_PROC_BROWSER_TEST_F(TouchActionBrowserTest,
                        MAYBE_PanXYAtYAreaMainThreadJanky) {
   LoadURL(kTouchActionURLWithOverlapArea);
 
@@ -636,7 +625,7 @@
 #define MAYBE_PanXYAtAutoYOverlapAreaMainThreadJanky \
   PanXYAtAutoYOverlapAreaMainThreadJanky
 #endif
-IN_PROC_BROWSER_TEST_P(TouchActionBrowserTest,
+IN_PROC_BROWSER_TEST_F(TouchActionBrowserTest,
                        MAYBE_PanXYAtAutoYOverlapAreaMainThreadJanky) {
   LoadURL(kTouchActionURLWithOverlapArea);
 
@@ -653,7 +642,7 @@
 #define MAYBE_PanXYAtAutoXOverlapAreaMainThreadJanky \
   PanXYAtAutoXOverlapAreaMainThreadJanky
 #endif
-IN_PROC_BROWSER_TEST_P(TouchActionBrowserTest,
+IN_PROC_BROWSER_TEST_F(TouchActionBrowserTest,
                        MAYBE_PanXYAtAutoXOverlapAreaMainThreadJanky) {
   LoadURL(kTouchActionURLWithOverlapArea);
 
@@ -669,7 +658,7 @@
 #endif
 // Test that two finger panning is treated as pinch zoom and is disallowed when
 // touching the pan-y area.
-IN_PROC_BROWSER_TEST_P(TouchActionBrowserTest, MAYBE_TwoFingerPanYDisallowed) {
+IN_PROC_BROWSER_TEST_F(TouchActionBrowserTest, MAYBE_TwoFingerPanYDisallowed) {
   LoadURL(kTouchActionURLWithOverlapArea);
 
   DoTwoFingerPan();
@@ -698,7 +687,7 @@
 
 // Test that |touch-action: none| correctly blocks a double-tap and drag zoom
 // gesture.
-IN_PROC_BROWSER_TEST_P(TouchActionBrowserTest, BlockDoubleTapDragZoom) {
+IN_PROC_BROWSER_TEST_F(TouchActionBrowserTest, BlockDoubleTapDragZoom) {
   LoadURL(kDoubleTapZoomDataURL.c_str());
 
   ASSERT_EQ(1, ExecuteScriptAndExtractDouble("window.visualViewport.scale"));
diff --git a/content/browser/renderer_host/input/touch_action_filter.cc b/content/browser/renderer_host/input/touch_action_filter.cc
index ec68e4b..8841d4b 100644
--- a/content/browser/renderer_host/input/touch_action_filter.cc
+++ b/content/browser/renderer_host/input/touch_action_filter.cc
@@ -96,9 +96,7 @@
 
 }  // namespace
 
-TouchActionFilter::TouchActionFilter()
-    : compositor_touch_action_enabled_(
-          base::FeatureList::IsEnabled(features::kCompositorTouchAction)) {
+TouchActionFilter::TouchActionFilter() {
   ResetTouchAction();
 }
 
@@ -109,7 +107,7 @@
   if (gesture_event->SourceDevice() != blink::WebGestureDevice::kTouchscreen)
     return FilterGestureEventResult::kFilterGestureEventAllowed;
 
-  if (compositor_touch_action_enabled_ && has_deferred_events_) {
+  if (has_deferred_events_) {
     WebInputEvent::Type type = gesture_event->GetType();
     if (type == WebInputEvent::kGestureScrollBegin ||
         type == WebInputEvent::kGestureScrollUpdate) {
@@ -143,13 +141,7 @@
           active_touch_action_ = allowed_touch_action_;
           touch_action = allowed_touch_action_.value();
         } else {
-          if (compositor_touch_action_enabled_) {
-            touch_action = white_listed_touch_action_;
-          } else {
-            gesture_sequence_.append("B");
-            SetTouchAction(cc::TouchAction::kAuto);
-            touch_action = cc::TouchAction::kAuto;
-          }
+          touch_action = white_listed_touch_action_;
         }
       }
       drop_scroll_events_ =
@@ -185,16 +177,8 @@
       // two-finger scrolling but a "touch-action: pan-x pinch-zoom" region
       // doesn't.
       // TODO(mustaq): Add it to spec?
-      if (!compositor_touch_action_enabled_ &&
-          !active_touch_action_.has_value()) {
-        static auto* crash_key = base::debug::AllocateCrashKeyString(
-            "scrollupdate-gestures", base::debug::CrashKeySize::Size256);
-        base::debug::SetCrashKeyString(crash_key, gesture_sequence_);
-        gesture_sequence_.clear();
-      }
       if (IsYAxisActionDisallowed(touch_action)) {
-        if (compositor_touch_action_enabled_ &&
-            !active_touch_action_.has_value() &&
+        if (!active_touch_action_.has_value() &&
             gesture_event->data.scroll_update.delta_y != 0) {
           has_deferred_events_ = true;
           ReportGestureEventFilterResults(
@@ -205,8 +189,7 @@
         gesture_event->data.scroll_update.delta_y = 0;
         gesture_event->data.scroll_update.velocity_y = 0;
       } else if (IsXAxisActionDisallowed(touch_action)) {
-        if (compositor_touch_action_enabled_ &&
-            !active_touch_action_.has_value() &&
+        if (!active_touch_action_.has_value() &&
             gesture_event->data.scroll_update.delta_x != 0) {
           has_deferred_events_ = true;
           ReportGestureEventFilterResults(
@@ -251,8 +234,7 @@
       gesture_sequence_.append("P");
       if (!drop_pinch_events_)
         return FilterGestureEventResult::kFilterGestureEventAllowed;
-      if (compositor_touch_action_enabled_ &&
-          !active_touch_action_.has_value()) {
+      if (!active_touch_action_.has_value()) {
         has_deferred_events_ = true;
         return FilterGestureEventResult::kFilterGestureEventDelayed;
       }
@@ -285,13 +267,6 @@
     case WebInputEvent::kGestureTapUnconfirmed: {
       DCHECK_EQ(1, gesture_event->data.tap.tap_count);
       gesture_sequence_.append("C");
-      if (!compositor_touch_action_enabled_ &&
-          !active_touch_action_.has_value()) {
-        static auto* crash_key = base::debug::AllocateCrashKeyString(
-            "tapunconfirmed-gestures", base::debug::CrashKeySize::Size256);
-        base::debug::SetCrashKeyString(crash_key, gesture_sequence_);
-        gesture_sequence_.clear();
-      }
       allow_current_double_tap_event_ =
           (touch_action & cc::TouchAction::kDoubleTapZoom) !=
           cc::TouchAction::kNone;
diff --git a/content/browser/renderer_host/input/touch_action_filter.h b/content/browser/renderer_host/input/touch_action_filter.h
index 7ebef22..4d2ff43 100644
--- a/content/browser/renderer_host/input/touch_action_filter.h
+++ b/content/browser/renderer_host/input/touch_action_filter.h
@@ -124,8 +124,6 @@
   // before GSE.
   bool gesture_sequence_in_progress_ = false;
 
-  bool compositor_touch_action_enabled_ = false;
-
   bool has_deferred_events_ = false;
 
   // Increment at receiving ACK for touch start and decrement at touch end.
diff --git a/content/browser/renderer_host/input/touch_action_filter_unittest.cc b/content/browser/renderer_host/input/touch_action_filter_unittest.cc
index b4ecee45..bedb364 100644
--- a/content/browser/renderer_host/input/touch_action_filter_unittest.cc
+++ b/content/browser/renderer_host/input/touch_action_filter_unittest.cc
@@ -22,20 +22,10 @@
 
 }  // namespace
 
-class TouchActionFilterTest : public testing::Test,
-                              public testing::WithParamInterface<bool> {
+class TouchActionFilterTest : public testing::Test {
  public:
-  TouchActionFilterTest() : compositor_touch_action_enabled_(GetParam()) {
-    filter_.OnHasTouchEventHandlers(true);
-    if (compositor_touch_action_enabled_) {
-      feature_list_.InitAndEnableFeature(features::kCompositorTouchAction);
-      filter_.compositor_touch_action_enabled_ = true;
-    } else {
-      feature_list_.InitAndDisableFeature(features::kCompositorTouchAction);
-      filter_.compositor_touch_action_enabled_ = false;
-    }
-  }
-  ~TouchActionFilterTest() override {}
+  TouchActionFilterTest() { filter_.OnHasTouchEventHandlers(true); }
+  ~TouchActionFilterTest() override = default;
 
  protected:
   base::Optional<cc::TouchAction> ActiveTouchAction() const {
@@ -238,15 +228,9 @@
     }
   }
   TouchActionFilter filter_;
-  const bool compositor_touch_action_enabled_;
-
- private:
-  base::test::ScopedFeatureList feature_list_;
 };
 
-INSTANTIATE_TEST_SUITE_P(All, TouchActionFilterTest, ::testing::Bool());
-
-TEST_P(TouchActionFilterTest, SimpleFilter) {
+TEST_F(TouchActionFilterTest, SimpleFilter) {
   WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
       WebInputEvent::kGestureTapDown, kSourceDevice);
   WebGestureEvent scroll_begin =
@@ -354,7 +338,7 @@
   filter_.DecreaseActiveTouches();
 }
 
-TEST_P(TouchActionFilterTest, PanLeft) {
+TEST_F(TouchActionFilterTest, PanLeft) {
   const float kDX = 5;
   const float kDY = 10;
   const float kScrollX = 7;
@@ -364,7 +348,7 @@
   PanTestForUnidirectionalTouchAction(cc::TouchAction::kPanLeft, kScrollX, 0);
 }
 
-TEST_P(TouchActionFilterTest, PanRight) {
+TEST_F(TouchActionFilterTest, PanRight) {
   const float kDX = 5;
   const float kDY = 10;
   const float kScrollX = -7;
@@ -374,7 +358,7 @@
   PanTestForUnidirectionalTouchAction(cc::TouchAction::kPanRight, kScrollX, 0);
 }
 
-TEST_P(TouchActionFilterTest, PanX) {
+TEST_F(TouchActionFilterTest, PanX) {
   const float kDX = 5;
   const float kDY = 10;
   const float kScrollX = 7;
@@ -383,7 +367,7 @@
   PanTest(cc::TouchAction::kPanX, kScrollX, kScrollY, kDX, kDY, kDX, 0);
 }
 
-TEST_P(TouchActionFilterTest, PanUp) {
+TEST_F(TouchActionFilterTest, PanUp) {
   const float kDX = 5;
   const float kDY = 10;
   const float kScrollX = 6;
@@ -393,7 +377,7 @@
   PanTestForUnidirectionalTouchAction(cc::TouchAction::kPanUp, 0, kScrollY);
 }
 
-TEST_P(TouchActionFilterTest, PanDown) {
+TEST_F(TouchActionFilterTest, PanDown) {
   const float kDX = 5;
   const float kDY = 10;
   const float kScrollX = 6;
@@ -403,7 +387,7 @@
   PanTestForUnidirectionalTouchAction(cc::TouchAction::kPanDown, 0, kScrollY);
 }
 
-TEST_P(TouchActionFilterTest, PanY) {
+TEST_F(TouchActionFilterTest, PanY) {
   const float kDX = 5;
   const float kDY = 10;
   const float kScrollX = 6;
@@ -412,7 +396,7 @@
   PanTest(cc::TouchAction::kPanY, kScrollX, kScrollY, kDX, kDY, 0, kDY);
 }
 
-TEST_P(TouchActionFilterTest, PanXY) {
+TEST_F(TouchActionFilterTest, PanXY) {
   const float kDX = 5;
   const float kDY = 10;
   WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
@@ -495,7 +479,7 @@
   }
 }
 
-TEST_P(TouchActionFilterTest, BitMath) {
+TEST_F(TouchActionFilterTest, BitMath) {
   // Verify that the simple flag mixing properties we depend on are now
   // trivially true.
   EXPECT_EQ(cc::TouchAction::kNone,
@@ -512,7 +496,7 @@
             cc::TouchAction::kManipulation | cc::TouchAction::kDoubleTapZoom);
 }
 
-TEST_P(TouchActionFilterTest, MultiTouch) {
+TEST_F(TouchActionFilterTest, MultiTouch) {
   WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
       WebInputEvent::kGestureTapDown, kSourceDevice);
   WebGestureEvent scroll_begin =
@@ -561,15 +545,9 @@
   filter_.DecreaseActiveTouches();
 }
 
-class TouchActionFilterPinchTest : public testing::Test,
-                                   public testing::WithParamInterface<bool> {
+class TouchActionFilterPinchTest : public testing::Test {
  public:
-  TouchActionFilterPinchTest() {
-    if (GetParam())
-      feature_list_.InitAndEnableFeature(features::kCompositorTouchAction);
-    else
-      feature_list_.InitAndDisableFeature(features::kCompositorTouchAction);
-  }
+  TouchActionFilterPinchTest() = default;
 
   void RunTest(bool force_enable_zoom) {
     filter_.OnHasTouchEventHandlers(true);
@@ -758,22 +736,19 @@
 
  private:
   TouchActionFilter filter_;
-  base::test::ScopedFeatureList feature_list_;
 };
 
-INSTANTIATE_TEST_SUITE_P(All, TouchActionFilterPinchTest, ::testing::Bool());
-
-TEST_P(TouchActionFilterPinchTest, Pinch) {
+TEST_F(TouchActionFilterPinchTest, Pinch) {
   RunTest(false);
 }
 
 // Enables force enable zoom will override touch-action except for
 // touch-action: none.
-TEST_P(TouchActionFilterPinchTest, ForceEnableZoom) {
+TEST_F(TouchActionFilterPinchTest, ForceEnableZoom) {
   RunTest(true);
 }
 
-TEST_P(TouchActionFilterTest, DoubleTapWithTouchActionAuto) {
+TEST_F(TouchActionFilterTest, DoubleTapWithTouchActionAuto) {
   WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
       WebInputEvent::kGestureTapDown, kSourceDevice);
   WebGestureEvent unconfirmed_tap = SyntheticWebGestureEventBuilder::Build(
@@ -804,7 +779,7 @@
             FilterGestureEventResult::kFilterGestureEventAllowed);
 }
 
-TEST_P(TouchActionFilterTest, DoubleTap) {
+TEST_F(TouchActionFilterTest, DoubleTap) {
   WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
       WebInputEvent::kGestureTapDown, kSourceDevice);
   WebGestureEvent unconfirmed_tap = SyntheticWebGestureEventBuilder::Build(
@@ -838,7 +813,7 @@
   filter_.DecreaseActiveTouches();
 }
 
-TEST_P(TouchActionFilterTest, SingleTapWithTouchActionAuto) {
+TEST_F(TouchActionFilterTest, SingleTapWithTouchActionAuto) {
   WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
       WebInputEvent::kGestureTapDown, kSourceDevice);
   WebGestureEvent unconfirmed_tap1 = SyntheticWebGestureEventBuilder::Build(
@@ -858,7 +833,7 @@
             FilterGestureEventResult::kFilterGestureEventAllowed);
 }
 
-TEST_P(TouchActionFilterTest, SingleTap) {
+TEST_F(TouchActionFilterTest, SingleTap) {
   WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
       WebInputEvent::kGestureTapDown, kSourceDevice);
   WebGestureEvent unconfirmed_tap1 = SyntheticWebGestureEventBuilder::Build(
@@ -880,7 +855,7 @@
   filter_.DecreaseActiveTouches();
 }
 
-TEST_P(TouchActionFilterTest, TouchActionResetsOnResetTouchAction) {
+TEST_F(TouchActionFilterTest, TouchActionResetsOnResetTouchAction) {
   WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
       WebInputEvent::kGestureTapDown, kSourceDevice);
   WebGestureEvent tap = SyntheticWebGestureEventBuilder::Build(
@@ -920,7 +895,7 @@
   filter_.DecreaseActiveTouches();
 }
 
-TEST_P(TouchActionFilterTest, TouchActionResetMidSequence) {
+TEST_F(TouchActionFilterTest, TouchActionResetMidSequence) {
   filter_.OnHasTouchEventHandlers(true);
   WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
       WebInputEvent::kGestureTapDown, kSourceDevice);
@@ -983,7 +958,7 @@
 
 // This test makes sure that we do not reset scrolling touch action in the
 // middle of a gesture sequence.
-TEST_P(TouchActionFilterTest, TouchActionNotResetWithinGestureSequence) {
+TEST_F(TouchActionFilterTest, TouchActionNotResetWithinGestureSequence) {
   filter_.OnHasTouchEventHandlers(true);
   EXPECT_FALSE(filter_.allowed_touch_action().has_value());
   filter_.OnSetTouchAction(cc::TouchAction::kPanY);
@@ -1027,7 +1002,7 @@
 // The following 3 tests ensures that when the IPC message
 // OnHasTouchEventHandlers is received in the middle of a gesture sequence, the
 // touch action is not reset.
-TEST_P(TouchActionFilterTest, OnHasTouchEventHandlersReceivedDuringTap) {
+TEST_F(TouchActionFilterTest, OnHasTouchEventHandlersReceivedDuringTap) {
   filter_.OnHasTouchEventHandlers(false);
 
   WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
@@ -1049,7 +1024,7 @@
   EXPECT_FALSE(filter_.allowed_touch_action().has_value());
 }
 
-TEST_P(TouchActionFilterTest, OnHasTouchEventHandlersReceivedDuringDoubleTap) {
+TEST_F(TouchActionFilterTest, OnHasTouchEventHandlersReceivedDuringDoubleTap) {
   filter_.OnHasTouchEventHandlers(false);
 
   WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
@@ -1079,7 +1054,7 @@
   filter_.DecreaseActiveTouches();
 }
 
-TEST_P(TouchActionFilterTest, OnHasTouchEventHandlersReceivedDuringScroll) {
+TEST_F(TouchActionFilterTest, OnHasTouchEventHandlersReceivedDuringScroll) {
   filter_.OnHasTouchEventHandlers(false);
 
   WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
@@ -1112,7 +1087,7 @@
 
 // If OnHasTouchEventHandlers IPC is received after LongTap or TwoFingerTap,
 // the touch action should be reset.
-TEST_P(TouchActionFilterTest,
+TEST_F(TouchActionFilterTest,
        OnHasTouchEventHandlersReceivedAfterLongTapOrTwoFingerTap) {
   filter_.OnHasTouchEventHandlers(false);
 
@@ -1149,7 +1124,7 @@
   EXPECT_FALSE(ActiveTouchAction().has_value());
 }
 
-TEST_P(TouchActionFilterTest, OnHasTouchEventHandlersReceivedAfterTouchStart) {
+TEST_F(TouchActionFilterTest, OnHasTouchEventHandlersReceivedAfterTouchStart) {
   filter_.OnHasTouchEventHandlers(true);
   EXPECT_FALSE(ActiveTouchAction().has_value());
   EXPECT_FALSE(filter_.allowed_touch_action().has_value());
@@ -1165,7 +1140,7 @@
   EXPECT_EQ(filter_.allowed_touch_action().value(), cc::TouchAction::kPanY);
 }
 
-TEST_P(TouchActionFilterTest, ResetTouchActionWithActiveTouch) {
+TEST_F(TouchActionFilterTest, ResetTouchActionWithActiveTouch) {
   filter_.OnHasTouchEventHandlers(true);
   EXPECT_FALSE(ActiveTouchAction().has_value());
   EXPECT_FALSE(filter_.allowed_touch_action().has_value());
@@ -1195,14 +1170,14 @@
 // If the renderer is busy, the gesture event might have come before the
 // OnHasTouchEventHanlders IPC is received. In this case, we should allow all
 // the gestures.
-TEST_P(TouchActionFilterTest, GestureArrivesBeforeHasHandlerSet) {
+TEST_F(TouchActionFilterTest, GestureArrivesBeforeHasHandlerSet) {
   WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
       WebInputEvent::kGestureTapDown, kSourceDevice);
   EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
             FilterGestureEventResult::kFilterGestureEventAllowed);
 }
 
-TEST_P(TouchActionFilterTest, PinchGesturesAllowedByWhiteListedTouchAction) {
+TEST_F(TouchActionFilterTest, PinchGesturesAllowedByWhiteListedTouchAction) {
   filter_.OnHasTouchEventHandlers(true);
   EXPECT_FALSE(ActiveTouchAction().has_value());
   EXPECT_FALSE(filter_.allowed_touch_action().has_value());
@@ -1226,7 +1201,7 @@
 
 // Test gesture event filtering with white listed touch action. It should test
 // all 3 kinds of results: Allowed / Dropped / Delayed.
-TEST_P(TouchActionFilterTest, FilterWithWhiteListedTouchAction) {
+TEST_F(TouchActionFilterTest, FilterWithWhiteListedTouchAction) {
   filter_.OnHasTouchEventHandlers(true);
   EXPECT_FALSE(ActiveTouchAction().has_value());
   EXPECT_FALSE(filter_.allowed_touch_action().has_value());
@@ -1242,8 +1217,6 @@
       WebInputEvent::kGestureScrollEnd, kSourceDevice);
 
   filter_.OnSetWhiteListedTouchAction(cc::TouchAction::kPan);
-  if (!compositor_touch_action_enabled_)
-    filter_.OnSetTouchAction(cc::TouchAction::kPan);
   EXPECT_EQ(filter_.white_listed_touch_action(), cc::TouchAction::kPan);
   SetGestureSequenceInProgress();
   EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
@@ -1258,8 +1231,6 @@
   ResetActiveTouchAction();
   ResetWhiteListedTouchAction();
   filter_.OnSetWhiteListedTouchAction(cc::TouchAction::kPan);
-  if (!compositor_touch_action_enabled_)
-    filter_.OnSetTouchAction(cc::TouchAction::kPan);
   EXPECT_EQ(filter_.white_listed_touch_action(), cc::TouchAction::kPan);
   WebGestureEvent pinch_begin = SyntheticWebGestureEventBuilder::Build(
       WebInputEvent::kGesturePinchBegin, kSourceDevice);
@@ -1268,21 +1239,12 @@
                                                         kSourceDevice);
   WebGestureEvent pinch_end = SyntheticWebGestureEventBuilder::Build(
       WebInputEvent::kGesturePinchEnd, kSourceDevice);
-  if (compositor_touch_action_enabled_) {
-    EXPECT_EQ(filter_.FilterGestureEvent(&pinch_begin),
-              FilterGestureEventResult::kFilterGestureEventDelayed);
-    EXPECT_EQ(filter_.FilterGestureEvent(&pinch_update),
-              FilterGestureEventResult::kFilterGestureEventDelayed);
-    EXPECT_EQ(filter_.FilterGestureEvent(&pinch_end),
-              FilterGestureEventResult::kFilterGestureEventDelayed);
-  } else {
-    EXPECT_EQ(filter_.FilterGestureEvent(&pinch_begin),
-              FilterGestureEventResult::kFilterGestureEventFiltered);
-    EXPECT_EQ(filter_.FilterGestureEvent(&pinch_update),
-              FilterGestureEventResult::kFilterGestureEventFiltered);
-    EXPECT_EQ(filter_.FilterGestureEvent(&pinch_end),
-              FilterGestureEventResult::kFilterGestureEventFiltered);
-  }
+  EXPECT_EQ(filter_.FilterGestureEvent(&pinch_begin),
+            FilterGestureEventResult::kFilterGestureEventDelayed);
+  EXPECT_EQ(filter_.FilterGestureEvent(&pinch_update),
+            FilterGestureEventResult::kFilterGestureEventDelayed);
+  EXPECT_EQ(filter_.FilterGestureEvent(&pinch_end),
+            FilterGestureEventResult::kFilterGestureEventDelayed);
 
   // Scroll updates should be delayed if white listed touch action is PanY,
   // because there are delta along the direction that is not allowed.
@@ -1290,31 +1252,20 @@
   ResetActiveTouchAction();
   ResetWhiteListedTouchAction();
   filter_.OnSetWhiteListedTouchAction(cc::TouchAction::kPanY);
-  if (!compositor_touch_action_enabled_)
-    filter_.OnSetTouchAction(cc::TouchAction::kPanY);
   SetNoDeferredEvents();
   EXPECT_EQ(filter_.white_listed_touch_action(), cc::TouchAction::kPanY);
   SetGestureSequenceInProgress();
   EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
             FilterGestureEventResult::kFilterGestureEventAllowed);
-  if (compositor_touch_action_enabled_) {
-    EXPECT_EQ(filter_.FilterGestureEvent(&scroll_update),
-              FilterGestureEventResult::kFilterGestureEventDelayed);
-    EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
-              FilterGestureEventResult::kFilterGestureEventDelayed);
-  } else {
-    EXPECT_EQ(filter_.FilterGestureEvent(&scroll_update),
-              FilterGestureEventResult::kFilterGestureEventAllowed);
-    EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
-              FilterGestureEventResult::kFilterGestureEventAllowed);
-  }
+  EXPECT_EQ(filter_.FilterGestureEvent(&scroll_update),
+            FilterGestureEventResult::kFilterGestureEventDelayed);
+  EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
+            FilterGestureEventResult::kFilterGestureEventDelayed);
 
   ResetTouchAction();
   ResetActiveTouchAction();
   ResetWhiteListedTouchAction();
   filter_.OnSetWhiteListedTouchAction(cc::TouchAction::kPanX);
-  if (!compositor_touch_action_enabled_)
-    filter_.OnSetTouchAction(cc::TouchAction::kPanX);
   SetNoDeferredEvents();
   EXPECT_EQ(filter_.white_listed_touch_action(), cc::TouchAction::kPanX);
 
@@ -1340,24 +1291,15 @@
   filter_.OnSetWhiteListedTouchAction(cc::TouchAction::kPanX);
   EXPECT_EQ(filter_.white_listed_touch_action(), cc::TouchAction::kPanX);
   SetGestureSequenceInProgress();
-  if (compositor_touch_action_enabled_) {
-    EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
-              FilterGestureEventResult::kFilterGestureEventDelayed);
-    EXPECT_EQ(filter_.FilterGestureEvent(&scroll_update),
-              FilterGestureEventResult::kFilterGestureEventDelayed);
-    EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
-              FilterGestureEventResult::kFilterGestureEventDelayed);
-  } else {
-    EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
-              FilterGestureEventResult::kFilterGestureEventFiltered);
-    EXPECT_EQ(filter_.FilterGestureEvent(&scroll_update),
-              FilterGestureEventResult::kFilterGestureEventFiltered);
-    EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
-              FilterGestureEventResult::kFilterGestureEventFiltered);
-  }
+  EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
+            FilterGestureEventResult::kFilterGestureEventDelayed);
+  EXPECT_EQ(filter_.FilterGestureEvent(&scroll_update),
+            FilterGestureEventResult::kFilterGestureEventDelayed);
+  EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
+            FilterGestureEventResult::kFilterGestureEventDelayed);
 }
 
-TEST_P(TouchActionFilterTest, WhiteListedTouchActionResetToAuto) {
+TEST_F(TouchActionFilterTest, WhiteListedTouchActionResetToAuto) {
   filter_.OnHasTouchEventHandlers(true);
 
   filter_.OnSetWhiteListedTouchAction(cc::TouchAction::kPan);
@@ -1366,7 +1308,7 @@
   EXPECT_EQ(filter_.white_listed_touch_action(), cc::TouchAction::kAuto);
 }
 
-TEST_P(TouchActionFilterTest, WhiteListedTouchActionAutoNoHasHandlers) {
+TEST_F(TouchActionFilterTest, WhiteListedTouchActionAutoNoHasHandlers) {
   filter_.OnHasTouchEventHandlers(false);
   EXPECT_EQ(filter_.white_listed_touch_action(), cc::TouchAction::kAuto);
 
@@ -1374,7 +1316,7 @@
   EXPECT_EQ(filter_.white_listed_touch_action(), cc::TouchAction::kAuto);
 }
 
-TEST_P(TouchActionFilterTest, ResetBeforeHasHandlerSet) {
+TEST_F(TouchActionFilterTest, ResetBeforeHasHandlerSet) {
   // This should not crash, and should set touch action to auto.
   ResetTouchAction();
   WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
@@ -1383,10 +1325,8 @@
             FilterGestureEventResult::kFilterGestureEventAllowed);
 }
 
-TEST_P(TouchActionFilterTest,
+TEST_F(TouchActionFilterTest,
        WhiteListedTouchActionNotResetAtGestureScrollEnd) {
-  if (!compositor_touch_action_enabled_)
-    return;
   filter_.OnHasTouchEventHandlers(true);
 
   filter_.OnSetWhiteListedTouchAction(cc::TouchAction::kPan);
@@ -1414,25 +1354,17 @@
 
 // Having a gesture scroll begin without tap down should set touch action to
 // Auto.
-TEST_P(TouchActionFilterTest, ScrollBeginWithoutTapDown) {
+TEST_F(TouchActionFilterTest, ScrollBeginWithoutTapDown) {
   filter_.OnHasTouchEventHandlers(true);
   EXPECT_FALSE(ActiveTouchAction().has_value());
   EXPECT_FALSE(filter_.allowed_touch_action().has_value());
 
-  if (compositor_touch_action_enabled_)
-    filter_.OnSetWhiteListedTouchAction(cc::TouchAction::kPan);
-  else
-    filter_.OnSetTouchAction(cc::TouchAction::kPan);
+  filter_.OnSetWhiteListedTouchAction(cc::TouchAction::kPan);
   WebGestureEvent scroll_begin =
       SyntheticWebGestureEventBuilder::BuildScrollBegin(5, 0, kSourceDevice);
   EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
             FilterGestureEventResult::kFilterGestureEventAllowed);
-  if (compositor_touch_action_enabled_) {
-    EXPECT_EQ(filter_.white_listed_touch_action(), cc::TouchAction::kPan);
-  } else {
-    EXPECT_EQ(ActiveTouchAction().value(), cc::TouchAction::kPan);
-    EXPECT_EQ(filter_.allowed_touch_action().value(), cc::TouchAction::kPan);
-  }
+  EXPECT_EQ(filter_.white_listed_touch_action(), cc::TouchAction::kPan);
 
   ResetTouchAction();
   ResetActiveTouchAction();
@@ -1442,18 +1374,13 @@
 
   // Ensure that there is no crash at GSB if both |allowed_| and |active_|
   // touch action have no value.
-  if (compositor_touch_action_enabled_)
-    filter_.OnSetWhiteListedTouchAction(cc::TouchAction::kPan);
+  filter_.OnSetWhiteListedTouchAction(cc::TouchAction::kPan);
   EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
             FilterGestureEventResult::kFilterGestureEventAllowed);
-  if (!compositor_touch_action_enabled_) {
-    EXPECT_EQ(filter_.allowed_touch_action().value(), cc::TouchAction::kAuto);
-    EXPECT_EQ(ActiveTouchAction().value(), cc::TouchAction::kAuto);
-  }
 }
 
 // This tests a gesture tap down with |num_of_active_touches_| == 0
-TEST_P(TouchActionFilterTest, TapDownWithZeroNumOfActiveTouches) {
+TEST_F(TouchActionFilterTest, TapDownWithZeroNumOfActiveTouches) {
   filter_.OnHasTouchEventHandlers(true);
   EXPECT_FALSE(ActiveTouchAction().has_value());
   EXPECT_FALSE(filter_.allowed_touch_action().has_value());
@@ -1469,7 +1396,7 @@
 // Regression test for crbug.com/771330. One can start one finger panning y, and
 // add another finger to pinch zooming. The pinch zooming should not be allowed
 // if the allowed touch action doesn't allow it.
-TEST_P(TouchActionFilterTest, PinchZoomStartsWithOneFingerPanDisallowed) {
+TEST_F(TouchActionFilterTest, PinchZoomStartsWithOneFingerPanDisallowed) {
   filter_.OnHasTouchEventHandlers(true);
   filter_.OnSetTouchAction(cc::TouchAction::kPanY);
   WebGestureEvent scroll_begin =
@@ -1506,7 +1433,7 @@
             FilterGestureEventResult::kFilterGestureEventAllowed);
 }
 
-TEST_P(TouchActionFilterTest, ScrollBeginWithoutTapDownWithKnownTouchAction) {
+TEST_F(TouchActionFilterTest, ScrollBeginWithoutTapDownWithKnownTouchAction) {
   filter_.OnHasTouchEventHandlers(true);
   EXPECT_FALSE(ActiveTouchAction().has_value());
   EXPECT_FALSE(filter_.allowed_touch_action().has_value());
@@ -1520,7 +1447,7 @@
   EXPECT_EQ(filter_.allowed_touch_action().value(), cc::TouchAction::kPan);
 }
 
-TEST_P(TouchActionFilterTest, TouchpadScroll) {
+TEST_F(TouchActionFilterTest, TouchpadScroll) {
   WebGestureEvent scroll_begin =
       SyntheticWebGestureEventBuilder::BuildScrollBegin(
           2, 3, blink::WebGestureDevice::kTouchpad);
diff --git a/content/browser/renderer_host/pepper/pepper_print_settings_manager.cc b/content/browser/renderer_host/pepper/pepper_print_settings_manager.cc
index 52ecd3b..6a7e4f5e 100644
--- a/content/browser/renderer_host/pepper/pepper_print_settings_manager.cc
+++ b/content/browser/renderer_host/pepper/pepper_print_settings_manager.cc
@@ -5,6 +5,7 @@
 #include "content/browser/renderer_host/pepper/pepper_print_settings_manager.h"
 
 #include "base/task/post_task.h"
+#include "build/build_config.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
@@ -12,6 +13,10 @@
 #include "ppapi/c/pp_errors.h"
 #include "printing/buildflags/buildflags.h"
 
+#if defined(OS_WIN)
+#include "base/threading/thread_restrictions.h"
+#endif
+
 #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
 #include "printing/printing_context.h"  // nogncheck
 #include "printing/units.h"  // nogncheck
@@ -59,11 +64,23 @@
   }
 };
 
-PepperPrintSettingsManager::Result ComputeDefaultPrintSettings() {
+#endif
+
+}  // namespace
+
+PepperPrintSettingsManager::Result
+PepperPrintSettingsManagerImpl::ComputeDefaultPrintSettings() {
+#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
   // This function should run on the UI thread because |PrintingContext| methods
   // call into platform APIs.
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
+#if defined(OS_WIN)
+  // Blocking is needed here because Windows printer drivers are oftentimes
+  // not thread-safe and have to be accessed on the UI thread.
+  base::ScopedAllowBlocking allow_blocking;
+#endif
+
   PrintingContextDelegate delegate;
   std::unique_ptr<printing::PrintingContext> context(
       printing::PrintingContext::Create(&delegate));
@@ -101,15 +118,11 @@
   // so just make it the default.
   settings.format = PP_PRINTOUTPUTFORMAT_PDF;
   return PepperPrintSettingsManager::Result(settings, PP_OK);
-}
 #else
-PepperPrintSettingsManager::Result ComputeDefaultPrintSettings() {
   return PepperPrintSettingsManager::Result(PP_PrintSettings_Dev(),
                                             PP_ERROR_NOTSUPPORTED);
-}
 #endif
-
-}  // namespace
+}
 
 void PepperPrintSettingsManagerImpl::GetDefaultPrintSettings(
     PepperPrintSettingsManager::Callback callback) {
diff --git a/content/browser/renderer_host/pepper/pepper_print_settings_manager.h b/content/browser/renderer_host/pepper/pepper_print_settings_manager.h
index 855fa2ab..c099ee2 100644
--- a/content/browser/renderer_host/pepper/pepper_print_settings_manager.h
+++ b/content/browser/renderer_host/pepper/pepper_print_settings_manager.h
@@ -42,6 +42,8 @@
       PepperPrintSettingsManager::Callback callback) override;
 
  private:
+  static PepperPrintSettingsManager::Result ComputeDefaultPrintSettings();
+
   DISALLOW_COPY_AND_ASSIGN(PepperPrintSettingsManagerImpl);
 };
 
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index bb1c8195..40485a6 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -12914,9 +12914,7 @@
 
 class SitePerProcessBrowserTouchActionTest : public SitePerProcessBrowserTest {
  public:
-  SitePerProcessBrowserTouchActionTest()
-      : compositor_touch_action_enabled_(
-            base::FeatureList::IsEnabled(features::kCompositorTouchAction)) {}
+  SitePerProcessBrowserTouchActionTest() = default;
 
   bool GetTouchActionForceEnableZoom(RenderWidgetHost* rwh) {
     InputRouterImpl* input_router = static_cast<InputRouterImpl*>(
@@ -12969,15 +12967,6 @@
     // touch start arrived because the ACK is from the main thread.
     whitelisted_touch_action =
         input_router->touch_action_filter_.white_listed_touch_action_;
-    // When flag is enabled, we may not have the value for the effective touch
-    // action when ack is received.
-    if (!compositor_touch_action_enabled_) {
-      while (!effective_touch_action.has_value()) {
-        GiveItSomeTime(TestTimeouts::tiny_timeout());
-        effective_touch_action =
-            input_router->touch_action_filter_.allowed_touch_action_;
-      }
-    }
 
     // Send a touch move and touch end to complete the sequence, this also
     // avoids triggering DCHECKs when sending followup events.
@@ -13020,9 +13009,6 @@
     // thread, upon return it should have handled any touch action update.
     root_thread_observer->Wait();
   }
-
- protected:
-  const bool compositor_touch_action_enabled_;
 };
 
 #if defined(OS_ANDROID)
@@ -13146,11 +13132,6 @@
   // TouchAction::kAuto in iframe's child.
   GetTouchActionsForChild(router, rwhv_root, rwhv_child, point_inside_child,
                           effective_touch_action, whitelisted_touch_action);
-  if (!compositor_touch_action_enabled_) {
-    EXPECT_EQ(expected_touch_action, effective_touch_action.has_value()
-                                         ? effective_touch_action.value()
-                                         : cc::TouchAction::kAuto);
-  }
   if (whitelisted_touch_action.has_value())
     EXPECT_EQ(expected_touch_action, whitelisted_touch_action.value());
 
@@ -13161,11 +13142,9 @@
   expected_touch_action = cc::TouchAction::kAuto;
   GetTouchActionsForChild(router, rwhv_root, rwhv_child, point_inside_child,
                           effective_touch_action, whitelisted_touch_action);
-  if (compositor_touch_action_enabled_) {
-    EXPECT_EQ(expected_touch_action, effective_touch_action.has_value()
-                                         ? effective_touch_action.value()
-                                         : cc::TouchAction::kAuto);
-  }
+  EXPECT_EQ(expected_touch_action, effective_touch_action.has_value()
+                                       ? effective_touch_action.value()
+                                       : cc::TouchAction::kAuto);
   if (whitelisted_touch_action.has_value())
     EXPECT_EQ(expected_touch_action, whitelisted_touch_action.value());
 }
@@ -13232,17 +13211,6 @@
   cc::TouchAction effective_touch_action_result =
       effective_touch_action.has_value() ? effective_touch_action.value()
                                          : cc::TouchAction::kAuto;
-  // TouchAction might have not been propagated to child frames yet, loop until
-  // we get the expected touch action value.
-  if (!compositor_touch_action_enabled_) {
-    while (expected_touch_action != effective_touch_action_result) {
-      GetTouchActionsForChild(router, rwhv_root, rwhv_child, point_inside_child,
-                              effective_touch_action, whitelisted_touch_action);
-      effective_touch_action_result = effective_touch_action.has_value()
-                                          ? effective_touch_action.value()
-                                          : cc::TouchAction::kAuto;
-    }
-  }
   if (whitelisted_touch_action.has_value())
     EXPECT_EQ(expected_touch_action, whitelisted_touch_action.value());
 
@@ -13259,15 +13227,6 @@
   effective_touch_action_result = effective_touch_action.has_value()
                                       ? effective_touch_action.value()
                                       : cc::TouchAction::kAuto;
-  if (!compositor_touch_action_enabled_) {
-    while (expected_touch_action != effective_touch_action_result) {
-      GetTouchActionsForChild(router, rwhv_root, rwhv_child, point_inside_child,
-                              effective_touch_action, whitelisted_touch_action);
-      effective_touch_action_result = effective_touch_action.has_value()
-                                          ? effective_touch_action.value()
-                                          : cc::TouchAction::kAuto;
-    }
-  }
   if (whitelisted_touch_action.has_value())
     EXPECT_EQ(expected_touch_action, whitelisted_touch_action.value());
 
@@ -13283,15 +13242,6 @@
   effective_touch_action_result = effective_touch_action.has_value()
                                       ? effective_touch_action.value()
                                       : cc::TouchAction::kAuto;
-  if (!compositor_touch_action_enabled_) {
-    while (expected_touch_action != effective_touch_action_result) {
-      GetTouchActionsForChild(router, rwhv_root, rwhv_child, point_inside_child,
-                              effective_touch_action, whitelisted_touch_action);
-      effective_touch_action_result = effective_touch_action.has_value()
-                                          ? effective_touch_action.value()
-                                          : cc::TouchAction::kAuto;
-    }
-  }
   if (whitelisted_touch_action.has_value())
     EXPECT_EQ(expected_touch_action, whitelisted_touch_action.value());
 }
@@ -13347,11 +13297,6 @@
   cc::TouchAction expected_touch_action = cc::TouchAction::kPan;
   GetTouchActionsForChild(router, rwhv_root, rwhv_child, point_inside_child,
                           effective_touch_action, whitelisted_touch_action);
-  if (!compositor_touch_action_enabled_) {
-    EXPECT_EQ(expected_touch_action, effective_touch_action.has_value()
-                                         ? effective_touch_action.value()
-                                         : cc::TouchAction::kAuto);
-  }
   if (whitelisted_touch_action.has_value())
     EXPECT_EQ(expected_touch_action, whitelisted_touch_action.value());
 
@@ -13375,11 +13320,6 @@
                             child_thread_observer.get());
   GetTouchActionsForChild(router, rwhv_root, rwhv_child, point_inside_child,
                           effective_touch_action, whitelisted_touch_action);
-  if (!compositor_touch_action_enabled_) {
-    EXPECT_EQ(expected_touch_action, effective_touch_action.has_value()
-                                         ? effective_touch_action.value()
-                                         : cc::TouchAction::kAuto);
-  }
   if (whitelisted_touch_action.has_value())
     EXPECT_EQ(expected_touch_action, whitelisted_touch_action.value());
 }
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index 516cf81..61279ef 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -230,8 +230,6 @@
     {wf::EnablePaymentHandlerMinimalUI, features::kWebPaymentsMinimalUI,
      kEnableOnly},
     {wf::EnablePaymentApp, features::kServiceWorkerPaymentApps, kEnableOnly},
-    {wf::EnableCompositorTouchAction, features::kCompositorTouchAction,
-     kEnableOnly},
     {wf::EnableGenericSensorExtraClasses, features::kGenericSensorExtraClasses,
      kEnableOnly},
     {wf::EnableMediaCastOverlayButton, media::kMediaCastOverlayButton,
diff --git a/content/common/input/input_handler.mojom b/content/common/input/input_handler.mojom
index a7853e55..f9ab479 100644
--- a/content/common/input/input_handler.mojom
+++ b/content/common/input/input_handler.mojom
@@ -177,16 +177,6 @@
   // browser.
   SetTouchActionFromMain(cc.mojom.TouchAction touch_action);
 
-  // The whitelisted touch action and the associated unique touch event id
-  // for a new touch point sent by the compositor. The unique touch event id is
-  // only needed to verify that the whitelisted touch action is being associated
-  // with the correct touch event. The input event ack state is needed when
-  // the touchstart message was not sent to the renderer and the touch
-  // actions need to be reset and the touch ack timeout needs to be started.
-  SetWhiteListedTouchAction(cc.mojom.TouchAction touch_action,
-                            uint32 unique_touch_event_id,
-                            InputEventAckState state);
-
   // Sent by the compositor when input scroll events are dropped due to bounds
   // restrictions on the root scroll offset.
   DidOverscroll(DidOverscrollParams params);
diff --git a/content/public/browser/ssl_status.cc b/content/public/browser/ssl_status.cc
index 7740146..bd9b1ff 100644
--- a/content/public/browser/ssl_status.cc
+++ b/content/public/browser/ssl_status.cc
@@ -24,7 +24,6 @@
     : initialized(true),
       certificate(ssl_info.cert),
       cert_status(ssl_info.cert_status),
-      public_key_hashes(ssl_info.public_key_hashes),
       key_exchange_group(ssl_info.key_exchange_group),
       peer_signature_algorithm(ssl_info.peer_signature_algorithm),
       connection_status(ssl_info.connection_status),
@@ -36,7 +35,6 @@
     : initialized(other.initialized),
       certificate(other.certificate),
       cert_status(other.cert_status),
-      public_key_hashes(other.public_key_hashes),
       key_exchange_group(other.key_exchange_group),
       peer_signature_algorithm(other.peer_signature_algorithm),
       connection_status(other.connection_status),
@@ -49,7 +47,6 @@
   initialized = other.initialized;
   certificate = other.certificate;
   cert_status = other.cert_status;
-  public_key_hashes = other.public_key_hashes;
   key_exchange_group = other.key_exchange_group;
   peer_signature_algorithm = other.peer_signature_algorithm;
   connection_status = other.connection_status;
diff --git a/content/public/browser/ssl_status.h b/content/public/browser/ssl_status.h
index 30c5f740..f177d33 100644
--- a/content/public/browser/ssl_status.h
+++ b/content/public/browser/ssl_status.h
@@ -70,10 +70,6 @@
   bool initialized;
   scoped_refptr<net::X509Certificate> certificate;
   net::CertStatus cert_status;
-  // The hashes of the SubjectPublicKeyInfos from each certificate in
-  // |certificate|. This field is not necessarily populated, e.g. for responses
-  // served from disk cache.
-  net::HashValueVector public_key_hashes;
   uint16_t key_exchange_group;
   uint16_t peer_signature_algorithm;
   int connection_status;
diff --git a/content/public/test/test_frame_navigation_observer.cc b/content/public/test/test_frame_navigation_observer.cc
index 51bd0f3..300783d 100644
--- a/content/public/test/test_frame_navigation_observer.cc
+++ b/content/public/test/test_frame_navigation_observer.cc
@@ -54,8 +54,7 @@
 void TestFrameNavigationObserver::DidStartNavigation(
     NavigationHandle* navigation_handle) {
   last_navigation_succeeded_ = false;
-  if (!navigation_handle->IsSameDocument() &&
-      navigation_handle->GetFrameTreeNodeId() == frame_tree_node_id_) {
+  if (navigation_handle->GetFrameTreeNodeId() == frame_tree_node_id_) {
     navigation_started_ = true;
     has_committed_ = false;
   }
diff --git a/content/renderer/browser_render_view_browsertest.cc b/content/renderer/browser_render_view_browsertest.cc
index 28e0505..00c6035 100644
--- a/content/renderer/browser_render_view_browsertest.cc
+++ b/content/renderer/browser_render_view_browsertest.cc
@@ -156,18 +156,8 @@
   GURL test_url(embedded_test_server()->GetURL("/nocache-with-etag.html"));
   NavigateToURLAndWaitForTitle(test_url, "Nocache Test Page", 1);
 
-  // Reload same URL after forcing an error from the the network layer;
-  // confirm that the error page is told the cached copy exists.
-  {
-    mojo::ScopedAllowSyncCallForTesting allow_sync_call;
-    content::StoragePartition* partition = shell()
-                                               ->web_contents()
-                                               ->GetMainFrame()
-                                               ->GetProcess()
-                                               ->GetStoragePartition();
-    partition->GetNetworkContext()->SetFailingHttpTransactionForTesting(
-        net::ERR_FAILED);
-  }
+  // Shut down the server to force a network error.
+  ASSERT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
 
   // An error results in one completed navigation.
   NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
@@ -175,7 +165,7 @@
   bool stale_cache_entry_present = false;
   ASSERT_TRUE(GetLatestErrorFromRendererClient(
       &error_code, &stale_cache_entry_present));
-  EXPECT_EQ(net::ERR_FAILED, error_code);
+  EXPECT_EQ(net::ERR_CONNECTION_REFUSED, error_code);
   EXPECT_TRUE(stale_cache_entry_present);
 
   // Clear the cache and repeat; confirm lack of entry in cache reported.
@@ -198,7 +188,7 @@
   stale_cache_entry_present = true;
   ASSERT_TRUE(GetLatestErrorFromRendererClient(
       &error_code, &stale_cache_entry_present));
-  EXPECT_EQ(net::ERR_FAILED, error_code);
+  EXPECT_EQ(net::ERR_CONNECTION_REFUSED, error_code);
   EXPECT_FALSE(stale_cache_entry_present);
 }
 
diff --git a/content/renderer/input/widget_input_handler_manager.cc b/content/renderer/input/widget_input_handler_manager.cc
index d06f3a92..ea1253b 100644
--- a/content/renderer/input/widget_input_handler_manager.cc
+++ b/content/renderer/input/widget_input_handler_manager.cc
@@ -280,16 +280,7 @@
     cc::TouchAction touch_action,
     uint32_t unique_touch_event_id,
     ui::InputHandlerProxy::EventDisposition event_disposition) {
-  if (base::FeatureList::IsEnabled(features::kCompositorTouchAction)) {
-    white_listed_touch_action_ = touch_action;
-    return;
-  }
-  mojom::WidgetInputHandlerHost* host = GetWidgetInputHandlerHost();
-  if (!host)
-    return;
-  InputEventAckState ack_state = InputEventDispositionToAck(event_disposition);
-  host->SetWhiteListedTouchAction(touch_action, unique_touch_event_id,
-                                  ack_state);
+  white_listed_touch_action_ = touch_action;
 }
 
 void WidgetInputHandlerManager::ProcessTouchAction(
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 76176518..2a1d7e60 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -1236,7 +1236,7 @@
   bool support_raster_interface = true;
   bool support_oop_rasterization =
       base::FeatureList::IsEnabled(features::kCanvasOopRasterization);
-  bool support_gles2_interface = !support_oop_rasterization;
+  bool support_gles2_interface = false;
   bool support_grcontext = !support_oop_rasterization;
   // Enable automatic flushes to improve canvas throughput.
   // See https://crbug.com/880901
diff --git a/content/test/data/accessibility/display-locking/all-committed-expected-blink.txt b/content/test/data/accessibility/display-locking/all-committed-expected-blink.txt
index 851b7d1c..316c86e 100644
--- a/content/test/data/accessibility/display-locking/all-committed-expected-blink.txt
+++ b/content/test/data/accessibility/display-locking/all-committed-expected-blink.txt
@@ -1,25 +1,26 @@
 rootWebArea
 ++genericContainer ignored
 ++++genericContainer ignored
-++++++genericContainer
-++++++++staticText name='spacer so that everything below will be offscreen (and won't get viewport-activated)'
-++++++++++inlineTextBox name='spacer so that everything below will be offscreen (and won't get viewport-activated)'
-++++++genericContainer offscreen
+++++++genericContainer ignored
+++++++++genericContainer
+++++++++++staticText name='spacer so that everything below will be offscreen (and won't get viewport-activated)'
+++++++++++++inlineTextBox name='spacer so that everything below will be offscreen (and won't get viewport-activated)'
 ++++++++genericContainer offscreen
-++++++++++staticText offscreen name='child text will be in AX tree but without layout'
-++++++++++++inlineTextBox offscreen name='child text will be in AX tree but without layout'
+++++++++++genericContainer offscreen
+++++++++++++staticText offscreen name='child text will be in AX tree but without layout'
+++++++++++++++inlineTextBox offscreen name='child text will be in AX tree but without layout'
+++++++++++genericContainer offscreen
+++++++++++++staticText offscreen name='nested activatable locked element will be in AX tree but without layout'
+++++++++++++++inlineTextBox offscreen name='nested activatable locked element will be in AX tree but without layout'
+++++++++staticText offscreen name='normal text 1'
+++++++++++inlineTextBox offscreen name='normal text 1'
 ++++++++genericContainer offscreen
-++++++++++staticText offscreen name='nested activatable locked element will be in AX tree but without layout'
-++++++++++++inlineTextBox offscreen name='nested activatable locked element will be in AX tree but without layout'
-++++++staticText offscreen name='normal text 1'
-++++++++inlineTextBox offscreen name='normal text 1'
-++++++genericContainer offscreen
-++++++++staticText offscreen name='nested non-viewport-activatable locked element will not be in AX tree'
-++++++++++inlineTextBox offscreen name='nested non-viewport-activatable locked element will not be in AX tree'
-++++++staticText offscreen name='normal text 2'
-++++++++inlineTextBox offscreen name='normal text 2'
-++++++genericContainer offscreen
-++++++++staticText offscreen name='nested non-activatable locked element will not be in AX tree'
-++++++++++inlineTextBox offscreen name='nested non-activatable locked element will not be in AX tree'
-++++++staticText offscreen name='normal text 3'
-++++++++inlineTextBox offscreen name='normal text 3'
+++++++++++staticText offscreen name='nested non-viewport-activatable locked element will not be in AX tree'
+++++++++++++inlineTextBox offscreen name='nested non-viewport-activatable locked element will not be in AX tree'
+++++++++staticText offscreen name='normal text 2'
+++++++++++inlineTextBox offscreen name='normal text 2'
+++++++++genericContainer offscreen
+++++++++++staticText offscreen name='nested non-activatable locked element will not be in AX tree'
+++++++++++++inlineTextBox offscreen name='nested non-activatable locked element will not be in AX tree'
+++++++++staticText offscreen name='normal text 3'
+++++++++++inlineTextBox offscreen name='normal text 3'
diff --git a/content/test/data/accessibility/display-locking/all-expected-blink.txt b/content/test/data/accessibility/display-locking/all-expected-blink.txt
index a78a116..758d45a 100644
--- a/content/test/data/accessibility/display-locking/all-expected-blink.txt
+++ b/content/test/data/accessibility/display-locking/all-expected-blink.txt
@@ -1,22 +1,23 @@
 rootWebArea
 ++genericContainer ignored
 ++++genericContainer ignored
-++++++genericContainer
-++++++++staticText name='spacer so that everything below will be offscreen (and won't get viewport-activated)'
-++++++++++inlineTextBox name='spacer so that everything below will be offscreen (and won't get viewport-activated)'
-++++++genericContainer offscreen
-++++++++staticText offscreen name='<newline>    '
+++++++genericContainer ignored
+++++++++genericContainer
+++++++++++staticText name='spacer so that everything below will be offscreen (and won't get viewport-activated)'
+++++++++++++inlineTextBox name='spacer so that everything below will be offscreen (and won't get viewport-activated)'
 ++++++++genericContainer offscreen
-++++++++++staticText offscreen name='child text will be in AX tree but without layout'
-++++++++staticText offscreen name='<newline>    '
+++++++++++staticText offscreen name='<newline>    '
+++++++++++genericContainer offscreen
+++++++++++++staticText offscreen name='child text will be in AX tree but without layout'
+++++++++++staticText offscreen name='<newline>    '
+++++++++++genericContainer offscreen
+++++++++++++staticText offscreen name='<newline>      nested activatable locked element will be in AX tree but without layout<newline>    '
+++++++++++staticText offscreen name='<newline>  '
+++++++++staticText offscreen name='normal text 1'
+++++++++++inlineTextBox offscreen name='normal text 1'
 ++++++++genericContainer offscreen
-++++++++++staticText offscreen name='<newline>      nested activatable locked element will be in AX tree but without layout<newline>    '
-++++++++staticText offscreen name='<newline>  '
-++++++staticText offscreen name='normal text 1'
-++++++++inlineTextBox offscreen name='normal text 1'
-++++++genericContainer offscreen
-++++++staticText offscreen name='normal text 2'
-++++++++inlineTextBox offscreen name='normal text 2'
-++++++genericContainer offscreen
-++++++staticText offscreen name='normal text 3'
-++++++++inlineTextBox offscreen name='normal text 3'
+++++++++staticText offscreen name='normal text 2'
+++++++++++inlineTextBox offscreen name='normal text 2'
+++++++++genericContainer offscreen
+++++++++staticText offscreen name='normal text 3'
+++++++++++inlineTextBox offscreen name='normal text 3'
diff --git a/content/test/data/accessibility/display-locking/non-activatable-expected-blink.txt b/content/test/data/accessibility/display-locking/non-activatable-expected-blink.txt
index 0cf70fd0..bbbbae78 100644
--- a/content/test/data/accessibility/display-locking/non-activatable-expected-blink.txt
+++ b/content/test/data/accessibility/display-locking/non-activatable-expected-blink.txt
@@ -1,4 +1,5 @@
 rootWebArea
 ++genericContainer ignored
 ++++genericContainer ignored
-++++++genericContainer
+++++++genericContainer ignored
+++++++++genericContainer
diff --git a/content/test/data/accessibility/display-locking/viewport-activation-expected-blink.txt b/content/test/data/accessibility/display-locking/viewport-activation-expected-blink.txt
index ba201df..4a3d7a2 100644
--- a/content/test/data/accessibility/display-locking/viewport-activation-expected-blink.txt
+++ b/content/test/data/accessibility/display-locking/viewport-activation-expected-blink.txt
@@ -1,20 +1,21 @@
 rootWebArea
 ++genericContainer ignored
 ++++genericContainer ignored
-++++++genericContainer
-++++++++staticText offscreen name='initial spacer, will initially make everything below this far away from the viewport'
-++++++++++inlineTextBox offscreen name='initial spacer, will initially make everything below this far away from the viewport'
-++++++genericContainer
-++++++++staticText name='This text will get viewport-activated because it's in the viewport, and will be in AX tree with layout.'
-++++++++++inlineTextBox name='This text will get viewport-activated because it's in the viewport, and will be in AX tree with layout.'
-++++++genericContainer
-++++++++staticText name='This text is also in viewport.'
-++++++++++inlineTextBox name='This text is also in viewport.'
-++++++genericContainer
-++++++++staticText name='spacer so that everything below will be offscreen (and won't get viewport-activated)'
-++++++++++inlineTextBox name='spacer so that everything below will be offscreen (and won't get viewport-activated)'
-++++++genericContainer
-++++++++staticText offscreen name='<newline>    This text will not get viewport-activated, and will be in AX tree but without layout.<newline>  '
-++++++genericContainer offscreen
-++++++++staticText offscreen name='doneActivating'
-++++++++++inlineTextBox offscreen name='doneActivating'
+++++++genericContainer ignored
+++++++++genericContainer
+++++++++++staticText offscreen name='initial spacer, will initially make everything below this far away from the viewport'
+++++++++++++inlineTextBox offscreen name='initial spacer, will initially make everything below this far away from the viewport'
+++++++++genericContainer
+++++++++++staticText name='This text will get viewport-activated because it's in the viewport, and will be in AX tree with layout.'
+++++++++++++inlineTextBox name='This text will get viewport-activated because it's in the viewport, and will be in AX tree with layout.'
+++++++++genericContainer
+++++++++++staticText name='This text is also in viewport.'
+++++++++++++inlineTextBox name='This text is also in viewport.'
+++++++++genericContainer
+++++++++++staticText name='spacer so that everything below will be offscreen (and won't get viewport-activated)'
+++++++++++++inlineTextBox name='spacer so that everything below will be offscreen (and won't get viewport-activated)'
+++++++++genericContainer
+++++++++++staticText offscreen name='<newline>    This text will not get viewport-activated, and will be in AX tree but without layout.<newline>  '
+++++++++genericContainer offscreen
+++++++++++staticText offscreen name='doneActivating'
+++++++++++++inlineTextBox offscreen name='doneActivating'
diff --git a/content/test/data/accessibility/html/button-with-listbox-popup-expected-blink.txt b/content/test/data/accessibility/html/button-with-listbox-popup-expected-blink.txt
index 25f6161..c67c2c6 100644
--- a/content/test/data/accessibility/html/button-with-listbox-popup-expected-blink.txt
+++ b/content/test/data/accessibility/html/button-with-listbox-popup-expected-blink.txt
@@ -1,13 +1,14 @@
 rootWebArea
 ++genericContainer ignored
-++++genericContainer
+++++genericContainer ignored
 ++++++genericContainer
-++++++++staticText name='Choose one:'
-++++++++++inlineTextBox name='Choose one:'
-++++++popUpButton name='Choose one: Foo'
-++++++++staticText name='Foo'
-++++++++++inlineTextBox name='Foo'
-++++++listBox name='Choose one:'
-++++++++listBoxOption name='Baz' selected=false
-++++++++listBoxOption name='Bar' selected=false
-++++++++listBoxOption name='Foo' selected=false
+++++++++genericContainer
+++++++++++staticText name='Choose one:'
+++++++++++++inlineTextBox name='Choose one:'
+++++++++popUpButton name='Choose one: Foo'
+++++++++++staticText name='Foo'
+++++++++++++inlineTextBox name='Foo'
+++++++++listBox name='Choose one:'
+++++++++++listBoxOption name='Baz' selected=false
+++++++++++listBoxOption name='Bar' selected=false
+++++++++++listBoxOption name='Foo' selected=false
diff --git a/content/test/data/accessibility/html/delete-selection-crash-expected-blink.txt b/content/test/data/accessibility/html/delete-selection-crash-expected-blink.txt
index 00f2a70..e646991 100644
--- a/content/test/data/accessibility/html/delete-selection-crash-expected-blink.txt
+++ b/content/test/data/accessibility/html/delete-selection-crash-expected-blink.txt
@@ -1,4 +1,5 @@
 rootWebArea
-++genericContainer
-++++staticText name='Done'
-++++++inlineTextBox name='Done'
+++genericContainer ignored
+++++genericContainer
+++++++staticText name='Done'
+++++++++inlineTextBox name='Done'
diff --git a/content/test/data/accessibility/html/ignored-selection-between-text-expected-blink.txt b/content/test/data/accessibility/html/ignored-selection-between-text-expected-blink.txt
index 93490b6..8fd29f6 100644
--- a/content/test/data/accessibility/html/ignored-selection-between-text-expected-blink.txt
+++ b/content/test/data/accessibility/html/ignored-selection-between-text-expected-blink.txt
@@ -1,18 +1,19 @@
 rootWebArea
 ++genericContainer ignored
 ++++genericContainer ignored
-++++++genericContainer
-++++++++staticText name='before selection' TreeData.textSelStartOffset=16
-++++++++++inlineTextBox name='before selection'
-++++++genericContainer ignored invisible
-++++++++staticText ignored invisible name='Some ignored text'
-++++++genericContainer
-++++++++staticText name='this text is not ignored'
-++++++++++inlineTextBox name='this text is not ignored'
-++++++genericContainer ignored invisible
-++++++++staticText ignored invisible name='this text is ignored'
-++++++genericContainer
-++++++++staticText name='after selection' TreeData.textSelEndOffset=0
-++++++++++inlineTextBox name='after selection'
-++++staticText name='Done'
-++++++inlineTextBox name='Done'
+++++++genericContainer ignored
+++++++++genericContainer
+++++++++++staticText name='before selection' TreeData.textSelStartOffset=16
+++++++++++++inlineTextBox name='before selection'
+++++++++genericContainer ignored invisible
+++++++++++staticText ignored invisible name='Some ignored text'
+++++++++genericContainer
+++++++++++staticText name='this text is not ignored'
+++++++++++++inlineTextBox name='this text is not ignored'
+++++++++genericContainer ignored invisible
+++++++++++staticText ignored invisible name='this text is ignored'
+++++++++genericContainer
+++++++++++staticText name='after selection' TreeData.textSelEndOffset=0
+++++++++++++inlineTextBox name='after selection'
+++++++staticText name='Done'
+++++++++inlineTextBox name='Done'
diff --git a/content/test/data/accessibility/html/ignored-selection-expected-blink.txt b/content/test/data/accessibility/html/ignored-selection-expected-blink.txt
index 036c5a4..e7bdf10 100644
--- a/content/test/data/accessibility/html/ignored-selection-expected-blink.txt
+++ b/content/test/data/accessibility/html/ignored-selection-expected-blink.txt
@@ -1,12 +1,13 @@
 rootWebArea
 ++genericContainer ignored
-++++paragraph ignored invisible
-++++staticText name='this text is not ignored' TreeData.textSelStartOffset=0
-++++++inlineTextBox name='this text is not ignored'
-++++genericContainer ignored invisible
-++++++staticText ignored invisible name='this text is ignored'
-++++genericContainer
-++++++staticText name='after selection' TreeData.textSelEndOffset=0
-++++++++inlineTextBox name='after selection'
-++++staticText name='Done'
-++++++inlineTextBox name='Done'
+++++genericContainer ignored
+++++++paragraph ignored invisible
+++++++staticText name='this text is not ignored' TreeData.textSelStartOffset=0
+++++++++inlineTextBox name='this text is not ignored'
+++++++genericContainer ignored invisible
+++++++++staticText ignored invisible name='this text is ignored'
+++++++genericContainer
+++++++++staticText name='after selection' TreeData.textSelEndOffset=0
+++++++++++inlineTextBox name='after selection'
+++++++staticText name='Done'
+++++++++inlineTextBox name='Done'
diff --git a/content/test/data/accessibility/html/ignored-selection-no-unignored-expected-blink.txt b/content/test/data/accessibility/html/ignored-selection-no-unignored-expected-blink.txt
index 0e6f0fac3..3bdf6cf5 100644
--- a/content/test/data/accessibility/html/ignored-selection-no-unignored-expected-blink.txt
+++ b/content/test/data/accessibility/html/ignored-selection-no-unignored-expected-blink.txt
@@ -1,9 +1,10 @@
 rootWebArea
 ++genericContainer ignored
 ++++genericContainer ignored
-++++++genericContainer ignored invisible
-++++++++staticText ignored invisible name='Some ignored text'
-++++++genericContainer ignored invisible
-++++++++staticText ignored invisible name='this text is also ignored'
-++++staticText name='Done'
-++++++inlineTextBox name='Done'
+++++++genericContainer ignored
+++++++++genericContainer ignored invisible
+++++++++++staticText ignored invisible name='Some ignored text'
+++++++++genericContainer ignored invisible
+++++++++++staticText ignored invisible name='this text is also ignored'
+++++++staticText name='Done'
+++++++++inlineTextBox name='Done'
diff --git a/content/test/data/accessibility/html/input-image-with-title-expected-blink.txt b/content/test/data/accessibility/html/input-image-with-title-expected-blink.txt
index cbf59aeb..4862440 100644
--- a/content/test/data/accessibility/html/input-image-with-title-expected-blink.txt
+++ b/content/test/data/accessibility/html/input-image-with-title-expected-blink.txt
@@ -1,6 +1,7 @@
 rootWebArea
-++genericContainer
-++++button inputType='image' name='email'
-++++++image
-++++++staticText name='email'
-++++++++inlineTextBox name='email'
+++genericContainer ignored
+++++genericContainer
+++++++button inputType='image' name='email'
+++++++++image
+++++++++staticText name='email'
+++++++++++inlineTextBox name='email'
diff --git a/content/test/data/accessibility/html/input-inside-label-expected-blink.txt b/content/test/data/accessibility/html/input-inside-label-expected-blink.txt
index 0e6acd17..3a21016 100644
--- a/content/test/data/accessibility/html/input-inside-label-expected-blink.txt
+++ b/content/test/data/accessibility/html/input-inside-label-expected-blink.txt
@@ -1,12 +1,13 @@
 rootWebArea
-++genericContainer
-++++checkBox inputType='checkbox' name='foo bar baz' checkedState=false
-++++textField inputType='text' value='bar'
-++++++genericContainer
-++++++++staticText name='bar'
-++++++++++inlineTextBox name='bar'
-++++checkBox inputType='checkbox' name='foo bar baz' checkedState=false
-++++textField inputType='text' value='bar'
-++++++genericContainer
-++++++++staticText name='bar'
-++++++++++inlineTextBox name='bar'
+++genericContainer ignored
+++++genericContainer
+++++++checkBox inputType='checkbox' name='foo bar baz' checkedState=false
+++++++textField inputType='text' value='bar'
+++++++++genericContainer
+++++++++++staticText name='bar'
+++++++++++++inlineTextBox name='bar'
+++++++checkBox inputType='checkbox' name='foo bar baz' checkedState=false
+++++++textField inputType='text' value='bar'
+++++++++genericContainer
+++++++++++staticText name='bar'
+++++++++++++inlineTextBox name='bar'
diff --git a/content/test/data/accessibility/html/label-with-presentational-child-expected-blink.txt b/content/test/data/accessibility/html/label-with-presentational-child-expected-blink.txt
index a944761..f45e537 100644
--- a/content/test/data/accessibility/html/label-with-presentational-child-expected-blink.txt
+++ b/content/test/data/accessibility/html/label-with-presentational-child-expected-blink.txt
@@ -1,17 +1,18 @@
 rootWebArea
-++genericContainer
-++++textField name='foo'
-++++++genericContainer
-++++labelText
-++++++genericContainer name='foo'
+++genericContainer ignored
+++++genericContainer
+++++++textField name='foo'
+++++++++genericContainer
+++++++labelText
+++++++++genericContainer name='foo'
+++++++++++genericContainer name='bar'
+++++++++++++staticText name='baz'
+++++++++++++++inlineTextBox name='baz'
+++++++lineBreak name='<newline>'
+++++++++inlineTextBox name='<newline>'
+++++++textField name='bar'
+++++++++genericContainer
+++++++labelText
 ++++++++genericContainer name='bar'
 ++++++++++staticText name='baz'
 ++++++++++++inlineTextBox name='baz'
-++++lineBreak name='<newline>'
-++++++inlineTextBox name='<newline>'
-++++textField name='bar'
-++++++genericContainer
-++++labelText
-++++++genericContainer name='bar'
-++++++++staticText name='baz'
-++++++++++inlineTextBox name='baz'
diff --git a/content/test/data/accessibility/html/label-with-selected-option-expected-blink.txt b/content/test/data/accessibility/html/label-with-selected-option-expected-blink.txt
index 552fc2a..33e71f5 100644
--- a/content/test/data/accessibility/html/label-with-selected-option-expected-blink.txt
+++ b/content/test/data/accessibility/html/label-with-selected-option-expected-blink.txt
@@ -1,34 +1,35 @@
 rootWebArea
 ++genericContainer ignored
-++++genericContainer
-++++++checkBox name='Test 1: Flash the screen 2 times.' checkedState=false
-++++++popUpButton collapsed value='2'
-++++++++menuListPopup invisible
-++++++++++menuListOption invisible name='1' selected=false
-++++++++++menuListOption name='2' selected=true
-++++++++++menuListOption invisible name='3' selected=false
-++++genericContainer
-++++++checkBox name='Test 2: Flash the screen 2 times.' checkedState=false
-++++++listBox activedescendantId=listBoxOption
-++++++++listBoxOption name='1' selected=false
-++++++++listBoxOption name='2' selected=true
-++++++++listBoxOption name='3' selected=false
-++++genericContainer
-++++++checkBox name='Test 3: Flash the screen two times.' checkedState=false
-++++++popUpButton collapsed value='two'
-++++++++menuListPopup invisible
-++++++++++menuListOption invisible name='1' selected=false
-++++++++++menuListOption name='two' selected=true
-++++++++++menuListOption invisible name='3' selected=false
-++++genericContainer
-++++++checkBox name='Test 4: Flash the screen two times.' checkedState=false
-++++++listBox activedescendantId=listBoxOption
-++++++++listBoxOption name='1' selected=false
-++++++++listBoxOption name='two' selected=true
-++++++++listBoxOption name='3' selected=false
-++++genericContainer
-++++++checkBox name='Test 5: Flash the screen two 3 times.' checkedState=false
-++++++listBox multiselectable activedescendantId=listBoxOption
-++++++++listBoxOption name='1' selected=false
-++++++++listBoxOption name='two' selected=true
-++++++++listBoxOption name='3' selected=true
+++++genericContainer ignored
+++++++genericContainer
+++++++++checkBox name='Test 1: Flash the screen 2 times.' checkedState=false
+++++++++popUpButton collapsed value='2'
+++++++++++menuListPopup invisible
+++++++++++++menuListOption invisible name='1' selected=false
+++++++++++++menuListOption name='2' selected=true
+++++++++++++menuListOption invisible name='3' selected=false
+++++++genericContainer
+++++++++checkBox name='Test 2: Flash the screen 2 times.' checkedState=false
+++++++++listBox activedescendantId=listBoxOption
+++++++++++listBoxOption name='1' selected=false
+++++++++++listBoxOption name='2' selected=true
+++++++++++listBoxOption name='3' selected=false
+++++++genericContainer
+++++++++checkBox name='Test 3: Flash the screen two times.' checkedState=false
+++++++++popUpButton collapsed value='two'
+++++++++++menuListPopup invisible
+++++++++++++menuListOption invisible name='1' selected=false
+++++++++++++menuListOption name='two' selected=true
+++++++++++++menuListOption invisible name='3' selected=false
+++++++genericContainer
+++++++++checkBox name='Test 4: Flash the screen two times.' checkedState=false
+++++++++listBox activedescendantId=listBoxOption
+++++++++++listBoxOption name='1' selected=false
+++++++++++listBoxOption name='two' selected=true
+++++++++++listBoxOption name='3' selected=false
+++++++genericContainer
+++++++++checkBox name='Test 5: Flash the screen two 3 times.' checkedState=false
+++++++++listBox multiselectable activedescendantId=listBoxOption
+++++++++++listBoxOption name='1' selected=false
+++++++++++listBoxOption name='two' selected=true
+++++++++++listBoxOption name='3' selected=true
diff --git a/content/test/data/accessibility/html/navigation-expected-blink.txt b/content/test/data/accessibility/html/navigation-expected-blink.txt
index 3db3511..e8ca9fd 100644
--- a/content/test/data/accessibility/html/navigation-expected-blink.txt
+++ b/content/test/data/accessibility/html/navigation-expected-blink.txt
@@ -1,6 +1,7 @@
 rootWebArea
 ++genericContainer ignored
-++++navigation
-++++++link name='Don't click on me'
-++++++++staticText name='Don't click on me'
-++++++++++inlineTextBox name='Don't click on me'
+++++genericContainer ignored
+++++++navigation
+++++++++link name='Don't click on me'
+++++++++++staticText name='Don't click on me'
+++++++++++++inlineTextBox name='Don't click on me'
diff --git a/content/test/data/accessibility/html/node-changed-crash-in-editable-text-expected-blink.txt b/content/test/data/accessibility/html/node-changed-crash-in-editable-text-expected-blink.txt
index 12a7d67..22293a0 100644
--- a/content/test/data/accessibility/html/node-changed-crash-in-editable-text-expected-blink.txt
+++ b/content/test/data/accessibility/html/node-changed-crash-in-editable-text-expected-blink.txt
@@ -1,4 +1,5 @@
 rootWebArea
-++genericContainer multiline name='Done'
-++++genericContainer
-++++genericContainer
+++genericContainer ignored
+++++genericContainer multiline name='Done'
+++++++genericContainer
+++++++genericContainer
diff --git a/content/test/data/accessibility/html/object-expected-blink.txt b/content/test/data/accessibility/html/object-expected-blink.txt
index 719bb45..a500159 100644
--- a/content/test/data/accessibility/html/object-expected-blink.txt
+++ b/content/test/data/accessibility/html/object-expected-blink.txt
@@ -1,3 +1,4 @@
 rootWebArea
-++genericContainer
-++++pluginObject
+++genericContainer ignored
+++++genericContainer
+++++++pluginObject
diff --git a/content/test/data/accessibility/html/offscreen-expected-blink.txt b/content/test/data/accessibility/html/offscreen-expected-blink.txt
index 01d484c..a2421e6 100644
--- a/content/test/data/accessibility/html/offscreen-expected-blink.txt
+++ b/content/test/data/accessibility/html/offscreen-expected-blink.txt
@@ -1,9 +1,10 @@
 rootWebArea
 ++genericContainer ignored
-++++button name='Onscreen'
-++++++staticText name='Onscreen'
-++++++++inlineTextBox name='Onscreen'
 ++++genericContainer ignored
-++++button offscreen name='Offscreen'
-++++++staticText offscreen name='Offscreen'
-++++++++inlineTextBox offscreen name='Offscreen'
+++++++button name='Onscreen'
+++++++++staticText name='Onscreen'
+++++++++++inlineTextBox name='Onscreen'
+++++++genericContainer ignored
+++++++button offscreen name='Offscreen'
+++++++++staticText offscreen name='Offscreen'
+++++++++++inlineTextBox offscreen name='Offscreen'
diff --git a/content/test/data/accessibility/html/offscreen-iframe-expected-blink.txt b/content/test/data/accessibility/html/offscreen-iframe-expected-blink.txt
index c568133..8bacf77 100644
--- a/content/test/data/accessibility/html/offscreen-iframe-expected-blink.txt
+++ b/content/test/data/accessibility/html/offscreen-iframe-expected-blink.txt
@@ -1,7 +1,9 @@
 rootWebArea
-++genericContainer
-++++iframe
-++++++rootWebArea
-++++++++genericContainer ignored
-++++++++++genericContainer name='iframe_onscreen'
-++++++++++genericContainer offscreen name='iframe_offscreen'
+++genericContainer ignored
+++++genericContainer
+++++++iframe
+++++++++rootWebArea
+++++++++++genericContainer ignored
+++++++++++++genericContainer ignored
+++++++++++++++genericContainer name='iframe_onscreen'
+++++++++++++++genericContainer offscreen name='iframe_offscreen'
diff --git a/content/test/data/accessibility/html/offscreen-scroll-expected-blink.txt b/content/test/data/accessibility/html/offscreen-scroll-expected-blink.txt
index dbb8a7e..8a8dac5 100644
--- a/content/test/data/accessibility/html/offscreen-scroll-expected-blink.txt
+++ b/content/test/data/accessibility/html/offscreen-scroll-expected-blink.txt
@@ -1,10 +1,11 @@
 rootWebArea scrollY=640
 ++genericContainer ignored
-++++button offscreen name='Onscreen before scroll'
-++++++staticText offscreen name='Onscreen before scroll'
-++++++++inlineTextBox offscreen name='Onscreen before scroll'
 ++++genericContainer ignored
-++++button name='Scrolled Button'
-++++++staticText name='Offscreen before scroll'
-++++++++inlineTextBox name='Offscreen before scroll'
-++++genericContainer ignored
+++++++button offscreen name='Onscreen before scroll'
+++++++++staticText offscreen name='Onscreen before scroll'
+++++++++++inlineTextBox offscreen name='Onscreen before scroll'
+++++++genericContainer ignored
+++++++button name='Scrolled Button'
+++++++++staticText name='Offscreen before scroll'
+++++++++++inlineTextBox name='Offscreen before scroll'
+++++++genericContainer ignored
diff --git a/content/test/data/accessibility/html/offscreen-select-expected-blink.txt b/content/test/data/accessibility/html/offscreen-select-expected-blink.txt
index cb2bc74f..9c8b9b5 100644
--- a/content/test/data/accessibility/html/offscreen-select-expected-blink.txt
+++ b/content/test/data/accessibility/html/offscreen-select-expected-blink.txt
@@ -1,13 +1,14 @@
 rootWebArea
 ++genericContainer ignored
-++++popUpButton collapsed value='Onscreen 1'
-++++++menuListPopup invisible
-++++++++menuListOption name='Onscreen 1' selected=true
-++++++++menuListOption invisible name='Onscreen 2' selected=false
-++++++++menuListOption invisible name='Onscreen 3' selected=false
 ++++genericContainer ignored
-++++popUpButton collapsed offscreen value='Offscreen 1'
-++++++menuListPopup invisible
-++++++++menuListOption offscreen name='Offscreen 1' selected=true
-++++++++menuListOption invisible offscreen name='Offscreen 2' selected=false
-++++++++menuListOption invisible offscreen name='Offscreen 3' selected=false
+++++++popUpButton collapsed value='Onscreen 1'
+++++++++menuListPopup invisible
+++++++++++menuListOption name='Onscreen 1' selected=true
+++++++++++menuListOption invisible name='Onscreen 2' selected=false
+++++++++++menuListOption invisible name='Onscreen 3' selected=false
+++++++genericContainer ignored
+++++++popUpButton collapsed offscreen value='Offscreen 1'
+++++++++menuListPopup invisible
+++++++++++menuListOption offscreen name='Offscreen 1' selected=true
+++++++++++menuListOption invisible offscreen name='Offscreen 2' selected=false
+++++++++++menuListOption invisible offscreen name='Offscreen 3' selected=false
diff --git a/content/test/data/accessibility/html/ol-expected-blink.txt b/content/test/data/accessibility/html/ol-expected-blink.txt
index 5f2f206..6da89e6 100644
--- a/content/test/data/accessibility/html/ol-expected-blink.txt
+++ b/content/test/data/accessibility/html/ol-expected-blink.txt
@@ -1,40 +1,41 @@
 rootWebArea
 ++genericContainer ignored
-++++list
-++++++listItem hierarchicalLevel=1
-++++++++listMarker name='1. '
-++++++++++staticText name='1. '
-++++++++++++inlineTextBox name='1. '
-++++++++staticText name='Chrome'
-++++++++++inlineTextBox name='Chrome'
-++++++listItem hierarchicalLevel=1
-++++++++listMarker name='2. '
-++++++++++staticText name='2. '
-++++++++++++inlineTextBox name='2. '
-++++++++staticText name='Safari'
-++++++++++inlineTextBox name='Safari'
-++++++listItem hierarchicalLevel=1
-++++++++listMarker name='3. '
-++++++++++staticText name='3. '
-++++++++++++inlineTextBox name='3. '
-++++++++staticText name='IE'
-++++++++++inlineTextBox name='IE'
-++++list
-++++++listItem hierarchicalLevel=1
-++++++++listMarker name='10. '
-++++++++++staticText name='10. '
-++++++++++++inlineTextBox name='10. '
-++++++++staticText name='Android'
-++++++++++inlineTextBox name='Android'
-++++++listItem hierarchicalLevel=1
-++++++++listMarker name='11. '
-++++++++++staticText name='11. '
-++++++++++++inlineTextBox name='11. '
-++++++++staticText name='Mac'
-++++++++++inlineTextBox name='Mac'
-++++++listItem hierarchicalLevel=1
-++++++++listMarker name='12. '
-++++++++++staticText name='12. '
-++++++++++++inlineTextBox name='12. '
-++++++++staticText name='Windows'
-++++++++++inlineTextBox name='Windows'
+++++genericContainer ignored
+++++++list
+++++++++listItem hierarchicalLevel=1
+++++++++++listMarker name='1. '
+++++++++++++staticText name='1. '
+++++++++++++++inlineTextBox name='1. '
+++++++++++staticText name='Chrome'
+++++++++++++inlineTextBox name='Chrome'
+++++++++listItem hierarchicalLevel=1
+++++++++++listMarker name='2. '
+++++++++++++staticText name='2. '
+++++++++++++++inlineTextBox name='2. '
+++++++++++staticText name='Safari'
+++++++++++++inlineTextBox name='Safari'
+++++++++listItem hierarchicalLevel=1
+++++++++++listMarker name='3. '
+++++++++++++staticText name='3. '
+++++++++++++++inlineTextBox name='3. '
+++++++++++staticText name='IE'
+++++++++++++inlineTextBox name='IE'
+++++++list
+++++++++listItem hierarchicalLevel=1
+++++++++++listMarker name='10. '
+++++++++++++staticText name='10. '
+++++++++++++++inlineTextBox name='10. '
+++++++++++staticText name='Android'
+++++++++++++inlineTextBox name='Android'
+++++++++listItem hierarchicalLevel=1
+++++++++++listMarker name='11. '
+++++++++++++staticText name='11. '
+++++++++++++++inlineTextBox name='11. '
+++++++++++staticText name='Mac'
+++++++++++++inlineTextBox name='Mac'
+++++++++listItem hierarchicalLevel=1
+++++++++++listMarker name='12. '
+++++++++++++staticText name='12. '
+++++++++++++++inlineTextBox name='12. '
+++++++++++staticText name='Windows'
+++++++++++++inlineTextBox name='Windows'
diff --git a/content/test/data/accessibility/html/open-modal-expected-blink.txt b/content/test/data/accessibility/html/open-modal-expected-blink.txt
index 635d082..3cfccc2 100644
--- a/content/test/data/accessibility/html/open-modal-expected-blink.txt
+++ b/content/test/data/accessibility/html/open-modal-expected-blink.txt
@@ -1,22 +1,25 @@
 rootWebArea
 ++genericContainer ignored
-++++staticText name='some text'
-++++++inlineTextBox name='some text'
 ++++genericContainer ignored
+++++++staticText name='some text'
+++++++++inlineTextBox name='some text'
+++++++genericContainer ignored
+++++++++genericContainer ignored invisible
+=== Start Continuation ===
+rootWebArea
+++genericContainer ignored
+++++genericContainer ignored invisible
 ++++++genericContainer ignored invisible
+++++++++dialog
+++++++++++genericContainer name='Some Text'
+++++++++++++staticText name='Some Text'
+++++++++++++++inlineTextBox name='Some Text'
 === Start Continuation ===
 rootWebArea
-++genericContainer ignored invisible
+++genericContainer ignored
 ++++genericContainer ignored invisible
-++++++dialog
-++++++++genericContainer name='Some Text'
-++++++++++staticText name='Some Text'
-++++++++++++inlineTextBox name='Some Text'
-=== Start Continuation ===
-rootWebArea
-++genericContainer ignored invisible
-++++genericContainer ignored invisible
-++++++dialog
-++++++++genericContainer name='Done'
-++++++++++staticText name='Done'
-++++++++++++inlineTextBox name='Done'
+++++++genericContainer ignored invisible
+++++++++dialog
+++++++++++genericContainer name='Done'
+++++++++++++staticText name='Done'
+++++++++++++++inlineTextBox name='Done'
diff --git a/content/test/data/accessibility/html/optgroup-expected-blink.txt b/content/test/data/accessibility/html/optgroup-expected-blink.txt
index b705b94..d0d3b87 100644
--- a/content/test/data/accessibility/html/optgroup-expected-blink.txt
+++ b/content/test/data/accessibility/html/optgroup-expected-blink.txt
@@ -1,19 +1,20 @@
 rootWebArea
-++genericContainer
-++++listBox setSize=8
-++++++genericContainer ignored
-++++++++group name='Enabled' setSize=0
-++++++++++staticText name='Enabled'
-++++++++++++inlineTextBox name='Enabled'
-++++++++listBoxOption name='One' setSize=8 posInSet=1 selected=false
-++++++++listBoxOption name='Two' setSize=8 posInSet=2 selected=false
-++++++++listBoxOption name='Three' setSize=8 posInSet=3 selected=false
-++++++++listBoxOption name='Four' setSize=8 posInSet=4 selected=false
-++++++genericContainer ignored
-++++++++group name='Disabled' setSize=0
-++++++++++staticText name='Disabled'
-++++++++++++inlineTextBox name='Disabled'
-++++++++listBoxOption name='One' restriction=disabled setSize=8 posInSet=5
-++++++++listBoxOption name='Two' restriction=disabled setSize=8 posInSet=6
-++++++++listBoxOption name='Three' restriction=disabled setSize=8 posInSet=7
-++++++++listBoxOption name='Four' restriction=disabled setSize=8 posInSet=8
+++genericContainer ignored
+++++genericContainer
+++++++listBox setSize=8
+++++++++genericContainer ignored
+++++++++++group name='Enabled' setSize=0
+++++++++++++staticText name='Enabled'
+++++++++++++++inlineTextBox name='Enabled'
+++++++++++listBoxOption name='One' setSize=8 posInSet=1 selected=false
+++++++++++listBoxOption name='Two' setSize=8 posInSet=2 selected=false
+++++++++++listBoxOption name='Three' setSize=8 posInSet=3 selected=false
+++++++++++listBoxOption name='Four' setSize=8 posInSet=4 selected=false
+++++++++genericContainer ignored
+++++++++++group name='Disabled' setSize=0
+++++++++++++staticText name='Disabled'
+++++++++++++++inlineTextBox name='Disabled'
+++++++++++listBoxOption name='One' restriction=disabled setSize=8 posInSet=5
+++++++++++listBoxOption name='Two' restriction=disabled setSize=8 posInSet=6
+++++++++++listBoxOption name='Three' restriction=disabled setSize=8 posInSet=7
+++++++++++listBoxOption name='Four' restriction=disabled setSize=8 posInSet=8
diff --git a/content/test/data/accessibility/html/p-expected-blink.txt b/content/test/data/accessibility/html/p-expected-blink.txt
index 87fb3dd..be2268d 100644
--- a/content/test/data/accessibility/html/p-expected-blink.txt
+++ b/content/test/data/accessibility/html/p-expected-blink.txt
@@ -1,9 +1,10 @@
 rootWebArea
 ++genericContainer ignored
-++++staticText name='Before'
-++++++inlineTextBox name='Before' wordStarts=0 wordEnds=6
-++++paragraph
-++++++staticText name='Paragraph'
-++++++++inlineTextBox name='Paragraph' wordStarts=0 wordEnds=9
-++++staticText name='After'
-++++++inlineTextBox name='After' wordStarts=0 wordEnds=5
+++++genericContainer ignored
+++++++staticText name='Before'
+++++++++inlineTextBox name='Before' wordStarts=0 wordEnds=6
+++++++paragraph
+++++++++staticText name='Paragraph'
+++++++++++inlineTextBox name='Paragraph' wordStarts=0 wordEnds=9
+++++++staticText name='After'
+++++++++inlineTextBox name='After' wordStarts=0 wordEnds=5
diff --git a/content/test/data/accessibility/html/param-expected-blink.txt b/content/test/data/accessibility/html/param-expected-blink.txt
index 719bb45..a500159 100644
--- a/content/test/data/accessibility/html/param-expected-blink.txt
+++ b/content/test/data/accessibility/html/param-expected-blink.txt
@@ -1,3 +1,4 @@
 rootWebArea
-++genericContainer
-++++pluginObject
+++genericContainer ignored
+++++genericContainer
+++++++pluginObject
diff --git a/content/test/data/accessibility/html/portal-expected-blink.txt b/content/test/data/accessibility/html/portal-expected-blink.txt
index e65e79ad..6daec66 100644
--- a/content/test/data/accessibility/html/portal-expected-blink.txt
+++ b/content/test/data/accessibility/html/portal-expected-blink.txt
@@ -1,11 +1,13 @@
 rootWebArea focusable
 ++genericContainer ignored
-++++paragraph
-++++++staticText name='Before portal'
-++++++++inlineTextBox name='Before portal'
-++++portal focusable name='portal'
-++++++rootWebArea name='Text in iframe'
-++++++++genericContainer ignored
-++++paragraph
-++++++staticText name='After portal'
-++++++++inlineTextBox name='After portal'
+++++genericContainer ignored
+++++++paragraph
+++++++++staticText name='Before portal'
+++++++++++inlineTextBox name='Before portal'
+++++++portal focusable name='portal'
+++++++++rootWebArea name='Text in iframe'
+++++++++++genericContainer ignored
+++++++++++++genericContainer ignored
+++++++paragraph
+++++++++staticText name='After portal'
+++++++++++inlineTextBox name='After portal'
diff --git a/content/test/data/accessibility/html/portal-name-from-text-expected-blink.txt b/content/test/data/accessibility/html/portal-name-from-text-expected-blink.txt
index e4147eaa..0967bdf 100644
--- a/content/test/data/accessibility/html/portal-name-from-text-expected-blink.txt
+++ b/content/test/data/accessibility/html/portal-name-from-text-expected-blink.txt
@@ -1,5 +1,7 @@
 rootWebArea
-++genericContainer
-++++portal
-++++++rootWebArea name='Text in iframe'
-++++++++genericContainer ignored
+++genericContainer ignored
+++++genericContainer
+++++++portal
+++++++++rootWebArea name='Text in iframe'
+++++++++++genericContainer ignored
+++++++++++++genericContainer ignored
diff --git a/content/test/data/accessibility/html/portal-name-from-visible-text-expected-blink.txt b/content/test/data/accessibility/html/portal-name-from-visible-text-expected-blink.txt
index 0dae2e0..8309412 100644
--- a/content/test/data/accessibility/html/portal-name-from-visible-text-expected-blink.txt
+++ b/content/test/data/accessibility/html/portal-name-from-visible-text-expected-blink.txt
@@ -1,8 +1,10 @@
 rootWebArea
-++genericContainer
-++++portal
-++++++rootWebArea name='visible text'
-++++++++genericContainer ignored
+++genericContainer ignored
+++++genericContainer
+++++++portal
+++++++++rootWebArea name='visible text'
 ++++++++++genericContainer ignored
-++++++++++genericContainer ignored
-++++++++++genericContainer ignored
+++++++++++++genericContainer ignored
+++++++++++++++genericContainer ignored
+++++++++++++++genericContainer ignored
+++++++++++++++genericContainer ignored
diff --git a/content/test/data/accessibility/html/pre-expected-blink.txt b/content/test/data/accessibility/html/pre-expected-blink.txt
index ade0523..d048678 100644
--- a/content/test/data/accessibility/html/pre-expected-blink.txt
+++ b/content/test/data/accessibility/html/pre-expected-blink.txt
@@ -1,20 +1,21 @@
 rootWebArea
 ++genericContainer ignored
-++++pre
-++++++staticText name='This test is to check   pre<newline>formatting.'
-++++++++inlineTextBox name='This test is to check   pre'
-++++++++inlineTextBox name='<newline>'
-++++++++inlineTextBox name='formatting.'
-++++genericContainer
-++++++staticText name='This test is to check   pre<newline>formatting'
-++++++++inlineTextBox name='This test is to check   pre'
-++++++++inlineTextBox name='<newline>'
-++++++++inlineTextBox name='formatting'
-++++genericContainer
-++++++staticText name='This test is to check   pre<newline>formatting.'
-++++++++inlineTextBox name='This test is to check   pre'
-++++++++inlineTextBox name='<newline>'
-++++++++inlineTextBox name='formatting.'
-++++genericContainer
-++++++staticText name='This test is to check pre formatting.'
-++++++++inlineTextBox name='This test is to check pre formatting.'
+++++genericContainer ignored
+++++++pre
+++++++++staticText name='This test is to check   pre<newline>formatting.'
+++++++++++inlineTextBox name='This test is to check   pre'
+++++++++++inlineTextBox name='<newline>'
+++++++++++inlineTextBox name='formatting.'
+++++++genericContainer
+++++++++staticText name='This test is to check   pre<newline>formatting'
+++++++++++inlineTextBox name='This test is to check   pre'
+++++++++++inlineTextBox name='<newline>'
+++++++++++inlineTextBox name='formatting'
+++++++genericContainer
+++++++++staticText name='This test is to check   pre<newline>formatting.'
+++++++++++inlineTextBox name='This test is to check   pre'
+++++++++++inlineTextBox name='<newline>'
+++++++++++inlineTextBox name='formatting.'
+++++++genericContainer
+++++++++staticText name='This test is to check pre formatting.'
+++++++++++inlineTextBox name='This test is to check pre formatting.'
diff --git a/content/test/data/accessibility/html/progress-expected-blink.txt b/content/test/data/accessibility/html/progress-expected-blink.txt
index 2a2bdddf..3adbbae 100644
--- a/content/test/data/accessibility/html/progress-expected-blink.txt
+++ b/content/test/data/accessibility/html/progress-expected-blink.txt
@@ -1,4 +1,5 @@
 rootWebArea
-++genericContainer
-++++progressIndicator valueForRange=22.00 minValueForRange=0.00 maxValueForRange=100.00
-++++progressIndicator minValueForRange=0.00 maxValueForRange=1.00
+++genericContainer ignored
+++++genericContainer
+++++++progressIndicator valueForRange=22.00 minValueForRange=0.00 maxValueForRange=100.00
+++++++progressIndicator minValueForRange=0.00 maxValueForRange=1.00
diff --git a/content/test/data/accessibility/html/q-expected-blink.txt b/content/test/data/accessibility/html/q-expected-blink.txt
index 62b1c0a..65ff6d0 100644
--- a/content/test/data/accessibility/html/q-expected-blink.txt
+++ b/content/test/data/accessibility/html/q-expected-blink.txt
@@ -1,13 +1,14 @@
 rootWebArea
 ++genericContainer ignored
-++++paragraph
-++++++staticText name='This is '
-++++++++inlineTextBox name='This is '
-++++++staticText name='"'
-++++++++inlineTextBox name='"'
-++++++staticText name='Chromium Blink'
-++++++++inlineTextBox name='Chromium Blink'
-++++++staticText name='"'
-++++++++inlineTextBox name='"'
-++++++staticText name=' based browser.'
-++++++++inlineTextBox name=' based browser.'
+++++genericContainer ignored
+++++++paragraph
+++++++++staticText name='This is '
+++++++++++inlineTextBox name='This is '
+++++++++staticText name='"'
+++++++++++inlineTextBox name='"'
+++++++++staticText name='Chromium Blink'
+++++++++++inlineTextBox name='Chromium Blink'
+++++++++staticText name='"'
+++++++++++inlineTextBox name='"'
+++++++++staticText name=' based browser.'
+++++++++++inlineTextBox name=' based browser.'
diff --git a/content/test/data/accessibility/html/reparent-crash-expected-blink.txt b/content/test/data/accessibility/html/reparent-crash-expected-blink.txt
index e3d1d542..c0fd23a 100644
--- a/content/test/data/accessibility/html/reparent-crash-expected-blink.txt
+++ b/content/test/data/accessibility/html/reparent-crash-expected-blink.txt
@@ -1,6 +1,7 @@
 rootWebArea
 ++genericContainer ignored
-++++listItem name='@NO_CHILDREN_DUMP'
-++++genericContainer
-++++++staticText name='Done'
-++++++++inlineTextBox name='Done'
+++++genericContainer ignored
+++++++listItem name='@NO_CHILDREN_DUMP'
+++++++genericContainer
+++++++++staticText name='Done'
+++++++++++inlineTextBox name='Done'
diff --git a/content/test/data/accessibility/html/replace-data-expected-blink.txt b/content/test/data/accessibility/html/replace-data-expected-blink.txt
index 5f3f9df1..5f96789 100644
--- a/content/test/data/accessibility/html/replace-data-expected-blink.txt
+++ b/content/test/data/accessibility/html/replace-data-expected-blink.txt
@@ -1,8 +1,9 @@
 rootWebArea
 ++genericContainer ignored
-++++paragraph
-++++++staticText name='apples'
-++++++++inlineTextBox name='apples'
-++++paragraph
-++++++staticText name='bananas'
-++++++++inlineTextBox name='bananas'
+++++genericContainer ignored
+++++++paragraph
+++++++++staticText name='apples'
+++++++++++inlineTextBox name='apples'
+++++++paragraph
+++++++++staticText name='bananas'
+++++++++++inlineTextBox name='bananas'
diff --git a/content/test/data/accessibility/html/ruby-expected-blink.txt b/content/test/data/accessibility/html/ruby-expected-blink.txt
index 4c510485..92dff8bc 100644
--- a/content/test/data/accessibility/html/ruby-expected-blink.txt
+++ b/content/test/data/accessibility/html/ruby-expected-blink.txt
@@ -1,8 +1,9 @@
 rootWebArea
-++genericContainer
-++++ruby
-++++++rubyAnnotation
-++++++++staticText name='ruby text'
-++++++++++inlineTextBox name='ruby text'
-++++++staticText name='ruby base'
-++++++++inlineTextBox name='ruby base'
+++genericContainer ignored
+++++genericContainer
+++++++ruby
+++++++++rubyAnnotation
+++++++++++staticText name='ruby text'
+++++++++++++inlineTextBox name='ruby text'
+++++++++staticText name='ruby base'
+++++++++++inlineTextBox name='ruby base'
diff --git a/content/test/data/accessibility/html/s-expected-blink.txt b/content/test/data/accessibility/html/s-expected-blink.txt
index b88b80e..39c2febc 100644
--- a/content/test/data/accessibility/html/s-expected-blink.txt
+++ b/content/test/data/accessibility/html/s-expected-blink.txt
@@ -1,4 +1,5 @@
 rootWebArea
-++genericContainer
-++++staticText name='My car is blue.'
-++++++inlineTextBox name='My car is blue.'
+++genericContainer ignored
+++++genericContainer
+++++++staticText name='My car is blue.'
+++++++++inlineTextBox name='My car is blue.'
diff --git a/content/test/data/accessibility/html/samp-expected-blink.txt b/content/test/data/accessibility/html/samp-expected-blink.txt
index c6c4237..d46050e 100644
--- a/content/test/data/accessibility/html/samp-expected-blink.txt
+++ b/content/test/data/accessibility/html/samp-expected-blink.txt
@@ -1,4 +1,5 @@
 rootWebArea
-++genericContainer
-++++staticText name='Sample output from a computer program'
-++++++inlineTextBox name='Sample output from a computer program'
+++genericContainer ignored
+++++genericContainer
+++++++staticText name='Sample output from a computer program'
+++++++++inlineTextBox name='Sample output from a computer program'
diff --git a/content/test/data/accessibility/html/section-expected-blink.txt b/content/test/data/accessibility/html/section-expected-blink.txt
index fe59ab54..3c2a5b5 100644
--- a/content/test/data/accessibility/html/section-expected-blink.txt
+++ b/content/test/data/accessibility/html/section-expected-blink.txt
@@ -1,8 +1,9 @@
 rootWebArea
 ++genericContainer ignored
-++++section
-++++++staticText name='This is a section element.'
-++++++++inlineTextBox name='This is a section element.'
-++++section name='section'
-++++++staticText name='This is a named section element.'
-++++++++inlineTextBox name='This is a named section element.'
+++++genericContainer ignored
+++++++section
+++++++++staticText name='This is a section element.'
+++++++++++inlineTextBox name='This is a section element.'
+++++++section name='section'
+++++++++staticText name='This is a named section element.'
+++++++++++inlineTextBox name='This is a named section element.'
diff --git a/content/test/data/accessibility/html/select-expected-blink.txt b/content/test/data/accessibility/html/select-expected-blink.txt
index a881ebd..c0a0a42 100644
--- a/content/test/data/accessibility/html/select-expected-blink.txt
+++ b/content/test/data/accessibility/html/select-expected-blink.txt
@@ -1,25 +1,26 @@
 rootWebArea focusable
-++genericContainer
-++++popUpButton collapsed focusable value='Placeholder option' setSize=3 haspopup=menu
-++++++menuListPopup invisible setSize=3
-++++++++menuListOption focusable name='Placeholder option' setSize=3 posInSet=1 selected=true
-++++++++menuListOption focusable invisible name='Option 1' setSize=3 posInSet=2 selected=false
-++++++++menuListOption focusable invisible name='Option 2' setSize=3 posInSet=3 selected=false
-++++popUpButton collapsed focusable value='Option 2' setSize=3 haspopup=menu
-++++++menuListPopup invisible setSize=3
-++++++++menuListOption focusable invisible name='Option 1' setSize=3 posInSet=1 selected=false
-++++++++menuListOption focusable name='Option 2' setSize=3 posInSet=2 selected=true
-++++++++menuListOption focusable invisible name='Option 3' setSize=3 posInSet=3 selected=false
-++++popUpButton collapsed focusable required value='Option 1' setSize=3 haspopup=menu
-++++++menuListPopup invisible setSize=3
-++++++++menuListOption focusable name='Option 1' setSize=3 posInSet=1 selected=true
-++++++++menuListOption focusable invisible name='Option 2' setSize=3 posInSet=2 selected=false
-++++++++menuListOption focusable invisible name='Option 3' setSize=3 posInSet=3 selected=false
-++++listBox focusable multiselectable setSize=3
-++++++listBoxOption focusable name='Option 1' setSize=3 posInSet=1 selected=false
-++++++listBoxOption focusable name='Option 2' setSize=3 posInSet=2 selected=false
-++++++listBoxOption focusable name='Option 3' setSize=3 posInSet=3 selected=false
-++++listBox focusable setSize=3
-++++++listBoxOption focusable name='Option 1' setSize=3 posInSet=1 selected=false
-++++++listBoxOption focusable name='Option 2' setSize=3 posInSet=2 selected=false
-++++++listBoxOption focusable name='Option 3' setSize=3 posInSet=3 selected=false
+++genericContainer ignored
+++++genericContainer
+++++++popUpButton collapsed focusable value='Placeholder option' setSize=3 haspopup=menu
+++++++++menuListPopup invisible setSize=3
+++++++++++menuListOption focusable name='Placeholder option' setSize=3 posInSet=1 selected=true
+++++++++++menuListOption focusable invisible name='Option 1' setSize=3 posInSet=2 selected=false
+++++++++++menuListOption focusable invisible name='Option 2' setSize=3 posInSet=3 selected=false
+++++++popUpButton collapsed focusable value='Option 2' setSize=3 haspopup=menu
+++++++++menuListPopup invisible setSize=3
+++++++++++menuListOption focusable invisible name='Option 1' setSize=3 posInSet=1 selected=false
+++++++++++menuListOption focusable name='Option 2' setSize=3 posInSet=2 selected=true
+++++++++++menuListOption focusable invisible name='Option 3' setSize=3 posInSet=3 selected=false
+++++++popUpButton collapsed focusable required value='Option 1' setSize=3 haspopup=menu
+++++++++menuListPopup invisible setSize=3
+++++++++++menuListOption focusable name='Option 1' setSize=3 posInSet=1 selected=true
+++++++++++menuListOption focusable invisible name='Option 2' setSize=3 posInSet=2 selected=false
+++++++++++menuListOption focusable invisible name='Option 3' setSize=3 posInSet=3 selected=false
+++++++listBox focusable multiselectable setSize=3
+++++++++listBoxOption focusable name='Option 1' setSize=3 posInSet=1 selected=false
+++++++++listBoxOption focusable name='Option 2' setSize=3 posInSet=2 selected=false
+++++++++listBoxOption focusable name='Option 3' setSize=3 posInSet=3 selected=false
+++++++listBox focusable setSize=3
+++++++++listBoxOption focusable name='Option 1' setSize=3 posInSet=1 selected=false
+++++++++listBoxOption focusable name='Option 2' setSize=3 posInSet=2 selected=false
+++++++++listBoxOption focusable name='Option 3' setSize=3 posInSet=3 selected=false
diff --git a/content/test/data/accessibility/html/span-expected-blink.txt b/content/test/data/accessibility/html/span-expected-blink.txt
index 723c1081..e613b149 100644
--- a/content/test/data/accessibility/html/span-expected-blink.txt
+++ b/content/test/data/accessibility/html/span-expected-blink.txt
@@ -1,119 +1,120 @@
 rootWebArea
 ++genericContainer ignored
-++++paragraph
-++++++staticText name='This'
-++++++++inlineTextBox name='This'
-++++++staticText name=' '
-++++++++inlineTextBox name=' '
-++++++staticText name='paragraph has '
-++++++++inlineTextBox name='paragraph has '
-++++++staticText name='text'
-++++++++inlineTextBox name='text'
-++++++staticText name=' '
-++++++++inlineTextBox name=' '
-++++++staticText name='in'
-++++++++inlineTextBox name='in'
-++++++staticText name=' '
-++++++++inlineTextBox name=' '
-++++++staticText name='spans'
-++++++++inlineTextBox name='spans'
-++++++staticText name='.'
-++++++++inlineTextBox name='.'
-++++paragraph
-++++++staticText name='E1. Eat'
-++++++++inlineTextBox name='E1. Eat'
-++++++staticText name=' '
-++++++++inlineTextBox name=' '
-++++++link name='space'
+++++genericContainer ignored
+++++++paragraph
+++++++++staticText name='This'
+++++++++++inlineTextBox name='This'
+++++++++staticText name=' '
+++++++++++inlineTextBox name=' '
+++++++++staticText name='paragraph has '
+++++++++++inlineTextBox name='paragraph has '
+++++++++staticText name='text'
+++++++++++inlineTextBox name='text'
+++++++++staticText name=' '
+++++++++++inlineTextBox name=' '
+++++++++staticText name='in'
+++++++++++inlineTextBox name='in'
+++++++++staticText name=' '
+++++++++++inlineTextBox name=' '
+++++++++staticText name='spans'
+++++++++++inlineTextBox name='spans'
+++++++++staticText name='.'
+++++++++++inlineTextBox name='.'
+++++++paragraph
+++++++++staticText name='E1. Eat'
+++++++++++inlineTextBox name='E1. Eat'
+++++++++staticText name=' '
+++++++++++inlineTextBox name=' '
+++++++++link name='space'
+++++++++++staticText name='space'
+++++++++++++inlineTextBox name='space'
+++++++paragraph
+++++++++staticText name='E2. Eat'
+++++++++++inlineTextBox name='E2. Eat'
+++++++++staticText name=' '
+++++++++++inlineTextBox name=' '
+++++++++link name='space'
+++++++++++staticText name='space'
+++++++++++++inlineTextBox name='space'
+++++++paragraph
+++++++++staticText name='E3. Eat'
+++++++++++inlineTextBox name='E3. Eat'
+++++++++staticText name=' '
+++++++++++inlineTextBox name=' '
+++++++++link name='space'
+++++++++++staticText name='space'
+++++++++++++inlineTextBox name='space'
+++++++paragraph
+++++++++link name='E4. Eat'
+++++++++++staticText name='E4. Eat'
+++++++++++++inlineTextBox name='E4. Eat'
+++++++++staticText name=' '
+++++++++++inlineTextBox name=' '
 ++++++++staticText name='space'
 ++++++++++inlineTextBox name='space'
-++++paragraph
-++++++staticText name='E2. Eat'
-++++++++inlineTextBox name='E2. Eat'
-++++++staticText name=' '
-++++++++inlineTextBox name=' '
-++++++link name='space'
+++++++paragraph
+++++++++link name='E5. Eat'
+++++++++++staticText name='E5. Eat'
+++++++++++++inlineTextBox name='E5. Eat'
+++++++++staticText name=' '
+++++++++++inlineTextBox name=' '
 ++++++++staticText name='space'
 ++++++++++inlineTextBox name='space'
-++++paragraph
-++++++staticText name='E3. Eat'
-++++++++inlineTextBox name='E3. Eat'
-++++++staticText name=' '
-++++++++inlineTextBox name=' '
-++++++link name='space'
+++++++paragraph
+++++++++link name='E6. Eat'
+++++++++++staticText name='E6. Eat'
+++++++++++++inlineTextBox name='E6. Eat'
+++++++++staticText name=' '
+++++++++++inlineTextBox name=' '
 ++++++++staticText name='space'
 ++++++++++inlineTextBox name='space'
-++++paragraph
-++++++link name='E4. Eat'
-++++++++staticText name='E4. Eat'
-++++++++++inlineTextBox name='E4. Eat'
-++++++staticText name=' '
-++++++++inlineTextBox name=' '
-++++++staticText name='space'
-++++++++inlineTextBox name='space'
-++++paragraph
-++++++link name='E5. Eat'
-++++++++staticText name='E5. Eat'
-++++++++++inlineTextBox name='E5. Eat'
-++++++staticText name=' '
-++++++++inlineTextBox name=' '
-++++++staticText name='space'
-++++++++inlineTextBox name='space'
-++++paragraph
-++++++link name='E6. Eat'
-++++++++staticText name='E6. Eat'
-++++++++++inlineTextBox name='E6. Eat'
-++++++staticText name=' '
-++++++++inlineTextBox name=' '
-++++++staticText name='space'
-++++++++inlineTextBox name='space'
-++++paragraph
-++++++staticText name='K1. Keep'
-++++++++inlineTextBox name='K1. Keep'
-++++++staticText name=' '
-++++++++inlineTextBox name=' '
-++++++staticText name='space'
-++++++++inlineTextBox name='space'
-++++paragraph
-++++++staticText name='K2. Keep'
-++++++++inlineTextBox name='K2. Keep'
-++++++staticText name=' '
-++++++++inlineTextBox name=' '
-++++++staticText name='space'
-++++++++inlineTextBox name='space'
-++++paragraph
-++++++staticText name='K3. Keep'
-++++++++inlineTextBox name='K3. Keep'
-++++++staticText name=' '
-++++++++inlineTextBox name=' '
-++++++staticText name='space'
-++++++++inlineTextBox name='space'
-++++paragraph
-++++++staticText name='K4. Keep '
-++++++++inlineTextBox name='K4. Keep '
-++++++staticText name='space'
-++++++++inlineTextBox name='space'
-++++paragraph
-++++++staticText name='K5. Keep'
-++++++++inlineTextBox name='K5. Keep'
-++++++staticText name=' '
-++++++++inlineTextBox name=' '
-++++++staticText name='space'
-++++++++inlineTextBox name='space'
-++++paragraph
-++++++staticText name='K6. Keep '
-++++++++inlineTextBox name='K6. Keep '
-++++++staticText name='space'
-++++++++inlineTextBox name='space'
-++++paragraph
-++++++staticText name='K7. Keep'
-++++++++inlineTextBox name='K7. Keep'
-++++++staticText name=' space'
-++++++++inlineTextBox name=' space'
-++++paragraph
-++++++staticText name='K8. Keep'
-++++++++inlineTextBox name='K8. Keep'
-++++++staticText name=' '
-++++++++inlineTextBox name=' '
-++++++staticText name='space'
-++++++++inlineTextBox name='space'
+++++++paragraph
+++++++++staticText name='K1. Keep'
+++++++++++inlineTextBox name='K1. Keep'
+++++++++staticText name=' '
+++++++++++inlineTextBox name=' '
+++++++++staticText name='space'
+++++++++++inlineTextBox name='space'
+++++++paragraph
+++++++++staticText name='K2. Keep'
+++++++++++inlineTextBox name='K2. Keep'
+++++++++staticText name=' '
+++++++++++inlineTextBox name=' '
+++++++++staticText name='space'
+++++++++++inlineTextBox name='space'
+++++++paragraph
+++++++++staticText name='K3. Keep'
+++++++++++inlineTextBox name='K3. Keep'
+++++++++staticText name=' '
+++++++++++inlineTextBox name=' '
+++++++++staticText name='space'
+++++++++++inlineTextBox name='space'
+++++++paragraph
+++++++++staticText name='K4. Keep '
+++++++++++inlineTextBox name='K4. Keep '
+++++++++staticText name='space'
+++++++++++inlineTextBox name='space'
+++++++paragraph
+++++++++staticText name='K5. Keep'
+++++++++++inlineTextBox name='K5. Keep'
+++++++++staticText name=' '
+++++++++++inlineTextBox name=' '
+++++++++staticText name='space'
+++++++++++inlineTextBox name='space'
+++++++paragraph
+++++++++staticText name='K6. Keep '
+++++++++++inlineTextBox name='K6. Keep '
+++++++++staticText name='space'
+++++++++++inlineTextBox name='space'
+++++++paragraph
+++++++++staticText name='K7. Keep'
+++++++++++inlineTextBox name='K7. Keep'
+++++++++staticText name=' space'
+++++++++++inlineTextBox name=' space'
+++++++paragraph
+++++++++staticText name='K8. Keep'
+++++++++++inlineTextBox name='K8. Keep'
+++++++++staticText name=' '
+++++++++++inlineTextBox name=' '
+++++++++staticText name='space'
+++++++++++inlineTextBox name='space'
diff --git a/content/test/data/accessibility/html/span-line-break-expected-blink.txt b/content/test/data/accessibility/html/span-line-break-expected-blink.txt
index 49c1aee..94531bd 100644
--- a/content/test/data/accessibility/html/span-line-break-expected-blink.txt
+++ b/content/test/data/accessibility/html/span-line-break-expected-blink.txt
@@ -1,62 +1,63 @@
 rootWebArea
 ++genericContainer ignored
-++++paragraph
-++++++staticText name='100(a)#abcdefghijklmnopqrstuvwxyz'
-++++++++inlineTextBox name='100(a)#abcdefghijklmnopqrstuvwxyz'
-++++++staticText name=' '
-++++++staticText name='abcdefghijklmnopqrstuvwxyz'
-++++++++inlineTextBox name='abcdefghijklmnopqrstuvwxyz'
-++++paragraph
-++++++staticText name='100(b)#abcdefghijklmnopqrstuvwxyz'
-++++++++inlineTextBox name='100(b)#abcdefghijklmnopqrstuvwxyz'
-++++++staticText name=' '
-++++++staticText name='abcdefghijklmnopqrstuvwxyz'
-++++++++inlineTextBox name='abcdefghijklmnopqrstuvwxyz'
-++++paragraph
-++++++staticText name='100(c)#abcdefghijklmnopqrstuvwxyz'
-++++++++inlineTextBox name='100(c)#abcdefghijklmnopqrstuvwxyz'
-++++++staticText name=' '
-++++++staticText name='abcdefghijklmnopqrstuvwxyz'
-++++++++inlineTextBox name='abcdefghijklmnopqrstuvwxyz'
-++++paragraph
-++++++staticText name='500(a)#abcdefghijklmnopqrstuvwxyz'
-++++++++inlineTextBox name='500(a)#abcdefghijklmnopqrstuvwxyz'
-++++++staticText name=' '
-++++++++inlineTextBox name=' '
-++++++staticText name='abcdefghijklmnopqrstuvwxyz'
-++++++++inlineTextBox name='abcdefghijklmnopqrstuvwxyz'
-++++paragraph
-++++++staticText name='500(b)#abcdefghijklmnopqrstuvwxyz'
-++++++++inlineTextBox name='500(b)#abcdefghijklmnopqrstuvwxyz'
-++++++staticText name=' '
-++++++++inlineTextBox name=' '
-++++++staticText name='abcdefghijklmnopqrstuvwxyz'
-++++++++inlineTextBox name='abcdefghijklmnopqrstuvwxyz'
-++++paragraph
-++++++staticText name='500(c)#abcdefghijklmnopqrstuvwxyz'
-++++++++inlineTextBox name='500(c)#abcdefghijklmnopqrstuvwxyz'
-++++++staticText name=' '
-++++++++inlineTextBox name=' '
-++++++staticText name='abcdefghijklmnopqrstuvwxyz'
-++++++++inlineTextBox name='abcdefghijklmnopqrstuvwxyz'
-++++paragraph
-++++++staticText name='900(a)#abcdefghijklmnopqrstuvwxyz'
-++++++++inlineTextBox name='900(a)#abcdefghijklmnopqrstuvwxyz'
-++++++staticText name=' '
-++++++++inlineTextBox name=' '
-++++++staticText name='abcdefghijklmnopqrstuvwxyz'
-++++++++inlineTextBox name='abcdefghijklmnopqrstuvwxyz'
-++++paragraph
-++++++staticText name='900(b)#abcdefghijklmnopqrstuvwxyz'
-++++++++inlineTextBox name='900(b)#abcdefghijklmnopqrstuvwxyz'
-++++++staticText name=' '
-++++++++inlineTextBox name=' '
-++++++staticText name='abcdefghijklmnopqrstuvwxyz'
-++++++++inlineTextBox name='abcdefghijklmnopqrstuvwxyz'
-++++paragraph
-++++++staticText name='900(c)#abcdefghijklmnopqrstuvwxyz'
-++++++++inlineTextBox name='900(c)#abcdefghijklmnopqrstuvwxyz'
-++++++staticText name=' '
-++++++++inlineTextBox name=' '
-++++++staticText name='abcdefghijklmnopqrstuvwxyz'
-++++++++inlineTextBox name='abcdefghijklmnopqrstuvwxyz'
+++++genericContainer ignored
+++++++paragraph
+++++++++staticText name='100(a)#abcdefghijklmnopqrstuvwxyz'
+++++++++++inlineTextBox name='100(a)#abcdefghijklmnopqrstuvwxyz'
+++++++++staticText name=' '
+++++++++staticText name='abcdefghijklmnopqrstuvwxyz'
+++++++++++inlineTextBox name='abcdefghijklmnopqrstuvwxyz'
+++++++paragraph
+++++++++staticText name='100(b)#abcdefghijklmnopqrstuvwxyz'
+++++++++++inlineTextBox name='100(b)#abcdefghijklmnopqrstuvwxyz'
+++++++++staticText name=' '
+++++++++staticText name='abcdefghijklmnopqrstuvwxyz'
+++++++++++inlineTextBox name='abcdefghijklmnopqrstuvwxyz'
+++++++paragraph
+++++++++staticText name='100(c)#abcdefghijklmnopqrstuvwxyz'
+++++++++++inlineTextBox name='100(c)#abcdefghijklmnopqrstuvwxyz'
+++++++++staticText name=' '
+++++++++staticText name='abcdefghijklmnopqrstuvwxyz'
+++++++++++inlineTextBox name='abcdefghijklmnopqrstuvwxyz'
+++++++paragraph
+++++++++staticText name='500(a)#abcdefghijklmnopqrstuvwxyz'
+++++++++++inlineTextBox name='500(a)#abcdefghijklmnopqrstuvwxyz'
+++++++++staticText name=' '
+++++++++++inlineTextBox name=' '
+++++++++staticText name='abcdefghijklmnopqrstuvwxyz'
+++++++++++inlineTextBox name='abcdefghijklmnopqrstuvwxyz'
+++++++paragraph
+++++++++staticText name='500(b)#abcdefghijklmnopqrstuvwxyz'
+++++++++++inlineTextBox name='500(b)#abcdefghijklmnopqrstuvwxyz'
+++++++++staticText name=' '
+++++++++++inlineTextBox name=' '
+++++++++staticText name='abcdefghijklmnopqrstuvwxyz'
+++++++++++inlineTextBox name='abcdefghijklmnopqrstuvwxyz'
+++++++paragraph
+++++++++staticText name='500(c)#abcdefghijklmnopqrstuvwxyz'
+++++++++++inlineTextBox name='500(c)#abcdefghijklmnopqrstuvwxyz'
+++++++++staticText name=' '
+++++++++++inlineTextBox name=' '
+++++++++staticText name='abcdefghijklmnopqrstuvwxyz'
+++++++++++inlineTextBox name='abcdefghijklmnopqrstuvwxyz'
+++++++paragraph
+++++++++staticText name='900(a)#abcdefghijklmnopqrstuvwxyz'
+++++++++++inlineTextBox name='900(a)#abcdefghijklmnopqrstuvwxyz'
+++++++++staticText name=' '
+++++++++++inlineTextBox name=' '
+++++++++staticText name='abcdefghijklmnopqrstuvwxyz'
+++++++++++inlineTextBox name='abcdefghijklmnopqrstuvwxyz'
+++++++paragraph
+++++++++staticText name='900(b)#abcdefghijklmnopqrstuvwxyz'
+++++++++++inlineTextBox name='900(b)#abcdefghijklmnopqrstuvwxyz'
+++++++++staticText name=' '
+++++++++++inlineTextBox name=' '
+++++++++staticText name='abcdefghijklmnopqrstuvwxyz'
+++++++++++inlineTextBox name='abcdefghijklmnopqrstuvwxyz'
+++++++paragraph
+++++++++staticText name='900(c)#abcdefghijklmnopqrstuvwxyz'
+++++++++++inlineTextBox name='900(c)#abcdefghijklmnopqrstuvwxyz'
+++++++++staticText name=' '
+++++++++++inlineTextBox name=' '
+++++++++staticText name='abcdefghijklmnopqrstuvwxyz'
+++++++++++inlineTextBox name='abcdefghijklmnopqrstuvwxyz'
diff --git a/content/test/data/accessibility/html/strong-expected-blink.txt b/content/test/data/accessibility/html/strong-expected-blink.txt
index 3af0ec5..240d519 100644
--- a/content/test/data/accessibility/html/strong-expected-blink.txt
+++ b/content/test/data/accessibility/html/strong-expected-blink.txt
@@ -1,4 +1,5 @@
 rootWebArea
-++genericContainer
-++++staticText name='Strong text'
-++++++inlineTextBox name='Strong text'
+++genericContainer ignored
+++++genericContainer
+++++++staticText name='Strong text'
+++++++++inlineTextBox name='Strong text'
diff --git a/content/test/data/accessibility/html/sub-expected-blink.txt b/content/test/data/accessibility/html/sub-expected-blink.txt
index 45905f3..148a9193 100644
--- a/content/test/data/accessibility/html/sub-expected-blink.txt
+++ b/content/test/data/accessibility/html/sub-expected-blink.txt
@@ -1,9 +1,10 @@
 rootWebArea
 ++genericContainer ignored
-++++paragraph
-++++++staticText name='This text contains '
-++++++++inlineTextBox name='This text contains '
-++++++staticText name='subscript'
-++++++++inlineTextBox name='subscript'
-++++++staticText name=' text.'
-++++++++inlineTextBox name=' text.'
+++++genericContainer ignored
+++++++paragraph
+++++++++staticText name='This text contains '
+++++++++++inlineTextBox name='This text contains '
+++++++++staticText name='subscript'
+++++++++++inlineTextBox name='subscript'
+++++++++staticText name=' text.'
+++++++++++inlineTextBox name=' text.'
diff --git a/content/test/data/accessibility/html/summary-expected-blink.txt b/content/test/data/accessibility/html/summary-expected-blink.txt
index d2d473916..2c61344 100644
--- a/content/test/data/accessibility/html/summary-expected-blink.txt
+++ b/content/test/data/accessibility/html/summary-expected-blink.txt
@@ -1,6 +1,7 @@
 rootWebArea
 ++genericContainer ignored
-++++details
-++++++disclosureTriangle collapsed name='details tag'
-++++++++staticText name='details tag'
-++++++++++inlineTextBox name='details tag'
+++++genericContainer ignored
+++++++details
+++++++++disclosureTriangle collapsed name='details tag'
+++++++++++staticText name='details tag'
+++++++++++++inlineTextBox name='details tag'
diff --git a/content/test/data/accessibility/html/sup-expected-blink.txt b/content/test/data/accessibility/html/sup-expected-blink.txt
index 7611a8b..3f7a5ec7 100644
--- a/content/test/data/accessibility/html/sup-expected-blink.txt
+++ b/content/test/data/accessibility/html/sup-expected-blink.txt
@@ -1,9 +1,10 @@
 rootWebArea
 ++genericContainer ignored
-++++paragraph
-++++++staticText name='This text contains'
-++++++++inlineTextBox name='This text contains'
-++++++staticText name='superscript'
-++++++++inlineTextBox name='superscript'
-++++++staticText name='text.'
-++++++++inlineTextBox name='text.'
+++++genericContainer ignored
+++++++paragraph
+++++++++staticText name='This text contains'
+++++++++++inlineTextBox name='This text contains'
+++++++++staticText name='superscript'
+++++++++++inlineTextBox name='superscript'
+++++++++staticText name='text.'
+++++++++++inlineTextBox name='text.'
diff --git a/content/test/data/accessibility/html/svg-expected-blink.txt b/content/test/data/accessibility/html/svg-expected-blink.txt
index 7c94050..efe48f9 100644
--- a/content/test/data/accessibility/html/svg-expected-blink.txt
+++ b/content/test/data/accessibility/html/svg-expected-blink.txt
@@ -1,6 +1,7 @@
 rootWebArea
-++genericContainer
-++++svgRoot name='svg'
-++++++genericContainer
-++++++++staticText name='Test'
-++++++++++inlineTextBox name='Test'
+++genericContainer ignored
+++++genericContainer
+++++++svgRoot name='svg'
+++++++++genericContainer
+++++++++++staticText name='Test'
+++++++++++++inlineTextBox name='Test'
diff --git a/content/test/data/accessibility/html/table-focusable-sections-expected-blink.txt b/content/test/data/accessibility/html/table-focusable-sections-expected-blink.txt
index 07d815b..ea63a64 100644
--- a/content/test/data/accessibility/html/table-focusable-sections-expected-blink.txt
+++ b/content/test/data/accessibility/html/table-focusable-sections-expected-blink.txt
@@ -1,34 +1,35 @@
 rootWebArea name='Table example - focusable thead, tbody, tfoot'
 ++genericContainer ignored
-++++table
-++++++rowGroup
-++++++++row
-++++++++++columnHeader name='Sum'
-++++++++++++staticText name='Sum'
-++++++++++++++inlineTextBox name='Sum'
-++++++++++columnHeader name='Subtraction'
-++++++++++++staticText name='Subtraction'
-++++++++++++++inlineTextBox name='Subtraction'
-++++++rowGroup
-++++++++row
-++++++++++cell name='10'
-++++++++++++staticText name='10'
-++++++++++++++inlineTextBox name='10'
-++++++++++cell name='7'
-++++++++++++staticText name='7'
-++++++++++++++inlineTextBox name='7'
-++++++++row
-++++++++++cell name='2'
-++++++++++++staticText name='2'
-++++++++++++++inlineTextBox name='2'
-++++++++++cell name='4'
-++++++++++++staticText name='4'
-++++++++++++++inlineTextBox name='4'
-++++++rowGroup
-++++++++row
-++++++++++cell name='12'
-++++++++++++staticText name='12'
-++++++++++++++inlineTextBox name='12'
-++++++++++cell name='3'
-++++++++++++staticText name='3'
-++++++++++++++inlineTextBox name='3'
+++++genericContainer ignored
+++++++table
+++++++++rowGroup
+++++++++++row
+++++++++++++columnHeader name='Sum'
+++++++++++++++staticText name='Sum'
+++++++++++++++++inlineTextBox name='Sum'
+++++++++++++columnHeader name='Subtraction'
+++++++++++++++staticText name='Subtraction'
+++++++++++++++++inlineTextBox name='Subtraction'
+++++++++rowGroup
+++++++++++row
+++++++++++++cell name='10'
+++++++++++++++staticText name='10'
+++++++++++++++++inlineTextBox name='10'
+++++++++++++cell name='7'
+++++++++++++++staticText name='7'
+++++++++++++++++inlineTextBox name='7'
+++++++++++row
+++++++++++++cell name='2'
+++++++++++++++staticText name='2'
+++++++++++++++++inlineTextBox name='2'
+++++++++++++cell name='4'
+++++++++++++++staticText name='4'
+++++++++++++++++inlineTextBox name='4'
+++++++++rowGroup
+++++++++++row
+++++++++++++cell name='12'
+++++++++++++++staticText name='12'
+++++++++++++++++inlineTextBox name='12'
+++++++++++++cell name='3'
+++++++++++++++staticText name='3'
+++++++++++++++++inlineTextBox name='3'
diff --git a/content/test/data/accessibility/html/table-headers-empty-first-cell-expected-blink.txt b/content/test/data/accessibility/html/table-headers-empty-first-cell-expected-blink.txt
index 337912e..86a7a4e12 100644
--- a/content/test/data/accessibility/html/table-headers-empty-first-cell-expected-blink.txt
+++ b/content/test/data/accessibility/html/table-headers-empty-first-cell-expected-blink.txt
@@ -1,99 +1,100 @@
 rootWebArea name='Table example - headers with empty first cell'
 ++genericContainer ignored
-++++table name='Delivery slots:'
-++++++caption
-++++++++staticText name='Delivery slots:'
-++++++++++inlineTextBox name='Delivery slots:'
-++++++row
-++++++++cell
-++++++++columnHeader name='Monday'
-++++++++++staticText name='Monday'
-++++++++++++inlineTextBox name='Monday'
-++++++++columnHeader name='Tuesday'
-++++++++++staticText name='Tuesday'
-++++++++++++inlineTextBox name='Tuesday'
-++++++++columnHeader name='Wednesday'
-++++++++++staticText name='Wednesday'
-++++++++++++inlineTextBox name='Wednesday'
-++++++++columnHeader name='Thursday'
-++++++++++staticText name='Thursday'
-++++++++++++inlineTextBox name='Thursday'
-++++++++columnHeader name='Friday'
-++++++++++staticText name='Friday'
-++++++++++++inlineTextBox name='Friday'
-++++++row
-++++++++rowHeader name='09:00 - 11:00'
-++++++++++staticText name='09:00 - 11:00'
-++++++++++++inlineTextBox name='09:00 - 11:00'
-++++++++cell name='Closed'
-++++++++++staticText name='Closed'
-++++++++++++inlineTextBox name='Closed'
-++++++++cell name='Open'
-++++++++++staticText name='Open'
-++++++++++++inlineTextBox name='Open'
-++++++++cell name='Open'
-++++++++++staticText name='Open'
-++++++++++++inlineTextBox name='Open'
-++++++++cell name='Closed'
-++++++++++staticText name='Closed'
-++++++++++++inlineTextBox name='Closed'
-++++++++cell name='Closed'
-++++++++++staticText name='Closed'
-++++++++++++inlineTextBox name='Closed'
-++++++row
-++++++++rowHeader name='11:00 - 13:00'
-++++++++++staticText name='11:00 - 13:00'
-++++++++++++inlineTextBox name='11:00 - 13:00'
-++++++++cell name='Open'
-++++++++++staticText name='Open'
-++++++++++++inlineTextBox name='Open'
-++++++++cell name='Open'
-++++++++++staticText name='Open'
-++++++++++++inlineTextBox name='Open'
-++++++++cell name='Closed'
-++++++++++staticText name='Closed'
-++++++++++++inlineTextBox name='Closed'
-++++++++cell name='Closed'
-++++++++++staticText name='Closed'
-++++++++++++inlineTextBox name='Closed'
-++++++++cell name='Closed'
-++++++++++staticText name='Closed'
-++++++++++++inlineTextBox name='Closed'
-++++++row
-++++++++rowHeader name='13:00 - 15:00'
-++++++++++staticText name='13:00 - 15:00'
-++++++++++++inlineTextBox name='13:00 - 15:00'
-++++++++cell name='Open'
-++++++++++staticText name='Open'
-++++++++++++inlineTextBox name='Open'
-++++++++cell name='Open'
-++++++++++staticText name='Open'
-++++++++++++inlineTextBox name='Open'
-++++++++cell name='Open'
-++++++++++staticText name='Open'
-++++++++++++inlineTextBox name='Open'
-++++++++cell name='Closed'
-++++++++++staticText name='Closed'
-++++++++++++inlineTextBox name='Closed'
-++++++++cell name='Closed'
-++++++++++staticText name='Closed'
-++++++++++++inlineTextBox name='Closed'
-++++++row
-++++++++rowHeader name='15:00 - 17:00'
-++++++++++staticText name='15:00 - 17:00'
-++++++++++++inlineTextBox name='15:00 - 17:00'
-++++++++cell name='Closed'
-++++++++++staticText name='Closed'
-++++++++++++inlineTextBox name='Closed'
-++++++++cell name='Closed'
-++++++++++staticText name='Closed'
-++++++++++++inlineTextBox name='Closed'
-++++++++cell name='Closed'
-++++++++++staticText name='Closed'
-++++++++++++inlineTextBox name='Closed'
-++++++++cell name='Open'
-++++++++++staticText name='Open'
-++++++++++++inlineTextBox name='Open'
-++++++++cell name='Open'
-++++++++++staticText name='Open'
-++++++++++++inlineTextBox name='Open'
+++++genericContainer ignored
+++++++table name='Delivery slots:'
+++++++++caption
+++++++++++staticText name='Delivery slots:'
+++++++++++++inlineTextBox name='Delivery slots:'
+++++++++row
+++++++++++cell
+++++++++++columnHeader name='Monday'
+++++++++++++staticText name='Monday'
+++++++++++++++inlineTextBox name='Monday'
+++++++++++columnHeader name='Tuesday'
+++++++++++++staticText name='Tuesday'
+++++++++++++++inlineTextBox name='Tuesday'
+++++++++++columnHeader name='Wednesday'
+++++++++++++staticText name='Wednesday'
+++++++++++++++inlineTextBox name='Wednesday'
+++++++++++columnHeader name='Thursday'
+++++++++++++staticText name='Thursday'
+++++++++++++++inlineTextBox name='Thursday'
+++++++++++columnHeader name='Friday'
+++++++++++++staticText name='Friday'
+++++++++++++++inlineTextBox name='Friday'
+++++++++row
+++++++++++rowHeader name='09:00 - 11:00'
+++++++++++++staticText name='09:00 - 11:00'
+++++++++++++++inlineTextBox name='09:00 - 11:00'
+++++++++++cell name='Closed'
+++++++++++++staticText name='Closed'
+++++++++++++++inlineTextBox name='Closed'
+++++++++++cell name='Open'
+++++++++++++staticText name='Open'
+++++++++++++++inlineTextBox name='Open'
+++++++++++cell name='Open'
+++++++++++++staticText name='Open'
+++++++++++++++inlineTextBox name='Open'
+++++++++++cell name='Closed'
+++++++++++++staticText name='Closed'
+++++++++++++++inlineTextBox name='Closed'
+++++++++++cell name='Closed'
+++++++++++++staticText name='Closed'
+++++++++++++++inlineTextBox name='Closed'
+++++++++row
+++++++++++rowHeader name='11:00 - 13:00'
+++++++++++++staticText name='11:00 - 13:00'
+++++++++++++++inlineTextBox name='11:00 - 13:00'
+++++++++++cell name='Open'
+++++++++++++staticText name='Open'
+++++++++++++++inlineTextBox name='Open'
+++++++++++cell name='Open'
+++++++++++++staticText name='Open'
+++++++++++++++inlineTextBox name='Open'
+++++++++++cell name='Closed'
+++++++++++++staticText name='Closed'
+++++++++++++++inlineTextBox name='Closed'
+++++++++++cell name='Closed'
+++++++++++++staticText name='Closed'
+++++++++++++++inlineTextBox name='Closed'
+++++++++++cell name='Closed'
+++++++++++++staticText name='Closed'
+++++++++++++++inlineTextBox name='Closed'
+++++++++row
+++++++++++rowHeader name='13:00 - 15:00'
+++++++++++++staticText name='13:00 - 15:00'
+++++++++++++++inlineTextBox name='13:00 - 15:00'
+++++++++++cell name='Open'
+++++++++++++staticText name='Open'
+++++++++++++++inlineTextBox name='Open'
+++++++++++cell name='Open'
+++++++++++++staticText name='Open'
+++++++++++++++inlineTextBox name='Open'
+++++++++++cell name='Open'
+++++++++++++staticText name='Open'
+++++++++++++++inlineTextBox name='Open'
+++++++++++cell name='Closed'
+++++++++++++staticText name='Closed'
+++++++++++++++inlineTextBox name='Closed'
+++++++++++cell name='Closed'
+++++++++++++staticText name='Closed'
+++++++++++++++inlineTextBox name='Closed'
+++++++++row
+++++++++++rowHeader name='15:00 - 17:00'
+++++++++++++staticText name='15:00 - 17:00'
+++++++++++++++inlineTextBox name='15:00 - 17:00'
+++++++++++cell name='Closed'
+++++++++++++staticText name='Closed'
+++++++++++++++inlineTextBox name='Closed'
+++++++++++cell name='Closed'
+++++++++++++staticText name='Closed'
+++++++++++++++inlineTextBox name='Closed'
+++++++++++cell name='Closed'
+++++++++++++staticText name='Closed'
+++++++++++++++inlineTextBox name='Closed'
+++++++++++cell name='Open'
+++++++++++++staticText name='Open'
+++++++++++++++inlineTextBox name='Open'
+++++++++++cell name='Open'
+++++++++++++staticText name='Open'
+++++++++++++++inlineTextBox name='Open'
diff --git a/content/test/data/accessibility/html/table-headers-on-all-sides-expected-blink.txt b/content/test/data/accessibility/html/table-headers-on-all-sides-expected-blink.txt
index edd0df22..6130cb75 100644
--- a/content/test/data/accessibility/html/table-headers-on-all-sides-expected-blink.txt
+++ b/content/test/data/accessibility/html/table-headers-on-all-sides-expected-blink.txt
@@ -1,47 +1,48 @@
 rootWebArea name='Table example - headers on all sides'
 ++genericContainer ignored
-++++table
-++++++row
-++++++++cell
-++++++++columnHeader name='Red'
-++++++++++staticText name='Red'
-++++++++++++inlineTextBox name='Red'
-++++++++columnHeader name='Green'
-++++++++++staticText name='Green'
-++++++++++++inlineTextBox name='Green'
-++++++++cell
-++++++row
-++++++++rowHeader name='Fruit'
-++++++++++staticText name='Fruit'
-++++++++++++inlineTextBox name='Fruit'
-++++++++cell name='strawberry'
-++++++++++staticText name='strawberry'
-++++++++++++inlineTextBox name='strawberry'
-++++++++cell name='lime'
-++++++++++staticText name='lime'
-++++++++++++inlineTextBox name='lime'
-++++++++rowHeader name='Fruit'
-++++++++++staticText name='Fruit'
-++++++++++++inlineTextBox name='Fruit'
-++++++row
-++++++++rowHeader name='Veggies'
-++++++++++staticText name='Veggies'
-++++++++++++inlineTextBox name='Veggies'
-++++++++cell name='radish'
-++++++++++staticText name='radish'
-++++++++++++inlineTextBox name='radish'
-++++++++cell name='spinach'
-++++++++++staticText name='spinach'
-++++++++++++inlineTextBox name='spinach'
-++++++++rowHeader name='Veggies'
-++++++++++staticText name='Veggies'
-++++++++++++inlineTextBox name='Veggies'
-++++++row
-++++++++cell
-++++++++columnHeader name='Red'
-++++++++++staticText name='Red'
-++++++++++++inlineTextBox name='Red'
-++++++++columnHeader name='Green'
-++++++++++staticText name='Green'
-++++++++++++inlineTextBox name='Green'
-++++++++cell
+++++genericContainer ignored
+++++++table
+++++++++row
+++++++++++cell
+++++++++++columnHeader name='Red'
+++++++++++++staticText name='Red'
+++++++++++++++inlineTextBox name='Red'
+++++++++++columnHeader name='Green'
+++++++++++++staticText name='Green'
+++++++++++++++inlineTextBox name='Green'
+++++++++++cell
+++++++++row
+++++++++++rowHeader name='Fruit'
+++++++++++++staticText name='Fruit'
+++++++++++++++inlineTextBox name='Fruit'
+++++++++++cell name='strawberry'
+++++++++++++staticText name='strawberry'
+++++++++++++++inlineTextBox name='strawberry'
+++++++++++cell name='lime'
+++++++++++++staticText name='lime'
+++++++++++++++inlineTextBox name='lime'
+++++++++++rowHeader name='Fruit'
+++++++++++++staticText name='Fruit'
+++++++++++++++inlineTextBox name='Fruit'
+++++++++row
+++++++++++rowHeader name='Veggies'
+++++++++++++staticText name='Veggies'
+++++++++++++++inlineTextBox name='Veggies'
+++++++++++cell name='radish'
+++++++++++++staticText name='radish'
+++++++++++++++inlineTextBox name='radish'
+++++++++++cell name='spinach'
+++++++++++++staticText name='spinach'
+++++++++++++++inlineTextBox name='spinach'
+++++++++++rowHeader name='Veggies'
+++++++++++++staticText name='Veggies'
+++++++++++++++inlineTextBox name='Veggies'
+++++++++row
+++++++++++cell
+++++++++++columnHeader name='Red'
+++++++++++++staticText name='Red'
+++++++++++++++inlineTextBox name='Red'
+++++++++++columnHeader name='Green'
+++++++++++++staticText name='Green'
+++++++++++++++inlineTextBox name='Green'
+++++++++++cell
diff --git a/content/test/data/accessibility/html/table-layout-expected-blink.txt b/content/test/data/accessibility/html/table-layout-expected-blink.txt
index e439b630..9ccee06d 100644
--- a/content/test/data/accessibility/html/table-layout-expected-blink.txt
+++ b/content/test/data/accessibility/html/table-layout-expected-blink.txt
@@ -1,33 +1,34 @@
 rootWebArea name='Table example #2'
 ++genericContainer ignored
-++++layoutTable
-++++++layoutTableRow
-++++++++layoutTableCell name='1'
-++++++++++staticText name='1'
-++++++++++++inlineTextBox name='1'
-++++++++layoutTableCell name='2'
-++++++++++staticText name='2'
-++++++++++++inlineTextBox name='2'
-++++++++layoutTableCell name='3'
-++++++++++staticText name='3'
-++++++++++++inlineTextBox name='3'
-++++++layoutTableRow
-++++++++layoutTableCell name='4'
-++++++++++staticText name='4'
-++++++++++++inlineTextBox name='4'
-++++++++layoutTableCell name='5'
-++++++++++staticText name='5'
-++++++++++++inlineTextBox name='5'
-++++++++layoutTableCell name='6'
-++++++++++staticText name='6'
-++++++++++++inlineTextBox name='6'
-++++++layoutTableRow
-++++++++layoutTableCell name='7'
-++++++++++staticText name='7'
-++++++++++++inlineTextBox name='7'
-++++++++layoutTableCell name='8'
-++++++++++staticText name='8'
-++++++++++++inlineTextBox name='8'
-++++++++layoutTableCell name='9'
-++++++++++staticText name='9'
-++++++++++++inlineTextBox name='9'
+++++genericContainer ignored
+++++++layoutTable
+++++++++layoutTableRow
+++++++++++layoutTableCell name='1'
+++++++++++++staticText name='1'
+++++++++++++++inlineTextBox name='1'
+++++++++++layoutTableCell name='2'
+++++++++++++staticText name='2'
+++++++++++++++inlineTextBox name='2'
+++++++++++layoutTableCell name='3'
+++++++++++++staticText name='3'
+++++++++++++++inlineTextBox name='3'
+++++++++layoutTableRow
+++++++++++layoutTableCell name='4'
+++++++++++++staticText name='4'
+++++++++++++++inlineTextBox name='4'
+++++++++++layoutTableCell name='5'
+++++++++++++staticText name='5'
+++++++++++++++inlineTextBox name='5'
+++++++++++layoutTableCell name='6'
+++++++++++++staticText name='6'
+++++++++++++++inlineTextBox name='6'
+++++++++layoutTableRow
+++++++++++layoutTableCell name='7'
+++++++++++++staticText name='7'
+++++++++++++++inlineTextBox name='7'
+++++++++++layoutTableCell name='8'
+++++++++++++staticText name='8'
+++++++++++++++inlineTextBox name='8'
+++++++++++layoutTableCell name='9'
+++++++++++++staticText name='9'
+++++++++++++++inlineTextBox name='9'
diff --git a/content/test/data/accessibility/html/table-multiple-row-and-column-headers-expected-blink.txt b/content/test/data/accessibility/html/table-multiple-row-and-column-headers-expected-blink.txt
index 5df4c51..bd4c47b 100644
--- a/content/test/data/accessibility/html/table-multiple-row-and-column-headers-expected-blink.txt
+++ b/content/test/data/accessibility/html/table-multiple-row-and-column-headers-expected-blink.txt
@@ -1,94 +1,95 @@
 rootWebArea name='Table example - multiple row and column headers'
 ++genericContainer ignored
-++++table
-++++++row
-++++++++cell
-++++++++columnHeader name='Mars'
-++++++++++staticText name='Mars'
-++++++++++++inlineTextBox name='Mars'
-++++++++columnHeader name='Venus'
-++++++++++staticText name='Venus'
-++++++++++++inlineTextBox name='Venus'
-++++++row
-++++++++columnHeader name='Produced'
-++++++++++staticText name='Produced'
-++++++++++++inlineTextBox name='Produced'
-++++++++columnHeader name='Sold'
-++++++++++staticText name='Sold'
-++++++++++++inlineTextBox name='Sold'
-++++++++columnHeader name='Produced'
-++++++++++staticText name='Produced'
-++++++++++++inlineTextBox name='Produced'
-++++++++columnHeader name='Sold'
-++++++++++staticText name='Sold'
-++++++++++++inlineTextBox name='Sold'
-++++++row
-++++++++rowHeader name='For Toddlers'
-++++++++++staticText name='For Toddlers'
-++++++++++++inlineTextBox name='For Toddlers'
-++++++++rowHeader name='Teddy Bears'
-++++++++++staticText name='Teddy Bears'
-++++++++++++inlineTextBox name='Teddy Bears'
-++++++++cell name='50,000'
-++++++++++staticText name='50,000'
-++++++++++++inlineTextBox name='50,000'
-++++++++cell name='30,000'
-++++++++++staticText name='30,000'
-++++++++++++inlineTextBox name='30,000'
-++++++++cell name='100,000'
-++++++++++staticText name='100,000'
-++++++++++++inlineTextBox name='100,000'
-++++++++cell name='80,000'
-++++++++++staticText name='80,000'
-++++++++++++inlineTextBox name='80,000'
-++++++row
-++++++++rowHeader name='Action Figures'
-++++++++++staticText name='Action Figures'
-++++++++++++inlineTextBox name='Action Figures'
-++++++++cell name='25,000'
-++++++++++staticText name='25,000'
-++++++++++++inlineTextBox name='25,000'
-++++++++cell name='15,000'
-++++++++++staticText name='15,000'
-++++++++++++inlineTextBox name='15,000'
-++++++++cell name='50,000'
-++++++++++staticText name='50,000'
-++++++++++++inlineTextBox name='50,000'
-++++++++cell name='40,000'
-++++++++++staticText name='40,000'
-++++++++++++inlineTextBox name='40,000'
-++++++row
-++++++++rowHeader name='For Teens'
-++++++++++staticText name='For Teens'
-++++++++++++inlineTextBox name='For Teens'
-++++++++rowHeader name='Board Games'
-++++++++++staticText name='Board Games'
-++++++++++++inlineTextBox name='Board Games'
-++++++++cell name='5,000'
-++++++++++staticText name='5,000'
-++++++++++++inlineTextBox name='5,000'
-++++++++cell name='2,000'
-++++++++++staticText name='2,000'
-++++++++++++inlineTextBox name='2,000'
-++++++++cell name='6,000'
-++++++++++staticText name='6,000'
-++++++++++++inlineTextBox name='6,000'
-++++++++cell name='4,000'
-++++++++++staticText name='4,000'
-++++++++++++inlineTextBox name='4,000'
-++++++row
-++++++++rowHeader name='Video Games'
-++++++++++staticText name='Video Games'
-++++++++++++inlineTextBox name='Video Games'
-++++++++cell name='10,000'
-++++++++++staticText name='10,000'
-++++++++++++inlineTextBox name='10,000'
-++++++++cell name='5,000'
-++++++++++staticText name='5,000'
-++++++++++++inlineTextBox name='5,000'
-++++++++cell name='12,000'
-++++++++++staticText name='12,000'
-++++++++++++inlineTextBox name='12,000'
-++++++++cell name='9,000'
-++++++++++staticText name='9,000'
-++++++++++++inlineTextBox name='9,000'
+++++genericContainer ignored
+++++++table
+++++++++row
+++++++++++cell
+++++++++++columnHeader name='Mars'
+++++++++++++staticText name='Mars'
+++++++++++++++inlineTextBox name='Mars'
+++++++++++columnHeader name='Venus'
+++++++++++++staticText name='Venus'
+++++++++++++++inlineTextBox name='Venus'
+++++++++row
+++++++++++columnHeader name='Produced'
+++++++++++++staticText name='Produced'
+++++++++++++++inlineTextBox name='Produced'
+++++++++++columnHeader name='Sold'
+++++++++++++staticText name='Sold'
+++++++++++++++inlineTextBox name='Sold'
+++++++++++columnHeader name='Produced'
+++++++++++++staticText name='Produced'
+++++++++++++++inlineTextBox name='Produced'
+++++++++++columnHeader name='Sold'
+++++++++++++staticText name='Sold'
+++++++++++++++inlineTextBox name='Sold'
+++++++++row
+++++++++++rowHeader name='For Toddlers'
+++++++++++++staticText name='For Toddlers'
+++++++++++++++inlineTextBox name='For Toddlers'
+++++++++++rowHeader name='Teddy Bears'
+++++++++++++staticText name='Teddy Bears'
+++++++++++++++inlineTextBox name='Teddy Bears'
+++++++++++cell name='50,000'
+++++++++++++staticText name='50,000'
+++++++++++++++inlineTextBox name='50,000'
+++++++++++cell name='30,000'
+++++++++++++staticText name='30,000'
+++++++++++++++inlineTextBox name='30,000'
+++++++++++cell name='100,000'
+++++++++++++staticText name='100,000'
+++++++++++++++inlineTextBox name='100,000'
+++++++++++cell name='80,000'
+++++++++++++staticText name='80,000'
+++++++++++++++inlineTextBox name='80,000'
+++++++++row
+++++++++++rowHeader name='Action Figures'
+++++++++++++staticText name='Action Figures'
+++++++++++++++inlineTextBox name='Action Figures'
+++++++++++cell name='25,000'
+++++++++++++staticText name='25,000'
+++++++++++++++inlineTextBox name='25,000'
+++++++++++cell name='15,000'
+++++++++++++staticText name='15,000'
+++++++++++++++inlineTextBox name='15,000'
+++++++++++cell name='50,000'
+++++++++++++staticText name='50,000'
+++++++++++++++inlineTextBox name='50,000'
+++++++++++cell name='40,000'
+++++++++++++staticText name='40,000'
+++++++++++++++inlineTextBox name='40,000'
+++++++++row
+++++++++++rowHeader name='For Teens'
+++++++++++++staticText name='For Teens'
+++++++++++++++inlineTextBox name='For Teens'
+++++++++++rowHeader name='Board Games'
+++++++++++++staticText name='Board Games'
+++++++++++++++inlineTextBox name='Board Games'
+++++++++++cell name='5,000'
+++++++++++++staticText name='5,000'
+++++++++++++++inlineTextBox name='5,000'
+++++++++++cell name='2,000'
+++++++++++++staticText name='2,000'
+++++++++++++++inlineTextBox name='2,000'
+++++++++++cell name='6,000'
+++++++++++++staticText name='6,000'
+++++++++++++++inlineTextBox name='6,000'
+++++++++++cell name='4,000'
+++++++++++++staticText name='4,000'
+++++++++++++++inlineTextBox name='4,000'
+++++++++row
+++++++++++rowHeader name='Video Games'
+++++++++++++staticText name='Video Games'
+++++++++++++++inlineTextBox name='Video Games'
+++++++++++cell name='10,000'
+++++++++++++staticText name='10,000'
+++++++++++++++inlineTextBox name='10,000'
+++++++++++cell name='5,000'
+++++++++++++staticText name='5,000'
+++++++++++++++inlineTextBox name='5,000'
+++++++++++cell name='12,000'
+++++++++++++staticText name='12,000'
+++++++++++++++inlineTextBox name='12,000'
+++++++++++cell name='9,000'
+++++++++++++staticText name='9,000'
+++++++++++++++inlineTextBox name='9,000'
diff --git a/content/test/data/accessibility/html/table-presentation-expected-blink.txt b/content/test/data/accessibility/html/table-presentation-expected-blink.txt
index cdf1ddc..2a84820 100644
--- a/content/test/data/accessibility/html/table-presentation-expected-blink.txt
+++ b/content/test/data/accessibility/html/table-presentation-expected-blink.txt
@@ -1,15 +1,16 @@
 rootWebArea name='Table with role=presentation'
 ++genericContainer ignored
-++++presentational ignored
-++++++genericContainer
-++++++++staticText name='1'
-++++++++++inlineTextBox name='1'
-++++++genericContainer
-++++++++staticText name='2'
-++++++++++inlineTextBox name='2'
-++++++genericContainer
-++++++++staticText name='4'
-++++++++++inlineTextBox name='4'
-++++++genericContainer
-++++++++staticText name='5'
-++++++++++inlineTextBox name='5'
+++++genericContainer ignored
+++++++presentational ignored
+++++++++genericContainer
+++++++++++staticText name='1'
+++++++++++++inlineTextBox name='1'
+++++++++genericContainer
+++++++++++staticText name='2'
+++++++++++++inlineTextBox name='2'
+++++++++genericContainer
+++++++++++staticText name='4'
+++++++++++++inlineTextBox name='4'
+++++++++genericContainer
+++++++++++staticText name='5'
+++++++++++++inlineTextBox name='5'
diff --git a/content/test/data/accessibility/html/table-simple-expected-blink.txt b/content/test/data/accessibility/html/table-simple-expected-blink.txt
index 5dac45b..9f662c15 100644
--- a/content/test/data/accessibility/html/table-simple-expected-blink.txt
+++ b/content/test/data/accessibility/html/table-simple-expected-blink.txt
@@ -1,24 +1,25 @@
 rootWebArea name='Table example'
 ++genericContainer ignored
-++++table
-++++++row
-++++++++columnHeader name='Pair'
-++++++++++staticText name='Pair'
-++++++++++++inlineTextBox name='Pair'
-++++++++columnHeader name='Single'
-++++++++++staticText name='Single'
-++++++++++++inlineTextBox name='Single'
-++++++row
-++++++++cell name='AB'
-++++++++++staticText name='AB'
-++++++++++++inlineTextBox name='AB'
-++++++++cell name='B'
-++++++++++staticText name='B'
-++++++++++++inlineTextBox name='B'
-++++++row
-++++++++cell name='CD'
-++++++++++staticText name='CD'
-++++++++++++inlineTextBox name='CD'
-++++++++cell name='D'
-++++++++++staticText name='D'
-++++++++++++inlineTextBox name='D'
+++++genericContainer ignored
+++++++table
+++++++++row
+++++++++++columnHeader name='Pair'
+++++++++++++staticText name='Pair'
+++++++++++++++inlineTextBox name='Pair'
+++++++++++columnHeader name='Single'
+++++++++++++staticText name='Single'
+++++++++++++++inlineTextBox name='Single'
+++++++++row
+++++++++++cell name='AB'
+++++++++++++staticText name='AB'
+++++++++++++++inlineTextBox name='AB'
+++++++++++cell name='B'
+++++++++++++staticText name='B'
+++++++++++++++inlineTextBox name='B'
+++++++++row
+++++++++++cell name='CD'
+++++++++++++staticText name='CD'
+++++++++++++++inlineTextBox name='CD'
+++++++++++cell name='D'
+++++++++++++staticText name='D'
+++++++++++++++inlineTextBox name='D'
diff --git a/content/test/data/accessibility/html/table-spans-expected-blink.txt b/content/test/data/accessibility/html/table-spans-expected-blink.txt
index 9c4f8b5..d698db9 100644
--- a/content/test/data/accessibility/html/table-spans-expected-blink.txt
+++ b/content/test/data/accessibility/html/table-spans-expected-blink.txt
@@ -1,29 +1,30 @@
 rootWebArea name='Table example with rowspan and colspan'
 ++genericContainer ignored
-++++table
-++++++row
-++++++++cell name='AD'
-++++++++++staticText name='AD'
-++++++++++++inlineTextBox name='AD'
-++++++++cell name='BC'
-++++++++++staticText name='BC'
-++++++++++++inlineTextBox name='BC'
-++++++row
-++++++++cell name='EF'
-++++++++++staticText name='EF'
-++++++++++++inlineTextBox name='EF'
-++++table
-++++++row
-++++++++cell name='AD'
-++++++++++staticText name='AD'
-++++++++++++inlineTextBox name='AD'
-++++++++cell name='BC'
-++++++++++staticText name='BC'
-++++++++++++inlineTextBox name='BC'
-++++++row
-++++++++cell name='EF'
-++++++++++staticText name='EF'
-++++++++++++inlineTextBox name='EF'
-++++++++cell name='GH'
-++++++++++staticText name='GH'
-++++++++++++inlineTextBox name='GH'
+++++genericContainer ignored
+++++++table
+++++++++row
+++++++++++cell name='AD'
+++++++++++++staticText name='AD'
+++++++++++++++inlineTextBox name='AD'
+++++++++++cell name='BC'
+++++++++++++staticText name='BC'
+++++++++++++++inlineTextBox name='BC'
+++++++++row
+++++++++++cell name='EF'
+++++++++++++staticText name='EF'
+++++++++++++++inlineTextBox name='EF'
+++++++table
+++++++++row
+++++++++++cell name='AD'
+++++++++++++staticText name='AD'
+++++++++++++++inlineTextBox name='AD'
+++++++++++cell name='BC'
+++++++++++++staticText name='BC'
+++++++++++++++inlineTextBox name='BC'
+++++++++row
+++++++++++cell name='EF'
+++++++++++++staticText name='EF'
+++++++++++++++inlineTextBox name='EF'
+++++++++++cell name='GH'
+++++++++++++staticText name='GH'
+++++++++++++++inlineTextBox name='GH'
diff --git a/content/test/data/accessibility/html/table-th-colheader-expected-blink.txt b/content/test/data/accessibility/html/table-th-colheader-expected-blink.txt
index 1f1a9d4..4e2783f 100644
--- a/content/test/data/accessibility/html/table-th-colheader-expected-blink.txt
+++ b/content/test/data/accessibility/html/table-th-colheader-expected-blink.txt
@@ -1,17 +1,18 @@
 rootWebArea
 ++genericContainer ignored
-++++table
-++++++row
-++++++++columnHeader name='Firstname'
-++++++++++staticText name='Firstname'
-++++++++++++inlineTextBox name='Firstname'
-++++++++columnHeader name='Lastname'
-++++++++++staticText name='Lastname'
-++++++++++++inlineTextBox name='Lastname'
-++++++row
-++++++++cell name='Jill'
-++++++++++staticText name='Jill'
-++++++++++++inlineTextBox name='Jill'
-++++++++cell name='Smith'
-++++++++++staticText name='Smith'
-++++++++++++inlineTextBox name='Smith'
+++++genericContainer ignored
+++++++table
+++++++++row
+++++++++++columnHeader name='Firstname'
+++++++++++++staticText name='Firstname'
+++++++++++++++inlineTextBox name='Firstname'
+++++++++++columnHeader name='Lastname'
+++++++++++++staticText name='Lastname'
+++++++++++++++inlineTextBox name='Lastname'
+++++++++row
+++++++++++cell name='Jill'
+++++++++++++staticText name='Jill'
+++++++++++++++inlineTextBox name='Jill'
+++++++++++cell name='Smith'
+++++++++++++staticText name='Smith'
+++++++++++++++inlineTextBox name='Smith'
diff --git a/content/test/data/accessibility/html/table-th-rowheader-expected-blink.txt b/content/test/data/accessibility/html/table-th-rowheader-expected-blink.txt
index 315fbdf..7d4ca5e 100644
--- a/content/test/data/accessibility/html/table-th-rowheader-expected-blink.txt
+++ b/content/test/data/accessibility/html/table-th-rowheader-expected-blink.txt
@@ -1,17 +1,18 @@
 rootWebArea name='Table example - th rowheader'
 ++genericContainer ignored
-++++table
-++++++row
-++++++++rowHeader name='Firstname'
-++++++++++staticText name='Firstname'
-++++++++++++inlineTextBox name='Firstname'
-++++++++cell name='Jill'
-++++++++++staticText name='Jill'
-++++++++++++inlineTextBox name='Jill'
-++++++row
-++++++++rowHeader name='Lastname'
-++++++++++staticText name='Lastname'
-++++++++++++inlineTextBox name='Lastname'
-++++++++cell name='Smith'
-++++++++++staticText name='Smith'
-++++++++++++inlineTextBox name='Smith'
+++++genericContainer ignored
+++++++table
+++++++++row
+++++++++++rowHeader name='Firstname'
+++++++++++++staticText name='Firstname'
+++++++++++++++inlineTextBox name='Firstname'
+++++++++++cell name='Jill'
+++++++++++++staticText name='Jill'
+++++++++++++++inlineTextBox name='Jill'
+++++++++row
+++++++++++rowHeader name='Lastname'
+++++++++++++staticText name='Lastname'
+++++++++++++++inlineTextBox name='Lastname'
+++++++++++cell name='Smith'
+++++++++++++staticText name='Smith'
+++++++++++++++inlineTextBox name='Smith'
diff --git a/content/test/data/accessibility/html/table-thead-tbody-tfoot-expected-blink.txt b/content/test/data/accessibility/html/table-thead-tbody-tfoot-expected-blink.txt
index cc17c74..b0e694a 100644
--- a/content/test/data/accessibility/html/table-thead-tbody-tfoot-expected-blink.txt
+++ b/content/test/data/accessibility/html/table-thead-tbody-tfoot-expected-blink.txt
@@ -1,31 +1,32 @@
 rootWebArea name='Table example - thead, tbody, tfoot'
 ++genericContainer ignored
-++++table
-++++++row
-++++++++columnHeader name='Sum'
-++++++++++staticText name='Sum'
-++++++++++++inlineTextBox name='Sum'
-++++++++columnHeader name='Subtraction'
-++++++++++staticText name='Subtraction'
-++++++++++++inlineTextBox name='Subtraction'
-++++++row
-++++++++cell name='10'
-++++++++++staticText name='10'
-++++++++++++inlineTextBox name='10'
-++++++++cell name='7'
-++++++++++staticText name='7'
-++++++++++++inlineTextBox name='7'
-++++++row
-++++++++cell name='2'
-++++++++++staticText name='2'
-++++++++++++inlineTextBox name='2'
-++++++++cell name='4'
-++++++++++staticText name='4'
-++++++++++++inlineTextBox name='4'
-++++++row
-++++++++cell name='12'
-++++++++++staticText name='12'
-++++++++++++inlineTextBox name='12'
-++++++++cell name='3'
-++++++++++staticText name='3'
-++++++++++++inlineTextBox name='3'
+++++genericContainer ignored
+++++++table
+++++++++row
+++++++++++columnHeader name='Sum'
+++++++++++++staticText name='Sum'
+++++++++++++++inlineTextBox name='Sum'
+++++++++++columnHeader name='Subtraction'
+++++++++++++staticText name='Subtraction'
+++++++++++++++inlineTextBox name='Subtraction'
+++++++++row
+++++++++++cell name='10'
+++++++++++++staticText name='10'
+++++++++++++++inlineTextBox name='10'
+++++++++++cell name='7'
+++++++++++++staticText name='7'
+++++++++++++++inlineTextBox name='7'
+++++++++row
+++++++++++cell name='2'
+++++++++++++staticText name='2'
+++++++++++++++inlineTextBox name='2'
+++++++++++cell name='4'
+++++++++++++staticText name='4'
+++++++++++++++inlineTextBox name='4'
+++++++++row
+++++++++++cell name='12'
+++++++++++++staticText name='12'
+++++++++++++++inlineTextBox name='12'
+++++++++++cell name='3'
+++++++++++++staticText name='3'
+++++++++++++++inlineTextBox name='3'
diff --git a/content/test/data/accessibility/html/text-decoration-styles-expected-blink.txt b/content/test/data/accessibility/html/text-decoration-styles-expected-blink.txt
index 93574ab..0ff1af2 100644
--- a/content/test/data/accessibility/html/text-decoration-styles-expected-blink.txt
+++ b/content/test/data/accessibility/html/text-decoration-styles-expected-blink.txt
@@ -1,56 +1,57 @@
 rootWebArea
 ++genericContainer ignored
-++++paragraph textOverlineStyle=solid
-++++++staticText name='overline style: none' textOverlineStyle=solid
-++++++++inlineTextBox name='overline style: none'
-++++paragraph textOverlineStyle=dotted
-++++++staticText name='overline style: dotted' textOverlineStyle=dotted
-++++++++inlineTextBox name='overline style: dotted'
-++++paragraph textOverlineStyle=dashed
-++++++staticText name='overline style: dashed' textOverlineStyle=dashed
-++++++++inlineTextBox name='overline style: dashed'
-++++paragraph textOverlineStyle=solid
-++++++staticText name='overline style: solid' textOverlineStyle=solid
-++++++++inlineTextBox name='overline style: solid'
-++++paragraph textOverlineStyle=double
-++++++staticText name='overline style: double' textOverlineStyle=double
-++++++++inlineTextBox name='overline style: double'
-++++paragraph textOverlineStyle=wavy
-++++++staticText name='overline style: wavy' textOverlineStyle=wavy
-++++++++inlineTextBox name='overline style: wavy'
-++++paragraph textUnderlineStyle=solid
-++++++staticText name='underline style: none' textUnderlineStyle=solid
-++++++++inlineTextBox name='underline style: none'
-++++paragraph textUnderlineStyle=dotted
-++++++staticText name='underline style: dotted' textUnderlineStyle=dotted
-++++++++inlineTextBox name='underline style: dotted'
-++++paragraph textUnderlineStyle=dashed
-++++++staticText name='underline style: dashed' textUnderlineStyle=dashed
-++++++++inlineTextBox name='underline style: dashed'
-++++paragraph textUnderlineStyle=solid
-++++++staticText name='underline style: solid' textUnderlineStyle=solid
-++++++++inlineTextBox name='underline style: solid'
-++++paragraph textUnderlineStyle=double
-++++++staticText name='underline style: double' textUnderlineStyle=double
-++++++++inlineTextBox name='underline style: double'
-++++paragraph textUnderlineStyle=wavy
-++++++staticText name='underline style: wavy' textUnderlineStyle=wavy
-++++++++inlineTextBox name='underline style: wavy'
-++++paragraph textStrikethroughStyle=solid
-++++++staticText name='line-through style: none' textStrikethroughStyle=solid
-++++++++inlineTextBox name='line-through style: none'
-++++paragraph textStrikethroughStyle=dotted
-++++++staticText name='line-through style: dotted' textStrikethroughStyle=dotted
-++++++++inlineTextBox name='line-through style: dotted'
-++++paragraph textStrikethroughStyle=dashed
-++++++staticText name='line-through style: dashed' textStrikethroughStyle=dashed
-++++++++inlineTextBox name='line-through style: dashed'
-++++paragraph textStrikethroughStyle=solid
-++++++staticText name='line-through style: solid' textStrikethroughStyle=solid
-++++++++inlineTextBox name='line-through style: solid'
-++++paragraph textStrikethroughStyle=double
-++++++staticText name='line-through style: double' textStrikethroughStyle=double
-++++++++inlineTextBox name='line-through style: double'
-++++paragraph textStrikethroughStyle=wavy
-++++++staticText name='line-through style: wavy' textStrikethroughStyle=wavy
-++++++++inlineTextBox name='line-through style: wavy'
+++++genericContainer ignored
+++++++paragraph textOverlineStyle=solid
+++++++++staticText name='overline style: none' textOverlineStyle=solid
+++++++++++inlineTextBox name='overline style: none'
+++++++paragraph textOverlineStyle=dotted
+++++++++staticText name='overline style: dotted' textOverlineStyle=dotted
+++++++++++inlineTextBox name='overline style: dotted'
+++++++paragraph textOverlineStyle=dashed
+++++++++staticText name='overline style: dashed' textOverlineStyle=dashed
+++++++++++inlineTextBox name='overline style: dashed'
+++++++paragraph textOverlineStyle=solid
+++++++++staticText name='overline style: solid' textOverlineStyle=solid
+++++++++++inlineTextBox name='overline style: solid'
+++++++paragraph textOverlineStyle=double
+++++++++staticText name='overline style: double' textOverlineStyle=double
+++++++++++inlineTextBox name='overline style: double'
+++++++paragraph textOverlineStyle=wavy
+++++++++staticText name='overline style: wavy' textOverlineStyle=wavy
+++++++++++inlineTextBox name='overline style: wavy'
+++++++paragraph textUnderlineStyle=solid
+++++++++staticText name='underline style: none' textUnderlineStyle=solid
+++++++++++inlineTextBox name='underline style: none'
+++++++paragraph textUnderlineStyle=dotted
+++++++++staticText name='underline style: dotted' textUnderlineStyle=dotted
+++++++++++inlineTextBox name='underline style: dotted'
+++++++paragraph textUnderlineStyle=dashed
+++++++++staticText name='underline style: dashed' textUnderlineStyle=dashed
+++++++++++inlineTextBox name='underline style: dashed'
+++++++paragraph textUnderlineStyle=solid
+++++++++staticText name='underline style: solid' textUnderlineStyle=solid
+++++++++++inlineTextBox name='underline style: solid'
+++++++paragraph textUnderlineStyle=double
+++++++++staticText name='underline style: double' textUnderlineStyle=double
+++++++++++inlineTextBox name='underline style: double'
+++++++paragraph textUnderlineStyle=wavy
+++++++++staticText name='underline style: wavy' textUnderlineStyle=wavy
+++++++++++inlineTextBox name='underline style: wavy'
+++++++paragraph textStrikethroughStyle=solid
+++++++++staticText name='line-through style: none' textStrikethroughStyle=solid
+++++++++++inlineTextBox name='line-through style: none'
+++++++paragraph textStrikethroughStyle=dotted
+++++++++staticText name='line-through style: dotted' textStrikethroughStyle=dotted
+++++++++++inlineTextBox name='line-through style: dotted'
+++++++paragraph textStrikethroughStyle=dashed
+++++++++staticText name='line-through style: dashed' textStrikethroughStyle=dashed
+++++++++++inlineTextBox name='line-through style: dashed'
+++++++paragraph textStrikethroughStyle=solid
+++++++++staticText name='line-through style: solid' textStrikethroughStyle=solid
+++++++++++inlineTextBox name='line-through style: solid'
+++++++paragraph textStrikethroughStyle=double
+++++++++staticText name='line-through style: double' textStrikethroughStyle=double
+++++++++++inlineTextBox name='line-through style: double'
+++++++paragraph textStrikethroughStyle=wavy
+++++++++staticText name='line-through style: wavy' textStrikethroughStyle=wavy
+++++++++++inlineTextBox name='line-through style: wavy'
diff --git a/content/test/data/accessibility/html/textarea-expected-blink.txt b/content/test/data/accessibility/html/textarea-expected-blink.txt
index 45af3d09..da5acae 100644
--- a/content/test/data/accessibility/html/textarea-expected-blink.txt
+++ b/content/test/data/accessibility/html/textarea-expected-blink.txt
@@ -1,13 +1,14 @@
 rootWebArea
-++genericContainer
-++++textField multiline value='The <newline>textarea tag  defines a multi-line text input control.<newline>' textSelStart=0 textSelEnd=0
-++++++genericContainer
-++++++++staticText name='The <newline>textarea tag  defines a multi-line text input control.<newline>'
-++++++++++inlineTextBox name='The '
-++++++++++inlineTextBox name='<newline>'
-++++++++++inlineTextBox name='textarea tag  defines a multi-line text input'
-++++++++++inlineTextBox name=' '
-++++++++++inlineTextBox name='control.'
-++++++++++inlineTextBox name='<newline>'
-++++++++lineBreak name='<newline>'
-++++++++++inlineTextBox name='<newline>'
+++genericContainer ignored
+++++genericContainer
+++++++textField multiline value='The <newline>textarea tag  defines a multi-line text input control.<newline>' textSelStart=0 textSelEnd=0
+++++++++genericContainer
+++++++++++staticText name='The <newline>textarea tag  defines a multi-line text input control.<newline>'
+++++++++++++inlineTextBox name='The '
+++++++++++++inlineTextBox name='<newline>'
+++++++++++++inlineTextBox name='textarea tag  defines a multi-line text input'
+++++++++++++inlineTextBox name=' '
+++++++++++++inlineTextBox name='control.'
+++++++++++++inlineTextBox name='<newline>'
+++++++++++lineBreak name='<newline>'
+++++++++++++inlineTextBox name='<newline>'
diff --git a/content/test/data/accessibility/html/textarea-read-only-expected-blink.txt b/content/test/data/accessibility/html/textarea-read-only-expected-blink.txt
index 7e1a896..978e17c 100644
--- a/content/test/data/accessibility/html/textarea-read-only-expected-blink.txt
+++ b/content/test/data/accessibility/html/textarea-read-only-expected-blink.txt
@@ -1,11 +1,12 @@
 rootWebArea
-++genericContainer
-++++textField multiline value='The textarea tag defines a multi-line text input control.<newline>' textSelStart=0 textSelEnd=0 restriction=readOnly
-++++++genericContainer
-++++++++staticText name='The textarea tag defines a multi-line text input control.<newline>'
-++++++++++inlineTextBox name='The textarea tag defines a multi-line text input'
-++++++++++inlineTextBox name=' '
-++++++++++inlineTextBox name='control.'
-++++++++++inlineTextBox name='<newline>'
-++++++++lineBreak name='<newline>'
-++++++++++inlineTextBox name='<newline>'
+++genericContainer ignored
+++++genericContainer
+++++++textField multiline value='The textarea tag defines a multi-line text input control.<newline>' textSelStart=0 textSelEnd=0 restriction=readOnly
+++++++++genericContainer
+++++++++++staticText name='The textarea tag defines a multi-line text input control.<newline>'
+++++++++++++inlineTextBox name='The textarea tag defines a multi-line text input'
+++++++++++++inlineTextBox name=' '
+++++++++++++inlineTextBox name='control.'
+++++++++++++inlineTextBox name='<newline>'
+++++++++++lineBreak name='<newline>'
+++++++++++++inlineTextBox name='<newline>'
diff --git a/content/test/data/accessibility/html/textarea-with-selection-expected-blink.txt b/content/test/data/accessibility/html/textarea-with-selection-expected-blink.txt
index 17c2e94..098a5a0 100644
--- a/content/test/data/accessibility/html/textarea-with-selection-expected-blink.txt
+++ b/content/test/data/accessibility/html/textarea-with-selection-expected-blink.txt
@@ -1,11 +1,12 @@
 rootWebArea
-++genericContainer
-++++textField multiline value='The textarea tag defines a multi-line text input control.<newline>' textSelStart=0 textSelEnd=58
-++++++genericContainer
-++++++++staticText name='The textarea tag defines a multi-line text input control.<newline>'
-++++++++++inlineTextBox name='The textarea tag defines a multi-line text input'
-++++++++++inlineTextBox name=' '
-++++++++++inlineTextBox name='control.'
-++++++++++inlineTextBox name='<newline>'
-++++++++lineBreak name='<newline>'
-++++++++++inlineTextBox name='<newline>'
+++genericContainer ignored
+++++genericContainer
+++++++textField multiline value='The textarea tag defines a multi-line text input control.<newline>' textSelStart=0 textSelEnd=58
+++++++++genericContainer
+++++++++++staticText name='The textarea tag defines a multi-line text input control.<newline>'
+++++++++++++inlineTextBox name='The textarea tag defines a multi-line text input'
+++++++++++++inlineTextBox name=' '
+++++++++++++inlineTextBox name='control.'
+++++++++++++inlineTextBox name='<newline>'
+++++++++++lineBreak name='<newline>'
+++++++++++++inlineTextBox name='<newline>'
diff --git a/content/test/data/accessibility/html/time-expected-blink.txt b/content/test/data/accessibility/html/time-expected-blink.txt
index e709bfd..cda9ef3 100644
--- a/content/test/data/accessibility/html/time-expected-blink.txt
+++ b/content/test/data/accessibility/html/time-expected-blink.txt
@@ -1,10 +1,11 @@
 rootWebArea
-++genericContainer
-++++time
-++++++staticText name='10:00'
-++++++++inlineTextBox name='10:00'
-++++staticText name=' '
-++++++inlineTextBox name=' '
-++++time
-++++++staticText name='Valentines day'
-++++++++inlineTextBox name='Valentines day'
+++genericContainer ignored
+++++genericContainer
+++++++time
+++++++++staticText name='10:00'
+++++++++++inlineTextBox name='10:00'
+++++++staticText name=' '
+++++++++inlineTextBox name=' '
+++++++time
+++++++++staticText name='Valentines day'
+++++++++++inlineTextBox name='Valentines day'
diff --git a/content/test/data/accessibility/html/title-changed-expected-blink.txt b/content/test/data/accessibility/html/title-changed-expected-blink.txt
index 2199bd8b..004a9e89 100644
--- a/content/test/data/accessibility/html/title-changed-expected-blink.txt
+++ b/content/test/data/accessibility/html/title-changed-expected-blink.txt
@@ -1,2 +1,3 @@
 rootWebArea name='New Title'
 ++genericContainer ignored
+++++genericContainer ignored
diff --git a/content/test/data/accessibility/html/title-expected-blink.txt b/content/test/data/accessibility/html/title-expected-blink.txt
index 265b4fc1..c5629f5 100644
--- a/content/test/data/accessibility/html/title-expected-blink.txt
+++ b/content/test/data/accessibility/html/title-expected-blink.txt
@@ -1,2 +1,3 @@
 rootWebArea name='Title of the document'
 ++genericContainer ignored
+++++genericContainer ignored
diff --git a/content/test/data/accessibility/html/transition-expected-blink.txt b/content/test/data/accessibility/html/transition-expected-blink.txt
index 9681602..c77af37 100644
--- a/content/test/data/accessibility/html/transition-expected-blink.txt
+++ b/content/test/data/accessibility/html/transition-expected-blink.txt
@@ -1,7 +1,8 @@
 rootWebArea
-++genericContainer
-++++button name='GrowButton'
-++++++staticText name='GrowButton'
-++++++++inlineTextBox name='GrowButton'
-++++staticText name='Done'
-++++++inlineTextBox name='Done'
+++genericContainer ignored
+++++genericContainer
+++++++button name='GrowButton'
+++++++++staticText name='GrowButton'
+++++++++++inlineTextBox name='GrowButton'
+++++++staticText name='Done'
+++++++++inlineTextBox name='Done'
diff --git a/content/test/data/accessibility/html/truncate-label-expected-blink.txt b/content/test/data/accessibility/html/truncate-label-expected-blink.txt
index 8485a24..da733772 100644
--- a/content/test/data/accessibility/html/truncate-label-expected-blink.txt
+++ b/content/test/data/accessibility/html/truncate-label-expected-blink.txt
@@ -1,3 +1,4 @@
 rootWebArea
 ++genericContainer ignored
-++++genericContainer name='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
+++++genericContainer ignored
+++++++genericContainer name='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
diff --git a/content/test/data/accessibility/html/var-expected-blink.txt b/content/test/data/accessibility/html/var-expected-blink.txt
index ca6d91b..0abe8a72 100644
--- a/content/test/data/accessibility/html/var-expected-blink.txt
+++ b/content/test/data/accessibility/html/var-expected-blink.txt
@@ -1,4 +1,5 @@
 rootWebArea
-++genericContainer
-++++staticText name='Variable'
-++++++inlineTextBox name='Variable'
+++genericContainer ignored
+++++genericContainer
+++++++staticText name='Variable'
+++++++++inlineTextBox name='Variable'
diff --git a/content/test/data/accessibility/html/wbr-expected-blink.txt b/content/test/data/accessibility/html/wbr-expected-blink.txt
index 911d792..3fc0cb2 100644
--- a/content/test/data/accessibility/html/wbr-expected-blink.txt
+++ b/content/test/data/accessibility/html/wbr-expected-blink.txt
@@ -1,8 +1,9 @@
 rootWebArea
-++genericContainer
-++++staticText name='Supercali'
-++++++inlineTextBox name='Supercali'
-++++staticText name='fragilistic'
-++++++inlineTextBox name='fragilistic'
-++++staticText name='expialidocious'
-++++++inlineTextBox name='expialidocious'
+++genericContainer ignored
+++++genericContainer
+++++++staticText name='Supercali'
+++++++++inlineTextBox name='Supercali'
+++++++staticText name='fragilistic'
+++++++++inlineTextBox name='fragilistic'
+++++++staticText name='expialidocious'
+++++++++inlineTextBox name='expialidocious'
diff --git a/content/test/data/accessibility/html/window-crops-items-expected-blink.txt b/content/test/data/accessibility/html/window-crops-items-expected-blink.txt
index 08f63ca..c91fa97 100644
--- a/content/test/data/accessibility/html/window-crops-items-expected-blink.txt
+++ b/content/test/data/accessibility/html/window-crops-items-expected-blink.txt
@@ -1,23 +1,24 @@
 rootWebArea
 ++genericContainer ignored
-++++button size=(300, 150) name='Button fits'
-++++++staticText name='Button fits'
-++++++++inlineTextBox name='Button fits'
-++++button offscreen size=(300, 150) pageSize=(1, 150) name='Button offscreen X'
-++++++staticText offscreen name='Button offscreen X'
-++++++++inlineTextBox offscreen name='Button offscreen X'
-++++button offscreen size=(300, 150) pageSize=(300, 1) name='Button offscreen Y'
-++++++staticText offscreen name='Button offscreen Y'
-++++++++inlineTextBox offscreen name='Button offscreen Y'
-++++button size=(300, 150) name='Button partially on screen'
-++++++staticText name='Button partially on screen'
-++++++++inlineTextBox name='Button partially on screen'
-++++button offscreen size=(300, 150) pageSize=(1, 1) name='Button offscreen'
-++++++staticText offscreen pageSize=(1, 1) name='Button offscreen'
-++++++++inlineTextBox offscreen pageSize=(1, 1) name='Button offscreen'
-++++button offscreen size=(300, 150) pageSize=(1, 1) name='Button offscreen top'
-++++++staticText offscreen pageSize=(1, 1) name='Button offscreen top'
-++++++++inlineTextBox offscreen pageSize=(1, 1) name='Button offscreen top'
-++++button size=(300, 150) pageSize=(208, 58) name='Button partially on screen'
-++++++staticText offscreen name='Button partially on screen'
-++++++++inlineTextBox offscreen name='Button partially on screen'
+++++genericContainer ignored
+++++++button size=(300, 150) name='Button fits'
+++++++++staticText name='Button fits'
+++++++++++inlineTextBox name='Button fits'
+++++++button offscreen size=(300, 150) pageSize=(1, 150) name='Button offscreen X'
+++++++++staticText offscreen name='Button offscreen X'
+++++++++++inlineTextBox offscreen name='Button offscreen X'
+++++++button offscreen size=(300, 150) pageSize=(300, 1) name='Button offscreen Y'
+++++++++staticText offscreen name='Button offscreen Y'
+++++++++++inlineTextBox offscreen name='Button offscreen Y'
+++++++button size=(300, 150) name='Button partially on screen'
+++++++++staticText name='Button partially on screen'
+++++++++++inlineTextBox name='Button partially on screen'
+++++++button offscreen size=(300, 150) pageSize=(1, 1) name='Button offscreen'
+++++++++staticText offscreen pageSize=(1, 1) name='Button offscreen'
+++++++++++inlineTextBox offscreen pageSize=(1, 1) name='Button offscreen'
+++++++button offscreen size=(300, 150) pageSize=(1, 1) name='Button offscreen top'
+++++++++staticText offscreen pageSize=(1, 1) name='Button offscreen top'
+++++++++++inlineTextBox offscreen pageSize=(1, 1) name='Button offscreen top'
+++++++button size=(300, 150) pageSize=(208, 58) name='Button partially on screen'
+++++++++staticText offscreen name='Button partially on screen'
+++++++++++inlineTextBox offscreen name='Button partially on screen'
diff --git a/content/test/data/accessibility/language-detection/dynamic-basic-expected-blink.txt b/content/test/data/accessibility/language-detection/dynamic-basic-expected-blink.txt
index 2472f5f..ff0c9ef 100644
--- a/content/test/data/accessibility/language-detection/dynamic-basic-expected-blink.txt
+++ b/content/test/data/accessibility/language-detection/dynamic-basic-expected-blink.txt
@@ -1,4 +1,5 @@
 rootWebArea language='en-US'
 ++genericContainer ignored language='fr-FR'
-++++genericContainer language='fr-FR'
-++++++staticText language='de' name='Ein Bild ist nicht zu verwechseln mit einer Sache, die man berühren kann. Können Sie meine Pfeife stopfen? Natürlich nicht! Sie ist nur eine Darstellung. Hätte ich auf mein Bild geschrieben, dies ist eine Pfeife, so hätte ich gelogen. Das Abbild einer Marmeladenschnitte ist ganz gewiss nichts Essbares.'
+++++genericContainer ignored language='fr-FR'
+++++++genericContainer language='fr-FR'
+++++++++staticText language='de' name='Ein Bild ist nicht zu verwechseln mit einer Sache, die man berühren kann. Können Sie meine Pfeife stopfen? Natürlich nicht! Sie ist nur eine Darstellung. Hätte ich auf mein Bild geschrieben, dies ist eine Pfeife, so hätte ich gelogen. Das Abbild einer Marmeladenschnitte ist ganz gewiss nichts Essbares.'
diff --git a/content/test/data/accessibility/language-detection/dynamic-multiple-inserts-expected-blink.txt b/content/test/data/accessibility/language-detection/dynamic-multiple-inserts-expected-blink.txt
index 841e129..6b850f9 100644
--- a/content/test/data/accessibility/language-detection/dynamic-multiple-inserts-expected-blink.txt
+++ b/content/test/data/accessibility/language-detection/dynamic-multiple-inserts-expected-blink.txt
@@ -1,9 +1,10 @@
 rootWebArea language='en-US'
 ++genericContainer ignored language='fr-FR'
-++++genericContainer language='fr-FR'
+++++genericContainer ignored language='fr-FR'
 ++++++genericContainer language='fr-FR'
-++++++++staticText language='en' name='This is text created using Google Translate, it is unlikely to be idiomatic in the given target language. This text is only used to test language detection'
-++++++genericContainer language='fr-FR'
-++++++++staticText language='fr' name='Ce texte a été créé avec Google Translate, il est peu probable qu'il soit idiomatique dans la langue cible indiquée Ce texte est uniquement utilisé pour tester la détection de la langue.'
-++++++genericContainer language='fr-FR'
-++++++++staticText language='de' name='Dies ist ein mit Google Translate erstellter Text. Es ist unwahrscheinlich, dass er in der angegebenen Zielsprache idiomatisch ist. Dieser Text wird nur zum Testen der Spracherkennung verwendet.'
+++++++++genericContainer language='fr-FR'
+++++++++++staticText language='en' name='This is text created using Google Translate, it is unlikely to be idiomatic in the given target language. This text is only used to test language detection'
+++++++++genericContainer language='fr-FR'
+++++++++++staticText language='fr' name='Ce texte a été créé avec Google Translate, il est peu probable qu'il soit idiomatique dans la langue cible indiquée Ce texte est uniquement utilisé pour tester la détection de la langue.'
+++++++++genericContainer language='fr-FR'
+++++++++++staticText language='de' name='Dies ist ein mit Google Translate erstellter Text. Es ist unwahrscheinlich, dass er in der angegebenen Zielsprache idiomatisch ist. Dieser Text wird nur zum Testen der Spracherkennung verwendet.'
diff --git a/content/test/data/accessibility/language-detection/dynamic-reparenting-expected-blink.txt b/content/test/data/accessibility/language-detection/dynamic-reparenting-expected-blink.txt
index f0b5083b..50720ddd 100644
--- a/content/test/data/accessibility/language-detection/dynamic-reparenting-expected-blink.txt
+++ b/content/test/data/accessibility/language-detection/dynamic-reparenting-expected-blink.txt
@@ -1,20 +1,21 @@
 rootWebArea language='en-US'
 ++genericContainer ignored language='fr-FR'
-++++list language='fr-FR'
-++++list language='fr-FR'
-++++++listItem language='fr-FR'
-++++++++listMarker language='fr-FR' name='• '
-++++++++++staticText language='fr-FR' name='• '
-++++++++staticText language='fr-FR' name='Placeholder listitem'
-++++++listItem language='fr-FR'
-++++++++listMarker language='fr-FR' name='• '
-++++++++++staticText language='fr-FR' name='• '
-++++++++staticText language='en' name='This is text created using Google Translate, it is unlikely to be idiomatic in the given target language. This text is only used to test language detection'
-++++++listItem language='fr-FR'
-++++++++listMarker language='fr-FR' name='• '
-++++++++++staticText language='fr-FR' name='• '
-++++++++staticText language='fr' name='Ce texte a été créé avec Google Translate, il est peu probable qu'il soit idiomatique dans la langue cible indiquée Ce texte est uniquement utilisé pour tester la détection de la langue.'
-++++++listItem language='fr-FR'
-++++++++listMarker language='fr-FR' name='• '
-++++++++++staticText language='fr-FR' name='• '
-++++++++staticText language='de' name='Dies ist ein mit Google Translate erstellter Text. Es ist unwahrscheinlich, dass er in der angegebenen Zielsprache idiomatisch ist. Dieser Text wird nur zum Testen der Spracherkennung verwendet.'
+++++genericContainer ignored language='fr-FR'
+++++++list language='fr-FR'
+++++++list language='fr-FR'
+++++++++listItem language='fr-FR'
+++++++++++listMarker language='fr-FR' name='• '
+++++++++++++staticText language='fr-FR' name='• '
+++++++++++staticText language='fr-FR' name='Placeholder listitem'
+++++++++listItem language='fr-FR'
+++++++++++listMarker language='fr-FR' name='• '
+++++++++++++staticText language='fr-FR' name='• '
+++++++++++staticText language='en' name='This is text created using Google Translate, it is unlikely to be idiomatic in the given target language. This text is only used to test language detection'
+++++++++listItem language='fr-FR'
+++++++++++listMarker language='fr-FR' name='• '
+++++++++++++staticText language='fr-FR' name='• '
+++++++++++staticText language='fr' name='Ce texte a été créé avec Google Translate, il est peu probable qu'il soit idiomatique dans la langue cible indiquée Ce texte est uniquement utilisé pour tester la détection de la langue.'
+++++++++listItem language='fr-FR'
+++++++++++listMarker language='fr-FR' name='• '
+++++++++++++staticText language='fr-FR' name='• '
+++++++++++staticText language='de' name='Dies ist ein mit Google Translate erstellter Text. Es ist unwahrscheinlich, dass er in der angegebenen Zielsprache idiomatisch ist. Dieser Text wird nur zum Testen der Spracherkennung verwendet.'
diff --git a/content/test/data/accessibility/language-detection/lang-attribute-expected-blink.txt b/content/test/data/accessibility/language-detection/lang-attribute-expected-blink.txt
index cea21b6..a0b91f6f 100644
--- a/content/test/data/accessibility/language-detection/lang-attribute-expected-blink.txt
+++ b/content/test/data/accessibility/language-detection/lang-attribute-expected-blink.txt
@@ -1,8 +1,9 @@
 rootWebArea language='en-US'
-++genericContainer language='en'
-++++staticText language='es-ES' name='Este documento es excelente. '
-++++++inlineTextBox language='es-ES' name='Este documento es excelente. '
-++++staticText language='fr' name='Ce document est excellent. '
-++++++inlineTextBox language='fr' name='Ce document est excellent. '
-++++staticText language='en' name='This document is excellent.'
-++++++inlineTextBox language='en' name='This document is excellent.'
+++genericContainer ignored language='en'
+++++genericContainer language='en'
+++++++staticText language='es-ES' name='Este documento es excelente. '
+++++++++inlineTextBox language='es-ES' name='Este documento es excelente. '
+++++++staticText language='fr' name='Ce document est excellent. '
+++++++++inlineTextBox language='fr' name='Ce document est excellent. '
+++++++staticText language='en' name='This document is excellent.'
+++++++++inlineTextBox language='en' name='This document is excellent.'
diff --git a/content/test/data/accessibility/language-detection/lang-attribute-nested-expected-blink.txt b/content/test/data/accessibility/language-detection/lang-attribute-nested-expected-blink.txt
index cb6c7c1..6fa75081 100644
--- a/content/test/data/accessibility/language-detection/lang-attribute-nested-expected-blink.txt
+++ b/content/test/data/accessibility/language-detection/lang-attribute-nested-expected-blink.txt
@@ -1,13 +1,14 @@
 rootWebArea language='en-US'
 ++genericContainer ignored language='en'
-++++genericContainer ignored language='es-ES'
-++++++genericContainer language='en'
-++++++++staticText language='en' name='This document is excellent.'
-++++++++++inlineTextBox language='en' name='This document is excellent.'
-++++++staticText language='es-ES' name='Este documento es excelente.'
-++++++++inlineTextBox language='es-ES' name='Este documento es excelente.'
-++++genericContainer language='fr'
-++++++staticText language='fr' name='Ce document est excellent.'
-++++++++inlineTextBox language='fr' name='Ce document est excellent.'
-++++staticText language='en' name='This document is excellent.'
-++++++inlineTextBox language='en' name='This document is excellent.'
+++++genericContainer ignored language='en'
+++++++genericContainer ignored language='es-ES'
+++++++++genericContainer language='en'
+++++++++++staticText language='en' name='This document is excellent.'
+++++++++++++inlineTextBox language='en' name='This document is excellent.'
+++++++++staticText language='es-ES' name='Este documento es excelente.'
+++++++++++inlineTextBox language='es-ES' name='Este documento es excelente.'
+++++++genericContainer language='fr'
+++++++++staticText language='fr' name='Ce document est excellent.'
+++++++++++inlineTextBox language='fr' name='Ce document est excellent.'
+++++++staticText language='en' name='This document is excellent.'
+++++++++inlineTextBox language='en' name='This document is excellent.'
diff --git a/content/test/data/accessibility/language-detection/lang-attribute-switching-expected-blink.txt b/content/test/data/accessibility/language-detection/lang-attribute-switching-expected-blink.txt
index 5f607759..372baeb 100644
--- a/content/test/data/accessibility/language-detection/lang-attribute-switching-expected-blink.txt
+++ b/content/test/data/accessibility/language-detection/lang-attribute-switching-expected-blink.txt
@@ -1,13 +1,14 @@
 rootWebArea language='en-US'
 ++genericContainer ignored language='en'
-++++paragraph language='en'
-++++++staticText language='en' name='In the morning, I sometimes eat breakfast.'
-++++++++inlineTextBox language='en' name='In the morning, I sometimes eat breakfast.'
-++++paragraph language='fr'
-++++++staticText language='fr' name='Dans l'apres-midi, je dejeune.'
-++++++++inlineTextBox language='fr' name='Dans l'apres-midi, je dejeune.'
-++++paragraph language='en'
-++++++staticText language='en' name='Hello it's a pleasure to meet you. '
-++++++++inlineTextBox language='en' name='Hello it's a pleasure to meet you. '
-++++++staticText language='fr' name='Comment ca va?'
-++++++++inlineTextBox language='fr' name='Comment ca va?'
+++++genericContainer ignored language='en'
+++++++paragraph language='en'
+++++++++staticText language='en' name='In the morning, I sometimes eat breakfast.'
+++++++++++inlineTextBox language='en' name='In the morning, I sometimes eat breakfast.'
+++++++paragraph language='fr'
+++++++++staticText language='fr' name='Dans l'apres-midi, je dejeune.'
+++++++++++inlineTextBox language='fr' name='Dans l'apres-midi, je dejeune.'
+++++++paragraph language='en'
+++++++++staticText language='en' name='Hello it's a pleasure to meet you. '
+++++++++++inlineTextBox language='en' name='Hello it's a pleasure to meet you. '
+++++++++staticText language='fr' name='Comment ca va?'
+++++++++++inlineTextBox language='fr' name='Comment ca va?'
diff --git a/content/test/data/accessibility/language-detection/static-basic-expected-blink.txt b/content/test/data/accessibility/language-detection/static-basic-expected-blink.txt
index c6648f0..94ba26a 100644
--- a/content/test/data/accessibility/language-detection/static-basic-expected-blink.txt
+++ b/content/test/data/accessibility/language-detection/static-basic-expected-blink.txt
@@ -1,6 +1,7 @@
 rootWebArea language='en-US'
 ++genericContainer ignored language='en-GB'
-++++genericContainer language='fr'
-++++++staticText language='en' name='“The famous pipe. How people reproached me for it! And yet, could you stuff my pipe? No, it’s just a representation, is it not? So if I had written on my picture ‘This is a pipe,’ I’d have been lying!"'
-++++genericContainer language='en'
-++++++staticText language='fr' name='« La fameuse pipe, me l’a-t-on assez reprochée ! Et pourtant, pouvez-vous la bourrer ma pipe ? Non, n’est-ce pas, elle n’est qu’une représentation. Donc si j’avais écrit sous mon tableau « ceci est une pipe », j’aurais menti ! »'
+++++genericContainer ignored language='en-GB'
+++++++genericContainer language='fr'
+++++++++staticText language='en' name='“The famous pipe. How people reproached me for it! And yet, could you stuff my pipe? No, it’s just a representation, is it not? So if I had written on my picture ‘This is a pipe,’ I’d have been lying!"'
+++++++genericContainer language='en'
+++++++++staticText language='fr' name='« La fameuse pipe, me l’a-t-on assez reprochée ! Et pourtant, pouvez-vous la bourrer ma pipe ? Non, n’est-ce pas, elle n’est qu’une représentation. Donc si j’avais écrit sous mon tableau « ceci est une pipe », j’aurais menti ! »'
diff --git a/content/test/data/accessibility/test-harness/deny-node-expected-blink.txt b/content/test/data/accessibility/test-harness/deny-node-expected-blink.txt
index 4df9bd7..223ce906 100644
--- a/content/test/data/accessibility/test-harness/deny-node-expected-blink.txt
+++ b/content/test/data/accessibility/test-harness/deny-node-expected-blink.txt
@@ -1,17 +1,18 @@
 rootWebArea
 ++genericContainer ignored
-++++genericContainer
-++++++staticText name='This is a very important form full of very important form related things to fill in, it is likely the most important form you will see within the next 100 milliseconds. You may think I am just rambling, but this is rambling with a purpose! We need enough content in this div to force splitting across multiple inlineTextBox-en which we can then ignore using *-DENY-NODE.'
-++++form
-++++++paragraph
-++++++++staticText name='Please provide your details:'
-++++++labelText
-++++++++staticText name='Quack:'
-++++++textField name='Quack:'
-++++++++genericContainer
-++++++labelText
-++++++++staticText name='Moo?:'
-++++++radioButton name='Mooooo!' checkedState=false
-++++++radioButton name='Mooooo?' checkedState=false
-++++++button name='Submit'
-++++++++staticText name='Submit'
+++++genericContainer ignored
+++++++genericContainer
+++++++++staticText name='This is a very important form full of very important form related things to fill in, it is likely the most important form you will see within the next 100 milliseconds. You may think I am just rambling, but this is rambling with a purpose! We need enough content in this div to force splitting across multiple inlineTextBox-en which we can then ignore using *-DENY-NODE.'
+++++++form
+++++++++paragraph
+++++++++++staticText name='Please provide your details:'
+++++++++labelText
+++++++++++staticText name='Quack:'
+++++++++textField name='Quack:'
+++++++++++genericContainer
+++++++++labelText
+++++++++++staticText name='Moo?:'
+++++++++radioButton name='Mooooo!' checkedState=false
+++++++++radioButton name='Mooooo?' checkedState=false
+++++++++button name='Submit'
+++++++++++staticText name='Submit'
diff --git a/fuchsia/runners/cast/cast_component.cc b/fuchsia/runners/cast/cast_component.cc
index 2fcf3f0..95fa1a2 100644
--- a/fuchsia/runners/cast/cast_component.cc
+++ b/fuchsia/runners/cast/cast_component.cc
@@ -102,6 +102,10 @@
   }
 }
 
+CastRunner* CastComponent::runner() const {
+  return static_cast<CastRunner*>(WebComponent::runner());
+}
+
 void CastComponent::DestroyComponent(int termination_exit_code,
                                      fuchsia::sys::TerminationReason reason) {
   DCHECK(!constructor_active_);
diff --git a/fuchsia/runners/cast/cast_component.h b/fuchsia/runners/cast/cast_component.h
index e7c21db..071970b 100644
--- a/fuchsia/runners/cast/cast_component.h
+++ b/fuchsia/runners/cast/cast_component.h
@@ -71,6 +71,8 @@
 
   cr_fuchsia::AgentManager* agent_manager() { return agent_manager_.get(); }
 
+  CastRunner* runner() const;
+
  private:
   FRIEND_TEST_ALL_PREFIXES(HeadlessCastRunnerIntegrationTest, Headless);
 
diff --git a/fuchsia/runners/cast/cast_runner.cc b/fuchsia/runners/cast/cast_runner.cc
index 760a566..baa6cd1b 100644
--- a/fuchsia/runners/cast/cast_runner.cc
+++ b/fuchsia/runners/cast/cast_runner.cc
@@ -49,10 +49,15 @@
 
 bool AreCastComponentParamsValid(
     const CastComponent::CastComponentParams& params) {
-  return !params.app_config.IsEmpty() &&
-         params.api_bindings_client->HasBindings() &&
-         params.rewrite_rules.has_value() &&
-         params.media_session_id.has_value();
+  if (params.app_config.IsEmpty())
+    return false;
+  if (!params.api_bindings_client->HasBindings())
+    return false;
+  if (!params.rewrite_rules.has_value())
+    return false;
+  if (!params.media_session_id.has_value())
+    return false;
+  return true;
 }
 
 // Creates a CreateContextParams object which can be used as a basis
@@ -110,18 +115,24 @@
 const char CastRunner::kAgentComponentUrl[] =
     "fuchsia-pkg://fuchsia.com/cast_agent#meta/cast_agent.cmx";
 
-CastRunner::CastRunner(fuchsia::web::CreateContextParams create_context_params,
-                       sys::OutgoingDirectory* outgoing_directory)
-    : WebContentRunner(std::move(create_context_params), outgoing_directory),
-      common_create_context_params_(
-          BuildCreateContextParamsForIsolatedRunners(create_params_)) {
-  InitializeServiceDirectory();
-}
+CastRunner::CastRunner(
+    WebContentRunner::GetContextParamsCallback get_context_params_callback,
+    bool is_headless,
+    sys::OutgoingDirectory* outgoing_directory)
+    : WebContentRunner(base::BindRepeating(&CastRunner::GetMainContextParams,
+                                           base::Unretained(this)),
+                       outgoing_directory),
+      get_context_params_callback_(std::move(get_context_params_callback)),
+      is_headless_(is_headless),
+      common_create_context_params_(BuildCreateContextParamsForIsolatedRunners(
+          get_context_params_callback_.Run())),
+      service_directory_(CreateServiceDirectory()) {}
 
 CastRunner::CastRunner(OnDestructionCallback on_destruction_callback,
                        fuchsia::web::ContextPtr context,
                        bool is_headless)
-    : WebContentRunner(std::move(context), is_headless),
+    : WebContentRunner(std::move(context)),
+      is_headless_(is_headless),
       on_destruction_callback_(std::move(on_destruction_callback)) {}
 
 CastRunner::~CastRunner() = default;
@@ -147,50 +158,62 @@
   // The application configuration is obtained asynchronously via the
   // per-component ApplicationConfigManager. The pointer to that service must be
   // kept live until the request completes or CastRunner is deleted.
-  auto pending_component =
+  auto pending_component_params =
       std::make_unique<CastComponent::CastComponentParams>();
-  pending_component->startup_context =
+  pending_component_params->startup_context =
       std::make_unique<base::fuchsia::StartupContext>(std::move(startup_info));
-  pending_component->agent_manager = std::make_unique<cr_fuchsia::AgentManager>(
-      pending_component->startup_context->component_context()->svc().get());
-  pending_component->controller_request = std::move(controller_request);
+  pending_component_params->agent_manager =
+      std::make_unique<cr_fuchsia::AgentManager>(
+          pending_component_params->startup_context->component_context()
+              ->svc()
+              .get());
+  pending_component_params->controller_request = std::move(controller_request);
 
   // Request the configuration for this application from the app_config_manager.
   // This will return the configuration for the application, as well as the
   // agent that should handle this application.
-  pending_component->startup_context->svc()->Connect(
-      pending_component->app_config_manager.NewRequest());
-  pending_component->app_config_manager.set_error_handler(
-      [this, pending_component = pending_component.get()](zx_status_t status) {
+  pending_component_params->startup_context->svc()->Connect(
+      pending_component_params->app_config_manager.NewRequest());
+  pending_component_params->app_config_manager.set_error_handler(
+      [this, pending_component_params =
+                 pending_component_params.get()](zx_status_t status) {
         ZX_LOG(ERROR, status) << "ApplicationConfigManager disconnected.";
-        CancelComponentLaunch(pending_component);
+        CancelComponentLaunch(pending_component_params);
       });
   const std::string cast_app_id(cast_url.GetContent());
-  pending_component->app_config_manager->GetConfig(
-      cast_app_id, [this, pending_component = pending_component.get()](
-                       chromium::cast::ApplicationConfig app_config) {
-        GetConfigCallback(pending_component, std::move(app_config));
+  pending_component_params->app_config_manager->GetConfig(
+      cast_app_id,
+      [this, pending_component_params = pending_component_params.get()](
+          chromium::cast::ApplicationConfig app_config) {
+        OnApplicationConfigReceived(pending_component_params,
+                                    std::move(app_config));
       });
 
-  pending_component->application_context =
-      pending_component->agent_manager
+  pending_component_params->application_context =
+      pending_component_params->agent_manager
           ->ConnectToAgentService<chromium::cast::ApplicationContext>(
               CastRunner::kAgentComponentUrl);
-  pending_component->application_context.set_error_handler(
-      [this, pending_component = pending_component.get()](zx_status_t status) {
+  pending_component_params->application_context.set_error_handler(
+      [this, pending_component_params =
+                 pending_component_params.get()](zx_status_t status) {
         ZX_LOG(ERROR, status) << "ApplicationContext disconnected.";
-        if (!pending_component->media_session_id) {
-          pending_component->media_session_id = 0;
-          MaybeStartComponent(pending_component);
+        if (!pending_component_params->media_session_id) {
+          pending_component_params->media_session_id = 0;
+          MaybeStartComponent(pending_component_params);
         }
       });
-  pending_component->application_context->GetMediaSessionId(
-      [this, pending_component = pending_component.get()](uint64_t session_id) {
-        pending_component->media_session_id = session_id;
-        MaybeStartComponent(pending_component);
+  pending_component_params->application_context->GetMediaSessionId(
+      [this, pending_component_params =
+                 pending_component_params.get()](uint64_t session_id) {
+        pending_component_params->media_session_id = session_id;
+        MaybeStartComponent(pending_component_params);
       });
 
-  pending_components_.emplace(std::move(pending_component));
+  pending_components_.emplace(std::move(pending_component_params));
+}
+
+size_t CastRunner::GetChildCastRunnerCountForTest() {
+  return isolated_runners_.size();
 }
 
 void CastRunner::DestroyComponent(WebComponent* component) {
@@ -205,10 +228,10 @@
   }
 }
 
-void CastRunner::GetConfigCallback(
-    CastComponent::CastComponentParams* pending_component,
+void CastRunner::OnApplicationConfigReceived(
+    CastComponent::CastComponentParams* pending_component_params,
     chromium::cast::ApplicationConfig app_config) {
-  auto it = pending_components_.find(pending_component);
+  auto it = pending_components_.find(pending_component_params);
   DCHECK(it != pending_components_.end());
 
   if (app_config.IsEmpty()) {
@@ -229,60 +252,65 @@
     return;
   }
 
-  pending_component->app_config = std::move(app_config);
+  pending_component_params->app_config = std::move(app_config);
 
   // Request binding details from the Agent.
   fidl::InterfaceHandle<chromium::cast::ApiBindings> api_bindings_client;
-  pending_component->agent_manager->ConnectToAgentService(
-      pending_component->app_config.agent_url(),
+  pending_component_params->agent_manager->ConnectToAgentService(
+      pending_component_params->app_config.agent_url(),
       api_bindings_client.NewRequest());
-  pending_component->api_bindings_client = std::make_unique<ApiBindingsClient>(
-      std::move(api_bindings_client),
-      base::BindOnce(&CastRunner::MaybeStartComponent, base::Unretained(this),
-                     base::Unretained(pending_component)),
-      base::BindOnce(&CastRunner::CancelComponentLaunch, base::Unretained(this),
-                     base::Unretained(pending_component)));
+  pending_component_params->api_bindings_client =
+      std::make_unique<ApiBindingsClient>(
+          std::move(api_bindings_client),
+          base::BindOnce(&CastRunner::MaybeStartComponent,
+                         base::Unretained(this),
+                         base::Unretained(pending_component_params)),
+          base::BindOnce(&CastRunner::CancelComponentLaunch,
+                         base::Unretained(this),
+                         base::Unretained(pending_component_params)));
 
   // Request UrlRequestRewriteRulesProvider from the Agent.
-  pending_component->agent_manager->ConnectToAgentService(
-      pending_component->app_config.agent_url(),
-      pending_component->rewrite_rules_provider.NewRequest());
-  pending_component->rewrite_rules_provider.set_error_handler(
-      [this, pending_component = pending_component](zx_status_t status) {
+  pending_component_params->agent_manager->ConnectToAgentService(
+      pending_component_params->app_config.agent_url(),
+      pending_component_params->rewrite_rules_provider.NewRequest());
+  pending_component_params->rewrite_rules_provider.set_error_handler(
+      [this, pending_component_params =
+                 pending_component_params](zx_status_t status) {
         if (status != ZX_ERR_PEER_CLOSED) {
           ZX_LOG(ERROR, status)
               << "UrlRequestRewriteRulesProvider disconnected.";
-          CancelComponentLaunch(pending_component);
+          CancelComponentLaunch(pending_component_params);
           return;
         }
         ZX_LOG(WARNING, status)
             << "UrlRequestRewriteRulesProvider unsupported.";
-        pending_component->rewrite_rules =
+        pending_component_params->rewrite_rules =
             std::vector<fuchsia::web::UrlRequestRewriteRule>();
-        MaybeStartComponent(pending_component);
+        MaybeStartComponent(pending_component_params);
       });
-  pending_component->rewrite_rules_provider->GetUrlRequestRewriteRules(
-      [this, pending_component = pending_component](
+  pending_component_params->rewrite_rules_provider->GetUrlRequestRewriteRules(
+      [this, pending_component_params = pending_component_params](
           std::vector<fuchsia::web::UrlRequestRewriteRule> rewrite_rules) {
-        pending_component->rewrite_rules =
+        pending_component_params->rewrite_rules =
             base::Optional<std::vector<fuchsia::web::UrlRequestRewriteRule>>(
                 std::move(rewrite_rules));
-        MaybeStartComponent(pending_component);
+        MaybeStartComponent(pending_component_params);
       });
 }
 
-void CastRunner::InitializeServiceDirectory() {
-  service_directory_ =
+std::unique_ptr<base::fuchsia::FilteredServiceDirectory>
+CastRunner::CreateServiceDirectory() {
+  auto service_directory =
       std::make_unique<base::fuchsia::FilteredServiceDirectory>(
           base::fuchsia::ComponentContextForCurrentProcess()->svc().get());
 
   for (auto* name : kServices) {
-    service_directory_->AddService(name);
+    service_directory->AddService(name);
   }
 
   // Handle fuchsia.media.Audio requests so we can redirect to the agent if
   // necessary.
-  service_directory_->outgoing_directory()->AddPublicService(
+  service_directory->outgoing_directory()->AddPublicService(
       std::make_unique<vfs::Service>([this](zx::channel channel,
                                             async_dispatcher_t* dispatcher) {
         this->ConnectAudioProtocol(
@@ -290,9 +318,7 @@
       }),
       fuchsia::media::Audio::Name_);
 
-  fidl::InterfaceHandle<fuchsia::io::Directory> client_handle;
-  service_directory_->ConnectClient(client_handle.NewRequest());
-  create_params_.set_service_directory(std::move(client_handle));
+  return service_directory;
 }
 
 void CastRunner::MaybeStartComponent(
@@ -319,16 +345,16 @@
 }
 
 void CastRunner::CancelComponentLaunch(
-    CastComponent::CastComponentParams* params) {
-  size_t count = pending_components_.erase(params);
+    CastComponent::CastComponentParams* pending_component_params) {
+  size_t count = pending_components_.erase(pending_component_params);
   DCHECK_EQ(count, 1u);
 }
 
 void CastRunner::CreateAndRegisterCastComponent(
-    CastComponent::CastComponentParams params) {
-  GURL app_url = GURL(params.app_config.web_url());
+    CastComponent::CastComponentParams component_params) {
+  GURL app_url = GURL(component_params.app_config.web_url());
   auto cast_component =
-      std::make_unique<CastComponent>(this, std::move(params));
+      std::make_unique<CastComponent>(this, std::move(component_params));
   cast_component->StartComponent();
   cast_component->LoadUrl(std::move(app_url),
                           std::vector<fuchsia::net::http::Header>());
@@ -343,7 +369,7 @@
 }
 
 CastRunner* CastRunner::CreateChildRunnerForIsolatedComponent(
-    CastComponent::CastComponentParams* params) {
+    CastComponent::CastComponentParams* component_params) {
   // Construct the CreateContextParams in order to create a new Context.
   // Some common parameters must be inherited from
   // |common_create_context_params_|.
@@ -362,7 +388,7 @@
   DCHECK(isolated_context_params.service_directory());
 
   isolated_context_params.set_content_directories(
-      std::move(*params->app_config
+      std::move(*component_params->app_config
                      .mutable_content_directories_for_isolated_application()));
 
   std::unique_ptr<CastRunner> cast_runner(new CastRunner(
@@ -389,10 +415,6 @@
   isolated_runners_.erase(runner_iterator);
 }
 
-size_t CastRunner::GetChildCastRunnerCountForTest() {
-  return isolated_runners_.size();
-}
-
 void CastRunner::ConnectAudioProtocol(
     fidl::InterfaceRequest<fuchsia::media::Audio> request) {
   // If we have a component that allows AudioCapturer access then redirect the
@@ -407,4 +429,15 @@
   // Otherwise use the default fuchsia.media.Audio implementation.
   base::fuchsia::ComponentContextForCurrentProcess()->svc()->Connect(
       std::move(request));
-}
\ No newline at end of file
+}
+
+fuchsia::web::CreateContextParams CastRunner::GetMainContextParams() {
+  fuchsia::web::CreateContextParams create_context_params =
+      get_context_params_callback_.Run();
+
+  // Override with the custom service directory.
+  service_directory_->ConnectClient(
+      create_context_params.mutable_service_directory()->NewRequest());
+
+  return create_context_params;
+}
diff --git a/fuchsia/runners/cast/cast_runner.h b/fuchsia/runners/cast/cast_runner.h
index 1b908157..34e244c9 100644
--- a/fuchsia/runners/cast/cast_runner.h
+++ b/fuchsia/runners/cast/cast_runner.h
@@ -29,16 +29,18 @@
 // sys::Runner which instantiates Cast activities specified via cast/casts URIs.
 class CastRunner : public WebContentRunner {
  public:
-  using OnDestructionCallback = base::OnceCallback<void(CastRunner*)>;
-
+  // Creates a Runner for Cast components and publishes it into the specified
+  // OutgoingDirectory.
+  // |get_context_params_callback|: Returns the context parameters to use.
+  // |is_headless|: True if |get_context_params_callback| sets the HEADLESS
+  //     feature flag.
   // |outgoing_directory|: The directory that this CastRunner will publish
   //     itself to.
-  // |context_feature_flags|: The feature flags to use when creating the
-  //     runner's Context.
-  CastRunner(fuchsia::web::CreateContextParams create_context_params,
+  CastRunner(GetContextParamsCallback get_context_params_callback,
+             bool is_headless,
              sys::OutgoingDirectory* outgoing_directory);
-
   ~CastRunner() override;
+
   CastRunner(const CastRunner&) = delete;
   CastRunner& operator=(const CastRunner&) = delete;
 
@@ -54,10 +56,15 @@
   // Used to connect to the CastAgent to access Cast-specific services.
   static const char kAgentComponentUrl[];
 
+  // Returns true if this Runner is configured not to use Scenic.
+  bool is_headless() const { return is_headless_; }
+
   // Returns the number of active CastRunner instances.
   size_t GetChildCastRunnerCountForTest();
 
  private:
+  using OnDestructionCallback = base::OnceCallback<void(CastRunner*)>;
+
   // Constructor used for creating CastRunners that run apps in dedicated
   // Contexts. Child CastRunners may only spawn one Component and will be
   // destroyed by their parents when their singleton Components are destroyed.
@@ -66,35 +73,43 @@
              fuchsia::web::ContextPtr context,
              bool is_headless);
 
-  // Initializes the service directory that's passed to the web context. Must be
-  // called during initialization, before the context is created.
-  void InitializeServiceDirectory();
+  // Creates and returns the service directory that is passed to the main web
+  // context.
+  std::unique_ptr<base::fuchsia::FilteredServiceDirectory>
+  CreateServiceDirectory();
 
   // Starts a component once all configuration data is available.
   void MaybeStartComponent(
       CastComponent::CastComponentParams* pending_component_params);
 
   // Cancels the launch of a component.
-  void CancelComponentLaunch(CastComponent::CastComponentParams* params);
+  void CancelComponentLaunch(
+      CastComponent::CastComponentParams* pending_component_params);
 
   void CreateAndRegisterCastComponent(
-      CastComponent::CastComponentParams params);
-  void GetConfigCallback(CastComponent::CastComponentParams* pending_component,
-                         chromium::cast::ApplicationConfig app_config);
-  void GetBindingsCallback(
-      CastComponent::CastComponentParams* pending_component,
-      std::vector<chromium::cast::ApiBinding> bindings);
+      CastComponent::CastComponentParams component_params);
+  void OnApplicationConfigReceived(
+      CastComponent::CastComponentParams* pending_component_params,
+      chromium::cast::ApplicationConfig app_config);
   void OnChildRunnerDestroyed(CastRunner* cast_runner);
 
   // Creates a CastRunner configured to serve data from content directories in
   // |params|. Returns nullptr if an error occurred during CastRunner creation.
   CastRunner* CreateChildRunnerForIsolatedComponent(
-      CastComponent::CastComponentParams* params);
+      CastComponent::CastComponentParams* component_params);
 
   // Handler for fuchsia.media.Audio requests in |service_directory_|.
   void ConnectAudioProtocol(
       fidl::InterfaceRequest<fuchsia::media::Audio> request);
 
+  // Returns the parameters with which the main context should be created.
+  fuchsia::web::CreateContextParams GetMainContextParams();
+
+  const WebContentRunner::GetContextParamsCallback get_context_params_callback_;
+
+  // True if this Runner uses Context(s) with the HEADLESS feature set.
+  const bool is_headless_;
+
   // Holds StartComponent() requests while the ApplicationConfig is being
   // fetched from the ApplicationConfigManager.
   base::flat_set<std::unique_ptr<CastComponent::CastComponentParams>,
@@ -112,7 +127,10 @@
   base::flat_set<std::unique_ptr<CastRunner>, base::UniquePtrComparator>
       isolated_runners_;
 
-  std::unique_ptr<base::fuchsia::FilteredServiceDirectory> service_directory_;
+  // ServiceDirectory passed to the main Context, to allow Audio capturer
+  // service requests to be routed to the relevant Agent.
+  const std::unique_ptr<base::fuchsia::FilteredServiceDirectory>
+      service_directory_;
 
   // Last component that was created with permission to access MICROPHONE.
   CastComponent* audio_capturer_component_ = nullptr;
diff --git a/fuchsia/runners/cast/cast_runner_integration_test.cc b/fuchsia/runners/cast/cast_runner_integration_test.cc
index 47b5d4e..69b1dda 100644
--- a/fuchsia/runners/cast/cast_runner_integration_test.cc
+++ b/fuchsia/runners/cast/cast_runner_integration_test.cc
@@ -222,16 +222,25 @@
     EnsureFuchsiaDirSchemeInitialized();
 
     // Create the CastRunner, published into |outgoing_directory_|.
-    fuchsia::web::CreateContextParams create_context_params;
-    create_context_params.set_features(feature_flags);
-    create_context_params.set_service_directory(base::fuchsia::OpenDirectory(
-        base::FilePath(base::fuchsia::kServiceDirectoryPath)));
-    CHECK(create_context_params.service_directory());
+    WebContentRunner::GetContextParamsCallback get_context_params =
+        base::BindLambdaForTesting([feature_flags]() {
+          fuchsia::web::CreateContextParams create_context_params;
+          create_context_params.set_features(feature_flags);
+          create_context_params.set_service_directory(
+              base::fuchsia::OpenDirectory(
+                  base::FilePath(base::fuchsia::kServiceDirectoryPath)));
+          CHECK(create_context_params.service_directory());
 
-    const uint16_t kRemoteDebuggingAnyPort = 0;
-    create_context_params.set_remote_debugging_port(kRemoteDebuggingAnyPort);
+          const uint16_t kRemoteDebuggingAnyPort = 0;
+          create_context_params.set_remote_debugging_port(
+              kRemoteDebuggingAnyPort);
+          return create_context_params;
+        });
     cast_runner_ = std::make_unique<CastRunner>(
-        std::move(create_context_params), &outgoing_directory_);
+        std::move(get_context_params),
+        (feature_flags & fuchsia::web::ContextFeatureFlags::HEADLESS) ==
+            fuchsia::web::ContextFeatureFlags::HEADLESS,
+        &outgoing_directory_);
 
     cast_runner_->SetContextProviderForTest(cr_fuchsia::ConnectContextProvider(
         context_provider_controller_.NewRequest()));
@@ -257,7 +266,7 @@
       base::StringPiece component_url) {
     auto component_state = std::make_unique<FakeComponentState>(
         component_url, &app_config_manager_, &api_bindings_,
-        &url_request_rewrite_rules_provider_);
+        url_request_rewrite_rules_provider_.get());
     component_state_ = component_state.get();
 
     if (init_component_state_callback_)
@@ -291,6 +300,8 @@
   }
 
   void CreateComponentContext(const base::StringPiece& component_url) {
+    url_request_rewrite_rules_provider_ =
+        std::make_unique<FakeUrlRequestRewriteRulesProvider>();
     component_context_ = std::make_unique<cr_fuchsia::FakeComponentContext>(
         base::BindRepeating(&CastRunnerIntegrationTest::OnComponentConnect,
                             base::Unretained(this)),
@@ -336,7 +347,7 @@
   }
 
   void WaitComponentCreated() {
-    EXPECT_FALSE(cast_component_);
+    ASSERT_FALSE(cast_component_);
 
     base::RunLoop run_loop;
     cr_fuchsia::ResultReceiver<WebComponent*> component_receiver(
@@ -359,13 +370,39 @@
     listener.RunUntilUrlAndTitleEquals(url, title);
   }
 
+  void WaitForComponentDestroyed() {
+    ASSERT_TRUE(cast_component_);
+    ASSERT_TRUE(component_state_);
+
+    base::RunLoop state_loop;
+    component_state_->set_on_delete(state_loop.QuitClosure());
+
+    if (component_controller_) {
+      base::RunLoop controller_loop;
+      component_controller_.set_error_handler(
+          [&controller_loop](zx_status_t status) {
+            EXPECT_EQ(status, ZX_ERR_PEER_CLOSED);
+            controller_loop.Quit();
+          });
+      controller_loop.Run();
+    }
+
+    state_loop.Run();
+
+    component_context_ = nullptr;
+    component_services_client_ = nullptr;
+    component_state_ = nullptr;
+    cast_component_ = nullptr;
+  }
+
   base::test::SingleThreadTaskEnvironment task_environment_{
       base::test::SingleThreadTaskEnvironment::MainThreadType::IO};
   net::EmbeddedTestServer test_server_;
 
   FakeApplicationConfigManager app_config_manager_;
   TestApiBindings api_bindings_;
-  FakeUrlRequestRewriteRulesProvider url_request_rewrite_rules_provider_;
+  std::unique_ptr<FakeUrlRequestRewriteRulesProvider>
+      url_request_rewrite_rules_provider_;
 
   // Incoming service directory, ComponentContext and per-component state.
   sys::OutgoingDirectory component_services_;
@@ -414,10 +451,41 @@
 
   // Verify that the component is torn down when |component_controller| is
   // unbound.
-  base::RunLoop run_loop;
-  component_state_->set_on_delete(run_loop.QuitClosure());
   component_controller_.Unbind();
-  run_loop.Run();
+  WaitForComponentDestroyed();
+}
+
+// Verify that the Runner can continue to be used even after its Context has
+// crashed. Regression test for https://crbug.com/1066826).
+// TODO(https://crbug.com/1066833): Make this a WebRunner test.
+TEST_F(CastRunnerIntegrationTest, CanRecreateContext) {
+  // Execute two iterations of launching the component and verifying that it
+  // reaches the expected URL.
+  for (int i = 0; i < 2; ++i) {
+    const GURL app_url = test_server_.GetURL(kBlankAppUrl);
+    app_config_manager_.AddApp(kTestAppId, app_url);
+
+    CreateComponentContextAndStartComponent();
+
+    fuchsia::web::NavigationControllerPtr nav_controller;
+    cast_component_->frame()->GetNavigationController(
+        nav_controller.NewRequest());
+
+    base::RunLoop run_loop;
+    cr_fuchsia::ResultReceiver<fuchsia::web::NavigationState> nav_entry(
+        run_loop.QuitClosure());
+    nav_controller->GetVisibleEntry(
+        cr_fuchsia::CallbackToFitFunction(nav_entry.GetReceiveCallback()));
+    run_loop.Run();
+
+    ASSERT_TRUE(nav_entry->has_url());
+    EXPECT_EQ(nav_entry->url(), app_url.spec());
+
+    // Fake teardown of the Context, forcing the next StartComponent to create
+    // a new one.
+    cast_runner_->DisconnectContextForTest();
+    WaitForComponentDestroyed();
+  }
 }
 
 TEST_F(CastRunnerIntegrationTest, ApiBindings) {
@@ -562,10 +630,8 @@
 
   // Verify that the component is torn down when |component_controller| is
   // unbound.
-  base::RunLoop run_loop;
-  component_state_->set_on_delete(run_loop.QuitClosure());
   component_controller_.Unbind();
-  run_loop.Run();
+  WaitForComponentDestroyed();
 
   EXPECT_EQ(cast_runner_->GetChildCastRunnerCountForTest(), 0u);
 }
@@ -787,10 +853,8 @@
 
   // Verify that the component is torn down when |component_controller| is
   // unbound.
-  base::RunLoop run_loop;
-  component_state_->set_on_delete(run_loop.QuitClosure());
   component_controller_.Unbind();
-  run_loop.Run();
+  WaitForComponentDestroyed();
 
   EXPECT_EQ(cast_runner_->GetChildCastRunnerCountForTest(), 0u);
 }
diff --git a/fuchsia/runners/cast/fake_application_config_manager.cc b/fuchsia/runners/cast/fake_application_config_manager.cc
index 33ded8a..ee39b533 100644
--- a/fuchsia/runners/cast/fake_application_config_manager.cc
+++ b/fuchsia/runners/cast/fake_application_config_manager.cc
@@ -54,6 +54,6 @@
     return;
   }
 
-  callback(std::move(std::move(id_to_config_[id])));
+  callback(std::move(id_to_config_[id]));
   id_to_config_.erase(id);
 }
diff --git a/fuchsia/runners/cast/main.cc b/fuchsia/runners/cast/main.cc
index f8cdfafd..a60f453 100644
--- a/fuchsia/runners/cast/main.cc
+++ b/fuchsia/runners/cast/main.cc
@@ -8,6 +8,7 @@
 #include "base/fuchsia/default_context.h"
 #include "base/fuchsia/file_utils.h"
 #include "base/message_loop/message_pump_type.h"
+#include "base/no_destructor.h"
 #include "base/optional.h"
 #include "base/run_loop.h"
 #include "base/task/single_thread_task_executor.h"
@@ -33,19 +34,7 @@
   return false;
 }
 
-}  // namespace
-
-int main(int argc, char** argv) {
-  base::SingleThreadTaskExecutor io_task_executor(base::MessagePumpType::IO);
-  base::RunLoop run_loop;
-
-  base::CommandLine::Init(argc, argv);
-  CHECK(cr_fuchsia::InitLoggingFromCommandLine(
-      *base::CommandLine::ForCurrentProcess()))
-      << "Failed to initialize logging.";
-
-  cr_fuchsia::RegisterFuchsiaDirScheme();
-
+fuchsia::web::CreateContextParams CreateMainContextParams() {
   fuchsia::web::ContextFeatureFlags features =
       fuchsia::web::ContextFeatureFlags::NETWORK |
       fuchsia::web::ContextFeatureFlags::AUDIO |
@@ -82,8 +71,27 @@
   create_context_params.set_unsafely_treat_insecure_origins_as_secure(
       {"allow-running-insecure-content"});
 
+  return create_context_params;
+}
+
+}  // namespace
+
+int main(int argc, char** argv) {
+  base::SingleThreadTaskExecutor io_task_executor(base::MessagePumpType::IO);
+  base::RunLoop run_loop;
+
+  base::CommandLine::Init(argc, argv);
+  CHECK(cr_fuchsia::InitLoggingFromCommandLine(
+      *base::CommandLine::ForCurrentProcess()))
+      << "Failed to initialize logging.";
+
+  cr_fuchsia::RegisterFuchsiaDirScheme();
+
+  WebContentRunner::GetContextParamsCallback get_context_params_callback =
+      base::BindRepeating(&CreateMainContextParams);
+
   CastRunner runner(
-      std::move(create_context_params),
+      std::move(get_context_params_callback), IsHeadless(),
       base::fuchsia::ComponentContextForCurrentProcess()->outgoing().get());
 
   base::fuchsia::ComponentContextForCurrentProcess()
diff --git a/fuchsia/runners/common/web_content_runner.cc b/fuchsia/runners/common/web_content_runner.cc
index 617743f..357ddc7 100644
--- a/fuchsia/runners/common/web_content_runner.cc
+++ b/fuchsia/runners/common/web_content_runner.cc
@@ -23,25 +23,21 @@
 #include "url/gurl.h"
 
 WebContentRunner::WebContentRunner(
-    fuchsia::web::CreateContextParams create_params,
+    GetContextParamsCallback get_context_params_callback,
     sys::OutgoingDirectory* outgoing_directory)
-    : create_params_(std::move(create_params)),
-      is_headless_((create_params_.features() &
-                    fuchsia::web::ContextFeatureFlags::HEADLESS) ==
-                   fuchsia::web::ContextFeatureFlags::HEADLESS) {
+    : get_context_params_callback_(std::move(get_context_params_callback)) {
   service_binding_.emplace(outgoing_directory, this);
 }
 
-WebContentRunner::WebContentRunner(fuchsia::web::ContextPtr context,
-                                   bool is_headless)
-    : context_(std::move(context)), is_headless_(is_headless) {}
+WebContentRunner::WebContentRunner(fuchsia::web::ContextPtr context)
+    : context_(std::move(context)) {}
 
 WebContentRunner::~WebContentRunner() = default;
 
 fuchsia::web::ContextPtr WebContentRunner::CreateWebContext(
-    fuchsia::web::CreateContextParams create_params) {
+    fuchsia::web::CreateContextParams context_params) {
   fuchsia::web::ContextPtr web_context;
-  GetContextProvider()->Create(std::move(create_params),
+  GetContextProvider()->Create(std::move(context_params),
                                web_context.NewRequest());
   web_context.set_error_handler([](zx_status_t status) {
     // If the browser instance died, then exit everything and do not attempt to
@@ -54,8 +50,7 @@
 
 fuchsia::web::Context* WebContentRunner::GetContext() {
   if (!context_)
-    context_ = CreateWebContext(std::move(create_params_));
-
+    context_ = CreateWebContext(get_context_params_callback_.Run());
   return context_.get();
 }
 
@@ -106,6 +101,10 @@
   context_provider_ = std::move(context_provider);
 }
 
+void WebContentRunner::DisconnectContextForTest() {
+  context_.Unbind();
+}
+
 fuchsia::web::ContextProvider* WebContentRunner::GetContextProvider() {
   if (!context_provider_) {
     context_provider_ = base::fuchsia::ComponentContextForCurrentProcess()
diff --git a/fuchsia/runners/common/web_content_runner.h b/fuchsia/runners/common/web_content_runner.h
index 49fbf2f..1d1d604 100644
--- a/fuchsia/runners/common/web_content_runner.h
+++ b/fuchsia/runners/common/web_content_runner.h
@@ -22,23 +22,29 @@
 // sys::Runner that instantiates components hosting standard web content.
 class WebContentRunner : public fuchsia::sys::Runner {
  public:
-  using CreateContextCallback = base::OnceCallback<fuchsia::web::ContextPtr()>;
+  using GetContextParamsCallback =
+      base::RepeatingCallback<fuchsia::web::CreateContextParams()>;
 
-  // |create_params|: Parameters to use for the Runner's web.Context.
+  // Creates a Runner for web-based components, and publishes it to the
+  // specified OutgoingDirectory.
+  // |get_context_params_callback|: Returns parameters for the Runner's
+  //     web.Context.
   // |outgoing_directory|: The directory that the Runner's services will be
-  //                       published to.
-  WebContentRunner(fuchsia::web::CreateContextParams create_params,
+  //     published to.
+  WebContentRunner(GetContextParamsCallback get_context_params_callback,
                    sys::OutgoingDirectory* outgoing_directory);
 
-  // Alternative constructor for unpublished Runners.
-  explicit WebContentRunner(fuchsia::web::ContextPtr context, bool is_headless);
+  // Creates a Runner which launches components using the specified |context|.
+  // The caller may publish the Runner, or call StartComponent() manually to
+  // create new components with it.
+  explicit WebContentRunner(fuchsia::web::ContextPtr context);
 
   ~WebContentRunner() override;
 
   // TODO(crbug.com/1046615): Make this static when the injected ContextProvider
   // goes away.
   fuchsia::web::ContextPtr CreateWebContext(
-      fuchsia::web::CreateContextParams create_params);
+      fuchsia::web::CreateContextParams context_params);
 
   // Gets a pointer to this runner's Context, creating one if needed.
   fuchsia::web::Context* GetContext();
@@ -47,9 +53,6 @@
   // channel was dropped, and therefore the component should be destroyed.
   virtual void DestroyComponent(WebComponent* component);
 
-  // Set if Cast applications are to be run without graphical rendering.
-  bool is_headless() const { return is_headless_; }
-
   // fuchsia::sys::Runner implementation.
   void StartComponent(fuchsia::sys::Package package,
                       fuchsia::sys::StartupInfo startup_info,
@@ -68,17 +71,20 @@
   void SetContextProviderForTest(
       fuchsia::web::ContextProviderPtr context_provider);
 
+  // Disconnects the Context used by this Runner.
+  void DisconnectContextForTest();
+
  protected:
   base::RepeatingCallback<void(WebComponent*)>
   web_component_created_callback_for_test() const {
     return web_component_created_callback_for_test_;
   }
 
-  fuchsia::web::CreateContextParams create_params_;
-
  private:
   fuchsia::web::ContextProvider* GetContextProvider();
 
+  const GetContextParamsCallback get_context_params_callback_;
+
   // If set, invoked whenever a WebComponent is created.
   base::RepeatingCallback<void(WebComponent*)>
       web_component_created_callback_for_test_;
@@ -87,7 +93,6 @@
   fuchsia::web::ContextPtr context_;
   std::set<std::unique_ptr<WebComponent>, base::UniquePtrComparator>
       components_;
-  const bool is_headless_;
 
   // Publishes this Runner into the service directory specified at construction.
   // This is not set for child runner instances.
diff --git a/fuchsia/runners/web/main.cc b/fuchsia/runners/web/main.cc
index 1996cd8..9ae6248 100644
--- a/fuchsia/runners/web/main.cc
+++ b/fuchsia/runners/web/main.cc
@@ -15,17 +15,9 @@
 #include "fuchsia/runners/buildflags.h"
 #include "fuchsia/runners/common/web_content_runner.h"
 
-int main(int argc, char** argv) {
-  base::SingleThreadTaskExecutor io_task_executor(base::MessagePumpType::IO);
-  base::RunLoop run_loop;
+namespace {
 
-  base::CommandLine::Init(argc, argv);
-  CHECK(cr_fuchsia::InitLoggingFromCommandLine(
-      *base::CommandLine::ForCurrentProcess()))
-      << "Failed to initialize logging.";
-
-  cr_fuchsia::RegisterFuchsiaDirScheme();
-
+fuchsia::web::CreateContextParams GetContextParams() {
   fuchsia::web::CreateContextParams create_context_params;
   create_context_params.set_features(
       fuchsia::web::ContextFeatureFlags::NETWORK |
@@ -46,9 +38,27 @@
   create_context_params.set_remote_debugging_port(
       BUILDFLAG(WEB_RUNNER_REMOTE_DEBUGGING_PORT));
 #endif
+  return create_context_params;
+}
+
+}  // namespace
+
+int main(int argc, char** argv) {
+  base::SingleThreadTaskExecutor io_task_executor(base::MessagePumpType::IO);
+  base::RunLoop run_loop;
+
+  base::CommandLine::Init(argc, argv);
+  CHECK(cr_fuchsia::InitLoggingFromCommandLine(
+      *base::CommandLine::ForCurrentProcess()))
+      << "Failed to initialize logging.";
+
+  cr_fuchsia::RegisterFuchsiaDirScheme();
+
+  WebContentRunner::GetContextParamsCallback get_context_params_callback =
+      base::BindRepeating(&GetContextParams);
 
   WebContentRunner runner(
-      std::move(create_context_params),
+      std::move(get_context_params_callback),
       base::fuchsia::ComponentContextForCurrentProcess()->outgoing().get());
 
   base::fuchsia::ComponentContextForCurrentProcess()
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_impl.cc b/ios/chrome/browser/browser_state/chrome_browser_state_impl.cc
index 91de3d5..6446ac76 100644
--- a/ios/chrome/browser/browser_state/chrome_browser_state_impl.cc
+++ b/ios/chrome/browser/browser_state/chrome_browser_state_impl.cc
@@ -200,11 +200,10 @@
 }
 
 PrefService* ChromeBrowserStateImpl::GetOffTheRecordPrefs() {
-  DCHECK(prefs_);
-  if (!otr_prefs_) {
-    otr_prefs_ = CreateIncognitoBrowserStatePrefs(prefs_.get());
+  if (otr_state_) {
+    return otr_state_->GetPrefs();
   }
-  return otr_prefs_.get();
+  return nullptr;
 }
 
 ChromeBrowserStateIOData* ChromeBrowserStateImpl::GetIOData() {
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_impl.h b/ios/chrome/browser/browser_state/chrome_browser_state_impl.h
index dc0eb70..41a902a 100644
--- a/ios/chrome/browser/browser_state/chrome_browser_state_impl.h
+++ b/ios/chrome/browser/browser_state/chrome_browser_state_impl.h
@@ -85,7 +85,6 @@
   // others store pointers to |prefs_| and shall be destructed first.
   scoped_refptr<user_prefs::PrefRegistrySyncable> pref_registry_;
   std::unique_ptr<sync_preferences::PrefServiceSyncable> prefs_;
-  std::unique_ptr<sync_preferences::PrefServiceSyncable> otr_prefs_;
   std::unique_ptr<ChromeBrowserStateImplIOData::Handle> io_data_;
 
   std::unique_ptr<PrefProxyConfigTracker> pref_proxy_config_tracker_;
diff --git a/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.cc b/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.cc
index b036506..203c58c 100644
--- a/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.cc
+++ b/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.cc
@@ -14,6 +14,7 @@
 #include "components/user_prefs/user_prefs.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/net/ios_chrome_url_request_context_getter.h"
+#include "ios/chrome/browser/prefs/ios_chrome_pref_service_factory.h"
 #include "ios/web/public/thread/web_task_traits.h"
 #include "ios/web/public/thread/web_thread.h"
 
@@ -24,8 +25,9 @@
     : ChromeBrowserState(std::move(io_task_runner)),
       otr_state_path_(otr_path),
       original_chrome_browser_state_(original_chrome_browser_state),
-      prefs_(static_cast<sync_preferences::PrefServiceSyncable*>(
-          original_chrome_browser_state->GetOffTheRecordPrefs())) {
+      prefs_(CreateIncognitoBrowserStatePrefs(
+          static_cast<sync_preferences::PrefServiceSyncable*>(
+              original_chrome_browser_state->GetPrefs()))) {
   user_prefs::UserPrefs::Set(this, GetPrefs());
   io_data_.reset(new OffTheRecordChromeBrowserStateIOData::Handle(this));
   BrowserStateDependencyManager::GetInstance()->CreateBrowserStateServices(
@@ -70,7 +72,7 @@
 }
 
 PrefService* OffTheRecordChromeBrowserStateImpl::GetPrefs() {
-  return prefs_;
+  return prefs_.get();
 }
 
 PrefService* OffTheRecordChromeBrowserStateImpl::GetOffTheRecordPrefs() {
diff --git a/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.h b/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.h
index 51923e7..7a04901 100644
--- a/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.h
+++ b/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.h
@@ -52,8 +52,7 @@
   base::FilePath otr_state_path_;
   ChromeBrowserState* original_chrome_browser_state_;  // weak
 
-  // Weak pointer owned by |original_chrome_browser_state_|.
-  sync_preferences::PrefServiceSyncable* prefs_;
+  std::unique_ptr<sync_preferences::PrefServiceSyncable> prefs_;
 
   std::unique_ptr<OffTheRecordChromeBrowserStateIOData::Handle> io_data_;
   std::unique_ptr<PrefProxyConfigTracker> pref_proxy_config_tracker_;
diff --git a/ios/chrome/credential_provider_extension/ui/BUILD.gn b/ios/chrome/credential_provider_extension/ui/BUILD.gn
index d3f0a1f..90dff22 100644
--- a/ios/chrome/credential_provider_extension/ui/BUILD.gn
+++ b/ios/chrome/credential_provider_extension/ui/BUILD.gn
@@ -6,6 +6,9 @@
   sources = [
     "consent_view_controller.h",
     "consent_view_controller.mm",
+    "credential_details_consumer.h",
+    "credential_details_view_controller.h",
+    "credential_details_view_controller.mm",
     "credential_list_consumer.h",
     "credential_list_coordinator.h",
     "credential_list_coordinator.mm",
diff --git a/ios/chrome/credential_provider_extension/ui/credential_details_consumer.h b/ios/chrome/credential_provider_extension/ui/credential_details_consumer.h
new file mode 100644
index 0000000..31d0670
--- /dev/null
+++ b/ios/chrome/credential_provider_extension/ui/credential_details_consumer.h
@@ -0,0 +1,35 @@
+// Copyright 2020 The Chromium 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_CREDENTIAL_PROVIDER_EXTENSION_UI_CREDENTIAL_DETAILS_CONSUMER_H_
+#define IOS_CHROME_CREDENTIAL_PROVIDER_EXTENSION_UI_CREDENTIAL_DETAILS_CONSUMER_H_
+
+#include "ios/chrome/common/credential_provider/credential.h"
+
+@class UIButton;
+
+@protocol CredentialDetailsConsumerDelegate <NSObject>
+
+// Called when the user taps the cancel button in the navigation bar.
+- (void)navigationCancelButtonWasPressed:(UIButton*)button;
+
+// Called when the user requests a clear view of the password. The delegate
+// should complete with the clear password or nil in case of failure or
+// deny by user.
+- (void)unlockPasswordForCredential:(id<Credential>)credential
+                  completionHandler:(void (^)(NSString*))completionHandler;
+
+@end
+
+@protocol CredentialDetailsConsumer <NSObject>
+
+// The delegate for the actions in the consumer.
+@property(nonatomic, weak) id<CredentialDetailsConsumerDelegate> delegate;
+
+// Tells the consumer to show the |credential| details.
+- (void)presentCredential:(id<Credential>)credential;
+
+@end
+
+#endif  // IOS_CHROME_CREDENTIAL_PROVIDER_EXTENSION_UI_CREDENTIAL_DETAILS_CONSUMER_H_
diff --git a/ios/chrome/credential_provider_extension/ui/credential_details_view_controller.h b/ios/chrome/credential_provider_extension/ui/credential_details_view_controller.h
new file mode 100644
index 0000000..307ef47
--- /dev/null
+++ b/ios/chrome/credential_provider_extension/ui/credential_details_view_controller.h
@@ -0,0 +1,18 @@
+// Copyright 2020 The Chromium 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_CREDENTIAL_PROVIDER_EXTENSION_UI_CREDENTIAL_DETAILS_VIEW_CONTROLLER_H_
+#define IOS_CHROME_CREDENTIAL_PROVIDER_EXTENSION_UI_CREDENTIAL_DETAILS_VIEW_CONTROLLER_H_
+
+#import <UIKit/UIKit.h>
+
+#import "ios/chrome/credential_provider_extension/ui/credential_details_consumer.h"
+
+// View controller for credential details. Similar to chrome settings password
+// details (i/c/b/u/s/p/password_details_table_view_controller).
+@interface CredentialDetailsViewController
+    : UITableViewController <CredentialDetailsConsumer>
+@end
+
+#endif  // IOS_CHROME_CREDENTIAL_PROVIDER_EXTENSION_UI_CREDENTIAL_DETAILS_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/credential_provider_extension/ui/credential_details_view_controller.mm b/ios/chrome/credential_provider_extension/ui/credential_details_view_controller.mm
new file mode 100644
index 0000000..192fc6c
--- /dev/null
+++ b/ios/chrome/credential_provider_extension/ui/credential_details_view_controller.mm
@@ -0,0 +1,50 @@
+// Copyright 2020 The Chromium 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/chrome/credential_provider_extension/ui/credential_details_view_controller.h"
+
+#import "base/mac/foundation_util.h"
+#import "ios/chrome/common/credential_provider/credential.h"
+#import "ios/chrome/common/ui/colors/semantic_color_names.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@interface CredentialDetailsViewController () <UITableViewDataSource>
+
+// Current credential.
+@property(nonatomic, weak) id<Credential> credential;
+
+@end
+
+@implementation CredentialDetailsViewController
+
+@synthesize delegate;
+
+- (void)viewDidLoad {
+  [super viewDidLoad];
+  self.view.backgroundColor = [UIColor colorNamed:kBackgroundColor];
+  self.navigationItem.rightBarButtonItem = [self navigationCancelButton];
+}
+
+#pragma mark - CredentialDetailsConsumer
+
+- (void)presentCredential:(id<Credential>)credential {
+  self.credential = credential;
+  [self.tableView reloadData];
+}
+
+#pragma mark - Private
+
+// Creates a cancel button for the navigation item.
+- (UIBarButtonItem*)navigationCancelButton {
+  UIBarButtonItem* cancelButton = [[UIBarButtonItem alloc]
+      initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
+                           target:self.delegate
+                           action:@selector(navigationCancelButtonWasPressed:)];
+  return cancelButton;
+}
+
+@end
diff --git a/ios/chrome/credential_provider_extension/ui/credential_list_consumer.h b/ios/chrome/credential_provider_extension/ui/credential_list_consumer.h
index 4cc8f831..ca73a9d 100644
--- a/ios/chrome/credential_provider_extension/ui/credential_list_consumer.h
+++ b/ios/chrome/credential_provider_extension/ui/credential_list_consumer.h
@@ -17,6 +17,9 @@
 // Called when the user is filtering results through search.
 - (void)updateResultsWithFilter:(NSString*)filter;
 
+// Called when user wants to see details for the given credential.
+- (void)showDetailsForCredential:(id<Credential>)credential;
+
 @end
 
 @protocol CredentialListConsumer <NSObject>
diff --git a/ios/chrome/credential_provider_extension/ui/credential_list_mediator.mm b/ios/chrome/credential_provider_extension/ui/credential_list_mediator.mm
index e99654a..f51eccff 100644
--- a/ios/chrome/credential_provider_extension/ui/credential_list_mediator.mm
+++ b/ios/chrome/credential_provider_extension/ui/credential_list_mediator.mm
@@ -68,4 +68,8 @@
   // TODO(crbug.com/1045454): Implement this method.
 }
 
+- (void)showDetailsForCredential:(id<Credential>)credential {
+  // TODO(crbug.com/1052143): Implement this method.
+}
+
 @end
diff --git a/ios/chrome/credential_provider_extension/ui/credential_list_view_controller.mm b/ios/chrome/credential_provider_extension/ui/credential_list_view_controller.mm
index 8aefd1e..39f2fd9 100644
--- a/ios/chrome/credential_provider_extension/ui/credential_list_view_controller.mm
+++ b/ios/chrome/credential_provider_extension/ui/credential_list_view_controller.mm
@@ -156,13 +156,8 @@
                                   reuseIdentifier:kCellIdentifier];
     cell.accessoryType = UITableViewCellAccessoryDetailButton;
   }
-  id<Credential> credential;
-  if ([self isSuggestedPasswordSection:indexPath.section]) {
-    credential = self.suggestedPasswords[indexPath.row];
-  } else {
-    credential = self.allPasswords[indexPath.row];
-  }
 
+  id<Credential> credential = [self credentialForIndexPath:indexPath];
   cell.imageView.image = GetFallbackImageWithStringAndColor(credential.user);
   cell.imageView.contentMode = UIViewContentModeScaleAspectFit;
   cell.textLabel.text = credential.user;
@@ -184,6 +179,12 @@
   return view;
 }
 
+- (void)tableView:(UITableView*)tableView
+    accessoryButtonTappedForRowWithIndexPath:(NSIndexPath*)indexPath {
+  id<Credential> credential = [self credentialForIndexPath:indexPath];
+  [self.delegate showDetailsForCredential:credential];
+}
+
 #pragma mark - UISearchResultsUpdating
 
 - (void)updateSearchResultsForSearchController:
@@ -227,4 +228,12 @@
   }
 }
 
+- (id<Credential>)credentialForIndexPath:(NSIndexPath*)indexPath {
+  if ([self isSuggestedPasswordSection:indexPath.section]) {
+    return self.suggestedPasswords[indexPath.row];
+  } else {
+    return self.allPasswords[indexPath.row];
+  }
+}
+
 @end
diff --git a/ios/showcase/credential_provider/sc_credential_list_coordinator.mm b/ios/showcase/credential_provider/sc_credential_list_coordinator.mm
index 6f8fe7f..1c0e8fc 100644
--- a/ios/showcase/credential_provider/sc_credential_list_coordinator.mm
+++ b/ios/showcase/credential_provider/sc_credential_list_coordinator.mm
@@ -7,6 +7,8 @@
 #import <UIKit/UIKit.h>
 
 #import "ios/chrome/common/credential_provider/credential.h"
+#import "ios/chrome/credential_provider_extension/ui/credential_details_consumer.h"
+#import "ios/chrome/credential_provider_extension/ui/credential_details_view_controller.h"
 #import "ios/chrome/credential_provider_extension/ui/credential_list_consumer.h"
 #import "ios/chrome/credential_provider_extension/ui/credential_list_view_controller.h"
 
@@ -56,8 +58,11 @@
 ];
 }
 
-@interface SCCredentialListCoordinator () <CredentialListConsumerDelegate>
+@interface SCCredentialListCoordinator () <CredentialDetailsConsumerDelegate,
+                                           CredentialListConsumerDelegate>
 @property(nonatomic, strong) CredentialListViewController* viewController;
+@property(nonatomic, strong)
+    CredentialDetailsViewController* detailsViewController;
 @end
 
 @implementation SCCredentialListCoordinator
@@ -66,11 +71,15 @@
 
 - (void)start {
   self.viewController = [[CredentialListViewController alloc] init];
-  self.viewController.title = @"Autofill Chrome Password";
+  self.viewController.title = @"CPE Passwords";
   self.viewController.delegate = self;
   [self.baseViewController setHidesBarsOnSwipe:NO];
   [self.baseViewController pushViewController:self.viewController animated:YES];
 
+  self.detailsViewController = [[CredentialDetailsViewController alloc] init];
+  self.detailsViewController.title = @"CPE Password Details";
+  self.detailsViewController.delegate = self;
+
   [self.viewController presentSuggestedPasswords:suggestedPasswords
                                     allPasswords:allPasswords];
 }
@@ -101,4 +110,17 @@
   [self.viewController presentSuggestedPasswords:suggested allPasswords:all];
 }
 
+#pragma mark - CredentialDetailsConsumerDelegate
+
+- (void)unlockPasswordForCredential:(id<Credential>)credential
+                  completionHandler:(void (^)(NSString*))completionHandler {
+  completionHandler(@"DreamOn");
+}
+
+- (void)showDetailsForCredential:(id<Credential>)credential {
+  [self.detailsViewController presentCredential:credential];
+  [self.baseViewController pushViewController:self.detailsViewController
+                                     animated:YES];
+}
+
 @end
diff --git a/ios/web_view/internal/sync/web_view_sync_client.mm b/ios/web_view/internal/sync/web_view_sync_client.mm
index 9f8bce5..70850d0 100644
--- a/ios/web_view/internal/sync/web_view_sync_client.mm
+++ b/ios/web_view/internal/sync/web_view_sync_client.mm
@@ -139,17 +139,8 @@
 syncer::DataTypeController::TypeVector
 WebViewSyncClient::CreateDataTypeControllers(
     syncer::SyncService* sync_service) {
-  // //ios/web_view clients are supposed to record their own consents.
-  syncer::DataTypeController::TypeVector type_vector =
-      component_factory_->CreateCommonDataTypeControllers(GetDisabledTypes(),
-                                                          sync_service);
-  type_vector.erase(std::remove_if(type_vector.begin(), type_vector.end(),
-                                   [](const auto& data_type_controller) {
-                                     return data_type_controller->type() ==
-                                            syncer::USER_CONSENTS;
-                                   }),
-                    type_vector.end());
-  return type_vector;
+  return component_factory_->CreateCommonDataTypeControllers(GetDisabledTypes(),
+                                                             sync_service);
 }
 
 BookmarkUndoService* WebViewSyncClient::GetBookmarkUndoService() {
@@ -183,12 +174,7 @@
 
 base::WeakPtr<syncer::ModelTypeControllerDelegate>
 WebViewSyncClient::GetControllerDelegateForModelType(syncer::ModelType type) {
-  // Even though USER_CONSENTS are disabled, the component factory will create
-  // its controller and ask for a delegate; this client later removes the
-  // controller. No other data type should ask for its delegate.
-  // TODO(crbug.com/873790): Figure out if USER_CONSENTS need to be enabled or
-  // find a better way how to disable it.
-  DCHECK_EQ(type, syncer::USER_CONSENTS);
+  NOTREACHED();
   return base::WeakPtr<syncer::ModelTypeControllerDelegate>();
 }
 
diff --git a/net/base/network_change_notifier_fuchsia_unittest.cc b/net/base/network_change_notifier_fuchsia_unittest.cc
index 0cf07575..cc2ff2b 100644
--- a/net/base/network_change_notifier_fuchsia_unittest.cc
+++ b/net/base/network_change_notifier_fuchsia_unittest.cc
@@ -10,6 +10,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/auto_reset.h"
 #include "base/bind.h"
 #include "base/run_loop.h"
 #include "base/test/task_environment.h"
@@ -24,77 +25,77 @@
 namespace net {
 namespace {
 
-const int kDefaultNic = 1;
-const int kSecondaryNic = kDefaultNic + 1;
+enum : uint32_t { kDefaultInterfaceId = 1, kSecondaryInterfaceId = 2 };
 
-fuchsia::net::IpAddress CreateIPv6Address(std::vector<uint8_t> addr) {
+using IPv4Octets = std::array<uint8_t, 4>;
+using IPv6Octets = std::array<uint8_t, 16>;
+
+constexpr IPv4Octets kIPv4DefaultGatewayNetmask = {0, 0, 0, 0};
+constexpr IPv4Octets kIPv4DefaultGatewayAddress = {192, 168, 0, 1};
+
+constexpr IPv4Octets kDefaultIPv4Address = {192, 168, 0, 2};
+constexpr IPv4Octets kDefaultIPv4Netmask = {255, 255, 0, 0};
+constexpr IPv4Octets kSecondaryIPv4Address = {10, 0, 0, 1};
+constexpr IPv4Octets kSecondaryIPv4Netmask = {255, 0, 0, 0};
+
+constexpr IPv6Octets kDefaultIPv6Address = {0xfe, 0x80, 0x01};
+constexpr IPv6Octets kDefaultIPv6Netmask = {0xfe, 0x80};
+constexpr IPv6Octets kSecondaryIPv6Address = {0xfe, 0x80, 0x02};
+constexpr IPv6Octets kSecondaryIPv6Netmask = {0xfe, 0x80};
+
+fuchsia::net::IpAddress IpAddressFrom(IPv4Octets octets) {
   fuchsia::net::IpAddress output;
-  for (size_t i = 0; i < addr.size(); ++i) {
-    output.ipv6().addr[i] = addr[i];
-  }
+  output.ipv4().addr = octets;
   return output;
 }
 
-fuchsia::net::Subnet CreateSubnet(const std::vector<uint8_t>& addr,
-                                  uint8_t prefix) {
+fuchsia::net::IpAddress IpAddressFrom(IPv6Octets octets) {
+  fuchsia::net::IpAddress output;
+  output.ipv6().addr = octets;
+  return output;
+}
+
+fuchsia::net::Subnet SubnetFrom(IPv6Octets octets, uint8_t prefix) {
   fuchsia::net::Subnet output;
-  output.addr = CreateIPv6Address(addr);
+  output.addr = IpAddressFrom(octets);
   output.prefix_len = prefix;
   return output;
 }
 
-fuchsia::net::IpAddress CreateIPv4Address(uint8_t a0,
-                                          uint8_t a1,
-                                          uint8_t a2,
-                                          uint8_t a3) {
-  fuchsia::net::IpAddress output;
-  output.ipv4().addr[0] = a0;
-  output.ipv4().addr[1] = a1;
-  output.ipv4().addr[2] = a2;
-  output.ipv4().addr[3] = a3;
-  return output;
+fuchsia::netstack::NetInterface DefaultNetInterface() {
+  // For most tests a live interface with an IPv4 address and no |features| set
+  // is sufficient.
+  fuchsia::netstack::NetInterface interface;
+  interface.id = kDefaultInterfaceId;
+  interface.flags = fuchsia::netstack::NetInterfaceFlagUp;
+  interface.features = 0;
+  interface.addr = IpAddressFrom(kDefaultIPv4Address);
+  interface.netmask = IpAddressFrom(kDefaultIPv4Netmask);
+  interface.broadaddr = IpAddressFrom(kDefaultIPv4Address);
+  return interface;
 }
 
-fuchsia::netstack::RouteTableEntry CreateRouteTableEntry(uint32_t nicid,
-                                                         bool is_default) {
-  fuchsia::netstack::RouteTableEntry output;
-  output.nicid = nicid;
-
-  if (is_default) {
-    output.netmask = CreateIPv4Address(0, 0, 0, 0);
-    output.destination = CreateIPv4Address(192, 168, 42, 0);
-    output.gateway = CreateIPv4Address(192, 168, 42, 1);
-  } else {
-    output.netmask = CreateIPv4Address(255, 255, 255, 0);
-    output.destination = CreateIPv4Address(192, 168, 43, 0);
-    output.gateway = CreateIPv4Address(192, 168, 43, 1);
-  }
-
-  return output;
+fuchsia::netstack::NetInterface SecondaryNetInterface() {
+  // For most tests a live interface with an IPv4 address and no |features| set
+  // is sufficient.
+  fuchsia::netstack::NetInterface interface;
+  interface.id = kSecondaryInterfaceId;
+  interface.flags = fuchsia::netstack::NetInterfaceFlagUp;
+  interface.features = 0;
+  interface.addr = IpAddressFrom(kSecondaryIPv4Address);
+  interface.netmask = IpAddressFrom(kSecondaryIPv4Netmask);
+  interface.broadaddr = IpAddressFrom(kSecondaryIPv4Address);
+  return interface;
 }
 
-fuchsia::netstack::NetInterface CreateNetInterface(
-    uint32_t id,
-    uint32_t flags,
-    uint32_t features,
-    fuchsia::net::IpAddress address,
-    fuchsia::net::IpAddress netmask,
-    std::vector<fuchsia::net::Subnet> ipv6) {
-  fuchsia::netstack::NetInterface output;
-  output.name = "foo";
-  output.id = id;
-  output.flags = flags;
-  output.features = features;
-  output.addr = std::move(address);
-  output.netmask = std::move(netmask);
-
-  output.addr.Clone(&output.broadaddr);
-
-  for (auto& x : ipv6) {
-    output.ipv6addrs.push_back(std::move(x));
+std::vector<fuchsia::netstack::NetInterface> CloneNetInterfaces(
+    const std::vector<fuchsia::netstack::NetInterface>& interfaces) {
+  std::vector<fuchsia::netstack::NetInterface> interfaces_copy(
+      interfaces.size());
+  for (size_t i = 0; i < interfaces.size(); ++i) {
+    CHECK_EQ(ZX_OK, interfaces[i].Clone(&interfaces_copy[i]));
   }
-
-  return output;
+  return interfaces_copy;
 }
 
 // Partial fake implementation of a Netstack.
@@ -107,34 +108,32 @@
   }
   ~FakeNetstack() override = default;
 
-  // Adds |interface| to the interface query response list.
-  void PushInterface(fuchsia::netstack::NetInterface interface) {
-    interfaces_.push_back(std::move(interface));
-  }
-
-  // Sends the accumulated |interfaces_| to the OnInterfacesChanged event.
-  void NotifyInterfaces() {
-    binding_.events().OnInterfacesChanged(std::move(interfaces_));
-    interfaces_.clear();
-  }
-
-  void SetOnGetRouteTableCallback(base::OnceClosure callback) {
-    on_get_route_table_ = std::move(callback);
+  // Sets the interfaces reported by the fake Netstack and sends an
+  // OnInterfacesChanged() event to the client.
+  void SetInterfaces(std::vector<fuchsia::netstack::NetInterface> interfaces) {
+    interfaces_ = std::move(interfaces);
+    binding_.events().OnInterfacesChanged(CloneNetInterfaces(interfaces_));
   }
 
  private:
   void GetInterfaces(GetInterfacesCallback callback) override {
-    callback(std::move(interfaces_));
+    callback(CloneNetInterfaces(interfaces_));
   }
 
   void GetRouteTable(GetRouteTableCallback callback) override {
     std::vector<fuchsia::netstack::RouteTableEntry> table(2);
-    table[0] = CreateRouteTableEntry(kDefaultNic, true);
-    table[1] = CreateRouteTableEntry(kSecondaryNic, false);
-    callback(std::move(table));
 
-    if (on_get_route_table_)
-      std::move(on_get_route_table_).Run();
+    table[0].nicid = kDefaultInterfaceId;
+    table[0].netmask = IpAddressFrom(kIPv4DefaultGatewayNetmask);
+    table[0].destination = IpAddressFrom(kDefaultIPv4Address);
+    table[0].gateway = IpAddressFrom(kIPv4DefaultGatewayAddress);
+
+    table[1].nicid = kSecondaryInterfaceId;
+    table[1].netmask = IpAddressFrom(kSecondaryIPv4Netmask);
+    table[1].destination = IpAddressFrom(kSecondaryIPv4Address);
+    table[1].gateway = IpAddressFrom(kSecondaryIPv4Address);
+
+    callback(std::move(table));
   }
 
   void NotImplemented_(const std::string& name) override {
@@ -142,11 +141,8 @@
   }
 
   std::vector<fuchsia::netstack::NetInterface> interfaces_;
-
   fidl::Binding<fuchsia::netstack::Netstack> binding_;
 
-  base::OnceClosure on_get_route_table_;
-
   DISALLOW_COPY_AND_ASSIGN(FakeNetstack);
 };
 
@@ -163,22 +159,15 @@
   ~FakeNetstackAsync() = default;
 
   // Asynchronously update the state of the netstack.
-  void PushInterface(fuchsia::netstack::NetInterface interface) {
-    netstack_.Post(FROM_HERE, &FakeNetstack::PushInterface,
-                   std::move(interface));
-  }
-  void NotifyInterfaces() {
-    netstack_.Post(FROM_HERE, &FakeNetstack::NotifyInterfaces);
+  void SetInterfaces(
+      const std::vector<fuchsia::netstack::NetInterface>& interfaces) {
+    netstack_.Post(FROM_HERE, &FakeNetstack::SetInterfaces,
+                   CloneNetInterfaces(interfaces));
   }
 
-  void SetOnGetRouteTableCallback(base::OnceClosure callback) {
-    netstack_.Post(FROM_HERE, &FakeNetstack::SetOnGetRouteTableCallback,
-                   std::move(callback));
-  }
-
-  // Ensure that any PushInterface() or NotifyInterfaces() have been processed.
+  // Ensures that any SetInterfaces() or SendOnInterfacesChanged() calls have
+  // been processed.
   void FlushNetstackThread() {
-    // Ensure that pending Push*() and Notify*() calls were processed.
     thread_.FlushForTesting();
   }
 
@@ -189,22 +178,112 @@
   DISALLOW_COPY_AND_ASSIGN(FakeNetstackAsync);
 };
 
-class MockConnectionTypeObserver
+template <class T>
+class ResultReceiver {
+ public:
+  ~ResultReceiver() { EXPECT_EQ(entries_.size(), 0u); }
+  bool RunAndExpectEntries(std::vector<T> expected_entries) {
+    if (entries_.size() < expected_entries.size()) {
+      base::RunLoop loop;
+      base::AutoReset<size_t> size(&expected_count_, expected_entries.size());
+      base::AutoReset<base::OnceClosure> quit(&quit_loop_, loop.QuitClosure());
+      loop.Run();
+    }
+    return expected_entries == std::exchange(entries_, {});
+  }
+  void AddEntry(T entry) {
+    entries_.push_back(entry);
+    if (quit_loop_ && entries_.size() >= expected_count_)
+      std::move(quit_loop_).Run();
+  }
+
+ protected:
+  size_t expected_count_ = 0u;
+  std::vector<T> entries_;
+  base::OnceClosure quit_loop_;
+};
+
+// Accumulates the list of ConnectionTypes notified via OnConnectionTypeChanged.
+class FakeConnectionTypeObserver
     : public NetworkChangeNotifier::ConnectionTypeObserver {
  public:
-  MOCK_METHOD1(OnConnectionTypeChanged,
-               void(NetworkChangeNotifier::ConnectionType));
+  FakeConnectionTypeObserver() {
+    NetworkChangeNotifier::AddConnectionTypeObserver(this);
+  }
+  ~FakeConnectionTypeObserver() final {
+    NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
+  }
+
+  bool RunAndExpectConnectionTypes(
+      std::vector<NetworkChangeNotifier::ConnectionType> sequence) {
+    return receiver_.RunAndExpectEntries(sequence);
+  }
+
+  // ConnectionTypeObserver implementation.
+  void OnConnectionTypeChanged(
+      NetworkChangeNotifier::ConnectionType type) final {
+    receiver_.AddEntry(type);
+  }
+
+ protected:
+  ResultReceiver<NetworkChangeNotifier::ConnectionType> receiver_;
 };
 
-class MockIPAddressObserver : public NetworkChangeNotifier::IPAddressObserver {
- public:
-  MOCK_METHOD0(OnIPAddressChanged, void());
-};
-
-class MockNetworkChangeObserver
+// Accumulates the list of ConnectionTypes notified via OnConnectionTypeChanged.
+class FakeNetworkChangeObserver
     : public NetworkChangeNotifier::NetworkChangeObserver {
  public:
-  MOCK_METHOD1(OnNetworkChanged, void(NetworkChangeNotifier::ConnectionType));
+  FakeNetworkChangeObserver() {
+    NetworkChangeNotifier::AddNetworkChangeObserver(this);
+  }
+  ~FakeNetworkChangeObserver() final {
+    NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
+  }
+
+  bool RunAndExpectNetworkChanges(
+      std::vector<NetworkChangeNotifier::ConnectionType> sequence) {
+    return receiver_.RunAndExpectEntries(sequence);
+  }
+
+  // NetworkChangeObserver implementation.
+  void OnNetworkChanged(NetworkChangeNotifier::ConnectionType type) final {
+    receiver_.AddEntry(type);
+  }
+
+ protected:
+  ResultReceiver<NetworkChangeNotifier::ConnectionType> receiver_;
+};
+
+// Accumulates the list of ConnectionTypes notified via OnConnectionTypeChanged.
+class FakeIPAddressObserver : public NetworkChangeNotifier::IPAddressObserver {
+ public:
+  FakeIPAddressObserver() { NetworkChangeNotifier::AddIPAddressObserver(this); }
+  ~FakeIPAddressObserver() final {
+    NetworkChangeNotifier::RemoveIPAddressObserver(this);
+    EXPECT_EQ(ip_change_count_, 0u);
+  }
+
+  bool RunAndExpectCallCount(size_t expected_count) {
+    if (ip_change_count_ < expected_count) {
+      base::RunLoop loop;
+      base::AutoReset<size_t> expectation(&expected_count_, expected_count);
+      base::AutoReset<base::OnceClosure> quit(&quit_loop_, loop.QuitClosure());
+      loop.Run();
+    }
+    return std::exchange(ip_change_count_, 0u) == expected_count;
+  }
+
+  // IPAddressObserver implementation.
+  void OnIPAddressChanged() final {
+    ip_change_count_++;
+    if (quit_loop_ && ip_change_count_ >= expected_count_)
+      std::move(quit_loop_).Run();
+  }
+
+ protected:
+  size_t expected_count_ = 0u;
+  size_t ip_change_count_ = 0u;
+  base::OnceClosure quit_loop_;
 };
 
 }  // namespace
@@ -230,35 +309,19 @@
         std::move(netstack_ptr_), required_features,
         dns_config_notifier_.get()));
 
-    NetworkChangeNotifier::AddConnectionTypeObserver(&observer_);
-    NetworkChangeNotifier::AddIPAddressObserver(&ip_observer_);
+    type_observer_ = std::make_unique<FakeConnectionTypeObserver>();
+    ip_observer_ = std::make_unique<FakeIPAddressObserver>();
   }
 
   void TearDown() override {
     // Spin the loops to catch any unintended notifications.
     netstack_.FlushNetstackThread();
     base::RunLoop().RunUntilIdle();
-
-    if (notifier_) {
-      NetworkChangeNotifier::RemoveConnectionTypeObserver(&observer_);
-      NetworkChangeNotifier::RemoveIPAddressObserver(&ip_observer_);
-    }
-  }
-
-  // Causes FakeNetstack to emit NotifyInterfaces(), and then runs the loop
-  // until the GetRouteTable() is called.
-  void NetstackNotifyInterfacesAndWaitForGetRouteTable() {
-    base::RunLoop loop;
-    netstack_.SetOnGetRouteTableCallback(loop.QuitClosure());
-    netstack_.NotifyInterfaces();
-    loop.Run();
   }
 
  protected:
   base::test::SingleThreadTaskEnvironment task_environment_{
       base::test::SingleThreadTaskEnvironment::MainThreadType::IO};
-  testing::StrictMock<MockConnectionTypeObserver> observer_;
-  testing::StrictMock<MockIPAddressObserver> ip_observer_;
 
   fuchsia::netstack::NetstackPtr netstack_ptr_;
   FakeNetstackAsync netstack_;
@@ -268,6 +331,9 @@
   std::unique_ptr<SystemDnsConfigChangeNotifier> dns_config_notifier_;
   std::unique_ptr<NetworkChangeNotifierFuchsia> notifier_;
 
+  std::unique_ptr<FakeConnectionTypeObserver> type_observer_;
+  std::unique_ptr<FakeIPAddressObserver> ip_observer_;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(NetworkChangeNotifierFuchsiaTest);
 };
@@ -279,337 +345,269 @@
 }
 
 TEST_F(NetworkChangeNotifierFuchsiaTest, NotifyNetworkChangeOnInitialIPChange) {
-  // Set up expectations on the IPAddressObserver, and attach a mock
-  // NetworkChangeObserver.
-  testing::StrictMock<MockNetworkChangeObserver> network_change_observer;
-  {
-    testing::InSequence seq;
-    EXPECT_CALL(network_change_observer,
-                OnNetworkChanged(NetworkChangeNotifier::CONNECTION_NONE));
-    EXPECT_CALL(network_change_observer,
-                OnNetworkChanged(NetworkChangeNotifier::CONNECTION_WIFI));
-  }
-  EXPECT_CALL(ip_observer_, OnIPAddressChanged());
+  // Set a live interface with an IP address and create the notifier.
+  std::vector<fuchsia::netstack::NetInterface> interfaces(1);
+  interfaces[0] = DefaultNetInterface();
+  interfaces[0].features = fuchsia::hardware::ethernet::INFO_FEATURE_WLAN;
 
-  // Set an initial IP address and create the notifier.
-  netstack_.PushInterface(
-      CreateNetInterface(kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp,
-                         fuchsia::hardware::ethernet::INFO_FEATURE_WLAN,
-                         CreateIPv4Address(169, 254, 0, 1),
-                         CreateIPv4Address(255, 255, 255, 0), {}));
+  netstack_.SetInterfaces(interfaces);
   CreateNotifier();
 
   // Add the NetworkChangeNotifier, and change the IP address. This should
   // trigger a network change notification, since the IP address is out-of-sync.
-  NetworkChangeNotifier::AddNetworkChangeObserver(&network_change_observer);
+  FakeNetworkChangeObserver network_change_observer;
 
-  netstack_.PushInterface(CreateNetInterface(
-      kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp,
-      fuchsia::hardware::ethernet::INFO_FEATURE_WLAN,
-      CreateIPv4Address(10, 0, 0, 1), CreateIPv4Address(255, 255, 0, 0), {}));
-  NetstackNotifyInterfacesAndWaitForGetRouteTable();
+  interfaces[0].addr = IpAddressFrom(kSecondaryIPv4Address);
+  netstack_.SetInterfaces(interfaces);
 
-  NetworkChangeNotifier::RemoveNetworkChangeObserver(&network_change_observer);
+  EXPECT_TRUE(network_change_observer.RunAndExpectNetworkChanges(
+      {NetworkChangeNotifier::CONNECTION_NONE,
+       NetworkChangeNotifier::CONNECTION_WIFI}));
+  EXPECT_TRUE(ip_observer_->RunAndExpectCallCount(1));
 }
 
 TEST_F(NetworkChangeNotifierFuchsiaTest, NoChange) {
-  netstack_.PushInterface(
-      CreateNetInterface(kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp, 0,
-                         CreateIPv4Address(169, 254, 0, 1),
-                         CreateIPv4Address(255, 255, 255, 0), {}));
+  // Set a live interface with an IP address and create the notifier.
+  std::vector<fuchsia::netstack::NetInterface> interfaces(1);
+  interfaces[0] = DefaultNetInterface();
 
+  netstack_.SetInterfaces(interfaces);
   CreateNotifier();
   EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN,
             notifier_->GetCurrentConnectionType());
 
-  netstack_.PushInterface(
-      CreateNetInterface(kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp, 0,
-                         CreateIPv4Address(169, 254, 0, 1),
-                         CreateIPv4Address(255, 255, 255, 0), {}));
-  netstack_.NotifyInterfaces();
+  // Leave the set of interfaces unchanged, but re-send OnInterfacesChanged.
+  netstack_.SetInterfaces(interfaces);
 }
 
 TEST_F(NetworkChangeNotifierFuchsiaTest, NoChangeV6) {
-  netstack_.PushInterface(
-      CreateNetInterface(kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp, 0,
-                         CreateIPv6Address({0xfe, 0x80, 0x01}),
-                         CreateIPv6Address({0xfe, 0x80}), {}));
+  std::vector<fuchsia::netstack::NetInterface> interfaces(1);
+  interfaces[0] = DefaultNetInterface();
+  interfaces[0].addr = IpAddressFrom(kDefaultIPv6Address);
+  interfaces[0].netmask = IpAddressFrom(kDefaultIPv6Netmask);
+
+  netstack_.SetInterfaces(interfaces);
   CreateNotifier();
 
-  netstack_.PushInterface(
-      CreateNetInterface(kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp, 0,
-                         CreateIPv6Address({0xfe, 0x80, 0x01}),
-                         CreateIPv6Address({0xfe, 0x80}), {}));
-  netstack_.NotifyInterfaces();
+  // Leave the set of interfaces unchanged, but re-send OnInterfacesChanged.
+  netstack_.SetInterfaces(interfaces);
 }
 
 TEST_F(NetworkChangeNotifierFuchsiaTest, MultiInterfaceNoChange) {
-  netstack_.PushInterface(
-      CreateNetInterface(kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp, 0,
-                         CreateIPv4Address(169, 254, 0, 1),
-                         CreateIPv4Address(255, 255, 255, 0), {}));
-  netstack_.PushInterface(
-      CreateNetInterface(kSecondaryNic, fuchsia::netstack::NetInterfaceFlagUp,
-                         0, CreateIPv4Address(169, 254, 0, 2),
-                         CreateIPv4Address(255, 255, 255, 0), {}));
+  std::vector<fuchsia::netstack::NetInterface> interfaces(2);
+  interfaces[0] = DefaultNetInterface();
+  interfaces[1] = SecondaryNetInterface();
+
+  netstack_.SetInterfaces(interfaces);
   CreateNotifier();
 
-  netstack_.PushInterface(
-      CreateNetInterface(kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp, 0,
-                         CreateIPv4Address(169, 254, 0, 1),
-                         CreateIPv4Address(255, 255, 255, 0), {}));
-  netstack_.PushInterface(
-      CreateNetInterface(kSecondaryNic, fuchsia::netstack::NetInterfaceFlagUp,
-                         0, CreateIPv4Address(169, 254, 0, 3),
-                         CreateIPv4Address(255, 255, 255, 0), {}));
-  netstack_.NotifyInterfaces();
+  // Leave the set of interfaces unchanged, but re-send OnInterfacesChanged.
+  netstack_.SetInterfaces(interfaces);
 }
 
 TEST_F(NetworkChangeNotifierFuchsiaTest, MultiV6IPNoChange) {
-  std::vector<fuchsia::net::Subnet> addresses;
-  addresses.push_back(CreateSubnet({0xfe, 0x80, 0x01}, 2));
-  netstack_.PushInterface(CreateNetInterface(
-      kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp, 0,
-      CreateIPv4Address(169, 254, 0, 1), CreateIPv4Address(255, 255, 255, 0),
-      std::move(addresses)));
+  std::vector<fuchsia::netstack::NetInterface> interfaces(1);
+  interfaces[0] = DefaultNetInterface();
+  interfaces[0].ipv6addrs.push_back(SubnetFrom(kDefaultIPv6Address, 2));
 
+  netstack_.SetInterfaces(interfaces);
   CreateNotifier();
 
-  addresses.push_back(CreateSubnet({0xfe, 0x80, 0x01}, 2));
-  netstack_.PushInterface(CreateNetInterface(
-      kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp, 0,
-      CreateIPv4Address(169, 254, 0, 1), CreateIPv4Address(255, 255, 255, 0),
-      std::move(addresses)));
-  netstack_.NotifyInterfaces();
+  // Leave the set of interfaces unchanged, but re-send OnInterfacesChanged.
+  netstack_.SetInterfaces(interfaces);
 }
 
 TEST_F(NetworkChangeNotifierFuchsiaTest, IpChange) {
-  EXPECT_CALL(ip_observer_, OnIPAddressChanged());
+  std::vector<fuchsia::netstack::NetInterface> interfaces(1);
+  interfaces[0] = DefaultNetInterface();
 
-  netstack_.PushInterface(
-      CreateNetInterface(kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp, 0,
-                         CreateIPv4Address(169, 254, 0, 1),
-                         CreateIPv4Address(255, 255, 255, 0), {}));
+  netstack_.SetInterfaces(interfaces);
   CreateNotifier();
-
   EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN,
             notifier_->GetCurrentConnectionType());
 
-  netstack_.PushInterface(CreateNetInterface(
-      kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp, 0,
-      CreateIPv4Address(10, 0, 0, 1), CreateIPv4Address(255, 255, 0, 0), {}));
+  interfaces[0].addr = IpAddressFrom(kSecondaryIPv4Address);
+  netstack_.SetInterfaces(interfaces);
 
-  NetstackNotifyInterfacesAndWaitForGetRouteTable();
+  // Expect a single OnIPAddressChanged() notification.
+  ip_observer_->RunAndExpectCallCount(1);
 }
 
 TEST_F(NetworkChangeNotifierFuchsiaTest, IpChangeV6) {
-  EXPECT_CALL(ip_observer_, OnIPAddressChanged());
+  std::vector<fuchsia::netstack::NetInterface> interfaces(1);
+  interfaces[0] = DefaultNetInterface();
+  interfaces[0].addr = IpAddressFrom(kDefaultIPv6Address);
+  interfaces[0].netmask = IpAddressFrom(kDefaultIPv6Netmask);
+  interfaces[0].broadaddr = IpAddressFrom(kDefaultIPv6Address);
 
-  netstack_.PushInterface(
-      CreateNetInterface(kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp, 0,
-                         CreateIPv6Address({0xfe, 0x80, 0x01}),
-                         CreateIPv6Address({0xfe, 0x80}), {}));
+  netstack_.SetInterfaces(interfaces);
   CreateNotifier();
   EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN,
             notifier_->GetCurrentConnectionType());
 
-  netstack_.PushInterface(
-      CreateNetInterface(kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp, 0,
-                         CreateIPv6Address({0xfe, 0x80, 0x02}),
-                         CreateIPv6Address({0xfe, 0x80}), {}));
+  interfaces[0].addr = IpAddressFrom(kSecondaryIPv6Address);
+  interfaces[0].netmask = IpAddressFrom(kSecondaryIPv6Netmask);
+  interfaces[0].broadaddr = IpAddressFrom(kSecondaryIPv6Address);
+  netstack_.SetInterfaces(interfaces);
 
-  NetstackNotifyInterfacesAndWaitForGetRouteTable();
+  // Expect a single OnIPAddressChanged() notification.
+  ip_observer_->RunAndExpectCallCount(1);
 }
 
 TEST_F(NetworkChangeNotifierFuchsiaTest, MultiV6IPChanged) {
-  EXPECT_CALL(ip_observer_, OnIPAddressChanged());
+  std::vector<fuchsia::netstack::NetInterface> interfaces(1);
+  interfaces[0] = DefaultNetInterface();
+  interfaces[0].ipv6addrs.push_back(SubnetFrom(kDefaultIPv6Address, 2));
 
-  std::vector<fuchsia::net::Subnet> addresses;
-  addresses.push_back(CreateSubnet({0xfe, 0x80, 0x01}, 2));
-  netstack_.PushInterface(CreateNetInterface(
-      kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp, 0,
-      CreateIPv4Address(169, 254, 0, 1), CreateIPv4Address(255, 255, 255, 0),
-      std::move(addresses)));
-
+  netstack_.SetInterfaces(interfaces);
   CreateNotifier();
   EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN,
             notifier_->GetCurrentConnectionType());
 
-  addresses.push_back(CreateSubnet({0xfe, 0x80, 0x02}, 2));
-  netstack_.PushInterface(CreateNetInterface(
-      kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp, 0,
-      CreateIPv4Address(10, 0, 0, 1), CreateIPv4Address(255, 255, 0, 0),
-      std::move(addresses)));
+  interfaces[0].addr = IpAddressFrom(kSecondaryIPv4Address);
+  interfaces[0].netmask = IpAddressFrom(kSecondaryIPv4Netmask);
+  interfaces[0].broadaddr = IpAddressFrom(kSecondaryIPv4Address);
+  interfaces[0].ipv6addrs[0] = SubnetFrom(kSecondaryIPv6Address, 2);
+  netstack_.SetInterfaces(interfaces);
 
-  NetstackNotifyInterfacesAndWaitForGetRouteTable();
+  // Expect a single OnIPAddressChanged() notification.
+  ip_observer_->RunAndExpectCallCount(1);
 }
 
 TEST_F(NetworkChangeNotifierFuchsiaTest, Ipv6AdditionalIpChange) {
-  EXPECT_CALL(ip_observer_, OnIPAddressChanged());
+  std::vector<fuchsia::netstack::NetInterface> interfaces(1);
+  interfaces[0] = DefaultNetInterface();
 
-  netstack_.PushInterface(
-      CreateNetInterface(kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp, 0,
-                         CreateIPv4Address(169, 254, 0, 1),
-                         CreateIPv4Address(255, 255, 255, 0), {}));
-
+  netstack_.SetInterfaces(interfaces);
   CreateNotifier();
   EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN,
             notifier_->GetCurrentConnectionType());
 
-  std::vector<fuchsia::net::Subnet> addresses;
-  addresses.push_back(CreateSubnet({0xfe, 0x80, 0x01}, 2));
-  netstack_.PushInterface(CreateNetInterface(
-      kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp, 0,
-      CreateIPv4Address(169, 254, 0, 1), CreateIPv4Address(255, 255, 255, 0),
-      std::move(addresses)));
+  interfaces[0].ipv6addrs.push_back(SubnetFrom(kDefaultIPv6Address, 2));
+  netstack_.SetInterfaces(interfaces);
 
-  NetstackNotifyInterfacesAndWaitForGetRouteTable();
+  // Expect a single OnIPAddressChanged() notification.
+  ip_observer_->RunAndExpectCallCount(1);
 }
 
 TEST_F(NetworkChangeNotifierFuchsiaTest, InterfaceDown) {
-  EXPECT_CALL(ip_observer_, OnIPAddressChanged());
-  EXPECT_CALL(observer_,
-              OnConnectionTypeChanged(NetworkChangeNotifier::CONNECTION_NONE));
+  std::vector<fuchsia::netstack::NetInterface> interfaces(1);
+  interfaces[0] = DefaultNetInterface();
 
-  netstack_.PushInterface(
-      CreateNetInterface(kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp, 0,
-                         CreateIPv4Address(169, 254, 0, 1),
-                         CreateIPv4Address(255, 255, 255, 0), {}));
-
+  netstack_.SetInterfaces(interfaces);
   CreateNotifier();
   EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN,
             notifier_->GetCurrentConnectionType());
 
-  netstack_.PushInterface(
-      CreateNetInterface(1, 0, 0, CreateIPv4Address(169, 254, 0, 1),
-                         CreateIPv4Address(255, 255, 0, 0), {}));
+  interfaces[0].flags = 0;
+  netstack_.SetInterfaces(interfaces);
 
-  NetstackNotifyInterfacesAndWaitForGetRouteTable();
+  type_observer_->RunAndExpectConnectionTypes(
+      {NetworkChangeNotifier::ConnectionType::CONNECTION_NONE});
+  ip_observer_->RunAndExpectCallCount(1);
 }
 
 TEST_F(NetworkChangeNotifierFuchsiaTest, InterfaceUp) {
-  EXPECT_CALL(ip_observer_, OnIPAddressChanged());
-  EXPECT_CALL(observer_, OnConnectionTypeChanged(
-                             NetworkChangeNotifier::CONNECTION_UNKNOWN));
+  std::vector<fuchsia::netstack::NetInterface> interfaces(1);
+  interfaces[0] = DefaultNetInterface();
+  interfaces[0].flags = 0;
 
-  netstack_.PushInterface(
-      CreateNetInterface(1, 0, 0, CreateIPv4Address(169, 254, 0, 1),
-                         CreateIPv4Address(255, 255, 255, 0), {}));
-
+  netstack_.SetInterfaces(interfaces);
   CreateNotifier();
   EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_NONE,
             notifier_->GetCurrentConnectionType());
 
-  netstack_.PushInterface(
-      CreateNetInterface(kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp, 0,
-                         CreateIPv4Address(169, 254, 0, 1),
-                         CreateIPv4Address(255, 255, 0, 0), {}));
+  interfaces[0].flags = fuchsia::netstack::NetInterfaceFlagUp;
+  netstack_.SetInterfaces(interfaces);
 
-  NetstackNotifyInterfacesAndWaitForGetRouteTable();
+  type_observer_->RunAndExpectConnectionTypes(
+      {NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN});
+  ip_observer_->RunAndExpectCallCount(1);
 }
 
 TEST_F(NetworkChangeNotifierFuchsiaTest, InterfaceDeleted) {
-  EXPECT_CALL(ip_observer_, OnIPAddressChanged());
-  EXPECT_CALL(observer_,
-              OnConnectionTypeChanged(NetworkChangeNotifier::CONNECTION_NONE));
+  std::vector<fuchsia::netstack::NetInterface> interfaces(1);
+  interfaces[0] = DefaultNetInterface();
 
-  netstack_.PushInterface(
-      CreateNetInterface(kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp, 0,
-                         CreateIPv4Address(169, 254, 0, 1),
-                         CreateIPv4Address(255, 255, 255, 0), {}));
+  netstack_.SetInterfaces(interfaces);
   CreateNotifier();
   EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN,
             notifier_->GetCurrentConnectionType());
 
-  // NotifyInterfaces() with no new PushInterfaces() means removing everything.
-  NetstackNotifyInterfacesAndWaitForGetRouteTable();
+  netstack_.SetInterfaces({});
+
+  type_observer_->RunAndExpectConnectionTypes(
+      {NetworkChangeNotifier::ConnectionType::CONNECTION_NONE});
+  ip_observer_->RunAndExpectCallCount(1);
 }
 
 TEST_F(NetworkChangeNotifierFuchsiaTest, InterfaceAdded) {
-  EXPECT_CALL(ip_observer_, OnIPAddressChanged());
-  EXPECT_CALL(observer_,
-              OnConnectionTypeChanged(NetworkChangeNotifier::CONNECTION_WIFI));
-
   // Initial interface list is intentionally left empty.
   CreateNotifier();
-
   EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_NONE,
             notifier_->GetCurrentConnectionType());
 
-  netstack_.PushInterface(
-      CreateNetInterface(kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp,
-                         fuchsia::hardware::ethernet::INFO_FEATURE_WLAN,
-                         CreateIPv4Address(169, 254, 0, 1),
-                         CreateIPv4Address(255, 255, 255, 0), {}));
+  std::vector<fuchsia::netstack::NetInterface> interfaces(1);
+  interfaces[0] = DefaultNetInterface();
+  interfaces[0].features = fuchsia::hardware::ethernet::INFO_FEATURE_WLAN;
 
-  NetstackNotifyInterfacesAndWaitForGetRouteTable();
+  netstack_.SetInterfaces(interfaces);
+
+  type_observer_->RunAndExpectConnectionTypes(
+      {NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI});
+  ip_observer_->RunAndExpectCallCount(1);
 }
 
 TEST_F(NetworkChangeNotifierFuchsiaTest, SecondaryInterfaceAddedNoop) {
-  netstack_.PushInterface(
-      CreateNetInterface(kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp, 0,
-                         CreateIPv4Address(169, 254, 0, 1),
-                         CreateIPv4Address(255, 255, 255, 0), {}));
+  std::vector<fuchsia::netstack::NetInterface> interfaces(1);
+  interfaces[0] = DefaultNetInterface();
+
+  netstack_.SetInterfaces(interfaces);
   CreateNotifier();
 
-  netstack_.PushInterface(
-      CreateNetInterface(kSecondaryNic, fuchsia::netstack::NetInterfaceFlagUp,
-                         0, CreateIPv4Address(169, 254, 0, 2),
-                         CreateIPv4Address(255, 255, 255, 0), {}));
-  netstack_.PushInterface(
-      CreateNetInterface(kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp, 0,
-                         CreateIPv4Address(169, 254, 0, 1),
-                         CreateIPv4Address(255, 255, 255, 0), {}));
-
-  netstack_.NotifyInterfaces();
+  interfaces.push_back(SecondaryNetInterface());
+  netstack_.SetInterfaces(interfaces);
 }
 
 TEST_F(NetworkChangeNotifierFuchsiaTest, SecondaryInterfaceDeletedNoop) {
-  netstack_.PushInterface(
-      CreateNetInterface(kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp, 0,
-                         CreateIPv4Address(169, 254, 0, 1),
-                         CreateIPv4Address(255, 255, 255, 0), {}));
-  netstack_.PushInterface(
-      CreateNetInterface(kSecondaryNic, fuchsia::netstack::NetInterfaceFlagUp,
-                         0, CreateIPv4Address(169, 254, 0, 2),
-                         CreateIPv4Address(255, 255, 255, 0), {}));
+  std::vector<fuchsia::netstack::NetInterface> interfaces(2);
+  interfaces[0] = DefaultNetInterface();
+  interfaces[1] = SecondaryNetInterface();
+
+  netstack_.SetInterfaces(interfaces);
   CreateNotifier();
 
-  netstack_.PushInterface(
-      CreateNetInterface(kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp, 0,
-                         CreateIPv4Address(169, 254, 0, 1),
-                         CreateIPv4Address(255, 255, 255, 0), {}));
-
-  netstack_.NotifyInterfaces();
+  interfaces.pop_back();
+  netstack_.SetInterfaces(interfaces);
 }
 
 TEST_F(NetworkChangeNotifierFuchsiaTest, FoundWiFi) {
-  netstack_.PushInterface(
-      CreateNetInterface(kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp,
-                         fuchsia::hardware::ethernet::INFO_FEATURE_WLAN,
-                         CreateIPv4Address(169, 254, 0, 1),
-                         CreateIPv4Address(255, 255, 255, 0), {}));
+  std::vector<fuchsia::netstack::NetInterface> interfaces(1);
+  interfaces[0] = DefaultNetInterface();
+  interfaces[0].features = fuchsia::hardware::ethernet::INFO_FEATURE_WLAN;
+
+  netstack_.SetInterfaces(interfaces);
   CreateNotifier();
   EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI,
             notifier_->GetCurrentConnectionType());
 }
 
 TEST_F(NetworkChangeNotifierFuchsiaTest, FindsInterfaceWithRequiredFeature) {
-  netstack_.PushInterface(
-      CreateNetInterface(kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp,
-                         fuchsia::hardware::ethernet::INFO_FEATURE_WLAN,
-                         CreateIPv4Address(169, 254, 0, 1),
-                         CreateIPv4Address(255, 255, 255, 0), {}));
+  std::vector<fuchsia::netstack::NetInterface> interfaces(1);
+  interfaces[0] = DefaultNetInterface();
+  interfaces[0].features = fuchsia::hardware::ethernet::INFO_FEATURE_WLAN;
+
+  netstack_.SetInterfaces(interfaces);
   CreateNotifier(fuchsia::hardware::ethernet::INFO_FEATURE_WLAN);
   EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI,
             notifier_->GetCurrentConnectionType());
 }
 
 TEST_F(NetworkChangeNotifierFuchsiaTest, IgnoresInterfaceWithMissingFeature) {
-  netstack_.PushInterface(
-      CreateNetInterface(kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp, 0,
-                         CreateIPv4Address(169, 254, 0, 1),
-                         CreateIPv4Address(255, 255, 255, 0), {}));
+  std::vector<fuchsia::netstack::NetInterface> interfaces(1);
+  interfaces[0] = DefaultNetInterface();
+
+  netstack_.SetInterfaces(interfaces);
   CreateNotifier(fuchsia::hardware::ethernet::INFO_FEATURE_WLAN);
   EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_NONE,
             notifier_->GetCurrentConnectionType());
diff --git a/printing/backend/print_backend_win.cc b/printing/backend/print_backend_win.cc
index b9952e1..2d37fdd 100644
--- a/printing/backend/print_backend_win.cc
+++ b/printing/backend/print_backend_win.cc
@@ -16,6 +16,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/scoped_blocking_call.h"
 #include "base/win/scoped_bstr.h"
 #include "base/win/scoped_hglobal.h"
 #include "printing/backend/print_backend_consts.h"
@@ -222,6 +223,8 @@
   DWORD size = MAX_PATH;
   TCHAR default_printer_name[MAX_PATH];
   std::string ret;
+  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
+                                                base::BlockingType::MAY_BLOCK);
   if (::GetDefaultPrinter(default_printer_name, &size))
     ret = base::WideToUTF8(default_printer_name);
   return ret;
diff --git a/printing/backend/win_helper.cc b/printing/backend/win_helper.cc
index 2bd0480..4ae1a951 100644
--- a/printing/backend/win_helper.cc
+++ b/printing/backend/win_helper.cc
@@ -20,6 +20,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/scoped_blocking_call.h"
 #include "base/win/windows_version.h"
 #include "printing/backend/print_backend.h"
 #include "printing/backend/print_backend_consts.h"
@@ -212,6 +213,8 @@
 HRESULT XPSModule::OpenProvider(const base::string16& printer_name,
                                 DWORD version,
                                 HPTPROVIDER* provider) {
+  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
+                                                base::BlockingType::MAY_BLOCK);
   return g_open_provider_proc(printer_name.c_str(), version, provider);
 }
 
@@ -219,6 +222,8 @@
                                         IStream* print_ticket,
                                         IStream* capabilities,
                                         BSTR* error_message) {
+  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
+                                                base::BlockingType::MAY_BLOCK);
   return g_get_print_capabilities_proc(provider, print_ticket, capabilities,
                                        error_message);
 }
@@ -228,6 +233,8 @@
                                                PDEVMODE devmode,
                                                EPrintTicketScope scope,
                                                IStream* print_ticket) {
+  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
+                                                base::BlockingType::MAY_BLOCK);
   return g_convert_devmode_to_print_ticket_proc(provider, devmode_size_in_bytes,
                                                 devmode, scope, print_ticket);
 }
@@ -240,6 +247,8 @@
     ULONG* devmode_byte_count,
     PDEVMODE* devmode,
     BSTR* error_message) {
+  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
+                                                base::BlockingType::MAY_BLOCK);
   return g_convert_print_ticket_to_devmode_proc(
       provider, print_ticket, base_devmode_type, scope, devmode_byte_count,
       devmode, error_message);
@@ -251,15 +260,21 @@
                                                EPrintTicketScope scope,
                                                IStream* result_ticket,
                                                BSTR* error_message) {
+  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
+                                                base::BlockingType::MAY_BLOCK);
   return g_merge_and_validate_print_ticket_proc(
       provider, base_ticket, delta_ticket, scope, result_ticket, error_message);
 }
 
 HRESULT XPSModule::ReleaseMemory(PVOID buffer) {
+  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
+                                                base::BlockingType::MAY_BLOCK);
   return g_release_memory_proc(buffer);
 }
 
 HRESULT XPSModule::CloseProvider(HPTPROVIDER provider) {
+  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
+                                                base::BlockingType::MAY_BLOCK);
   return g_close_provider_proc(provider);
 }
 
@@ -489,14 +504,21 @@
 }
 
 bool PrinterHasValidPaperSize(const wchar_t* name, const wchar_t* port) {
+  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
+                                                base::BlockingType::MAY_BLOCK);
   return DeviceCapabilities(name, port, DC_PAPERSIZE, nullptr, nullptr) > 0;
 }
 
 std::unique_ptr<DEVMODE, base::FreeDeleter> CreateDevMode(HANDLE printer,
                                                           DEVMODE* in) {
   wchar_t* device_name_ptr = const_cast<wchar_t*>(L"");
-  LONG buffer_size = DocumentProperties(nullptr, printer, device_name_ptr,
-                                        nullptr, nullptr, 0);
+  LONG buffer_size;
+  {
+    base::ScopedBlockingCall scoped_blocking_call(
+        FROM_HERE, base::BlockingType::MAY_BLOCK);
+    buffer_size = DocumentProperties(nullptr, printer, device_name_ptr, nullptr,
+                                     nullptr, 0);
+  }
   if (buffer_size < static_cast<int>(sizeof(DEVMODE)))
     return nullptr;
 
@@ -521,9 +543,13 @@
     return nullptr;
   }
 
-  if (DocumentProperties(nullptr, printer, device_name_ptr, out.get(), in,
-                         flags) != IDOK) {
-    return nullptr;
+  {
+    base::ScopedBlockingCall scoped_blocking_call(
+        FROM_HERE, base::BlockingType::MAY_BLOCK);
+    if (DocumentProperties(nullptr, printer, device_name_ptr, out.get(), in,
+                           flags) != IDOK) {
+      return nullptr;
+    }
   }
 
   int size = out->dmSize;
@@ -559,8 +585,14 @@
   std::unique_ptr<DEVMODE, base::FreeDeleter> out(
       reinterpret_cast<DEVMODE*>(calloc(buffer_size, 1)));
   DWORD flags = (in ? (DM_IN_BUFFER) : 0) | DM_OUT_BUFFER | DM_IN_PROMPT;
-  LONG result = DocumentProperties(window, printer, printer_name_ptr, out.get(),
-                                   in, flags);
+  LONG result;
+  {
+    base::ScopedBlockingCall scoped_blocking_call(
+        FROM_HERE, base::BlockingType::MAY_BLOCK);
+    result = DocumentProperties(window, printer, printer_name_ptr, out.get(),
+                                in, flags);
+  }
+
   if (canceled)
     *canceled = (result == IDCANCEL);
   if (result != IDOK)
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index 5e37a45..3422b14 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -1445,22 +1445,6 @@
   std::move(callback).Run();
 }
 
-void NetworkContext::SetFailingHttpTransactionForTesting(
-    int32_t error_code,
-    SetFailingHttpTransactionForTestingCallback callback) {
-  net::HttpCache* cache(
-      url_request_context_->http_transaction_factory()->GetCache());
-  DCHECK(cache);
-  auto factory = std::make_unique<net::FailingHttpTransactionFactory>(
-      cache->GetSession(), static_cast<net::Error>(error_code));
-
-  // Throw away old version; since this is a a browser test, we don't
-  // need to restore the old state.
-  cache->SetHttpNetworkTransactionFactoryForTesting(std::move(factory));
-
-  std::move(callback).Run();
-}
-
 void NetworkContext::VerifyCertificateForTesting(
     const scoped_refptr<net::X509Certificate>& certificate,
     const std::string& hostname,
diff --git a/services/network/network_context.h b/services/network/network_context.h
index 00f14ca..b529d0d4 100644
--- a/services/network/network_context.h
+++ b/services/network/network_context.h
@@ -343,9 +343,6 @@
           cors_extra_safelisted_request_header_names) override;
   void EnableStaticKeyPinningForTesting(
       EnableStaticKeyPinningForTestingCallback callback) override;
-  void SetFailingHttpTransactionForTesting(
-      int32_t rv,
-      SetFailingHttpTransactionForTestingCallback callback) override;
   void VerifyCertificateForTesting(
       const scoped_refptr<net::X509Certificate>& certificate,
       const std::string& hostname,
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom
index 9515fe9..1dc1133 100644
--- a/services/network/public/mojom/network_context.mojom
+++ b/services/network/public/mojom/network_context.mojom
@@ -1301,10 +1301,6 @@
   EnableStaticKeyPinningForTesting() => ();
 
   [Sync]
-  // Will force the transaction to fail with the given error code.
-  SetFailingHttpTransactionForTesting(int32 rv) => ();
-
-  [Sync]
   // Verifies the given certificate using the context's CertVerifier.
   VerifyCertificateForTesting(X509Certificate certificate,
                               string hostname,
diff --git a/services/network/test/test_network_context.h b/services/network/test/test_network_context.h
index 4d832a7..7d09d1b 100644
--- a/services/network/test/test_network_context.h
+++ b/services/network/test/test_network_context.h
@@ -211,9 +211,6 @@
                     GetHSTSStateCallback callback) override {}
   void EnableStaticKeyPinningForTesting(
       EnableStaticKeyPinningForTestingCallback callback) override {}
-  void SetFailingHttpTransactionForTesting(
-      int32_t rv,
-      SetFailingHttpTransactionForTestingCallback callback) override {}
   void VerifyCertificateForTesting(
       const scoped_refptr<net::X509Certificate>& certificate,
       const std::string& hostname,
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index 3c8ffdd..23b4e608 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -211,6 +211,10 @@
 // Staging for lowp::bilerp_clamp_8888, and for planned misc. others.
 #define SK_DISABLE_LOWP_BILERP_CLAMP_CLAMP_STAGE
 
+#ifndef SK_SUPPORT_LEGACY_DIDCONCAT44
+#define SK_SUPPORT_LEGACY_DIDCONCAT44
+#endif
+
 ///////////////////////// Imported from BUILD.gn and skia_common.gypi
 
 /* In some places Skia can use static initializers for global initialization,
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 47041706..33a0dd6 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -974,6 +974,27 @@
             ]
         }
     ],
+    "AutofillUseVariationCountryCode": [
+        {
+            "platforms": [
+                "android",
+                "android_weblayer",
+                "chromeos",
+                "ios",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "AutofillUseVariationCountryCode"
+                    ]
+                }
+            ]
+        }
+    ],
     "BackForwardCache": [
         {
             "platforms": [
diff --git a/third_party/blink/common/mime_util/mime_util.cc b/third_party/blink/common/mime_util/mime_util.cc
index eb1c752..c8ccb699 100644
--- a/third_party/blink/common/mime_util/mime_util.cc
+++ b/third_party/blink/common/mime_util/mime_util.cc
@@ -8,7 +8,6 @@
 #include <unordered_set>
 
 #include "base/lazy_instance.h"
-#include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "build/build_config.h"
 #include "net/base/mime_util.h"
@@ -131,15 +130,15 @@
 };
 
 MimeUtil::MimeUtil() {
-  for (size_t i = 0; i < base::size(kSupportedNonImageTypes); ++i)
-    non_image_types_.insert(kSupportedNonImageTypes[i]);
-  for (size_t i = 0; i < base::size(kSupportedImageTypes); ++i)
-    image_types_.insert(kSupportedImageTypes[i]);
-  for (size_t i = 0; i < base::size(kUnsupportedTextTypes); ++i)
-    unsupported_text_types_.insert(kUnsupportedTextTypes[i]);
-  for (size_t i = 0; i < base::size(kSupportedJavascriptTypes); ++i) {
-    javascript_types_.insert(kSupportedJavascriptTypes[i]);
-    non_image_types_.insert(kSupportedJavascriptTypes[i]);
+  for (const char* type : kSupportedNonImageTypes)
+    non_image_types_.insert(type);
+  for (const char* type : kSupportedImageTypes)
+    image_types_.insert(type);
+  for (const char* type : kUnsupportedTextTypes)
+    unsupported_text_types_.insert(type);
+  for (const char* type : kSupportedJavascriptTypes) {
+    javascript_types_.insert(type);
+    non_image_types_.insert(type);
   }
 }
 
diff --git a/third_party/blink/public/platform/web_runtime_features.h b/third_party/blink/public/platform/web_runtime_features.h
index 6eb3bff..bb7e435 100644
--- a/third_party/blink/public/platform/web_runtime_features.h
+++ b/third_party/blink/public/platform/web_runtime_features.h
@@ -71,8 +71,6 @@
   BLINK_PLATFORM_EXPORT static void EnableCompositedSelectionUpdate(bool);
   BLINK_PLATFORM_EXPORT static bool IsCompositedSelectionUpdateEnabled();
 
-  BLINK_PLATFORM_EXPORT static void EnableCompositorTouchAction(bool);
-
   BLINK_PLATFORM_EXPORT static void EnableAccelerated2dCanvas(bool);
   BLINK_PLATFORM_EXPORT static void EnableAccessibilityExposeARIAAnnotations(
       bool);
diff --git a/third_party/blink/renderer/bindings/generated_in_modules.gni b/third_party/blink/renderer/bindings/generated_in_modules.gni
index 997d5288..d591c14 100644
--- a/third_party/blink/renderer/bindings/generated_in_modules.gni
+++ b/third_party/blink/renderer/bindings/generated_in_modules.gni
@@ -45,6 +45,8 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_client_lifecycle_state_query.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_client_type.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_client_type.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_color_gamut.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_color_gamut.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_connection_type.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_connection_type.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_contact_property.cc",
@@ -123,6 +125,8 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_view_dimension.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_format.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_format.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_hdr_metadata_type.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_hdr_metadata_type.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_hid_unit_system.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_hid_unit_system.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_cursor_direction.cc",
@@ -283,6 +287,8 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_task_priority.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_track_default_type.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_track_default_type.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_transfer_function.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_transfer_function.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_usb_direction.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_usb_direction.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_usb_endpoint_type.cc",
@@ -1166,6 +1172,8 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_usb_out_transfer_result.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_decoder.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_decoder.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_encoder.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_encoder.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_frame.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_frame.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_playback_quality.cc",
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
index 9b6cb73..9795640 100644
--- a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
+++ b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
@@ -257,8 +257,6 @@
                                "V8PerIsolateData::From(${isolate});")),
         S("property_name",
           "const char* const ${property_name} = \"${property.identifier}\";"),
-        S("v8_receiver",
-          "v8::Local<v8::Object> ${v8_receiver} = ${info}.This();"),
         S("receiver_context", ("v8::Local<v8::Context> ${receiver_context} = "
                                "${v8_receiver}->CreationContext();")),
         S("receiver_script_state",
@@ -373,6 +371,19 @@
             S("v8_property_value",
               "v8::Local<v8::Value> ${v8_property_value} = ${info}[0];"))
 
+    # v8_receiver
+    if cg_context.v8_callback_type == CodeGenContext.V8_FUNCTION_CALLBACK:
+        # In case of v8::FunctionCallbackInfo, This() is the receiver object.
+        local_vars.append(
+            S("v8_receiver",
+              "v8::Local<v8::Object> ${v8_receiver} = ${info}.This();"))
+    else:
+        # In case of v8::PropertyCallbackInfo, Holder() is the object that has
+        # the property being processed.
+        local_vars.append(
+            S("v8_receiver",
+              "v8::Local<v8::Object> ${v8_receiver} = ${info}.Holder();"))
+
     code_node.register_code_symbols(local_vars)
     code_node.add_template_vars(template_vars)
 
@@ -1928,6 +1939,14 @@
     body.extend([
         make_runtime_call_timer_scope(cg_context, "IndexedPropertyGetter"),
         EmptyNode(),
+        TextNode("""\
+// LegacyPlatformObjectGetOwnProperty
+// https://heycam.github.io/webidl/#LegacyPlatformObjectGetOwnProperty
+// step 1.2. If index is a supported property index, then:
+// step 3. Return OrdinaryGetOwnProperty(O, P).
+if (${index} >= ${blink_receiver}->length())
+  return;  // Do not intercept.  Fallback to OrdinaryGetOwnProperty.\
+"""),
         make_v8_set_return_value(cg_context),
     ])
 
@@ -1938,12 +1957,9 @@
     assert isinstance(cg_context, CodeGenContext)
     assert isinstance(function_name, str)
 
-    if cg_context.indexed_property_setter is None:
-        return None, None
-
     arg_decls = [
         "uint32_t index",
-        "v8::Local<v8::Value> v8_value",
+        "v8::Local<v8::Value> v8_property_value",
         "const v8::PropertyCallbackInfo<v8::Value>& info",
     ]
     return_type = "void"
@@ -1962,24 +1978,126 @@
     func_def.set_base_template_vars(cg_context.template_bindings())
     body = func_def.body
     body.add_template_var("index", "index")
-    body.add_template_var("v8_value", "v8_value")
+    body.add_template_var("v8_property_value", "v8_property_value")
     body.add_template_var("info", "info")
     bind_callback_local_vars(body, cg_context)
-    bind_return_value(
-        body, cg_context, overriding_args=["${index}", "${blink_value}"])
-    body.register_code_symbol(
-        make_v8_to_blink_value(
-            "blink_value",
-            "${v8_value}",
-            cg_context.indexed_property_setter.arguments[1].idl_type,
-            argument_index=2))
 
     body.extend([
         make_runtime_call_timer_scope(cg_context, "IndexedPropertySetter"),
         EmptyNode(),
-        make_steps_of_ce_reactions(cg_context),
+    ])
+
+    if not cg_context.indexed_property_setter:
+        body.append(
+            TextNode("""\
+// 3.8.2. [[Set]]
+// https://heycam.github.io/webidl/#legacy-platform-object-set
+// step 1. If O and Receiver are the same object, then:
+if (${info}.Holder() == ${info}.This()) {
+  // OrdinarySetWithOwnDescriptor will end up calling DefineOwnProperty,
+  // which will fail when the receiver object is this legacy platform
+  // object.
+  bindings::V8SetReturnValue(${info}, nullptr);
+  if (${info}.ShouldThrowOnError()) {
+    ExceptionState exception_state(${info}.GetIsolate(),
+                                   ExceptionState::kIndexedSetterContext,
+                                   "${interface.identifier}");
+    exception_state.ThrowTypeError(
+        "Indexed property setter is not supported.");
+  }
+  return;
+}
+
+// step 2. Let ownDesc be LegacyPlatformObjectGetOwnProperty(O, P, true).
+// step 3. Perform ? OrdinarySetWithOwnDescriptor(O, P, V, Receiver,
+//   ownDesc).
+//
+// Do not intercept.  Fallback to OrdinarySetWithOwnDescriptor.\
+"""))
+        return func_decl, func_def
+
+    bind_return_value(
+        body,
+        cg_context,
+        overriding_args=["${index}", "${blink_property_value}"])
+    body.register_code_symbol(
+        make_v8_to_blink_value(
+            "blink_property_value",
+            "${v8_property_value}",
+            cg_context.indexed_property_setter.arguments[1].idl_type,
+            argument_index=2))
+
+    body.extend([
+        TextNode("""\
+// 3.8.2. [[Set]]
+// https://heycam.github.io/webidl/#legacy-platform-object-set
+// step 1. If O and Receiver are the same object, then:\
+"""),
+        CxxLikelyIfNode(
+            cond="${info}.Holder() == ${info}.This()",
+            body=[
+                TextNode("""\
+// step 1.1.1. Invoke the indexed property setter with P and V.\
+"""),
+                make_steps_of_ce_reactions(cg_context),
+                EmptyNode(),
+                make_v8_set_return_value(cg_context),
+                TextNode("""\
+bindings::V8SetReturnValue(${info}, nullptr);
+return;"""),
+            ]),
         EmptyNode(),
-        make_v8_set_return_value(cg_context),
+        TextNode("""\
+// Do not intercept.  Fallback to OrdinarySetWithOwnDescriptor.\
+"""),
+    ])
+
+    return func_decl, func_def
+
+
+def make_indexed_property_deleter_callback(cg_context, function_name):
+    assert isinstance(cg_context, CodeGenContext)
+    assert isinstance(function_name, str)
+
+    arg_decls = [
+        "uint32_t index",
+        "const v8::PropertyCallbackInfo<v8::Boolean>& info",
+    ]
+    return_type = "void"
+
+    func_decl = CxxFuncDeclNode(
+        name=function_name,
+        arg_decls=arg_decls,
+        return_type=return_type,
+        static=True)
+
+    func_def = CxxFuncDefNode(
+        name=function_name,
+        arg_decls=arg_decls,
+        return_type=return_type,
+        class_name=cg_context.class_name)
+    func_def.set_base_template_vars(cg_context.template_bindings())
+    body = func_def.body
+    body.add_template_var("index", "index")
+    body.add_template_var("info", "info")
+    bind_callback_local_vars(body, cg_context)
+
+    body.extend([
+        make_runtime_call_timer_scope(cg_context, "IndexedPropertyDeleter"),
+        EmptyNode(),
+        TextNode("""\
+// 3.8.4. [[Delete]]
+// https://heycam.github.io/webidl/#legacy-platform-object-delete
+// step 1.2. If index is not a supported property index, then return true.
+// step 1.3. Return false.
+const bool is_supported = ${index} < ${blink_receiver}->length();
+bindings::V8SetReturnValue(${info}, !is_supported);
+if (is_supported and ${info}.ShouldThrowOnError()) {
+  ExceptionState exception_state(${info}.GetIsolate(),
+                                 ExceptionState::kIndexedDeletionContext,
+                                 "${interface.identifier}");
+  exception_state.ThrowTypeError("Index property deleter is not supported.");
+}"""),
     ])
 
     return func_decl, func_def
@@ -1991,7 +2109,7 @@
 
     arg_decls = [
         "uint32_t index",
-        "const v8::PropertyDescriptor& desc",
+        "const v8::PropertyDescriptor& v8_property_desc",
         "const v8::PropertyCallbackInfo<v8::Value>& info",
     ]
     return_type = "void"
@@ -2010,17 +2128,19 @@
     func_def.set_base_template_vars(cg_context.template_bindings())
     body = func_def.body
     body.add_template_var("index", "index")
-    body.add_template_var("desc", "desc")
+    body.add_template_var("v8_property_desc", "v8_property_desc")
     body.add_template_var("info", "info")
     bind_callback_local_vars(body, cg_context)
 
-    body.append(
+    body.extend([
+        make_runtime_call_timer_scope(cg_context, "IndexedPropertyDefiner"),
+        EmptyNode(),
         TextNode("""\
-// https://heycam.github.io/webidl/#legacy-platform-object-defineownproperty
 // 3.8.3. [[DefineOwnProperty]]
+// https://heycam.github.io/webidl/#legacy-platform-object-defineownproperty
 // step 1.1. If the result of calling IsDataDescriptor(Desc) is false, then
 //   return false.
-if (desc.has_get() || desc.has_set()) {
+if (v8_property_desc.has_get() || v8_property_desc.has_set()) {
   bindings::V8SetReturnValue(${info}, nullptr);
   if (${info}.ShouldThrowOnError()) {
     ExceptionState exception_state(${info}.GetIsolate(),
@@ -2030,18 +2150,10 @@
   }
   return;
 }
-"""))
+"""),
+    ])
 
-    writable = bool(
-        cg_context.interface.indexed_and_named_properties.indexed_setter)
-    if writable:
-        body.append(
-            TextNode("""\
-// step 1.3. Invoke the indexed property setter with P and Desc.[[Value]].
-//
-// Return nothing and fall back to
-// ${class_name}::IndexedPropertySetterCallback."""))
-    else:
+    if not cg_context.interface.indexed_and_named_properties.indexed_setter:
         body.append(
             TextNode("""\
 // step 1.2. If O does not implement an interface with an indexed property
@@ -2052,8 +2164,15 @@
                                  ExceptionState::kIndexedSetterContext,
                                  "${interface.identifier}");
   exception_state.ThrowTypeError("Index property setter is not supported.");
-  return;
 }"""))
+    else:
+        body.append(
+            TextNode("""\
+// step 1.3. Invoke the indexed property setter with P and Desc.[[Value]].
+${class_name}::IndexedPropertySetterCallback(
+    ${index}, ${v8_property_desc}.value(), ${info});
+bindings::V8SetReturnValue(${info}, nullptr);\
+"""))
 
     return func_decl, func_def
 
@@ -2085,27 +2204,36 @@
     body.add_template_var("info", "info")
     bind_callback_local_vars(body, cg_context)
 
+    body.extend([
+        make_runtime_call_timer_scope(cg_context, "IndexedPropertyDescriptor"),
+        EmptyNode(),
+    ])
+
     pattern = """\
+// LegacyPlatformObjectGetOwnProperty
 // https://heycam.github.io/webidl/#LegacyPlatformObjectGetOwnProperty
-// Steps 1.1. to 1.2. are covered here: we rely on
-// IndexedPropertyGetterCallback() to call the getter function and check
-// that |index| is a valid property index, in which case it will have set
-// info.GetReturnValue() to something other than undefined.
+// step 1.2.3. If operation was defined without an identifier, then set
+//   value to the result of performing the steps listed in the interface
+//   description to determine the value of an indexed property with index
+//   as the index.
+// step 1.2.4. Otherwise, operation was defined with an identifier. Set
+//   value to the result of performing the steps listed in the description
+//   of operation with index as the only argument value.
 ${class_name}::IndexedPropertyGetterCallback(${index}, ${info});
 v8::Local<v8::Value> v8_value = ${info}.GetReturnValue().Get();
+// step 1.2. If index is a supported property index, then:
+// step 3. Return OrdinaryGetOwnProperty(O, P).
 if (v8_value->IsUndefined())
-  return;
+  return;  // Do not intercept.  Fallback to OrdinaryGetOwnProperty.
 
-// 1.2.5. Let |desc| be a newly created Property Descriptor with no fields.
-// 1.2.6. Set desc.[[Value]] to the result of converting value to an
+// step 1.2.6. Set desc.[[Value]] to the result of converting value to an
 //   ECMAScript value.
-// 1.2.7. If O implements an interface with an indexed property setter,
+// step 1.2.7. If O implements an interface with an indexed property setter,
 //   then set desc.[[Writable]] to true, otherwise set it to false.
+// step 1.2.8. Set desc.[[Enumerable]] and desc.[[Configurable]] to true.
 v8::PropertyDescriptor desc(v8_value, /*writable=*/{cxx_writable});
-// 1.2.8. Set desc.[[Enumerable]] and desc.[[Configurable]] to true.
 desc.set_enumerable(true);
 desc.set_configurable(true);
-// 1.2.9. Return |desc|.
 bindings::V8SetReturnValue(${info}, desc);"""
     writable = bool(
         cg_context.interface.indexed_and_named_properties.indexed_setter)
@@ -2138,12 +2266,20 @@
     body.add_template_var("info", "info")
     bind_callback_local_vars(body, cg_context)
 
-    body.append(
+    body.extend([
+        make_runtime_call_timer_scope(cg_context, "IndexedPropertyEnumerator"),
+        EmptyNode(),
         TextNode("""\
+// 3.8.6. [[OwnPropertyKeys]]
+// https://heycam.github.io/webidl/#legacy-platform-object-ownpropertykeys
+// step 2. If O supports indexed properties, then for each index of O's
+//   supported property indices, in ascending numerical order, append
+//   ! ToString(index) to keys.
 uint32_t length = ${blink_receiver}->length();
 v8::Local<v8::Array> array =
     bindings::EnumerateIndexedProperties(${isolate}, length);
-bindings::V8SetReturnValue(${info}, array);"""))
+bindings::V8SetReturnValue(${info}, array);"""),
+    ])
 
     return func_decl, func_def
 
@@ -2186,8 +2322,47 @@
         text = _format("${class_name}::{}(${blink_property_name}, ${info});",
                        custom_function_name(cg_context))
         body.append(TextNode(text))
+        return func_decl, func_def
+
+    # The named property getter's implementation of Blink is not designed to
+    # represent the property existence, and we have to determine the property
+    # existence by heuristics.
+    type = cg_context.return_type.unwrap()
+    if type.is_any or type.is_object:
+        not_found_expr = "${return_value}.IsEmpty()"
+    elif type.is_string:
+        not_found_expr = "${return_value}.IsNull()"
+    elif type.is_interface:
+        not_found_expr = "!${return_value}"
+    elif type.is_union:
+        not_found_expr = "${return_value}.IsNull()"
     else:
-        body.append(make_v8_set_return_value(cg_context))
+        assert False
+
+    body.extend([
+        TextNode("""\
+// LegacyPlatformObjectGetOwnProperty
+// https://heycam.github.io/webidl/#LegacyPlatformObjectGetOwnProperty
+// step 2.1. If the result of running the named property visibility
+//   algorithm with property name P and object O is true, then:\
+"""),
+        CxxUnlikelyIfNode(
+            cond=not_found_expr,
+            body=[
+                TextNode("// step 3. Return OrdinaryGetOwnProperty(O, P)."),
+                TextNode("return;  // Do not intercept."),
+            ]),
+        TextNode("""\
+// step 2.1.3. If operation was defined without an identifier, then set
+//   value to the result of performing the steps listed in the interface
+//   description to determine the value of a named property with P as the
+//   name.
+// step 2.1.4. Otherwise, operation was defined with an identifier. Set
+//   value to the result of performing the steps listed in the description
+//   of operation with P as the only argument value.\
+"""),
+        make_v8_set_return_value(cg_context),
+    ])
 
     return func_decl, func_def
 
@@ -2196,9 +2371,6 @@
     assert isinstance(cg_context, CodeGenContext)
     assert isinstance(function_name, str)
 
-    if cg_context.named_property_setter is None:
-        return None, None
-
     arg_decls = [
         "v8::Local<v8::Name> v8_property_name",
         "v8::Local<v8::Value> v8_property_value",
@@ -2223,34 +2395,92 @@
     body.add_template_var("v8_property_value", "v8_property_value")
     body.add_template_var("info", "info")
     bind_callback_local_vars(body, cg_context)
-    bind_return_value(
-        body,
-        cg_context,
-        overriding_args=["${blink_property_name}", "${blink_value}"])
-    body.register_code_symbol(
-        make_v8_to_blink_value(
-            "blink_value",
-            "${v8_property_value}",
-            cg_context.named_property_setter.arguments[1].idl_type,
-            argument_index=2))
 
     body.extend([
         make_runtime_call_timer_scope(cg_context, "NamedPropertySetter"),
         EmptyNode(),
     ])
 
+    if not cg_context.named_property_setter:
+        body.append(
+            TextNode("""\
+// 3.8.2. [[Set]]
+// https://heycam.github.io/webidl/#legacy-platform-object-set
+// step 1. If O and Receiver are the same object, then:
+if (${info}.Holder() == ${info}.This()) {
+  // OrdinarySetWithOwnDescriptor will end up calling DefineOwnProperty.
+  // 3.8.3. [[DefineOwnProperty]]
+  // https://heycam.github.io/webidl/#legacy-platform-object-defineownproperty
+  // step 2.1. Let creating be true if P is not a supported property name,
+  //   and false otherwise.
+  // step 2.2.1. If creating is false and O does not implement an interface
+  //   with a named property setter, then return false.
+  ${class_name}::NamedPropertyGetterCallback(${v8_property_name}, ${info});
+  const bool is_creating = ${info}.GetReturnValue().Get()->IsUndefined();
+  if (!is_creating) {
+    bindings::V8SetReturnValue(${info}, nullptr);
+    if (${info}.ShouldThrowOnError()) {
+      ExceptionState exception_state(${info}.GetIsolate(),
+                                     ExceptionState::kSetterContext,
+                                     "${interface.identifier}");
+      exception_state.ThrowTypeError(
+          "Named property setter is not supported.");
+    }
+    return;
+  }
+}
+
+// step 2. Let ownDesc be LegacyPlatformObjectGetOwnProperty(O, P, true).
+// step 3. Perform ? OrdinarySetWithOwnDescriptor(O, P, V, Receiver,
+//   ownDesc).
+//
+// Do not intercept.  Fallback to OrdinarySetWithOwnDescriptor.\
+"""))
+        return func_decl, func_def
+
+    bind_return_value(
+        body,
+        cg_context,
+        overriding_args=["${blink_property_name}", "${blink_property_value}"])
+    body.register_code_symbol(
+        make_v8_to_blink_value(
+            "blink_property_value",
+            "${v8_property_value}",
+            cg_context.named_property_setter.arguments[1].idl_type,
+            argument_index=2))
+
     if "Custom" in cg_context.named_property_setter.extended_attributes:
         text = _format(
             "${class_name}::{}"
             "(${blink_property_name}, ${v8_property_value}, ${info});",
             custom_function_name(cg_context))
         body.append(TextNode(text))
-    else:
-        body.extend([
-            make_steps_of_ce_reactions(cg_context),
-            EmptyNode(),
-            make_v8_set_return_value(cg_context),
-        ])
+        return func_decl, func_def
+
+    body.extend([
+        TextNode("""\
+// 3.8.2. [[Set]]
+// https://heycam.github.io/webidl/#legacy-platform-object-set
+// step 1. If O and Receiver are the same object, then:\
+"""),
+        CxxLikelyIfNode(
+            cond="${info}.Holder() == ${info}.This()",
+            body=[
+                TextNode("""\
+// step 1.2.1. Invoke the named property setter with P and V.\
+"""),
+                make_steps_of_ce_reactions(cg_context),
+                EmptyNode(),
+                make_v8_set_return_value(cg_context),
+                TextNode("""\
+bindings::V8SetReturnValue(${info}, nullptr);
+return;"""),
+            ]),
+        EmptyNode(),
+        TextNode("""\
+// Do not intercept.  Fallback to OrdinarySetWithOwnDescriptor.\
+"""),
+    ])
 
     return func_decl, func_def
 
@@ -2259,9 +2489,6 @@
     assert isinstance(cg_context, CodeGenContext)
     assert isinstance(function_name, str)
 
-    if cg_context.named_property_deleter is None:
-        return None, None
-
     arg_decls = [
         "v8::Local<v8::Name> v8_property_name",
         "const v8::PropertyCallbackInfo<v8::Boolean>& info",
@@ -2284,24 +2511,88 @@
     body.add_template_var("v8_property_name", "v8_property_name")
     body.add_template_var("info", "info")
     bind_callback_local_vars(body, cg_context)
-    bind_return_value(
-        body, cg_context, overriding_args=["${blink_property_name}"])
 
     body.extend([
-        make_runtime_call_timer_scope(cg_context),
+        make_runtime_call_timer_scope(cg_context, "NamedPropertyDeleter"),
         EmptyNode(),
     ])
 
+    props = cg_context.interface.indexed_and_named_properties
+    if (not cg_context.named_property_deleter
+            and "NotEnumerable" in props.named_getter.extended_attributes):
+        body.append(
+            TextNode("""\
+// 3.8.4. [[Delete]]
+// https://heycam.github.io/webidl/#legacy-platform-object-delete
+// step 2. If O supports named properties, O does not implement an interface
+//   with the [Global] extended attribute and the result of calling the
+//   named property visibility algorithm with property name P and object O
+//   is true, then:
+//
+// There is no easy way to determine whether the named property is visible
+// or not.  Just do not intercept and fallback to the default behavior.\
+"""))
+        return func_decl, func_def
+
+    if not cg_context.named_property_deleter:
+        body.append(
+            TextNode("""\
+// 3.8.4. [[Delete]]
+// https://heycam.github.io/webidl/#legacy-platform-object-delete
+// step 2. If O supports named properties, O does not implement an interface
+//   with the [Global] extended attribute and the result of calling the
+//   named property visibility algorithm with property name P and object O
+//   is true, then:
+// step 2.1. If O does not implement an interface with a named property
+//   deleter, then return false.
+ExceptionState exception_state(${info}.GetIsolate(),
+                               ExceptionState::kDeletionContext,
+                               "${interface.identifier}");
+bool does_exist = ${blink_receiver}->NamedPropertyQuery(
+    ${blink_property_name}, exception_state);
+if (exception_state.HadException())
+  return;
+if (does_exist) {
+  bindings::V8SetReturnValue(${info}, false);
+  if (${info}.ShouldThrowOnError()) {
+    exception_state.ThrowTypeError(
+        "Named property deleter is not supported.");
+  }
+  return;
+}
+
+// Do not intercept.\
+"""))
+        return func_decl, func_def
+
+    bind_return_value(
+        body, cg_context, overriding_args=["${blink_property_name}"])
+
     if "Custom" in cg_context.named_property_deleter.extended_attributes:
         text = _format("${class_name}::{}(${blink_property_name}, ${info});",
                        custom_function_name(cg_context))
         body.append(TextNode(text))
-    else:
-        body.extend([
-            make_steps_of_ce_reactions(cg_context),
-            EmptyNode(),
-            make_v8_set_return_value(cg_context),
-        ])
+        return func_decl, func_def
+
+    body.extend([
+        TextNode("""\
+// 3.8.4. [[Delete]]
+// https://heycam.github.io/webidl/#legacy-platform-object-delete\
+"""),
+        make_steps_of_ce_reactions(cg_context),
+        EmptyNode(),
+        make_v8_set_return_value(cg_context),
+        TextNode("""\
+if (${return_value} == NamedPropertyDeleterResult::kDidNotDelete) {
+  if (${info}.ShouldThrowOnError()) {
+    ExceptionState exception_state(${info}.GetIsolate(),
+                                   ExceptionState::kDeletionContext,
+                                   "${interface.identifier}");
+    exception_state.ThrowTypeError("Failed to delete a property.");
+  }
+  return;
+}"""),
+    ])
 
     return func_decl, func_def
 
@@ -2312,7 +2603,7 @@
 
     arg_decls = [
         "v8::Local<v8::Name> v8_property_name",
-        "const v8::PropertyDescriptor& desc",
+        "const v8::PropertyDescriptor& v8_property_desc",
         "const v8::PropertyCallbackInfo<v8::Value>& info",
     ]
     return_type = "void"
@@ -2331,17 +2622,48 @@
     func_def.set_base_template_vars(cg_context.template_bindings())
     body = func_def.body
     body.add_template_var("v8_property_name", "v8_property_name")
-    body.add_template_var("desc", "desc")
+    body.add_template_var("v8_property_desc", "v8_property_desc")
     body.add_template_var("info", "info")
     bind_callback_local_vars(body, cg_context)
 
-    body.append(
+    body.extend([
+        make_runtime_call_timer_scope(cg_context, "NamedPropertyDefiner"),
+        EmptyNode(),
         TextNode("""\
-// https://heycam.github.io/webidl/#legacy-platform-object-defineownproperty
 // 3.8.3. [[DefineOwnProperty]]
+// https://heycam.github.io/webidl/#legacy-platform-object-defineownproperty\
+"""),
+    ])
+    if not cg_context.interface.indexed_and_named_properties.named_setter:
+        body.append(
+            TextNode("""\
+// step 2.1. Let creating be true if P is not a supported property name, and
+//   false otherwise.
+// step 2.2.1. If creating is false and O does not implement an interface
+//   with a named property setter, then return false.
+${class_name}::NamedPropertyGetterCallback(${v8_property_name}, ${info});
+const bool is_creating = ${info}.GetReturnValue().Get()->IsUndefined();
+if (!is_creating) {
+  bindings::V8SetReturnValue(${info}, nullptr);
+  if (${info}.ShouldThrowOnError()) {
+    ExceptionState exception_state(${info}.GetIsolate(),
+                                   ExceptionState::kSetterContext,
+                                   "${interface.identifier}");
+    exception_state.ThrowTypeError("Named property setter is not supported.");
+  }
+  return;
+}
+
+// Do not intercept.  Fallback to OrdinaryDefineOwnProperty.\
+"""))
+    else:
+        body.append(
+            TextNode("""\
+// step 2.2.2. If O implements an interface with a named property setter,
+//   then:
 // step 2.2.2.1. If the result of calling IsDataDescriptor(Desc) is false,
 //   then return false.
-if (desc.has_get() || desc.has_set()) {
+if (v8_property_desc.has_get() || v8_property_desc.has_set()) {
   bindings::V8SetReturnValue(${info}, nullptr);
   if (${info}.ShouldThrowOnError()) {
     ExceptionState exception_state(${info}.GetIsolate(),
@@ -2351,31 +2673,12 @@
   }
   return;
 }
+// step 2.2.2.2. Invoke the named property setter with P and Desc.[[Value]].
+${class_name}::NamedPropertySetterCallback(
+    ${v8_property_name}, ${v8_property_desc}.value(), ${info});
+bindings::V8SetReturnValue(${info}, nullptr);\
 """))
 
-    writable = bool(
-        cg_context.interface.indexed_and_named_properties.named_setter)
-    if writable:
-        body.append(
-            TextNode("""\
-// step 2.2.2. Invoke the named property setter with P and Desc.[[Value]].
-//
-// Return nothing and fall back to
-// ${class_name}::NamedPropertySetterCallback."""))
-    else:
-        body.append(
-            TextNode("""\
-// step 2.2.1. If creating is false and O does not implement an interface
-// with a named property setter, then return false.
-bindings::V8SetReturnValue(${info}, nullptr);
-if (${info}.ShouldThrowOnError()) {
-  ExceptionState exception_state(${info}.GetIsolate(),
-                                 ExceptionState::kSetterContext,
-                                 "${interface.identifier}");
-  exception_state.ThrowTypeError("Named property setter is not supported.");
-  return;
-}"""))
-
     return func_decl, func_def
 
 
@@ -2406,30 +2709,40 @@
     body.add_template_var("info", "info")
     bind_callback_local_vars(body, cg_context)
 
+    body.extend([
+        make_runtime_call_timer_scope(cg_context, "NamedPropertyDescriptor"),
+        EmptyNode(),
+    ])
+
     pattern = """\
+// LegacyPlatformObjectGetOwnProperty
 // https://heycam.github.io/webidl/#LegacyPlatformObjectGetOwnProperty
-// Steps 2.1. is covered here: we rely on
-// NamedPropertyGetterCallback() to call the getter function and check
-// that |v8_property_name| is a valid property name, in which case it will
-// have set info.GetReturnValue() to something other than undefined.
+// step 2.1.3. If operation was defined without an identifier, then set
+//   value to the result of performing the steps listed in the interface
+//   description to determine the value of a named property with P as the
+//   name.
+// step 2.1.4. Otherwise, operation was defined with an identifier. Set
+//   value to the result of performing the steps listed in the description
+//   of operation with P as the only argument value.
 ${class_name}::NamedPropertyGetterCallback(${v8_property_name}, ${info});
 v8::Local<v8::Value> v8_value = ${info}.GetReturnValue().Get();
+// step 2.1. If the result of running the named property visibility
+//   algorithm with property name P and object O is true, then:
+// step 3. Return OrdinaryGetOwnProperty(O, P).
 if (v8_value->IsUndefined())
-  return;
+  return;  // Do not intercept.  Fallback to OrdinaryGetOwnProperty.
 
-// 2.1.5. Let |desc| be a newly created Property Descriptor with no fields.
-// 2.1.6. Set desc.[[Value]] to the result of converting value to an
+// step 2.1.6. Set desc.[[Value]] to the result of converting value to an
 //   ECMAScript value.
-// 2.1.7. If O implements an interface with a named property setter, then
-//   set desc.[[Writable]] to true, otherwise set it to false.
-v8::PropertyDescriptor desc(v8_value, /*writable=*/{cxx_writable});
-// 2.1.8. If O implements an interface with the
+// step 2.1.7. If O implements an interface with a named property setter,
+//   then set desc.[[Writable]] to true, otherwise set it to false.
+// step 2.1.8. If O implements an interface with the
 //   [LegacyUnenumerableNamedProperties] extended attribute, then set
 //   desc.[[Enumerable]] to false, otherwise set it to true.
+// step 2.1.9. Set desc.[[Configurable]] to true.
+v8::PropertyDescriptor desc(v8_value, /*writable=*/{cxx_writable});
 desc.set_enumerable({cxx_enumerable});
-// 2.1.9. Set desc.[[Configurable]] to true.
 desc.set_configurable(true);
-// 1.2.9. Return |desc|.
 bindings::V8SetReturnValue(${info}, desc);"""
     props = cg_context.interface.indexed_and_named_properties
     writable = bool(props.named_setter)
@@ -2446,12 +2759,77 @@
     return func_decl, func_def
 
 
+def make_named_property_query_callback(cg_context, function_name):
+    assert isinstance(cg_context, CodeGenContext)
+    assert isinstance(function_name, str)
+
+    props = cg_context.interface.indexed_and_named_properties
+    if "NotEnumerable" in props.named_getter.extended_attributes:
+        return None, None
+
+    arg_decls = [
+        "v8::Local<v8::Name> v8_property_name",
+        "const v8::PropertyCallbackInfo<v8::Integer>& info",
+    ]
+    return_type = "void"
+
+    func_decl = CxxFuncDeclNode(
+        name=function_name,
+        arg_decls=arg_decls,
+        return_type=return_type,
+        static=True)
+
+    func_def = CxxFuncDefNode(
+        name=function_name,
+        arg_decls=arg_decls,
+        return_type=return_type,
+        class_name=cg_context.class_name)
+    func_def.set_base_template_vars(cg_context.template_bindings())
+    body = func_def.body
+    body.add_template_var("v8_property_name", "v8_property_name")
+    body.add_template_var("info", "info")
+    bind_callback_local_vars(body, cg_context)
+
+    flags = []
+    if not props.named_setter:
+        flags.append("v8::ReadOnly")
+    if not props.is_named_property_enumerable:
+        flags.append("v8::DontEnum")
+    if not flags:
+        flags.append("v8::None")
+    if len(flags) == 1:
+        property_attribute = flags[0]
+    else:
+        property_attribute = " | ".join(flags)
+
+    body.extend([
+        make_runtime_call_timer_scope(cg_context, "NamedPropertyQuery"),
+        EmptyNode(),
+        TextNode("""\
+ExceptionState exception_state(${isolate},
+                               ExceptionState::kQueryContext,
+                               "${interface.identifier}");
+bool does_exist = ${blink_receiver}->NamedPropertyQuery(
+    ${blink_property_name}, exception_state);
+if (!does_exist)
+  return;  // Do not intercept.
+"""),
+        TextNode(
+            _format(
+                "bindings::V8SetReturnValue"
+                "(${info}, uint32_t({property_attribute}));",
+                property_attribute=property_attribute)),
+    ])
+
+    return func_decl, func_def
+
+
 def make_named_property_enumerator_callback(cg_context, function_name):
     assert isinstance(cg_context, CodeGenContext)
     assert isinstance(function_name, str)
 
-    if not (cg_context.interface.indexed_and_named_properties.
-            is_named_property_enumerable):
+    props = cg_context.interface.indexed_and_named_properties
+    if "NotEnumerable" in props.named_getter.extended_attributes:
         return None, None
 
     arg_decls = ["const v8::PropertyCallbackInfo<v8::Array>& info"]
@@ -2473,8 +2851,15 @@
     body.add_template_var("info", "info")
     bind_callback_local_vars(body, cg_context)
 
-    body.append(
+    body.extend([
+        make_runtime_call_timer_scope(cg_context, "NamedPropertyEnumerator"),
+        EmptyNode(),
         TextNode("""\
+// 3.8.6. [[OwnPropertyKeys]]
+// https://heycam.github.io/webidl/#legacy-platform-object-ownpropertykeys
+// step 3. If O supports named properties, then for each P of O's supported
+//   property names that is visible according to the named property
+//   visibility algorithm, append P to keys.
 Vector<String> blink_property_names;
 ${blink_receiver}->NamedPropertyEnumerator(
     blink_property_names, ${exception_state});
@@ -2482,8 +2867,9 @@
   return;
 bindings::V8SetReturnValue(
     ${info},
-    ToV8(blink_property_names, ${creation_context_object}, ${isolate}));
-"""))
+    ToV8(blink_property_names, ${creation_context_object}, ${isolate}));\
+"""),
+    ])
 
     return func_decl, func_def
 
@@ -3616,6 +4002,23 @@
 ${instance_template}->MarkAsUndetectable();
 """))
 
+    if cg_context.class_like.identifier == "Iterator":
+        body.append(
+            T("""\
+// Iterator-specific settings
+// https://heycam.github.io/webidl/#es-iterator-prototype-object
+{
+  v8::Local<v8::FunctionTemplate>
+      intrinsic_iterator_prototype_interface_template =
+      v8::FunctionTemplate::New(${isolate});
+  intrinsic_iterator_prototype_interface_template->RemovePrototype();
+  intrinsic_iterator_prototype_interface_template->SetIntrinsicDataProperty(
+      V8AtomicString(${isolate}, "prototype"), v8::kIteratorPrototype);
+  ${interface_template}->Inherit(
+      intrinsic_iterator_prototype_interface_template);
+}
+"""))
+
     if cg_context.class_like.identifier == "Location":
         body.append(
             T("""\
@@ -3631,7 +4034,7 @@
     V8AtomicString(${isolate}, "valueOf"),
     v8::kObjProto_valueOf,
     static_cast<v8::PropertyAttribute>(
-        int(v8::ReadOnly) | int(v8::DontEnum) | int(v8::DontDelete)));
+        v8::ReadOnly | v8::DontEnum | v8::DontDelete));
 // step 4. Perform ! location.[[DefineOwnProperty]](@@toPrimitive,
 //   { [[Value]]: undefined, [[Writable]]: false, [[Enumerable]]: false,
 //     [[Configurable]]: false }).
@@ -3639,7 +4042,7 @@
     v8::Symbol::GetToPrimitive(${isolate}),
     v8::Undefined(${isolate}),
     static_cast<v8::PropertyAttribute>(
-        int(v8::ReadOnly) | int(v8::DontEnum) | int(v8::DontDelete)));
+        v8::ReadOnly | v8::DontEnum | v8::DontDelete));
 """))
 
     if indexed_and_named_property_install_nodes:
@@ -3648,6 +4051,31 @@
             EmptyNode(),
         ])
 
+    if (cg_context.interface
+            and cg_context.interface.indexed_and_named_properties and
+            cg_context.interface.indexed_and_named_properties.indexed_getter
+            and "Global" not in cg_context.interface.extended_attributes):
+        body.append(
+            T("""\
+// @@iterator for indexed properties
+${prototype_template}->SetIntrinsicDataProperty(
+    v8::Symbol::GetIterator(${isolate}), v8::kArrayProto_values, v8::DontEnum);
+"""))
+        if (cg_context.interface.iterable
+                and cg_context.interface.iterable.key_type is None):
+            body.append(
+                T("""\
+// Value iterator for indexed properties
+${prototype_template}->SetIntrinsicDataProperty(
+    V8AtomicString(${isolate}, "entries"), v8::kArrayProto_entries, v8::None);
+${prototype_template}->SetIntrinsicDataProperty(
+    V8AtomicString(${isolate}, "keys"), v8::kArrayProto_keys, v8::None);
+${prototype_template}->SetIntrinsicDataProperty(
+    V8AtomicString(${isolate}, "values"), v8::kArrayProto_values, v8::None);
+${prototype_template}->SetIntrinsicDataProperty(
+    V8AtomicString(${isolate}, "forEach"), v8::kArrayProto_forEach, v8::None);
+"""))
+
     if ("Global" in cg_context.class_like.extended_attributes
             or cg_context.class_like.identifier == "Location"):
         if "Global" in cg_context.class_like.extended_attributes:
@@ -3936,6 +4364,8 @@
         add_callback(*make_indexed_property_setter_callback(
             cg_context.make_copy(indexed_property_setter=props.indexed_setter),
             "IndexedPropertySetterCallback"))
+        add_callback(*make_indexed_property_deleter_callback(
+            cg_context, "IndexedPropertyDeleterCallback"))
         add_callback(*make_indexed_property_definer_callback(
             cg_context, "IndexedPropertyDefinerCallback"))
         add_callback(*make_indexed_property_descriptor_callback(
@@ -3961,15 +4391,12 @@
 ${instance_template}->SetHandler(
     v8::IndexedPropertyHandlerConfiguration(
         {impl_bridge}::IndexedPropertyGetterCallback,
-% if interface.indexed_and_named_properties.indexed_setter:
         {impl_bridge}::IndexedPropertySetterCallback,
-% else:
-        nullptr,  // setter
-% endif
-        {impl_bridge}::IndexedPropertyDescriptorCallback,
-        nullptr,  // deleter
+        nullptr,  // query
+        {impl_bridge}::IndexedPropertyDeleterCallback,
         {impl_bridge}::IndexedPropertyEnumeratorCallback,
         {impl_bridge}::IndexedPropertyDefinerCallback,
+        {impl_bridge}::IndexedPropertyDescriptorCallback,
         v8::Local<v8::Value>(),
         {property_handler_flags}));"""
         install_nodes.append(
@@ -3994,6 +4421,8 @@
             cg_context, "NamedPropertyDefinerCallback"))
         add_callback(*make_named_property_descriptor_callback(
             cg_context, "NamedPropertyDescriptorCallback"))
+        add_callback(*make_named_property_query_callback(
+            cg_context, "NamedPropertyQueryCallback"))
         add_callback(*make_named_property_enumerator_callback(
             cg_context, "NamedPropertyEnumeratorCallback"))
 
@@ -4012,7 +4441,7 @@
             flags.append("v8::PropertyHandlerFlags::kHasNoSideEffect")
         property_handler_flags = (
             "static_cast<v8::PropertyHandlerFlags>({})".format(" | ".join(
-                map(lambda flag: "int({})".format(flag), flags))))
+                map(lambda flag: "int32_t({})".format(flag), flags))))
         pattern = """\
 // Named properties
 % if "Global" in interface.extended_attributes:
@@ -4023,23 +4452,22 @@
 ->SetHandler(
     v8::NamedPropertyHandlerConfiguration(
         {impl_bridge}::NamedPropertyGetterCallback,
-% if interface.indexed_and_named_properties.named_setter:
         {impl_bridge}::NamedPropertySetterCallback,
+% if "NotEnumerable" not in \
+interface.indexed_and_named_properties.named_getter.extended_attributes:
+        {impl_bridge}::NamedPropertyQueryCallback,
 % else:
-        nullptr,  // setter
+        nullptr,  // query
 % endif
-        {impl_bridge}::NamedPropertyDescriptorCallback,
-% if interface.indexed_and_named_properties.named_deleter:
         {impl_bridge}::NamedPropertyDeleterCallback,
-% else:
-        nullptr,  // deleter
-% endif
-% if interface.indexed_and_named_properties.is_named_property_enumerable:
+% if "NotEnumerable" not in \
+interface.indexed_and_named_properties.named_getter.extended_attributes:
         {impl_bridge}::NamedPropertyEnumeratorCallback,
 % else:
         nullptr,  // enumerator
 % endif
         {impl_bridge}::NamedPropertyDefinerCallback,
+        {impl_bridge}::NamedPropertyDescriptorCallback,
         v8::Local<v8::Value>(),
         {property_handler_flags}));"""
         install_nodes.append(
diff --git a/third_party/blink/renderer/core/animation/scroll_timeline_offset.h b/third_party/blink/renderer/core/animation/scroll_timeline_offset.h
index 7c16162..ba17456 100644
--- a/third_party/blink/renderer/core/animation/scroll_timeline_offset.h
+++ b/third_party/blink/renderer/core/animation/scroll_timeline_offset.h
@@ -5,7 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_SCROLL_TIMELINE_OFFSET_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_SCROLL_TIMELINE_OFFSET_H_
 
-#include "third_party/blink/renderer/core/animation/scroll_timeline_element_based_offset.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_scroll_timeline_element_based_offset.h"
 #include "third_party/blink/renderer/core/css/properties/css_parsing_utils.h"
 #include "third_party/blink/renderer/core/scroll/scroll_types.h"
 
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index df38e80..08671a4 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -680,6 +680,8 @@
   void UpdateStyleAndLayoutForNode(const Node*, DocumentUpdateReason);
   void IncLayoutCallsCounter() { ++layout_calls_counter_; }
   void IncLayoutCallsCounterNG() { ++layout_calls_counter_ng_; }
+  void IncLayoutBlockCounter() { ++layout_blocks_counter_; }
+  void IncLayoutBlockCounterNG() { ++layout_blocks_counter_ng_; }
 
   scoped_refptr<const ComputedStyle> StyleForPage(int page_index);
 
@@ -2218,6 +2220,13 @@
   // The number of LayoutObject::UpdateLayout() calls for LayoutNG.
   uint32_t layout_calls_counter_ng_ = 0;
 
+  // The number of LayoutBlock instances for both of the legacy layout
+  // and LayoutNG.
+  uint32_t layout_blocks_counter_ = 0;
+
+  // The number of LayoutNGMixin<LayoutBlock> instances
+  uint32_t layout_blocks_counter_ng_ = 0;
+
   bool deferred_compositor_commit_is_allowed_ = false;
 
   // True when the document was created (in DomImplementation) for specific MIME
diff --git a/third_party/blink/renderer/core/fetch/fetch_header_list.cc b/third_party/blink/renderer/core/fetch/fetch_header_list.cc
index 99658116..fff5f517 100644
--- a/third_party/blink/renderer/core/fetch/fetch_header_list.cc
+++ b/third_party/blink/renderer/core/fetch/fetch_header_list.cc
@@ -104,6 +104,23 @@
   return found;
 }
 
+String FetchHeaderList::GetAsRawString(int status_code,
+                                       String status_message) const {
+  StringBuilder builder;
+  builder.Append("HTTP/1.1 ");
+  builder.AppendNumber(status_code);
+  builder.Append(" ");
+  builder.Append(status_message);
+  builder.Append("\r\n");
+  for (auto& it : header_list_) {
+    builder.Append(it.first);
+    builder.Append(":");
+    builder.Append(it.second);
+    builder.Append("\r\n");
+  }
+  return builder.ToString();
+}
+
 bool FetchHeaderList::Has(const String& name) const {
   // https://fetch.spec.whatwg.org/#header-list-contains
   // "A header list (|list|) contains a name (|name|) if |list| contains a
diff --git a/third_party/blink/renderer/core/fetch/fetch_header_list.h b/third_party/blink/renderer/core/fetch/fetch_header_list.h
index b7bb616..d1a5617 100644
--- a/third_party/blink/renderer/core/fetch/fetch_header_list.h
+++ b/third_party/blink/renderer/core/fetch/fetch_header_list.h
@@ -37,6 +37,7 @@
   size_t size() const;
   void Remove(const String&);
   bool Get(const String&, String&) const;
+  String GetAsRawString(int status_code, String status_message) const;
   bool Has(const String&) const;
   void ClearList();
 
diff --git a/third_party/blink/renderer/core/fetch/fetch_response_data.cc b/third_party/blink/renderer/core/fetch/fetch_response_data.cc
index 3ff54a5c..23077d5 100644
--- a/third_party/blink/renderer/core/fetch/fetch_response_data.cc
+++ b/third_party/blink/renderer/core/fetch/fetch_response_data.cc
@@ -4,9 +4,6 @@
 
 #include "third_party/blink/renderer/core/fetch/fetch_response_data.h"
 
-#include "services/network/public/cpp/content_security_policy/content_security_policy.h"
-#include "services/network/public/cpp/features.h"
-#include "services/network/public/mojom/content_security_policy.mojom-blink.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_response.mojom-blink.h"
 #include "third_party/blink/renderer/core/fetch/fetch_header_list.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
@@ -15,76 +12,13 @@
 #include "third_party/blink/renderer/platform/loader/cors/cors.h"
 #include "third_party/blink/renderer/platform/loader/fetch/fetch_utils.h"
 #include "third_party/blink/renderer/platform/network/http_names.h"
+#include "third_party/blink/renderer/platform/network/http_parsers.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
-#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
-#include "url/gurl.h"
 
 using Type = network::mojom::FetchResponseType;
 using ResponseSource = network::mojom::FetchResponseSource;
 
-// TODO(lfg): Stop converting from/to blink type. Instead use mojo to
-// automagically convert this.
-namespace network {
-namespace mojom {
-
-blink::CSPSourcePtr ConvertToBlink(CSPSourcePtr source) {
-  return blink::CSPSource::New(
-      String::FromUTF8(source->scheme), String::FromUTF8(source->host),
-      source->port, String::FromUTF8(source->path), source->is_host_wildcard,
-      source->is_port_wildcard);
-}
-
-blink::CSPSourceListPtr ConvertToBlink(CSPSourceListPtr source_list) {
-  WTF::Vector<blink::CSPSourcePtr> sources;
-  for (auto& it : source_list->sources)
-    sources.push_back(ConvertToBlink(std::move(it)));
-
-  return blink::CSPSourceList::New(std::move(sources), source_list->allow_self,
-                                   source_list->allow_star,
-                                   source_list->allow_response_redirects);
-}
-
-blink::CSPDirectiveName ConvertToBlink(CSPDirectiveName name) {
-  return static_cast<blink::CSPDirectiveName>(name);
-}
-
-blink::ContentSecurityPolicyHeaderPtr ConvertToBlink(
-    ContentSecurityPolicyHeaderPtr header) {
-  return blink::ContentSecurityPolicyHeader::New(
-      String::FromUTF8(header->header_value), header->type, header->source);
-}
-
-blink::ContentSecurityPolicyPtr ConvertToBlink(
-    ContentSecurityPolicyPtr policy_in) {
-  auto policy = blink::ContentSecurityPolicy::New();
-
-  policy->header = ConvertToBlink(std::move(policy_in->header));
-  policy->use_reporting_api = policy_in->use_reporting_api;
-
-  for (auto& directive : policy_in->directives) {
-    policy->directives.insert(ConvertToBlink(directive.first),
-                              ConvertToBlink(std::move(directive.second)));
-  }
-
-  for (auto& endpoint : policy_in->report_endpoints)
-    policy->report_endpoints.push_back(String::FromUTF8(endpoint));
-
-  return policy;
-}
-
-WTF::Vector<blink::ContentSecurityPolicyPtr> ConvertToBlink(
-    std::vector<ContentSecurityPolicyPtr> policies) {
-  WTF::Vector<blink::ContentSecurityPolicyPtr> blink_policies;
-  for (auto& policy : policies)
-    blink_policies.push_back(ConvertToBlink(std::move(policy)));
-
-  return blink_policies;
-}
-
-}  // namespace mojom
-}  // namespace network
-
 namespace blink {
 
 namespace {
@@ -331,30 +265,8 @@
   response->loaded_with_credentials = loaded_with_credentials_;
   for (const auto& header : HeaderList()->List())
     response->headers.insert(header.first, header.second);
-
-  // Check if there's a Content-Security-Policy header and parse it if
-  // necessary.
-  // TODO(lfg). What about report only header?
-  if (base::FeatureList::IsEnabled(
-          network::features::kOutOfBlinkFrameAncestors)) {
-    String content_security_policy_header;
-    std::vector<network::mojom::ContentSecurityPolicyPtr> policies;
-    if (HeaderList()->Get("content-security-policy",
-                          content_security_policy_header)) {
-      network::AddContentSecurityPolicyFromHeaders(
-          StringUTF8Adaptor(content_security_policy_header).AsStringPiece(),
-          network::mojom::ContentSecurityPolicyType::kEnforce, request_url,
-          &policies);
-    }
-    if (HeaderList()->Get("content-security-policy-report-only",
-                          content_security_policy_header)) {
-      network::AddContentSecurityPolicyFromHeaders(
-          StringUTF8Adaptor(content_security_policy_header).AsStringPiece(),
-          network::mojom::ContentSecurityPolicyType::kReport, request_url,
-          &policies);
-    }
-    response->content_security_policy = ConvertToBlink(std::move(policies));
-  }
+  response->content_security_policy = ParseContentSecurityPolicy(
+      HeaderList()->GetAsRawString(status_, status_message_), request_url);
   return response;
 }
 
diff --git a/third_party/blink/renderer/core/fetch/fetch_response_data.h b/third_party/blink/renderer/core/fetch/fetch_response_data.h
index a9783153..a50bb553 100644
--- a/third_party/blink/renderer/core/fetch/fetch_response_data.h
+++ b/third_party/blink/renderer/core/fetch/fetch_response_data.h
@@ -18,7 +18,6 @@
 #include "third_party/blink/renderer/platform/network/http_header_set.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
-
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/fetch/request.cc b/third_party/blink/renderer/core/fetch/request.cc
index ee851d8..f4b92970 100644
--- a/third_party/blink/renderer/core/fetch/request.cc
+++ b/third_party/blink/renderer/core/fetch/request.cc
@@ -31,7 +31,6 @@
 #include "third_party/blink/renderer/core/fetch/body_stream_buffer.h"
 #include "third_party/blink/renderer/core/fetch/fetch_manager.h"
 #include "third_party/blink/renderer/core/fetch/form_data_bytes_consumer.h"
-#include "third_party/blink/renderer/core/fetch/trust_token.h"
 #include "third_party/blink/renderer/core/fetch/trust_token_to_mojom.h"
 #include "third_party/blink/renderer/core/fileapi/blob.h"
 #include "third_party/blink/renderer/core/fileapi/public_url_manager.h"
diff --git a/third_party/blink/renderer/core/fetch/trust_token_to_mojom.h b/third_party/blink/renderer/core/fetch/trust_token_to_mojom.h
index a18f2a2..680f710 100644
--- a/third_party/blink/renderer/core/fetch/trust_token_to_mojom.h
+++ b/third_party/blink/renderer/core/fetch/trust_token_to_mojom.h
@@ -6,7 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_FETCH_TRUST_TOKEN_TO_MOJOM_H_
 
 #include "services/network/public/mojom/trust_tokens.mojom-blink.h"
-#include "third_party/blink/renderer/core/fetch/trust_token.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_trust_token.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/html/forms/html_select_element_test.cc b/third_party/blink/renderer/core/html/forms/html_select_element_test.cc
index f92a9abb..c93e684 100644
--- a/third_party/blink/renderer/core/html/forms/html_select_element_test.cc
+++ b/third_party/blink/renderer/core/html/forms/html_select_element_test.cc
@@ -566,4 +566,13 @@
   }
 }
 
+TEST_F(HTMLSelectElementTest, IntrinsicInlineSizeOverflow) {
+  // crbug.com/1068338
+  // This test passes if UBSAN doesn't complain.
+  SetHtmlInnerHTML(
+      "<select style='word-spacing:1073741824em;'>"
+      "<option>abc def</option></select>");
+  GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kTest);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/html/resources/controls_refresh.css b/third_party/blink/renderer/core/html/resources/controls_refresh.css
index e90e099..d3e87b5 100644
--- a/third_party/blink/renderer/core/html/resources/controls_refresh.css
+++ b/third_party/blink/renderer/core/html/resources/controls_refresh.css
@@ -16,6 +16,19 @@
   border-color: -internal-light-dark-color(#767676, #C3C3C3);
 }
 
+a:-webkit-any-link:focus {
+  outline-offset: 1px;
+}
+
+input:focus, textarea:focus, select:focus {
+  outline-offset: 0;
+}
+
+input[type="checkbox" i]:focus,
+input[type="radio" i]:focus {
+  outline-offset: 2px;
+}
+
 input,
 input[type="email" i],
 input[type="number" i],
diff --git a/third_party/blink/renderer/core/html/trust_token_attribute_parsing.cc b/third_party/blink/renderer/core/html/trust_token_attribute_parsing.cc
index 1143b61..0724901 100644
--- a/third_party/blink/renderer/core/html/trust_token_attribute_parsing.cc
+++ b/third_party/blink/renderer/core/html/trust_token_attribute_parsing.cc
@@ -5,7 +5,7 @@
 #include "third_party/blink/renderer/core/html/trust_token_attribute_parsing.h"
 #include "services/network/public/mojom/trust_tokens.mojom-blink.h"
 #include "services/network/public/mojom/trust_tokens.mojom-shared.h"
-#include "third_party/blink/renderer/core/fetch/trust_token.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_trust_token.h"
 #include "third_party/blink/renderer/platform/json/json_values.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
diff --git a/third_party/blink/renderer/core/inspector/devtools_session.cc b/third_party/blink/renderer/core/inspector/devtools_session.cc
index 7286135..4ee6a0e 100644
--- a/third_party/blink/renderer/core/inspector/devtools_session.cc
+++ b/third_party/blink/renderer/core/inspector/devtools_session.cc
@@ -35,7 +35,8 @@
 const char kSessionId[] = "sessionId";
 
 bool ShouldInterruptForMethod(const String& method) {
-  return method != "Runtime.evaluate" && method != "Runtime.callFunctionOn" &&
+  return method != "Debugger.evaluateOnCallFrame" &&
+         method != "Runtime.evaluate" && method != "Runtime.callFunctionOn" &&
          method != "Runtime.runScript";
 }
 
diff --git a/third_party/blink/renderer/core/layout/layout_block.cc b/third_party/blink/renderer/core/layout/layout_block.cc
index c17f250..ef59cdc 100644
--- a/third_party/blink/renderer/core/layout/layout_block.cc
+++ b/third_party/blink/renderer/core/layout/layout_block.cc
@@ -111,6 +111,9 @@
       has_percent_height_descendants_(false),
       pagination_state_changed_(false),
       is_legacy_initiated_out_of_flow_layout_(false) {
+  if (node)
+    GetDocument().IncLayoutBlockCounter();
+
   // LayoutBlockFlow calls setChildrenInline(true).
   // By default, subclasses do not have inline children.
 }
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index b155d33..b7a0da4f 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -210,8 +210,8 @@
   LayoutTheme& theme = LayoutTheme::GetTheme();
   int paddings = theme.PopupInternalPaddingStart(style) +
                  theme.PopupInternalPaddingEnd(box.GetFrame(), style);
-  return std::max(static_cast<int>(ceilf(max_option_width)),
-                  LayoutTheme::GetTheme().MinimumMenuListSize(style)) +
+  return std::max(LayoutUnit(ceilf(max_option_width)),
+                  LayoutUnit(theme.MinimumMenuListSize(style))) +
          LayoutUnit(paddings);
 }
 
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc
index f5e29f8ef..66f4604 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc
@@ -435,7 +435,7 @@
   }
 }
 
-void NGFragmentItem::SetDeltaToNextForSameLayoutObject(wtf_size_t delta) {
+void NGFragmentItem::SetDeltaToNextForSameLayoutObject(wtf_size_t delta) const {
   DCHECK_NE(delta, 0u);
   delta_to_next_for_same_layout_object_ = delta;
 }
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h
index d4bb16b..4c1b9c50 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h
@@ -129,7 +129,7 @@
   wtf_size_t DeltaToNextForSameLayoutObject() const {
     return delta_to_next_for_same_layout_object_;
   }
-  void SetDeltaToNextForSameLayoutObject(wtf_size_t delta);
+  void SetDeltaToNextForSameLayoutObject(wtf_size_t delta) const;
 
   const PhysicalRect& RectInContainerBlock() const { return rect_; }
   const PhysicalOffset& OffsetInContainerBlock() const { return rect_.offset; }
@@ -359,7 +359,7 @@
   std::unique_ptr<NGInkOverflow> ink_overflow_;
 
   // Item index delta to the next item for the same |LayoutObject|.
-  wtf_size_t delta_to_next_for_same_layout_object_ = 0;
+  mutable wtf_size_t delta_to_next_for_same_layout_object_ = 0;
 
   // Note: We should not add |bidi_level_| because it is used only for layout.
   unsigned type_ : 2;           // ItemType
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
index 89ad701..04449aa 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
@@ -26,6 +26,8 @@
       std::is_base_of<LayoutBlock, Base>::value,
       "Base class of LayoutNGMixin must be LayoutBlock or derived class.");
   DCHECK(!element || !element->ShouldForceLegacyLayout());
+  if (element)
+    Base::GetDocument().IncLayoutBlockCounterNG();
 }
 
 template <typename Base>
diff --git a/third_party/blink/renderer/core/paint/object_painter_base.cc b/third_party/blink/renderer/core/paint/object_painter_base.cc
index 3660bc3e..dc969467 100644
--- a/third_party/blink/renderer/core/paint/object_painter_base.cc
+++ b/third_party/blink/renderer/core/paint/object_painter_base.cc
@@ -550,8 +550,7 @@
     float border_radius = GetFocusRingBorderRadius(style);
     paint_info.context.DrawFocusRing(
         pixel_snapped_outline_rects, style.GetOutlineStrokeWidthForFocusRing(),
-        style.OutlineOffset(), style.GetDefaultOffsetForFocusRing(),
-        border_radius, min_border_width, color);
+        style.OutlineOffset(), border_radius, min_border_width, color);
     return;
   }
 
diff --git a/third_party/blink/renderer/core/style/computed_style.cc b/third_party/blink/renderer/core/style/computed_style.cc
index ba5680b..2bc69f9 100644
--- a/third_party/blink/renderer/core/style/computed_style.cc
+++ b/third_party/blink/renderer/core/style/computed_style.cc
@@ -2234,8 +2234,7 @@
     return 0;
   if (OutlineStyleIsAuto()) {
     return GraphicsContext::FocusRingOutsetExtent(
-        OutlineOffset(), GetDefaultOffsetForFocusRing(),
-        std::ceil(GetOutlineStrokeWidthForFocusRing()));
+        OutlineOffset(), std::ceil(GetOutlineStrokeWidthForFocusRing()));
   }
   return base::ClampAdd(OutlineWidth(), OutlineOffset()).Max(0);
 }
@@ -2254,20 +2253,6 @@
 #endif
 }
 
-int ComputedStyle::GetDefaultOffsetForFocusRing() const {
-  if (!::features::IsFormControlsRefreshEnabled())
-    return 0;
-
-  if (EffectiveAppearance() == kCheckboxPart ||
-      EffectiveAppearance() == kRadioPart) {
-    return 2;
-  } else if (IsLink()) {
-    return 1;
-  }
-
-  return 0;
-}
-
 bool ComputedStyle::ColumnRuleEquivalent(
     const ComputedStyle& other_style) const {
   return ColumnRuleStyle() == other_style.ColumnRuleStyle() &&
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h
index 790c5be..dfd982a 100644
--- a/third_party/blink/renderer/core/style/computed_style.h
+++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -2006,7 +2006,6 @@
   }
   CORE_EXPORT int OutlineOutsetExtent() const;
   CORE_EXPORT float GetOutlineStrokeWidthForFocusRing() const;
-  CORE_EXPORT int GetDefaultOffsetForFocusRing() const;
   bool HasOutlineWithCurrentColor() const {
     return HasOutline() && OutlineColor().IsCurrentColor();
   }
diff --git a/third_party/blink/renderer/core/style/computed_style_test.cc b/third_party/blink/renderer/core/style/computed_style_test.cc
index 9a426bb..e9c920d 100644
--- a/third_party/blink/renderer/core/style/computed_style_test.cc
+++ b/third_party/blink/renderer/core/style/computed_style_test.cc
@@ -105,8 +105,6 @@
   style->SetEffectiveZoom(4.75);
   if (::features::IsFormControlsRefreshEnabled()) {
     EXPECT_EQ(4, style->OutlineOutsetExtent());
-    style->SetEffectiveAppearance(kRadioPart);
-    EXPECT_EQ(6, style->OutlineOutsetExtent());
   } else {
 #if defined(OS_MACOSX)
     EXPECT_EQ(4, style->OutlineOutsetExtent());
diff --git a/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.h b/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.h
index 438c6da..ce493b4 100644
--- a/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.h
+++ b/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.h
@@ -30,9 +30,9 @@
 #include "services/network/public/mojom/trust_tokens.mojom-blink.h"
 #include "services/network/public/mojom/url_loader_factory.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_trust_token.h"
 #include "third_party/blink/renderer/core/dom/document_parser_client.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
-#include "third_party/blink/renderer/core/fetch/trust_token.h"
 #include "third_party/blink/renderer/core/loader/threadable_loader_client.h"
 #include "third_party/blink/renderer/core/probe/async_task_id.h"
 #include "third_party/blink/renderer/core/xmlhttprequest/xml_http_request_event_target.h"
diff --git a/third_party/blink/renderer/modules/idle/idle_detector.cc b/third_party/blink/renderer/modules/idle/idle_detector.cc
index f0a415b2..2168dd5 100644
--- a/third_party/blink/renderer/modules/idle/idle_detector.cc
+++ b/third_party/blink/renderer/modules/idle/idle_detector.cc
@@ -57,14 +57,13 @@
 }
 
 IdleDetector::IdleDetector(ExecutionContext* context, base::TimeDelta threshold)
-    : ExecutionContextClient(context), threshold_(threshold), receiver_(this) {}
+    : ExecutionContextClient(context),
+      threshold_(threshold),
+      receiver_(this, context),
+      service_(context) {}
 
 IdleDetector::~IdleDetector() = default;
 
-void IdleDetector::Dispose() {
-  StopMonitoring();
-}
-
 const AtomicString& IdleDetector::InterfaceName() const {
   return event_target_names::kIdleDetector;
 }
@@ -98,7 +97,7 @@
 }
 
 void IdleDetector::stop() {
-  StopMonitoring();
+  receiver_.reset();
 }
 
 void IdleDetector::StartMonitoring() {
@@ -110,7 +109,7 @@
   scoped_refptr<base::SingleThreadTaskRunner> task_runner =
       GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI);
 
-  if (!service_) {
+  if (!service_.is_bound()) {
     GetExecutionContext()->GetBrowserInterfaceBroker().GetInterface(
         service_.BindNewPipeAndPassReceiver(task_runner));
   }
@@ -124,10 +123,6 @@
       WTF::Bind(&IdleDetector::OnAddMonitor, WrapWeakPersistent(this)));
 }
 
-void IdleDetector::StopMonitoring() {
-  receiver_.reset();
-}
-
 void IdleDetector::OnAddMonitor(mojom::blink::IdleStatePtr state) {
   Update(std::move(state));
 }
@@ -151,6 +146,8 @@
 
 void IdleDetector::Trace(Visitor* visitor) {
   visitor->Trace(state_);
+  visitor->Trace(receiver_);
+  visitor->Trace(service_);
   EventTargetWithInlineData::Trace(visitor);
   ExecutionContextClient::Trace(visitor);
   ActiveScriptWrappable::Trace(visitor);
diff --git a/third_party/blink/renderer/modules/idle/idle_detector.h b/third_party/blink/renderer/modules/idle/idle_detector.h
index 92b3b276..f7388d0 100644
--- a/third_party/blink/renderer/modules/idle/idle_detector.h
+++ b/third_party/blink/renderer/modules/idle/idle_detector.h
@@ -6,8 +6,6 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_IDLE_IDLE_DETECTOR_H_
 
 #include "base/macros.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/blink/public/mojom/idle/idle_manager.mojom-blink-forward.h"
 #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
@@ -18,6 +16,8 @@
 #include "third_party/blink/renderer/modules/event_target_modules.h"
 #include "third_party/blink/renderer/modules/idle/idle_state.h"
 #include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 
 namespace blink {
@@ -30,7 +30,6 @@
                            public mojom::blink::IdleMonitor {
   USING_GARBAGE_COLLECTED_MIXIN(IdleDetector);
   DEFINE_WRAPPERTYPEINFO();
-  USING_PRE_FINALIZER(IdleDetector, Dispose);
 
  public:
   static IdleDetector* Create(ScriptState*,
@@ -42,8 +41,6 @@
 
   ~IdleDetector() override;
 
-  void Dispose();
-
   // EventTarget implementation.
   const AtomicString& InterfaceName() const override;
   ExecutionContext* GetExecutionContext() const override;
@@ -72,12 +69,16 @@
 
   // Holds a pipe which the service uses to notify this object
   // when the idle state has changed.
-  mojo::Receiver<mojom::blink::IdleMonitor> receiver_;
+  HeapMojoReceiver<mojom::blink::IdleMonitor,
+                   IdleDetector,
+                   HeapMojoWrapperMode::kWithoutContextObserver>
+      receiver_;
 
   void StartMonitoring();
-  void StopMonitoring();
 
-  mojo::Remote<mojom::blink::IdleManager> service_;
+  HeapMojoRemote<mojom::blink::IdleManager,
+                 HeapMojoWrapperMode::kWithoutContextObserver>
+      service_;
 
   DISALLOW_COPY_AND_ASSIGN(IdleDetector);
 };
diff --git a/third_party/blink/renderer/modules/media_capabilities/media_capabilities_test.cc b/third_party/blink/renderer/modules/media_capabilities/media_capabilities_test.cc
index a179995..7551cac3 100644
--- a/third_party/blink/renderer/modules/media_capabilities/media_capabilities_test.cc
+++ b/third_party/blink/renderer/modules/media_capabilities/media_capabilities_test.cc
@@ -28,10 +28,9 @@
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_tester.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_media_capabilities_info.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_media_configuration.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_media_decoding_configuration.h"
 #include "third_party/blink/renderer/core/testing/page_test_base.h"
-#include "third_party/blink/renderer/modules/media_capabilities/media_capabilities_info.h"
-#include "third_party/blink/renderer/modules/media_capabilities/media_configuration.h"
-#include "third_party/blink/renderer/modules/media_capabilities/media_decoding_configuration.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_view.h"
diff --git a/third_party/blink/renderer/modules/nfc/nfc_proxy.cc b/third_party/blink/renderer/modules/nfc/nfc_proxy.cc
index b90735f7..3da736ba 100644
--- a/third_party/blink/renderer/modules/nfc/nfc_proxy.cc
+++ b/third_party/blink/renderer/modules/nfc/nfc_proxy.cc
@@ -36,15 +36,13 @@
 
 // NFCProxy
 NFCProxy::NFCProxy(LocalDOMWindow& window)
-    : Supplement<LocalDOMWindow>(window), client_receiver_(this) {}
+    : Supplement<LocalDOMWindow>(window),
+      client_receiver_(this, window.GetExecutionContext()) {}
 
 NFCProxy::~NFCProxy() = default;
 
-void NFCProxy::Dispose() {
-  client_receiver_.reset();
-}
-
 void NFCProxy::Trace(Visitor* visitor) {
+  visitor->Trace(client_receiver_);
   visitor->Trace(writers_);
   visitor->Trace(readers_);
   Supplement<LocalDOMWindow>::Trace(visitor);
diff --git a/third_party/blink/renderer/modules/nfc/nfc_proxy.h b/third_party/blink/renderer/modules/nfc/nfc_proxy.h
index 7ebc41d..06fbc7e 100644
--- a/third_party/blink/renderer/modules/nfc/nfc_proxy.h
+++ b/third_party/blink/renderer/modules/nfc/nfc_proxy.h
@@ -9,6 +9,8 @@
 #include "mojo/public/cpp/bindings/remote.h"
 #include "services/device/public/mojom/nfc.mojom-blink.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
 #include "third_party/blink/renderer/platform/supplementable.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 
@@ -25,7 +27,6 @@
                                       public Supplement<LocalDOMWindow>,
                                       public device::mojom::blink::NFCClient {
   USING_GARBAGE_COLLECTED_MIXIN(NFCProxy);
-  USING_PRE_FINALIZER(NFCProxy, Dispose);
 
  public:
   static const char kSupplementName[];
@@ -34,8 +35,6 @@
   explicit NFCProxy(LocalDOMWindow&);
   ~NFCProxy() override;
 
-  void Dispose();
-
   void Trace(Visitor*) override;
 
   // There is no matching RemoveWriter() method because writers are
@@ -83,7 +82,10 @@
   WriterSet writers_;
 
   mojo::Remote<device::mojom::blink::NFC> nfc_remote_;
-  mojo::Receiver<device::mojom::blink::NFCClient> client_receiver_;
+  HeapMojoReceiver<device::mojom::blink::NFCClient,
+                   NFCProxy,
+                   HeapMojoWrapperMode::kWithoutContextObserver>
+      client_receiver_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webaudio/audio_context.cc b/third_party/blink/renderer/modules/webaudio/audio_context.cc
index 8f982aad..6eb1a85 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_context.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_context.cc
@@ -131,6 +131,7 @@
                            base::Optional<float> sample_rate)
     : BaseAudioContext(&document, kRealtimeContext),
       context_id_(g_context_id++),
+      audio_context_manager_(document.ToExecutionContext()),
       keep_alive_(PERSISTENT_FROM_HERE, this) {
   destination_node_ =
       RealtimeAudioDestinationNode::Create(this, latency_hint, sample_rate);
@@ -168,7 +169,6 @@
           destination()->GetAudioDestinationHandler());
   base_latency_ = destination_handler.GetFramesPerBuffer() /
                   static_cast<double>(sampleRate());
-
 }
 
 void AudioContext::Uninitialize() {
@@ -196,6 +196,7 @@
 
 void AudioContext::Trace(Visitor* visitor) {
   visitor->Trace(close_resolver_);
+  visitor->Trace(audio_context_manager_);
   BaseAudioContext::Trace(visitor);
 }
 
@@ -606,7 +607,7 @@
   DCHECK(IsMainThread());
 
   EnsureAudioContextManagerService();
-  if (audio_context_manager_)
+  if (audio_context_manager_.is_bound())
     audio_context_manager_->AudioContextAudiblePlaybackStarted(context_id_);
 }
 
@@ -697,17 +698,18 @@
   DCHECK(IsMainThread());
 
   EnsureAudioContextManagerService();
-  if (audio_context_manager_)
+  if (audio_context_manager_.is_bound())
     audio_context_manager_->AudioContextAudiblePlaybackStopped(context_id_);
 }
 
 void AudioContext::EnsureAudioContextManagerService() {
-  if (audio_context_manager_ || !GetDocument())
+  if (audio_context_manager_.is_bound() || !GetDocument())
     return;
 
   GetDocument()->GetFrame()->GetBrowserInterfaceBroker().GetInterface(
       mojo::GenericPendingReceiver(
-          audio_context_manager_.BindNewPipeAndPassReceiver()));
+          audio_context_manager_.BindNewPipeAndPassReceiver(
+              GetDocument()->GetTaskRunner(TaskType::kInternalMedia))));
 
   audio_context_manager_.set_disconnect_handler(
       WTF::Bind(&AudioContext::OnAudioContextManagerServiceConnectionError,
diff --git a/third_party/blink/renderer/modules/webaudio/audio_context.h b/third_party/blink/renderer/modules/webaudio/audio_context.h
index 10630b0..489e97515 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_context.h
+++ b/third_party/blink/renderer/modules/webaudio/audio_context.h
@@ -5,7 +5,6 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_AUDIO_CONTEXT_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_AUDIO_CONTEXT_H_
 
-#include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/blink/public/mojom/webaudio/audio_context_manager.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
@@ -14,6 +13,8 @@
 #include "third_party/blink/renderer/modules/webaudio/base_audio_context.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/heap/self_keep_alive.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
 
 namespace blink {
 
@@ -192,7 +193,9 @@
   double base_latency_ = 0;
 
   // AudioContextManager for reporting audibility.
-  mojo::Remote<mojom::blink::AudioContextManager> audio_context_manager_;
+  HeapMojoRemote<mojom::blink::AudioContextManager,
+                 HeapMojoWrapperMode::kWithoutContextObserver>
+      audio_context_manager_;
 
   // Keeps track if the output of this destination was audible, before the
   // current rendering quantum.  Used for recording "playback" time.
diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
index 9f67d55..c3d17c4 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
+++ b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
@@ -8,14 +8,14 @@
 #include "third_party/blink/renderer/bindings/core/v8/script_function.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_dom_exception.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_video_encoder_encode_options.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_video_encoder_init.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_video_encoder_tune_options.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/streams/readable_stream.h"
 #include "third_party/blink/renderer/core/streams/writable_stream.h"
 #include "third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.h"
 #include "third_party/blink/renderer/modules/webcodecs/encoded_video_metadata.h"
-#include "third_party/blink/renderer/modules/webcodecs/video_encoder_encode_options.h"
-#include "third_party/blink/renderer/modules/webcodecs/video_encoder_init.h"
-#include "third_party/blink/renderer/modules/webcodecs/video_encoder_tune_options.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 
diff --git a/third_party/blink/renderer/modules/webcodecs/video_frame.cc b/third_party/blink/renderer/modules/webcodecs/video_frame.cc
index 9a8890e..0a1f7ea 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_frame.cc
+++ b/third_party/blink/renderer/modules/webcodecs/video_frame.cc
@@ -8,9 +8,9 @@
 
 #include "media/base/video_frame.h"
 #include "media/base/video_frame_metadata.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_video_frame_init.h"
 #include "third_party/blink/renderer/core/html/canvas/image_data.h"
 #include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
-#include "third_party/blink/renderer/modules/webcodecs/video_frame_init.h"
 #include "third_party/blink/renderer/platform/graphics/image.h"
 #include "third_party/libyuv/include/libyuv.h"
 
diff --git a/third_party/blink/renderer/platform/exported/web_runtime_features.cc b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
index 6bfd9fd..39af902 100644
--- a/third_party/blink/renderer/platform/exported/web_runtime_features.cc
+++ b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
@@ -167,10 +167,6 @@
   return RuntimeEnabledFeatures::CompositedSelectionUpdateEnabled();
 }
 
-void WebRuntimeFeatures::EnableCompositorTouchAction(bool enable) {
-  RuntimeEnabledFeatures::SetCompositorTouchActionEnabled(enable);
-}
-
 void WebRuntimeFeatures::EnableCSSHexAlphaColor(bool enable) {
   RuntimeEnabledFeatures::SetCSSHexAlphaColorEnabled(enable);
 }
diff --git a/third_party/blink/renderer/platform/graphics/graphics_context.cc b/third_party/blink/renderer/platform/graphics/graphics_context.cc
index 8c471fe..f800478 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_context.cc
+++ b/third_party/blink/renderer/platform/graphics/graphics_context.cc
@@ -322,11 +322,10 @@
 
 namespace {
 
-int AdjustedFocusRingOffset(int offset, int default_offset, int width) {
+int AdjustedFocusRingOffset(int offset, int width) {
   if (::features::IsFormControlsRefreshEnabled()) {
-    // For FormControlsRefresh the focus ring has a default offset that
-    // depends on the element type.
-    return default_offset;
+    // For FormControlsRefresh just use the value of outline-offset.
+    return offset;
   }
 
 #if defined(OS_MACOSX)
@@ -339,19 +338,16 @@
 }  // namespace
 
 int GraphicsContext::FocusRingOutsetExtent(int offset,
-                                           int default_offset,
                                            int width) {
   // Unlike normal outlines (whole width is outside of the offset), focus
   // rings can be drawn with the center of the path aligned with the offset, so
   // only half of the width is outside of the offset.
   if (::features::IsFormControlsRefreshEnabled()) {
     // For FormControlsRefresh 2/3 of the width is outside of the offset.
-    return AdjustedFocusRingOffset(offset, default_offset, width) +
-           std::ceil(width / 3.f) * 2;
+    return AdjustedFocusRingOffset(offset, width) + std::ceil(width / 3.f) * 2;
   }
 
-  return AdjustedFocusRingOffset(offset, /*default_offset=*/0, width) +
-         (width + 1) / 2;
+  return AdjustedFocusRingOffset(offset, width) + (width + 1) / 2;
 }
 
 void GraphicsContext::DrawFocusRingPath(const SkPath& path,
@@ -400,8 +396,7 @@
   if (!::features::IsFormControlsRefreshEnabled()) {
     // For FormControlsRefresh the offset is already adjusted by
     // GraphicsContext::DrawFocusRing.
-    offset =
-        AdjustedFocusRingOffset(offset, /*default_offset=*/0, std::ceil(width));
+    offset = AdjustedFocusRingOffset(offset, std::ceil(width));
   }
   for (unsigned i = 0; i < rect_count; i++) {
     SkIRect r = rects[i];
@@ -427,7 +422,6 @@
 void GraphicsContext::DrawFocusRing(const Vector<IntRect>& rects,
                                     float width,
                                     int offset,
-                                    int default_offset,
                                     float border_radius,
                                     float min_border_width,
                                     const Color& color) {
@@ -436,7 +430,7 @@
     const float first_border_width = (width / 3) * 2;
     const float second_border_width = width - first_border_width;
 
-    offset = AdjustedFocusRingOffset(offset, default_offset, std::ceil(width));
+    offset = AdjustedFocusRingOffset(offset, std::ceil(width));
     // How much space the focus ring would like to take from the actual border.
     const float inside_border_width = 1;
     if (min_border_width >= inside_border_width) {
diff --git a/third_party/blink/renderer/platform/graphics/graphics_context.h b/third_party/blink/renderer/platform/graphics/graphics_context.h
index 88784e6..af2ca36c 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_context.h
+++ b/third_party/blink/renderer/platform/graphics/graphics_context.h
@@ -362,7 +362,6 @@
   void DrawFocusRing(const Vector<IntRect>&,
                      float width,
                      int offset,
-                     int default_offset,
                      float border_radius,
                      float min_border_width,
                      const Color&);
@@ -421,7 +420,7 @@
                                           FloatPoint& p2,
                                           float stroke_width);
 
-  static int FocusRingOutsetExtent(int offset, int default_offset, int width);
+  static int FocusRingOutsetExtent(int offset, int width);
 
   void SetInDrawingRecorder(bool);
   bool InDrawingRecorder() const { return in_drawing_recorder_; }
diff --git a/third_party/blink/renderer/platform/image-decoders/image_decoder.cc b/third_party/blink/renderer/platform/image-decoders/image_decoder.cc
index fa3876e5..f677b4003 100644
--- a/third_party/blink/renderer/platform/image-decoders/image_decoder.cc
+++ b/third_party/blink/renderer/platform/image-decoders/image_decoder.cc
@@ -202,8 +202,8 @@
     return kUndefinedFormat;
 
   // Attempt to sniff whether a WebP image is using a lossy or lossless
-  // compression algorithm. Note: Will return kUndefinedFormat in the case of an
-  // animated WebP image.
+  // compression algorithm. Note: Will return kWebPAnimationFormat in the case
+  // of an animated WebP image.
   size_t available_data = image_data ? image_data->size() : 0;
   if (EqualIgnoringASCIICase(mime_type, "image/webp") && available_data >= 16) {
     // Attempt to sniff only 8 bytes (the second half of the first 16). This
diff --git a/third_party/blink/renderer/platform/network/http_parsers.cc b/third_party/blink/renderer/platform/network/http_parsers.cc
index 4921866..c9708cc 100644
--- a/third_party/blink/renderer/platform/network/http_parsers.cc
+++ b/third_party/blink/renderer/platform/network/http_parsers.cc
@@ -36,6 +36,9 @@
 #include "net/http/http_content_disposition.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_util.h"
+#include "services/network/public/cpp/content_security_policy/content_security_policy.h"
+#include "services/network/public/cpp/features.h"
+#include "services/network/public/mojom/content_security_policy.mojom-blink.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
 #include "third_party/blink/renderer/platform/network/header_field_tokenizer.h"
@@ -50,6 +53,69 @@
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "third_party/blink/renderer/platform/wtf/wtf.h"
 
+// We would like finding a way to convert from/to blink type automatically.
+// The following attempt has been withdrawn:
+// https://chromium-review.googlesource.com/c/chromium/src/+/2126933/7
+namespace network {
+namespace mojom {
+
+blink::CSPSourcePtr ConvertToBlink(CSPSourcePtr source) {
+  return blink::CSPSource::New(
+      String::FromUTF8(source->scheme), String::FromUTF8(source->host),
+      source->port, String::FromUTF8(source->path), source->is_host_wildcard,
+      source->is_port_wildcard);
+}
+
+blink::CSPSourceListPtr ConvertToBlink(CSPSourceListPtr source_list) {
+  WTF::Vector<blink::CSPSourcePtr> sources;
+  for (auto& it : source_list->sources)
+    sources.push_back(ConvertToBlink(std::move(it)));
+
+  return blink::CSPSourceList::New(std::move(sources), source_list->allow_self,
+                                   source_list->allow_star,
+                                   source_list->allow_response_redirects);
+}
+
+blink::CSPDirectiveName ConvertToBlink(CSPDirectiveName name) {
+  return static_cast<blink::CSPDirectiveName>(name);
+}
+
+blink::ContentSecurityPolicyHeaderPtr ConvertToBlink(
+    ContentSecurityPolicyHeaderPtr header) {
+  return blink::ContentSecurityPolicyHeader::New(
+      String::FromUTF8(header->header_value), header->type, header->source);
+}
+
+blink::ContentSecurityPolicyPtr ConvertToBlink(
+    ContentSecurityPolicyPtr policy_in) {
+  auto policy = blink::ContentSecurityPolicy::New();
+
+  policy->header = ConvertToBlink(std::move(policy_in->header));
+  policy->use_reporting_api = policy_in->use_reporting_api;
+
+  for (auto& directive : policy_in->directives) {
+    policy->directives.insert(ConvertToBlink(directive.first),
+                              ConvertToBlink(std::move(directive.second)));
+  }
+
+  for (auto& endpoint : policy_in->report_endpoints)
+    policy->report_endpoints.push_back(String::FromUTF8(endpoint));
+
+  return policy;
+}
+
+WTF::Vector<blink::ContentSecurityPolicyPtr> ConvertToBlink(
+    std::vector<ContentSecurityPolicyPtr> policies) {
+  WTF::Vector<blink::ContentSecurityPolicyPtr> blink_policies;
+  for (auto& policy : policies)
+    blink_policies.push_back(ConvertToBlink(std::move(policy)));
+
+  return blink_policies;
+}
+
+}  // namespace mojom
+}  // namespace network
+
 namespace blink {
 
 namespace {
@@ -600,4 +666,21 @@
   return headers;
 }
 
+// This function is simply calling network::AddContentSecurityPolicyFromHeaders
+// and convert from/to blink types. It is used for navigation requests served by
+// a ServiceWorker. It is tested by FetchResponseDataTest.ContentSecurityPolicy.
+WTF::Vector<network::mojom::blink::ContentSecurityPolicyPtr>
+ParseContentSecurityPolicy(const String& raw_headers, const KURL& url) {
+  if (!base::FeatureList::IsEnabled(
+          network::features::kOutOfBlinkFrameAncestors)) {
+    return {};
+  }
+
+  auto headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+      net::HttpUtil::AssembleRawHeaders(raw_headers.Latin1()));
+  std::vector<network::mojom::ContentSecurityPolicyPtr> policies;
+  network::AddContentSecurityPolicyFromHeaders(*headers, url, &policies);
+  return network::mojom::ConvertToBlink(std::move(policies));
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/network/http_parsers.h b/third_party/blink/renderer/platform/network/http_parsers.h
index ab4c4758..156aea7 100644
--- a/third_party/blink/renderer/platform/network/http_parsers.h
+++ b/third_party/blink/renderer/platform/network/http_parsers.h
@@ -33,6 +33,7 @@
 
 #include "base/optional.h"
 #include "base/time/time.h"
+#include "services/network/public/mojom/content_security_policy.mojom-blink-forward.h"
 #include "third_party/blink/renderer/platform/network/parsed_content_type.h"
 #include "third_party/blink/renderer/platform/network/server_timing_header.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
@@ -49,6 +50,7 @@
 
 class HTTPHeaderMap;
 class ResourceResponse;
+class KURL;
 
 enum ContentTypeOptionsDisposition {
   kContentTypeOptionsNone,
@@ -141,6 +143,13 @@
 
 PLATFORM_EXPORT std::unique_ptr<ServerTimingHeaderVector>
 ParseServerTimingHeader(const String&);
+
+// Parse CSP ContentSecurityPolicy from raw headers.
+// This is the same as network::AddContentSecurityPolicyFromHeaders(), but using
+// blink types.
+PLATFORM_EXPORT WTF::Vector<network::mojom::blink::ContentSecurityPolicyPtr>
+ParseContentSecurityPolicy(const String& raw_headers, const KURL& url);
+
 }  // namespace blink
 
 #endif
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 976a0ec..5f886c4 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -294,7 +294,7 @@
     },
     {
       name: "CaptureTimeInCsrc",
-      status: "test",
+      status: "stable",
     },
     {
       name: "ClickPointerEvent",
@@ -321,10 +321,6 @@
       status: {"Android": "stable"},
     },
     {
-      name: "CompositorTouchAction",
-      status: "test",
-    },
-    {
       name: "ComputedAccessibilityInfo",
       status: "experimental",
     },
diff --git a/third_party/blink/renderer/platform/scheduler/BUILD.gn b/third_party/blink/renderer/platform/scheduler/BUILD.gn
index 0d511400..9e1692a6 100644
--- a/third_party/blink/renderer/platform/scheduler/BUILD.gn
+++ b/third_party/blink/renderer/platform/scheduler/BUILD.gn
@@ -99,8 +99,6 @@
     "main_thread/page_visibility_state.h",
     "main_thread/pending_user_input.cc",
     "main_thread/pending_user_input.h",
-    "main_thread/prioritize_compositing_after_input_experiment.cc",
-    "main_thread/prioritize_compositing_after_input_experiment.h",
     "main_thread/queueing_time_estimator.cc",
     "main_thread/queueing_time_estimator.h",
     "main_thread/render_widget_signals.cc",
diff --git a/third_party/blink/renderer/platform/scheduler/common/features.h b/third_party/blink/renderer/platform/scheduler/common/features.h
index 6f12fc5f..ff3089f2 100644
--- a/third_party/blink/renderer/platform/scheduler/common/features.h
+++ b/third_party/blink/renderer/platform/scheduler/common/features.h
@@ -25,33 +25,6 @@
 
 // COMPOSITING PRIORITY EXPERIMENT CONTROLS
 
-// Enables experiment to increase priority of the compositing tasks during
-// input handling. Other features in this section do not have any effect
-// when this feature is disabled.
-const base::Feature kPrioritizeCompositingAfterInput{
-    "BlinkSchedulerPrioritizeCompositingAfterInput",
-    base::FEATURE_DISABLED_BY_DEFAULT};
-
-// Use kHighestPriority for compositing tasks during the experiment.
-// kHighPriority is used otherwise.
-const base::Feature kHighestPriorityForCompositingAfterInput{
-    "BlinkSchedulerHighestPriorityForCompostingAfterInput",
-    base::FEATURE_DISABLED_BY_DEFAULT};
-
-// If enabled, MainFrameSchedulerImpl::OnRequestMainFrameForInput is used as
-// triggering signal for the experiment. If disabled, the presence of an input
-// task is used as trigger.
-const base::Feature kUseExplicitSignalForTriggeringCompositingPrioritization{
-    "BlinkSchedulerUseExplicitSignalForTriggeringCompositingPrioritization",
-    base::FEATURE_DISABLED_BY_DEFAULT};
-
-// If enabled, the increased priority continues until we get the appropriate
-// number of WillBeginMainFrame signals. If disabled, the priority is increased
-// for the fixed number of compositing tasks.
-const base::Feature kUseWillBeginMainFrameForCompositingPrioritization{
-    "BlinkSchedulerUseWillBeginMainFrameForCompositingPrioritization",
-    base::FEATURE_DISABLED_BY_DEFAULT};
-
 // If enabled, the compositor will always be set to kVeryHighPriority if it
 // is not already set to kHighestPriority.
 const base::Feature kVeryHighPriorityForCompositingAlways{
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
index 9bf6ae8..08ce18f 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
@@ -395,12 +395,6 @@
           main_thread_scheduler_impl,
           &main_thread_scheduler_impl->tracing_controller_,
           YesNoStateToString),
-      have_seen_a_begin_main_frame(
-          false,
-          "Scheduler.HasSeenBeginMainFrame",
-          main_thread_scheduler_impl,
-          &main_thread_scheduler_impl->tracing_controller_,
-          YesNoStateToString),
       have_reported_blocking_intervention_in_current_policy(
           false,
           "Scheduler.HasReportedBlockingInterventionInCurrentPolicy",
@@ -419,12 +413,6 @@
           main_thread_scheduler_impl,
           &main_thread_scheduler_impl->tracing_controller_,
           YesNoStateToString),
-      begin_frame_not_expected_soon(
-          false,
-          "Scheduler.BeginFrameNotExpectedSoon",
-          main_thread_scheduler_impl,
-          &main_thread_scheduler_impl->tracing_controller_,
-          YesNoStateToString),
       in_idle_period_for_testing(
           false,
           "Scheduler.InIdlePeriod",
@@ -486,8 +474,12 @@
       max_virtual_time_task_starvation_count(0),
       virtual_time_stopped(false),
       nested_runloop(false),
-      compositing_experiment(main_thread_scheduler_impl),
-      should_prioritize_compositing(false),
+      prioritize_compositing_after_input(
+          false,
+          "Scheduler.PrioritizeCompositingAfterInput",
+          main_thread_scheduler_impl,
+          &main_thread_scheduler_impl->tracing_controller_,
+          YesNoStateToString),
       compositor_priority_experiments(main_thread_scheduler_impl),
       main_thread_compositing_is_fast(false) {}
 
@@ -817,6 +809,9 @@
 }
 
 void MainThreadSchedulerImpl::WillBeginFrame(const viz::BeginFrameArgs& args) {
+  // TODO(crbug/1068426): Figure out when and if |UpdatePolicy| should be called
+  //  and, if needed, remove the call to it from
+  //  |SetPrioritizeCompositingAfterInput|.
   TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
                "MainThreadSchedulerImpl::WillBeginFrame", "args",
                args.AsValue());
@@ -827,14 +822,12 @@
   EndIdlePeriod();
   main_thread_only().estimated_next_frame_begin =
       args.frame_time + args.interval;
-  main_thread_only().have_seen_a_begin_main_frame = true;
-  main_thread_only().begin_frame_not_expected_soon = false;
   main_thread_only().compositor_frame_interval = args.interval;
   {
     base::AutoLock lock(any_thread_lock_);
     any_thread().begin_main_frame_on_critical_path = args.on_critical_path;
   }
-  main_thread_only().compositing_experiment.OnWillBeginMainFrame();
+  SetPrioritizeCompositingAfterInput(false);
   main_thread_only().compositor_priority_experiments.OnWillBeginMainFrame();
 }
 
@@ -858,13 +851,13 @@
 }
 
 void MainThreadSchedulerImpl::BeginFrameNotExpectedSoon() {
+  // TODO(crbug/1068426): Should this call |UpdatePolicy|?
   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
                "MainThreadSchedulerImpl::BeginFrameNotExpectedSoon");
   helper_.CheckOnValidThread();
   if (helper_.IsShutdown())
     return;
 
-  main_thread_only().begin_frame_not_expected_soon = true;
   idle_helper_.EnableLongIdlePeriod();
   {
     base::AutoLock lock(any_thread_lock_);
@@ -1000,7 +993,7 @@
 }
 
 void MainThreadSchedulerImpl::OnMainFrameRequestedForInput() {
-  main_thread_only().compositing_experiment.OnMainFrameRequestedForInput();
+  SetPrioritizeCompositingAfterInput(true);
 }
 
 bool MainThreadSchedulerImpl::SchedulerKeepActive() {
@@ -1498,10 +1491,9 @@
       NOTREACHED();
   }
 
-  if (main_thread_only().should_prioritize_compositing) {
+  if (main_thread_only().prioritize_compositing_after_input) {
     new_policy.compositor_priority() =
-        main_thread_only()
-            .compositing_experiment.GetIncreasedCompositingPriority();
+        base::sequence_manager::TaskQueue::QueuePriority::kVeryHighPriority;
   } else if (scheduling_settings_
                  .prioritize_compositing_and_loading_during_early_loading &&
              current_use_case() == UseCase::kEarlyLoading) {
@@ -1978,8 +1970,6 @@
       main_thread_only().has_visible_render_widget_with_touch_handler);
   state->SetString("current_use_case",
                    UseCaseToString(main_thread_only().current_use_case));
-  state->SetBoolean("begin_frame_not_expected_soon",
-                    main_thread_only().begin_frame_not_expected_soon);
   state->SetBoolean(
       "compositor_will_send_main_frame_not_expected",
       main_thread_only().compositor_will_send_main_frame_not_expected);
@@ -1989,8 +1979,6 @@
                    IdleHelper::IdlePeriodStateToString(
                        idle_helper_.SchedulerIdlePeriodState()));
   state->SetBoolean("renderer_hidden", main_thread_only().renderer_hidden);
-  state->SetBoolean("have_seen_a_begin_main_frame",
-                    main_thread_only().have_seen_a_begin_main_frame);
   state->SetBoolean("waiting_for_contentful_paint",
                     any_thread().waiting_for_contentful_paint);
   state->SetBoolean("waiting_for_meaningful_paint",
@@ -2244,7 +2232,6 @@
   any_thread().waiting_for_meaningful_paint = true;
   any_thread().have_seen_input_since_navigation = false;
   main_thread_only().idle_time_estimator.Clear();
-  main_thread_only().have_seen_a_begin_main_frame = false;
   main_thread_only().have_reported_blocking_intervention_since_navigation =
       false;
   for (PageSchedulerImpl* page_scheduler : main_thread_only().page_schedulers) {
@@ -2484,8 +2471,6 @@
         queue.get(), task_timing->start_time(), task_timing->end_time());
   }
 
-  main_thread_only().compositing_experiment.OnTaskCompleted(queue.get());
-
   // TODO(altimin): Per-page metrics should also be considered.
   main_thread_only().metrics_helper.RecordTaskMetrics(queue.get(), task,
                                                       *task_timing);
@@ -2769,14 +2754,14 @@
   return scheduling_settings_;
 }
 
-void MainThreadSchedulerImpl::SetShouldPrioritizeCompositing(
-    bool should_prioritize_compositing) {
-  if (main_thread_only().should_prioritize_compositing ==
-      should_prioritize_compositing) {
+void MainThreadSchedulerImpl::SetPrioritizeCompositingAfterInput(
+    bool prioritize_compositing_after_input) {
+  if (main_thread_only().prioritize_compositing_after_input ==
+      prioritize_compositing_after_input) {
     return;
   }
-  main_thread_only().should_prioritize_compositing =
-      should_prioritize_compositing;
+  main_thread_only().prioritize_compositing_after_input =
+      prioritize_compositing_after_input;
   UpdatePolicy();
 }
 
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
index 5914b7f..88978fe 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
@@ -41,7 +41,6 @@
 #include "third_party/blink/renderer/platform/scheduler/main_thread/non_waking_time_domain.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/pending_user_input.h"
-#include "third_party/blink/renderer/platform/scheduler/main_thread/prioritize_compositing_after_input_experiment.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/queueing_time_estimator.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/render_widget_signals.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/use_case.h"
@@ -396,7 +395,8 @@
 
   const SchedulingSettings& scheduling_settings() const;
 
-  void SetShouldPrioritizeCompositing(bool should_prioritize_compositing);
+  void SetPrioritizeCompositingAfterInput(
+      bool prioritize_compositing_after_input);
 
   void OnCompositorPriorityExperimentUpdateCompositorPriority();
 
@@ -885,16 +885,12 @@
     TraceableState<bool, TracingCategoryName::kDefault>
         blocking_input_expected_soon;
     TraceableState<bool, TracingCategoryName::kDebug>
-        have_seen_a_begin_main_frame;
-    TraceableState<bool, TracingCategoryName::kDebug>
         have_reported_blocking_intervention_in_current_policy;
     TraceableState<bool, TracingCategoryName::kDebug>
         have_reported_blocking_intervention_since_navigation;
     TraceableState<bool, TracingCategoryName::kDebug>
         has_visible_render_widget_with_touch_handler;
     TraceableState<bool, TracingCategoryName::kDebug>
-        begin_frame_not_expected_soon;
-    TraceableState<bool, TracingCategoryName::kDebug>
         in_idle_period_for_testing;
     TraceableState<bool, TracingCategoryName::kInfo> use_virtual_time;
     TraceableState<bool, TracingCategoryName::kTopLevel> is_audio_playing;
@@ -907,8 +903,8 @@
     base::TimeTicks background_status_changed_at;
     HashSet<PageSchedulerImpl*> page_schedulers;  // Not owned.
     base::ObserverList<RAILModeObserver>::Unchecked
-        rail_mode_observers;                                      // Not owned.
-    WakeUpBudgetPool* wake_up_budget_pool;                        // Not owned.
+        rail_mode_observers;                // Not owned.
+    WakeUpBudgetPool* wake_up_budget_pool;  // Not owned.
     MainThreadMetricsHelper metrics_helper;
     TraceableState<WebRendererProcessType, TracingCategoryName::kTopLevel>
         process_type;
@@ -948,9 +944,11 @@
     // True if a nested RunLoop is running.
     bool nested_runloop;
 
-    // High-priority for compositing events after input experiment.
-    PrioritizeCompositingAfterInputExperiment compositing_experiment;
-    bool should_prioritize_compositing;
+    // High-priority for compositing events after input. This will cause
+    // compositing events get a higher priority until the start of the next
+    // animation frame.
+    TraceableState<bool, TracingCategoryName::kDefault>
+        prioritize_compositing_after_input;
 
     // List of callbacks to execute after the current task.
     WTF::Vector<base::OnceClosure> on_task_completion_callbacks;
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
index 1f4d240..b8cc31b 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
@@ -323,8 +323,7 @@
     feature_list_.InitWithFeatures(features_to_enable, features_to_disable);
   }
 
-  MainThreadSchedulerImplTest()
-      : MainThreadSchedulerImplTest({}, {kPrioritizeCompositingAfterInput}) {}
+  MainThreadSchedulerImplTest() : MainThreadSchedulerImplTest({}, {}) {}
 
   ~MainThreadSchedulerImplTest() override = default;
 
@@ -376,7 +375,7 @@
     loading_control_task_runner_ =
         main_frame_scheduler_->FrameTaskQueueControllerForTest()
             ->GetTaskQueue(
-             main_frame_scheduler_->LoadingControlTaskQueueTraits())
+                main_frame_scheduler_->LoadingControlTaskQueueTraits())
             ->task_runner();
     timer_task_runner_ = timer_task_queue()->task_runner();
     find_in_page_task_runner_ = main_frame_scheduler_->GetTaskRunner(
@@ -386,15 +385,15 @@
   TaskQueue* loading_task_queue() {
     auto queue_traits = FrameSchedulerImpl::LoadingTaskQueueTraits();
     return main_frame_scheduler_->FrameTaskQueueControllerForTest()
-        ->GetTaskQueue(queue_traits).get();
+        ->GetTaskQueue(queue_traits)
+        .get();
   }
 
   TaskQueue* timer_task_queue() {
     auto* frame_task_queue_controller =
         main_frame_scheduler_->FrameTaskQueueControllerForTest();
     return frame_task_queue_controller
-        ->GetTaskQueue(
-            main_frame_scheduler_->ThrottleableTaskQueueTraits())
+        ->GetTaskQueue(main_frame_scheduler_->ThrottleableTaskQueueTraits())
         .get();
   }
 
@@ -645,18 +644,10 @@
     return scheduler_->main_thread_only().current_policy.rail_mode();
   }
 
-  bool BeginFrameNotExpectedSoon() {
-    return scheduler_->main_thread_only().begin_frame_not_expected_soon;
-  }
-
   bool BlockingInputExpectedSoon() {
     return scheduler_->main_thread_only().blocking_input_expected_soon;
   }
 
-  bool HaveSeenABeginMainframe() {
-    return scheduler_->main_thread_only().have_seen_a_begin_main_frame;
-  }
-
   base::TimeTicks EstimatedNextFrameBegin() {
     return scheduler_->main_thread_only().estimated_next_frame_begin;
   }
@@ -1326,9 +1317,7 @@
 
 class DefaultUseCaseTest : public MainThreadSchedulerImplTest {
  public:
-  DefaultUseCaseTest() : MainThreadSchedulerImplTest({}, {}) {
-    initially_ensure_usecase_none_ = false;
-  }
+  DefaultUseCaseTest() { initially_ensure_usecase_none_ = false; }
 };
 
 TEST_F(DefaultUseCaseTest, InitiallyInEarlyLoadingUseCase) {
@@ -2868,7 +2857,6 @@
   scheduler_->AddRAILModeObserver(&observer);
   EXPECT_CALL(observer, OnRAILModeChanged(RAILMode::kAnimation)).Times(0);
 
-  EXPECT_FALSE(BeginFrameNotExpectedSoon());
   EXPECT_EQ(UseCase::kNone, ForceUpdatePolicyAndGetCurrentUseCase());
   EXPECT_EQ(RAILMode::kAnimation, GetRAILMode());
   scheduler_->RemoveRAILModeObserver(&observer);
@@ -3399,18 +3387,7 @@
   EXPECT_EQ(base::Time::Now(), base::Time::FromJsTime(1000000.0));
 }
 
-class CompositingExperimentWithExplicitSignalsTest
-    : public MainThreadSchedulerImplTest {
- public:
-  CompositingExperimentWithExplicitSignalsTest()
-      : MainThreadSchedulerImplTest(
-            {kPrioritizeCompositingAfterInput,
-             kUseExplicitSignalForTriggeringCompositingPrioritization,
-             kUseWillBeginMainFrameForCompositingPrioritization},
-            {}) {}
-};
-
-TEST_F(CompositingExperimentWithExplicitSignalsTest, CompositingAfterInput) {
+TEST_F(MainThreadSchedulerImplTest, CompositingAfterInput) {
   Vector<String> run_order;
   PostTestTasks(&run_order, "P1 T1 C1");
   base::RunLoop().RunUntilIdle();
@@ -3435,25 +3412,6 @@
   run_order.clear();
 }
 
-class CompositingExperimentWithImplicitSignalsTest
-    : public MainThreadSchedulerImplTest {
- public:
-  CompositingExperimentWithImplicitSignalsTest()
-      : MainThreadSchedulerImplTest(
-            {kPrioritizeCompositingAfterInput},
-            {kHighestPriorityForCompositingAfterInput,
-             kUseExplicitSignalForTriggeringCompositingPrioritization,
-             kUseWillBeginMainFrameForCompositingPrioritization}) {}
-};
-
-TEST_F(CompositingExperimentWithImplicitSignalsTest, CompositingAfterInput) {
-  Vector<String> run_order;
-  PostTestTasks(&run_order, "T1 C1 C2 P1 P2");
-  base::RunLoop().RunUntilIdle();
-  // One compositing task should be prioritized after input.
-  EXPECT_THAT(run_order, testing::ElementsAre("P1", "P2", "C1", "T1", "C2"));
-}
-
 TEST_F(MainThreadSchedulerImplTest, EQTWithNestedLoop) {
   AdvanceMockTickClockBy(base::TimeDelta::FromMilliseconds(100));
 
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/prioritize_compositing_after_input_experiment.cc b/third_party/blink/renderer/platform/scheduler/main_thread/prioritize_compositing_after_input_experiment.cc
deleted file mode 100644
index 3b660d3..0000000
--- a/third_party/blink/renderer/platform/scheduler/main_thread/prioritize_compositing_after_input_experiment.cc
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright 2018 The Chromium 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 "third_party/blink/renderer/platform/scheduler/main_thread/prioritize_compositing_after_input_experiment.h"
-
-#include "base/metrics/field_trial_params.h"
-#include "base/strings/string_number_conversions.h"
-#include "third_party/blink/renderer/platform/scheduler/common/features.h"
-#include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h"
-#include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h"
-
-namespace blink {
-namespace scheduler {
-
-namespace {
-
-// Prioritize compositing after input trial.
-constexpr const char kPrioritizeCompositingAfterInputTrial[] =
-    "BlinkSchedulerPrioritizeCompositingAfterInput";
-constexpr const char kNumberOfCompositingTasksToPrioritizeAfterInputParam[] =
-    "number_of_tasks";
-
-constexpr int kDefaultNumberOfTasksToPrioritizeAfterInput = 1;
-
-int GetNumberOfCompositingTasksToPrioritizeAfterInput() {
-  if (!base::FeatureList::IsEnabled(kPrioritizeCompositingAfterInput))
-    return 0;
-  int number_of_tasks;
-  if (!base::StringToInt(
-          base::GetFieldTrialParamValue(
-              kPrioritizeCompositingAfterInputTrial,
-              kNumberOfCompositingTasksToPrioritizeAfterInputParam),
-          &number_of_tasks)) {
-    return kDefaultNumberOfTasksToPrioritizeAfterInput;
-  }
-  return number_of_tasks;
-}
-
-}  // namespace
-
-PrioritizeCompositingAfterInputExperiment::
-    PrioritizeCompositingAfterInputExperiment(
-        MainThreadSchedulerImpl* scheduler)
-    : scheduler_(scheduler),
-      increased_compositing_priority_(
-          base::FeatureList::IsEnabled(kHighestPriorityForCompositingAfterInput)
-              ? base::sequence_manager::TaskQueue::QueuePriority::
-                    kHighestPriority
-              : base::sequence_manager::TaskQueue::QueuePriority::
-                    kHighPriority),
-      number_of_tasks_to_prioritize_after_input_(
-          GetNumberOfCompositingTasksToPrioritizeAfterInput()),
-      trigger_type_(
-          base::FeatureList::IsEnabled(
-              kUseExplicitSignalForTriggeringCompositingPrioritization)
-              ? TriggerType::kExplicitSignal
-              : TriggerType::kInferredFromInput),
-      stop_signal_type_(base::FeatureList::IsEnabled(
-                            kUseWillBeginMainFrameForCompositingPrioritization)
-                            ? StopSignalType::kWillBeginMainFrameSignal
-                            : StopSignalType::kAllCompositingTasks),
-      number_of_tasks_to_prioritize_(0) {}
-
-PrioritizeCompositingAfterInputExperiment::
-    ~PrioritizeCompositingAfterInputExperiment() {}
-
-void PrioritizeCompositingAfterInputExperiment::
-    SetNumberOfCompositingTasksToPrioritize(int number_of_tasks) {
-  number_of_tasks = std::max(number_of_tasks, 0);
-  bool did_prioritize_compositing = number_of_tasks_to_prioritize_ > 0;
-  number_of_tasks_to_prioritize_ = number_of_tasks;
-  bool should_prioritize_compositing = number_of_tasks_to_prioritize_ > 0;
-  if (did_prioritize_compositing != should_prioritize_compositing)
-    scheduler_->SetShouldPrioritizeCompositing(should_prioritize_compositing);
-}
-
-base::sequence_manager::TaskQueue::QueuePriority
-PrioritizeCompositingAfterInputExperiment::GetIncreasedCompositingPriority() {
-  return increased_compositing_priority_;
-}
-
-void PrioritizeCompositingAfterInputExperiment::OnTaskCompleted(
-    MainThreadTaskQueue* queue) {
-  if (!queue)
-    return;
-  if (queue->queue_type() == MainThreadTaskQueue::QueueType::kInput &&
-      trigger_type_ == TriggerType::kInferredFromInput) {
-    SetNumberOfCompositingTasksToPrioritize(
-        number_of_tasks_to_prioritize_after_input_);
-  } else if (queue->queue_type() ==
-                 MainThreadTaskQueue::QueueType::kCompositor &&
-             stop_signal_type_ == StopSignalType::kAllCompositingTasks) {
-    SetNumberOfCompositingTasksToPrioritize(number_of_tasks_to_prioritize_ - 1);
-  }
-}
-
-void PrioritizeCompositingAfterInputExperiment::OnWillBeginMainFrame() {
-  if (stop_signal_type_ != StopSignalType::kWillBeginMainFrameSignal)
-    return;
-  SetNumberOfCompositingTasksToPrioritize(number_of_tasks_to_prioritize_ - 1);
-}
-
-void PrioritizeCompositingAfterInputExperiment::OnMainFrameRequestedForInput() {
-  if (trigger_type_ != TriggerType::kExplicitSignal)
-    return;
-  SetNumberOfCompositingTasksToPrioritize(
-      number_of_tasks_to_prioritize_after_input_);
-}
-
-}  // namespace scheduler
-}  // namespace blink
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/prioritize_compositing_after_input_experiment.h b/third_party/blink/renderer/platform/scheduler/main_thread/prioritize_compositing_after_input_experiment.h
deleted file mode 100644
index fc74b9c..0000000
--- a/third_party/blink/renderer/platform/scheduler/main_thread/prioritize_compositing_after_input_experiment.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2018 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_MAIN_THREAD_PRIORITIZE_COMPOSITING_AFTER_INPUT_EXPERIMENT_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_MAIN_THREAD_PRIORITIZE_COMPOSITING_AFTER_INPUT_EXPERIMENT_H_
-
-#include "base/task/sequence_manager/task_queue.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-
-namespace blink {
-namespace scheduler {
-
-class MainThreadSchedulerImpl;
-class MainThreadTaskQueue;
-
-class PLATFORM_EXPORT PrioritizeCompositingAfterInputExperiment {
-  DISALLOW_NEW();
-
- public:
-  explicit PrioritizeCompositingAfterInputExperiment(
-      MainThreadSchedulerImpl* scheduler);
-  ~PrioritizeCompositingAfterInputExperiment();
-
-  base::sequence_manager::TaskQueue::QueuePriority
-  GetIncreasedCompositingPriority();
-
-  void OnTaskCompleted(MainThreadTaskQueue* queue);
-
-  void OnWillBeginMainFrame();
-
-  void OnMainFrameRequestedForInput();
-
- private:
-  enum class TriggerType { kExplicitSignal, kInferredFromInput };
-
-  enum class StopSignalType { kAllCompositingTasks, kWillBeginMainFrameSignal };
-
-  void SetNumberOfCompositingTasksToPrioritize(int number_of_tasks);
-
-  MainThreadSchedulerImpl* scheduler_;  // Not owned.
-
-  const base::sequence_manager::TaskQueue::QueuePriority
-      increased_compositing_priority_;
-  const int number_of_tasks_to_prioritize_after_input_;
-  const TriggerType trigger_type_;
-  const StopSignalType stop_signal_type_;
-
-  int number_of_tasks_to_prioritize_;
-};
-
-}  // namespace scheduler
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_MAIN_THREAD_PRIORITIZE_COMPOSITING_AFTER_INPUT_EXPERIMENT_H_
diff --git a/third_party/blink/web_tests/FlagExpectations/composite-after-paint b/third_party/blink/web_tests/FlagExpectations/composite-after-paint
index 695bb1f..02fae9ae 100644
--- a/third_party/blink/web_tests/FlagExpectations/composite-after-paint
+++ b/third_party/blink/web_tests/FlagExpectations/composite-after-paint
@@ -129,3 +129,7 @@
 
 compositing/gestures/gesture-tapHighlight-composited-img.html [ Pass Failure ]
 http/tests/images/image-decode-in-frame.html [ Pass Failure ]
+
+# TODO(iopopesc) these need to be rebaselined for FormControlsRefresh focus ring.
+crbug.com/1035582 virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi.html [ Failure ]
+crbug.com/1035582 compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents.html [ Failure ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 8925094..dd43d69e 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2144,6 +2144,7 @@
 crbug.com/591099 [ Mac ] virtual/form-controls-refresh-disabled/fast/forms/text/text-lineheight-centering.html [ Failure ]
 crbug.com/770971 [ Win7 ] virtual/form-controls-refresh-disabled/fast/forms/suggested-value.html [ Pass Failure ]
 crbug.com/1035582 virtual/form-controls-refresh-disabled/fast/forms/number/number-input-event-composed.html [ Pass Failure ]
+crbug.com/1035582 [ Mac ] virtual/form-controls-refresh-disabled/fast/forms/text/input-readonly-focus-ring.html [ Skip ]
 
 # From never fix tests:
 crbug.com/123456 [ Mac ] virtual/form-controls-refresh-disabled/fast/forms/select-popup/* [ Skip ]
@@ -3150,12 +3151,11 @@
 crbug.com/1053965 external/wpt/css/css-values/ex-unit-004.html [ Failure ]
 
 crbug.com/947951 [ Win ] external/wpt/pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch.html [ Pass Timeout ]
+crbug.com/1067277 external/wpt/css/css-content/element-replacement-on-replaced-element.tentative.html [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 [ Mac10.10 ] external/wpt/storage/estimate-indexeddb.https.any.worker.html [ Failure Timeout ]
 crbug.com/626703 [ Mac10.10 ] external/wpt/fetch/origin/assorted.window.html [ Failure Timeout ]
-crbug.com/626703 [ Linux ] external/wpt/css/css-content/element-replacement-on-replaced-element.tentative.html [ Failure ]
-crbug.com/626703 [ Mac ] external/wpt/css/css-content/element-replacement-on-replaced-element.tentative.html [ Failure ]
-crbug.com/626703 [ Win ] external/wpt/css/css-content/element-replacement-on-replaced-element.tentative.html [ Failure ]
 crbug.com/626703 [ Linux ] external/wpt/css/css-overflow/text-overflow-ellipsis-002.html [ Failure ]
 crbug.com/626703 [ Mac ] external/wpt/css/css-overflow/text-overflow-ellipsis-002.html [ Failure ]
 crbug.com/626703 [ Win ] external/wpt/css/css-overflow/text-overflow-ellipsis-002.html [ Failure ]
@@ -3606,7 +3606,6 @@
 crbug.com/626703 external/wpt/mediacapture-record/MediaRecorder-no-sink.https.html [ Timeout ]
 crbug.com/626703 external/wpt/css/css-text/white-space/trailing-ideographic-space-002.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-text/white-space/trailing-ideographic-space-004.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-fonts/variations/font-descriptor-range-reversed.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-will-change/will-change-abspos-cb-dynamic-001.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-will-change/will-change-abspos-cb-001.html [ Failure ]
 ### See crbug.com/891427 comment near the top of this file:
@@ -5657,9 +5656,6 @@
 crbug.com/959002 crbug.com/959042 http/tests/devtools/elements/styles-4/styles-keyframes.js [ Pass Timeout ]
 crbug.com/959002 crbug.com/959042 http/tests/devtools/elements/styles-4/undo-add-new-rule.js [ Pass Timeout ]
 
-# Sheriff 2019-05-10
-crbug.com/960623 [ Win ] http/tests/misc/resource-timing-sizes-multipart.html [ Pass Failure ]
-
 # This test might need to be removed.
 crbug.com/954349 fast/forms/autofocus-in-sandbox-with-allow-scripts.html [ Timeout ]
 
diff --git a/third_party/blink/web_tests/css3/flexbox/flex-item-stretch-image.html b/third_party/blink/web_tests/css3/flexbox/flex-item-stretch-image.html
new file mode 100644
index 0000000..0b9f6e8
--- /dev/null
+++ b/third_party/blink/web_tests/css3/flexbox/flex-item-stretch-image.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<title>CSS Flexbox: image stretch</title>
+<meta name="assert" content="This test ensures that flexbox stretches a given image
+to fit the size of flexitem according to flex values.">
+<link rel="issue" href="https://bugs.chromium.org/p/chromium/issues/detail?id=721123">
+<link rel="bookmark" href="http://wpt.live/css/css-flexbox/flexitem-stretch-image.html">
+<html>
+<style>
+.flexbox {
+    width: 600px;
+    display: flex;
+    background-color: #aaa;
+    position: relative;
+    min-height: 10px;
+}
+.flexbox > * {
+    margin: 0;
+    border: 0;
+    padding: 0;
+    min-width: 0;
+}
+</style>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../../resources/check-layout-th.js"></script>
+<body onload="checkLayout('.flexbox')">
+<div id=log></div>
+
+<div class="flexbox">
+  <img data-expected-display="block" data-expected-width="345" style="flex: 1 0 auto;" src="../../images/resources/blue-100.png">
+  <img data-expected-display="block" data-expected-width="255" data-expected-height="100" style="flex: 1 0 auto;" src="../../images/resources/green-10.png">
+</div>
+
+</body>
diff --git a/third_party/blink/web_tests/css3/flexbox/nested-orthogonal-flexbox-relayout.html b/third_party/blink/web_tests/css3/flexbox/nested-orthogonal-flexbox-relayout.html
deleted file mode 100644
index 775e93a1..0000000
--- a/third_party/blink/web_tests/css3/flexbox/nested-orthogonal-flexbox-relayout.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!DOCTYPE html>
-<style>
-#column {
-    display: flex;
-    flex-direction: column;
-    border: 5px solid yellow;
-}
-
-#row {
-    display: flex;
-    flex-direction: row;
-    border: 5px solid blue;
-}
-
-.item {
-    border: 5px solid green;
-}
-</style>
-<body>
-<div id="column">
-    <div id="row">
-        <div class="item">This text should not overflow its box</div>
-    </div>
-</div>
-<script>
-var columnBox = document.getElementById("column");
-columnBox.offsetHeight;
-columnBox.style.width = "200px";
-</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_7.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_7.json
index 40c1344..ad686e1f 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_7.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_7.json
@@ -49515,6 +49515,18 @@
      {}
     ]
    ],
+   "css/css-flexbox/nested-orthogonal-flexbox-relayout.html": [
+    [
+     "css/css-flexbox/nested-orthogonal-flexbox-relayout.html",
+     [
+      [
+       "/css/css-flexbox/reference/nested-orthogonal-flexbox-relayout-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-flexbox/order-painting.html": [
     [
      "css/css-flexbox/order-painting.html",
@@ -142979,6 +142991,9 @@
    "css/css-flexbox/reference/negative-margins-001-ref.html": [
     []
    ],
+   "css/css-flexbox/reference/nested-orthogonal-flexbox-relayout-ref.html": [
+    []
+   ],
    "css/css-flexbox/reference/order-painting-ref.html": [
     []
    ],
@@ -385954,6 +385969,10 @@
    "82f5bdbc1569580d5c07b26e402da189287bd870",
    "testharness"
   ],
+  "css/css-flexbox/nested-orthogonal-flexbox-relayout.html": [
+   "ef158c6a4884b8ee2840bafe27e605e618aa8be5",
+   "reftest"
+  ],
   "css/css-flexbox/order-001.htm": [
    "46113dd1d66de6c26b8aa85b299601a240db671b",
    "visual"
@@ -386430,6 +386449,10 @@
    "186c5d130c5ea7facc55ff2ac88b1f1f9edf63af",
    "support"
   ],
+  "css/css-flexbox/reference/nested-orthogonal-flexbox-relayout-ref.html": [
+   "124ecf843c848a71918559c0b853032184a5e5b1",
+   "support"
+  ],
   "css/css-flexbox/reference/order-painting-ref.html": [
    "bf7bc30d017dd4066193b7ed18bdd94dbfeb8de3",
    "support"
@@ -439507,7 +439530,7 @@
    "testharness"
   ],
   "css/cssom/CSSStyleSheet-constructable-expected.txt": [
-   "160bd9243bad6a1f467a343a7e89c77950ae3a79",
+   "2f84a0d554569cea4c707b04371f3f14058e96fe",
    "support"
   ],
   "css/cssom/CSSStyleSheet-constructable-replace-on-regular-sheet.html": [
@@ -439515,7 +439538,7 @@
    "testharness"
   ],
   "css/cssom/CSSStyleSheet-constructable.html": [
-   "fbee4298c1411937f8c45a2f6001ee78dccadbb5",
+   "e6293909c2178966a942abb7e544ff437e6d51d3",
    "testharness"
   ],
   "css/cssom/CSSStyleSheet.html": [
@@ -477391,7 +477414,7 @@
    "testharness"
   ],
   "html/semantics/scripting-1/the-script-element/css-module/import-css-module-basic.html": [
-   "902430d0779e3b9e34f95db1da4d4b96c2b24bbb",
+   "1cb290de3feb584bf9dc63e8090f6b31dd10eeb9",
    "testharness"
   ],
   "html/semantics/scripting-1/the-script-element/css-module/resources/bad-import.css": [
@@ -523751,11 +523774,11 @@
    "testharness"
   ],
   "wasm/jsapi/table/grow-reftypes.tentative.any-expected.txt": [
-   "a4a558a77af42ea786deb6941c6ab0fb595f4d07",
+   "5a04fca68f6843a86f7f5e900a26253a9a08dd5b",
    "support"
   ],
   "wasm/jsapi/table/grow-reftypes.tentative.any.js": [
-   "54141c059ed04e0654fa6be24d2d3f8f01209509",
+   "edfb334991e04d2cabfeeb4426ad053796c67ec5",
    "testharness"
   ],
   "wasm/jsapi/table/grow-reftypes.tentative.any.worker-expected.txt": [
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/nested-orthogonal-flexbox-relayout.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/nested-orthogonal-flexbox-relayout.html
new file mode 100644
index 0000000..ef158c6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/nested-orthogonal-flexbox-relayout.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<title>CSS Flexbox: nested orthogonal children on relayout.</title>
+<link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#flex-direction-property">
+<link rel="match" href="reference/nested-orthogonal-flexbox-relayout-ref.html">
+<meta name="assert" content="This test ensures nested orthogonal flex items get properly relaid out when flexbox changes dimensions."/>
+<style>
+#column {
+  display: flex;
+  flex-direction: column;
+  border: 5px solid yellow;
+}
+
+#row {
+  display: flex;
+  flex-direction: row;
+  border: 5px solid blue;
+}
+
+.item {
+  border: 5px solid green;
+}
+</style>
+<body>
+<div id="column">
+  <div id="row">
+    <div class="item">This text should not overflow its box</div>
+  </div>
+</div>
+<script>
+var columnBox = document.getElementById("column");
+columnBox.offsetHeight;
+columnBox.style.width = "200px";
+</script>
diff --git a/third_party/blink/web_tests/css3/flexbox/nested-orthogonal-flexbox-relayout-expected.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/reference/nested-orthogonal-flexbox-relayout-ref.html
similarity index 100%
rename from third_party/blink/web_tests/css3/flexbox/nested-orthogonal-flexbox-relayout-expected.html
rename to third_party/blink/web_tests/external/wpt/css/css-flexbox/reference/nested-orthogonal-flexbox-relayout-ref.html
diff --git a/third_party/blink/web_tests/external/wpt/wasm/jsapi/table/grow-reftypes.tentative.any-expected.txt b/third_party/blink/web_tests/external/wpt/wasm/jsapi/table/grow-reftypes.tentative.any-expected.txt
index a4a558a..5a04fca6 100644
--- a/third_party/blink/web_tests/external/wpt/wasm/jsapi/table/grow-reftypes.tentative.any-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/wasm/jsapi/table/grow-reftypes.tentative.any-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-FAIL Grow with exported-function argument WebAssembly.Module(): Compiling function #0:"fn" failed: trailing code after function end @+32
+FAIL Grow with exported-function argument assert_equals: expected (function) function "function 0() { [native code] }" but got (object) null
 FAIL Grow with non-function argument assert_throws_js: function "() => table.grow(2, {})" did not throw
 FAIL Grow with JS-function argument assert_throws_js: function "() => table.grow(2, () => true)" did not throw
 Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/wasm/jsapi/table/grow-reftypes.tentative.any.js b/third_party/blink/web_tests/external/wpt/wasm/jsapi/table/grow-reftypes.tentative.any.js
index 54141c0..edfb334 100644
--- a/third_party/blink/web_tests/external/wpt/wasm/jsapi/table/grow-reftypes.tentative.any.js
+++ b/third_party/blink/web_tests/external/wpt/wasm/jsapi/table/grow-reftypes.tentative.any.js
@@ -16,7 +16,7 @@
   const builder = new WasmModuleBuilder();
   builder
     .addFunction("fn", kSig_v_v)
-    .addBody([kExprEnd])
+    .addBody([])
     .exportFunc();
   const bin = builder.toBuffer()
   const argument = { "element": "anyfunc", "initial": 1 };
diff --git a/third_party/blink/web_tests/fast/forms/text/input-readonly-focus-ring-expected.html b/third_party/blink/web_tests/fast/forms/text/input-readonly-focus-ring-expected.html
index 19ee40c..2287109b 100644
--- a/third_party/blink/web_tests/fast/forms/text/input-readonly-focus-ring-expected.html
+++ b/third_party/blink/web_tests/fast/forms/text/input-readonly-focus-ring-expected.html
@@ -1 +1 @@
- <input id="target" readonly style="outline-offset: -2px; outline: -webkit-focus-ring-color auto 5px;">
+ <input id="target" readonly style="outline-offset: 0px; outline: -webkit-focus-ring-color auto 5px;">
diff --git a/third_party/blink/web_tests/platform/linux/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png b/third_party/blink/web_tests/platform/linux/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
index f8c749d..c0534d9 100644
--- a/third_party/blink/web_tests/platform/linux/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
+++ b/third_party/blink/web_tests/platform/linux/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/css/focus-ring-outline-offset-expected.png b/third_party/blink/web_tests/platform/linux/fast/css/focus-ring-outline-offset-expected.png
index ee0c9696..015fea47 100644
--- a/third_party/blink/web_tests/platform/linux/fast/css/focus-ring-outline-offset-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/css/focus-ring-outline-offset-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/select/multiselect-in-listbox-keyboard-focusring-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/select/multiselect-in-listbox-keyboard-focusring-expected.png
index 140c360..f874f69 100644
--- a/third_party/blink/web_tests/platform/linux/fast/forms/select/multiselect-in-listbox-keyboard-focusring-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/select/multiselect-in-listbox-keyboard-focusring-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/focus-rect/focus-ring-outline-offset-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/focus-rect/focus-ring-outline-offset-expected.png
new file mode 100644
index 0000000..c606bb1
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/focus-rect/focus-ring-outline-offset-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png b/third_party/blink/web_tests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
index f8c749d..c0534d9 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/blink/web_tests/platform/linux/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index f6df0002..eb33086 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/blink/web_tests/platform/linux/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index b8b5e15..61937ab 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
index ad16105..0a4f20e 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.10/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
index ad16105..0a4f20e 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
new file mode 100644
index 0000000..26e4531d
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
new file mode 100644
index 0000000..26e4531d
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/select/multiselect-in-listbox-keyboard-focusring-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/select/multiselect-in-listbox-keyboard-focusring-expected.png
index 8fb6065..251b265 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/select/multiselect-in-listbox-keyboard-focusring-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/select/multiselect-in-listbox-keyboard-focusring-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
new file mode 100644
index 0000000..26e4531d
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
new file mode 100644
index 0000000..26e4531d
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-retina/virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png b/third_party/blink/web_tests/platform/mac/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
index da30bae..26e4531d 100644
--- a/third_party/blink/web_tests/platform/mac/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
+++ b/third_party/blink/web_tests/platform/mac/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/css/focus-ring-outline-offset-expected.png b/third_party/blink/web_tests/platform/mac/fast/css/focus-ring-outline-offset-expected.png
index b524a89..eb669202 100644
--- a/third_party/blink/web_tests/platform/mac/fast/css/focus-ring-outline-offset-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/css/focus-ring-outline-offset-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/checkbox/checkbox-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/checkbox/checkbox-appearance-basic-expected.png
index e2a90a59..e277d51 100644
--- a/third_party/blink/web_tests/platform/mac/fast/forms/checkbox/checkbox-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/checkbox/checkbox-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/radio/radio-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/radio/radio-appearance-basic-expected.png
index af5567d..dd00eaae 100644
--- a/third_party/blink/web_tests/platform/mac/fast/forms/radio/radio-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/radio/radio-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/select/multiselect-in-listbox-keyboard-focusring-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/select/multiselect-in-listbox-keyboard-focusring-expected.png
index 64878ac..41b1ca4 100644
--- a/third_party/blink/web_tests/platform/mac/fast/forms/select/multiselect-in-listbox-keyboard-focusring-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/select/multiselect-in-listbox-keyboard-focusring-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/focus-rect/checkbox-zoom-focus-ring-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/focus-rect/checkbox-zoom-focus-ring-expected.png
index 343001d..486bfcb 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/focus-rect/checkbox-zoom-focus-ring-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/focus-rect/checkbox-zoom-focus-ring-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/focus-rect/focus-ring-outline-offset-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/focus-rect/focus-ring-outline-offset-expected.png
new file mode 100644
index 0000000..dca3467
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/focus-rect/focus-ring-outline-offset-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/focus-rect/radio-focus-ring-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/focus-rect/radio-focus-ring-expected.png
index af11d83..0945d084 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/focus-rect/radio-focus-ring-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/focus-rect/radio-focus-ring-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png b/third_party/blink/web_tests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
index da30bae..26e4531d 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png b/third_party/blink/web_tests/platform/win/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
index d08bbbb..5ce7566 100644
--- a/third_party/blink/web_tests/platform/win/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
+++ b/third_party/blink/web_tests/platform/win/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/css/focus-ring-outline-offset-expected.png b/third_party/blink/web_tests/platform/win/fast/css/focus-ring-outline-offset-expected.png
index 63f6227..fd0ddf3c 100644
--- a/third_party/blink/web_tests/platform/win/fast/css/focus-ring-outline-offset-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/css/focus-ring-outline-offset-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/checkbox/checkbox-appearance-basic-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/checkbox/checkbox-appearance-basic-expected.png
index 58bc18d..5daab0a 100644
--- a/third_party/blink/web_tests/platform/win/fast/forms/checkbox/checkbox-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/forms/checkbox/checkbox-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/radio/radio-appearance-basic-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/radio/radio-appearance-basic-expected.png
index 9dc7241..dda9941 100644
--- a/third_party/blink/web_tests/platform/win/fast/forms/radio/radio-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/forms/radio/radio-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/select/multiselect-in-listbox-keyboard-focusring-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/select/multiselect-in-listbox-keyboard-focusring-expected.png
index f6a66920..be9361a 100644
--- a/third_party/blink/web_tests/platform/win/fast/forms/select/multiselect-in-listbox-keyboard-focusring-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/forms/select/multiselect-in-listbox-keyboard-focusring-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/focus-rect/checkbox-zoom-focus-ring-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/focus-rect/checkbox-zoom-focus-ring-expected.png
index f57d162..f681132a 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/focus-rect/checkbox-zoom-focus-ring-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/focus-rect/checkbox-zoom-focus-ring-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png b/third_party/blink/web_tests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
new file mode 100644
index 0000000..5ce7566
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/blink/web_tests/platform/win/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index 69a2662..b7dc004 100644
--- a/third_party/blink/web_tests/platform/win/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/blink/web_tests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index 7c97da43..c338278 100644
--- a/third_party/blink/web_tests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png b/third_party/blink/web_tests/platform/win7/virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
new file mode 100644
index 0000000..5ce7566
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win7/virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/blink/web_tests/platform/win7/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
new file mode 100644
index 0000000..b7dc004
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win7/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/blink/web_tests/platform/win7/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
new file mode 100644
index 0000000..c338278
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win7/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/focus-rect/focus-ring-outline-offset-expected.png b/third_party/blink/web_tests/virtual/controls-refresh/focus-rect/focus-ring-outline-offset-expected.png
new file mode 100644
index 0000000..da4ae01
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/controls-refresh/focus-rect/focus-ring-outline-offset-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/focus-rect/focus-ring-outline-offset.html b/third_party/blink/web_tests/virtual/controls-refresh/focus-rect/focus-ring-outline-offset.html
new file mode 100644
index 0000000..c6bcabff
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/controls-refresh/focus-rect/focus-ring-outline-offset.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<script src="../../../resources/run-after-layout-and-paint.js"></script>
+<script src="../../../fast/forms/resources/common.js"></script>
+<body style="background-color: red">
+<!-- no style for reference -->
+<input type="button" id="focusTarget" value="button" />
+<br>
+<br>
+<input type="checkbox" checked id="focusTarget" />
+<br>
+<br>
+<input type="radio" id="focusTarget" />
+<br>
+<br>
+<input type="text" value="example text" id="focusTarget" />
+<br>
+<br>
+<a href="#" id="focusTarget" >Test</a>
+<br>
+<br>
+<!-- outline-offset: 4px -->
+<input type="button" style="outline-offset: 4px" value="button" id="focusTarget" />
+<br>
+<br>
+<input type="checkbox" style="outline-offset: 4px" checked id="focusTarget" />
+<br>
+<br>
+<input type="radio" style="outline-offset: 4px" id="focusTarget" />
+<br>
+<br>
+<input type="text" style="outline-offset: 4px" value="example text" id="focusTarget" />
+<br>
+<br>
+<a href="#" style="outline-offset: 4px" id="focusTarget">Test</a>
+<br>
+<script>
+  runAfterLayoutAndPaint(function() {
+    document.querySelectorAll("#focusTarget").forEach(node => {
+      internals.setPseudoClassState(node, ":focus", true);
+      // console.log(node);
+    });
+  }, true);
+</script>
+</body>
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/focus-rect/radio-focus-ring-expected.png b/third_party/blink/web_tests/virtual/controls-refresh/focus-rect/radio-focus-ring-expected.png
index 1ff7a39..b448a74 100644
--- a/third_party/blink/web_tests/virtual/controls-refresh/focus-rect/radio-focus-ring-expected.png
+++ b/third_party/blink/web_tests/virtual/controls-refresh/focus-rect/radio-focus-ring-expected.png
Binary files differ
diff --git a/third_party/libvpx/BUILD.gn b/third_party/libvpx/BUILD.gn
index 31a26e5..5902278 100644
--- a/third_party/libvpx/BUILD.gn
+++ b/third_party/libvpx/BUILD.gn
@@ -6,7 +6,7 @@
 import("//build/config/arm.gni")
 import("//build/config/sanitizers/sanitizers.gni")
 import("//third_party/libvpx/libvpx_srcs.gni")
-import("//third_party/yasm/yasm_assemble.gni")
+import("//third_party/nasm/nasm_assemble.gni")
 
 # Sets the architecture name for building libvpx.
 if (current_cpu == "x86") {
@@ -101,7 +101,7 @@
 }
 
 if (current_cpu == "x86" || (current_cpu == "x64" && !is_msan)) {
-  yasm_assemble("libvpx_yasm") {
+  nasm_assemble("libvpx_asm") {
     if (current_cpu == "x86") {
       sources = libvpx_srcs_x86_assembly
     } else if (current_cpu == "x64") {
@@ -344,6 +344,7 @@
   deps = []
   if (current_cpu == "x86" || (current_cpu == "x64" && !is_msan)) {
     deps += [
+      ":libvpx_asm",
       ":libvpx_intrinsics_avx",
       ":libvpx_intrinsics_avx2",
       ":libvpx_intrinsics_avx512",
@@ -351,7 +352,6 @@
       ":libvpx_intrinsics_sse2",
       ":libvpx_intrinsics_sse4_1",
       ":libvpx_intrinsics_ssse3",
-      ":libvpx_yasm",
     ]
   }
   if (cpu_arch_full == "arm-neon-cpu-detect") {
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 269e35f..84319f3 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -18691,49 +18691,6 @@
   </description>
 </action>
 
-<action name="SafetyCheck.Extensions.Review">
-  <owner>rainhard@chromium.org</owner>
-  <owner>andzaytsev@google.com</owner>
-  <owner>msramek@chromium.org</owner>
-  <description>
-    User clicks the review extensions button in safety check.
-  </description>
-</action>
-
-<action name="SafetyCheck.Passwords.Manage">
-  <owner>rainhard@chromium.org</owner>
-  <owner>andzaytsev@google.com</owner>
-  <owner>msramek@chromium.org</owner>
-  <description>
-    User clicks the manage passwords button in safety check.
-  </description>
-</action>
-
-<action name="SafetyCheck.SafeBrowsing.Manage">
-  <owner>rainhard@chromium.org</owner>
-  <owner>andzaytsev@google.com</owner>
-  <owner>msramek@chromium.org</owner>
-  <description>
-    User clicks the manage safe browsing button in safety check.
-  </description>
-</action>
-
-<action name="SafetyCheck.Started">
-  <owner>rainhard@chromium.org</owner>
-  <owner>andzaytsev@google.com</owner>
-  <owner>msramek@chromium.org</owner>
-  <description>User started a browser safety check in settings.</description>
-</action>
-
-<action name="SafetyCheck.Updates.Relaunch">
-  <owner>rainhard@chromium.org</owner>
-  <owner>andzaytsev@google.com</owner>
-  <owner>msramek@chromium.org</owner>
-  <description>
-    User clicks the relaunch browser button in safety check after an update.
-  </description>
-</action>
-
 <action name="Save">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <description>Please enter the description of this user action.</description>
@@ -19273,6 +19230,49 @@
   </description>
 </action>
 
+<action name="Settings.SafetyCheck.ManagePasswords">
+  <owner>rainhard@chromium.org</owner>
+  <owner>andzaytsev@google.com</owner>
+  <owner>msramek@chromium.org</owner>
+  <description>
+    User clicks the manage passwords button in safety check.
+  </description>
+</action>
+
+<action name="Settings.SafetyCheck.ManageSafeBrowsing">
+  <owner>rainhard@chromium.org</owner>
+  <owner>andzaytsev@google.com</owner>
+  <owner>msramek@chromium.org</owner>
+  <description>
+    User clicks the manage safe browsing button in safety check.
+  </description>
+</action>
+
+<action name="Settings.SafetyCheck.RelaunchAfterUpdates">
+  <owner>rainhard@chromium.org</owner>
+  <owner>andzaytsev@google.com</owner>
+  <owner>msramek@chromium.org</owner>
+  <description>
+    User clicks the relaunch browser button in safety check after an update.
+  </description>
+</action>
+
+<action name="Settings.SafetyCheck.ReviewExtensions">
+  <owner>rainhard@chromium.org</owner>
+  <owner>andzaytsev@google.com</owner>
+  <owner>msramek@chromium.org</owner>
+  <description>
+    User clicks the review extensions button in safety check.
+  </description>
+</action>
+
+<action name="Settings.SafetyCheck.Start">
+  <owner>rainhard@chromium.org</owner>
+  <owner>andzaytsev@google.com</owner>
+  <owner>msramek@chromium.org</owner>
+  <description>User started a browser safety check in settings.</description>
+</action>
+
 <action name="Settings.Searching">
   <owner>dschuyler@chromium.org</owner>
   <description>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 1ae86b7a..30568d3 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -38604,6 +38604,7 @@
   <int value="-864234985" label="UseDdljsonApi:enabled"/>
   <int value="-864232986" label="StartSurfaceAndroid:disabled"/>
   <int value="-864205629" label="enable-offline-load-stale-cache"/>
+  <int value="-863581676" label="BluetoothFixA2dpPacketSize:disabled"/>
   <int value="-861678473" label="disable-offer-upload-credit-cards"/>
   <int value="-861343291" label="ChromeHome:disabled"/>
   <int value="-860578793" label="TabGridLayoutAndroid:disabled"/>
@@ -38752,6 +38753,7 @@
   <int value="-695687521" label="double-buffer-compositing"/>
   <int value="-694622753" label="VizHitTest:disabled"/>
   <int value="-694187898" label="MashOopViz:disabled"/>
+  <int value="-687302378" label="BluetoothFixA2dpPacketSize:enabled"/>
   <int value="-684900739" label="disable-merge-key-char-events"/>
   <int value="-684503292"
       label="OmniboxTabSwitchSuggestionsDedicatedRow:enabled"/>
@@ -54494,6 +54496,7 @@
       label="Failed: No shared DB provider provided, unique DB failed"/>
   <int value="27"
       label="Success: No shared DB provider provided, using unique"/>
+  <int value="28" label="Failed: Unique DB missing, shared deletion failed"/>
 </enum>
 
 <enum name="ProvisionalLoadEvent">
@@ -59849,7 +59852,7 @@
   <int value="3" label="Startup URLs"/>
 </enum>
 
-<enum name="SettingsSafetyCheckElementInteractions">
+<enum name="SettingsSafetyCheckInteractions">
   <int value="0" label="Safety check started"/>
   <int value="1" label="Safety check, relaunch after updates"/>
   <int value="2" label="Safety check, manage passwords"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 0059a4a..110e1f5 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -8331,7 +8331,7 @@
 </histogram>
 
 <histogram name="ArcAuth.MainAccountResolutionStatus"
-    enum="ArcAuthMainAccountResolutionStatus" expires_after="M82">
+    enum="ArcAuthMainAccountResolutionStatus" expires_after="M85">
   <owner>khmel@chromium.org</owner>
   <owner>jhorwich@chromium.org</owner>
   <summary>Contains the status of main account resolution.</summary>
@@ -135939,6 +135939,19 @@
   </summary>
 </histogram>
 
+<histogram name="SafeBrowsing.BlockingPage.ResourceType"
+    enum="ContentResourceType2" expires_after="2021-03-27">
+  <owner>xinghuilu@chromium.org</owner>
+  <owner>chrome-safebrowsing-alerts@google.com</owner>
+  <summary>
+    Logs the resource type that triggers the safe browsing blocking page. Logged
+    each time a safe browsing blocking page is created. This metric is useful to
+    show the priority of checking each resource type in real time. Note that
+    this metric may be bias towards mainframe, because the default resource type
+    is set to mainframe.
+  </summary>
+</histogram>
+
 <histogram name="SafeBrowsing.CheckBrowseUrl.HasLocalMatch"
     enum="BooleanMatched" expires_after="2020-08-05">
   <owner>vakh@chromium.org</owner>
@@ -145992,8 +146005,10 @@
 </histogram>
 
 <histogram name="ServiceWorker.FetchEvent.MainResource.Status"
-    enum="ServiceWorkerStatusCode" expires_after="2020-04-19">
+    enum="ServiceWorkerStatusCode" expires_after="2021-04-19">
   <owner>falken@chromium.org</owner>
+  <owner>shimazu@chromium.org</owner>
+  <owner>chrome-worker@google.com</owner>
   <summary>
     The result of dispatching a fetch event to a Service Worker for a main
     resource request (i.e., a request for a navigation or a shared worker).
@@ -146001,8 +146016,10 @@
 </histogram>
 
 <histogram name="ServiceWorker.FetchEvent.Subresource.Status"
-    enum="ServiceWorkerStatusCode" expires_after="2020-04-19">
+    enum="ServiceWorkerStatusCode" expires_after="2021-04-19">
   <owner>falken@chromium.org</owner>
+  <owner>shimazu@chromium.org</owner>
+  <owner>chrome-worker@google.com</owner>
   <summary>
     The result of dispatching a fetch event to a Service Worker for a
     subresource request (i.e., not a navigation or a shared worker request).
@@ -148940,6 +148957,17 @@
   <summary>Resulting state of the safety check extensions check.</summary>
 </histogram>
 
+<histogram name="Settings.SafetyCheck.Interactions"
+    enum="SettingsSafetyCheckInteractions" expires_after="M86">
+  <owner>rainhard@chromium.org</owner>
+  <owner>msramek@chromium.org</owner>
+  <owner>anaudrey@chromium.org</owner>
+  <summary>
+    Which user actions were taken in safety check. Recorded every time a user
+    does an interaction in safety check.
+  </summary>
+</histogram>
+
 <histogram name="Settings.SafetyCheck.PasswordsResult"
     enum="SafetyCheckPasswordsStatus" expires_after="M86">
   <owner>andzaytsev@google.com</owner>
@@ -149413,17 +149441,6 @@
   </summary>
 </histogram>
 
-<histogram name="SettingsPage.SafetyCheckElementInteractions"
-    enum="SettingsSafetyCheckElementInteractions" expires_after="M86">
-  <owner>rainhard@chromium.org</owner>
-  <owner>msramek@chromium.org</owner>
-  <owner>anaudrey@chromium.org</owner>
-  <summary>
-    Which user actions were taken in safety check. Recorded every time a user
-    does an interaction in safety check.
-  </summary>
-</histogram>
-
 <histogram name="SettingsPage.SettingsPageInteractions"
     enum="SettingsPageInteractions" expires_after="M83">
   <obsolete>
diff --git a/ui/base/ime/ime_suggestion_window_handler_interface.h b/ui/base/ime/ime_suggestion_window_handler_interface.h
index ab0f6b5..494b79a 100644
--- a/ui/base/ime/ime_suggestion_window_handler_interface.h
+++ b/ui/base/ime/ime_suggestion_window_handler_interface.h
@@ -22,7 +22,9 @@
   virtual ~IMESuggestionWindowHandlerInterface() {}
 
   // Called when showing/hiding suggestion window.
-  virtual void Show(const base::string16& text) {}
+  virtual void Show(const base::string16& text,
+                    const base::string16& confirmed_text,
+                    const bool show_tab) {}
   virtual void Hide() {}
 
   // Called to get the current suggestion text.
diff --git a/ui/chromeos/ime/suggestion_view.cc b/ui/chromeos/ime/suggestion_view.cc
index 7e84ca2..6bbb924 100644
--- a/ui/chromeos/ime/suggestion_view.cc
+++ b/ui/chromeos/ime/suggestion_view.cc
@@ -19,15 +19,14 @@
 
 // Creates the suggestion label, and returns it (never returns nullptr).
 // The label text is not set in this function.
-std::unique_ptr<views::Label> CreateSuggestionLabel() {
-  std::unique_ptr<views::Label> suggestion_label =
-      std::make_unique<views::Label>();
-
-  suggestion_label->SetFontList(kSuggestionFont);
-  suggestion_label->SetEnabledColor(kSuggestionLabelColor);
+std::unique_ptr<views::StyledLabel> CreateSuggestionLabel() {
+  std::unique_ptr<views::StyledLabel> suggestion_label =
+      std::make_unique<views::StyledLabel>(base::EmptyString16(),
+                                           /*listener=*/nullptr);
   suggestion_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
   suggestion_label->SetBorder(
       views::CreateEmptyBorder(gfx::Insets(kPadding / 2, 0)));
+  suggestion_label->SetAutoColorReadabilityEnabled(false);
 
   return suggestion_label;
 }
@@ -37,14 +36,14 @@
   std::unique_ptr<views::Label> annotation_label =
       std::make_unique<views::Label>();
   annotation_label->SetFontList(kAnnotationFont);
-  annotation_label->SetEnabledColor(kSuggestionLabelColor);
+  annotation_label->SetEnabledColor(kSuggestionColor);
   annotation_label->SetHorizontalAlignment(gfx::ALIGN_CENTER);
 
   // Set insets.
   const gfx::Insets insets(0, 0, 0, kPadding / 2);
   annotation_label->SetBorder(views::CreateRoundedRectBorder(
       kAnnotationBorderThickness, kAnnotationCornerRadius, insets,
-      kSuggestionLabelColor));
+      kSuggestionColor));
 
   // Set text.
   annotation_label->SetText(base::UTF8ToUTF16(kTabKey));
@@ -61,9 +60,31 @@
 
 SuggestionView::~SuggestionView() = default;
 
-void SuggestionView::SetText(const base::string16& text) {
-  suggestion_label_->SetText(text);
+void SuggestionView::SetView(const base::string16& text,
+                             const base::string16& confirmed_text,
+                             const bool show_tab) {
+  SetSuggestionText(text, confirmed_text);
   suggestion_width_ = suggestion_label_->GetPreferredSize().width();
+  annotation_label_->SetVisible(show_tab);
+}
+
+void SuggestionView::SetSuggestionText(const base::string16& text,
+                                       const base::string16& confirmed_text) {
+  // SetText clears the existing style.
+  suggestion_label_->SetText(text);
+  size_t offset = confirmed_text.length();
+  if (offset != 0) {
+    views::StyledLabel::RangeStyleInfo confirmed_style;
+    confirmed_style.custom_font = kSuggestionFont;
+    confirmed_style.override_color = kConfirmedTextColor;
+    suggestion_label_->AddStyleRange(gfx::Range(0, offset), confirmed_style);
+  }
+
+  views::StyledLabel::RangeStyleInfo suggestion_style;
+  suggestion_style.custom_font = kSuggestionFont;
+  suggestion_style.override_color = kSuggestionColor;
+  suggestion_label_->AddStyleRange(gfx::Range(offset, text.length()),
+                                   suggestion_style);
 }
 
 const char* SuggestionView::GetClassName() const {
@@ -73,11 +94,13 @@
 void SuggestionView::Layout() {
   suggestion_label_->SetBounds(kPadding, 0, suggestion_width_, height());
 
-  int annotation_left = kPadding + suggestion_width_ + kPadding;
-  int right = bounds().right();
-  annotation_label_->SetBounds(annotation_left, kAnnotationPaddingHeight,
-                               right - annotation_left - kPadding / 2,
-                               height() - 2 * kAnnotationPaddingHeight);
+  if (annotation_label_->GetVisible()) {
+    int annotation_left = kPadding + suggestion_width_ + kPadding;
+    int right = bounds().right();
+    annotation_label_->SetBounds(annotation_left, kAnnotationPaddingHeight,
+                                 right - annotation_left - kPadding / 2,
+                                 height() - 2 * kAnnotationPaddingHeight);
+  }
 }
 
 gfx::Size SuggestionView::CalculatePreferredSize() const {
@@ -87,12 +110,10 @@
   suggestion_size.SetToMax(gfx::Size(suggestion_width_, 0));
   size.Enlarge(suggestion_size.width() + 2 * kPadding, 0);
   size.SetToMax(suggestion_size);
-  gfx::Size annotation_size = annotation_label_->GetPreferredSize();
-  size.Enlarge(annotation_size.width() + kPadding, 0);
-  // size.SetToMax(annotation_size);
-  LOG(ERROR) << "suggestion_size " << suggestion_size.width()
-             << " annotation size " << annotation_size.width() << " size "
-             << size.width() << " height " << size.height();
+  if (annotation_label_->GetVisible()) {
+    gfx::Size annotation_size = annotation_label_->GetPreferredSize();
+    size.Enlarge(annotation_size.width() + kPadding, 0);
+  }
   return size;
 }
 
diff --git a/ui/chromeos/ime/suggestion_view.h b/ui/chromeos/ime/suggestion_view.h
index b8d8f5a..4e5575b 100644
--- a/ui/chromeos/ime/suggestion_view.h
+++ b/ui/chromeos/ime/suggestion_view.h
@@ -9,6 +9,7 @@
 #include "base/macros.h"
 #include "ui/chromeos/ui_chromeos_export.h"
 #include "ui/views/controls/label.h"
+#include "ui/views/controls/styled_label.h"
 #include "ui/views/view.h"
 
 namespace ui {
@@ -32,7 +33,8 @@
 constexpr int kPadding = 10;
 constexpr int kAnnotationPaddingHeight = 6;
 constexpr char kTabKey[] = "tab";
-constexpr SkColor kSuggestionLabelColor =
+constexpr SkColor kConfirmedTextColor = gfx::kGoogleGrey900;
+constexpr SkColor kSuggestionColor =
     SkColorSetA(gfx::kGoogleGrey900, gfx::kGoogleGreyAlpha500);
 
 // SuggestionView renders a suggestion.
@@ -41,7 +43,9 @@
   SuggestionView();
   ~SuggestionView() override;
 
-  void SetText(const base::string16& text);
+  void SetView(const base::string16& text,
+               const base::string16& confirmed_text,
+               const bool show_tab);
 
  private:
   friend class SuggestionWindowViewTest;
@@ -55,8 +59,11 @@
   // Views created in the class will be part of tree of |this|, so these
   // child views will be deleted when |this| is deleted.
 
+  void SetSuggestionText(const base::string16& text,
+                         const base::string16& confirmed_text);
+
   // The suggestion label renders suggestions.
-  views::Label* suggestion_label_ = nullptr;
+  views::StyledLabel* suggestion_label_ = nullptr;
   // The annotation label renders annotations.
   views::Label* annotation_label_ = nullptr;
 
diff --git a/ui/chromeos/ime/suggestion_window_view.cc b/ui/chromeos/ime/suggestion_window_view.cc
index b72c3000..c6fc496e 100644
--- a/ui/chromeos/ime/suggestion_window_view.cc
+++ b/ui/chromeos/ime/suggestion_window_view.cc
@@ -87,14 +87,19 @@
   GetWidget()->Close();
 }
 
-void SuggestionWindowView::Show(const base::string16& text) {
-  UpdateSuggestion(text);
+void SuggestionWindowView::Show(const base::string16& text,
+                                const base::string16& confirmed_text,
+                                const bool show_tab) {
+  UpdateSuggestion(text, confirmed_text, show_tab);
   suggestion_view_->SetVisible(true);
   SizeToContents();
 }
 
-void SuggestionWindowView::UpdateSuggestion(const base::string16& text) {
-  suggestion_view_->SetText(text);
+void SuggestionWindowView::UpdateSuggestion(
+    const base::string16& text,
+    const base::string16& confirmed_text,
+    const bool show_tab) {
+  suggestion_view_->SetView(text, confirmed_text, show_tab);
 
   std::unique_ptr<SuggestionWindowBorder> border =
       std::make_unique<SuggestionWindowBorder>();
diff --git a/ui/chromeos/ime/suggestion_window_view.h b/ui/chromeos/ime/suggestion_window_view.h
index 348c4ded..e309eb0 100644
--- a/ui/chromeos/ime/suggestion_window_view.h
+++ b/ui/chromeos/ime/suggestion_window_view.h
@@ -31,14 +31,19 @@
   void Hide();
 
   // Shows suggestion text.
-  void Show(const base::string16& text);
-  void UpdateSuggestion(const base::string16& text);
+  void Show(const base::string16& text,
+            const base::string16& confirmed_text,
+            const bool show_tab);
 
   void SetBounds(const gfx::Rect& cursor_bounds);
 
  private:
   friend class SuggestionWindowViewTest;
 
+  void UpdateSuggestion(const base::string16& text,
+                        const base::string16& confirmed_text,
+                        const bool show_tab);
+
   // views::BubbleDialogDelegateView:
   const char* GetClassName() const override;
 
diff --git a/ui/events/blink/blink_features.cc b/ui/events/blink/blink_features.cc
index 93e816c..a8bc072 100644
--- a/ui/events/blink/blink_features.cc
+++ b/ui/events/blink/blink_features.cc
@@ -21,9 +21,6 @@
 const base::Feature kSendMouseLeaveEvents{"SendMouseLeaveEvents",
                                           base::FEATURE_ENABLED_BY_DEFAULT};
 
-const base::Feature kCompositorTouchAction{"CompositorTouchAction",
-                                           base::FEATURE_ENABLED_BY_DEFAULT};
-
 const base::Feature kFallbackCursorMode{"FallbackCursorMode",
                                         base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/ui/events/blink/blink_features.h b/ui/events/blink/blink_features.h
index c66a982..725b779 100644
--- a/ui/events/blink/blink_features.h
+++ b/ui/events/blink/blink_features.h
@@ -34,11 +34,6 @@
 COMPONENT_EXPORT(BLINK_FEATURES)
 extern const base::Feature kSendMouseLeaveEvents;
 
-// Enables handling touch events in compositor using impl side touch action
-// knowledge.
-COMPONENT_EXPORT(BLINK_FEATURES)
-extern const base::Feature kCompositorTouchAction;
-
 // Enables fallback cursor mode for dpad devices.
 COMPONENT_EXPORT(BLINK_FEATURES)
 extern const base::Feature kFallbackCursorMode;
diff --git a/ui/events/blink/input_handler_proxy.cc b/ui/events/blink/input_handler_proxy.cc
index 8540083..11a11e1 100644
--- a/ui/events/blink/input_handler_proxy.cc
+++ b/ui/events/blink/input_handler_proxy.cc
@@ -192,8 +192,6 @@
       last_injected_gesture_was_begin_(false),
       tick_clock_(base::DefaultTickClock::GetInstance()),
       snap_fling_controller_(std::make_unique<cc::SnapFlingController>(this)),
-      compositor_touch_action_enabled_(
-          base::FeatureList::IsEnabled(features::kCompositorTouchAction)),
       force_input_to_main_thread_(force_input_to_main_thread) {
   DCHECK(client);
   input_handler_->BindToClient(this);
@@ -1048,7 +1046,7 @@
       // A non-passive touch start / move will always set the whitelisted touch
       // action to TouchAction::kNone, and in that case we do not ack the event
       // from the compositor.
-      if (compositor_touch_action_enabled_ && white_listed_touch_action &&
+      if (white_listed_touch_action &&
           *white_listed_touch_action != cc::TouchAction::kNone)
         result = DID_HANDLE_NON_BLOCKING;
       else
diff --git a/ui/events/blink/input_handler_proxy.h b/ui/events/blink/input_handler_proxy.h
index 5b7ff6b7..2487ca64 100644
--- a/ui/events/blink/input_handler_proxy.h
+++ b/ui/events/blink/input_handler_proxy.h
@@ -249,8 +249,6 @@
 
   std::unique_ptr<ScrollPredictor> scroll_predictor_;
 
-  bool compositor_touch_action_enabled_;
-
   // This flag can be used to force all input to be forwarded to Blink. It's
   // used in LayoutTests to preserve existing behavior for non-threaded layout
   // tests and to allow testing both Blink and CC input handling paths.
diff --git a/ui/events/blink/input_handler_proxy_unittest.cc b/ui/events/blink/input_handler_proxy_unittest.cc
index 90d227e..a7505abc 100644
--- a/ui/events/blink/input_handler_proxy_unittest.cc
+++ b/ui/events/blink/input_handler_proxy_unittest.cc
@@ -69,20 +69,12 @@
   ROOT_SCROLL_SYNCHRONOUS_HANDLER,
   CHILD_SCROLL_NORMAL_HANDLER,
   CHILD_SCROLL_SYNCHRONOUS_HANDLER,
-  COMPOSITOR_TOUCH_ACTION_ENABLED_ROOT_NORMAL,
-  COMPOSITOR_TOUCH_ACTION_ENABLED_ROOT_SYNCHRONOUS,
-  COMPOSITOR_TOUCH_ACTION_ENABLED_CHILD_NORMAL,
-  COMPOSITOR_TOUCH_ACTION_ENABLED_CHILD_SYNCHRONOUS,
 };
 static const InputHandlerProxyTestType test_types[] = {
     ROOT_SCROLL_NORMAL_HANDLER,
     ROOT_SCROLL_SYNCHRONOUS_HANDLER,
     CHILD_SCROLL_NORMAL_HANDLER,
     CHILD_SCROLL_SYNCHRONOUS_HANDLER,
-    COMPOSITOR_TOUCH_ACTION_ENABLED_ROOT_NORMAL,
-    COMPOSITOR_TOUCH_ACTION_ENABLED_ROOT_SYNCHRONOUS,
-    COMPOSITOR_TOUCH_ACTION_ENABLED_CHILD_NORMAL,
-    COMPOSITOR_TOUCH_ACTION_ENABLED_CHILD_SYNCHRONOUS,
 };
 
 MATCHER_P(WheelEventsMatch, expected, "") {
@@ -336,24 +328,11 @@
       public testing::WithParamInterface<InputHandlerProxyTestType> {
  public:
   InputHandlerProxyTest()
-      : synchronous_root_scroll_(
-            GetParam() == ROOT_SCROLL_SYNCHRONOUS_HANDLER ||
-            GetParam() == COMPOSITOR_TOUCH_ACTION_ENABLED_ROOT_SYNCHRONOUS),
+      : synchronous_root_scroll_(GetParam() == ROOT_SCROLL_SYNCHRONOUS_HANDLER),
         install_synchronous_handler_(
             GetParam() == ROOT_SCROLL_SYNCHRONOUS_HANDLER ||
-            GetParam() == CHILD_SCROLL_SYNCHRONOUS_HANDLER ||
-            GetParam() == COMPOSITOR_TOUCH_ACTION_ENABLED_ROOT_SYNCHRONOUS ||
-            GetParam() == COMPOSITOR_TOUCH_ACTION_ENABLED_CHILD_SYNCHRONOUS),
-        compositor_touch_action_enabled_(
-            GetParam() == COMPOSITOR_TOUCH_ACTION_ENABLED_ROOT_NORMAL ||
-            GetParam() == COMPOSITOR_TOUCH_ACTION_ENABLED_ROOT_SYNCHRONOUS ||
-            GetParam() == COMPOSITOR_TOUCH_ACTION_ENABLED_CHILD_NORMAL ||
-            GetParam() == COMPOSITOR_TOUCH_ACTION_ENABLED_CHILD_SYNCHRONOUS),
+            GetParam() == CHILD_SCROLL_SYNCHRONOUS_HANDLER),
         expected_disposition_(InputHandlerProxy::DID_HANDLE) {
-    if (compositor_touch_action_enabled_)
-      feature_list_.InitAndEnableFeature(features::kCompositorTouchAction);
-    else
-      feature_list_.InitAndDisableFeature(features::kCompositorTouchAction);
     input_handler_ = std::make_unique<TestInputHandlerProxy>(
         &mock_input_handler_, &mock_client_,
         /*force_input_to_main_thread=*/false);
@@ -408,7 +387,6 @@
 
   const bool synchronous_root_scroll_;
   const bool install_synchronous_handler_;
-  const bool compositor_touch_action_enabled_;
   testing::StrictMock<MockInputHandler> mock_input_handler_;
   testing::StrictMock<MockSynchronousInputHandler>
       mock_synchronous_input_handler_;
@@ -419,9 +397,6 @@
   base::HistogramTester histogram_tester_;
   cc::InputHandlerScrollResult scroll_result_did_scroll_;
   cc::InputHandlerScrollResult scroll_result_did_not_scroll_;
-
- private:
-  base::test::ScopedFeatureList feature_list_;
 };
 
 // The helper basically returns the EventDisposition that is returned by
@@ -1290,9 +1265,7 @@
 TEST_P(InputHandlerProxyTest, HitTestTouchEventNonNullTouchAction) {
   // One of the touch points is on a touch-region. So the event should be sent
   // to the main thread.
-  expected_disposition_ = compositor_touch_action_enabled_
-                              ? InputHandlerProxy::DID_HANDLE_NON_BLOCKING
-                              : InputHandlerProxy::DID_NOT_HANDLE;
+  expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
   VERIFY_AND_RESET_MOCKS();
 
   EXPECT_CALL(mock_input_handler_,
@@ -1515,9 +1488,7 @@
 TEST_P(InputHandlerProxyTest, MultiTouchPointHitTestPositive) {
   // One of the touch points is on a touch-region. So the event should be sent
   // to the main thread.
-  expected_disposition_ = compositor_touch_action_enabled_
-                              ? InputHandlerProxy::DID_HANDLE_NON_BLOCKING
-                              : InputHandlerProxy::DID_NOT_HANDLE;
+  expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
   VERIFY_AND_RESET_MOCKS();
 
   EXPECT_CALL(mock_input_handler_,
@@ -1678,9 +1649,7 @@
   touch.touches_length = 1;
   touch.touch_start_or_first_touch_move = true;
   touch.touches[0] = CreateWebTouchPoint(WebTouchPoint::kStateMoved, 10, 10);
-  EXPECT_EQ(compositor_touch_action_enabled_
-                ? InputHandlerProxy::DID_HANDLE_NON_BLOCKING
-                : InputHandlerProxy::DID_NOT_HANDLE,
+  EXPECT_EQ(InputHandlerProxy::DID_HANDLE_NON_BLOCKING,
             HandleInputEventWithLatencyInfo(input_handler_.get(), touch));
   VERIFY_AND_RESET_MOCKS();
 }
@@ -2552,7 +2521,7 @@
 TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
        GestureScrollTouchEventHandlerRegion) {
   // The touch event hits a touch event handler that is acked from the
-  // compositor thread when kCompositorTouchAction is enabld.
+  // compositor thread.
   SetupEvents(TestEventType::Touch);
 
   EXPECT_CALL(mock_input_handler_,
@@ -2564,21 +2533,16 @@
   EXPECT_CALL(mock_client_, SetWhiteListedTouchAction(_, _, _))
       .WillOnce(testing::Return());
 
-  expected_disposition_ = compositor_touch_action_enabled_
-                              ? InputHandlerProxy::DID_HANDLE_NON_BLOCKING
-                              : InputHandlerProxy::DID_NOT_HANDLE;
+  expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
   EXPECT_EQ(expected_disposition_,
             HandleInputEventAndFlushEventQueue(
                 mock_input_handler_, input_handler_.get(), touch_start_));
 
   EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
       .WillOnce(testing::Return(kImplThreadScrollState));
-  EXPECT_CALL(mock_input_handler_,
-              RecordScrollBegin(
-                  _, compositor_touch_action_enabled_
-                         ? cc::ScrollBeginThreadState::kScrollingOnCompositor
-                         : cc::ScrollBeginThreadState::
-                               kScrollingOnCompositorBlockedOnMain))
+  EXPECT_CALL(
+      mock_input_handler_,
+      RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnCompositor))
       .Times(1);
   expected_disposition_ = InputHandlerProxy::DID_HANDLE;
   EXPECT_EQ(
@@ -2590,10 +2554,7 @@
       histogram_tester().GetAllSamples(
           "Renderer4.MainThreadGestureScrollReason"),
       testing::ElementsAre(base::Bucket(
-          GetBucketSample(
-              compositor_touch_action_enabled_
-                  ? cc::MainThreadScrollingReason::kNotScrollingOnMain
-                  : cc::MainThreadScrollingReason::kTouchEventHandlerRegion),
+          GetBucketSample(cc::MainThreadScrollingReason::kNotScrollingOnMain),
           1)));
 
   EXPECT_CALL(mock_input_handler_, ScrollEnd(true));
@@ -2624,9 +2585,7 @@
   EXPECT_CALL(mock_client_, SetWhiteListedTouchAction(_, _, _))
       .WillOnce(testing::Return());
 
-  expected_disposition_ = compositor_touch_action_enabled_
-                              ? InputHandlerProxy::DID_HANDLE_NON_BLOCKING
-                              : InputHandlerProxy::DID_NOT_HANDLE;
+  expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
   EXPECT_EQ(expected_disposition_, HandleInputEventWithLatencyInfo(
                                        input_handler_.get(), touch_start_));
 
@@ -2646,9 +2605,7 @@
           "Renderer4.MainThreadGestureScrollReason"),
       testing::ElementsAre(base::Bucket(
           GetBucketSample(
-              compositor_touch_action_enabled_
-                  ? cc::MainThreadScrollingReason::kHandlingScrollFromMainThread
-                  : cc::MainThreadScrollingReason::kTouchEventHandlerRegion),
+              cc::MainThreadScrollingReason::kHandlingScrollFromMainThread),
           1)));
 
   // Handle touch end event so that input handler proxy is out of the state of
diff --git a/ui/file_manager/externs/app_window_common.js b/ui/file_manager/externs/app_window_common.js
index 70073025..697f1a5 100644
--- a/ui/file_manager/externs/app_window_common.js
+++ b/ui/file_manager/externs/app_window_common.js
@@ -30,3 +30,17 @@
  * @type {function(function())}
  */
 Window.prototype.HTMLImports.whenReady;
+
+/**
+ * True if in test: set by the background.js page.
+ *
+ * @type {boolean}
+ */
+Window.prototype.IN_TEST;
+
+/**
+ * Set true in some unit tests.
+ *
+ * @type {boolean}
+ */
+Window.prototype.UNIT_TEST;
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager.css b/ui/file_manager/file_manager/foreground/css/file_manager.css
index ff2e8a70..6c51b20ad 100644
--- a/ui/file_manager/file_manager/foreground/css/file_manager.css
+++ b/ui/file_manager/file_manager/foreground/css/file_manager.css
@@ -1019,16 +1019,22 @@
 #files-selected-label {
   display: none;
   font-weight: 500;
+}
+
+body:not(.files-ng) #files-selected-label {
   margin-inline-start: 20px;
 }
 
+body.files-ng #files-selected-label {
+  margin-inline-start: 8px;
+}
+
 body.check-select #files-selected-label {
   display: block;
 }
 
 #cancel-selection-button {
   --ink-color: currentColor;
-  background-color: transparent;
   border: none;
   box-shadow: none;
   color: currentColor;
@@ -1036,17 +1042,36 @@
   text-transform: none;
 }
 
-#cancel-selection-button:focus:not([tabindex='-1']):not(:active) {
+body:not(.files-ng) #cancel-selection-button {
+  background-color: transparent;
+}
+
+/* TODO(adanilo) document the calc() reason. */
+body.files-ng #cancel-selection-button {
+  border: 1px solid transparent;
+  margin-inline-start: calc(10px + 1px);
+  width: 36px;
+}
+
+body:not(.files-ng) #cancel-selection-button:focus:not([tabindex='-1']):not(:active) {
   background-color: rgba(153, 153, 153, 20%);
 }
 
-#cancel-selection-button > span {
+html.focus-outline-visible body.files-ng #cancel-selection-button:focus:not([tabindex='-1']):not(:active) {
+  border: 1px solid var(--google-blue-600);
+}
+
+body:not(.files-ng) #cancel-selection-button > span {
   display: inline-block;
   font-weight: 500;
   vertical-align: middle;
 }
 
-#cancel-selection-button .icon-arrow-back {
+body.files-ng #cancel-selection-button > span#cancel-selection-label {
+  display: none;
+}
+
+body:not(.files-ng) #cancel-selection-button .icon-arrow-back {
   background-image: -webkit-image-set(
       url(../images/files/ui/back.png) 1x,
       url(../images/files/ui/2x/back.png) 2x);
@@ -1058,9 +1083,22 @@
   width: 16px;
 }
 
+body.files-ng #cancel-selection-button .icon-arrow-back {
+  -webkit-mask-image: url(../images/files/ui/list_check.svg);
+  -webkit-mask-position: center;
+  -webkit-mask-repeat: no-repeat;
+  background-color: var(--google-blue-600);
+  flex: none;
+  height: 20px;
+  width: 20px;
+}
+
+body:not(.files-ng) #cancel-selection-button-wrapper {
+  width: 240px;  /* initial value, same as .dialog-navigation-list's width. */
+}
+
 #cancel-selection-button-wrapper {
   display: none;
-  width: 240px;  /* initial value, same as .dialog-navigation-list's width. */
 }
 
 #cancel-selection-button > iron-icon {
diff --git a/ui/file_manager/file_manager/foreground/js/toolbar_controller.js b/ui/file_manager/file_manager/foreground/js/toolbar_controller.js
index d797d8f8..6c182a5 100644
--- a/ui/file_manager/file_manager/foreground/js/toolbar_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/toolbar_controller.js
@@ -142,8 +142,12 @@
     this.deleteButton_.addEventListener(
         'click', this.onDeleteButtonClicked_.bind(this));
 
-    this.navigationList_.addEventListener(
-        'relayout', this.onNavigationListRelayout_.bind(this));
+    // The old layout needed the cancel selection button to resize every
+    // time the splitter was moved. Not needed for files-ng.
+    if (!util.isFilesNg()) {
+      this.navigationList_.addEventListener(
+          'relayout', this.onNavigationListRelayout_.bind(this));
+    }
 
     this.directoryModel_.addEventListener(
         'directory-changed', this.updateCurrentDirectoryButtons_.bind(this));
@@ -270,10 +274,13 @@
    * @private
    */
   onNavigationListRelayout_() {
-    // Make the width of spacer same as the width of navigation list.
-    const navWidth =
-        parseFloat(window.getComputedStyle(this.navigationList_).width);
-    this.cancelSelectionButtonWrapper_.style.width = navWidth + 'px';
+    // Not needed for files-ng, see comment above where this function is used.
+    if (!util.isFilesNg()) {
+      // Make the width of spacer same as the width of navigation list.
+      const navWidth =
+          parseFloat(window.getComputedStyle(this.navigationList_).width);
+      this.cancelSelectionButtonWrapper_.style.width = navWidth + 'px';
+    }
   }
 
   /**
diff --git a/ui/file_manager/file_manager/foreground/js/ui/breadcrumb.js b/ui/file_manager/file_manager/foreground/js/ui/breadcrumb.js
index 6b33d47b..5c51f08 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/breadcrumb.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/breadcrumb.js
@@ -423,10 +423,10 @@
     // Show drop-down below the elider button.
     const menu = this.shadowRoot.querySelector('cr-action-menu');
     const top = elider.offsetTop + elider.offsetHeight + 4;
-    menu.showAt(elider, {top: top});
+    !window.UNIT_TEST && menu.showAt(elider, {top: top});
 
     // Style drop-down and horizontal position.
-    const dialog = menu.getDialog();
+    const dialog = !window.UNIT_TEST ? menu.getDialog() : {style: {}};
     dialog.style['left'] = position + 'px';
     dialog.style['right'] = position + 'px';
     dialog.style['overflow'] = 'hidden auto';
@@ -455,7 +455,7 @@
 
     // Close the drop-down <dialog> if needed.
     const menu = this.shadowRoot.querySelector('cr-action-menu');
-    if (menu.getDialog().hasAttribute('open')) {
+    if (!window.UNIT_TEST && menu.getDialog().hasAttribute('open')) {
       menu.close();
     }
   }
diff --git a/url/url_canon_icu_unittest.cc b/url/url_canon_icu_unittest.cc
index 62ec1a9..4ce31d4 100644
--- a/url/url_canon_icu_unittest.cc
+++ b/url/url_canon_icu_unittest.cc
@@ -4,6 +4,7 @@
 
 #include <stddef.h>
 
+#include "base/logging.h"
 #include "base/stl_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/icu/source/common/unicode/ucnv.h"
@@ -22,6 +23,10 @@
   explicit UConvScoper(const char* charset_name) {
     UErrorCode err = U_ZERO_ERROR;
     converter_ = ucnv_open(charset_name, &err);
+    if (!converter_) {
+      LOG(ERROR) << "Failed to open charset " << charset_name << ": "
+                 << u_errorName(err);
+    }
   }
 
   ~UConvScoper() {