diff --git a/DEPS b/DEPS
index eb7e510..0388ba0 100644
--- a/DEPS
+++ b/DEPS
@@ -162,11 +162,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': 'c096654fa7c64fc2dccf38ca6ddd37f0e906000e',
+  'skia_revision': 'f07a36341330877adc12ab61582e13801dd7fe42',
   # 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': '778af2fde9d4c9e22a56f888396844bdfe1bca0f',
+  'v8_revision': '1a76e68814fab189993fa11e0cd534eb49df7977',
   # 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.
@@ -174,7 +174,7 @@
   # 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': '6d625bfe6e8a74869e2a6389512bb87ec7f8f4c3',
+  'angle_revision': '3c049a34714db5d033ba2edc82c8dfe7d911dc48',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -297,7 +297,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': '41f8aa550b4304d6132f8f7f7a6c0ae5eeee319d',
+  'dawn_revision': 'c3b613296d26ee9ffa1d0ecdb6e0bc8ab3ff9d7a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -853,7 +853,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '53ffaae2b80a9db82ac5093b77ec44625eeccf70',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '8de7737d65f367549efce0ad1677b6a3f2e79e10',
       'condition': 'checkout_linux',
   },
 
@@ -1257,7 +1257,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '55783c1d04037e95075acbed55abb2968a5c5819',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '5a9d89d158eb86d62e11caf7afac82060da98d2f',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1425,7 +1425,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '7c4e67ff117d6c640e6dd17989afe2fb7da7eecb',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'bc646eee208f90dd4297f88793616381f422b957',
+    Var('webrtc_git') + '/src.git' + '@' + '67309ef93c4f8ff0c62d2d8806f79e69cd553b5c',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1487,7 +1487,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@ca2ef4313b406944f445630ffc4f712c0fb84b64',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@a4f7741ee65c7dfc7b353ccf806d32b10feb32d4',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/browser/cookie_manager.h b/android_webview/browser/cookie_manager.h
index 82d7ccc66..fa763d7 100644
--- a/android_webview/browser/cookie_manager.h
+++ b/android_webview/browser/cookie_manager.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include <vector>
 
+#include "base/android/scoped_java_ref.h"
 #include "base/containers/circular_deque.h"
 #include "base/lazy_instance.h"
 #include "base/threading/thread.h"
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 3544b79b..27dbec4 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -1249,6 +1249,7 @@
     "//base/allocator:buildflags",
     "//base/third_party/double_conversion",
     "//base/third_party/dynamic_annotations",
+    "//build:branding_buildflags",
     "//third_party/modp_b64",
   ]
 
diff --git a/base/files/file_util_posix.cc b/base/files/file_util_posix.cc
index 5743863..72beeab 100644
--- a/base/files/file_util_posix.cc
+++ b/base/files/file_util_posix.cc
@@ -43,6 +43,7 @@
 #include "base/system/sys_info.h"
 #include "base/threading/scoped_blocking_call.h"
 #include "base/time/time.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 
 #if defined(OS_MACOSX)
@@ -134,7 +135,7 @@
   return StringPrintf(".%s.XXXXXX", base::mac::BaseBundleID());
 #endif
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   return std::string(".com.google.Chrome.XXXXXX");
 #else
   return std::string(".org.chromium.Chromium.XXXXXX");
diff --git a/base/mac/foundation_util.mm b/base/mac/foundation_util.mm
index 8b20ebc6..2a83d4d8 100644
--- a/base/mac/foundation_util.mm
+++ b/base/mac/foundation_util.mm
@@ -15,6 +15,7 @@
 #include "base/numerics/safe_conversions.h"
 #include "base/stl_util.h"
 #include "base/strings/sys_string_conversions.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 
 #if !defined(OS_IOS)
@@ -239,7 +240,7 @@
     return base_bundle_id;
   }
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   return "com.google.Chrome";
 #else
   return "org.chromium.Chromium";
diff --git a/base/message_loop/message_loop_unittest.cc b/base/message_loop/message_loop_unittest.cc
index 3cae10a..02cb94b5 100644
--- a/base/message_loop/message_loop_unittest.cc
+++ b/base/message_loop/message_loop_unittest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/message_loop/message_loop.h"
+
 #include <stddef.h>
 #include <stdint.h>
 
diff --git a/base/message_loop/message_pump_io_ios_unittest.cc b/base/message_loop/message_pump_io_ios_unittest.cc
index 4d15d44..aec10012 100644
--- a/base/message_loop/message_pump_io_ios_unittest.cc
+++ b/base/message_loop/message_pump_io_ios_unittest.cc
@@ -7,6 +7,7 @@
 #include <unistd.h>
 
 #include "base/macros.h"
+#include "base/message_loop/message_pump_for_io.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/test/gtest_util.h"
 #include "base/threading/thread.h"
diff --git a/base/threading/thread_perftest.cc b/base/threading/thread_perftest.cc
index e19b18b..5e1e65b 100644
--- a/base/threading/thread_perftest.cc
+++ b/base/threading/thread_perftest.cc
@@ -12,6 +12,7 @@
 #include "base/command_line.h"
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop_current.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/condition_variable.h"
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
index 8b1bd7a..d79d405 100644
--- a/base/trace_event/memory_dump_manager.cc
+++ b/base/trace_event/memory_dump_manager.cc
@@ -529,7 +529,8 @@
       dump_thread_task_runner(std::move(dump_thread_task_runner)) {
   pending_dump_providers.reserve(dump_providers.size());
   pending_dump_providers.assign(dump_providers.rbegin(), dump_providers.rend());
-  MemoryDumpArgs args = {req_args.level_of_detail, req_args.dump_guid};
+  MemoryDumpArgs args = {req_args.level_of_detail, req_args.determinism,
+                         req_args.dump_guid};
   process_memory_dump = std::make_unique<ProcessMemoryDump>(args);
 }
 
diff --git a/base/trace_event/memory_dump_manager_unittest.cc b/base/trace_event/memory_dump_manager_unittest.cc
index b33b677..c7b413d 100644
--- a/base/trace_event/memory_dump_manager_unittest.cc
+++ b/base/trace_event/memory_dump_manager_unittest.cc
@@ -54,6 +54,14 @@
   return arg.level_of_detail == MemoryDumpLevelOfDetail::LIGHT;
 }
 
+MATCHER(IsDeterministicDump, "") {
+  return arg.determinism == MemoryDumpDeterminism::FORCE_GC;
+}
+
+MATCHER(IsNotDeterministicDump, "") {
+  return arg.determinism == MemoryDumpDeterminism::NONE;
+}
+
 namespace {
 
 const char* kMDPName = "TestDumpProvider";
@@ -193,12 +201,14 @@
   // memory dump is complete. Returns:
   // - return value: the |success| from the CreateProcessDump() callback.
   bool RequestProcessDumpAndWait(MemoryDumpType dump_type,
-                                 MemoryDumpLevelOfDetail level_of_detail) {
+                                 MemoryDumpLevelOfDetail level_of_detail,
+                                 MemoryDumpDeterminism determinism) {
     RunLoop run_loop;
     bool success = false;
     static uint64_t test_guid = 1;
     test_guid++;
-    MemoryDumpRequestArgs request_args{test_guid, dump_type, level_of_detail};
+    MemoryDumpRequestArgs request_args{test_guid, dump_type, level_of_detail,
+                                       determinism};
 
     // The signature of the callback delivered by MemoryDumpManager is:
     // void ProcessMemoryDumpCallback(
@@ -276,7 +286,8 @@
   EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(3);
   for (int i = 0; i < 3; ++i) {
     EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                          MemoryDumpLevelOfDetail::DETAILED));
+                                          MemoryDumpLevelOfDetail::DETAILED,
+                                          MemoryDumpDeterminism::NONE));
   }
   DisableTracing();
 
@@ -288,7 +299,8 @@
   EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
   for (int i = 0; i < 3; ++i) {
     EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                          MemoryDumpLevelOfDetail::DETAILED));
+                                          MemoryDumpLevelOfDetail::DETAILED,
+                                          MemoryDumpDeterminism::NONE));
   }
   DisableTracing();
 }
@@ -302,7 +314,8 @@
   EnableForTracing();
   EXPECT_CALL(mdp, OnMemoryDump(IsDetailedDump(), _));
   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                        MemoryDumpLevelOfDetail::DETAILED));
+                                        MemoryDumpLevelOfDetail::DETAILED,
+                                        MemoryDumpDeterminism::NONE));
   DisableTracing();
   mdm_->UnregisterDumpProvider(&mdp);
 
@@ -312,7 +325,34 @@
   EnableForTracing();
   EXPECT_CALL(mdp, OnMemoryDump(IsLightDump(), _));
   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                        MemoryDumpLevelOfDetail::LIGHT));
+                                        MemoryDumpLevelOfDetail::LIGHT,
+                                        MemoryDumpDeterminism::NONE));
+  DisableTracing();
+  mdm_->UnregisterDumpProvider(&mdp);
+}
+
+// Checks that requesting deterministic dumps actually propagates
+// the deterministic option properly to OnMemoryDump() call on dump providers.
+TEST_F(MemoryDumpManagerTest, CheckMemoryDumpArgsDeterministic) {
+  MockMemoryDumpProvider mdp;
+
+  RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get());
+  EnableForTracing();
+  EXPECT_CALL(mdp, OnMemoryDump(IsDeterministicDump(), _));
+  EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                                        MemoryDumpLevelOfDetail::DETAILED,
+                                        MemoryDumpDeterminism::FORCE_GC));
+  DisableTracing();
+  mdm_->UnregisterDumpProvider(&mdp);
+
+  // Check that requesting dumps with deterministic option set to false
+  // actually propagates to OnMemoryDump() call on dump providers.
+  RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get());
+  EnableForTracing();
+  EXPECT_CALL(mdp, OnMemoryDump(IsNotDeterministicDump(), _));
+  EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                                        MemoryDumpLevelOfDetail::LIGHT,
+                                        MemoryDumpDeterminism::NONE));
   DisableTracing();
   mdm_->UnregisterDumpProvider(&mdp);
 }
@@ -328,7 +368,8 @@
   EXPECT_CALL(mdp1, OnMemoryDump(_, _));
   EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(0);
   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                        MemoryDumpLevelOfDetail::DETAILED));
+                                        MemoryDumpLevelOfDetail::DETAILED,
+                                        MemoryDumpDeterminism::NONE));
   DisableTracing();
 
   // Invert: enable mdp2 and disable mdp1.
@@ -338,7 +379,8 @@
   EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0);
   EXPECT_CALL(mdp2, OnMemoryDump(_, _));
   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                        MemoryDumpLevelOfDetail::DETAILED));
+                                        MemoryDumpLevelOfDetail::DETAILED,
+                                        MemoryDumpDeterminism::NONE));
   DisableTracing();
 
   // Enable both mdp1 and mdp2.
@@ -347,7 +389,8 @@
   EXPECT_CALL(mdp1, OnMemoryDump(_, _));
   EXPECT_CALL(mdp2, OnMemoryDump(_, _));
   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                        MemoryDumpLevelOfDetail::DETAILED));
+                                        MemoryDumpLevelOfDetail::DETAILED,
+                                        MemoryDumpDeterminism::NONE));
   DisableTracing();
 }
 
@@ -368,7 +411,8 @@
     EXPECT_CALL(mdp, OnMemoryDump(_, _));
     EnableForTracing();
     EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                          MemoryDumpLevelOfDetail::DETAILED));
+                                          MemoryDumpLevelOfDetail::DETAILED,
+                                          MemoryDumpDeterminism::NONE));
     DisableTracing();
   }
 
@@ -378,7 +422,8 @@
     EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
     EnableForTracing();
     EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                          MemoryDumpLevelOfDetail::DETAILED));
+                                          MemoryDumpLevelOfDetail::DETAILED,
+                                          MemoryDumpDeterminism::NONE));
     DisableTracing();
   }
 
@@ -389,7 +434,8 @@
     EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
     EnableForTracing();
     EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                          MemoryDumpLevelOfDetail::DETAILED));
+                                          MemoryDumpLevelOfDetail::DETAILED,
+                                          MemoryDumpDeterminism::NONE));
     DisableTracing();
   }
 
@@ -401,7 +447,8 @@
     EXPECT_CALL(mdp, OnMemoryDump(_, _));
     EnableForTracing();
     EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                          MemoryDumpLevelOfDetail::DETAILED));
+                                          MemoryDumpLevelOfDetail::DETAILED,
+                                          MemoryDumpDeterminism::NONE));
     DisableTracing();
   }
 }
@@ -439,7 +486,8 @@
 
   while (!threads.empty()) {
     EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                          MemoryDumpLevelOfDetail::DETAILED));
+                                          MemoryDumpLevelOfDetail::DETAILED,
+                                          MemoryDumpDeterminism::NONE));
 
     // Unregister a MDP and destroy one thread at each iteration to check the
     // live unregistration logic. The unregistration needs to happen on the same
@@ -485,13 +533,15 @@
 
   task_runner1->set_enabled(false);
   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                        MemoryDumpLevelOfDetail::DETAILED));
+                                        MemoryDumpLevelOfDetail::DETAILED,
+                                        MemoryDumpDeterminism::NONE));
   EXPECT_EQ(1u, task_runner1->no_of_post_tasks());
   EXPECT_EQ(1u, task_runner2->no_of_post_tasks());
 
   task_runner1->set_enabled(true);
   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                        MemoryDumpLevelOfDetail::DETAILED));
+                                        MemoryDumpLevelOfDetail::DETAILED,
+                                        MemoryDumpDeterminism::NONE));
   EXPECT_EQ(2u, task_runner1->no_of_post_tasks());
   EXPECT_EQ(2u, task_runner2->no_of_post_tasks());
   DisableTracing();
@@ -522,7 +572,8 @@
   const int kNumDumps = 2 * GetMaxConsecutiveFailuresCount();
   for (int i = 0; i < kNumDumps; i++) {
     EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                          MemoryDumpLevelOfDetail::DETAILED));
+                                          MemoryDumpLevelOfDetail::DETAILED,
+                                          MemoryDumpDeterminism::NONE));
   }
 
   DisableTracing();
@@ -553,7 +604,8 @@
 
   for (int i = 0; i < 4; i++) {
     EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                          MemoryDumpLevelOfDetail::DETAILED));
+                                          MemoryDumpLevelOfDetail::DETAILED,
+                                          MemoryDumpDeterminism::NONE));
   }
 
   DisableTracing();
@@ -584,7 +636,8 @@
 
   for (int i = 0; i < 4; i++) {
     EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                          MemoryDumpLevelOfDetail::DETAILED));
+                                          MemoryDumpLevelOfDetail::DETAILED,
+                                          MemoryDumpDeterminism::NONE));
   }
 
   DisableTracing();
@@ -632,7 +685,8 @@
 
   EnableForTracing();
   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                        MemoryDumpLevelOfDetail::DETAILED));
+                                        MemoryDumpLevelOfDetail::DETAILED,
+                                        MemoryDumpDeterminism::NONE));
   ASSERT_EQ(1, on_memory_dump_call_count);
 
   DisableTracing();
@@ -679,7 +733,8 @@
 
   EnableForTracing();
   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                        MemoryDumpLevelOfDetail::DETAILED));
+                                        MemoryDumpLevelOfDetail::DETAILED,
+                                        MemoryDumpDeterminism::NONE));
   ASSERT_EQ(1, on_memory_dump_call_count);
 
   DisableTracing();
@@ -692,7 +747,8 @@
   RegisterDumpProvider(&mdp, nullptr);
   EXPECT_CALL(mdp, OnMemoryDump(_, _));
   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                        MemoryDumpLevelOfDetail::DETAILED));
+                                        MemoryDumpLevelOfDetail::DETAILED,
+                                        MemoryDumpDeterminism::NONE));
 }
 
 TEST_F(MemoryDumpManagerTest, BackgroundWhitelisting) {
@@ -707,7 +763,8 @@
 
   EXPECT_CALL(backgroundMdp, OnMemoryDump(_, _)).Times(1);
   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::SUMMARY_ONLY,
-                                        MemoryDumpLevelOfDetail::BACKGROUND));
+                                        MemoryDumpLevelOfDetail::BACKGROUND,
+                                        MemoryDumpDeterminism::NONE));
   DisableTracing();
 }
 
@@ -769,7 +826,8 @@
   EnableForTracing();
   for (int i = 0; i < 2; ++i) {
     EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                          MemoryDumpLevelOfDetail::DETAILED));
+                                          MemoryDumpLevelOfDetail::DETAILED,
+                                          MemoryDumpDeterminism::NONE));
   }
   DisableTracing();
 }
@@ -822,11 +880,14 @@
   stopped_thread->Stop();
 
   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                        MemoryDumpLevelOfDetail::DETAILED));
+                                        MemoryDumpLevelOfDetail::DETAILED,
+                                        MemoryDumpDeterminism::NONE));
   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                        MemoryDumpLevelOfDetail::BACKGROUND));
+                                        MemoryDumpLevelOfDetail::BACKGROUND,
+                                        MemoryDumpDeterminism::NONE));
   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::SUMMARY_ONLY,
-                                        MemoryDumpLevelOfDetail::BACKGROUND));
+                                        MemoryDumpLevelOfDetail::BACKGROUND,
+                                        MemoryDumpDeterminism::NONE));
 }
 
 }  // namespace trace_event
diff --git a/base/trace_event/memory_dump_request_args.h b/base/trace_event/memory_dump_request_args.h
index c50a1cb..d62a0dc 100644
--- a/base/trace_event/memory_dump_request_args.h
+++ b/base/trace_event/memory_dump_request_args.h
@@ -58,6 +58,12 @@
   LAST = DETAILED
 };
 
+// Tells the MemoryDumpProvider(s) if they should try to make the result
+// more deterministic by forcing garbage collection.
+// Keep this consistent with memory_instrumentation.mojo and
+// memory_instrumentation_struct_traits.{h,cc}
+enum class MemoryDumpDeterminism : uint32_t { NONE, FORCE_GC };
+
 // Keep this consistent with memory_instrumentation.mojo and
 // memory_instrumentation_struct_traits.{h,cc}
 struct BASE_EXPORT MemoryDumpRequestArgs {
@@ -68,6 +74,7 @@
 
   MemoryDumpType dump_type;
   MemoryDumpLevelOfDetail level_of_detail;
+  MemoryDumpDeterminism determinism;
 };
 
 // Args for ProcessMemoryDump and passed to OnMemoryDump calls for memory dump
@@ -75,6 +82,8 @@
 struct MemoryDumpArgs {
   // Specifies how detailed the dumps should be.
   MemoryDumpLevelOfDetail level_of_detail;
+  // Specifies whether the dumps should be more deterministic.
+  MemoryDumpDeterminism determinism;
 
   // Globally unique identifier. In multi-process dumps, all processes issue a
   // local dump with the same guid. This allows the trace importers to
diff --git a/base/win/windows_types.h b/base/win/windows_types.h
index a57277a..60c4ffe 100644
--- a/base/win/windows_types.h
+++ b/base/win/windows_types.h
@@ -244,6 +244,8 @@
 #define DeleteFile DeleteFileW
 #define DispatchMessage DispatchMessageW
 #define DrawText DrawTextW
+#define FindFirstFile FindFirstFileW
+#define FindNextFile FindNextFileW
 #define GetComputerName GetComputerNameW
 #define GetCurrentDirectory GetCurrentDirectoryW
 #define GetCurrentTime() GetTickCount()
@@ -253,6 +255,7 @@
 #define LoadIcon LoadIconW
 #define LoadImage LoadImageW
 #define PostMessage PostMessageW
+#define RemoveDirectory RemoveDirectoryW
 #define ReplaceFile ReplaceFileW
 #define ReportEvent ReportEventW
 #define SendMessage SendMessageW
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 7bd8ab14..25944cf 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8901476404455095504
\ No newline at end of file
+8901447639518533984
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index de90e86..0d6122f 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-8901478046424570128
\ No newline at end of file
+8901448833775125712
\ No newline at end of file
diff --git a/cc/layers/texture_layer_unittest.cc b/cc/layers/texture_layer_unittest.cc
index 0f5a97da..f47ff407 100644
--- a/cc/layers/texture_layer_unittest.cc
+++ b/cc/layers/texture_layer_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/callback.h"
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
 #include "base/sequenced_task_runner.h"
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/lock.h"
diff --git a/cc/paint/paint_canvas.h b/cc/paint/paint_canvas.h
index ff5a69b..32918efd 100644
--- a/cc/paint/paint_canvas.h
+++ b/cc/paint/paint_canvas.h
@@ -176,7 +176,6 @@
   virtual void drawPicture(sk_sp<const PaintRecord> record) = 0;
 
   virtual bool isClipEmpty() const = 0;
-  virtual bool isClipRect() const = 0;
   virtual const SkMatrix& getTotalMatrix() const = 0;
 
   // Used for printing
diff --git a/cc/paint/record_paint_canvas.cc b/cc/paint/record_paint_canvas.cc
index d53569f7..b6c58cb 100644
--- a/cc/paint/record_paint_canvas.cc
+++ b/cc/paint/record_paint_canvas.cc
@@ -296,11 +296,6 @@
   return GetCanvas()->isClipEmpty();
 }
 
-bool RecordPaintCanvas::isClipRect() const {
-  DCHECK(InitializedWithRecordingBounds());
-  return GetCanvas()->isClipRect();
-}
-
 const SkMatrix& RecordPaintCanvas::getTotalMatrix() const {
   return GetCanvas()->getTotalMatrix();
 }
diff --git a/cc/paint/record_paint_canvas.h b/cc/paint/record_paint_canvas.h
index 24fb177..27256f5 100644
--- a/cc/paint/record_paint_canvas.h
+++ b/cc/paint/record_paint_canvas.h
@@ -102,7 +102,6 @@
   void drawPicture(sk_sp<const PaintRecord> record) override;
 
   bool isClipEmpty() const override;
-  bool isClipRect() const override;
   const SkMatrix& getTotalMatrix() const override;
 
   void Annotate(AnnotationType type,
diff --git a/cc/paint/skia_paint_canvas.cc b/cc/paint/skia_paint_canvas.cc
index d014d7e..72d34e9 100644
--- a/cc/paint/skia_paint_canvas.cc
+++ b/cc/paint/skia_paint_canvas.cc
@@ -328,10 +328,6 @@
   return canvas_->isClipEmpty();
 }
 
-bool SkiaPaintCanvas::isClipRect() const {
-  return canvas_->isClipRect();
-}
-
 const SkMatrix& SkiaPaintCanvas::getTotalMatrix() const {
   return canvas_->getTotalMatrix();
 }
diff --git a/cc/paint/skia_paint_canvas.h b/cc/paint/skia_paint_canvas.h
index 6c567ce..3dc12517 100644
--- a/cc/paint/skia_paint_canvas.h
+++ b/cc/paint/skia_paint_canvas.h
@@ -126,7 +126,6 @@
   void drawPicture(sk_sp<const PaintRecord> record) override;
 
   bool isClipEmpty() const override;
-  bool isClipRect() const override;
   const SkMatrix& getTotalMatrix() const override;
 
   void Annotate(AnnotationType type,
diff --git a/chrome/android/chrome_junit_test_java_sources.gni b/chrome/android/chrome_junit_test_java_sources.gni
index 8b207ec..59a03e5 100644
--- a/chrome/android/chrome_junit_test_java_sources.gni
+++ b/chrome/android/chrome_junit_test_java_sources.gni
@@ -18,6 +18,7 @@
   "junit/src/org/chromium/chrome/browser/autofill/AutofillUiUtilsTest.java",
   "junit/src/org/chromium/chrome/browser/background_sync/BackgroundSyncBackgroundTaskSchedulerTest.java",
   "junit/src/org/chromium/chrome/browser/background_sync/BackgroundSyncBackgroundTaskTest.java",
+  "junit/src/org/chromium/chrome/browser/background_sync/BackgroundSyncGooglePlayServicesCheckerTest.java",
   "junit/src/org/chromium/chrome/browser/background_sync/PeriodicBackgroundSyncChromeWakeUpTaskTest.java",
   "junit/src/org/chromium/chrome/browser/background_task_scheduler/NativeBackgroundTaskTest.java",
   "junit/src/org/chromium/chrome/browser/browserservices/ClearDataDialogResultRecorderTest.java",
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni
index 900993a..7f884d3 100644
--- a/chrome/android/chrome_test_java_sources.gni
+++ b/chrome/android/chrome_test_java_sources.gni
@@ -303,6 +303,7 @@
   "javatests/src/org/chromium/chrome/browser/password_manager/OnboardingDialogIntegrationTest.java",
   "javatests/src/org/chromium/chrome/browser/password_manager/PasswordGenerationDialogTest.java",
   "javatests/src/org/chromium/chrome/browser/password_manager/PasswordManagerDialogTest.java",
+  "javatests/src/org/chromium/chrome/browser/payments/micro/MicrotransactionRenderTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinderTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/CurrencyFormatterTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/MockPackageManagerDelegate.java",
diff --git a/chrome/android/features/start_surface/internal/java/res/layout/ss_feed_header.xml b/chrome/android/features/start_surface/internal/java/res/layout/ss_feed_header.xml
new file mode 100644
index 0000000..83daf1f
--- /dev/null
+++ b/chrome/android/features/start_surface/internal/java/res/layout/ss_feed_header.xml
@@ -0,0 +1,31 @@
+<?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. -->
+
+<org.chromium.chrome.browser.ntp.snippets.SectionHeaderView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="@dimen/snippets_article_header_height"
+    android:orientation="horizontal"
+    android:paddingTop="8dp"
+    android:paddingBottom="8dp"
+    android:gravity="center_vertical">
+
+    <TextView
+        android:id="@+id/header_title"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:paddingStart="6dp"
+        android:textAlignment="viewStart"
+        android:textAppearance="@style/TextAppearance.BlackTitle2" />
+
+    <TextView
+        android:id="@+id/header_status"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="@style/TextAppearance.BlueLink2" />
+
+</org.chromium.chrome.browser.ntp.snippets.SectionHeaderView>
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceCoordinator.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceCoordinator.java
index 0cb06b0..b5f1bb9 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceCoordinator.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceCoordinator.java
@@ -18,6 +18,7 @@
 import org.chromium.chrome.browser.feed.FeedProcessScopeFactory;
 import org.chromium.chrome.browser.feed.FeedSurfaceCoordinator;
 import org.chromium.chrome.browser.feed.StreamLifecycleManager;
+import org.chromium.chrome.browser.ntp.snippets.SectionHeaderView;
 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.start_surface.R;
@@ -29,6 +30,7 @@
     private final ChromeActivity mActivity;
     private final PropertyModelChangeProcessor mPropertyModelChangeProcessor;
     private final FeedSurfaceCreator mFeedSurfaceCreator;
+    private final boolean mHasHeader;
 
     // mExploreSurfaceNavigationDelegate is lightweight, we keep it across FeedSurfaceCoordinators
     // after creating it during the first show.
@@ -46,10 +48,11 @@
     ExploreSurfaceCoordinator(ChromeActivity activity, ViewGroup parentView,
             @Nullable ViewGroup headerContainerView, PropertyModel containerPropertyModel) {
         mActivity = activity;
+        mHasHeader = (headerContainerView != null);
 
         mPropertyModelChangeProcessor = PropertyModelChangeProcessor.create(containerPropertyModel,
                 new ExploreSurfaceViewBinder.ViewHolder(parentView,
-                        headerContainerView == null
+                        !mHasHeader
                                 ? null
                                 : (NestedScrollView) LayoutInflater.from(activity).inflate(
                                         R.layout.ss_explore_scroll_container, parentView, false),
@@ -58,7 +61,7 @@
         mFeedSurfaceCreator = new FeedSurfaceCreator() {
             @Override
             public FeedSurfaceCoordinator createFeedSurfaceCoordinator() {
-                return internalCreateFeedSurfaceCoordinator();
+                return internalCreateFeedSurfaceCoordinator(mHasHeader);
             }
         };
     }
@@ -74,7 +77,7 @@
     // Implements FeedSurfaceCoordinator.FeedSurfaceDelegate.
     @Override
     public StreamLifecycleManager createStreamLifecycleManager(Stream stream, Activity activity) {
-        return new ExploreSurfaceStreamLifecycleManager(stream, activity);
+        return new ExploreSurfaceStreamLifecycleManager(stream, activity, mHasHeader);
     }
 
     @Override
@@ -82,9 +85,10 @@
         return false;
     }
 
-    private FeedSurfaceCoordinator internalCreateFeedSurfaceCoordinator() {
-        if (mExploreSurfaceNavigationDelegate == null)
+    private FeedSurfaceCoordinator internalCreateFeedSurfaceCoordinator(boolean hasHeader) {
+        if (mExploreSurfaceNavigationDelegate == null) {
             mExploreSurfaceNavigationDelegate = new ExploreSurfaceNavigationDelegate(mActivity);
+        }
 
         ExploreSurfaceActionHandler exploreSurfaceActionHandler =
                 new ExploreSurfaceActionHandler(mExploreSurfaceNavigationDelegate,
@@ -92,8 +96,15 @@
                         FeedProcessScopeFactory.getFeedOfflineIndicator(),
                         OfflinePageBridge.getForProfile(Profile.getLastUsedProfile()),
                         FeedProcessScopeFactory.getFeedLoggingBridge());
-        return new FeedSurfaceCoordinator(
-                mActivity, null, null, null, exploreSurfaceActionHandler, false, this);
+
+        SectionHeaderView sectionHeaderView = null;
+        if (hasHeader) {
+            LayoutInflater inflater = LayoutInflater.from(mActivity);
+            sectionHeaderView =
+                    (SectionHeaderView) inflater.inflate(R.layout.ss_feed_header, null, false);
+        }
+        return new FeedSurfaceCoordinator(mActivity, null, null, null, sectionHeaderView,
+                exploreSurfaceActionHandler, false, this);
         // TODO(crbug.com/982018): Customize surface background for incognito and dark mode.
         // TODO(crbug.com/982018): Hide signin promo UI in incognito mode.
     }
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceStreamLifecycleManager.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceStreamLifecycleManager.java
index 2e98e757..b227dd0 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceStreamLifecycleManager.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceStreamLifecycleManager.java
@@ -9,19 +9,40 @@
 import com.google.android.libraries.feed.api.client.stream.Stream;
 
 import org.chromium.chrome.browser.feed.StreamLifecycleManager;
+import org.chromium.chrome.browser.preferences.Pref;
+import org.chromium.chrome.browser.preferences.PrefServiceBridge;
 
 /** Explore surface feed stream lifecycle manager. */
 class ExploreSurfaceStreamLifecycleManager extends StreamLifecycleManager {
+    private final boolean mHasHeader;
     /**
      * The constructor.
      * @param stream The {@link Stream} this manager manages.
      * @param activity The activity the {@link Stream} associates with.
      */
-    ExploreSurfaceStreamLifecycleManager(Stream stream, Activity activity) {
+    ExploreSurfaceStreamLifecycleManager(Stream stream, Activity activity, boolean hasHeader) {
         super(stream, activity);
+        mHasHeader = hasHeader;
         start();
     }
 
+    @Override
+    protected boolean canShow() {
+        return super.canShow() && shouldShowFeed();
+    }
+
+    @Override
+    protected boolean canActivate() {
+        return super.canShow() && shouldShowFeed();
+    }
+
+    private boolean shouldShowFeed() {
+        // If there is a header to opt out from article suggestions, we don't call
+        // Stream#onShow to prevent feed services from being warmed up if the user
+        // has opted out during the previous session.
+        return (!mHasHeader
+                || PrefServiceBridge.getInstance().getBoolean(Pref.NTP_ARTICLES_LIST_VISIBLE));
+    }
     // TODO(crbug.com/982018): Save and restore instance state when opening the feeds in normal
     // Tabs.
-}
\ No newline at end of file
+}
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutPerfTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutPerfTest.java
index c2c0ec8..70ab0918 100644
--- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutPerfTest.java
+++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutPerfTest.java
@@ -106,12 +106,6 @@
             mTabNumCap = 0;
         }
         assertTrue(FeatureUtilities.isTabToGtsAnimationEnabled());
-
-        CriteriaHelper.pollUiThread(Criteria.equals(true,
-                mActivityTestRule.getActivity()
-                        .getTabModelSelector()
-                        .getTabModelFilterProvider()
-                        .getCurrentTabModelFilter()::isTabModelRestored));
     }
 
     @Test
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 724e057..4501645 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
@@ -4,10 +4,6 @@
 
 package org.chromium.chrome.features.start_surface;
 
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.click;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
@@ -21,16 +17,15 @@
 import android.graphics.Bitmap;
 import android.os.Build;
 import android.provider.Settings;
-import android.support.annotation.Nullable;
 import android.support.test.InstrumentationRegistry;
-import android.support.test.espresso.NoMatchingViewException;
-import android.support.test.espresso.ViewAssertion;
+import android.support.test.espresso.Espresso;
+import android.support.test.espresso.action.ViewActions;
 import android.support.test.espresso.contrib.RecyclerViewActions;
+import android.support.test.espresso.matcher.ViewMatchers;
 import android.support.test.filters.MediumTest;
-import android.support.test.filters.SmallTest;
-import android.support.v7.widget.RecyclerView;
 import android.text.TextUtils;
-import android.view.View;
+
+import androidx.annotation.Nullable;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -80,6 +75,7 @@
         "force-fieldtrials=Study/Group"})
 @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
 public class StartSurfaceLayoutTest {
+    private static final String TAG = "SSLayoutTest";
     private static final String BASE_PARAMS = "force-fieldtrial-params="
             + "Study.Group:soft-cleanup-delay/0/cleanup-delay/0/skip-slow-zooming/false"
             + "/zooming-min-sdk-version/19/zooming-min-memory-mb/512";
@@ -100,7 +96,6 @@
     @Before
     public void setUp() throws InterruptedException {
         FeatureUtilities.setGridTabSwitcherEnabledForTesting(true);
-
         EmbeddedTestServer testServer =
                 EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext());
         mActivityTestRule.startMainActivityFromLauncher();
@@ -118,12 +113,6 @@
 
         mActivityTestRule.getActivity().getTabContentManager().setCaptureMinRequestTimeForTesting(
                 0);
-
-        CriteriaHelper.pollUiThread(Criteria.equals(true,
-                mActivityTestRule.getActivity()
-                        .getTabModelSelector()
-                        .getTabModelFilterProvider()
-                        .getCurrentTabModelFilter()::isTabModelRestored));
     }
 
     @Test
@@ -351,9 +340,8 @@
             if (mActivityTestRule.getActivity()
                             .getTabContentManager()
                             .getPendingReadbacksForTesting()
-                    > 0) {
+                    > 0)
                 break;
-            }
 
             // Restart Chrome.
             // Although we're destroying the activity, the Application will still live on since its
@@ -427,8 +415,9 @@
                 waitForCaptureRateControl();
             }
             int count = getCaptureCount();
-            onView(withId(org.chromium.chrome.tab_ui.R.id.tab_list_view))
-                    .perform(RecyclerViewActions.actionOnItemAtPosition(targetIndex, click()));
+            Espresso.onView(ViewMatchers.withId(org.chromium.chrome.tab_ui.R.id.tab_list_view))
+                    .perform(RecyclerViewActions.actionOnItemAtPosition(
+                            targetIndex, ViewActions.click()));
             CriteriaHelper.pollUiThread(() -> {
                 boolean doneHiding =
                         !mActivityTestRule.getActivity().getLayoutManager().overviewVisible();
@@ -543,57 +532,14 @@
         Assert.assertEquals(0, mAllBitmaps.size() - count);
     }
 
-    @Test
-    @SmallTest
-    @CommandLineFlags.Add({BASE_PARAMS})
-    public void testIncognitoEnterGts() throws Exception {
-        mActivityTestRule.newIncognitoTabFromMenu();
-        onView(withId(org.chromium.chrome.R.id.tab_switcher_button)).perform(click());
-
-        onView(withId(org.chromium.chrome.tab_ui.R.id.tab_list_view))
-                .check(TabCountAssertion.havingTabCount(1));
-
-        onView(withId(org.chromium.chrome.tab_ui.R.id.tab_list_view))
-                .perform(RecyclerViewActions.actionOnItemAtPosition(0, click()));
-
-        CriteriaHelper.pollInstrumentationThread(
-                () -> !mActivityTestRule.getActivity().getLayoutManager().overviewVisible());
-
-        onView(withId(org.chromium.chrome.R.id.tab_switcher_button)).perform(click());
-
-        onView(withId(org.chromium.chrome.tab_ui.R.id.tab_list_view))
-                .check(TabCountAssertion.havingTabCount(1));
-    }
-
-    private static class TabCountAssertion implements ViewAssertion {
-        private int mExpectedCount;
-
-        public static TabCountAssertion havingTabCount(int tabCount) {
-            return new TabCountAssertion(tabCount);
-        }
-
-        public TabCountAssertion(int expectedCount) {
-            mExpectedCount = expectedCount;
-        }
-
-        @Override
-        public void check(View view, NoMatchingViewException noMatchException) {
-            if (noMatchException != null) throw noMatchException;
-
-            RecyclerView.Adapter adapter = ((RecyclerView) view).getAdapter();
-            assertEquals(mExpectedCount, adapter.getItemCount());
-        }
-    }
-
     private void enterGTS() throws InterruptedException {
         Tab currentTab = mActivityTestRule.getActivity().getTabModelSelector().getCurrentTab();
         // Native tabs need to be invalidated first to trigger thumbnail taking, so skip them.
         boolean checkThumbnail = !currentTab.isNativePage();
 
-        if (checkThumbnail) {
+        if (checkThumbnail)
             mActivityTestRule.getActivity().getTabContentManager().removeTabThumbnail(
                     currentTab.getId());
-        }
 
         int count = getCaptureCount();
         waitForCaptureRateControl();
diff --git a/chrome/android/features/tab_ui/java/res/drawable/ic_arrow_right.xml b/chrome/android/features/tab_ui/java/res/drawable/ic_arrow_right.xml
new file mode 100644
index 0000000..a0de3e9
--- /dev/null
+++ b/chrome/android/features/tab_ui/java/res/drawable/ic_arrow_right.xml
@@ -0,0 +1,11 @@
+<?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. -->
+
+<vector xmlns:tools="http://schemas.android.com/tools" tools:targetApi="21"
+    android:autoMirrored="true" android:height="24dp"
+    android:viewportHeight="24" android:viewportWidth="24"
+    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="@color/default_icon_color" android:pathData="M8.59,16.59L13.17,12L8.59,7.41L10,6l6,6l-6,6L8.59,16.59z"/>
+</vector>
diff --git a/chrome/android/features/tab_ui/java/res/layout/tasks_view_layout.xml b/chrome/android/features/tab_ui/java/res/layout/tasks_view_layout.xml
index 6350e1cd..1f87ec2a 100644
--- a/chrome/android/features/tab_ui/java/res/layout/tasks_view_layout.xml
+++ b/chrome/android/features/tab_ui/java/res/layout/tasks_view_layout.xml
@@ -26,6 +26,10 @@
         android:id="@+id/tab_switcher_title"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        android:paddingStart="12dp"
+        android:paddingEnd="4dp"
+        android:paddingTop="8dp"
+        android:paddingBottom="8dp"
         android:visibility="gone"
         android:background="@color/modern_primary_color"
         android:orientation="horizontal">
@@ -34,23 +38,28 @@
             android:layout_height="wrap_content"
             android:layout_weight="1.0"
             android:layout_gravity="center_vertical"
-            android:paddingTop="@dimen/tasks_view_items_vertical_spacing"
-            android:paddingBottom="@dimen/tasks_view_items_vertical_spacing"
-            android:paddingStart="24dp"
-            android:paddingEnd="16dp"
-            android:textAlignment="viewStart"
-            android:textAppearance="@style/TextAppearance.BlackCaption"
+            android:gravity="center_vertical"
+            android:paddingStart="6dp"
+            android:singleLine="true"
+            android:textAppearance="@style/TextAppearance.BlackTitle2"
             android:text="@string/tab_switcher_carousel_title" />
-        <org.chromium.ui.widget.ChromeImageButton
+        <org.chromium.ui.widget.ChromeImageView
             android:id="@+id/more_tabs"
-            style="@style/ToolbarButton"
-            android:layout_height="wrap_content"
-            android:src="@drawable/breadcrumb_arrow"
-            tools:tint="@color/standard_mode_tint"
+            android:layout_width="48dp"
+            android:layout_height="48dp"
+            android:layout_gravity="center_vertical|end"
+            android:layout_marginTop="-16dp"
+            android:layout_marginBottom="-16dp"
+            android:scaleType="center"
+            android:src="@drawable/ic_arrow_right"
+            android:tint="@color/default_icon_color"
+            android:tintMode="src_in"
+            android:paddingTop="16dp"
+            android:paddingBottom="16dp"
             android:contentDescription="@string/accessibility_tab_switcher_carousel_more_tabs"/>
     </LinearLayout>
     <FrameLayout
         android:id="@+id/tab_switcher_container"
         android:layout_width="match_parent"
         android:layout_height="match_parent" />
-</org.chromium.chrome.browser.tasks.TasksView>
\ No newline at end of file
+</org.chromium.chrome.browser.tasks.TasksView>
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupModelFilter.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupModelFilter.java
index 9657a526..89eaf472 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupModelFilter.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupModelFilter.java
@@ -101,7 +101,7 @@
      * group.
      */
     private class TabGroup {
-        private static final int INVALID_GROUP_ID = -1;
+        private final static int INVALID_GROUP_ID = -1;
         private final Set<Integer> mTabIds;
         private int mLastShownTabId;
         private int mGroupId;
@@ -174,6 +174,7 @@
     private int mActualGroupCount;
     private Tab mAbsentSelectedTab;
     private boolean mShouldRecordUma = true;
+    private boolean mTabRestoreCompleted;
     private boolean mIsResetting;
 
     public TabGroupModelFilter(TabModel tabModel) {
@@ -187,6 +188,7 @@
                 RecordHistogram.recordCountHistogram("TabGroups.UserGroupCount", mActualGroupCount);
                 Tab currentTab = TabModelUtils.getCurrentTab(getTabModel());
                 if (currentTab != null) recordSessionsCount(currentTab);
+                mTabRestoreCompleted = true;
                 removeObserver(this);
             }
         });
@@ -652,7 +654,7 @@
     public void didMoveTab(Tab tab, int newIndex, int curIndex) {
         // Ignore didMoveTab calls in tab restoring stage. For incognito mode, bypass this check
         // since there is no restoring stage.
-        if (!isTabModelRestored()) return;
+        if (!mTabRestoreCompleted && !isIncognito()) return;
         // Need to cache the flags before resetting the internal data map.
         boolean isMergeTabToGroup = isMergeTabToGroup(tab);
         boolean isMoveTabOutOfGroup = isMoveTabOutOfGroup(tab);
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 62631c0..3123116 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
@@ -739,13 +739,7 @@
      * The selected border should re-appear in the final fading-in stage.
      */
     void prepareOverview() {
-        if (!FeatureUtilities.isTabToGtsAnimationEnabled()
-                || !mTabModelSelector.getTabModelFilterProvider()
-                            .getCurrentTabModelFilter()
-                            .isTabModelRestored()) {
-            return;
-        }
-
+        if (!FeatureUtilities.isTabToGtsAnimationEnabled()) return;
         assert mVisible;
         int count = 0;
         for (int i = 0; i < mModel.size(); i++) {
@@ -822,7 +816,7 @@
     }
 
     /**
-     * @see TabSwitcherMediator.ResetHandler#softCleanup
+     * @see GridTabSwitcherMediator.ResetHandler#softCleanup
      */
     void softCleanup() {
         assert !mVisible;
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 ab3f495..8d630fd 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
@@ -119,7 +119,7 @@
     private boolean mShouldIgnoreNextSelect;
 
     private int mModelIndexWhenShown;
-    private int mTabIdWhenShown;
+    private int mTabIdwhenShown;
     private int mIndexInNewModelWhenSwitched;
     private boolean mIsSelectingInTabSwitcher;
 
@@ -225,15 +225,6 @@
                     onTabSelecting(tab.getId());
                 }
             }
-
-            @Override
-            public void restoreCompleted() {
-                if (!mContainerViewModel.get(IS_VISIBLE)) return;
-
-                mResetHandler.resetWithTabList(
-                        mTabModelSelector.getTabModelFilterProvider().getCurrentTabModelFilter(),
-                        false, mShowTabsInMruOrder);
-            }
         };
 
         mFullscreenManager.addListener(mFullscreenListener);
@@ -344,7 +335,7 @@
         Tab fromTab = TabModelUtils.getTabById(mTabModelSelector.getCurrentModel(), lastId);
         assert fromTab != null;
         if (mModelIndexWhenShown == mTabModelSelector.getCurrentModelIndex()) {
-            if (tab.getId() == mTabIdWhenShown) {
+            if (tab.getId() == mTabIdwhenShown) {
                 RecordUserAction.record("MobileTabReturnedToCurrentTab");
                 RecordHistogram.recordSparseHistogram(
                         "Tabs.TabOffsetOfSwitch." + TabSwitcherCoordinator.COMPONENT_NAME, 0);
@@ -420,10 +411,7 @@
         mHandler.removeCallbacks(mSoftClearTabListRunnable);
         mHandler.removeCallbacks(mClearTabListRunnable);
         boolean quick = false;
-        if (FeatureUtilities.isTabToGtsAnimationEnabled()
-                && mTabModelSelector.getTabModelFilterProvider()
-                           .getCurrentTabModelFilter()
-                           .isTabModelRestored()) {
+        if (FeatureUtilities.isTabToGtsAnimationEnabled()) {
             quick = mResetHandler.resetWithTabList(
                     mTabModelSelector.getTabModelFilterProvider().getCurrentTabModelFilter(), false,
                     mShowTabsInMruOrder);
@@ -441,17 +429,13 @@
 
     @Override
     public void showOverview(boolean animate) {
-        if (mTabModelSelector.getTabModelFilterProvider()
-                        .getCurrentTabModelFilter()
-                        .isTabModelRestored()) {
-            mResetHandler.resetWithTabList(
-                    mTabModelSelector.getTabModelFilterProvider().getCurrentTabModelFilter(),
-                    FeatureUtilities.isTabToGtsAnimationEnabled(), mShowTabsInMruOrder);
-        }
+        mResetHandler.resetWithTabList(
+                mTabModelSelector.getTabModelFilterProvider().getCurrentTabModelFilter(),
+                FeatureUtilities.isTabToGtsAnimationEnabled(), mShowTabsInMruOrder);
         if (!animate) mContainerViewModel.set(ANIMATE_VISIBILITY_CHANGES, false);
         setVisibility(true);
         mModelIndexWhenShown = mTabModelSelector.getCurrentModelIndex();
-        mTabIdWhenShown = mTabModelSelector.getCurrentTabId();
+        mTabIdwhenShown = mTabModelSelector.getCurrentTabId();
         mContainerViewModel.set(ANIMATE_VISIBILITY_CHANGES, true);
         if (mIphProvider != null) {
             mIphProvider.maybeShowIPH(mTabModelSelector.isIncognitoSelected());
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupModelFilterUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupModelFilterUnitTest.java
index 7233aa9..8d15da7 100644
--- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupModelFilterUnitTest.java
+++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupModelFilterUnitTest.java
@@ -272,23 +272,6 @@
     }
 
     @Test
-    // TODO(mattsimmons): This is actually testing behavior of the superclass but there's no unit
-    //  tests for the superclass today. If one ever exists, this should move to that test.
-    public void isTabModelRestored() {
-        setupTabGroupModelFilter(false, false);
-        assertThat(mTabGroupModelFilter.isTabModelRestored(), equalTo(false));
-
-        setupTabGroupModelFilter(true, false);
-        assertThat(mTabGroupModelFilter.isTabModelRestored(), equalTo(true));
-
-        setupTabGroupModelFilter(false, true);
-        assertThat(mTabGroupModelFilter.isTabModelRestored(), equalTo(true));
-
-        setupTabGroupModelFilter(true, true);
-        assertThat(mTabGroupModelFilter.isTabModelRestored(), equalTo(true));
-    }
-
-    @Test
     public void addTab_ToExistingGroup() {
         Tab newTab = prepareTab(NEW_TAB_ID, NEW_TAB_ID, TAB1_ID);
         doReturn(TabLaunchType.FROM_CHROME_UI).when(newTab).getLaunchType();
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 63a1567..10771ef 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
@@ -434,60 +434,6 @@
     }
 
     @Test
-    public void updatesResetHandlerOnRestoreCompleted() {
-        initAndAssertAllProperties();
-        mMediator.showOverview(true);
-        assertThat(mModel.get(TabListContainerProperties.IS_VISIBLE), equalTo(true));
-
-        mTabModelObserverCaptor.getValue().restoreCompleted();
-
-        // MRU will be false unless the start surface is enabled.
-        verify(mResetHandler).resetWithTabList(mTabModelFilter, false, false);
-    }
-
-    @Test
-    public void showOverviewDoesNotUpdateResetHandlerBeforeRestoreCompleted() {
-        initAndAssertAllProperties();
-        doReturn(false).when(mTabModelFilter).isTabModelRestored();
-        mMediator.showOverview(true);
-
-        // MRU will be false unless the start surface is enabled.
-        verify(mResetHandler, never()).resetWithTabList(mTabModelFilter, true, false);
-    }
-
-    @Test
-    public void prepareOverviewDoesNotUpdateResetHandlerBeforeRestoreCompleted() {
-        initAndAssertAllProperties();
-        doReturn(false).when(mTabModelFilter).isTabModelRestored();
-        mMediator.prepareOverview();
-
-        // MRU will be false unless the start surface is enabled.
-        verify(mResetHandler, never()).resetWithTabList(mTabModelFilter, false, false);
-    }
-
-    @Test
-    public void showOverviewUpdatesResetHandlerAfterRestoreCompleted() {
-        initAndAssertAllProperties();
-        doReturn(true).when(mTabModelFilter).isTabModelRestored();
-
-        mMediator.showOverview(true);
-
-        // MRU will be false unless the start surface is enabled.
-        verify(mResetHandler).resetWithTabList(mTabModelFilter, true, false);
-    }
-
-    @Test
-    public void prepareOverviewUpdatesResetHandlerAfterRestoreCompleted() {
-        initAndAssertAllProperties();
-        doReturn(true).when(mTabModelFilter).isTabModelRestored();
-
-        mMediator.prepareOverview();
-
-        // MRU will be false unless the start surface is enabled.
-        verify(mResetHandler).resetWithTabList(mTabModelFilter, false, false);
-    }
-
-    @Test
     @DisableFeatures(ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID)
     public void openDialogButton_FlagDisabled() {
         FeatureUtilities.setTabGroupsAndroidEnabledForTesting(false);
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedNewTabPage.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedNewTabPage.java
index 9ea8762..f222919 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedNewTabPage.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedNewTabPage.java
@@ -28,6 +28,7 @@
 import org.chromium.chrome.browser.ntp.NewTabPageLayout;
 import org.chromium.chrome.browser.ntp.NewTabPageUma;
 import org.chromium.chrome.browser.ntp.SnapScrollHelper;
+import org.chromium.chrome.browser.ntp.snippets.SectionHeaderView;
 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
 import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
@@ -82,12 +83,15 @@
                 FeedProcessScopeFactory.getFeedOfflineIndicator(),
                 OfflinePageBridge.getForProfile(mTab.getProfile()),
                 FeedProcessScopeFactory.getFeedLoggingBridge());
-        mNewTabPageLayout = (NewTabPageLayout) LayoutInflater.from(mTab.getActivity())
-                                    .inflate(R.layout.new_tab_page_layout, null);
+        LayoutInflater inflater = LayoutInflater.from(mTab.getActivity());
+        mNewTabPageLayout = (NewTabPageLayout) inflater.inflate(R.layout.new_tab_page_layout, null);
+        SectionHeaderView sectionHeaderView = (SectionHeaderView) inflater.inflate(
+                R.layout.new_tab_page_snippets_expandable_header, null, false);
         mCoordinator = new FeedSurfaceCoordinator(mTab.getActivity(),
                 host.createHistoryNavigationDelegate(),
                 new SnapScrollHelper(mNewTabPageManager, mNewTabPageLayout), mNewTabPageLayout,
-                actionApi, mTab.getActivity().getNightModeStateProvider().isInNightMode(), this);
+                sectionHeaderView, actionApi,
+                mTab.getActivity().getNightModeStateProvider().isInNightMode(), this);
 
         // Record the timestamp at which the new tab page's construction started.
         NewTabPageUma.trackTimeToFirstDraw(mCoordinator.getView(), mConstructedTimeNs);
@@ -162,4 +166,4 @@
     public View getSectionHeaderViewForTesting() {
         return mCoordinator.getSectionHeaderView();
     }
-}
\ No newline at end of file
+}
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java
index 8431f5b..3c45efc 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java
@@ -269,6 +269,7 @@
      * @param historyNavigationDelegate The {@link HistoryNavigationDelegate} for the root view.
      * @param snapScrollHelper The {@link SnapScrollHelper} for the New Tab Page.
      * @param ntpHeader The extra header on top of the feeds for the New Tab Page.
+     * @param sectionHeaderView The {@link SectionHeaderView} for the feed.
      * @param actionApi The {@link ActionApi} implementation to handle actions.
      * @param showDarkBackground Whether is shown on dark background.
      * @param delegate The constructing {@link FeedSurfaceDelegate}.
@@ -276,9 +277,11 @@
     public FeedSurfaceCoordinator(ChromeActivity activity,
             @Nullable HistoryNavigationDelegate historyNavigationDelegate,
             @Nullable SnapScrollHelper snapScrollHelper, @Nullable View ntpHeader,
-            ActionApi actionApi, boolean showDarkBackground, FeedSurfaceDelegate delegate) {
+            @Nullable SectionHeaderView sectionHeaderView, ActionApi actionApi,
+            boolean showDarkBackground, FeedSurfaceDelegate delegate) {
         mActivity = activity;
         mNtpHeader = ntpHeader;
+        mSectionHeaderView = sectionHeaderView;
         mActionApi = actionApi;
         mShowDarkBackground = showDarkBackground;
         mDelegate = delegate;
@@ -378,10 +381,6 @@
         mStream = streamScope.getStream();
         mStreamLifecycleManager = mDelegate.createStreamLifecycleManager(mStream, mActivity);
 
-        LayoutInflater inflater = LayoutInflater.from(mActivity);
-        mSectionHeaderView = (SectionHeaderView) inflater.inflate(
-                R.layout.new_tab_page_snippets_expandable_header, mRootView, false);
-
         View view = mStream.getView();
         view.setBackgroundResource(R.color.modern_primary_color);
         mRootView.addView(view);
@@ -389,12 +388,13 @@
                 ViewResizer.createAndAttach(view, mUiConfig, mDefaultMargin, mWideMargin);
 
         if (mNtpHeader != null) UiUtils.removeViewFromParent(mNtpHeader);
-        UiUtils.removeViewFromParent(mSectionHeaderView);
+        if (mSectionHeaderView != null) UiUtils.removeViewFromParent(mSectionHeaderView);
         if (mSigninPromoView != null) UiUtils.removeViewFromParent(mSigninPromoView);
+
         if (mNtpHeader != null) {
             mStream.setHeaderViews(Arrays.asList(new NonDismissibleHeader(mNtpHeader),
                     new NonDismissibleHeader(mSectionHeaderView)));
-        } else {
+        } else if (mSectionHeaderView != null) {
             mStream.setHeaderViews(Arrays.asList(new NonDismissibleHeader(mSectionHeaderView)));
         }
         mStream.addScrollListener(new FeedLoggingBridge.ScrollEventReporter(
@@ -482,11 +482,14 @@
     /** Update header views in the Stream. */
     void updateHeaderViews(boolean isPromoVisible) {
         if (mNtpHeader != null) {
+            assert mSectionHeaderView != null;
             mStream.setHeaderViews(
                     isPromoVisible ? Arrays.asList(new NonDismissibleHeader(mNtpHeader),
                             new NonDismissibleHeader(mSectionHeaderView), new SignInPromoHeader())
                                    : Arrays.asList(new NonDismissibleHeader(mNtpHeader),
                                            new NonDismissibleHeader(mSectionHeaderView)));
+        } else if (mSectionHeaderView == null) {
+            if (isPromoVisible) mStream.setHeaderViews(Arrays.asList(new SignInPromoHeader()));
         } else {
             mStream.setHeaderViews(isPromoVisible
                             ? Arrays.asList(new NonDismissibleHeader(mSectionHeaderView),
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java
index 8df5990..17893fc 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java
@@ -50,6 +50,7 @@
     private @Nullable SignInPromo mSignInPromo;
 
     private boolean mFeedEnabled;
+    private boolean mHasHeader;
     private boolean mTouchEnabled = true;
     private boolean mStreamContentChanged;
     private int mThumbnailWidth;
@@ -67,6 +68,7 @@
         mSigninManager = IdentityServicesProvider.getSigninManager();
 
         mPrefChangeRegistrar = new PrefChangeRegistrar();
+        mHasHeader = mCoordinator.getSectionHeaderView() != null;
         mPrefChangeRegistrar.addObserver(Pref.NTP_ARTICLES_SECTION_ENABLED, this::updateContent);
         initialize();
         // Create the content.
@@ -95,19 +97,22 @@
     private void updateContent() {
         mFeedEnabled = FeedProcessScopeFactory.isFeedProcessEnabled();
         if ((mFeedEnabled && mCoordinator.getStream() != null)
-                || (!mFeedEnabled && mCoordinator.getScrollViewForPolicy() != null))
+                || (!mFeedEnabled && mCoordinator.getScrollViewForPolicy() != null)) {
             return;
+        }
 
         if (mFeedEnabled) {
             mCoordinator.createStream();
-            if (mSnapScrollHelper != null)
+            if (mSnapScrollHelper != null) {
                 mSnapScrollHelper.setView(mCoordinator.getStream().getView());
+            }
             initializePropertiesForStream();
         } else {
             destroyPropertiesForStream();
             mCoordinator.createScrollViewForPolicy();
-            if (mSnapScrollHelper != null)
+            if (mSnapScrollHelper != null) {
                 mSnapScrollHelper.setView(mCoordinator.getScrollViewForPolicy());
+            }
             initializePropertiesForPolicy();
         }
     }
@@ -140,13 +145,19 @@
 
         boolean suggestionsVisible =
                 PrefServiceBridge.getInstance().getBoolean(Pref.NTP_ARTICLES_LIST_VISIBLE);
-        Resources res = mCoordinator.getSectionHeaderView().getResources();
-        mSectionHeader =
-                new SectionHeader(res.getString(R.string.ntp_article_suggestions_section_header),
-                        suggestionsVisible, this::onSectionHeaderToggled);
-        mPrefChangeRegistrar.addObserver(Pref.NTP_ARTICLES_LIST_VISIBLE, this::updateSectionHeader);
-        mCoordinator.getSectionHeaderView().setHeader(mSectionHeader);
-        stream.setStreamContentVisibility(mSectionHeader.isExpanded());
+
+        if (mHasHeader) {
+            Resources res = mCoordinator.getSectionHeaderView().getResources();
+            mSectionHeader = new SectionHeader(
+                    res.getString(R.string.ntp_article_suggestions_section_header),
+                    suggestionsVisible, this::onSectionHeaderToggled);
+            mPrefChangeRegistrar.addObserver(
+                    Pref.NTP_ARTICLES_LIST_VISIBLE, this::updateSectionHeader);
+            mCoordinator.getSectionHeaderView().setHeader(mSectionHeader);
+        }
+        // Show feed if there is no header that would allow user to hide feed.
+        // This is currently only relevant for the two panes start surface.
+        stream.setStreamContentVisibility(mHasHeader ? mSectionHeader.isExpanded() : true);
 
         if (SignInPromo.shouldCreatePromo()) {
             mSignInPromo = new FeedSignInPromo(mSigninManager);
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/NtpStreamLifecycleManager.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/NtpStreamLifecycleManager.java
index 95c99f4f..7f02d80b 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/NtpStreamLifecycleManager.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/NtpStreamLifecycleManager.java
@@ -12,6 +12,8 @@
 
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.browser.ntp.NewTabPage;
+import org.chromium.chrome.browser.preferences.Pref;
+import org.chromium.chrome.browser.preferences.PrefServiceBridge;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.Tab.TabHidingType;
@@ -81,13 +83,19 @@
     /** @return Whether the {@link Stream} can be shown. */
     @Override
     protected boolean canShow() {
-        return super.canShow() && !mTab.isHidden();
+        // We don't call Stream#onShow to prevent feed services from being warmed up if the user
+        // has opted out from article suggestions during the previous session.
+        return super.canShow()
+                && PrefServiceBridge.getInstance().getBoolean(Pref.NTP_ARTICLES_LIST_VISIBLE)
+                && !mTab.isHidden();
     }
 
     /** @return Whether the {@link Stream} can be activated. */
     @Override
     protected boolean canActivate() {
-        return super.canActivate() && mTab.isUserInteractable();
+        return super.canActivate()
+                && PrefServiceBridge.getInstance().getBoolean(Pref.NTP_ARTICLES_LIST_VISIBLE)
+                && mTab.isUserInteractable();
     }
 
     /**
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/StreamLifecycleManager.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/StreamLifecycleManager.java
index 3921ddfb..2aced8e 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/StreamLifecycleManager.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/StreamLifecycleManager.java
@@ -89,11 +89,8 @@
     /** @return Whether the {@link Stream} can be shown. */
     protected boolean canShow() {
         final int state = ApplicationStatus.getStateForActivity(mActivity);
-        // We don't call Stream#onShow to prevent feed services from being warmed up if the user
-        // has opted out from article suggestions during the previous session.
         return (mStreamState == StreamState.CREATED || mStreamState == StreamState.HIDDEN)
-                && (state == ActivityState.STARTED || state == ActivityState.RESUMED)
-                && FeedProcessScopeFactory.areArticlesVisibleDuringSession();
+                && (state == ActivityState.STARTED || state == ActivityState.RESUMED);
     }
 
     /** Calls {@link Stream#onShow()}. */
@@ -107,8 +104,7 @@
     /** @return Whether the {@link Stream} can be activated. */
     protected boolean canActivate() {
         return (mStreamState == StreamState.SHOWN || mStreamState == StreamState.INACTIVE)
-                && ApplicationStatus.getStateForActivity(mActivity) == ActivityState.RESUMED
-                && FeedProcessScopeFactory.areArticlesVisibleDuringSession();
+                && ApplicationStatus.getStateForActivity(mActivity) == ActivityState.RESUMED;
     }
 
     /** Calls {@link Stream#onActive()}. */
@@ -132,8 +128,9 @@
     /** Calls {@link Stream#onHide()}. */
     protected void hide() {
         if (mStreamState == StreamState.HIDDEN || mStreamState == StreamState.CREATED
-                || mStreamState == StreamState.DESTROYED)
+                || mStreamState == StreamState.DESTROYED) {
             return;
+        }
 
         // Make sure the Stream is inactive before setting it to hidden state.
         deactivate();
@@ -169,4 +166,4 @@
     protected String restoreInstanceState() {
         return null;
     }
-}
\ No newline at end of file
+}
diff --git a/chrome/android/java/res/layout/microtransaction_toolbar.xml b/chrome/android/java/res/layout/microtransaction_toolbar.xml
index 1f22722..cc5b2fc 100644
--- a/chrome/android/java/res/layout/microtransaction_toolbar.xml
+++ b/chrome/android/java/res/layout/microtransaction_toolbar.xml
@@ -4,7 +4,6 @@
      found in the LICENSE file. -->
 <RelativeLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:background="@color/sheet_bg_color"
     android:layout_height="wrap_content"
     android:layout_width="match_parent">
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/background_sync/GooglePlayServicesChecker.java b/chrome/android/java/src/org/chromium/chrome/browser/background_sync/GooglePlayServicesChecker.java
index e0944f8fa..f7efb83 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/background_sync/GooglePlayServicesChecker.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/background_sync/GooglePlayServicesChecker.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.background_sync;
 
 import org.chromium.base.Log;
+import org.chromium.base.VisibleForTesting;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.browser.externalauth.ExternalAuthUtils;
@@ -15,7 +16,6 @@
  */
 final class GooglePlayServicesChecker {
     private static final String TAG = "PlayServicesChecker";
-
     private GooglePlayServicesChecker() {}
 
     /**
@@ -25,14 +25,16 @@
      * wait until Play Services is updated before attempting them.
      */
     @CalledByNative
-    private static boolean shouldDisableBackgroundSync() {
+    @VisibleForTesting
+    protected static boolean shouldDisableBackgroundSync() {
         boolean isAvailable = true;
         if (!ExternalAuthUtils.canUseGooglePlayServices()) {
             Log.i(TAG, "Disabling Background Sync because Play Services is not up to date.");
             isAvailable = false;
         }
+
         RecordHistogram.recordBooleanHistogram(
                 "BackgroundSync.LaunchTask.PlayServicesAvailable", isAvailable);
-        return isAvailable;
+        return !isAvailable;
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
index 6cd8497..b98b8d6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
@@ -134,10 +134,7 @@
             mPasswordLabel.setError(getContext().getString(
                     R.string.pref_edit_dialog_field_required_validation_message));
         } else {
-            PasswordEditingDelegateProvider.getInstance()
-                    .getPasswordEditingDelegate()
-                    .editSavedPasswordEntry(
-                            mUsernameText.getText().toString(), mPasswordText.getText().toString());
+            // TODO(crbug.com/377410): Save the changes if everything was ok.
             getActivity().finish();
         }
     }
@@ -147,10 +144,4 @@
         super.onSaveInstanceState(savedInstanceState);
         savedInstanceState.putBoolean(VIEW_BUTTON_PRESSED, mViewButtonPressed);
     }
-
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        PasswordEditingDelegateProvider.getInstance().getPasswordEditingDelegate().destroy();
-    }
 }
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryViewer.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryViewer.java
index 86cb1b4..e212d36 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryViewer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryViewer.java
@@ -199,9 +199,6 @@
             if (mCopyButtonPressed) copyPassword();
         }
         PasswordManagerHandlerProvider.getInstance().addObserver(this);
-        PasswordManagerHandlerProvider.getInstance()
-                .getPasswordManagerHandler()
-                .updatePasswordLists();
     }
 
     @Override
@@ -437,13 +434,13 @@
     @Override
     public void passwordListAvailable(int count) {
         if (mException) return;
-        TextView passwordTextView = mView.findViewById(R.id.password_entry_viewer_password);
+        TextView passwordsLinkTextView = mView.findViewById(R.id.passwords_link);
         SavedPasswordEntry SavedPasswordEntry = PasswordManagerHandlerProvider.getInstance()
                                                         .getPasswordManagerHandler()
                                                         .getSavedPasswordEntry(mID);
         setRowText(R.id.url_row, SavedPasswordEntry.getUrl());
         setRowText(R.id.username_row, SavedPasswordEntry.getUserName());
-        passwordTextView.setText(SavedPasswordEntry.getPassword());
+        passwordsLinkTextView.setText(SavedPasswordEntry.getPassword());
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/sync/AccountManagementFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/sync/AccountManagementFragment.java
index b312c9c..b65a74d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/sync/AccountManagementFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/sync/AccountManagementFragment.java
@@ -391,15 +391,15 @@
 
         final DialogFragment clearDataProgressDialog = new ClearDataProgressDialog();
         IdentityServicesProvider.getSigninManager().signOut(
-                SignoutReason.USER_CLICKED_SIGNOUT_SETTINGS,
-                null, new SigninManager.WipeDataHooks() {
+                SignoutReason.USER_CLICKED_SIGNOUT_SETTINGS, new SigninManager.SignOutCallback() {
                     @Override
                     public void preWipeData() {
                         clearDataProgressDialog.show(
                                 getFragmentManager(), CLEAR_DATA_PROGRESS_DIALOG_TAG);
                     }
+
                     @Override
-                    public void postWipeData() {
+                    public void signOutComplete() {
                         if (clearDataProgressDialog.isAdded()) {
                             clearDataProgressDialog.dismissAllowingStateLoss();
                         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/sync/SyncAndServicesPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/sync/SyncAndServicesPreferences.java
index 8f53420..3ae9d01 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/sync/SyncAndServicesPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/sync/SyncAndServicesPreferences.java
@@ -528,7 +528,8 @@
             // TODO(https://crbug.com/873116): Pass the correct reason for the signout.
             IdentityServicesProvider.getSigninManager().signOut(
                     SignoutReason.USER_CLICKED_SIGNOUT_SETTINGS,
-                    () -> IdentityServicesProvider.getSigninManager().signIn(account, null, null));
+                    () -> IdentityServicesProvider.getSigninManager().signIn(account, null, null),
+                    false);
             return;
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninHelper.java
index 2447505..aa0e24ff 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninHelper.java
@@ -226,7 +226,7 @@
             // signed-out.
             clearNewSignedInAccountName();
             performResignin(newName);
-        });
+        }, false);
     }
 
     private void performResignin(String newName) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java
index 5ce6493d..ad24c41 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java
@@ -99,18 +99,18 @@
     }
 
     /**
-     * Hooks for wiping data during sign out.
+     * Callbacks for the sign-out flow.
      */
-    public interface WipeDataHooks {
+    public interface SignOutCallback {
         /**
-         * Called before data is wiped.
+         * Called before the data wiping is started.
          */
-        void preWipeData();
+        default void preWipeData() {}
 
         /**
-         * Called after data is wiped.
+         * Called after the data is wiped.
          */
-        void postWipeData();
+        void signOutComplete();
     }
 
     /**
@@ -171,20 +171,16 @@
      * cleared atomically, and all final fields to be set upon initialization.
      */
     private static class SignOutState {
-        final Runnable mCallback;
-        final WipeDataHooks mWipeDataHooks;
+        final @Nullable SignOutCallback mSignOutCallback;
         final boolean mShouldWipeUserData;
 
         /**
-         * @param callback Called after sign-out finishes and all data has been cleared.
-         * @param wipeDataHooks Hooks to call before/after data wiping phase of sign-out.
+         * @param signOutCallback Hooks to call before/after data wiping phase of sign-out.
          * @param shouldWipeUserData Flag to wipe user data as requested by the user and enforced
          *         for managed users.
          */
-        SignOutState(@Nullable Runnable callback, @Nullable WipeDataHooks wipeDataHooks,
-                boolean shouldWipeUserData) {
-            this.mCallback = callback;
-            this.mWipeDataHooks = wipeDataHooks;
+        SignOutState(@Nullable SignOutCallback signOutCallback, boolean shouldWipeUserData) {
+            this.mSignOutCallback = signOutCallback;
             this.mShouldWipeUserData = shouldWipeUserData;
         }
     }
@@ -587,40 +583,30 @@
     }
 
     /**
-     * Invokes signOut with no callback or wipeDataHooks.
+     * Invokes signOut with no callback.
      */
     public void signOut(@SignoutReason int signoutSource) {
-        signOut(signoutSource, null, null, false);
+        signOut(signoutSource, null, false);
     }
 
     /**
-     * Invokes signOut() with no wipeDataHooks.
-     */
-    public void signOut(@SignoutReason int signoutSource, Runnable callback) {
-        signOut(signoutSource, callback, null, false);
-    }
-
-    /**
-     * Signs out of Chrome.
-     * <p/>
-     * This method clears the signed-in username, stops sync and sends out a
+     * Signs out of Chrome. This method clears the signed-in username, stops sync and sends out a
      * sign-out notification on the native side.
      *
      * @param signoutSource describes the event driving the signout (e.g.
      *         {@link SignoutReason.USER_CLICKED_SIGNOUT_SETTINGS}).
-     * @param callback Will be invoked after sign-out completes, if not null.
-     * @param wipeDataHooks Hooks to call before/after data wiping phase of sign-out.
+     * @param signOutCallback Callback to notify about the sign-out progress.
      * @param forceWipeUserData Whether user selected to wipe all device data.
      */
-    public void signOut(@SignoutReason int signoutSource, Runnable callback,
-            WipeDataHooks wipeDataHooks, boolean forceWipeUserData) {
+    public void signOut(@SignoutReason int signoutSource, SignOutCallback signOutCallback,
+            boolean forceWipeUserData) {
         // Only one signOut at a time!
         assert mSignOutState == null;
 
         // Grab the management domain before nativeSignOut() potentially clears it.
         String managementDomain = getManagementDomain();
-        mSignOutState = new SignOutState(
-                callback, wipeDataHooks, forceWipeUserData || managementDomain != null);
+        mSignOutState =
+                new SignOutState(signOutCallback, forceWipeUserData || managementDomain != null);
         Log.d(TAG, "Signing out, management domain: " + managementDomain);
 
         // User data will be wiped in disableSyncAndWipeData(), called from
@@ -668,7 +654,7 @@
             // native (since otherwise SigninManager.signOut would have created
             // it). As sign out from native can only happen from policy code,
             // the account is managed and the user data must be wiped.
-            mSignOutState = new SignOutState(null, null, true);
+            mSignOutState = new SignOutState(null, true);
         }
 
         Log.d(TAG, "On native signout, wipe user data: " + mSignOutState.mShouldWipeUserData);
@@ -676,28 +662,19 @@
         // Native sign-out must happen before resetting the account so data is deleted correctly.
         // http://crbug.com/589028
         ChromeSigninController.get().setSignedInAccountName(null);
-        if (mSignOutState.mWipeDataHooks != null) mSignOutState.mWipeDataHooks.preWipeData();
-        disableSyncAndWipeData(mSignOutState.mShouldWipeUserData, this::onProfileDataWiped);
+        if (mSignOutState.mSignOutCallback != null) mSignOutState.mSignOutCallback.preWipeData();
+        disableSyncAndWipeData(mSignOutState.mShouldWipeUserData, this::finishSignOut);
         mAccountTrackerService.invalidateAccountSeedStatus(true);
     }
 
-    @VisibleForTesting
-    protected void onProfileDataWiped() {
+    void finishSignOut() {
         // Should be set at start of sign-out flow.
         assert mSignOutState != null;
 
-        if (mSignOutState.mWipeDataHooks != null) mSignOutState.mWipeDataHooks.postWipeData();
-        finishSignOut();
-    }
-
-    private void finishSignOut() {
-        // Should be set at start of sign-out flow.
-        assert mSignOutState != null;
-
-        if (mSignOutState.mCallback != null) {
-            PostTask.postTask(UiThreadTaskTraits.DEFAULT, mSignOutState.mCallback);
-        }
+        SignOutCallback signOutCallback = mSignOutState.mSignOutCallback;
         mSignOutState = null;
+
+        if (signOutCallback != null) signOutCallback.signOutComplete();
         notifyCallbacksWaitingForOperation();
 
         for (SignInStateObserver observer : mSignInStateObservers) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelFilter.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelFilter.java
index fa2b5ac0..06ec0d0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelFilter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelFilter.java
@@ -26,7 +26,6 @@
             Collections.unmodifiableList(new ArrayList<Tab>());
     private TabModel mTabModel;
     protected ObserverList<TabModelObserver> mFilteredObservers = new ObserverList<>();
-    private boolean mTabRestoreCompleted;
 
     public TabModelFilter(TabModel tabModel) {
         mTabModel = tabModel;
@@ -89,7 +88,7 @@
      * @return An unmodifiable list of {@link Tab}s that are not related to any tabs
      */
     @NonNull
-    public final List<Tab> getTabsWithNoOtherRelatedTabs() {
+    final public List<Tab> getTabsWithNoOtherRelatedTabs() {
         List<Tab> tabs = new ArrayList<>();
         for (int i = 0; i < mTabModel.getCount(); i++) {
             Tab tab = mTabModel.getTabAt(i);
@@ -142,13 +141,6 @@
     protected abstract void resetFilterStateInternal();
 
     /**
-     * @return Whether the tab model is fully restored.
-     */
-    public boolean isTabModelRestored() {
-        return mTabRestoreCompleted || isIncognito();
-    }
-
-    /**
      * Concrete class requires to define what's the behavior when {@link TabModel} removed a
      * {@link Tab}.
      * @param tab {@link Tab} had removed.
@@ -272,8 +264,6 @@
 
     @Override
     public void restoreCompleted() {
-        mTabRestoreCompleted = true;
-
         if (getCount() != 0) reorder();
 
         for (TabModelObserver observer : mFilteredObservers) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
index 63c1a18..011d20e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
@@ -949,11 +949,11 @@
     }
 
     /**
-     * Tap on the peeking Bar to expand the panel, then taps on the base page to close it.
+     * Tap on the peeking Bar to expand the panel, then close it.
      */
     private void tapBarToExpandAndClosePanel() throws InterruptedException {
         tapPeekingBarToExpandAndAssert();
-        tapBasePageToClosePanel();
+        closePanel();
     }
 
     /**
@@ -1836,7 +1836,7 @@
         pressAppMenuKey();
         assertAppMenuVisibility(false);
 
-        tapBasePageToClosePanel();
+        closePanel();
 
         pressAppMenuKey();
         assertAppMenuVisibility(true);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/micro/MicrotransactionRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/micro/MicrotransactionRenderTest.java
new file mode 100644
index 0000000..e2490c4
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/micro/MicrotransactionRenderTest.java
@@ -0,0 +1,348 @@
+// 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.chrome.browser.payments.micro;
+
+import android.support.annotation.Nullable;
+import android.support.graphics.drawable.VectorDrawableCompat;
+import android.support.test.filters.SmallTest;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ProgressBar;
+import android.widget.RelativeLayout;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.R;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DummyUiActivityTestCase;
+import org.chromium.chrome.test.util.RenderTestRule;
+import org.chromium.content_public.browser.test.util.TestThreadUtils;
+import org.chromium.ui.modelutil.PropertyModel;
+import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
+
+/** Tests for the microtransaction view binder. */
+@RunWith(ChromeJUnit4ClassRunner.class)
+public class MicrotransactionRenderTest extends DummyUiActivityTestCase {
+    @Rule
+    public RenderTestRule mRenderTestRule =
+            new RenderTestRule("components/test/data/payments/render_tests");
+
+    private PropertyModel mModel;
+    private MicrotransactionView mView;
+    private RelativeLayout mLayout;
+    private PropertyModelChangeProcessor mProcessor;
+
+    @Override
+    public void setUpTest() throws Exception {
+        super.setUpTest();
+        // Initial button state:
+        mModel =
+                new PropertyModel.Builder(MicrotransactionProperties.ALL_KEYS)
+                        .with(MicrotransactionProperties.ACCOUNT_BALANCE, "$18.00")
+                        .with(MicrotransactionProperties.AMOUNT, "$1.00")
+                        .with(MicrotransactionProperties.CURRENCY, "USD")
+                        .with(MicrotransactionProperties.IS_SHOWING_LINE_ITEMS, true)
+                        .with(MicrotransactionProperties.IS_SHOWING_PAY_BUTTON, true)
+                        .with(MicrotransactionProperties.IS_SHOWING_PROCESSING_SPINNER, false)
+                        .with(MicrotransactionProperties.PAYMENT_APP_ICON,
+                                VectorDrawableCompat.create(getActivity().getResources(),
+                                        R.drawable.ic_done_googblue_36dp, getActivity().getTheme()))
+                        .with(MicrotransactionProperties.PAYMENT_APP_NAME, "App Name")
+                        .with(MicrotransactionProperties.STATUS_TEXT_RESOURCE,
+                                R.string.payment_request_payment_method_section_name)
+                        .build();
+
+        mView = new MicrotransactionView(getActivity());
+        mProcessor = PropertyModelChangeProcessor.create(
+                mModel, mView, MicrotransactionViewBinder::bind);
+
+        mLayout = new RelativeLayout(getActivity());
+        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+        mLayout.addView(mView.getContentView(), params);
+        mLayout.addView(mView.getToolbarView(), params);
+
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            getActivity().setContentView(mLayout,
+                    new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                            ViewGroup.LayoutParams.WRAP_CONTENT));
+        });
+    }
+
+    @Override
+    public void tearDownTest() throws Exception {
+        mProcessor.destroy();
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Microtransaction", "RenderTest"})
+    public void testButtonInitial() throws Throwable {
+        mRenderTestRule.render(mLayout, "button_initial");
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Microtransaction", "RenderTest"})
+    public void testButtonInitialExpanded() throws Throwable {
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> mModel.set(MicrotransactionProperties.PAYMENT_APP_NAME_ALPHA, 1f));
+        mRenderTestRule.render(mLayout, "button_initial_expanded");
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Microtransaction", "RenderTest"})
+    public void testButtonProcessing() throws Throwable {
+        TestThreadUtils.runOnUiThreadBlocking(() -> showButtonProcessing());
+        mRenderTestRule.render(mLayout, "button_processing");
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Microtransaction", "RenderTest"})
+    public void testButtonProcessingExpanded() throws Throwable {
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mModel.set(MicrotransactionProperties.PAYMENT_APP_NAME_ALPHA, 1f);
+            showButtonProcessing();
+        });
+        mRenderTestRule.render(mLayout, "button_processing_expanded");
+    }
+
+    private void showButtonProcessing() {
+        mModel.set(MicrotransactionProperties.IS_SHOWING_LINE_ITEMS, false);
+        mModel.set(MicrotransactionProperties.IS_SHOWING_PAY_BUTTON, false);
+        mModel.set(MicrotransactionProperties.IS_SHOWING_PROCESSING_SPINNER, true);
+        mModel.set(MicrotransactionProperties.STATUS_TEXT, null);
+        mModel.set(MicrotransactionProperties.STATUS_TEXT_RESOURCE,
+                R.string.payments_processing_message);
+
+        stopSpinner(mView.mToolbarProcessingSpinner);
+        stopSpinner(mView.mContentProcessingSpinner);
+    }
+
+    private void stopSpinner(View view) {
+        ProgressBar spinner = (ProgressBar) view;
+        spinner.setIndeterminate(false);
+        spinner.setMax(2);
+        spinner.setProgress(1);
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Microtransaction", "RenderTest"})
+    public void testButtonErrorResource() throws Throwable {
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            showEmphasizedStatus(R.string.payment_fingerprint_not_recognized, null,
+                    R.drawable.ic_error_googred_36dp, R.color.microtransaction_error_tint);
+            mModel.set(MicrotransactionProperties.IS_SHOWING_LINE_ITEMS, false);
+        });
+        mRenderTestRule.render(mLayout, "button_error_resource");
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Microtransaction", "RenderTest"})
+    public void testButtonErrorResourceExpanded() throws Throwable {
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mModel.set(MicrotransactionProperties.PAYMENT_APP_NAME_ALPHA, 1f);
+            showEmphasizedStatus(R.string.payment_fingerprint_not_recognized, null,
+                    R.drawable.ic_error_googred_36dp, R.color.microtransaction_error_tint);
+            mModel.set(MicrotransactionProperties.IS_SHOWING_LINE_ITEMS, false);
+        });
+        mRenderTestRule.render(mLayout, "button_error_resource_expanded");
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Microtransaction", "RenderTest"})
+    public void testButtonErrorString() throws Throwable {
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            showEmphasizedStatus(null, "Finger moved too fast. Try again.",
+                    R.drawable.ic_error_googred_36dp, R.color.microtransaction_error_tint);
+            mModel.set(MicrotransactionProperties.IS_SHOWING_LINE_ITEMS, false);
+        });
+        mRenderTestRule.render(mLayout, "button_error_string");
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Microtransaction", "RenderTest"})
+    public void testButtonErrorStringExpanded() throws Throwable {
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mModel.set(MicrotransactionProperties.PAYMENT_APP_NAME_ALPHA, 1f);
+            showEmphasizedStatus(null, "Finger moved too fast. Try again.",
+                    R.drawable.ic_error_googred_36dp, R.color.microtransaction_error_tint);
+            mModel.set(MicrotransactionProperties.IS_SHOWING_LINE_ITEMS, false);
+        });
+        mRenderTestRule.render(mLayout, "button_error_string_expanded");
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Microtransaction", "RenderTest"})
+    public void testButtonSuccess() throws Throwable {
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            showEmphasizedStatus(R.string.payment_complete_message, null,
+                    R.drawable.ic_done_googblue_36dp, R.color.microtransaction_emphasis_tint);
+            mModel.set(MicrotransactionProperties.IS_SHOWING_LINE_ITEMS, false);
+        });
+        mRenderTestRule.render(mLayout, "button_success");
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Microtransaction", "RenderTest"})
+    public void testButtonSuccessExpanded() throws Throwable {
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mModel.set(MicrotransactionProperties.PAYMENT_APP_NAME_ALPHA, 1f);
+            showEmphasizedStatus(R.string.payment_complete_message, null,
+                    R.drawable.ic_done_googblue_36dp, R.color.microtransaction_emphasis_tint);
+            mModel.set(MicrotransactionProperties.IS_SHOWING_LINE_ITEMS, false);
+        });
+        mRenderTestRule.render(mLayout, "button_success_expanded");
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Microtransaction", "RenderTest"})
+    public void testFingerprintInitial() throws Throwable {
+        TestThreadUtils.runOnUiThreadBlocking(() -> showFingerprintInitial());
+        mRenderTestRule.render(mLayout, "fingerprint_initial");
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Microtransaction", "RenderTest"})
+    public void testFingerprintInitialExpanded() throws Throwable {
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mModel.set(MicrotransactionProperties.PAYMENT_APP_NAME_ALPHA, 1f);
+            showFingerprintInitial();
+        });
+        mRenderTestRule.render(mLayout, "fingerprint_initial_expanded");
+    }
+
+    private void showFingerprintInitial() {
+        mModel.set(MicrotransactionProperties.IS_SHOWING_PAY_BUTTON, false);
+        mModel.set(MicrotransactionProperties.STATUS_ICON, R.drawable.ic_fingerprint_grey500_36dp);
+        mModel.set(
+                MicrotransactionProperties.STATUS_ICON_TINT, R.color.microtransaction_default_tint);
+        mModel.set(MicrotransactionProperties.STATUS_TEXT_RESOURCE,
+                R.string.payment_touch_sensor_to_pay);
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Microtransaction", "RenderTest"})
+    public void testFingerprintProcessing() throws Throwable {
+        TestThreadUtils.runOnUiThreadBlocking(() -> showFingerprintProcessing());
+        mRenderTestRule.render(mLayout, "fingerprint_processing");
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Microtransaction", "RenderTest"})
+    public void testFingerprintProcessingExpanded() throws Throwable {
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mModel.set(MicrotransactionProperties.PAYMENT_APP_NAME_ALPHA, 1f);
+            showFingerprintProcessing();
+        });
+        mRenderTestRule.render(mLayout, "fingerprint_processing_expanded");
+    }
+
+    private void showFingerprintProcessing() {
+        mModel.set(MicrotransactionProperties.IS_SHOWING_PAY_BUTTON, false);
+        mModel.set(MicrotransactionProperties.STATUS_TEXT, null);
+        mModel.set(MicrotransactionProperties.STATUS_TEXT_RESOURCE,
+                R.string.payments_processing_message);
+        mModel.set(MicrotransactionProperties.STATUS_ICON, R.drawable.ic_fingerprint_grey500_36dp);
+        mModel.set(MicrotransactionProperties.STATUS_ICON_TINT,
+                R.color.microtransaction_emphasis_tint);
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Microtransaction", "RenderTest"})
+    public void testFingerprintErrorResource() throws Throwable {
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            showEmphasizedStatus(R.string.payment_fingerprint_not_recognized, null,
+                    R.drawable.ic_error_googred_36dp, R.color.microtransaction_error_tint);
+        });
+        mRenderTestRule.render(mLayout, "fingerprint_error_resource");
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Microtransaction", "RenderTest"})
+    public void testFingerprintErrorResourceExpanded() throws Throwable {
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mModel.set(MicrotransactionProperties.PAYMENT_APP_NAME_ALPHA, 1f);
+            showEmphasizedStatus(R.string.payment_fingerprint_not_recognized, null,
+                    R.drawable.ic_error_googred_36dp, R.color.microtransaction_error_tint);
+        });
+        mRenderTestRule.render(mLayout, "fingerprint_error_resource_expanded");
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Microtransaction", "RenderTest"})
+    public void testFingerprintErrorString() throws Throwable {
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            showEmphasizedStatus(null, "Finger moved too fast. Try again.",
+                    R.drawable.ic_error_googred_36dp, R.color.microtransaction_error_tint);
+        });
+        mRenderTestRule.render(mLayout, "fingerprint_error_string");
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Microtransaction", "RenderTest"})
+    public void testFingerprintErrorStringExpanded() throws Throwable {
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mModel.set(MicrotransactionProperties.PAYMENT_APP_NAME_ALPHA, 1f);
+            showEmphasizedStatus(null, "Finger moved too fast. Try again.",
+                    R.drawable.ic_error_googred_36dp, R.color.microtransaction_error_tint);
+        });
+        mRenderTestRule.render(mLayout, "fingerprint_error_string_expanded");
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Microtransaction", "RenderTest"})
+    public void testFingerprintSuccess() throws Throwable {
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            showEmphasizedStatus(R.string.payment_complete_message, null,
+                    R.drawable.ic_done_googblue_36dp, R.color.microtransaction_emphasis_tint);
+        });
+        mRenderTestRule.render(mLayout, "fingerprint_success");
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Microtransaction", "RenderTest"})
+    public void testFingerprintSuccessExpanded() throws Throwable {
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mModel.set(MicrotransactionProperties.PAYMENT_APP_NAME_ALPHA, 1f);
+            showEmphasizedStatus(R.string.payment_complete_message, null,
+                    R.drawable.ic_done_googblue_36dp, R.color.microtransaction_emphasis_tint);
+        });
+        mRenderTestRule.render(mLayout, "fingerprint_success_expanded");
+    }
+
+    private void showEmphasizedStatus(@Nullable Integer messageResourceId,
+            @Nullable CharSequence message, @Nullable Integer iconResourceId,
+            @Nullable Integer iconTint) {
+        mModel.set(MicrotransactionProperties.IS_SHOWING_PAY_BUTTON, false);
+        mModel.set(MicrotransactionProperties.STATUS_TEXT, message);
+        mModel.set(MicrotransactionProperties.STATUS_TEXT_RESOURCE, messageResourceId);
+        mModel.set(MicrotransactionProperties.IS_STATUS_EMPHASIZED, true);
+        mModel.set(MicrotransactionProperties.STATUS_ICON, iconResourceId);
+        mModel.set(MicrotransactionProperties.STATUS_ICON_TINT, iconTint);
+        mModel.set(MicrotransactionProperties.IS_SHOWING_PROCESSING_SPINNER, false);
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferencesTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferencesTest.java
index d14af979..9e548ed 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferencesTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferencesTest.java
@@ -37,8 +37,6 @@
 import static org.hamcrest.Matchers.not;
 import static org.hamcrest.Matchers.nullValue;
 import static org.hamcrest.Matchers.sameInstance;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
 
 import static org.chromium.chrome.test.util.ViewUtils.VIEW_GONE;
 import static org.chromium.chrome.test.util.ViewUtils.VIEW_INVISIBLE;
@@ -76,19 +74,17 @@
 import org.hamcrest.Matcher;
 import org.junit.After;
 import org.junit.Assert;
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TestRule;
 import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
 
 import org.chromium.base.Callback;
 import org.chromium.base.CollectionUtil;
 import org.chromium.base.IntStringCallback;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.ScalableTimeout;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.history.HistoryActivity;
@@ -105,7 +101,6 @@
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.components.signin.ChromeSigninController;
 import org.chromium.components.sync.ModelType;
-import org.chromium.content_public.browser.test.util.CriteriaHelper;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 
 import java.io.File;
@@ -124,9 +119,6 @@
 @RunWith(BaseJUnit4ClassRunner.class)
 public class SavePasswordsPreferencesTest {
     private static final long UI_UPDATING_TIMEOUT_MS = 3000;
-    @Mock
-    private PasswordEditingDelegate mMockPasswordEditingDelegate;
-
     @Rule
     public final ChromeBrowserTestRule mBrowserTestRule = new ChromeBrowserTestRule();
 
@@ -233,15 +225,6 @@
         @Override
         public void showPasswordEntryEditingView(Context context, int index) {
             mLastEntryIndex = index;
-            Bundle fragmentArgs = new Bundle();
-            fragmentArgs.putString(
-                    PasswordEntryEditor.CREDENTIAL_URL, getSavedPasswordEntry(index).getUrl());
-            fragmentArgs.putString(PasswordEntryEditor.CREDENTIAL_NAME,
-                    getSavedPasswordEntry(index).getUserName());
-            fragmentArgs.putString(PasswordEntryEditor.CREDENTIAL_PASSWORD,
-                    getSavedPasswordEntry(index).getPassword());
-            PreferencesLauncher.launchSettingsPage(
-                    context, PasswordEntryEditor.class, fragmentArgs);
         }
     }
 
@@ -273,10 +256,6 @@
      */
     private final ManualCallbackDelayer mManualDelayer = new ManualCallbackDelayer();
 
-    public SavePasswordsPreferencesTest() {
-        MockitoAnnotations.initMocks(this);
-    }
-
     private void overrideProfileSyncService(
             final boolean usingPassphrase, final boolean syncingPasswords) {
         TestThreadUtils.runOnUiThreadBlocking(() -> {
@@ -744,8 +723,6 @@
     @Features.EnableFeatures(ChromeFeatureList.PASSWORD_EDITING_ANDROID)
     public void testSelectedStoredPasswordIndexIsSameAsInShowPasswordEntryEditingView()
             throws Exception {
-        PasswordEditingDelegateProvider.getInstance().setPasswordEditingDelegate(
-                mMockPasswordEditingDelegate);
         setPasswordSourceWithMultipleEntries( // Initialize preferences
                 new SavedPasswordEntry[] {new SavedPasswordEntry("https://example.com",
                                                   "example user", "example password"),
@@ -769,8 +746,6 @@
     @Feature({"Preferences"})
     @Features.EnableFeatures(ChromeFeatureList.PASSWORD_EDITING_ANDROID)
     public void testPasswordDataDisplayedInEditingActivity() throws Exception {
-        PasswordEditingDelegateProvider.getInstance().setPasswordEditingDelegate(
-                mMockPasswordEditingDelegate);
         Bundle fragmentArgs = new Bundle();
         fragmentArgs.putString(PasswordEntryEditor.CREDENTIAL_URL, "https://example.com");
         fragmentArgs.putString(PasswordEntryEditor.CREDENTIAL_NAME, "test user");
@@ -784,16 +759,17 @@
     }
 
     /**
-     * Check that the password editing method from the PasswordEditingDelegate was called when the
-     * save button in the password editing activity was clicked.
+     * Check that the changes of password data in the password editing activity are preserved and
+     * shown in the password viewing activity and in the list of passwords after the save button
+     * was clicked.
      */
+    // TODO(izuzic): Remove @Ignore when saving of changes is enabled again.
+    @Ignore("The test is ignored because saving the changes of credentials is currently disabled.")
     @Test
     @SmallTest
     @Feature({"Preferences"})
     @Features.EnableFeatures(ChromeFeatureList.PASSWORD_EDITING_ANDROID)
-    public void testPasswordEditingMethodWasCalled() throws Exception {
-        PasswordEditingDelegateProvider.getInstance().setPasswordEditingDelegate(
-                mMockPasswordEditingDelegate);
+    public void testChangeOfStoredPasswordDataIsPreserved() throws Exception {
         setPasswordSource(new SavedPasswordEntry("https://example.com", "test user", "password"));
 
         PreferencesTest.startPreferences(InstrumentationRegistry.getInstrumentation(),
@@ -807,38 +783,6 @@
 
         Espresso.onView(withSaveMenuIdOrText()).perform(click());
 
-        verify(mMockPasswordEditingDelegate).editSavedPasswordEntry("test user new", "password");
-
-        // Verify that the delegate was destroyed when the password editing activity finished.
-        waitForEvent().destroy();
-    }
-
-    /**
-     * Check that the changes of password data are shown in the password viewing activity and in the
-     * list of passwords after the save button was clicked.
-     */
-    @Test
-    @SmallTest
-    @Feature({"Preferences"})
-    @Features.EnableFeatures(ChromeFeatureList.PASSWORD_EDITING_ANDROID)
-    public void testChangeOfStoredPasswordDataIsPropagated() throws Exception {
-        PasswordEditingDelegateProvider.getInstance().setPasswordEditingDelegate(
-                mMockPasswordEditingDelegate);
-        setPasswordSource(new SavedPasswordEntry("https://example.com", "test user", "password"));
-
-        PreferencesTest.startPreferences(InstrumentationRegistry.getInstrumentation(),
-                SavePasswordsPreferences.class.getName());
-
-        Espresso.onView(withText(containsString("test user"))).perform(click());
-
-        Espresso.onView(withEditMenuIdOrText()).perform(click());
-
-        // Performing a change of saved credentials.
-        mHandler.mSavedPasswords.set(
-                0, new SavedPasswordEntry("https://example.com", "test user new", "password"));
-
-        Espresso.onView(withSaveMenuIdOrText()).perform(click());
-
         // Check if the password viewing activity has the updated data.
         Espresso.onView(withText("test user new")).check(matches(isDisplayed()));
 
@@ -856,8 +800,6 @@
     @Feature({"Preferences"})
     @Features.EnableFeatures(ChromeFeatureList.PASSWORD_EDITING_ANDROID)
     public void testStoredPasswordCanBeUnmaskedAndMaskedAgain() throws Exception {
-        PasswordEditingDelegateProvider.getInstance().setPasswordEditingDelegate(
-                mMockPasswordEditingDelegate);
         Bundle fragmentArgs = new Bundle();
         fragmentArgs.putString(SavePasswordsPreferences.PASSWORD_LIST_NAME, "test user");
         fragmentArgs.putString(SavePasswordsPreferences.PASSWORD_LIST_URL, "https://example.com");
@@ -2195,9 +2137,4 @@
                                 allOf(withId(R.id.search_src_text), withText("Zeu"))));
         Espresso.onView(withId(R.id.search_src_text)).check(matches(withText("Zeu")));
     }
-
-    PasswordEditingDelegate waitForEvent() {
-        return verify(mMockPasswordEditingDelegate,
-                timeout(ScalableTimeout.scaleTimeout(CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL)));
-    }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTestRule.java
index f66174ab..2ac73ae 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTestRule.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTestRule.java
@@ -186,12 +186,7 @@
         final Semaphore s = new Semaphore(0);
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             IdentityServicesProvider.getSigninManager().signOut(
-                    SignoutReason.SIGNOUT_TEST, new Runnable() {
-                        @Override
-                        public void run() {
-                            s.release();
-                        }
-                    });
+                    SignoutReason.SIGNOUT_TEST, s::release, false);
         });
         Assert.assertTrue(s.tryAcquire(SyncTestUtil.TIMEOUT_MS, TimeUnit.MILLISECONDS));
         Assert.assertNull(SigninTestUtil.getCurrentAccount());
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 99436c2..1b2d259 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
@@ -4,11 +4,11 @@
 
 package org.chromium.chrome.browser.tasks;
 
-import static org.junit.Assert.assertEquals;
-
 import static org.chromium.chrome.browser.tasks.ReturnToChromeExperimentsUtil.TAB_SWITCHER_ON_RETURN_MS;
 
 import android.app.Activity;
+import android.content.Context;
+import android.os.SystemClock;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 
@@ -22,20 +22,13 @@
 import org.chromium.base.ApplicationStatus;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
-import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
-import org.chromium.chrome.test.util.MenuUtils;
-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.net.test.EmbeddedTestServer;
-import org.chromium.ui.test.util.UiRestriction;
 
 import java.util.concurrent.TimeoutException;
 
@@ -44,7 +37,6 @@
  * has passed.
  */
 @RunWith(ChromeJUnit4ClassRunner.class)
-@Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
 public class ReturnToChromeTest {
     @Rule
     public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
@@ -53,12 +45,10 @@
 
     @Before
     public void setUp() throws Exception {
-        FeatureUtilities.setGridTabSwitcherEnabledForTesting(true);
+        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
 
         mActivityTestRule.startMainActivityFromLauncher();
         mActivity = mActivityTestRule.getActivity();
-
-        setupTabs();
     }
 
     /**
@@ -74,7 +64,7 @@
             "force-fieldtrial-params=FakeStudyName.Enabled:" + TAB_SWITCHER_ON_RETURN_MS
                     + "/100000"})
     public void
-    testTabSwitcherModeNotTriggeredWithinThreshold() throws Exception {
+    testObserverModeNotTriggeredWithoutDelay() throws Exception {
         finishActivityCompletely();
 
         mActivityTestRule.startMainActivityFromLauncher();
@@ -83,51 +73,25 @@
         Assert.assertFalse(mActivity.getLayoutManager().overviewVisible());
     }
 
-    /**
-     * Test that overview mode is triggered if the delay is shorter than the interval between
-     * stop and start.
-     */
     @Test
     @SmallTest
     @Feature({"ReturnToChrome"})
+    @DisabledTest(message = "crbug.com/955436")
     @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
             "enable-features=" + ChromeFeatureList.TAB_SWITCHER_ON_RETURN + "<FakeStudyName",
             "force-fieldtrials=FakeStudyName/Enabled",
-            "force-fieldtrial-params=FakeStudyName.Enabled:" + TAB_SWITCHER_ON_RETURN_MS + "/0"})
+            "force-fieldtrial-params=FakeStudyName.Enabled:" + TAB_SWITCHER_ON_RETURN_MS + "/1"})
     public void
-    testTabSwitcherModeTriggeredBeyondThreshold() throws Exception {
+    testObserverModeTriggeredWithDelay() throws Exception {
         finishActivityCompletely();
 
+        // Sleep past the timeout.
+        SystemClock.sleep(30);
+
         mActivityTestRule.startMainActivityFromLauncher();
         mActivity = mActivityTestRule.getActivity();
 
         Assert.assertTrue(mActivity.getLayoutManager().overviewVisible());
-
-        CriteriaHelper.pollUiThread(Criteria.equals(true,
-                mActivityTestRule.getActivity()
-                        .getTabModelSelector()
-                        .getTabModelFilterProvider()
-                        .getCurrentTabModelFilter()::isTabModelRestored));
-
-        assertEquals(2, mActivityTestRule.getActivity().getTabModelSelector().getTotalTabCount());
-    }
-
-    private void setupTabs() throws InterruptedException {
-        TestThreadUtils.runOnUiThreadBlocking(
-                () -> mActivityTestRule.getActivity().getTabModelSelector().closeAllTabs());
-        EmbeddedTestServer testServer =
-                EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext());
-        final String url = testServer.getURL("/chrome/test/data/android/navigate/simple.html");
-
-        // Add 2 tabs.
-        MenuUtils.invokeCustomMenuActionSync(InstrumentationRegistry.getInstrumentation(),
-                mActivity, org.chromium.chrome.R.id.new_tab_menu_id);
-        mActivityTestRule.loadUrl(url);
-        MenuUtils.invokeCustomMenuActionSync(InstrumentationRegistry.getInstrumentation(),
-                mActivity, org.chromium.chrome.R.id.new_tab_menu_id);
-        mActivityTestRule.loadUrl(url);
-
-        assertEquals(2, mActivity.getTabModelSelector().getTotalTabCount());
     }
 
     private void finishActivityCompletely() throws InterruptedException, TimeoutException {
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/background_sync/BackgroundSyncGooglePlayServicesCheckerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/background_sync/BackgroundSyncGooglePlayServicesCheckerTest.java
new file mode 100644
index 0000000..80572be
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/background_sync/BackgroundSyncGooglePlayServicesCheckerTest.java
@@ -0,0 +1,46 @@
+// 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.chrome.browser.background_sync;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.google.android.gms.common.ConnectionResult;
+import com.google.android.gms.common.GoogleApiAvailability;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.gms.Shadows;
+import org.robolectric.shadows.gms.common.ShadowGoogleApiAvailability;
+
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.test.support.DisableHistogramsRule;
+
+/** Unit tests for GooglePlayServicesChecker. */
+@RunWith(BaseRobolectricTestRunner.class)
+@Config(manifest = Config.NONE, shadows = {ShadowGoogleApiAvailability.class})
+public class BackgroundSyncGooglePlayServicesCheckerTest {
+    @Rule
+    public DisableHistogramsRule mDisableHistogramsRule = new DisableHistogramsRule();
+
+    @Test
+    @Feature("BackgroundSync")
+    public void testDisableLogicWhenGooglePlayServicesReturnsSuccess() {
+        Shadows.shadowOf(GoogleApiAvailability.getInstance())
+                .setIsGooglePlayServicesAvailable(ConnectionResult.SUCCESS);
+        assertFalse(GooglePlayServicesChecker.shouldDisableBackgroundSync());
+    }
+
+    @Test
+    @Feature("BackgroundSync")
+    public void testDisableLogicWhenGooglePlayServicesReturnsError() {
+        Shadows.shadowOf(GoogleApiAvailability.getInstance())
+                .setIsGooglePlayServicesAvailable(ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED);
+        assertTrue(GooglePlayServicesChecker.shouldDisableBackgroundSync());
+    }
+}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/feed/NtpStreamLifecycleManagerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/feed/NtpStreamLifecycleManagerTest.java
index f79c735..937bd8f 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/feed/NtpStreamLifecycleManagerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/feed/NtpStreamLifecycleManagerTest.java
@@ -120,12 +120,6 @@
         // Verify that onHide is called after tab is hidden.
         mNtpStreamLifecycleManager.getTabObserverForTesting().onHidden(mTab, CHANGED_TABS);
         verify(mStream, times(1)).onHide();
-
-        // Verify that onShow is called when articles are set hidden by the user within the same
-        // session.
-        when(mPrefServiceBridge.getBoolean(Pref.NTP_ARTICLES_LIST_VISIBLE)).thenReturn(false);
-        mNtpStreamLifecycleManager.getTabObserverForTesting().onShown(mTab, FROM_NEW);
-        verify(mStream, times(2)).onShow();
     }
 
     @Test
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/signin/SigninManagerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/signin/SigninManagerTest.java
index c0499d14..3e04124 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/signin/SigninManagerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/signin/SigninManagerTest.java
@@ -146,7 +146,7 @@
         doReturn(null).when(mNativeMock).getManagementDomain(anyLong());
 
         // Trigger the sign out flow
-        mSigninManager.signOut(SignoutReason.SIGNOUT_TEST, null, null, true);
+        mSigninManager.signOut(SignoutReason.SIGNOUT_TEST, null, true);
 
         // PrimaryAccountCleared should be called *before* clearing any account data.
         // http://crbug.com/589028
@@ -200,7 +200,7 @@
         mSigninManager.runAfterOperationInProgress(callCount::incrementAndGet);
         assertEquals(0, callCount.get());
 
-        mSigninManager.onProfileDataWiped();
+        mSigninManager.finishSignOut();
         assertFalse(mSigninManager.isOperationInProgress());
         assertEquals(1, callCount.get());
     }
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index eaee8343..7b0aac0e 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -1137,10 +1137,10 @@
           Please wait while Chromium installs the latest system updates.
         </message>
         <message name="IDS_CHECKING_FOR_UPDATE_MSG" desc="Chrome OS OOBE: message shown during checking for update stage.">
-          Chromium updates automatically so you always have the freshest version.
+          Future versions of Chromium will install automatically.
         </message>
         <message name="IDS_UPDATE_MSG" desc="Chrome OS OOBE: message shown during update stage.">
-          Chromium updates automatically so you always have the freshest version. When this download completes, Chromium will restart and you'll be on your way.
+          Future versions of Chromium will install automatically. When this download completes, Chromium will restart and you'll be on your way.
         </message>
         <message name="IDS_EULA_SCREEN_ACCESSIBLE_TITLE" desc="Title to be spoken on opening the OOBE EULA screen">
           Chromium OS terms
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd
index e6eb76f..e86e35e 100644
--- a/chrome/app/google_chrome_strings.grd
+++ b/chrome/app/google_chrome_strings.grd
@@ -1156,10 +1156,10 @@
           Please wait while Chrome installs the latest system updates.
         </message>
         <message name="IDS_CHECKING_FOR_UPDATE_MSG" desc="Chrome OS OOBE: message shown during checking for update stage.">
-          Chrome updates automatically so you always have the freshest version.
+          Future versions of Chrome will install automatically.
         </message>
         <message name="IDS_UPDATE_MSG" desc="Chrome OS OOBE: message shown during update stage.">
-          Chrome updates automatically so you always have the freshest version. When this download completes, Chrome will restart and you'll be on your way.
+          Future versions of Chrome will install automatically. When this download completes, Chrome will restart and you'll be on your way.
         </message>
         <message name="IDS_EULA_SCREEN_ACCESSIBLE_TITLE" desc="Title to be spoken on opening the OOBE EULA screen">
           Chrome OS terms
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index a4bbd33..1bfb5916 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2961,6 +2961,8 @@
       "apps/app_service/app_icon_source.h",
       "apps/app_service/app_launch_params.cc",
       "apps/app_service/app_launch_params.h",
+      "apps/app_service/app_service_metrics.cc",
+      "apps/app_service/app_service_metrics.h",
       "apps/app_service/app_service_proxy.cc",
       "apps/app_service/app_service_proxy.h",
       "apps/app_service/app_service_proxy_factory.cc",
diff --git a/chrome/browser/apps/app_service/app_service_metrics.cc b/chrome/browser/apps/app_service/app_service_metrics.cc
new file mode 100644
index 0000000..53d117d6
--- /dev/null
+++ b/chrome/browser/apps/app_service/app_service_metrics.cc
@@ -0,0 +1,70 @@
+// 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.
+
+#include "chrome/browser/apps/app_service/app_service_metrics.h"
+
+#include "base/metrics/histogram_macros.h"
+#include "chrome/browser/chromeos/extensions/default_web_app_ids.h"
+#include "chrome/browser/chromeos/file_manager/app_id.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/services/app_service/public/mojom/app_service.mojom.h"
+#include "extensions/common/constants.h"
+
+namespace apps {
+
+void RecordDefaultAppLaunch(DefaultAppName default_app_name,
+                            apps::mojom::LaunchSource launch_source) {
+  switch (launch_source) {
+    case apps::mojom::LaunchSource::kUnknown:
+    case apps::mojom::LaunchSource::kFromParentalControls:
+      return;
+    case apps::mojom::LaunchSource::kFromAppListGrid:
+      UMA_HISTOGRAM_ENUMERATION("Apps.DefaultAppLaunch.FromAppListGrid",
+                                default_app_name);
+      break;
+    case apps::mojom::LaunchSource::kFromAppListGridContextMenu:
+      UMA_HISTOGRAM_ENUMERATION(
+          "Apps.DefaultAppLaunch.FromAppListGridContextMenu", default_app_name);
+      break;
+    case apps::mojom::LaunchSource::kFromAppListQuery:
+      UMA_HISTOGRAM_ENUMERATION("Apps.DefaultAppLaunch.FromAppListQuery",
+                                default_app_name);
+      break;
+    case apps::mojom::LaunchSource::kFromAppListQueryContextMenu:
+      UMA_HISTOGRAM_ENUMERATION(
+          "Apps.DefaultAppLaunch.FromAppListQueryContextMenu",
+          default_app_name);
+      break;
+    case apps::mojom::LaunchSource::kFromAppListRecommendation:
+      UMA_HISTOGRAM_ENUMERATION(
+          "Apps.DefaultAppLaunch.FromAppListRecommendation", default_app_name);
+      break;
+    case apps::mojom::LaunchSource::kFromShelf:
+      UMA_HISTOGRAM_ENUMERATION("Apps.DefaultAppLaunch.FromShelf",
+                                default_app_name);
+      break;
+  }
+}
+
+void RecordAppLaunch(const std::string& app_id,
+                     apps::mojom::LaunchSource launch_source) {
+  if (app_id == extension_misc::kCalculatorAppId)
+    RecordDefaultAppLaunch(DefaultAppName::kCalculator, launch_source);
+  else if (app_id == extension_misc::kTextEditorAppId)
+    RecordDefaultAppLaunch(DefaultAppName::kText, launch_source);
+  else if (app_id == extension_misc::kGeniusAppId)
+    RecordDefaultAppLaunch(DefaultAppName::kGetHelp, launch_source);
+  else if (app_id == file_manager::kGalleryAppId)
+    RecordDefaultAppLaunch(DefaultAppName::kGallery, launch_source);
+  else if (app_id == file_manager::kVideoPlayerAppId)
+    RecordDefaultAppLaunch(DefaultAppName::kVideoPlayer, launch_source);
+  else if (app_id == file_manager::kAudioPlayerAppId)
+    RecordDefaultAppLaunch(DefaultAppName::kAudioPlayer, launch_source);
+  else if (app_id == chromeos::default_web_apps::kCanvasAppId)
+    RecordDefaultAppLaunch(DefaultAppName::kChromeCanvas, launch_source);
+  else if (app_id == extension_misc::kCameraAppId)
+    RecordDefaultAppLaunch(DefaultAppName::kCamera, launch_source);
+}
+
+}  // namespace apps
diff --git a/chrome/browser/apps/app_service/app_service_metrics.h b/chrome/browser/apps/app_service/app_service_metrics.h
new file mode 100644
index 0000000..40286a4
--- /dev/null
+++ b/chrome/browser/apps/app_service/app_service_metrics.h
@@ -0,0 +1,39 @@
+// 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.
+
+#ifndef CHROME_BROWSER_APPS_APP_SERVICE_APP_SERVICE_METRICS_H_
+#define CHROME_BROWSER_APPS_APP_SERVICE_APP_SERVICE_METRICS_H_
+
+#include <map>
+#include <string>
+
+#include "chrome/services/app_service/public/mojom/types.mojom.h"
+
+namespace apps {
+
+// The app's histogram name. This is used for logging so do not change the
+// order of this enum.
+enum class DefaultAppName {
+  kCalculator = 0,
+  kText = 1,
+  kGetHelp = 2,
+  kGallery = 3,
+  kVideoPlayer = 4,
+  kAudioPlayer = 5,
+  kChromeCanvas = 6,
+  kCamera = 7,
+  // Add any new values above this one, and update kMaxValue to the highest
+  // enumerator value.
+  kMaxValue = kCamera,
+};
+
+void RecordDefaultAppLaunch(DefaultAppName default_app_name,
+                            apps::mojom::LaunchSource launch_source);
+
+void RecordAppLaunch(const std::string& app_id,
+                     apps::mojom::LaunchSource launch_source);
+
+}  // namespace apps
+
+#endif  // CHROME_BROWSER_APPS_APP_SERVICE_APP_SERVICE_METRICS_H_
diff --git a/chrome/browser/apps/app_service/app_service_proxy.cc b/chrome/browser/apps/app_service/app_service_proxy.cc
index 7035c23..43998aa 100644
--- a/chrome/browser/apps/app_service/app_service_proxy.cc
+++ b/chrome/browser/apps/app_service/app_service_proxy.cc
@@ -10,6 +10,7 @@
 #include "base/location.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/apps/app_service/app_icon_source.h"
+#include "chrome/browser/apps/app_service/app_service_metrics.h"
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/services/app_service/public/mojom/constants.mojom.h"
@@ -167,6 +168,7 @@
   if (app_service_.is_bound()) {
     cache_.ForOneApp(app_id, [this, event_flags, launch_source,
                               display_id](const apps::AppUpdate& update) {
+      RecordAppLaunch(update.AppId(), launch_source);
       app_service_->Launch(update.AppType(), update.AppId(), event_flags,
                            launch_source, display_id);
     });
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 613647d8..33a17d7 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -26,7 +26,7 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/scoped_refptr.h"
-#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/path_service.h"
diff --git a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service.cc b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service.cc
index 64ab502a..8593cc0 100644
--- a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service.cc
+++ b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service.cc
@@ -358,9 +358,14 @@
   using chromeos::input_method::InputMethodDescriptors;
   using chromeos::input_method::InputMethodManager;
 
+  InputMethodManager* imm = InputMethodManager::Get();
+  if (!imm || !imm->GetActiveIMEState()) {
+    LOG(WARNING) << "InputMethodManager is not ready yet.";
+    return;
+  }
+
   base::AutoReset<bool> in_updating(&is_updating_imm_entry_, true);
-  scoped_refptr<InputMethodManager::State> state =
-      InputMethodManager::Get()->GetActiveIMEState();
+  scoped_refptr<InputMethodManager::State> state = imm->GetActiveIMEState();
   const std::string active_ime_id = state->GetCurrentInputMethod().id();
 
   // Remove the old registered entry.
diff --git a/chrome/browser/chromeos/backdrop_wallpaper_handlers/backdrop_wallpaper_handlers.cc b/chrome/browser/chromeos/backdrop_wallpaper_handlers/backdrop_wallpaper_handlers.cc
index fee1e26..be8962d 100644
--- a/chrome/browser/chromeos/backdrop_wallpaper_handlers/backdrop_wallpaper_handlers.cc
+++ b/chrome/browser/chromeos/backdrop_wallpaper_handlers/backdrop_wallpaper_handlers.cc
@@ -306,8 +306,8 @@
             "Backdrop wallpaper service."
           trigger:
             "When ChromeOS Wallpaper Picker extension is open, "
-            "GOOGLE_CHROME_BUILD is defined and user turns on the surprise me "
-            "feature."
+            "BUILDFLAG(GOOGLE_CHROME_BRANDING) is defined and user turns on "
+            "the surprise me feature."
           data:
             "The Backdrop protocol buffer messages. No user data is included."
           destination: GOOGLE_OWNED_SERVICE
diff --git a/chrome/browser/chromeos/login/demo_mode/demo_mode_test_helper.cc b/chrome/browser/chromeos/login/demo_mode/demo_mode_test_helper.cc
index 89dbe77..f2493ef 100644
--- a/chrome/browser/chromeos/login/demo_mode/demo_mode_test_helper.cc
+++ b/chrome/browser/chromeos/login/demo_mode/demo_mode_test_helper.cc
@@ -10,6 +10,7 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
+#include "base/run_loop.h"
 #include "base/test/scoped_path_override.h"
 #include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/login/demo_mode/demo_resources.h"
diff --git a/chrome/browser/chromeos/login/lock/screen_locker.cc b/chrome/browser/chromeos/login/lock/screen_locker.cc
index 8e85530e..bab0c73 100644
--- a/chrome/browser/chromeos/login/lock/screen_locker.cc
+++ b/chrome/browser/chromeos/login/lock/screen_locker.cc
@@ -15,7 +15,7 @@
 #include "base/location.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
 #include "base/single_thread_task_runner.h"
diff --git a/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc b/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc
index 1580773..3af9d62 100644
--- a/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc
@@ -6,7 +6,7 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/location.h"
-#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/browser_process.h"
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index d54f43a..e00d22d 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -1341,6 +1341,10 @@
   if (!GetOobeUI())
     return;
 
+  // Check for tests configuration.
+  if (StartupUtils::IsEulaAccepted() || StartupUtils::IsOobeCompleted())
+    return;
+
   const auto* skip_screen_key = oobe_configuration_.FindKeyOfType(
       configuration::kSkipHIDDetection, base::Value::Type::BOOLEAN);
   const bool skip_screen = skip_screen_key && skip_screen_key->GetBool();
diff --git a/chrome/browser/defaults.cc b/chrome/browser/defaults.cc
index be70bcf..179fcfd 100644
--- a/chrome/browser/defaults.cc
+++ b/chrome/browser/defaults.cc
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "build/build_config.h"
 #include "chrome/browser/defaults.h"
 
+#include "build/branding_buildflags.h"
+#include "build/build_config.h"
+
 namespace browser_defaults {
 
 #if defined(OS_CHROMEOS) || defined(OS_MACOSX)
@@ -27,7 +29,7 @@
 const bool kAlwaysCreateTabbedBrowserOnSessionRestore = true;
 #endif
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #if defined(OS_CHROMEOS)
 const bool kShowHelpMenuItemIcon = true;
 #else
diff --git a/chrome/browser/extensions/chrome_extensions_interface_registration.cc b/chrome/browser/extensions/chrome_extensions_interface_registration.cc
index 225be8a..b334d2e0 100644
--- a/chrome/browser/extensions/chrome_extensions_interface_registration.cc
+++ b/chrome/browser/extensions/chrome_extensions_interface_registration.cc
@@ -143,7 +143,7 @@
       extension->permissions_data()->HasAPIPermission(
           APIPermission::kMediaRouterPrivate)) {
     registry->AddInterface(
-        base::Bind(&media_router::MediaRouterDesktop::BindToRequest,
+        base::Bind(&media_router::MediaRouterDesktop::BindToReceiver,
                    base::RetainedRef(extension), context));
   }
 
diff --git a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
index ab59df1..14289ab0 100644
--- a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
+++ b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
@@ -6,13 +6,19 @@
 
 #include <memory>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/bind.h"
 #include "base/json/json_string_value_serializer.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
 #include "base/system/sys_info.h"
 #include "base/task/post_task.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.h"
@@ -45,6 +51,9 @@
 
 #if defined(OS_WIN)
 #include "base/win/win_util.h"
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+#include "chrome/browser/google/google_update_win.h"
+#endif
 #include "ui/base/win/hidden_window.h"
 #endif
 
@@ -74,6 +83,12 @@
 constexpr char kUsbKeyboardDetected[] = "usb_keyboard_detected";
 constexpr char kIsEnrolledToDomain[] = "enrolled_to_domain";
 constexpr char kInstallerBrandCode[] = "installer_brand_code";
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+constexpr char kUpdateErrorCode[] = "update_error_code";
+constexpr char kUpdateHresult[] = "update_hresult";
+constexpr char kInstallResultCode[] = "install_result_code";
+constexpr char kInstallLocation[] = "install_location";
+#endif
 #endif
 
 #if defined(OS_CHROMEOS)
@@ -192,6 +207,38 @@
 }
 #endif  // defined(OS_CHROMEOS)
 
+#if defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
+// Returns true if the path identified by |key| with the PathService is a parent
+// or ancestor of |child|.
+bool IsParentOf(int key, const base::FilePath& child) {
+  base::FilePath path;
+  return base::PathService::Get(key, &path) && path.IsParent(child);
+}
+
+// Returns a string representing the overall install location of the browser.
+// "Program Files" and "Program Files (x86)" are both considered "per-machine"
+// locations (for all users), whereas anything in a user's local app data dir is
+// considered a "per-user" location. This function returns an answer that gives,
+// in essence, the broad category of location without checking that the browser
+// is operating out of the exact expected install directory. It is interesting
+// to know via feedback reports if updates are failing with
+// CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY, which checks the exact directory,
+// yet the reported install_location is not "unknown".
+std::string DetermineInstallLocation() {
+  base::FilePath exe_path;
+
+  if (base::PathService::Get(base::FILE_EXE, &exe_path)) {
+    if (IsParentOf(base::DIR_PROGRAM_FILESX86, exe_path) ||
+        IsParentOf(base::DIR_PROGRAM_FILES, exe_path)) {
+      return "per-machine";
+    }
+    if (IsParentOf(base::DIR_LOCAL_APP_DATA, exe_path))
+      return "per-user";
+  }
+  return "unknown";
+}
+#endif  // defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
+
 }  // namespace
 
 ChromeInternalLogSource::ChromeInternalLogSource()
@@ -230,6 +277,7 @@
   PopulateUsbKeyboardDetected(response.get());
   PopulateEnrolledToDomain(response.get());
   PopulateInstallerBrandCode(response.get());
+  PopulateLastUpdateState(response.get());
 #endif
 
   if (ProfileManager::GetLastUsedProfile()->IsChild())
@@ -410,6 +458,29 @@
   response->emplace(kInstallerBrandCode,
                     brand.empty() ? "Unknown brand code" : brand);
 }
-#endif
+
+void ChromeInternalLogSource::PopulateLastUpdateState(
+    SystemLogsResponse* response) {
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+  const base::Optional<UpdateState> update_state = GetLastUpdateState();
+  if (!update_state)
+    return;  // There is nothing to include if no update check has completed.
+
+  response->emplace(kUpdateErrorCode,
+                    base::NumberToString(update_state->error_code));
+  response->emplace(kInstallLocation, DetermineInstallLocation());
+
+  if (update_state->error_code == GOOGLE_UPDATE_NO_ERROR)
+    return;  // There is nothing more to include if the last check succeeded.
+
+  response->emplace(kUpdateHresult,
+                    base::StringPrintf("0x%08lX", update_state->hresult));
+  if (update_state->installer_exit_code) {
+    response->emplace(kInstallResultCode,
+                      base::NumberToString(*update_state->installer_exit_code));
+  }
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
+}
+#endif  // defined(OS_WIN)
 
 }  // namespace system_logs
diff --git a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.h b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.h
index 5f74d5a..79681f1 100644
--- a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.h
+++ b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.h
@@ -38,6 +38,7 @@
   void PopulateUsbKeyboardDetected(SystemLogsResponse* response);
   void PopulateEnrolledToDomain(SystemLogsResponse* response);
   void PopulateInstallerBrandCode(SystemLogsResponse* response);
+  void PopulateLastUpdateState(SystemLogsResponse* response);
 #endif
 
 #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/google/google_update_win.cc b/chrome/browser/google/google_update_win.cc
index 9c44a72..756024b 100644
--- a/chrome/browser/google/google_update_win.cc
+++ b/chrome/browser/google/google_update_win.cc
@@ -8,7 +8,6 @@
 #include <stdint.h>
 #include <string.h>
 
-#include <string>
 #include <utility>
 #include <vector>
 
@@ -18,11 +17,13 @@
 #include "base/location.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/no_destructor.h"
 #include "base/path_service.h"
 #include "base/sequenced_task_runner.h"
 #include "base/sequenced_task_runner_helpers.h"
 #include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
@@ -194,6 +195,12 @@
       nullptr, IID_PPV_ARGS(google_update->GetAddressOf()));
 }
 
+// Returns the process-wide storage for the state of the last update check.
+base::Optional<UpdateState>* GetLastUpdateStateStorage() {
+  static base::NoDestructor<base::Optional<UpdateState>> storage;
+  return storage.get();
+}
+
 // UpdateCheckDriver -----------------------------------------------------------
 
 // A driver that is created and destroyed on the caller's thread and drives
@@ -239,14 +246,15 @@
   // steps that failed.
   HRESULT BeginUpdateCheckInternal(GoogleUpdateErrorCode* error_code);
 
-  // Sets status_ to UPGRADE_ERROR, error_code_ to |error_code|, hresult_ to
-  // |hresult|, installer_exit_code_ to |installer_exit_code|, and
-  // html_error_message_ to a composition of all values suitable for display
-  // to the user. This call should be followed by deletion of the driver,
-  // which will result in callers being notified via their delegates.
+  // Sets status_ to UPGRADE_ERROR, update_state_.error_code to |error_code|,
+  // update_state_.hresult to |hresult|, update_state_.installer_exit_code to
+  // |installer_exit_code|, and html_error_message_ to a composition of all
+  // values suitable for display to the user. This call should be followed by
+  // deletion of the driver, which will result in callers being notified via
+  // their delegates.
   void OnUpgradeError(GoogleUpdateErrorCode error_code,
                       HRESULT hresult,
-                      int installer_exit_code,
+                      base::Optional<int> installer_exit_code,
                       const base::string16& error_string);
 
   // Returns true if |current_state| and |state_value| can be obtained from the
@@ -264,14 +272,13 @@
   // https://code.google.com/p/omaha/source/browse/trunk/base/error.h). In case
   // Chrome's installer failed during execution, |installer_exit_code| may be
   // populated with its process exit code (see enum installer::InstallStatus in
-  // chrome/installer/util/util_constants.h); otherwise, it will be -1.
-  // |error_string| will be populated with a completion message if one is
-  // provided by Google Update.
+  // chrome/installer/util/util_constants.h). |error_string| will be populated
+  // with a completion message if one is provided by Google Update.
   bool IsErrorState(const Microsoft::WRL::ComPtr<ICurrentState>& current_state,
                     CurrentState state_value,
                     GoogleUpdateErrorCode* error_code,
                     HRESULT* hresult,
-                    int* installer_exit_code,
+                    base::Optional<int>* installer_exit_code,
                     base::string16* error_string) const;
 
   // Returns true if |current_state| and |state_value| constitute a final state
@@ -349,11 +356,8 @@
   // The results of the update check to be logged via UMA and/or reported to the
   // caller.
   GoogleUpdateUpgradeStatus status_;
-  GoogleUpdateErrorCode error_code_;
+  UpdateState update_state_;
   base::string16 html_error_message_;
-  base::string16 new_version_;
-  HRESULT hresult_;
-  int installer_exit_code_;
 
   DISALLOW_COPY_AND_ASSIGN(UpdateCheckDriver);
 };
@@ -400,25 +404,28 @@
       allowed_retries_(kGoogleAllowedRetries),
       system_level_install_(false),
       last_reported_progress_(0),
-      status_(UPGRADE_ERROR),
-      error_code_(GOOGLE_UPDATE_NO_ERROR),
-      hresult_(S_OK),
-      installer_exit_code_(-1) {}
+      status_(UPGRADE_ERROR) {}
 
 UpdateCheckDriver::~UpdateCheckDriver() {
   DCHECK(result_runner_->RunsTasksInCurrentSequence());
   // If there is an error, then error_code must not be blank, and vice versa.
-  DCHECK_NE(status_ == UPGRADE_ERROR, error_code_ == GOOGLE_UPDATE_NO_ERROR);
+  DCHECK_NE(status_ == UPGRADE_ERROR,
+            update_state_.error_code == GOOGLE_UPDATE_NO_ERROR);
+
+  *GetLastUpdateStateStorage() = update_state_;
+
   UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.UpgradeResult", status_,
                             NUM_UPGRADE_STATUS);
   if (status_ == UPGRADE_ERROR) {
-    UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.UpdateErrorCode", error_code_,
-                              NUM_ERROR_CODES);
-    if (FAILED(hresult_))
-      base::UmaHistogramSparse("GoogleUpdate.ErrorHresult", hresult_);
-    if (installer_exit_code_ != -1) {
+    UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.UpdateErrorCode",
+                              update_state_.error_code, NUM_ERROR_CODES);
+    if (FAILED(update_state_.hresult)) {
+      base::UmaHistogramSparse("GoogleUpdate.ErrorHresult",
+                               update_state_.hresult);
+    }
+    if (update_state_.installer_exit_code) {
       base::UmaHistogramSparse("GoogleUpdate.InstallerExitCode",
-                               installer_exit_code_);
+                               *update_state_.installer_exit_code);
     }
   }
 
@@ -429,12 +436,14 @@
 
   for (const auto& delegate : delegates_) {
     if (delegate) {
-      if (status_ == UPGRADE_ERROR)
-        delegate->OnError(error_code_, html_error_message_, new_version_);
-      else if (install_update_if_possible_)
-        delegate->OnUpgradeComplete(new_version_);
-      else
-        delegate->OnUpdateCheckComplete(new_version_);
+      if (status_ == UPGRADE_ERROR) {
+        delegate->OnError(update_state_.error_code, html_error_message_,
+                          update_state_.new_version);
+      } else if (install_update_if_possible_) {
+        delegate->OnUpgradeComplete(update_state_.new_version);
+      } else {
+        delegate->OnUpdateCheckComplete(update_state_.new_version);
+      }
     }
   }
 }
@@ -480,7 +489,7 @@
   }
 
   DCHECK(FAILED(hresult));
-  OnUpgradeError(error_code, hresult, -1, base::string16());
+  OnUpgradeError(error_code, hresult, base::nullopt, base::string16());
   result_runner_->DeleteSoon(FROM_HERE, this);
 }
 
@@ -609,7 +618,7 @@
     CurrentState state_value,
     GoogleUpdateErrorCode* error_code,
     HRESULT* hresult,
-    int* installer_exit_code,
+    base::Optional<int>* installer_exit_code,
     base::string16* error_string) const {
   if (state_value == STATE_ERROR) {
     // In general, errors reported by Google Update fall under this category
@@ -618,7 +627,7 @@
 
     // In general, the exit code of Chrome's installer is unknown (see special
     // case below).
-    *installer_exit_code = -1;
+    installer_exit_code->reset();
 
     // Report the error_code provided by Google Update if possible, or the
     // reason it wasn't possible otherwise.
@@ -654,7 +663,7 @@
       // Report a failure to start the install as a general error while trying
       // to interact with Google Update.
       *error_code = GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR;
-      *installer_exit_code = -1;
+      installer_exit_code->reset();
       return true;
     }
     // Return false for handling in IsIntermediateState.
@@ -766,30 +775,31 @@
   CurrentState state_value = STATE_INIT;
   HRESULT hresult = S_OK;
   GoogleUpdateErrorCode error_code = GOOGLE_UPDATE_NO_ERROR;
-  int installer_exit_code = -1;
+  base::Optional<int> installer_exit_code;
   base::string16 error_string;
   GoogleUpdateUpgradeStatus upgrade_status = UPGRADE_ERROR;
   base::string16 new_version;
   int progress = 0;
 
   if (!GetCurrentState(&state, &state_value, &hresult)) {
-    OnUpgradeError(GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR, hresult, -1,
-                   base::string16());
+    OnUpgradeError(GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR, hresult,
+                   base::nullopt, base::string16());
   } else if (IsErrorState(state, state_value, &error_code, &hresult,
                           &installer_exit_code, &error_string)) {
     OnUpgradeError(error_code, hresult, installer_exit_code, error_string);
   } else if (IsFinalState(state, state_value, &upgrade_status, &new_version)) {
     status_ = upgrade_status;
-    error_code_ = GOOGLE_UPDATE_NO_ERROR;
+    update_state_.error_code = GOOGLE_UPDATE_NO_ERROR;
     html_error_message_.clear();
     if (!new_version.empty())
-      new_version_ = new_version;
-    hresult_ = S_OK;
-    installer_exit_code_ = -1;
+      update_state_.new_version = new_version;
+    update_state_.hresult = S_OK;
+    update_state_.installer_exit_code.reset();
   } else if (IsIntermediateState(state, state_value, &new_version, &progress)) {
-    bool got_new_version = new_version_.empty() && !new_version.empty();
+    bool got_new_version =
+        update_state_.new_version.empty() && !new_version.empty();
     if (got_new_version)
-      new_version_ = new_version;
+      update_state_.new_version = new_version;
     // Give the caller this status update if it differs from the last one given.
     if (got_new_version || progress != last_reported_progress_) {
       last_reported_progress_ = progress;
@@ -797,9 +807,10 @@
       // It is safe to post this task with an unretained pointer since the task
       // is guaranteed to run before a subsequent DeleteSoon is handled.
       result_runner_->PostTask(
-          FROM_HERE, base::BindOnce(&UpdateCheckDriver::NotifyUpgradeProgress,
-                                    base::Unretained(this),
-                                    last_reported_progress_, new_version_));
+          FROM_HERE,
+          base::BindOnce(&UpdateCheckDriver::NotifyUpgradeProgress,
+                         base::Unretained(this), last_reported_progress_,
+                         update_state_.new_version));
     }
 
     // Schedule the next check.
@@ -824,12 +835,12 @@
 
 void UpdateCheckDriver::OnUpgradeError(GoogleUpdateErrorCode error_code,
                                        HRESULT hresult,
-                                       int installer_exit_code,
+                                       base::Optional<int> installer_exit_code,
                                        const base::string16& error_string) {
   status_ = UPGRADE_ERROR;
-  error_code_ = error_code;
-  hresult_ = hresult;
-  installer_exit_code_ = installer_exit_code;
+  update_state_.error_code = error_code;
+  update_state_.hresult = hresult;
+  update_state_.installer_exit_code = installer_exit_code;
 
   // Some specific result codes have dedicated messages.
   if (hresult == GOOPDATE_E_APP_USING_EXTERNAL_UPDATER) {
@@ -838,13 +849,14 @@
     return;
   }
 
-  base::string16 html_error_msg =
-      base::StringPrintf(L"%d: <a href='%ls0x%X' target=_blank>0x%X</a>",
-                         error_code_, base::UTF8ToUTF16(
-                             chrome::kUpgradeHelpCenterBaseURL).c_str(),
-                         hresult_, hresult_);
-  if (installer_exit_code_ != -1)
-    html_error_msg += base::StringPrintf(L": %d", installer_exit_code_);
+  base::string16 html_error_msg = base::StringPrintf(
+      L"%d: <a href='%ls0x%X' target=_blank>0x%X</a>", update_state_.error_code,
+      base::UTF8ToUTF16(chrome::kUpgradeHelpCenterBaseURL).c_str(),
+      update_state_.hresult, update_state_.hresult);
+  if (update_state_.installer_exit_code) {
+    html_error_msg +=
+        L": " + base::NumberToString16(*update_state_.installer_exit_code);
+  }
   if (system_level_install_)
     html_error_msg += L" -- system level";
   if (error_string.empty()) {
@@ -870,6 +882,17 @@
                                     elevation_window, delegate);
 }
 
+// UpdateState -----------------------------------------------------------------
+
+UpdateState::UpdateState() = default;
+UpdateState::UpdateState(const UpdateState&) = default;
+UpdateState::UpdateState(UpdateState&&) = default;
+UpdateState& UpdateState::operator=(UpdateState&&) = default;
+UpdateState::~UpdateState() = default;
+
+base::Optional<UpdateState> GetLastUpdateState() {
+  return *GetLastUpdateStateStorage();
+}
 
 // Private API exposed for testing. --------------------------------------------
 
diff --git a/chrome/browser/google/google_update_win.h b/chrome/browser/google/google_update_win.h
index b66e322b..a69ac60 100644
--- a/chrome/browser/google/google_update_win.h
+++ b/chrome/browser/google/google_update_win.h
@@ -7,9 +7,12 @@
 
 #include <wrl/client.h>
 
+#include <string>
+
 #include "base/callback_forward.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "base/optional.h"
 #include "base/strings/string16.h"
 #include "google_update/google_update_idl.h"
 #include "ui/gfx/native_widget_types.h"
@@ -100,6 +103,34 @@
     gfx::AcceleratedWidget elevation_window,
     const base::WeakPtr<UpdateCheckDelegate>& delegate);
 
+// The state from a completed update check.
+struct UpdateState {
+  UpdateState();
+  UpdateState(const UpdateState&);
+  UpdateState(UpdateState&&);
+  UpdateState& operator=(UpdateState&&);
+  ~UpdateState();
+
+  // GOOGLE_UPDATE_NO_ERROR if the last check or update succeeded; otherwise,
+  // the nature of the failure.
+  GoogleUpdateErrorCode error_code = GOOGLE_UPDATE_NO_ERROR;
+
+  // The next version available or an empty string if either no update is
+  // available or an error occurred before the new version was discovered.
+  base::string16 new_version;
+
+  // S_OK if the last check or update succeeded; otherwise, the failing error
+  // from Google Update or COM.
+  HRESULT hresult = S_OK;
+
+  // If present, the process exit code from the failed run of the installer.
+  base::Optional<int> installer_exit_code;
+};
+
+// Returns the state from the most recent completed update check or no value if
+// no such check has taken place.
+base::Optional<UpdateState> GetLastUpdateState();
+
 // A type of callback supplied by tests to provide a custom IGoogleUpdate3Web
 // implementation (see src/google_update/google_update_idl.idl).
 typedef base::Callback<HRESULT(Microsoft::WRL::ComPtr<IGoogleUpdate3Web>*)>
diff --git a/chrome/browser/google/google_update_win_unittest.cc b/chrome/browser/google/google_update_win_unittest.cc
index c0bed81..cd31714 100644
--- a/chrome/browser/google/google_update_win_unittest.cc
+++ b/chrome/browser/google/google_update_win_unittest.cc
@@ -9,6 +9,7 @@
 #include <wrl/client.h>
 
 #include <memory>
+#include <string>
 
 #include "base/base_paths.h"
 #include "base/bind.h"
@@ -684,6 +685,9 @@
   BeginUpdateCheck(std::string(), false, 0,
                    mock_update_check_delegate_.AsWeakPtr());
   task_runner_->RunUntilIdle();
+  ASSERT_TRUE(GetLastUpdateState());
+  EXPECT_EQ(GetLastUpdateState()->error_code,
+            CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY);
 }
 
 // Test the case where the GoogleUpdate class can't be created for an update
@@ -698,6 +702,9 @@
   BeginUpdateCheck(std::string(), false, 0,
                    mock_update_check_delegate_.AsWeakPtr());
   task_runner_->RunUntilIdle();
+  ASSERT_TRUE(GetLastUpdateState());
+  EXPECT_EQ(GetLastUpdateState()->error_code,
+            GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND);
 }
 
 // Test the case where the GoogleUpdate class can't be created for an upgrade.
@@ -711,6 +718,9 @@
   BeginUpdateCheck(std::string(), true, 0,
                    mock_update_check_delegate_.AsWeakPtr());
   task_runner_->RunUntilIdle();
+  ASSERT_TRUE(GetLastUpdateState());
+  EXPECT_EQ(GetLastUpdateState()->error_code,
+            GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND);
 }
 
 // Test the case where the GoogleUpdate class returns an error when an update
@@ -728,6 +738,10 @@
   BeginUpdateCheck(std::string(), false, 0,
                    mock_update_check_delegate_.AsWeakPtr());
   task_runner_->RunUntilIdle();
+  ASSERT_TRUE(GetLastUpdateState());
+  EXPECT_EQ(GetLastUpdateState()->error_code,
+            GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR);
+  EXPECT_EQ(GetLastUpdateState()->hresult, E_FAIL);
 }
 
 // Test the case where the GoogleUpdate class reports that updates are disabled
@@ -753,6 +767,8 @@
   BeginUpdateCheck(std::string(), false, 0,
                    mock_update_check_delegate_.AsWeakPtr());
   task_runner_->RunUntilIdle();
+  ASSERT_TRUE(GetLastUpdateState());
+  EXPECT_EQ(GetLastUpdateState()->error_code, GOOGLE_UPDATE_DISABLED_BY_POLICY);
 }
 
 // Test the case where the GoogleUpdate class reports that manual updates are
@@ -779,6 +795,9 @@
   BeginUpdateCheck(std::string(), false, 0,
                    mock_update_check_delegate_.AsWeakPtr());
   task_runner_->RunUntilIdle();
+  ASSERT_TRUE(GetLastUpdateState());
+  EXPECT_EQ(GetLastUpdateState()->error_code,
+            GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY);
 }
 
 // Test an update check where no update is available.
@@ -800,6 +819,9 @@
   BeginUpdateCheck(std::string(), false, 0,
                    mock_update_check_delegate_.AsWeakPtr());
   task_runner_->RunUntilIdle();
+  ASSERT_TRUE(GetLastUpdateState());
+  EXPECT_EQ(GetLastUpdateState()->error_code, GOOGLE_UPDATE_NO_ERROR);
+  EXPECT_EQ(GetLastUpdateState()->new_version, STRING16_LITERAL(""));
 }
 
 // Test an update check where an update is available.
@@ -821,6 +843,9 @@
   BeginUpdateCheck(std::string(), false, 0,
                    mock_update_check_delegate_.AsWeakPtr());
   task_runner_->RunUntilIdle();
+  ASSERT_TRUE(GetLastUpdateState());
+  EXPECT_EQ(GetLastUpdateState()->error_code, GOOGLE_UPDATE_NO_ERROR);
+  EXPECT_EQ(GetLastUpdateState()->new_version, new_version_);
 }
 
 // Test a successful upgrade.
@@ -866,6 +891,9 @@
   BeginUpdateCheck(std::string(), true, 0,
                    mock_update_check_delegate_.AsWeakPtr());
   task_runner_->RunUntilIdle();
+  ASSERT_TRUE(GetLastUpdateState());
+  EXPECT_EQ(GetLastUpdateState()->error_code, GOOGLE_UPDATE_NO_ERROR);
+  EXPECT_EQ(GetLastUpdateState()->new_version, new_version_);
 }
 
 // Test a failed upgrade where Google Update reports that the installer failed.
@@ -917,6 +945,12 @@
   BeginUpdateCheck(std::string(), true, 0,
                    mock_update_check_delegate_.AsWeakPtr());
   task_runner_->RunUntilIdle();
+  ASSERT_TRUE(GetLastUpdateState());
+  EXPECT_EQ(GetLastUpdateState()->error_code, GOOGLE_UPDATE_ERROR_UPDATING);
+  EXPECT_EQ(GetLastUpdateState()->new_version, new_version_);
+  EXPECT_EQ(GetLastUpdateState()->hresult, GOOPDATEINSTALL_E_INSTALLER_FAILED);
+  ASSERT_TRUE(GetLastUpdateState()->installer_exit_code);
+  EXPECT_EQ(GetLastUpdateState()->installer_exit_code.value(), kInstallerError);
 }
 
 // Test that a retry after a USING_EXTERNAL_UPDATER failure succeeds.
@@ -958,6 +992,9 @@
   BeginUpdateCheck(std::string(), false, 0,
                    mock_update_check_delegate_.AsWeakPtr());
   task_runner_->RunUntilIdle();
+  ASSERT_TRUE(GetLastUpdateState());
+  EXPECT_EQ(GetLastUpdateState()->error_code, GOOGLE_UPDATE_NO_ERROR);
+  EXPECT_EQ(GetLastUpdateState()->new_version, STRING16_LITERAL(""));
 }
 
 TEST_P(GoogleUpdateWinTest, UpdateInstalledMultipleDelegates) {
@@ -1020,6 +1057,9 @@
   BeginUpdateCheck(std::string(), true, 0,
                    mock_update_check_delegate_2.AsWeakPtr());
   task_runner_->RunUntilIdle();
+  ASSERT_TRUE(GetLastUpdateState());
+  EXPECT_EQ(GetLastUpdateState()->error_code, GOOGLE_UPDATE_NO_ERROR);
+  EXPECT_EQ(GetLastUpdateState()->new_version, new_version_);
 }
 
 INSTANTIATE_TEST_SUITE_P(UserLevel, GoogleUpdateWinTest, Values(false));
diff --git a/chrome/browser/importer/external_process_importer_client.cc b/chrome/browser/importer/external_process_importer_client.cc
index b39cff2..5c56fb7 100644
--- a/chrome/browser/importer/external_process_importer_client.cc
+++ b/chrome/browser/importer/external_process_importer_client.cc
@@ -71,10 +71,8 @@
 
   // If the utility process hasn't started yet the message will queue until it
   // does.
-  chrome::mojom::ProfileImportObserverPtr observer;
-  receiver_.Bind(mojo::MakeRequest(&observer));
   profile_import_->StartImport(source_profile_, items_, localized_strings,
-                               std::move(observer));
+                               receiver_.BindNewPipeAndPassRemote());
 }
 
 void ExternalProcessImporterClient::Cancel() {
diff --git a/chrome/browser/media/router/media_router.h b/chrome/browser/media/router/media_router.h
index 8fd83c8..07f9eed 100644
--- a/chrome/browser/media/router/media_router.h
+++ b/chrome/browser/media/router/media_router.h
@@ -30,6 +30,7 @@
 #if !defined(OS_ANDROID)
 #include "chrome/common/media_router/mojom/media_controller.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #endif  // !defined(OS_ANDROID)
 
 namespace content {
@@ -204,7 +205,7 @@
   virtual void GetMediaController(
       const MediaRoute::Id& route_id,
       mojo::PendingReceiver<mojom::MediaController> controller,
-      mojom::MediaStatusObserverPtr observer) = 0;
+      mojo::PendingRemote<mojom::MediaStatusObserver> observer) = 0;
 #endif  // !defined(OS_ANDROID)
 
   // Registers/Unregisters a CastRemotingConnector with the |tab_id|. For a
diff --git a/chrome/browser/media/router/media_router_base.cc b/chrome/browser/media/router/media_router_base.cc
index a8d599d..24d66af2 100644
--- a/chrome/browser/media/router/media_router_base.cc
+++ b/chrome/browser/media/router/media_router_base.cc
@@ -92,7 +92,7 @@
 void MediaRouterBase::GetMediaController(
     const MediaRoute::Id& route_id,
     mojo::PendingReceiver<mojom::MediaController> controller,
-    mojom::MediaStatusObserverPtr observer) {}
+    mojo::PendingRemote<mojom::MediaStatusObserver> observer) {}
 #endif  // !defined(OS_ANDROID)
 
 MediaRouterBase::MediaRouterBase() : initialized_(false) {}
diff --git a/chrome/browser/media/router/media_router_base.h b/chrome/browser/media/router/media_router_base.h
index ec62fe66..c4338a95 100644
--- a/chrome/browser/media/router/media_router_base.h
+++ b/chrome/browser/media/router/media_router_base.h
@@ -22,6 +22,7 @@
 #if !defined(OS_ANDROID)
 #include "chrome/common/media_router/mojom/media_controller.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #endif  // !defined(OS_ANDROID)
 
 namespace media_router {
@@ -45,7 +46,7 @@
   void GetMediaController(
       const MediaRoute::Id& route_id,
       mojo::PendingReceiver<mojom::MediaController> controller,
-      mojom::MediaStatusObserverPtr observer) override;
+      mojo::PendingRemote<mojom::MediaStatusObserver> observer) override;
 #endif  // !defined(OS_ANDROID)
   void RegisterRemotingSource(SessionID tab_id,
                               CastRemotingConnector* remoting_source) override;
diff --git a/chrome/browser/media/router/mojo/media_router_desktop.cc b/chrome/browser/media/router/mojo/media_router_desktop.cc
index a027e3b..3a59b27 100644
--- a/chrome/browser/media/router/mojo/media_router_desktop.cc
+++ b/chrome/browser/media/router/mojo/media_router_desktop.cc
@@ -21,6 +21,8 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/system_connector.h"
 #include "extensions/common/extension.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/service_manager/public/cpp/connector.h"
 #if defined(OS_WIN)
 #include "chrome/browser/media/router/mojo/media_route_provider_util_win.h"
@@ -43,15 +45,16 @@
 MediaRouterDesktop::~MediaRouterDesktop() = default;
 
 // static
-void MediaRouterDesktop::BindToRequest(const extensions::Extension* extension,
-                                       content::BrowserContext* context,
-                                       mojom::MediaRouterRequest request,
-                                       content::RenderFrameHost* source) {
+void MediaRouterDesktop::BindToReceiver(
+    const extensions::Extension* extension,
+    content::BrowserContext* context,
+    mojo::PendingReceiver<mojom::MediaRouter> receiver,
+    content::RenderFrameHost* source) {
   MediaRouterDesktop* impl = static_cast<MediaRouterDesktop*>(
       MediaRouterFactory::GetApiForBrowserContext(context));
   DCHECK(impl);
 
-  impl->BindToMojoRequest(std::move(request), *extension);
+  impl->BindToMojoReceiver(std::move(receiver), *extension);
 }
 
 void MediaRouterDesktop::OnUserGesture() {
@@ -106,7 +109,7 @@
 
 void MediaRouterDesktop::RegisterMediaRouteProvider(
     MediaRouteProviderId provider_id,
-    mojom::MediaRouteProviderPtr media_route_provider_ptr,
+    mojo::PendingRemote<mojom::MediaRouteProvider> media_route_provider_remote,
     mojom::MediaRouter::RegisterMediaRouteProviderCallback callback) {
   auto config = mojom::MediaRouteProviderConfig::New();
   // Enabling browser side discovery / sink query means disabling extension side
@@ -122,12 +125,14 @@
   SyncStateToMediaRouteProvider(provider_id);
 
   if (provider_id == MediaRouteProviderId::EXTENSION) {
-    RegisterExtensionMediaRouteProvider(std::move(media_route_provider_ptr));
+    RegisterExtensionMediaRouteProvider(std::move(media_route_provider_remote));
   } else {
-    media_route_provider_ptr.set_connection_error_handler(
+    mojo::Remote<mojom::MediaRouteProvider> bound_remote(
+        std::move(media_route_provider_remote));
+    bound_remote.set_disconnect_handler(
         base::BindOnce(&MediaRouterDesktop::OnProviderConnectionError,
                        weak_factory_.GetWeakPtr(), provider_id));
-    media_route_providers_[provider_id] = std::move(media_route_provider_ptr);
+    media_route_providers_[provider_id] = std::move(bound_remote);
   }
 }
 
@@ -148,7 +153,7 @@
 }
 
 void MediaRouterDesktop::RegisterExtensionMediaRouteProvider(
-    mojom::MediaRouteProviderPtr extension_provider_ptr) {
+    mojo::PendingRemote<mojom::MediaRouteProvider> extension_provider_remote) {
   ProvideSinksToExtension();
 #if defined(OS_WIN)
   // The extension MRP already turns on mDNS discovery for platforms other than
@@ -160,14 +165,14 @@
     EnsureMdnsDiscoveryEnabled();
 #endif
   extension_provider_proxy_->RegisterMediaRouteProvider(
-      std::move(extension_provider_ptr));
+      std::move(extension_provider_remote));
 }
 
-void MediaRouterDesktop::BindToMojoRequest(
-    mojo::InterfaceRequest<mojom::MediaRouter> request,
+void MediaRouterDesktop::BindToMojoReceiver(
+    mojo::PendingReceiver<mojom::MediaRouter> receiver,
     const extensions::Extension& extension) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  MediaRouterMojoImpl::BindToMojoRequest(std::move(request));
+  MediaRouterMojoImpl::BindToMojoReceiver(std::move(receiver));
   extension_provider_proxy_->SetExtensionId(extension.id());
   if (!provider_version_was_recorded_) {
     MediaRouterMojoMetrics::RecordMediaRouteProviderVersion(extension);
@@ -217,13 +222,13 @@
     extension_provider_proxy_ =
         std::make_unique<ExtensionMediaRouteProviderProxy>(context());
   }
-  mojom::MediaRouteProviderPtr extension_provider_proxy_ptr;
+  mojo::Remote<mojom::MediaRouteProvider> extension_provider_proxy_remote;
   extension_provider_proxy_->Bind(
-      mojo::MakeRequest(&extension_provider_proxy_ptr));
-  extension_provider_proxy_ptr.set_connection_error_handler(base::BindOnce(
+      extension_provider_proxy_remote.BindNewPipeAndPassReceiver());
+  extension_provider_proxy_remote.set_disconnect_handler(base::BindOnce(
       &MediaRouterDesktop::OnExtensionProviderError, base::Unretained(this)));
   media_route_providers_[MediaRouteProviderId::EXTENSION] =
-      std::move(extension_provider_proxy_ptr);
+      std::move(extension_provider_proxy_remote);
 }
 
 void MediaRouterDesktop::OnExtensionProviderError() {
@@ -241,14 +246,15 @@
 }
 
 void MediaRouterDesktop::InitializeWiredDisplayMediaRouteProvider() {
-  mojom::MediaRouterPtr media_router_ptr;
-  MediaRouterMojoImpl::BindToMojoRequest(mojo::MakeRequest(&media_router_ptr));
-  mojom::MediaRouteProviderPtr wired_display_provider_ptr;
+  mojo::PendingRemote<mojom::MediaRouter> media_router_remote;
+  MediaRouterMojoImpl::BindToMojoReceiver(
+      media_router_remote.InitWithNewPipeAndPassReceiver());
+  mojo::PendingRemote<mojom::MediaRouteProvider> wired_display_provider_remote;
   wired_display_provider_ = std::make_unique<WiredDisplayMediaRouteProvider>(
-      mojo::MakeRequest(&wired_display_provider_ptr),
-      std::move(media_router_ptr), Profile::FromBrowserContext(context()));
+      wired_display_provider_remote.InitWithNewPipeAndPassReceiver(),
+      std::move(media_router_remote), Profile::FromBrowserContext(context()));
   RegisterMediaRouteProvider(MediaRouteProviderId::WIRED_DISPLAY,
-                             std::move(wired_display_provider_ptr),
+                             std::move(wired_display_provider_remote),
                              base::DoNothing());
 }
 
@@ -260,27 +266,30 @@
 void MediaRouterDesktop::InitializeCastMediaRouteProvider() {
   auto task_runner =
       cast_channel::CastSocketService::GetInstance()->task_runner();
-  mojom::MediaRouterPtr media_router_ptr;
-  MediaRouterMojoImpl::BindToMojoRequest(mojo::MakeRequest(&media_router_ptr));
-  mojom::MediaRouteProviderPtr cast_provider_ptr;
+  mojo::PendingRemote<mojom::MediaRouter> media_router_remote;
+  MediaRouterMojoImpl::BindToMojoReceiver(
+      media_router_remote.InitWithNewPipeAndPassReceiver());
+  mojo::PendingRemote<mojom::MediaRouteProvider> cast_provider_remote;
   cast_provider_ =
       std::unique_ptr<CastMediaRouteProvider, base::OnTaskRunnerDeleter>(
           new CastMediaRouteProvider(
-              mojo::MakeRequest(&cast_provider_ptr),
-              media_router_ptr.PassInterface(),
+              cast_provider_remote.InitWithNewPipeAndPassReceiver(),
+              std::move(media_router_remote),
               media_sink_service_->GetCastMediaSinkServiceImpl(),
               media_sink_service_->cast_app_discovery_service(),
               GetCastMessageHandler(), GetConnector(), GetHashToken(),
               task_runner),
           base::OnTaskRunnerDeleter(task_runner));
   RegisterMediaRouteProvider(MediaRouteProviderId::CAST,
-                             std::move(cast_provider_ptr), base::DoNothing());
+                             std::move(cast_provider_remote),
+                             base::DoNothing());
 }
 
 void MediaRouterDesktop::InitializeDialMediaRouteProvider() {
-  mojom::MediaRouterPtr media_router_ptr;
-  MediaRouterMojoImpl::BindToMojoRequest(mojo::MakeRequest(&media_router_ptr));
-  mojom::MediaRouteProviderPtr dial_provider_ptr;
+  mojo::PendingRemote<mojom::MediaRouter> media_router_remote;
+  MediaRouterMojoImpl::BindToMojoReceiver(
+      media_router_remote.InitWithNewPipeAndPassReceiver());
+  mojo::PendingRemote<mojom::MediaRouteProvider> dial_provider_remote;
 
   auto* dial_media_sink_service =
       media_sink_service_->GetDialMediaSinkServiceImpl();
@@ -288,13 +297,14 @@
 
   dial_provider_ =
       std::unique_ptr<DialMediaRouteProvider, base::OnTaskRunnerDeleter>(
-          new DialMediaRouteProvider(mojo::MakeRequest(&dial_provider_ptr),
-                                     media_router_ptr.PassInterface(),
-                                     dial_media_sink_service, GetConnector(),
-                                     GetHashToken(), task_runner),
+          new DialMediaRouteProvider(
+              dial_provider_remote.InitWithNewPipeAndPassReceiver(),
+              std::move(media_router_remote), dial_media_sink_service,
+              GetConnector(), GetHashToken(), task_runner),
           base::OnTaskRunnerDeleter(task_runner));
   RegisterMediaRouteProvider(MediaRouteProviderId::DIAL,
-                             std::move(dial_provider_ptr), base::DoNothing());
+                             std::move(dial_provider_remote),
+                             base::DoNothing());
 }
 
 #if defined(OS_WIN)
diff --git a/chrome/browser/media/router/mojo/media_router_desktop.h b/chrome/browser/media/router/mojo/media_router_desktop.h
index 34327ab..102d4888 100644
--- a/chrome/browser/media/router/mojo/media_router_desktop.h
+++ b/chrome/browser/media/router/mojo/media_router_desktop.h
@@ -12,6 +12,8 @@
 #include "chrome/browser/media/router/providers/cast/dual_media_sink_service.h"
 #include "chrome/browser/media/router/providers/dial/dial_media_route_provider.h"
 #include "chrome/browser/media/router/providers/extension/extension_media_route_provider_proxy.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 
 namespace content {
 class RenderFrameHost;
@@ -45,11 +47,11 @@
   // |extension|: The component extension, used for querying
   //     suspension state.
   // |context|: The BrowserContext which owns the extension process.
-  // |request|: The Mojo connection request used for binding.
-  static void BindToRequest(const extensions::Extension* extension,
-                            content::BrowserContext* context,
-                            mojom::MediaRouterRequest request,
-                            content::RenderFrameHost* source);
+  // |receiver|: The Mojo pending receiver used for binding.
+  static void BindToReceiver(const extensions::Extension* extension,
+                             content::BrowserContext* context,
+                             mojo::PendingReceiver<mojom::MediaRouter> receiver,
+                             content::RenderFrameHost* source);
 
   // MediaRouter implementation.
   void OnUserGesture() override;
@@ -79,7 +81,8 @@
   // mojom::MediaRouter implementation.
   void RegisterMediaRouteProvider(
       MediaRouteProviderId provider_id,
-      mojom::MediaRouteProviderPtr media_route_provider_ptr,
+      mojo::PendingRemote<mojom::MediaRouteProvider>
+          media_route_provider_remote,
       mojom::MediaRouter::RegisterMediaRouteProviderCallback callback) override;
   void OnSinksReceived(MediaRouteProviderId provider_id,
                        const std::string& media_source,
@@ -88,17 +91,17 @@
   void GetMediaSinkServiceStatus(
       mojom::MediaRouter::GetMediaSinkServiceStatusCallback callback) override;
 
-  // Registers a Mojo pointer to the extension MRP with
+  // Registers a Mojo remote to the extension MRP with
   // |extension_provider_proxy_| and does initializations specific to the
   // extension MRP.
   void RegisterExtensionMediaRouteProvider(
-      mojom::MediaRouteProviderPtr extension_provider_ptr);
+      mojo::PendingRemote<mojom::MediaRouteProvider> extension_provider_remote);
 
-  // Binds |this| to a Mojo interface request, so that clients can acquire a
+  // Binds |this| to a Mojo pending receiver, so that clients can acquire a
   // handle to a MediaRouter instance via the Mojo service connector.
   // Passes the extension's ID to the event page request manager.
-  void BindToMojoRequest(mojo::InterfaceRequest<mojom::MediaRouter> request,
-                         const extensions::Extension& extension);
+  void BindToMojoReceiver(mojo::PendingReceiver<mojom::MediaRouter> receiver,
+                          const extensions::Extension& extension);
 
   // Provides the current list of sinks from |media_sink_service_| to the
   // extension. Also registers with |media_sink_service_| to listen for updates.
diff --git a/chrome/browser/media/router/mojo/media_router_desktop_unittest.cc b/chrome/browser/media/router/mojo/media_router_desktop_unittest.cc
index 6e25070..27805e68 100644
--- a/chrome/browser/media/router/mojo/media_router_desktop_unittest.cc
+++ b/chrome/browser/media/router/mojo/media_router_desktop_unittest.cc
@@ -11,6 +11,7 @@
 #include <string>
 #include <utility>
 
+#include "base/macros.h"
 #include "base/run_loop.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
@@ -208,13 +209,13 @@
   // |extension_mrp_proxy|.
   for (int i = 0; i < MediaRouterDesktop::kMaxMediaRouteProviderErrorCount;
        i++) {
-    extension_mrp_proxy->binding_.Unbind();
+    ignore_result(extension_mrp_proxy->receiver_.Unbind());
     base::RunLoop().RunUntilIdle();
-    EXPECT_TRUE(extension_mrp_proxy->binding_.is_bound());
+    EXPECT_TRUE(extension_mrp_proxy->receiver_.is_bound());
   }
-  extension_mrp_proxy->binding_.Unbind();
+  ignore_result(extension_mrp_proxy->receiver_.Unbind());
   base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(extension_mrp_proxy->binding_.is_bound());
+  EXPECT_FALSE(extension_mrp_proxy->receiver_.is_bound());
 }
 
 }  // namespace media_router
diff --git a/chrome/browser/media/router/mojo/media_router_mojo_impl.cc b/chrome/browser/media/router/mojo/media_router_mojo_impl.cc
index 2d738535..2190bf8 100644
--- a/chrome/browser/media/router/mojo/media_router_mojo_impl.cc
+++ b/chrome/browser/media/router/mojo/media_router_mojo_impl.cc
@@ -138,14 +138,16 @@
 
 void MediaRouterMojoImpl::RegisterMediaRouteProvider(
     MediaRouteProviderId provider_id,
-    mojom::MediaRouteProviderPtr media_route_provider_ptr,
+    mojo::PendingRemote<mojom::MediaRouteProvider> media_route_provider_remote,
     mojom::MediaRouter::RegisterMediaRouteProviderCallback callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(!base::Contains(media_route_providers_, provider_id));
-  media_route_provider_ptr.set_connection_error_handler(
+  mojo::Remote<mojom::MediaRouteProvider> bound_remote(
+      std::move(media_route_provider_remote));
+  bound_remote.set_disconnect_handler(
       base::BindOnce(&MediaRouterMojoImpl::OnProviderConnectionError,
                      weak_factory_.GetWeakPtr(), provider_id));
-  media_route_providers_[provider_id] = std::move(media_route_provider_ptr);
+  media_route_providers_[provider_id] = std::move(bound_remote);
   std::move(callback).Run(instance_id_, mojom::MediaRouteProviderConfig::New());
 }
 
@@ -439,7 +441,7 @@
 void MediaRouterMojoImpl::GetMediaController(
     const MediaRoute::Id& route_id,
     mojo::PendingReceiver<mojom::MediaController> controller,
-    mojom::MediaStatusObserverPtr observer) {
+    mojo::PendingRemote<mojom::MediaStatusObserver> observer) {
   auto* route = GetRoute(route_id);
   base::Optional<MediaRouteProviderId> provider_id =
       GetProviderIdForRoute(route_id);
@@ -968,9 +970,9 @@
   }
 }
 
-void MediaRouterMojoImpl::BindToMojoRequest(
-    mojo::InterfaceRequest<mojom::MediaRouter> request) {
-  bindings_.AddBinding(this, std::move(request));
+void MediaRouterMojoImpl::BindToMojoReceiver(
+    mojo::PendingReceiver<mojom::MediaRouter> receiver) {
+  receivers_.Add(this, std::move(receiver));
 }
 
 base::Optional<MediaRouteProviderId> MediaRouterMojoImpl::GetProviderIdForRoute(
diff --git a/chrome/browser/media/router/mojo/media_router_mojo_impl.h b/chrome/browser/media/router/mojo/media_router_mojo_impl.h
index 7c86793b..879507d 100644
--- a/chrome/browser/media/router/mojo/media_router_mojo_impl.h
+++ b/chrome/browser/media/router/mojo/media_router_mojo_impl.h
@@ -27,8 +27,10 @@
 #include "chrome/common/media_router/mojom/media_router.mojom.h"
 #include "chrome/common/media_router/route_request_result.h"
 #include "content/public/browser/browser_thread.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/blink/public/mojom/presentation/presentation.mojom.h"
 
 namespace content {
@@ -81,10 +83,11 @@
   void GetMediaController(
       const MediaRoute::Id& route_id,
       mojo::PendingReceiver<mojom::MediaController> controller,
-      mojom::MediaStatusObserverPtr observer) final;
+      mojo::PendingRemote<mojom::MediaStatusObserver> observer) final;
   void RegisterMediaRouteProvider(
       MediaRouteProviderId provider_id,
-      mojom::MediaRouteProviderPtr media_route_provider_ptr,
+      mojo::PendingRemote<mojom::MediaRouteProvider>
+          media_route_provider_remote,
       mojom::MediaRouter::RegisterMediaRouteProviderCallback callback) override;
 
   // Issues 0+ calls to the provider given by |provider_id| to ensure its state
@@ -111,8 +114,8 @@
   // Removes the pointer from |media_route_providers_|.
   void OnProviderConnectionError(MediaRouteProviderId provider_id);
 
-  // Creates a binding between |this| and |request|.
-  void BindToMojoRequest(mojo::InterfaceRequest<mojom::MediaRouter> request);
+  // Creates a binding between |this| and |receiver|.
+  void BindToMojoReceiver(mojo::PendingReceiver<mojom::MediaRouter> receiver);
 
   // Methods for obtaining a pointer to the provider associated with the given
   // object. They return a nullopt when such a provider is not found.
@@ -129,9 +132,9 @@
                        const std::vector<MediaSinkInternal>& internal_sinks,
                        const std::vector<url::Origin>& origins) override;
 
-  // Mojo pointers to media route providers. Providers are added via
+  // Mojo remotes to media route providers. Providers are added via
   // RegisterMediaRouteProvider().
-  base::flat_map<MediaRouteProviderId, mojom::MediaRouteProviderPtr>
+  base::flat_map<MediaRouteProviderId, mojo::Remote<mojom::MediaRouteProvider>>
       media_route_providers_;
 
  private:
@@ -416,8 +419,8 @@
   // The last reported sink availability from the media route providers.
   ProviderSinkAvailability sink_availability_;
 
-  // Bindings for Mojo pointers to |this| held by media route providers.
-  mojo::BindingSet<mojom::MediaRouter> bindings_;
+  // Receivers for Mojo remotes to |this| held by media route providers.
+  mojo::ReceiverSet<mojom::MediaRouter> receivers_;
 
   content::BrowserContext* const context_;
 
diff --git a/chrome/browser/media/router/mojo/media_router_mojo_impl_unittest.cc b/chrome/browser/media/router/mojo/media_router_mojo_impl_unittest.cc
index cce461a..8aa1278 100644
--- a/chrome/browser/media/router/mojo/media_router_mojo_impl_unittest.cc
+++ b/chrome/browser/media/router/mojo/media_router_mojo_impl_unittest.cc
@@ -981,9 +981,10 @@
 TEST_F(MediaRouterMojoImplTest, GetMediaController) {
   MockMediaController mock_controller;
   mojo::Remote<mojom::MediaController> controller_remote;
-  mojom::MediaStatusObserverPtr observer_ptr;
-  MockMediaStatusObserver mock_observer(mojo::MakeRequest(&observer_ptr));
-  mojom::MediaStatusObserverPtr observer_ptr_held_by_controller;
+  mojo::PendingRemote<mojom::MediaStatusObserver> observer_remote;
+  MockMediaStatusObserver mock_observer(
+      observer_remote.InitWithNewPipeAndPassReceiver());
+  mojo::Remote<mojom::MediaStatusObserver> observer_remote_held_by_controller;
   router()->OnRoutesUpdated(MediaRouteProviderId::EXTENSION,
                             {CreateMediaRoute()}, "", {});
 
@@ -992,22 +993,22 @@
       .WillOnce(
           [&](const std::string& route_id,
               mojo::PendingReceiver<mojom::MediaController>& media_controller,
-              mojom::MediaStatusObserverPtr& observer,
+              mojo::PendingRemote<mojom::MediaStatusObserver>& observer,
               MockMediaRouteProvider::CreateMediaRouteControllerCallback&
                   callback) {
             mock_controller.Bind(std::move(media_controller));
-            observer_ptr_held_by_controller = std::move(observer);
+            observer_remote_held_by_controller.Bind(std::move(observer));
             std::move(callback).Run(true);
           });
   router()->GetMediaController(kRouteId,
                                controller_remote.BindNewPipeAndPassReceiver(),
-                               std::move(observer_ptr));
+                               std::move(observer_remote));
   base::RunLoop().RunUntilIdle();
 
   EXPECT_CALL(mock_controller, Play());
   controller_remote->Play();
   EXPECT_CALL(mock_observer, OnMediaStatusUpdated(_));
-  observer_ptr_held_by_controller->OnMediaStatusUpdated(
+  observer_remote_held_by_controller->OnMediaStatusUpdated(
       mojom::MediaStatus::New());
   base::RunLoop().RunUntilIdle();
 }
diff --git a/chrome/browser/media/router/providers/cast/activity_record.h b/chrome/browser/media/router/providers/cast/activity_record.h
index c067102..4a8f313 100644
--- a/chrome/browser/media/router/providers/cast/activity_record.h
+++ b/chrome/browser/media/router/providers/cast/activity_record.h
@@ -18,6 +18,7 @@
 #include "chrome/common/media_router/mojom/media_router.mojom.h"
 #include "chrome/common/media_router/providers/cast/cast_media_source.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 
 namespace cast_channel {
 class CastMessageHandler;
@@ -143,7 +144,7 @@
 
   virtual void CreateMediaController(
       mojo::PendingReceiver<mojom::MediaController> media_controller,
-      mojom::MediaStatusObserverPtr observer) = 0;
+      mojo::PendingRemote<mojom::MediaStatusObserver> observer) = 0;
 
  protected:
   CastSession* GetSession() const;
diff --git a/chrome/browser/media/router/providers/cast/cast_activity_manager.cc b/chrome/browser/media/router/providers/cast/cast_activity_manager.cc
index d275112..6e6e001 100644
--- a/chrome/browser/media/router/providers/cast/cast_activity_manager.cc
+++ b/chrome/browser/media/router/providers/cast/cast_activity_manager.cc
@@ -391,7 +391,7 @@
 bool CastActivityManager::CreateMediaController(
     const std::string& route_id,
     mojo::PendingReceiver<mojom::MediaController> media_controller,
-    mojom::MediaStatusObserverPtr observer) {
+    mojo::PendingRemote<mojom::MediaStatusObserver> observer) {
   auto activity_it = activities_.find(route_id);
   if (activity_it == activities_.end())
     return false;
diff --git a/chrome/browser/media/router/providers/cast/cast_activity_manager.h b/chrome/browser/media/router/providers/cast/cast_activity_manager.h
index c934e2f..dda3a5d 100644
--- a/chrome/browser/media/router/providers/cast/cast_activity_manager.h
+++ b/chrome/browser/media/router/providers/cast/cast_activity_manager.h
@@ -22,6 +22,7 @@
 #include "chrome/common/media_router/mojom/media_router.mojom.h"
 #include "chrome/common/media_router/providers/cast/cast_media_source.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "url/origin.h"
 
 namespace cast_channel {
@@ -109,7 +110,7 @@
   bool CreateMediaController(
       const std::string& route_id,
       mojo::PendingReceiver<mojom::MediaController> media_controller,
-      mojom::MediaStatusObserverPtr observer);
+      mojo::PendingRemote<mojom::MediaStatusObserver> observer);
 
   const MediaRoute* GetRoute(const MediaRoute::Id& route_id) const;
   std::vector<MediaRoute> GetRoutes() const;
diff --git a/chrome/browser/media/router/providers/cast/cast_activity_manager_unittest.cc b/chrome/browser/media/router/providers/cast/cast_activity_manager_unittest.cc
index c5a36999..9d2847a0 100644
--- a/chrome/browser/media/router/providers/cast/cast_activity_manager_unittest.cc
+++ b/chrome/browser/media/router/providers/cast/cast_activity_manager_unittest.cc
@@ -29,6 +29,8 @@
 #include "components/cast_channel/cast_test_util.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/test/browser_task_environment.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/data_decoder/data_decoder_service.h"
 #include "services/data_decoder/public/cpp/testing_json_parser.h"
 #include "services/data_decoder/public/mojom/constants.mojom.h"
@@ -104,15 +106,15 @@
   void SetUp() override {
     CastActivityManager::SetActitivyRecordFactoryForTest(this);
 
-    router_binding_ = std::make_unique<mojo::Binding<mojom::MediaRouter>>(
-        &mock_router_, mojo::MakeRequest(&router_ptr_));
+    router_receiver_ = std::make_unique<mojo::Receiver<mojom::MediaRouter>>(
+        &mock_router_, router_remote_.BindNewPipeAndPassReceiver());
 
     session_tracker_.reset(
         new CastSessionTracker(&media_sink_service_, &message_handler_,
                                socket_service_.task_runner()));
     manager_ = std::make_unique<CastActivityManager>(
         &media_sink_service_, session_tracker_.get(), &message_handler_,
-        router_ptr_.get(),
+        router_remote_.get(),
         std::make_unique<DataDecoder>(connector_factory_.GetDefaultConnector()),
         "theHashToken");
 
@@ -306,8 +308,8 @@
   data_decoder::TestingJsonParser::ScopedFactoryOverride parser_override_;
   service_manager::TestConnectorFactory connector_factory_;
   MockMojoMediaRouter mock_router_;
-  mojom::MediaRouterPtr router_ptr_;
-  std::unique_ptr<mojo::Binding<mojom::MediaRouter>> router_binding_;
+  mojo::Remote<mojom::MediaRouter> router_remote_;
+  std::unique_ptr<mojo::Receiver<mojom::MediaRouter>> router_receiver_;
   cast_channel::MockCastSocketService socket_service_;
   cast_channel::MockCastSocket socket_;
   cast_channel::MockCastMessageHandler message_handler_;
diff --git a/chrome/browser/media/router/providers/cast/cast_activity_record.cc b/chrome/browser/media/router/providers/cast/cast_activity_record.cc
index da34f9f..65e9a8f 100644
--- a/chrome/browser/media/router/providers/cast/cast_activity_record.cc
+++ b/chrome/browser/media/router/providers/cast/cast_activity_record.cc
@@ -206,7 +206,7 @@
 
 void CastActivityRecord::CreateMediaController(
     mojo::PendingReceiver<mojom::MediaController> media_controller,
-    mojom::MediaStatusObserverPtr observer) {
+    mojo::PendingRemote<mojom::MediaStatusObserver> observer) {
   media_controller_ = std::make_unique<CastMediaController>(
       this, std::move(media_controller), std::move(observer));
 
diff --git a/chrome/browser/media/router/providers/cast/cast_activity_record.h b/chrome/browser/media/router/providers/cast/cast_activity_record.h
index 0d62577..24f2231f 100644
--- a/chrome/browser/media/router/providers/cast/cast_activity_record.h
+++ b/chrome/browser/media/router/providers/cast/cast_activity_record.h
@@ -16,6 +16,7 @@
 #include "chrome/common/media_router/providers/cast/cast_media_source.h"
 #include "components/cast_channel/cast_message_handler.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 
 namespace url {
 class Origin;
@@ -85,7 +86,7 @@
   void OnInternalMessage(const cast_channel::InternalMessage& message) override;
   void CreateMediaController(
       mojo::PendingReceiver<mojom::MediaController> media_controller,
-      mojom::MediaStatusObserverPtr observer) override;
+      mojo::PendingRemote<mojom::MediaStatusObserver> observer) override;
 
   static void SetClientFactoryForTest(
       CastSessionClientFactoryForTest* factory) {
diff --git a/chrome/browser/media/router/providers/cast/cast_media_controller.cc b/chrome/browser/media/router/providers/cast/cast_media_controller.cc
index d9f26df5..f81a47f 100644
--- a/chrome/browser/media/router/providers/cast/cast_media_controller.cc
+++ b/chrome/browser/media/router/providers/cast/cast_media_controller.cc
@@ -62,7 +62,7 @@
 CastMediaController::CastMediaController(
     ActivityRecord* activity,
     mojo::PendingReceiver<mojom::MediaController> receiver,
-    mojom::MediaStatusObserverPtr observer)
+    mojo::PendingRemote<mojom::MediaStatusObserver> observer)
     : sender_id_("sender-" + base::NumberToString(base::RandUint64())),
       activity_(activity),
       receiver_(this, std::move(receiver)),
diff --git a/chrome/browser/media/router/providers/cast/cast_media_controller.h b/chrome/browser/media/router/providers/cast/cast_media_controller.h
index 54fb0ea..cd8ca7e 100644
--- a/chrome/browser/media/router/providers/cast/cast_media_controller.h
+++ b/chrome/browser/media/router/providers/cast/cast_media_controller.h
@@ -10,7 +10,9 @@
 #include "chrome/common/media_router/mojom/media_status.mojom.h"
 #include "components/cast_channel/cast_message_util.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 
 namespace base {
 class Value;
@@ -49,7 +51,7 @@
  public:
   CastMediaController(ActivityRecord* activity,
                       mojo::PendingReceiver<mojom::MediaController> receiver,
-                      mojom::MediaStatusObserverPtr observer);
+                      mojo::PendingRemote<mojom::MediaStatusObserver> observer);
   ~CastMediaController() override;
 
   // mojom::MediaController overrides:
@@ -81,7 +83,7 @@
   int media_session_id_;
 
   mojo::Receiver<mojom::MediaController> receiver_;
-  mojom::MediaStatusObserverPtr observer_;
+  mojo::Remote<mojom::MediaStatusObserver> observer_;
 
   DISALLOW_COPY_AND_ASSIGN(CastMediaController);
 };
diff --git a/chrome/browser/media/router/providers/cast/cast_media_controller_unittest.cc b/chrome/browser/media/router/providers/cast/cast_media_controller_unittest.cc
index 9899e26..7162425 100644
--- a/chrome/browser/media/router/providers/cast/cast_media_controller_unittest.cc
+++ b/chrome/browser/media/router/providers/cast/cast_media_controller_unittest.cc
@@ -127,9 +127,9 @@
   void SetUp() override {
     testing::Test::SetUp();
 
-    mojom::MediaStatusObserverPtr mojo_status_observer;
+    mojo::PendingRemote<mojom::MediaStatusObserver> mojo_status_observer;
     status_observer_ = std::make_unique<MockMediaStatusObserver>(
-        mojo::MakeRequest(&mojo_status_observer));
+        mojo_status_observer.InitWithNewPipeAndPassReceiver());
     controller_ = std::make_unique<CastMediaController>(
         &activity_, mojo_controller_.BindNewPipeAndPassReceiver(),
         std::move(mojo_status_observer));
diff --git a/chrome/browser/media/router/providers/cast/cast_media_route_provider.cc b/chrome/browser/media/router/providers/cast/cast_media_route_provider.cc
index 4457902..57b05907 100644
--- a/chrome/browser/media/router/providers/cast/cast_media_route_provider.cc
+++ b/chrome/browser/media/router/providers/cast/cast_media_route_provider.cc
@@ -38,16 +38,15 @@
 }  // namespace
 
 CastMediaRouteProvider::CastMediaRouteProvider(
-    mojom::MediaRouteProviderRequest request,
-    mojom::MediaRouterPtrInfo media_router,
+    mojo::PendingReceiver<mojom::MediaRouteProvider> receiver,
+    mojo::PendingRemote<mojom::MediaRouter> media_router,
     MediaSinkServiceBase* media_sink_service,
     CastAppDiscoveryService* app_discovery_service,
     cast_channel::CastMessageHandler* message_handler,
     service_manager::Connector* connector,
     const std::string& hash_token,
     const scoped_refptr<base::SequencedTaskRunner>& task_runner)
-    : binding_(this),
-      media_sink_service_(media_sink_service),
+    : media_sink_service_(media_sink_service),
       app_discovery_service_(app_discovery_service),
       message_handler_(message_handler) {
   DETACH_FROM_SEQUENCE(sequence_checker_);
@@ -58,19 +57,20 @@
   task_runner->PostTask(
       FROM_HERE,
       base::BindOnce(&CastMediaRouteProvider::Init, base::Unretained(this),
-                     std::move(request), std::move(media_router),
+                     std::move(receiver), std::move(media_router),
                      CastSessionTracker::GetInstance(),
                      std::make_unique<DataDecoder>(connector), hash_token));
 }
 
-void CastMediaRouteProvider::Init(mojom::MediaRouteProviderRequest request,
-                                  mojom::MediaRouterPtrInfo media_router,
-                                  CastSessionTracker* session_tracker,
-                                  std::unique_ptr<DataDecoder> data_decoder,
-                                  const std::string& hash_token) {
+void CastMediaRouteProvider::Init(
+    mojo::PendingReceiver<mojom::MediaRouteProvider> receiver,
+    mojo::PendingRemote<mojom::MediaRouter> media_router,
+    CastSessionTracker* session_tracker,
+    std::unique_ptr<DataDecoder> data_decoder,
+    const std::string& hash_token) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  binding_.Bind(std::move(request));
+  receiver_.Bind(std::move(receiver));
   media_router_.Bind(std::move(media_router));
 
   activity_manager_ = std::make_unique<CastActivityManager>(
@@ -262,7 +262,7 @@
 void CastMediaRouteProvider::CreateMediaRouteController(
     const std::string& route_id,
     mojo::PendingReceiver<mojom::MediaController> media_controller,
-    mojom::MediaStatusObserverPtr observer,
+    mojo::PendingRemote<mojom::MediaStatusObserver> observer,
     CreateMediaRouteControllerCallback callback) {
   std::move(callback).Run(activity_manager_->CreateMediaController(
       route_id, std::move(media_controller), std::move(observer)));
diff --git a/chrome/browser/media/router/providers/cast/cast_media_route_provider.h b/chrome/browser/media/router/providers/cast/cast_media_route_provider.h
index 9846544..584a9fe 100644
--- a/chrome/browser/media/router/providers/cast/cast_media_route_provider.h
+++ b/chrome/browser/media/router/providers/cast/cast_media_route_provider.h
@@ -14,8 +14,10 @@
 #include "chrome/browser/media/router/providers/cast/cast_app_discovery_service.h"
 #include "chrome/browser/media/router/providers/cast/dual_media_sink_service.h"
 #include "chrome/common/media_router/mojom/media_router.mojom.h"
-#include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 
 namespace cast_channel {
 class CastMessageHandler;
@@ -41,8 +43,8 @@
 class CastMediaRouteProvider : public mojom::MediaRouteProvider {
  public:
   CastMediaRouteProvider(
-      mojom::MediaRouteProviderRequest request,
-      mojom::MediaRouterPtrInfo media_router,
+      mojo::PendingReceiver<mojom::MediaRouteProvider> receiver,
+      mojo::PendingRemote<mojom::MediaRouter> media_router,
       MediaSinkServiceBase* media_sink_service,
       CastAppDiscoveryService* app_discovery_service,
       cast_channel::CastMessageHandler* message_handler,
@@ -100,12 +102,12 @@
   void CreateMediaRouteController(
       const std::string& route_id,
       mojo::PendingReceiver<mojom::MediaController> media_controller,
-      mojom::MediaStatusObserverPtr observer,
+      mojo::PendingRemote<mojom::MediaStatusObserver> observer,
       CreateMediaRouteControllerCallback callback) override;
 
  private:
-  void Init(mojom::MediaRouteProviderRequest request,
-            mojom::MediaRouterPtrInfo media_router,
+  void Init(mojo::PendingReceiver<mojom::MediaRouteProvider> receiver,
+            mojo::PendingRemote<mojom::MediaRouter> media_router,
             CastSessionTracker* session_tracker,
             std::unique_ptr<DataDecoder> data_decoder,
             const std::string& hash_token);
@@ -118,11 +120,11 @@
   void BroadcastMessageToSinks(const std::vector<std::string>& app_ids,
                                const cast_channel::BroadcastRequest& request);
 
-  // Binds |this| to the Mojo request passed into the ctor.
-  mojo::Binding<mojom::MediaRouteProvider> binding_;
+  // Binds |this| to the Mojo receiver passed into the ctor.
+  mojo::Receiver<mojom::MediaRouteProvider> receiver_{this};
 
-  // Mojo pointer to the Media Router.
-  mojom::MediaRouterPtr media_router_;
+  // Mojo remote to the Media Router.
+  mojo::Remote<mojom::MediaRouter> media_router_;
 
   // Non-owned pointer to the Cast MediaSinkServiceBase instance.
   MediaSinkServiceBase* const media_sink_service_;
diff --git a/chrome/browser/media/router/providers/cast/cast_media_route_provider_unittest.cc b/chrome/browser/media/router/providers/cast/cast_media_route_provider_unittest.cc
index 8ba39cb2..36eef233 100644
--- a/chrome/browser/media/router/providers/cast/cast_media_route_provider_unittest.cc
+++ b/chrome/browser/media/router/providers/cast/cast_media_route_provider_unittest.cc
@@ -15,6 +15,9 @@
 #include "components/cast_channel/cast_test_util.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/test/browser_task_environment.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/data_decoder/data_decoder_service.h"
 #include "services/data_decoder/public/mojom/constants.mojom.h"
 #include "services/service_manager/public/cpp/connector.h"
@@ -46,9 +49,9 @@
   ~CastMediaRouteProviderTest() override = default;
 
   void SetUp() override {
-    mojom::MediaRouterPtr router_ptr;
-    router_binding_ = std::make_unique<mojo::Binding<mojom::MediaRouter>>(
-        &mock_router_, mojo::MakeRequest(&router_ptr));
+    mojo::PendingRemote<mojom::MediaRouter> router_remote;
+    router_receiver_ = std::make_unique<mojo::Receiver<mojom::MediaRouter>>(
+        &mock_router_, router_remote.InitWithNewPipeAndPassReceiver());
 
     session_tracker_ = std::unique_ptr<CastSessionTracker>(
         new CastSessionTracker(&media_sink_service_, &message_handler_,
@@ -57,7 +60,7 @@
 
     EXPECT_CALL(mock_router_, OnSinkAvailabilityUpdated(_, _));
     provider_ = std::make_unique<CastMediaRouteProvider>(
-        mojo::MakeRequest(&provider_ptr_), router_ptr.PassInterface(),
+        provider_remote_.BindNewPipeAndPassReceiver(), std::move(router_remote),
         &media_sink_service_, &app_discovery_service_, &message_handler_,
         connector_factory_.GetDefaultConnector(), "hash-token",
         base::SequencedTaskRunnerHandle::Get());
@@ -106,9 +109,9 @@
   service_manager::TestConnectorFactory connector_factory_;
   data_decoder::DataDecoderService data_decoder_service_;
 
-  mojom::MediaRouteProviderPtr provider_ptr_;
+  mojo::Remote<mojom::MediaRouteProvider> provider_remote_;
   MockMojoMediaRouter mock_router_;
-  std::unique_ptr<mojo::Binding<mojom::MediaRouter>> router_binding_;
+  std::unique_ptr<mojo::Receiver<mojom::MediaRouter>> router_receiver_;
 
   cast_channel::MockCastSocketService socket_service_;
   cast_channel::MockCastMessageHandler message_handler_;
diff --git a/chrome/browser/media/router/providers/cast/mirroring_activity_record.cc b/chrome/browser/media/router/providers/cast/mirroring_activity_record.cc
index 93c2e4c..88b2774 100644
--- a/chrome/browser/media/router/providers/cast/mirroring_activity_record.cc
+++ b/chrome/browser/media/router/providers/cast/mirroring_activity_record.cc
@@ -253,7 +253,7 @@
 
 void MirroringActivityRecord::CreateMediaController(
     mojo::PendingReceiver<mojom::MediaController> media_controller,
-    mojom::MediaStatusObserverPtr observer) {}
+    mojo::PendingRemote<mojom::MediaStatusObserver> observer) {}
 
 void MirroringActivityRecord::StopMirroring() {
   // Running the callback will cause this object to be deleted.
diff --git a/chrome/browser/media/router/providers/cast/mirroring_activity_record.h b/chrome/browser/media/router/providers/cast/mirroring_activity_record.h
index 9c834c1d6..10559b1b 100644
--- a/chrome/browser/media/router/providers/cast/mirroring_activity_record.h
+++ b/chrome/browser/media/router/providers/cast/mirroring_activity_record.h
@@ -18,6 +18,7 @@
 #include "components/mirroring/mojom/mirroring_service_host.mojom.h"
 #include "components/mirroring/mojom/session_observer.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
 
@@ -81,7 +82,7 @@
  protected:
   void CreateMediaController(
       mojo::PendingReceiver<mojom::MediaController> media_controller,
-      mojom::MediaStatusObserverPtr observer) override;
+      mojo::PendingRemote<mojom::MediaStatusObserver> observer) override;
 
  private:
   enum class MirroringType {
diff --git a/chrome/browser/media/router/providers/cast/mock_activity_record.h b/chrome/browser/media/router/providers/cast/mock_activity_record.h
index b2aab5b..7379a16 100644
--- a/chrome/browser/media/router/providers/cast/mock_activity_record.h
+++ b/chrome/browser/media/router/providers/cast/mock_activity_record.h
@@ -11,6 +11,7 @@
 #include "chrome/browser/media/router/providers/cast/cast_internal_message_util.h"
 #include "chrome/browser/media/router/providers/cast/cast_session_client.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace media_router {
@@ -69,7 +70,7 @@
   MOCK_METHOD2(
       CreateMediaController,
       void(mojo::PendingReceiver<mojom::MediaController> media_controller,
-           mojom::MediaStatusObserverPtr observer));
+           mojo::PendingRemote<mojom::MediaStatusObserver> observer));
 };
 
 }  // namespace media_router
diff --git a/chrome/browser/media/router/providers/dial/dial_media_route_provider.cc b/chrome/browser/media/router/providers/dial/dial_media_route_provider.cc
index 93347db..ca46f69 100644
--- a/chrome/browser/media/router/providers/dial/dial_media_route_provider.cc
+++ b/chrome/browser/media/router/providers/dial/dial_media_route_provider.cc
@@ -37,14 +37,13 @@
 }  // namespace
 
 DialMediaRouteProvider::DialMediaRouteProvider(
-    mojom::MediaRouteProviderRequest request,
-    mojom::MediaRouterPtrInfo media_router,
+    mojo::PendingReceiver<mojom::MediaRouteProvider> receiver,
+    mojo::PendingRemote<mojom::MediaRouter> media_router,
     DialMediaSinkServiceImpl* media_sink_service,
     service_manager::Connector* connector,
     const std::string& hash_token,
     const scoped_refptr<base::SequencedTaskRunner>& task_runner)
-    : binding_(this),
-      media_sink_service_(media_sink_service),
+    : media_sink_service_(media_sink_service),
       data_decoder_(std::make_unique<DataDecoder>(connector)),
       internal_message_util_(hash_token) {
   DETACH_FROM_SEQUENCE(sequence_checker_);
@@ -53,14 +52,15 @@
   task_runner->PostTask(
       FROM_HERE,
       base::BindOnce(&DialMediaRouteProvider::Init, base::Unretained(this),
-                     std::move(request), std::move(media_router)));
+                     std::move(receiver), std::move(media_router)));
 }
 
-void DialMediaRouteProvider::Init(mojom::MediaRouteProviderRequest request,
-                                  mojom::MediaRouterPtrInfo media_router) {
+void DialMediaRouteProvider::Init(
+    mojo::PendingReceiver<mojom::MediaRouteProvider> receiver,
+    mojo::PendingRemote<mojom::MediaRouter> media_router) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  binding_.Bind(std::move(request));
+  receiver_.Bind(std::move(receiver));
   media_router_.Bind(std::move(media_router));
   media_sink_service_->AddObserver(this);
 
@@ -511,7 +511,7 @@
 void DialMediaRouteProvider::CreateMediaRouteController(
     const std::string& route_id,
     mojo::PendingReceiver<mojom::MediaController> media_controller,
-    mojom::MediaStatusObserverPtr observer,
+    mojo::PendingRemote<mojom::MediaStatusObserver> observer,
     CreateMediaRouteControllerCallback callback) {
   NOTIMPLEMENTED();
   std::move(callback).Run(false);
diff --git a/chrome/browser/media/router/providers/dial/dial_media_route_provider.h b/chrome/browser/media/router/providers/dial/dial_media_route_provider.h
index a3c3365..14a8ff6 100644
--- a/chrome/browser/media/router/providers/dial/dial_media_route_provider.h
+++ b/chrome/browser/media/router/providers/dial/dial_media_route_provider.h
@@ -20,8 +20,10 @@
 #include "chrome/browser/media/router/providers/dial/dial_activity_manager.h"
 #include "chrome/browser/media/router/providers/dial/dial_internal_message_util.h"
 #include "chrome/common/media_router/mojom/media_router.mojom.h"
-#include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 
 namespace url {
 class Origin;
@@ -49,15 +51,15 @@
 class DialMediaRouteProvider : public mojom::MediaRouteProvider,
                                public MediaSinkServiceBase::Observer {
  public:
-  // |request|: Request to bind to |this|.
-  // |media_router|: Pointer to MediaRouter.
+  // |receiver|: Mojo receiver to bind to |this|.
+  // |media_router|: Pending remote to MediaRouter.
   // |media_sink_service|: DIAL MediaSinkService providing information on sinks.
   // |connector|: Connector object for accessing data_decoder services.
   // |hash_token|: A per-profile value used to hash sink IDs.
   // |task_runner|: The task runner on which |this| runs.
   DialMediaRouteProvider(
-      mojom::MediaRouteProviderRequest request,
-      mojom::MediaRouterPtrInfo media_router,
+      mojo::PendingReceiver<mojom::MediaRouteProvider> receiver,
+      mojo::PendingRemote<mojom::MediaRouter> media_router,
       DialMediaSinkServiceImpl* media_sink_service,
       service_manager::Connector* connector,
       const std::string& hash_token,
@@ -113,7 +115,7 @@
   void CreateMediaRouteController(
       const std::string& route_id,
       mojo::PendingReceiver<mojom::MediaController> media_controller,
-      mojom::MediaStatusObserverPtr observer,
+      mojo::PendingRemote<mojom::MediaStatusObserver> observer,
       CreateMediaRouteControllerCallback callback) override;
 
   void SetActivityManagerForTest(
@@ -143,9 +145,9 @@
   // MediaSinkServiceBase::Observer:
   void OnSinksDiscovered(const std::vector<MediaSinkInternal>& sinks) override;
 
-  // Binds the message pipes |request| and |media_router| to |this|.
-  void Init(mojom::MediaRouteProviderRequest request,
-            mojom::MediaRouterPtrInfo media_router);
+  // Binds the message pipes |receiver| and |media_router| to |this|.
+  void Init(mojo::PendingReceiver<mojom::MediaRouteProvider> receiver,
+            mojo::PendingRemote<mojom::MediaRouter> media_router);
 
   void OnAvailableSinksUpdated(const std::string& app_name);
 
@@ -179,11 +181,11 @@
   // all origins are valid.
   std::vector<url::Origin> GetOrigins(const std::string& app_name);
 
-  // Binds |this| to the Mojo request passed into the ctor.
-  mojo::Binding<mojom::MediaRouteProvider> binding_;
+  // Binds |this| to the Mojo receiver passed into the ctor.
+  mojo::Receiver<mojom::MediaRouteProvider> receiver_{this};
 
-  // Mojo pointer to the Media Router.
-  mojom::MediaRouterPtr media_router_;
+  // Mojo remote to the Media Router.
+  mojo::Remote<mojom::MediaRouter> media_router_;
 
   // Non-owned pointer to the DialMediaSinkServiceImpl instance.
   DialMediaSinkServiceImpl* const media_sink_service_;
diff --git a/chrome/browser/media/router/providers/dial/dial_media_route_provider_unittest.cc b/chrome/browser/media/router/providers/dial/dial_media_route_provider_unittest.cc
index b245a4f..7420f87 100644
--- a/chrome/browser/media/router/providers/dial/dial_media_route_provider_unittest.cc
+++ b/chrome/browser/media/router/providers/dial/dial_media_route_provider_unittest.cc
@@ -15,6 +15,9 @@
 #include "chrome/browser/media/router/route_message_util.h"
 #include "chrome/browser/media/router/test/test_helper.h"
 #include "content/public/test/browser_task_environment.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "net/http/http_status_code.h"
 #include "services/data_decoder/data_decoder_service.h"
 #include "services/data_decoder/public/cpp/testing_json_parser.h"
@@ -93,13 +96,13 @@
         mock_sink_service_(connector_factory_.GetDefaultConnector()) {}
 
   void SetUp() override {
-    mojom::MediaRouterPtr router_ptr;
-    router_binding_ = std::make_unique<mojo::Binding<mojom::MediaRouter>>(
-        &mock_router_, mojo::MakeRequest(&router_ptr));
+    mojo::PendingRemote<mojom::MediaRouter> router_remote;
+    router_receiver_ = std::make_unique<mojo::Receiver<mojom::MediaRouter>>(
+        &mock_router_, router_remote.InitWithNewPipeAndPassReceiver());
 
     EXPECT_CALL(mock_router_, OnSinkAvailabilityUpdated(_, _));
     provider_ = std::make_unique<DialMediaRouteProvider>(
-        mojo::MakeRequest(&provider_ptr_), router_ptr.PassInterface(),
+        provider_remote_.BindNewPipeAndPassReceiver(), std::move(router_remote),
         &mock_sink_service_, connector_factory_.GetDefaultConnector(),
         "hash-token", base::SequencedTaskRunnerHandle::Get());
 
@@ -382,9 +385,9 @@
 
   network::TestURLLoaderFactory loader_factory_;
 
-  mojom::MediaRouteProviderPtr provider_ptr_;
+  mojo::Remote<mojom::MediaRouteProvider> provider_remote_;
   MockMojoMediaRouter mock_router_;
-  std::unique_ptr<mojo::Binding<mojom::MediaRouter>> router_binding_;
+  std::unique_ptr<mojo::Receiver<mojom::MediaRouter>> router_receiver_;
 
   data_decoder::TestingJsonParser::ScopedFactoryOverride parser_override_;
 
diff --git a/chrome/browser/media/router/providers/extension/extension_media_route_provider_proxy.cc b/chrome/browser/media/router/providers/extension/extension_media_route_provider_proxy.cc
index 86a66866..cb792a9 100644
--- a/chrome/browser/media/router/providers/extension/extension_media_route_provider_proxy.cc
+++ b/chrome/browser/media/router/providers/extension/extension_media_route_provider_proxy.cc
@@ -17,18 +17,17 @@
 
 ExtensionMediaRouteProviderProxy::ExtensionMediaRouteProviderProxy(
     content::BrowserContext* context)
-    : binding_(this),
-      request_manager_(
+    : request_manager_(
           EventPageRequestManagerFactory::GetApiForBrowserContext(context)) {}
 
 ExtensionMediaRouteProviderProxy::~ExtensionMediaRouteProviderProxy() = default;
 
 void ExtensionMediaRouteProviderProxy::Bind(
-    mojom::MediaRouteProviderRequest request) {
-  // This method is called when the previous Binding became invalid. We close it
-  // first to make sure it is in a clean state.
-  binding_.Close();
-  binding_.Bind(std::move(request));
+    mojo::PendingReceiver<mojom::MediaRouteProvider> receiver) {
+  // This method is called when the previous receiver became invalid. We close
+  // it first to make sure it is in a clean state.
+  receiver_.reset();
+  receiver_.Bind(std::move(receiver));
 }
 
 void ExtensionMediaRouteProviderProxy::CreateRoute(
@@ -212,7 +211,7 @@
 void ExtensionMediaRouteProviderProxy::CreateMediaRouteController(
     const std::string& route_id,
     mojo::PendingReceiver<mojom::MediaController> media_controller,
-    mojom::MediaStatusObserverPtr observer,
+    mojo::PendingRemote<mojom::MediaStatusObserver> observer,
     CreateMediaRouteControllerCallback callback) {
   request_manager_->RunOrDefer(
       base::BindOnce(
@@ -223,9 +222,10 @@
 }
 
 void ExtensionMediaRouteProviderProxy::RegisterMediaRouteProvider(
-    mojom::MediaRouteProviderPtr media_route_provider) {
-  media_route_provider_ = std::move(media_route_provider);
-  media_route_provider_.set_connection_error_handler(
+    mojo::PendingRemote<mojom::MediaRouteProvider> media_route_provider) {
+  media_route_provider_.reset();
+  media_route_provider_.Bind(std::move(media_route_provider));
+  media_route_provider_.set_disconnect_handler(
       base::BindOnce(&ExtensionMediaRouteProviderProxy::OnMojoConnectionError,
                      base::Unretained(this)));
   request_manager_->OnMojoConnectionsReady();
@@ -383,10 +383,10 @@
 void ExtensionMediaRouteProviderProxy::DoCreateMediaRouteController(
     const std::string& route_id,
     mojo::PendingReceiver<mojom::MediaController> media_controller,
-    mojom::MediaStatusObserverPtr observer,
+    mojo::PendingRemote<mojom::MediaStatusObserver> observer,
     CreateMediaRouteControllerCallback callback) {
   DVLOG(1) << "DoCreateMediaRouteController";
-  if (!media_controller.is_valid() || !observer.is_bound())
+  if (!media_controller.is_valid() || !observer.is_valid())
     return;
 
   media_route_provider_->CreateMediaRouteController(
diff --git a/chrome/browser/media/router/providers/extension/extension_media_route_provider_proxy.h b/chrome/browser/media/router/providers/extension/extension_media_route_provider_proxy.h
index 6226ad4e..1a6e75e 100644
--- a/chrome/browser/media/router/providers/extension/extension_media_route_provider_proxy.h
+++ b/chrome/browser/media/router/providers/extension/extension_media_route_provider_proxy.h
@@ -7,8 +7,10 @@
 
 #include "base/memory/weak_ptr.h"
 #include "chrome/common/media_router/mojom/media_router.mojom.h"
-#include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 
 namespace content {
 class BrowserContext;
@@ -25,9 +27,9 @@
 // the request passed into the ctor.
 //
 // Calls from this object to the component extension MRP are queued with
-// EventPageRequestManager. When the extension is awake, the Mojo pointer to the
+// EventPageRequestManager. When the extension is awake, the Mojo remote to the
 // MRP is valid, so the request is executed immediately. Otherwise, when the
-// extension is awakened, this object obtains a valid Mojo pointer to the MRP
+// extension is awakened, this object obtains a valid Mojo remote to the MRP
 // from MediaRouter, and MediaRouter makes EventPageRequestManager execute all
 // the requests.
 class ExtensionMediaRouteProviderProxy : public mojom::MediaRouteProvider {
@@ -35,9 +37,9 @@
   explicit ExtensionMediaRouteProviderProxy(content::BrowserContext* context);
   ~ExtensionMediaRouteProviderProxy() override;
 
-  // Binds |request| to |this|. If |this| is already bound to a previous
-  // request, that previous request will be dropped.
-  void Bind(mojom::MediaRouteProviderRequest request);
+  // Binds |receiver| to |this|. If |this| is already bound to a previous
+  // receiver, that previous receiver will be reset first.
+  void Bind(mojo::PendingReceiver<mojom::MediaRouteProvider> receiver);
 
   // mojom::MediaRouteProvider implementation. Forwards the calls to
   // |media_route_provider_| through |request_manager_|.
@@ -89,13 +91,13 @@
   void CreateMediaRouteController(
       const std::string& route_id,
       mojo::PendingReceiver<mojom::MediaController> media_controller,
-      mojom::MediaStatusObserverPtr observer,
+      mojo::PendingRemote<mojom::MediaStatusObserver> observer,
       CreateMediaRouteControllerCallback callback) override;
 
   // Sets the MediaRouteProvider to forward calls to. Notifies
   // |request_manager_| that Mojo connections are ready.
   void RegisterMediaRouteProvider(
-      mojom::MediaRouteProviderPtr media_route_provider);
+      mojo::PendingRemote<mojom::MediaRouteProvider> media_route_provider);
 
   // Called when a Mojo connection to the component extension is invalidated.
   void OnMojoConnectionError();
@@ -158,17 +160,17 @@
   void DoCreateMediaRouteController(
       const std::string& route_id,
       mojo::PendingReceiver<mojom::MediaController> media_controller,
-      mojom::MediaStatusObserverPtr observer,
+      mojo::PendingRemote<mojom::MediaStatusObserver> observer,
       CreateMediaRouteControllerCallback callback);
 
-  // Mojo pointer to the MediaRouteProvider in the component extension.
-  // Set to null initially, and later set to the Mojo pointer passed in via
-  // RegisterMediaRouteProvider(). This is set to null again when the component
+  // Mojo remote to the MediaRouteProvider in the component extension.
+  // Set to NullRemote initially, and later set to the Mojo remote passed in via
+  // RegisterMediaRouteProvider(). This is set to NullRemote again when
   // extension is suspended or a Mojo channel error occurs.
-  mojom::MediaRouteProviderPtr media_route_provider_;
+  mojo::Remote<mojom::MediaRouteProvider> media_route_provider_;
 
-  // Binds |this| to the Mojo request passed into the ctor.
-  mojo::Binding<mojom::MediaRouteProvider> binding_;
+  // Binds |this| to the Mojo receiver passed into the ctor.
+  mojo::Receiver<mojom::MediaRouteProvider> receiver_{this};
 
   // Request manager responsible for waking the component extension and calling
   // the requests to it.
diff --git a/chrome/browser/media/router/providers/extension/extension_media_route_provider_proxy_unittest.cc b/chrome/browser/media/router/providers/extension/extension_media_route_provider_proxy_unittest.cc
index 68f1adf..2edfb157 100644
--- a/chrome/browser/media/router/providers/extension/extension_media_route_provider_proxy_unittest.cc
+++ b/chrome/browser/media/router/providers/extension/extension_media_route_provider_proxy_unittest.cc
@@ -15,6 +15,9 @@
 #include "chrome/browser/media/router/test/media_router_mojo_test.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/browser_task_environment.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -69,7 +72,7 @@
 
     provider_proxy_ =
         std::make_unique<ExtensionMediaRouteProviderProxy>(&profile_);
-    provider_proxy_->Bind(mojo::MakeRequest(&provider_proxy_ptr_));
+    provider_proxy_->Bind(provider_proxy_remote_.BindNewPipeAndPassReceiver());
     RegisterMockMediaRouteProvider();
   }
 
@@ -81,19 +84,20 @@
                                        false,
                                        false);
   std::unique_ptr<ExtensionMediaRouteProviderProxy> provider_proxy_;
-  mojom::MediaRouteProviderPtr provider_proxy_ptr_;
+  mojo::Remote<mojom::MediaRouteProvider> provider_proxy_remote_;
   StrictMock<MockMediaRouteProvider> mock_provider_;
   MockEventPageRequestManager* request_manager_ = nullptr;
-  std::unique_ptr<mojo::Binding<mojom::MediaRouteProvider>> binding_;
+  std::unique_ptr<mojo::Receiver<mojom::MediaRouteProvider>> receiver_;
 
  private:
   void RegisterMockMediaRouteProvider() {
     mock_provider_.SetRouteToReturn(route_);
 
-    mojom::MediaRouteProviderPtr mock_provider_ptr;
-    binding_ = std::make_unique<mojo::Binding<mojom::MediaRouteProvider>>(
-        &mock_provider_, mojo::MakeRequest(&mock_provider_ptr));
-    provider_proxy_->RegisterMediaRouteProvider(std::move(mock_provider_ptr));
+    mojo::PendingRemote<mojom::MediaRouteProvider> mock_provider_remote;
+    receiver_ = std::make_unique<mojo::Receiver<mojom::MediaRouteProvider>>(
+        &mock_provider_, mock_provider_remote.InitWithNewPipeAndPassReceiver());
+    provider_proxy_->RegisterMediaRouteProvider(
+        std::move(mock_provider_remote));
   }
 
   content::BrowserTaskEnvironment task_environment_;
@@ -260,23 +264,22 @@
                  &MockMediaRouteProvider::CreateMediaRouteControllerSuccess)));
 
   mojo::Remote<mojom::MediaController> controller_remote;
-  mojom::MediaStatusObserverPtr observer_ptr;
-  mojom::MediaStatusObserverRequest observer_request =
-      mojo::MakeRequest(&observer_ptr);
+  mojo::PendingRemote<mojom::MediaStatusObserver> observer_remote;
+  ignore_result(observer_remote.InitWithNewPipeAndPassReceiver());
 
   MockBoolCallback callback;
   provider_proxy_->CreateMediaRouteController(
       kRouteId, controller_remote.BindNewPipeAndPassReceiver(),
-      std::move(observer_ptr),
+      std::move(observer_remote),
       base::BindOnce(&MockBoolCallback::Run, base::Unretained(&callback)));
   base::RunLoop().RunUntilIdle();
 }
 
 TEST_F(ExtensionMediaRouteProviderProxyTest, NotifyRequestManagerOnError) {
-  // Invalidating the Mojo pointer to the MRP held by the proxy should make it
+  // Invalidating the Mojo remote to the MRP held by the proxy should make it
   // notify request manager.
   EXPECT_CALL(*request_manager_, OnMojoConnectionError());
-  binding_.reset();
+  receiver_.reset();
   base::RunLoop().RunUntilIdle();
 }
 
diff --git a/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.cc b/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.cc
index 9d442add..ed6b8d1 100644
--- a/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.cc
+++ b/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.cc
@@ -85,10 +85,10 @@
 }
 
 WiredDisplayMediaRouteProvider::WiredDisplayMediaRouteProvider(
-    mojom::MediaRouteProviderRequest request,
-    mojom::MediaRouterPtr media_router,
+    mojo::PendingReceiver<mojom::MediaRouteProvider> receiver,
+    mojo::PendingRemote<mojom::MediaRouter> media_router,
     Profile* profile)
-    : binding_(this, std::move(request)),
+    : receiver_(this, std::move(receiver)),
       media_router_(std::move(media_router)),
       profile_(profile) {
   media_router_->OnSinkAvailabilityUpdated(
@@ -273,7 +273,7 @@
 void WiredDisplayMediaRouteProvider::CreateMediaRouteController(
     const std::string& route_id,
     mojo::PendingReceiver<mojom::MediaController> media_controller,
-    mojom::MediaStatusObserverPtr observer,
+    mojo::PendingRemote<mojom::MediaStatusObserver> observer,
     CreateMediaRouteControllerCallback callback) {
   // Local screens do not support media controls.
   auto it = presentations_.find(route_id);
@@ -345,21 +345,22 @@
 
 void WiredDisplayMediaRouteProvider::Presentation::SetMojoConnections(
     mojo::PendingReceiver<mojom::MediaController> media_controller,
-    mojom::MediaStatusObserverPtr observer) {
+    mojo::PendingRemote<mojom::MediaStatusObserver> observer) {
   // This provider does not support media controls, so we do not bind
   // |media_controller| to a controller implementation.
   media_controller_receiver_ = std::move(media_controller);
 
-  media_status_observer_ = std::move(observer);
+  media_status_observer_.reset();
+  media_status_observer_.Bind(std::move(observer));
   media_status_observer_->OnMediaStatusUpdated(status_.Clone());
-  media_status_observer_.set_connection_error_handler(base::BindOnce(
+  media_status_observer_.set_disconnect_handler(base::BindOnce(
       &WiredDisplayMediaRouteProvider::Presentation::ResetMojoConnections,
       base::Unretained(this)));
 }
 
 void WiredDisplayMediaRouteProvider::Presentation::ResetMojoConnections() {
   media_controller_receiver_.reset();
-  media_status_observer_ = nullptr;
+  media_status_observer_.reset();
 }
 
 void WiredDisplayMediaRouteProvider::NotifyRouteObservers() const {
diff --git a/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.h b/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.h
index 58505c3f..a981723d 100644
--- a/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.h
+++ b/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.h
@@ -18,8 +18,10 @@
 #include "chrome/browser/media/router/providers/wired_display/wired_display_presentation_receiver.h"
 #include "chrome/common/media_router/media_route_provider_helper.h"
 #include "chrome/common/media_router/mojom/media_router.mojom.h"
-#include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "ui/display/display.h"
 #include "ui/display/display_observer.h"
 
@@ -41,9 +43,10 @@
 
   static std::string GetRouteDescription(const std::string& media_source);
 
-  WiredDisplayMediaRouteProvider(mojom::MediaRouteProviderRequest request,
-                                 mojom::MediaRouterPtr media_router,
-                                 Profile* profile);
+  WiredDisplayMediaRouteProvider(
+      mojo::PendingReceiver<mojom::MediaRouteProvider> receiver,
+      mojo::PendingRemote<mojom::MediaRouter> media_router,
+      Profile* profile);
   ~WiredDisplayMediaRouteProvider() override;
 
   // mojom::MediaRouteProvider:
@@ -95,7 +98,7 @@
   void CreateMediaRouteController(
       const std::string& route_id,
       mojo::PendingReceiver<mojom::MediaController> media_controller,
-      mojom::MediaStatusObserverPtr observer,
+      mojo::PendingRemote<mojom::MediaStatusObserver> observer,
       CreateMediaRouteControllerCallback callback) override;
 
   // display::DisplayObserver:
@@ -124,7 +127,7 @@
 
     void SetMojoConnections(
         mojo::PendingReceiver<mojom::MediaController> media_controller,
-        mojom::MediaStatusObserverPtr observer);
+        mojo::PendingRemote<mojom::MediaStatusObserver> observer);
 
     // Resets the Mojo connections to media controller and status observer.
     void ResetMojoConnections();
@@ -150,7 +153,7 @@
 
     // |media_status_observer|, when set, gets notified whenever |status|
     // changes.
-    mojom::MediaStatusObserverPtr media_status_observer_;
+    mojo::Remote<mojom::MediaStatusObserver> media_status_observer_;
 
     DISALLOW_COPY_AND_ASSIGN(Presentation);
   };
@@ -188,11 +191,11 @@
   // primary display.
   std::vector<display::Display> GetAvailableDisplays() const;
 
-  // Binds |this| to the Mojo request passed into the ctor.
-  mojo::Binding<mojom::MediaRouteProvider> binding_;
+  // Binds |this| to the Mojo receiver passed into the ctor.
+  mojo::Receiver<mojom::MediaRouteProvider> receiver_;
 
-  // Mojo pointer to the Media Router.
-  mojom::MediaRouterPtr media_router_;
+  // Mojo remote to the Media Router.
+  mojo::Remote<mojom::MediaRouter> media_router_;
 
   // Presentation profiles are created based on this original profile. This
   // profile is not owned by |this|.
diff --git a/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider_unittest.cc b/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider_unittest.cc
index 6920ecd5..1d648fe7 100644
--- a/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider_unittest.cc
+++ b/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider_unittest.cc
@@ -13,6 +13,9 @@
 #include "chrome/common/media_router/mojom/media_router.mojom.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/browser_task_environment.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -115,10 +118,11 @@
 class TestWiredDisplayMediaRouteProvider
     : public WiredDisplayMediaRouteProvider {
  public:
-  TestWiredDisplayMediaRouteProvider(mojom::MediaRouteProviderRequest request,
-                                     mojom::MediaRouterPtr media_router,
-                                     Profile* profile)
-      : WiredDisplayMediaRouteProvider(std::move(request),
+  TestWiredDisplayMediaRouteProvider(
+      mojo::PendingReceiver<mojom::MediaRouteProvider> receiver,
+      mojo::PendingRemote<mojom::MediaRouter> media_router,
+      Profile* profile)
+      : WiredDisplayMediaRouteProvider(std::move(receiver),
                                        std::move(media_router),
                                        profile) {}
   ~TestWiredDisplayMediaRouteProvider() override = default;
@@ -168,12 +172,12 @@
   void SetUp() override {
     display::Screen::SetScreenInstance(&test_screen_);
 
-    mojom::MediaRouterPtr router_pointer;
-    router_binding_ = std::make_unique<mojo::Binding<mojom::MediaRouter>>(
-        &router_, mojo::MakeRequest(&router_pointer));
+    mojo::PendingRemote<mojom::MediaRouter> router_pointer;
+    router_receiver_ = std::make_unique<mojo::Receiver<mojom::MediaRouter>>(
+        &router_, router_pointer.InitWithNewPipeAndPassReceiver());
     provider_ = std::make_unique<TestWiredDisplayMediaRouteProvider>(
-        mojo::MakeRequest(&provider_pointer_), std::move(router_pointer),
-        &profile_);
+        provider_remote_.BindNewPipeAndPassReceiver(),
+        std::move(router_pointer), &profile_);
     provider_->set_primary_display(primary_display_);
     WiredDisplayPresentationReceiverFactory::SetCreateReceiverCallbackForTest(
         base::BindRepeating(&MockReceiverCreator::CreateReceiver,
@@ -188,11 +192,10 @@
 
  protected:
   content::BrowserTaskEnvironment task_environment_;
-  // A mojo pointer to |provider_|.
-  mojom::MediaRouteProviderPtr provider_pointer_;
+  mojo::Remote<mojom::MediaRouteProvider> provider_remote_;
   std::unique_ptr<TestWiredDisplayMediaRouteProvider> provider_;
   MockMojoMediaRouter router_;
-  std::unique_ptr<mojo::Binding<mojom::MediaRouter>> router_binding_;
+  std::unique_ptr<mojo::Receiver<mojom::MediaRouter>> router_receiver_;
 
   gfx::Rect primary_display_bounds_;
   gfx::Rect secondary_display1_bounds_;
@@ -231,14 +234,14 @@
                       MediaRouteProviderId::WIRED_DISPLAY);
             EXPECT_EQ(sinks[0].sink().icon_type(), SinkIconType::WIRED_DISPLAY);
           })));
-  provider_pointer_->StartObservingMediaSinks(kPresentationSource);
+  provider_remote_->StartObservingMediaSinks(kPresentationSource);
   base::RunLoop().RunUntilIdle();
 }
 
 TEST_F(WiredDisplayMediaRouteProviderTest, NotifyOnDisplayChange) {
   const std::string primary_id = GetSinkId(primary_display_);
   const std::string secondary_id1 = GetSinkId(secondary_display1_);
-  provider_pointer_->StartObservingMediaSinks(kPresentationSource);
+  provider_remote_->StartObservingMediaSinks(kPresentationSource);
   base::RunLoop().RunUntilIdle();
 
   // Add an external display. MediaRouter should be notified of the sink and the
@@ -300,7 +303,7 @@
   EXPECT_CALL(router_,
               OnSinksReceived(kProviderId, kNonPresentationSource, _, _))
       .Times(0);
-  provider_pointer_->StartObservingMediaSinks(kNonPresentationSource);
+  provider_remote_->StartObservingMediaSinks(kNonPresentationSource);
   base::RunLoop().RunUntilIdle();
 }
 
@@ -309,7 +312,7 @@
   MockCallback callback;
 
   provider_->set_all_displays({secondary_display1_, primary_display_});
-  provider_pointer_->StartObservingMediaRoutes(kPresentationSource);
+  provider_remote_->StartObservingMediaRoutes(kPresentationSource);
   base::RunLoop().RunUntilIdle();
 
   // Create a route for |presentation_id|.
@@ -331,7 +334,7 @@
           })));
   EXPECT_CALL(*receiver_creator_.receiver(),
               Start(presentation_id, GURL(kPresentationSource)));
-  provider_pointer_->CreateRoute(
+  provider_remote_->CreateRoute(
       kPresentationSource, GetSinkId(secondary_display1_), presentation_id,
       url::Origin::Create(GURL(kPresentationSource)), 0,
       base::TimeDelta::FromSeconds(100), false,
@@ -346,9 +349,9 @@
               OnPresentationConnectionStateChanged(
                   presentation_id,
                   mojom::MediaRouter::PresentationConnectionState::TERMINATED));
-  provider_pointer_->TerminateRoute(
-      presentation_id, base::BindOnce(&MockCallback::TerminateRoute,
-                                      base::Unretained(&callback)));
+  provider_remote_->TerminateRoute(presentation_id,
+                                   base::BindOnce(&MockCallback::TerminateRoute,
+                                                  base::Unretained(&callback)));
   base::RunLoop().RunUntilIdle();
 
   // The presentation should not be removed until the receiver's termination
@@ -364,11 +367,11 @@
   MockCallback callback;
 
   provider_->set_all_displays({secondary_display1_, primary_display_});
-  provider_pointer_->StartObservingMediaRoutes(kPresentationSource);
+  provider_remote_->StartObservingMediaRoutes(kPresentationSource);
   base::RunLoop().RunUntilIdle();
 
   // Create a route for |presentation_id|.
-  provider_pointer_->CreateRoute(
+  provider_remote_->CreateRoute(
       kPresentationSource, GetSinkId(secondary_display1_), presentation_id,
       url::Origin::Create(GURL(kPresentationSource)), 0,
       base::TimeDelta::FromSeconds(100), false,
@@ -376,12 +379,12 @@
   base::RunLoop().RunUntilIdle();
 
   mojo::Remote<mojom::MediaController> media_controller_remote;
-  mojom::MediaStatusObserverPtr status_observer_ptr;
+  mojo::PendingRemote<mojom::MediaStatusObserver> status_observer_remote;
   MockMediaStatusObserver status_observer(
-      mojo::MakeRequest(&status_observer_ptr));
-  provider_pointer_->CreateMediaRouteController(
+      status_observer_remote.InitWithNewPipeAndPassReceiver());
+  provider_remote_->CreateMediaRouteController(
       presentation_id, media_controller_remote.BindNewPipeAndPassReceiver(),
-      std::move(status_observer_ptr), base::BindOnce([](bool success) {}));
+      std::move(status_observer_remote), base::BindOnce([](bool success) {}));
 
   EXPECT_CALL(status_observer, OnMediaStatusUpdated(_))
       .WillOnce(Invoke([&page_title](mojom::MediaStatusPtr status) {
@@ -394,10 +397,10 @@
 TEST_F(WiredDisplayMediaRouteProviderTest, ExitFullscreenOnDisplayRemoved) {
   MockCallback callback;
   provider_->set_all_displays({secondary_display1_, primary_display_});
-  provider_pointer_->StartObservingMediaRoutes(kPresentationSource);
+  provider_remote_->StartObservingMediaRoutes(kPresentationSource);
   base::RunLoop().RunUntilIdle();
 
-  provider_pointer_->CreateRoute(
+  provider_remote_->CreateRoute(
       kPresentationSource, GetSinkId(secondary_display1_), "presentationId",
       url::Origin::Create(GURL(kPresentationSource)), 0,
       base::TimeDelta::FromSeconds(100), false,
diff --git a/chrome/browser/media/router/test/media_router_mojo_test.cc b/chrome/browser/media/router/test/media_router_mojo_test.cc
index cc7594a0..2a1a844 100644
--- a/chrome/browser/media/router/test/media_router_mojo_test.cc
+++ b/chrome/browser/media/router/test/media_router_mojo_test.cc
@@ -116,8 +116,8 @@
 }
 
 MockMediaStatusObserver::MockMediaStatusObserver(
-    mojom::MediaStatusObserverRequest request)
-    : binding_(this, std::move(request)) {}
+    mojo::PendingReceiver<mojom::MediaStatusObserver> receiver)
+    : receiver_(this, std::move(receiver)) {}
 
 MockMediaStatusObserver::~MockMediaStatusObserver() {}
 
@@ -395,8 +395,9 @@
 void MediaRouterMojoTest::RegisterMediaRouteProvider(
     mojom::MediaRouteProvider* provider,
     MediaRouteProviderId provider_id) {
-  mojom::MediaRouteProviderPtr mojo_provider;
-  provider_bindings_.AddBinding(provider, mojo::MakeRequest(&mojo_provider));
+  mojo::PendingRemote<mojom::MediaRouteProvider> mojo_provider;
+  provider_receivers_.Add(provider,
+                          mojo_provider.InitWithNewPipeAndPassReceiver());
   media_router_->RegisterMediaRouteProvider(
       provider_id, std::move(mojo_provider),
       base::BindOnce([](const std::string& instance_id,
diff --git a/chrome/browser/media/router/test/media_router_mojo_test.h b/chrome/browser/media/router/test/media_router_mojo_test.h
index b0d49a61..d12a3d3 100644
--- a/chrome/browser/media/router/test/media_router_mojo_test.h
+++ b/chrome/browser/media/router/test/media_router_mojo_test.h
@@ -21,10 +21,10 @@
 #include "content/public/test/browser_task_environment.h"
 #include "extensions/browser/event_page_tracker.h"
 #include "extensions/common/extension.h"
-#include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -144,7 +144,7 @@
   void CreateMediaRouteController(
       const std::string& route_id,
       mojo::PendingReceiver<mojom::MediaController> media_controller,
-      mojom::MediaStatusObserverPtr observer,
+      mojo::PendingRemote<mojom::MediaStatusObserver> observer,
       CreateMediaRouteControllerCallback callback) override {
     CreateMediaRouteControllerInternal(route_id, media_controller, observer,
                                        callback);
@@ -153,7 +153,7 @@
       CreateMediaRouteControllerInternal,
       void(const std::string& route_id,
            mojo::PendingReceiver<mojom::MediaController>& media_controller,
-           mojom::MediaStatusObserverPtr& observer,
+           mojo::PendingRemote<mojom::MediaStatusObserver>& observer,
            CreateMediaRouteControllerCallback& callback));
 
   // These methods execute the callbacks with the success or timeout result
@@ -209,13 +209,14 @@
 
 class MockMediaStatusObserver : public mojom::MediaStatusObserver {
  public:
-  explicit MockMediaStatusObserver(mojom::MediaStatusObserverRequest request);
+  explicit MockMediaStatusObserver(
+      mojo::PendingReceiver<mojom::MediaStatusObserver> receiver);
   ~MockMediaStatusObserver() override;
 
   MOCK_METHOD1(OnMediaStatusUpdated, void(mojom::MediaStatusPtr status));
 
  private:
-  mojo::Binding<mojom::MediaStatusObserver> binding_;
+  mojo::Receiver<mojom::MediaStatusObserver> receiver_;
 };
 
 class MockMediaController : public mojom::MediaController {
@@ -297,7 +298,7 @@
   scoped_refptr<const extensions::Extension> extension_;
   TestingProfile profile_;
   std::unique_ptr<MediaRouterMojoImpl> media_router_;
-  mojo::BindingSet<mojom::MediaRouteProvider> provider_bindings_;
+  mojo::ReceiverSet<mojom::MediaRouteProvider> provider_receivers_;
   std::unique_ptr<MediaRoutesObserver> routes_observer_;
   std::unique_ptr<MockMediaSinksObserver> sinks_observer_;
 
diff --git a/chrome/browser/media/router/test/mock_media_router.h b/chrome/browser/media/router/test/mock_media_router.h
index cf2b3c48..495a9c2c 100644
--- a/chrome/browser/media/router/test/mock_media_router.h
+++ b/chrome/browser/media/router/test/mock_media_router.h
@@ -15,6 +15,8 @@
 #include "chrome/common/media_router/media_route.h"
 #include "chrome/common/media_router/media_sink.h"
 #include "chrome/common/media_router/media_source.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "url/origin.h"
 
@@ -135,7 +137,7 @@
   MOCK_METHOD3(GetMediaController,
                void(const MediaRoute::Id& route_id,
                     mojo::PendingReceiver<mojom::MediaController> controller,
-                    mojom::MediaStatusObserverPtr observer));
+                    mojo::PendingRemote<mojom::MediaStatusObserver> observer));
 #endif  // !defined(OS_ANDROID)
   MOCK_METHOD1(OnAddPresentationConnectionStateChangedCallbackInvoked,
                void(const content::PresentationConnectionStateChangedCallback&
diff --git a/chrome/browser/media/router/test/mock_mojo_media_router.h b/chrome/browser/media/router/test/mock_mojo_media_router.h
index 71f92bb..5793955d 100644
--- a/chrome/browser/media/router/test/mock_mojo_media_router.h
+++ b/chrome/browser/media/router/test/mock_mojo_media_router.h
@@ -9,6 +9,7 @@
 #include "chrome/common/media_router/media_route_provider_helper.h"
 #include "chrome/common/media_router/mojom/media_router.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace media_router {
@@ -21,14 +22,15 @@
   // mojom::MediaRouter overrides:
   void RegisterMediaRouteProvider(
       MediaRouteProviderId provider_id,
-      mojom::MediaRouteProviderPtr provider_ptr,
+      mojo::PendingRemote<mojom::MediaRouteProvider> provider_remote,
       RegisterMediaRouteProviderCallback callback) override {
-    RegisterMediaRouteProviderInternal(provider_id, provider_ptr, callback);
+    RegisterMediaRouteProviderInternal(provider_id, provider_remote, callback);
   }
-  MOCK_METHOD3(RegisterMediaRouteProviderInternal,
-               void(MediaRouteProviderId provider_id,
-                    mojom::MediaRouteProviderPtr& provider_ptr,
-                    RegisterMediaRouteProviderCallback& callback));
+  MOCK_METHOD3(
+      RegisterMediaRouteProviderInternal,
+      void(MediaRouteProviderId provider_id,
+           mojo::PendingRemote<mojom::MediaRouteProvider>& provider_remote,
+           RegisterMediaRouteProviderCallback& callback));
   MOCK_METHOD1(OnIssue, void(const IssueInfo& issue));
   MOCK_METHOD4(OnSinksReceived,
                void(MediaRouteProviderId provider_id,
diff --git a/chrome/browser/media/webrtc/webrtc_getdisplaymedia_browsertest.cc b/chrome/browser/media/webrtc/webrtc_getdisplaymedia_browsertest.cc
index 85d08ce..44027f5 100644
--- a/chrome/browser/media/webrtc/webrtc_getdisplaymedia_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_getdisplaymedia_browsertest.cc
@@ -37,7 +37,8 @@
   }
 
   void RunGetDisplayMedia(content::WebContents* tab,
-                          const std::string& constraints) {
+                          const std::string& constraints,
+                          bool is_fake_ui = false) {
     std::string result;
     EXPECT_TRUE(content::ExecuteScriptAndExtractString(
         tab->GetMainFrame(),
@@ -45,9 +46,11 @@
         &result));
 #if defined(OS_MACOSX)
     // Starting from macOS 10.15, screen capture requires system permissions
-    // that are disabled by default.
-    EXPECT_EQ(result, base::mac::IsAtMostOS10_14() ? "getdisplaymedia-success"
-                                                   : "getdisplaymedia-failure");
+    // that are disabled by default. The permission is reported as granted
+    // if the fake UI is used.
+    EXPECT_EQ(result, base::mac::IsAtMostOS10_14() || is_fake_ui
+                          ? "getdisplaymedia-success"
+                          : "getdisplaymedia-failure");
 #else
     EXPECT_EQ(result, "getdisplaymedia-success");
 #endif
@@ -133,7 +136,7 @@
 
   content::WebContents* tab = OpenTestPageInNewTab(kMainHtmlPage);
   std::string constraints("{video:true}");
-  RunGetDisplayMedia(tab, constraints);
+  RunGetDisplayMedia(tab, constraints, /*is_fake_ui=*/true);
 
   std::string result;
   EXPECT_TRUE(content::ExecuteScriptAndExtractString(
@@ -155,7 +158,7 @@
 
   content::WebContents* tab = OpenTestPageInNewTab(kMainHtmlPage);
   std::string constraints("{video:true, audio:true}");
-  RunGetDisplayMedia(tab, constraints);
+  RunGetDisplayMedia(tab, constraints, /*is_fake_ui=*/true);
 
   std::string result;
   EXPECT_TRUE(content::ExecuteScriptAndExtractString(
@@ -173,7 +176,7 @@
   const std::string& constraints =
       base::StringPrintf("{video: {width: {max: %d}, frameRate: {max: %d}}}",
                          kMaxWidth, kMaxFrameRate);
-  RunGetDisplayMedia(tab, constraints);
+  RunGetDisplayMedia(tab, constraints, /*is_fake_ui=*/true);
 
   std::string result;
   EXPECT_TRUE(content::ExecuteScriptAndExtractString(
diff --git a/chrome/browser/metrics/process_memory_metrics_emitter_browsertest.cc b/chrome/browser/metrics/process_memory_metrics_emitter_browsertest.cc
index 74c0724..cbeaee6 100644
--- a/chrome/browser/metrics/process_memory_metrics_emitter_browsertest.cc
+++ b/chrome/browser/metrics/process_memory_metrics_emitter_browsertest.cc
@@ -44,6 +44,7 @@
 
 namespace {
 
+using base::trace_event::MemoryDumpDeterminism;
 using base::trace_event::MemoryDumpType;
 using memory_instrumentation::GlobalMemoryDump;
 using memory_instrumentation::mojom::ProcessType;
@@ -88,6 +89,7 @@
   memory_instrumentation::MemoryInstrumentation::GetInstance()
       ->RequestGlobalDumpAndAppendToTrace(
           MemoryDumpType::EXPLICITLY_TRIGGERED, explicit_dump_type,
+          MemoryDumpDeterminism::NONE,
           Bind(&RequestGlobalDumpCallback, quit_closure));
 }
 
diff --git a/chrome/browser/net/system_network_context_manager.cc b/chrome/browser/net/system_network_context_manager.cc
index 7fb3154..95964da 100644
--- a/chrome/browser/net/system_network_context_manager.cc
+++ b/chrome/browser/net/system_network_context_manager.cc
@@ -476,6 +476,9 @@
   pref_change_registrar_.Add(prefs::kKerberosEnabled, auth_pref_callback);
 #endif  // defined(OS_CHROMEOS)
 
+  local_state_->SetDefaultPrefValue(
+      prefs::kEnableReferrers,
+      base::Value(!base::FeatureList::IsEnabled(features::kNoReferrers)));
   enable_referrers_.Init(
       prefs::kEnableReferrers, local_state_,
       base::BindRepeating(&SystemNetworkContextManager::UpdateReferrersEnabled,
diff --git a/chrome/browser/net/system_network_context_manager_browsertest.cc b/chrome/browser/net/system_network_context_manager_browsertest.cc
index f6f7da5..c283951c 100644
--- a/chrome/browser/net/system_network_context_manager_browsertest.cc
+++ b/chrome/browser/net/system_network_context_manager_browsertest.cc
@@ -20,7 +20,6 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "components/prefs/pref_service.h"
 #include "components/version_info/version_info.h"
-#include "content/public/common/content_switches.h"
 #include "content/public/common/user_agent.h"
 #include "services/network/public/cpp/network_service_buildflags.h"
 #include "services/network/public/mojom/network_context.mojom.h"
@@ -295,6 +294,36 @@
                          SystemNetworkContextManagerStubResolverBrowsertest,
                          ::testing::Bool());
 
+class SystemNetworkContextManagerReferrersFeatureBrowsertest
+    : public SystemNetworkContextManagerBrowsertest,
+      public testing::WithParamInterface<bool> {
+ public:
+  SystemNetworkContextManagerReferrersFeatureBrowsertest() {
+    scoped_feature_list_.InitWithFeatureState(features::kNoReferrers,
+                                              GetParam());
+  }
+  ~SystemNetworkContextManagerReferrersFeatureBrowsertest() override {}
+
+  void SetUpOnMainThread() override {}
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+// Tests that toggling the kNoReferrers feature correctly changes the default
+// value of the kEnableReferrers pref.
+IN_PROC_BROWSER_TEST_P(SystemNetworkContextManagerReferrersFeatureBrowsertest,
+                       TestDefaultReferrerReflectsFeatureValue) {
+  ASSERT_TRUE(!!g_browser_process);
+  PrefService* local_state = g_browser_process->local_state();
+  ASSERT_TRUE(!!local_state);
+  EXPECT_NE(local_state->GetBoolean(prefs::kEnableReferrers), GetParam());
+}
+
+INSTANTIATE_TEST_SUITE_P(,
+                         SystemNetworkContextManagerReferrersFeatureBrowsertest,
+                         ::testing::Bool());
+
 class SystemNetworkContextManagerFreezeQUICUaBrowsertest
     : public SystemNetworkContextManagerBrowsertest,
       public testing::WithParamInterface<bool> {
diff --git a/chrome/browser/performance_manager/decorators/page_almost_idle_decorator.cc b/chrome/browser/performance_manager/decorators/page_almost_idle_decorator.cc
index c6fa924..1493559 100644
--- a/chrome/browser/performance_manager/decorators/page_almost_idle_decorator.cc
+++ b/chrome/browser/performance_manager/decorators/page_almost_idle_decorator.cc
@@ -81,12 +81,9 @@
   UpdateLoadIdleStatePage(PageNodeImpl::FromNode(page_node));
 }
 
-void PageAlmostIdleDecorator::OnMainFrameNavigationCommitted(
+void PageAlmostIdleDecorator::OnMainFrameDocumentChanged(
     const PageNode* page_node) {
-  // Filter out the initial visible URL notification.
-  if (page_node->GetNavigationID() == 0)
-    return;
-
+  DCHECK_NE(0, page_node->GetNavigationID());
   // Reset the load-idle state associated with this page as a new navigation has
   // started.
   auto* page_impl = PageNodeImpl::FromNode(page_node);
diff --git a/chrome/browser/performance_manager/decorators/page_almost_idle_decorator.h b/chrome/browser/performance_manager/decorators/page_almost_idle_decorator.h
index fd6a2c2..1edc9ad 100644
--- a/chrome/browser/performance_manager/decorators/page_almost_idle_decorator.h
+++ b/chrome/browser/performance_manager/decorators/page_almost_idle_decorator.h
@@ -41,7 +41,7 @@
 
   // PageNodeObserver implementation:
   void OnIsLoadingChanged(const PageNode* page_node) override;
-  void OnMainFrameNavigationCommitted(const PageNode* page_node) override;
+  void OnMainFrameDocumentChanged(const PageNode* page_node) override;
 
   // ProcessNodeObserver implementation:
   void OnMainThreadTaskLoadIsLow(const ProcessNode* process_node) override;
diff --git a/chrome/browser/performance_manager/decorators/page_almost_idle_decorator_unittest.cc b/chrome/browser/performance_manager/decorators/page_almost_idle_decorator_unittest.cc
index 3c1f6f6..727f1ec 100644
--- a/chrome/browser/performance_manager/decorators/page_almost_idle_decorator_unittest.cc
+++ b/chrome/browser/performance_manager/decorators/page_almost_idle_decorator_unittest.cc
@@ -127,7 +127,7 @@
   EXPECT_FALSE(Data::GetForTesting(page_node));
 
   // Post a navigation. The state should reset.
-  page_node->OnMainFrameNavigationCommitted(base::TimeTicks::Now(), 1,
+  page_node->OnMainFrameNavigationCommitted(false, base::TimeTicks::Now(), 1,
                                             GURL("https://www.example.org"));
   page_data = Data::GetForTesting(page_node);
   EXPECT_EQ(LIS::kLoadingNotStarted, page_data->load_idle_state_);
diff --git a/chrome/browser/performance_manager/graph/node_base.h b/chrome/browser/performance_manager/graph/node_base.h
index 4743184..82085f1 100644
--- a/chrome/browser/performance_manager/graph/node_base.h
+++ b/chrome/browser/performance_manager/graph/node_base.h
@@ -12,7 +12,6 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
-#include "base/observer_list.h"
 #include "base/sequence_checker.h"
 #include "chrome/browser/performance_manager/graph/graph_impl.h"
 #include "chrome/browser/performance_manager/graph/node_type.h"
diff --git a/chrome/browser/performance_manager/graph/page_node_impl.cc b/chrome/browser/performance_manager/graph/page_node_impl.cc
index 9464407..ff6b5e45 100644
--- a/chrome/browser/performance_manager/graph/page_node_impl.cc
+++ b/chrome/browser/performance_manager/graph/page_node_impl.cc
@@ -19,11 +19,13 @@
 PageNodeImpl::PageNodeImpl(GraphImpl* graph,
                            const WebContentsProxy& contents_proxy,
                            const std::string& browser_context_id,
+                           const GURL& visible_url,
                            bool is_visible,
                            bool is_audible)
     : TypedNodeBase(graph),
       contents_proxy_(contents_proxy),
       visibility_change_time_(base::TimeTicks::Now()),
+      main_frame_url_(visible_url),
       browser_context_id_(browser_context_id),
       is_visible_(is_visible),
       is_audible_(is_audible) {
@@ -97,15 +99,25 @@
 }
 
 void PageNodeImpl::OnMainFrameNavigationCommitted(
+    bool same_document,
     base::TimeTicks navigation_committed_time,
     int64_t navigation_id,
     const GURL& url) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  // This should never be invoked with a null navigation, nor should it be
+  // called twice for the same navigation.
+  DCHECK_NE(0, navigation_id);
+  DCHECK_NE(navigation_id_, navigation_id);
   navigation_committed_time_ = navigation_committed_time;
-  main_frame_url_ = url;
   navigation_id_ = navigation_id;
+  main_frame_url_.SetAndMaybeNotify(this, url);
+
+  // No mainframe document change notification on same-document navigations.
+  if (same_document)
+    return;
+
   for (auto* observer : GetObservers())
-    observer->OnMainFrameNavigationCommitted(this);
+    observer->OnMainFrameDocumentChanged(this);
 }
 
 double PageNodeImpl::GetCPUUsage() const {
@@ -215,7 +227,7 @@
 
 const GURL& PageNodeImpl::main_frame_url() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  return main_frame_url_;
+  return main_frame_url_.value();
 }
 
 int64_t PageNodeImpl::navigation_id() const {
diff --git a/chrome/browser/performance_manager/graph/page_node_impl.h b/chrome/browser/performance_manager/graph/page_node_impl.h
index 45655ae..351cb1d 100644
--- a/chrome/browser/performance_manager/graph/page_node_impl.h
+++ b/chrome/browser/performance_manager/graph/page_node_impl.h
@@ -31,6 +31,7 @@
   PageNodeImpl(GraphImpl* graph,
                const WebContentsProxy& contents_proxy,
                const std::string& browser_context_id,
+               const GURL& visible_url,
                bool is_visible,
                bool is_audible);
   ~PageNodeImpl() override;
@@ -46,7 +47,8 @@
   void SetUkmSourceId(ukm::SourceId ukm_source_id);
   void OnFaviconUpdated();
   void OnTitleUpdated();
-  void OnMainFrameNavigationCommitted(base::TimeTicks navigation_committed_time,
+  void OnMainFrameNavigationCommitted(bool same_document,
+                                      base::TimeTicks navigation_committed_time,
                                       int64_t navigation_id,
                                       const GURL& url);
 
@@ -174,7 +176,10 @@
 
   // The URL the main frame last committed, or the initial URL a page was
   // initialized with. The latter case is distinguished by a zero navigation ID.
-  GURL main_frame_url_;
+  ObservedProperty::
+      NotifiesOnlyOnChanges<GURL, &PageNodeObserver::OnMainFrameUrlChanged>
+          main_frame_url_;
+
   // The unique ID of the navigation handle the main frame last committed, or
   // zero if the page has never committed a navigation.
   int64_t navigation_id_ = 0;
diff --git a/chrome/browser/performance_manager/graph/page_node_impl_unittest.cc b/chrome/browser/performance_manager/graph/page_node_impl_unittest.cc
index 7e6be0fe..f4b889e 100644
--- a/chrome/browser/performance_manager/graph/page_node_impl_unittest.cc
+++ b/chrome/browser/performance_manager/graph/page_node_impl_unittest.cc
@@ -123,8 +123,8 @@
 
   // 1st navigation.
   GURL url("http://www.example.org");
-  mock_graph.page->OnMainFrameNavigationCommitted(base::TimeTicks::Now(), 10u,
-                                                  url);
+  mock_graph.page->OnMainFrameNavigationCommitted(false, base::TimeTicks::Now(),
+                                                  10u, url);
   EXPECT_EQ(url, mock_graph.page->main_frame_url());
   EXPECT_EQ(10u, mock_graph.page->navigation_id());
   AdvanceClock(base::TimeDelta::FromSeconds(11));
@@ -133,13 +133,23 @@
 
   // 2nd navigation.
   url = GURL("http://www.example.org/bobcat");
-  mock_graph.page->OnMainFrameNavigationCommitted(base::TimeTicks::Now(), 20u,
-                                                  url);
+  mock_graph.page->OnMainFrameNavigationCommitted(false, base::TimeTicks::Now(),
+                                                  20u, url);
   EXPECT_EQ(url, mock_graph.page->main_frame_url());
   EXPECT_EQ(20u, mock_graph.page->navigation_id());
   AdvanceClock(base::TimeDelta::FromSeconds(17));
   EXPECT_EQ(base::TimeDelta::FromSeconds(17),
             mock_graph.page->TimeSinceLastNavigation());
+
+  // Test a same-document navigation.
+  url = GURL("http://www.example.org/bobcat#fun");
+  mock_graph.page->OnMainFrameNavigationCommitted(true, base::TimeTicks::Now(),
+                                                  30u, url);
+  EXPECT_EQ(url, mock_graph.page->main_frame_url());
+  EXPECT_EQ(30u, mock_graph.page->navigation_id());
+  AdvanceClock(base::TimeDelta::FromSeconds(17));
+  EXPECT_EQ(base::TimeDelta::FromSeconds(17),
+            mock_graph.page->TimeSinceLastNavigation());
 }
 
 TEST_F(PageNodeImplTest, BrowserContextID) {
@@ -188,8 +198,9 @@
   MOCK_METHOD1(OnUkmSourceIdChanged, void(const PageNode*));
   MOCK_METHOD1(OnPageLifecycleStateChanged, void(const PageNode*));
   MOCK_METHOD1(OnPageOriginTrialFreezePolicyChanged, void(const PageNode*));
+  MOCK_METHOD1(OnMainFrameUrlChanged, void(const PageNode*));
   MOCK_METHOD1(OnPageAlmostIdleChanged, void(const PageNode*));
-  MOCK_METHOD1(OnMainFrameNavigationCommitted, void(const PageNode*));
+  MOCK_METHOD1(OnMainFrameDocumentChanged, void(const PageNode*));
   MOCK_METHOD1(OnTitleUpdated, void(const PageNode*));
   MOCK_METHOD1(OnFaviconUpdated, void(const PageNode*));
 
@@ -257,10 +268,19 @@
   page_node->SetPageAlmostIdleForTesting(true);
   EXPECT_EQ(raw_page_node, obs.TakeNotifiedPageNode());
 
-  EXPECT_CALL(obs, OnMainFrameNavigationCommitted(_))
+  const GURL kTestUrl = GURL("https://foo.com/");
+  int64_t navigation_id = 0x1234;
+  EXPECT_CALL(obs, OnMainFrameUrlChanged(_))
       .WillOnce(Invoke(&obs, &MockObserver::SetNotifiedPageNode));
-  page_node->OnMainFrameNavigationCommitted(base::TimeTicks::Now(), 0x1234ull,
-                                            GURL("https://foo.com/"));
+  // Expect no OnMainFrameDocumentChanged for same-document navigation
+  page_node->OnMainFrameNavigationCommitted(true, base::TimeTicks::Now(),
+                                            ++navigation_id, kTestUrl);
+  EXPECT_EQ(raw_page_node, obs.TakeNotifiedPageNode());
+
+  EXPECT_CALL(obs, OnMainFrameDocumentChanged(_))
+      .WillOnce(Invoke(&obs, &MockObserver::SetNotifiedPageNode));
+  page_node->OnMainFrameNavigationCommitted(false, base::TimeTicks::Now(),
+                                            ++navigation_id, kTestUrl);
   EXPECT_EQ(raw_page_node, obs.TakeNotifiedPageNode());
 
   EXPECT_CALL(obs, OnTitleUpdated(_))
diff --git a/chrome/browser/performance_manager/observers/metrics_collector_unittest.cc b/chrome/browser/performance_manager/observers/metrics_collector_unittest.cc
index b9171c0..e4b5777 100644
--- a/chrome/browser/performance_manager/observers/metrics_collector_unittest.cc
+++ b/chrome/browser/performance_manager/observers/metrics_collector_unittest.cc
@@ -57,8 +57,8 @@
 TEST_F(MAYBE_MetricsCollectorTest, FromBackgroundedToFirstTitleUpdatedUMA) {
   auto page_node = CreateNode<PageNodeImpl>();
 
-  page_node->OnMainFrameNavigationCommitted(base::TimeTicks::Now(), kDummyID,
-                                            kDummyUrl);
+  page_node->OnMainFrameNavigationCommitted(false, base::TimeTicks::Now(),
+                                            kDummyID, kDummyUrl);
   AdvanceClock(kTestMetricsReportDelayTimeout);
 
   page_node->SetIsVisible(true);
@@ -90,8 +90,8 @@
        FromBackgroundedToFirstTitleUpdatedUMA5MinutesTimeout) {
   auto page_node = CreateNode<PageNodeImpl>();
 
-  page_node->OnMainFrameNavigationCommitted(base::TimeTicks::Now(), kDummyID,
-                                            kDummyUrl);
+  page_node->OnMainFrameNavigationCommitted(false, base::TimeTicks::Now(),
+                                            kDummyID, kDummyUrl);
   page_node->SetIsVisible(false);
   page_node->OnTitleUpdated();
   // The page is within 5 minutes after main frame navigation was committed,
@@ -111,8 +111,8 @@
   auto frame_node =
       CreateNode<FrameNodeImpl>(process_node.get(), page_node.get());
 
-  page_node->OnMainFrameNavigationCommitted(base::TimeTicks::Now(), kDummyID,
-                                            kDummyUrl);
+  page_node->OnMainFrameNavigationCommitted(false, base::TimeTicks::Now(),
+                                            kDummyID, kDummyUrl);
   AdvanceClock(kTestMetricsReportDelayTimeout);
 
   page_node->SetIsVisible(true);
@@ -148,8 +148,8 @@
   auto frame_node =
       CreateNode<FrameNodeImpl>(process_node.get(), page_node.get());
 
-  page_node->OnMainFrameNavigationCommitted(base::TimeTicks::Now(), kDummyID,
-                                            kDummyUrl);
+  page_node->OnMainFrameNavigationCommitted(false, base::TimeTicks::Now(),
+                                            kDummyID, kDummyUrl);
   page_node->SetIsVisible(false);
   frame_node->OnNonPersistentNotificationCreated();
   // The page is within 5 minutes after main frame navigation was committed,
@@ -165,8 +165,8 @@
 TEST_F(MAYBE_MetricsCollectorTest, FromBackgroundedToFirstFaviconUpdatedUMA) {
   auto page_node = CreateNode<PageNodeImpl>();
 
-  page_node->OnMainFrameNavigationCommitted(base::TimeTicks::Now(), kDummyID,
-                                            kDummyUrl);
+  page_node->OnMainFrameNavigationCommitted(false, base::TimeTicks::Now(),
+                                            kDummyID, kDummyUrl);
   AdvanceClock(kTestMetricsReportDelayTimeout);
 
   page_node->SetIsVisible(true);
@@ -198,8 +198,8 @@
        FromBackgroundedToFirstFaviconUpdatedUMA5MinutesTimeout) {
   auto page_node = CreateNode<PageNodeImpl>();
 
-  page_node->OnMainFrameNavigationCommitted(base::TimeTicks::Now(), kDummyID,
-                                            kDummyUrl);
+  page_node->OnMainFrameNavigationCommitted(false, base::TimeTicks::Now(),
+                                            kDummyID, kDummyUrl);
   page_node->SetIsVisible(false);
   page_node->OnFaviconUpdated();
   // The page is within 5 minutes after main frame navigation was committed,
@@ -226,8 +226,8 @@
   GURL url = GURL("https://google.com/foobar");
   ukm_recorder.UpdateSourceURL(id, url);
   page_node->SetUkmSourceId(id);
-  page_node->OnMainFrameNavigationCommitted(base::TimeTicks::Now(), kDummyID,
-                                            kDummyUrl);
+  page_node->OnMainFrameNavigationCommitted(false, base::TimeTicks::Now(),
+                                            kDummyID, kDummyUrl);
 
   for (int count = 1; count < kDefaultFrequencyUkmEQTReported; ++count) {
     process_node->SetExpectedTaskQueueingDuration(
diff --git a/chrome/browser/performance_manager/performance_manager_impl.cc b/chrome/browser/performance_manager/performance_manager_impl.cc
index db5ba4d5..1a91fbf 100644
--- a/chrome/browser/performance_manager/performance_manager_impl.cc
+++ b/chrome/browser/performance_manager/performance_manager_impl.cc
@@ -155,11 +155,12 @@
 std::unique_ptr<PageNodeImpl> PerformanceManagerImpl::CreatePageNode(
     const WebContentsProxy& contents_proxy,
     const std::string& browser_context_id,
+    const GURL& visible_url,
     bool is_visible,
     bool is_audible) {
   return CreateNodeImpl<PageNodeImpl>(base::OnceCallback<void(PageNodeImpl*)>(),
                                       contents_proxy, browser_context_id,
-                                      is_visible, is_audible);
+                                      visible_url, is_visible, is_audible);
 }
 
 std::unique_ptr<ProcessNodeImpl> PerformanceManagerImpl::CreateProcessNode(
diff --git a/chrome/browser/performance_manager/performance_manager_impl.h b/chrome/browser/performance_manager/performance_manager_impl.h
index ef5d135..f06e3dbe 100644
--- a/chrome/browser/performance_manager/performance_manager_impl.h
+++ b/chrome/browser/performance_manager/performance_manager_impl.h
@@ -93,6 +93,7 @@
   std::unique_ptr<PageNodeImpl> CreatePageNode(
       const WebContentsProxy& contents_proxy,
       const std::string& browser_context_id,
+      const GURL& visible_url,
       bool is_visible,
       bool is_audible);
   std::unique_ptr<ProcessNodeImpl> CreateProcessNode(
diff --git a/chrome/browser/performance_manager/performance_manager_impl_unittest.cc b/chrome/browser/performance_manager/performance_manager_impl_unittest.cc
index 437ef18..3f92688 100644
--- a/chrome/browser/performance_manager/performance_manager_impl_unittest.cc
+++ b/chrome/browser/performance_manager/performance_manager_impl_unittest.cc
@@ -60,7 +60,7 @@
   EXPECT_NE(nullptr, process_node.get());
   std::unique_ptr<PageNodeImpl> page_node =
       performance_manager()->CreatePageNode(WebContentsProxy(), std::string(),
-                                            false, false);
+                                            GURL(), false, false);
   EXPECT_NE(nullptr, page_node.get());
 
   // Create a node of each type.
@@ -81,7 +81,7 @@
       performance_manager()->CreateProcessNode(RenderProcessHostProxy());
   std::unique_ptr<PageNodeImpl> page_node =
       performance_manager()->CreatePageNode(WebContentsProxy(), std::string(),
-                                            false, false);
+                                            GURL(), false, false);
 
   std::unique_ptr<FrameNodeImpl> parent1_frame =
       performance_manager()->CreateFrameNode(
@@ -125,7 +125,7 @@
   // Create a page node for something to target.
   std::unique_ptr<PageNodeImpl> page_node =
       performance_manager()->CreatePageNode(WebContentsProxy(), std::string(),
-                                            false, false);
+                                            GURL(), false, false);
   base::RunLoop run_loop;
   base::OnceClosure quit_closure = run_loop.QuitClosure();
   EXPECT_FALSE(performance_manager()->OnPMTaskRunnerForTesting());
@@ -147,7 +147,7 @@
   // Create a page node for something to target.
   std::unique_ptr<PageNodeImpl> page_node =
       performance_manager()->CreatePageNode(WebContentsProxy(), std::string(),
-                                            false, false);
+                                            GURL(), false, false);
   base::RunLoop run_loop;
 
   EXPECT_FALSE(performance_manager()->OnPMTaskRunnerForTesting());
diff --git a/chrome/browser/performance_manager/performance_manager_tab_helper.cc b/chrome/browser/performance_manager/performance_manager_tab_helper.cc
index b0de4ac..0b99637 100644
--- a/chrome/browser/performance_manager/performance_manager_tab_helper.cc
+++ b/chrome/browser/performance_manager/performance_manager_tab_helper.cc
@@ -46,21 +46,9 @@
   page_node_ = performance_manager_->CreatePageNode(
       WebContentsProxy(weak_factory_.GetWeakPtr()),
       web_contents->GetBrowserContext()->UniqueId(),
+      web_contents->GetVisibleURL(),
       web_contents->GetVisibility() == content::Visibility::VISIBLE,
       web_contents->IsCurrentlyAudible());
-
-  // Set the initial (visible) URL of the page early. In the rare and unlikely
-  // case the main frame has been navigated, this URL will be overridden with
-  // the main frame's last committed URL and navigation ID in the loop below.
-  GURL visible_url = web_contents->GetVisibleURL();
-  if (visible_url.is_valid()) {
-    // Post the visible URL as a navigation to the zero navigation ID.
-    constexpr int64_t kZeroNavigationId = 0;
-    PostToGraph(FROM_HERE, &PageNodeImpl::OnMainFrameNavigationCommitted,
-                page_node_.get(), base::TimeTicks::Now(), kZeroNavigationId,
-                visible_url);
-  }
-
   // Dispatch creation notifications for any pre-existing frames.
   std::vector<content::RenderFrameHost*> existing_frames =
       web_contents->GetAllFrames();
@@ -286,17 +274,16 @@
   PostToGraph(FROM_HERE, &FrameNodeImpl::OnNavigationCommitted, frame_node, url,
               navigation_handle->IsSameDocument());
 
-  if (navigation_handle->IsSameDocument() ||
-      !navigation_handle->IsInMainFrame()) {
+  if (!navigation_handle->IsInMainFrame())
     return;
-  }
 
   // Make sure the hierarchical structure is constructed before sending signal
   // to the performance manager.
   OnMainFrameNavigation(navigation_handle->GetNavigationId());
   PostToGraph(FROM_HERE, &PageNodeImpl::OnMainFrameNavigationCommitted,
-              page_node_.get(), navigation_committed_time,
-              navigation_handle->GetNavigationId(), url);
+              page_node_.get(), navigation_handle->IsSameDocument(),
+              navigation_committed_time, navigation_handle->GetNavigationId(),
+              url);
 }
 
 void PerformanceManagerTabHelper::TitleWasSet(content::NavigationEntry* entry) {
diff --git a/chrome/browser/performance_manager/public/graph/page_node.h b/chrome/browser/performance_manager/public/graph/page_node.h
index 7b82daf..1e82e2e9 100644
--- a/chrome/browser/performance_manager/public/graph/page_node.h
+++ b/chrome/browser/performance_manager/public/graph/page_node.h
@@ -140,16 +140,16 @@
   virtual void OnPageOriginTrialFreezePolicyChanged(
       const PageNode* page_node) = 0;
 
+  // Invoked when the MainFrameUrl property changes.
+  virtual void OnMainFrameUrlChanged(const PageNode* page_node) = 0;
+
   // Invoked when the PageAlmostIdle property changes.
   virtual void OnPageAlmostIdleChanged(const PageNode* page_node) = 0;
 
-  // This is fired when a main frame navigation commits. It indicates that the
-  // |main_frame_url| and possibly the |navigation_id| properties have changed.
-  // Prior to loading and initial navigation of page, the |main_frame_url| can
-  // change, while the |navigation_id| stays zero.
-  // TODO(siggi): Maybe #hash navigation can work the same way, or perhaps the
-  //     two each properties deserve their own notification?
-  virtual void OnMainFrameNavigationCommitted(const PageNode* page_node) = 0;
+  // This is fired when a non-same document navigation commits in the main
+  // frame. It indicates that the the |NavigationId| property and possibly the
+  // |MainFrameUrl| properties have changed.
+  virtual void OnMainFrameDocumentChanged(const PageNode* page_node) = 0;
 
   // Events with no property changes.
 
@@ -184,7 +184,8 @@
   void OnPageOriginTrialFreezePolicyChanged(
       const PageNode* page_node) override {}
   void OnPageAlmostIdleChanged(const PageNode* page_node) override {}
-  void OnMainFrameNavigationCommitted(const PageNode* page_node) override {}
+  void OnMainFrameUrlChanged(const PageNode* page_node) override {}
+  void OnMainFrameDocumentChanged(const PageNode* page_node) override {}
   void OnTitleUpdated(const PageNode* page_node) override {}
   void OnFaviconUpdated(const PageNode* page_node) override {}
 
diff --git a/chrome/browser/performance_manager/test_support/graph_test_harness.h b/chrome/browser/performance_manager/test_support/graph_test_harness.h
index 0e22103..c517e0e 100644
--- a/chrome/browser/performance_manager/test_support/graph_test_harness.h
+++ b/chrome/browser/performance_manager/test_support/graph_test_harness.h
@@ -107,10 +107,11 @@
       GraphImpl* graph,
       const WebContentsProxy& wc_proxy = WebContentsProxy(),
       const std::string& browser_context_id = std::string(),
+      const GURL& url = GURL(),
       bool is_visible = false,
       bool is_audible = false) {
     return std::make_unique<PageNodeImpl>(graph, wc_proxy, browser_context_id,
-                                          is_visible, is_audible);
+                                          url, is_visible, is_audible);
   }
 };
 
diff --git a/chrome/browser/platform_util_unittest.cc b/chrome/browser/platform_util_unittest.cc
index 3704d421..ff182eb 100644
--- a/chrome/browser/platform_util_unittest.cc
+++ b/chrome/browser/platform_util_unittest.cc
@@ -252,7 +252,8 @@
 // ChromeOS doesn't follow symbolic links in sandboxed filesystems. So all the
 // symbolic link tests should return PATH_NOT_FOUND.
 
-TEST_F(PlatformUtilPosixTest, OpenFileWithPosixSymlinksChromeOS) {
+// Very flaky due to memory unsafety: crbug.com/1007240
+TEST_F(PlatformUtilPosixTest, DISABLED_OpenFileWithPosixSymlinksChromeOS) {
   EXPECT_EQ(OPEN_FAILED_PATH_NOT_FOUND,
             CallOpenItem(symlink_to_file_, OPEN_FILE));
   EXPECT_EQ(OPEN_FAILED_PATH_NOT_FOUND,
@@ -270,7 +271,8 @@
             CallOpenItem(symlink_to_nowhere_, OPEN_FOLDER));
 }
 
-TEST_F(PlatformUtilTest, OpenFileWithUnhandledFileType) {
+// Very flaky due to memory unsafety: crbug.com/1007240
+TEST_F(PlatformUtilTest, DISABLED_OpenFileWithUnhandledFileType) {
   base::FilePath unhandled_file =
       directory_.GetPath().AppendASCII("myfile.filetype");
   ASSERT_EQ(3, base::WriteFile(unhandled_file, "cat", 3));
diff --git a/chrome/browser/policy/policy_test_utils.cc b/chrome/browser/policy/policy_test_utils.cc
index 9f2ff884..3ed7f00 100644
--- a/chrome/browser/policy/policy_test_utils.cc
+++ b/chrome/browser/policy/policy_test_utils.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/policy/policy_test_utils.h"
 
+#include "base/message_loop/message_loop_current.h"
 #include "base/path_service.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
diff --git a/chrome/browser/resource_coordinator/tab_manager_stats_collector_unittest.cc b/chrome/browser/resource_coordinator/tab_manager_stats_collector_unittest.cc
index d7d999d..c92c059 100644
--- a/chrome/browser/resource_coordinator/tab_manager_stats_collector_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_stats_collector_unittest.cc
@@ -10,6 +10,7 @@
 
 #include "base/bind.h"
 #include "base/macros.h"
+#include "base/message_loop/message_loop_current.h"
 #include "base/metrics/metrics_hashes.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/simple_test_tick_clock.h"
diff --git a/chrome/browser/resources/chromeos/camera/src/css/main.css b/chrome/browser/resources/chromeos/camera/src/css/main.css
index 571d1e2..b8ba077 100644
--- a/chrome/browser/resources/chromeos/camera/src/css/main.css
+++ b/chrome/browser/resources/chromeos/camera/src/css/main.css
@@ -259,11 +259,14 @@
   z-index: 0;
 }
 
-#modes-group.hide,
-.mode-item.hide {
+#modes-group.hide {
   visibility: hidden;
 }
 
+.mode-item.hide {
+  display: none;
+}
+
 .mode-item>input {
   height: 100%;
   position: absolute;
diff --git a/chrome/browser/resources/chromeos/login/oobe_update.html b/chrome/browser/resources/chromeos/login/oobe_update.html
index 8a06be5..f1afb3c 100644
--- a/chrome/browser/resources/chromeos/login/oobe_update.html
+++ b/chrome/browser/resources/chromeos/login/oobe_update.html
@@ -30,6 +30,9 @@
         aria-live="polite" id="checking-for-updates-dialog">
       <iron-icon icon="oobe-update:googleg" slot="oobe-icon"></iron-icon>
       <h1 slot="title" i18n-content="checkingForUpdates"></h1>
+      <div slot="subtitle" class="update-subtitle" id="checkingForUpdatesMsg"
+          i18n-content="checkingForUpdatesMsg">
+      </div>
       <div slot="subtitle" class="update-subtitle" id="checkingForUpdateCancelHint"
           i18n-content="cancelUpdateHint" hidden="[[!cancelAllowed]]">
       </div>
diff --git a/chrome/browser/resources/local_ntp/doodles.css b/chrome/browser/resources/local_ntp/doodles.css
index 885619d..ca9a379 100644
--- a/chrome/browser/resources/local_ntp/doodles.css
+++ b/chrome/browser/resources/local_ntp/doodles.css
@@ -263,7 +263,8 @@
 #ddlsd-title {
   color: #212121;
   font-size: 22px;
-  padding: 0 40px 16px 0;
+  padding-bottom: 16px;
+  padding-inline-end: 40px;
 }
 
 @media (prefers-color-scheme: dark) {
@@ -273,7 +274,6 @@
 }
 
 #ddlsd-close {
-  background: url(icons/close.svg) no-repeat;
   height: 24px;
   position: absolute;
   right: 22px;
@@ -281,6 +281,29 @@
   width: 24px;
 }
 
+[dir=rtl] #ddlsd-close {
+  left: 22px;
+  right: auto;
+}
+
+#ddlsd-close::before {
+  -webkit-mask-image: url(../../../../ui/webui/resources/images/icon_clear.svg);
+  -webkit-mask-position: center center;
+  -webkit-mask-repeat: no-repeat;
+  -webkit-mask-size: 32px;
+  background-color: #4d4d4d;
+  content: '';
+  display: block;
+  height: 100%;
+  width: 100%;
+}
+
+@media (prefers-color-scheme: dark) {
+  #ddlsd-close::before {
+    background-color: rgb(var(--GG500-rgb));
+  }
+}
+
 #ddlsd-fbb {
   background: url(icons/facebook.svg) no-repeat center;
 }
@@ -315,7 +338,6 @@
   background: url(icons/copy.svg) no-repeat center;
   background-size: contain;
   display: inline-block;
-  float: right;
   height: 36px;
   margin: 5px;
   width: 36px;
@@ -338,8 +360,8 @@
 }
 
 #ddlsd-link {
+  display: flex;
   margin: 6px;
-  overflow: hidden;
 }
 
 #ddlsd-text-ctr {
diff --git a/chrome/browser/resources/local_ntp/icons/close.svg b/chrome/browser/resources/local_ntp/icons/close.svg
deleted file mode 100644
index 282fa77..0000000
--- a/chrome/browser/resources/local_ntp/icons/close.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><defs><style>.a{fill:none;stroke:#4d4d4d;stroke-miterlimit:10;stroke-width:3px}</style></defs><path class="a" d="M3.5 3.5L21 21M3.5 21L21 3.5"/></svg>
\ No newline at end of file
diff --git a/chrome/browser/resources/local_ntp/local_ntp.html b/chrome/browser/resources/local_ntp/local_ntp.html
index ac5bac8b..5690800 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.html
+++ b/chrome/browser/resources/local_ntp/local_ntp.html
@@ -157,10 +157,10 @@
       <button id="ddlsd-emb" class="ddlsd-sbtn"></button>
       <hr id="ddlsd-hr">
       <div id="ddlsd-link">
-        <button id="ddlsd-copy"></button>
         <span id="ddlsd-text-ctr">
           <input type="text" id="ddlsd-text" dir="ltr">
         </span>
+        <button id="ddlsd-copy"></button>
       </div>
     </div>
   </dialog>
diff --git a/chrome/browser/safe_browsing/browser_feature_extractor_unittest.cc b/chrome/browser/safe_browsing/browser_feature_extractor_unittest.cc
index bccb9561..e5d5bcb 100644
--- a/chrome/browser/safe_browsing/browser_feature_extractor_unittest.cc
+++ b/chrome/browser/safe_browsing/browser_feature_extractor_unittest.cc
@@ -11,7 +11,7 @@
 
 #include "base/bind.h"
 #include "base/macros.h"
-#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
 #include "base/time/time.h"
diff --git a/chrome/browser/safe_browsing/client_side_detection_host.cc b/chrome/browser/safe_browsing/client_side_detection_host.cc
index 04bdf84..c93ee3e 100644
--- a/chrome/browser/safe_browsing/client_side_detection_host.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_host.cc
@@ -508,7 +508,9 @@
     DVLOG(1) << "Instruct renderer to start phishing detection for URL: "
              << browse_info_->url;
     content::RenderFrameHost* rfh = web_contents()->GetMainFrame();
-    rfh->GetRemoteInterfaces()->GetInterface(&phishing_detector_);
+    phishing_detector_.reset();
+    rfh->GetRemoteInterfaces()->GetInterface(
+        phishing_detector_.BindNewPipeAndPassReceiver());
     phishing_detector_->StartPhishingDetection(
         browse_info_->url,
         base::BindRepeating(&ClientSideDetectionHost::PhishingDetectionDone,
diff --git a/chrome/browser/safe_browsing/client_side_detection_host.h b/chrome/browser/safe_browsing/client_side_detection_host.h
index a946471b..95b35a6 100644
--- a/chrome/browser/safe_browsing/client_side_detection_host.h
+++ b/chrome/browser/safe_browsing/client_side_detection_host.h
@@ -18,7 +18,7 @@
 #include "components/safe_browsing/common/safe_browsing.mojom.h"
 #include "components/safe_browsing/db/database_manager.h"
 #include "content/public/browser/web_contents_observer.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
 #include "url/gurl.h"
 
@@ -155,7 +155,7 @@
   // Current host, used to help determine cur_host_redirects_.
   std::string cur_host_;
   // The currently active message pipe to the renderer PhishingDetector.
-  mojom::PhishingDetectorPtr phishing_detector_;
+  mojo::Remote<mojom::PhishingDetector> phishing_detector_;
 
   // Max number of ips we save for each browse
   static const size_t kMaxIPsPerBrowse;
diff --git a/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc b/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
index 4053ff0..c5d5bf4 100644
--- a/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
@@ -39,6 +39,8 @@
 #include "content/public/test/test_renderer_host.h"
 #include "content/public/test/web_contents_tester.h"
 #include "ipc/ipc_test_sink.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -205,9 +207,9 @@
 
   ~FakePhishingDetector() override = default;
 
-  void BindRequest(mojo::ScopedMessagePipeHandle handle) {
-    bindings_.AddBinding(this,
-                         mojom::PhishingDetectorRequest(std::move(handle)));
+  void BindReceiver(mojo::ScopedMessagePipeHandle handle) {
+    receivers_.Add(this, mojo::PendingReceiver<mojom::PhishingDetector>(
+                             std::move(handle)));
   }
 
   // mojom::PhishingDetector
@@ -241,7 +243,7 @@
   }
 
  private:
-  mojo::BindingSet<mojom::PhishingDetector> bindings_;
+  mojo::ReceiverSet<mojom::PhishingDetector> receivers_;
   bool phishing_detection_started_ = false;
   GURL url_;
 
@@ -263,7 +265,7 @@
 
     test_api.SetBinderForName(
         mojom::PhishingDetector::Name_,
-        base::BindRepeating(&FakePhishingDetector::BindRequest,
+        base::BindRepeating(&FakePhishingDetector::BindReceiver,
                             base::Unretained(&fake_phishing_detector_)));
   }
 
diff --git a/chrome/browser/signin/account_consistency_mode_manager.cc b/chrome/browser/signin/account_consistency_mode_manager.cc
index 8bf187e..e52abb7 100644
--- a/chrome/browser/signin/account_consistency_mode_manager.cc
+++ b/chrome/browser/signin/account_consistency_mode_manager.cc
@@ -298,12 +298,8 @@
     if (IsDiceMigrationCompleted(profile))
       return AccountConsistencyMethod::kDice;
 
-    if (!IsReadyForDiceMigration(profile) &&
-        profile->GetPrefs()->GetBoolean(prefs::kTokenServiceDiceCompatible) &&
-        base::FeatureList::IsEnabled(kForceDiceMigration)) {
-      // Force migration to Dice.
+    if (base::FeatureList::IsEnabled(kForceDiceMigration))
       return AccountConsistencyMethod::kDice;
-    }
   }
 
   return method;
diff --git a/chrome/browser/signin/e2e_tests/demo_signin_e2e_test.cc b/chrome/browser/signin/e2e_tests/demo_signin_e2e_test.cc
index 5f12702..d7a40fc 100644
--- a/chrome/browser/signin/e2e_tests/demo_signin_e2e_test.cc
+++ b/chrome/browser/signin/e2e_tests/demo_signin_e2e_test.cc
@@ -2,25 +2,106 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/strings/stringprintf.h"
 #include "chrome/browser/signin/e2e_tests/live_test.h"
 #include "chrome/browser/signin/e2e_tests/test_accounts_util.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "chrome/browser/ui/webui/signin/login_ui_test_utils.h"
-#include "content/public/test/browser_test_utils.h"
-#include "content/public/test/test_utils.h"
+#include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h"
+#include "components/signin/public/identity_manager/identity_manager.h"
+#include "components/signin/public/identity_manager/test_identity_manager_observer.h"
+#include "google_apis/gaia/gaia_urls.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
 
-using signin::test::TestAccount;
-using signin::test::TestAccountsUtil;
+namespace signin {
+namespace test {
 
-class DemoSignInTest : public signin::test::LiveTest {};
+// IdentityManager observer allowing to wait for sign out events for several
+// accounts.
+class SignOutTestObserver : public IdentityManager::Observer {
+ public:
+  explicit SignOutTestObserver(IdentityManager* identity_manager)
+      : identity_manager_(identity_manager) {
+    identity_manager_->AddObserver(this);
+  }
+  ~SignOutTestObserver() override { identity_manager_->RemoveObserver(this); }
 
+  void OnRefreshTokenRemovedForAccount(
+      const CoreAccountId& account_id) override {
+    ++signed_out_accounts_;
+    if (expected_accounts_ != -1 && signed_out_accounts_ >= expected_accounts_)
+      run_loop_.Quit();
+  }
+
+  void WaitForRefreshTokenRemovedForAccounts(int expected_accounts) {
+    expected_accounts_ = expected_accounts;
+    if (signed_out_accounts_ >= expected_accounts_)
+      return;
+
+    run_loop_.Run();
+  }
+
+ private:
+  signin::IdentityManager* identity_manager_;
+  base::RunLoop run_loop_;
+  int signed_out_accounts_ = 0;
+  int expected_accounts_ = -1;
+};
+
+// Live tests for SignIn.
+class DemoSignInTest : public signin::test::LiveTest {
+ public:
+  DemoSignInTest() = default;
+  ~DemoSignInTest() override = default;
+
+  void SetUp() override {
+    LiveTest::SetUp();
+    // Always disable animation for stability.
+    ui::ScopedAnimationDurationScaleMode disable_animation(
+        ui::ScopedAnimationDurationScaleMode::ZERO_DURATION);
+  }
+
+  void SignInFromWeb(const TestAccount& test_account) {
+    AddTabAtIndex(0, GaiaUrls::GetInstance()->add_account_url(),
+                  ui::PageTransition::PAGE_TRANSITION_TYPED);
+    SignInFromCurrentPage(test_account);
+  }
+
+  void SignInFromCurrentPage(const TestAccount& test_account) {
+    TestIdentityManagerObserver observer(identity_manager());
+    base::RunLoop cookie_update_loop;
+    observer.SetOnAccountsInCookieUpdatedCallback(
+        cookie_update_loop.QuitClosure());
+    base::RunLoop refresh_token_update_loop;
+    observer.SetOnRefreshTokenUpdatedCallback(
+        refresh_token_update_loop.QuitClosure());
+    login_ui_test_utils::ExecuteJsToSigninInSigninFrame(
+        browser(), test_account.user, test_account.password);
+    cookie_update_loop.Run();
+    refresh_token_update_loop.Run();
+  }
+
+  void SignOutFromWeb(size_t signed_in_accounts) {
+    TestIdentityManagerObserver observer(identity_manager());
+    base::RunLoop cookie_update_loop;
+    observer.SetOnAccountsInCookieUpdatedCallback(
+        cookie_update_loop.QuitClosure());
+    SignOutTestObserver sign_out_observer(identity_manager());
+    AddTabAtIndex(0, GaiaUrls::GetInstance()->service_logout_url(),
+                  ui::PageTransition::PAGE_TRANSITION_TYPED);
+    cookie_update_loop.Run();
+    sign_out_observer.WaitForRefreshTokenRemovedForAccounts(signed_in_accounts);
+  }
+
+  signin::IdentityManager* identity_manager() {
+    return IdentityManagerFactory::GetForProfile(browser()->profile());
+  }
+};
+
+// Sings in an account through the settings page and checks that the account is
+// added to Chrome. Sync should be disabled.
 IN_PROC_BROWSER_TEST_F(DemoSignInTest, SimpleSignInFlow) {
-  // Always disable animation for stability.
-  ui::ScopedAnimationDurationScaleMode disable_animation(
-      ui::ScopedAnimationDurationScaleMode::ZERO_DURATION);
   GURL url("chrome://settings");
   AddTabAtIndex(0, url, ui::PageTransition::PAGE_TRANSITION_TYPED);
   auto* settings_tab = browser()->tab_strip_model()->GetActiveWebContents();
@@ -31,14 +112,63 @@
       "testElement.$$('#sign-in').click();"));
   TestAccount ta;
   CHECK(GetTestAccountsUtil()->GetAccount("TEST_ACCOUNT_1", ta));
-  login_ui_test_utils::ExecuteJsToSigninInSigninFrame(browser(), ta.user,
-                                                      ta.password);
-  login_ui_test_utils::DismissSyncConfirmationDialog(
-      browser(), base::TimeDelta::FromSeconds(3));
-  GURL signin("chrome://signin-internals");
-  AddTabAtIndex(0, signin, ui::PageTransition::PAGE_TRANSITION_TYPED);
-  auto* signin_tab = browser()->tab_strip_model()->GetActiveWebContents();
-  std::string query_str = base::StringPrintf(
-      "document.body.innerHTML.indexOf('%s');", ta.user.c_str());
-  EXPECT_GT(content::EvalJs(signin_tab, query_str).ExtractInt(), 0);
+  SignInFromCurrentPage(ta);
+
+  const AccountsInCookieJarInfo& accounts_in_cookie_jar =
+      identity_manager()->GetAccountsInCookieJar();
+  EXPECT_TRUE(accounts_in_cookie_jar.accounts_are_fresh);
+  ASSERT_EQ(1u, accounts_in_cookie_jar.signed_in_accounts.size());
+  EXPECT_TRUE(accounts_in_cookie_jar.signed_out_accounts.empty());
+  const gaia::ListedAccount& account =
+      accounts_in_cookie_jar.signed_in_accounts[0];
+  EXPECT_TRUE(gaia::AreEmailsSame(ta.user, account.email));
+  EXPECT_TRUE(identity_manager()->HasAccountWithRefreshToken(account.id));
+  EXPECT_FALSE(identity_manager()->HasPrimaryAccount());
 }
+
+// Sings in two accounts on the web and checks that cookies and refresh tokens
+// are added to Chrome. Sync should be disabled.
+// Then, signs out on the web and checks that accounts are removed from Chrome.
+IN_PROC_BROWSER_TEST_F(DemoSignInTest, WebSignInAndSignOut) {
+  TestAccount test_account_1;
+  CHECK(GetTestAccountsUtil()->GetAccount("TEST_ACCOUNT_1", test_account_1));
+  SignInFromWeb(test_account_1);
+
+  const AccountsInCookieJarInfo& accounts_in_cookie_jar_1 =
+      identity_manager()->GetAccountsInCookieJar();
+  EXPECT_TRUE(accounts_in_cookie_jar_1.accounts_are_fresh);
+  ASSERT_EQ(1u, accounts_in_cookie_jar_1.signed_in_accounts.size());
+  EXPECT_TRUE(accounts_in_cookie_jar_1.signed_out_accounts.empty());
+  const gaia::ListedAccount& account_1 =
+      accounts_in_cookie_jar_1.signed_in_accounts[0];
+  EXPECT_TRUE(gaia::AreEmailsSame(test_account_1.user, account_1.email));
+  EXPECT_TRUE(identity_manager()->HasAccountWithRefreshToken(account_1.id));
+  EXPECT_FALSE(identity_manager()->HasPrimaryAccount());
+
+  TestAccount test_account_2;
+  CHECK(GetTestAccountsUtil()->GetAccount("TEST_ACCOUNT_2", test_account_2));
+  SignInFromWeb(test_account_2);
+
+  const AccountsInCookieJarInfo& accounts_in_cookie_jar_2 =
+      identity_manager()->GetAccountsInCookieJar();
+  EXPECT_TRUE(accounts_in_cookie_jar_2.accounts_are_fresh);
+  ASSERT_EQ(2u, accounts_in_cookie_jar_2.signed_in_accounts.size());
+  EXPECT_TRUE(accounts_in_cookie_jar_2.signed_out_accounts.empty());
+  EXPECT_EQ(accounts_in_cookie_jar_2.signed_in_accounts[0].id, account_1.id);
+  const gaia::ListedAccount& account_2 =
+      accounts_in_cookie_jar_2.signed_in_accounts[1];
+  EXPECT_TRUE(gaia::AreEmailsSame(test_account_2.user, account_2.email));
+  EXPECT_TRUE(identity_manager()->HasAccountWithRefreshToken(account_2.id));
+  EXPECT_FALSE(identity_manager()->HasPrimaryAccount());
+
+  SignOutFromWeb(2);
+
+  const AccountsInCookieJarInfo& accounts_in_cookie_jar_3 =
+      identity_manager()->GetAccountsInCookieJar();
+  EXPECT_TRUE(accounts_in_cookie_jar_3.accounts_are_fresh);
+  ASSERT_TRUE(accounts_in_cookie_jar_3.signed_in_accounts.empty());
+  EXPECT_EQ(2u, accounts_in_cookie_jar_3.signed_out_accounts.size());
+}
+
+}  // namespace test
+}  // namespace signin
diff --git a/chrome/browser/sync/test/integration/encryption_helper.cc b/chrome/browser/sync/test/integration/encryption_helper.cc
index 4d5a0e6..6205c96 100644
--- a/chrome/browser/sync/test/integration/encryption_helper.cc
+++ b/chrome/browser/sync/test/integration/encryption_helper.cc
@@ -27,10 +27,11 @@
   return true;
 }
 
-void InitCustomPassphraseCryptographerFromNigori(
+std::unique_ptr<syncer::Cryptographer>
+InitCustomPassphraseCryptographerFromNigori(
     const sync_pb::NigoriSpecifics& nigori,
-    syncer::Cryptographer* cryptographer,
     const std::string& passphrase) {
+  auto cryptographer = std::make_unique<syncer::DirectoryCryptographer>();
   sync_pb::EncryptedData keybag = nigori.encryption_keybag();
   cryptographer->SetPendingKeys(keybag);
 
@@ -38,22 +39,24 @@
   switch (syncer::ProtoKeyDerivationMethodToEnum(
       nigori.custom_passphrase_key_derivation_method())) {
     case syncer::KeyDerivationMethod::PBKDF2_HMAC_SHA1_1003:
-      ASSERT_TRUE(cryptographer->DecryptPendingKeys(
+      EXPECT_TRUE(cryptographer->DecryptPendingKeys(
           {syncer::KeyDerivationParams::CreateForPbkdf2(), passphrase}));
       break;
     case syncer::KeyDerivationMethod::SCRYPT_8192_8_11:
-      ASSERT_TRUE(base::Base64Decode(
+      EXPECT_TRUE(base::Base64Decode(
           nigori.custom_passphrase_key_derivation_salt(), &decoded_salt));
-      ASSERT_TRUE(cryptographer->DecryptPendingKeys(
+      EXPECT_TRUE(cryptographer->DecryptPendingKeys(
           {syncer::KeyDerivationParams::CreateForScrypt(decoded_salt),
            passphrase}));
       break;
     case syncer::KeyDerivationMethod::UNSUPPORTED:
       // This test cannot pass since we wouldn't know how to decrypt data
       // encrypted using an unsupported method.
-      FAIL() << "Unsupported key derivation method encountered: "
-             << nigori.custom_passphrase_key_derivation_method();
+      ADD_FAILURE() << "Unsupported key derivation method encountered: "
+                    << nigori.custom_passphrase_key_derivation_method();
   }
+
+  return cryptographer;
 }
 
 sync_pb::NigoriSpecifics CreateCustomPassphraseNigori(
@@ -95,7 +98,7 @@
   // keybag using a key derived from that passphrase). However, in some migrated
   // states, the keybag might also additionally contain an old, pre-migration
   // key.
-  syncer::Cryptographer cryptographer;
+  syncer::DirectoryCryptographer cryptographer;
   bool add_key_result = cryptographer.AddKey(params);
   DCHECK(add_key_result);
   bool get_keys_result =
@@ -112,7 +115,7 @@
 
   sync_pb::EntitySpecifics wrapped_entity_specifics;
   *wrapped_entity_specifics.mutable_bookmark() = bookmark_specifics;
-  syncer::Cryptographer cryptographer;
+  syncer::DirectoryCryptographer cryptographer;
   bool add_key_result = cryptographer.AddKey(key_params);
   DCHECK(add_key_result);
   bool encrypt_result = cryptographer.Encrypt(
diff --git a/chrome/browser/sync/test/integration/encryption_helper.h b/chrome/browser/sync/test/integration/encryption_helper.h
index aa4cf09b..4166bba 100644
--- a/chrome/browser/sync/test/integration/encryption_helper.h
+++ b/chrome/browser/sync/test/integration/encryption_helper.h
@@ -5,12 +5,13 @@
 #ifndef CHROME_BROWSER_SYNC_TEST_INTEGRATION_ENCRYPTION_HELPER_H_
 #define CHROME_BROWSER_SYNC_TEST_INTEGRATION_ENCRYPTION_HELPER_H_
 
+#include <memory>
 #include <string>
 
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/sync/test/integration/single_client_status_change_checker.h"
-#include "components/sync/nigori/cryptographer.h"
 #include "components/sync/protocol/nigori_specifics.pb.h"
+#include "components/sync/syncable/directory_cryptographer.h"
 #include "components/sync/test/fake_server/fake_server.h"
 
 namespace encryption_helper {
@@ -30,9 +31,9 @@
 // Nigori is encrypted (by design), the provided |passphrase| will be used to
 // decrypt it. This function will fail the test (using ASSERT) if the Nigori is
 // not a custom passphrase one, or if the key cannot be decrypted.
-void InitCustomPassphraseCryptographerFromNigori(
+std::unique_ptr<syncer::Cryptographer>
+InitCustomPassphraseCryptographerFromNigori(
     const sync_pb::NigoriSpecifics& nigori,
-    syncer::Cryptographer* cryptographer,
     const std::string& passphrase);
 
 // Returns an EntitySpecifics containing encrypted data corresponding to the
diff --git a/chrome/browser/sync/test/integration/single_client_custom_passphrase_sync_test.cc b/chrome/browser/sync/test/integration/single_client_custom_passphrase_sync_test.cc
index f920849..b067adc1 100644
--- a/chrome/browser/sync/test/integration/single_client_custom_passphrase_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_custom_passphrase_sync_test.cc
@@ -144,10 +144,7 @@
     EXPECT_TRUE(GetServerNigori(GetFakeServer(), &nigori));
     EXPECT_EQ(ProtoPassphraseInt32ToEnum(nigori.passphrase_type()),
               PassphraseType::kCustomPassphrase);
-    auto cryptographer = std::make_unique<Cryptographer>();
-    InitCustomPassphraseCryptographerFromNigori(nigori, cryptographer.get(),
-                                                passphrase);
-    return cryptographer;
+    return InitCustomPassphraseCryptographerFromNigori(nigori, passphrase);
   }
 
   // A cryptographer initialized with the given KeyParams has not "seen" the
@@ -155,7 +152,7 @@
   // does not depend on external info.
   std::unique_ptr<Cryptographer> CreateCryptographerWithKeyParams(
       const KeyParams& key_params) {
-    auto cryptographer = std::make_unique<Cryptographer>();
+    auto cryptographer = std::make_unique<syncer::DirectoryCryptographer>();
     cryptographer->AddKey(key_params);
     return cryptographer;
   }
diff --git a/chrome/browser/sync/test/integration/single_client_passwords_sync_test.cc b/chrome/browser/sync/test/integration/single_client_passwords_sync_test.cc
index f781c80..8f6ede2 100644
--- a/chrome/browser/sync/test/integration/single_client_passwords_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_passwords_sync_test.cc
@@ -20,7 +20,7 @@
 #include "components/sync/base/time.h"
 #include "components/sync/driver/profile_sync_service.h"
 #include "components/sync/driver/sync_driver_switches.h"
-#include "components/sync/nigori/cryptographer.h"
+#include "components/sync/syncable/directory_cryptographer.h"
 
 namespace {
 
@@ -52,7 +52,7 @@
 sync_pb::PasswordSpecifics EncryptPasswordSpecifics(
     const syncer::KeyParams& key_params,
     const sync_pb::PasswordSpecificsData& password_data) {
-  syncer::Cryptographer cryptographer;
+  syncer::DirectoryCryptographer cryptographer;
   cryptographer.AddKey(key_params);
 
   sync_pb::PasswordSpecifics encrypted_specifics;
@@ -338,12 +338,12 @@
     nigori.set_encrypt_everything(false);
     nigori.set_passphrase_type(sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE);
 
-    syncer::Cryptographer cryptographer;
+    syncer::DirectoryCryptographer cryptographer;
     ASSERT_TRUE(cryptographer.AddKey(key_params));
     ASSERT_TRUE(cryptographer.AddNonDefaultKey(key_params));
     ASSERT_TRUE(cryptographer.GetKeys(nigori.mutable_encryption_keybag()));
 
-    syncer::Cryptographer keystore_cryptographer;
+    syncer::DirectoryCryptographer keystore_cryptographer;
     ASSERT_TRUE(keystore_cryptographer.AddKey(key_params));
     ASSERT_TRUE(keystore_cryptographer.EncryptString(
         cryptographer.GetDefaultNigoriKeyData(),
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 3ffd157..ac801fb4 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1894,6 +1894,7 @@
       "webui/version_handler_chromeos.h",
       "window_sizer/window_sizer_ash.cc",
     ]
+
     deps += [
       "//ash",
       "//ash/components/shortcut_viewer",
@@ -1901,6 +1902,7 @@
       "//ash/public/cpp",
       "//ash/public/cpp/resources:ash_public_unscaled_resources",
       "//ash/public/cpp/vector_icons",
+      "//build:branding_buildflags",
       "//chrome/browser/chromeos",
       "//chrome/browser/chromeos:backdrop_wallpaper_proto",
       "//chrome/browser/resources/chromeos:camera_resources",
diff --git a/chrome/browser/ui/ash/chrome_screenshot_grabber.cc b/chrome/browser/ui/ash/chrome_screenshot_grabber.cc
index 82ba484..9c35f13 100644
--- a/chrome/browser/ui/ash/chrome_screenshot_grabber.cc
+++ b/chrome/browser/ui/ash/chrome_screenshot_grabber.cc
@@ -18,7 +18,7 @@
 #include "base/files/file_util.h"
 #include "base/i18n/time_formatting.h"
 #include "base/macros.h"
-#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
 #include "base/metrics/user_metrics.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/chrome/browser/ui/ash/media_client_impl.cc b/chrome/browser/ui/ash/media_client_impl.cc
index 44b0a144..f07830e 100644
--- a/chrome/browser/ui/ash/media_client_impl.cc
+++ b/chrome/browser/ui/ash/media_client_impl.cc
@@ -10,7 +10,7 @@
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/chromeos/extensions/media_player_api.h"
diff --git a/chrome/browser/ui/views/menu_model_adapter_test.cc b/chrome/browser/ui/views/menu_model_adapter_test.cc
index 8fbf146..0be63a5 100644
--- a/chrome/browser/ui/views/menu_model_adapter_test.cc
+++ b/chrome/browser/ui/views/menu_model_adapter_test.cc
@@ -6,7 +6,7 @@
 #include "base/callback.h"
 #include "base/location.h"
 #include "base/macros.h"
-#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
diff --git a/chrome/browser/ui/views/profiles/avatar_toolbar_button.cc b/chrome/browser/ui/views/profiles/avatar_toolbar_button.cc
index 3caba49..96b279c 100644
--- a/chrome/browser/ui/views/profiles/avatar_toolbar_button.cc
+++ b/chrome/browser/ui/views/profiles/avatar_toolbar_button.cc
@@ -224,6 +224,8 @@
 
 void AvatarToolbarButton::NotifyClick(const ui::Event& event) {
   Button::NotifyClick(event);
+  if (should_reset_user_email_when_no_longer_hovered_or_focused_)
+    ResetUserEmailWhenNotHoveredOrFocused();
   // TODO(bsep): Other toolbar buttons have ToolbarView as a listener and let it
   // call ExecuteCommandWithDisposition on their behalf. Unfortunately, it's not
   // possible to plumb IsKeyEvent through, so this has to be a special case.
@@ -233,6 +235,18 @@
       event.IsKeyEvent());
 }
 
+void AvatarToolbarButton::OnMouseExited(const ui::MouseEvent& event) {
+  if (should_reset_user_email_when_no_longer_hovered_or_focused_)
+    ResetUserEmailWhenNotHoveredOrFocused();
+  ToolbarButton::OnMouseExited(event);
+}
+
+void AvatarToolbarButton::OnBlur() {
+  if (should_reset_user_email_when_no_longer_hovered_or_focused_)
+    ResetUserEmailWhenNotHoveredOrFocused();
+  ToolbarButton::OnBlur();
+}
+
 void AvatarToolbarButton::OnThemeChanged() {
   ToolbarButton::OnThemeChanged();
   UpdateIcon();
@@ -336,11 +350,28 @@
   // Hide the pill after a while.
   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
-      base::BindOnce(&AvatarToolbarButton::ResetUserEmail,
-                     weak_ptr_factory_.GetWeakPtr()),
+      base::BindOnce(
+          &AvatarToolbarButton::ResetUserEmailWhenNotHoveredOrFocused,
+          weak_ptr_factory_.GetWeakPtr()),
       kEmailExpansionDuration);
 }
 
+void AvatarToolbarButton::ResetUserEmailWhenNotHoveredOrFocused() {
+  // No-op if it has been reset already.
+  if (!user_email_)
+    return;
+
+  // Keep email visible while hovering or being focused.
+  if (IsMouseHovered() || HasFocus()) {
+    // TODO(crbug.com/967317): Include also the case when some other button from
+    // the parent container is shown and hovered / focused.
+    should_reset_user_email_when_no_longer_hovered_or_focused_ = true;
+    return;
+  }
+  should_reset_user_email_when_no_longer_hovered_or_focused_ = false;
+  ResetUserEmail();
+}
+
 void AvatarToolbarButton::ResetUserEmail() {
   DCHECK(user_email_.has_value());
   user_email_ = base::nullopt;
diff --git a/chrome/browser/ui/views/profiles/avatar_toolbar_button.h b/chrome/browser/ui/views/profiles/avatar_toolbar_button.h
index 72073d7..24e0ba68 100644
--- a/chrome/browser/ui/views/profiles/avatar_toolbar_button.h
+++ b/chrome/browser/ui/views/profiles/avatar_toolbar_button.h
@@ -56,6 +56,8 @@
 
   // ToolbarButton:
   void NotifyClick(const ui::Event& event) override;
+  void OnMouseExited(const ui::MouseEvent& event) override;
+  void OnBlur() override;
   void OnThemeChanged() override;
   void AddedToWidget() override;
 
@@ -93,6 +95,7 @@
   void OnCreditCardSaved() override;
 
   void ExpandToShowEmail();
+  void ResetUserEmailWhenNotHoveredOrFocused();
   void ResetUserEmail();
 
   base::string16 GetAvatarTooltipText() const;
@@ -130,6 +133,8 @@
   base::Optional<std::string> user_email_;
   // We cannot show the animation before we fetch the new avatar.
   bool waiting_for_image_to_show_user_email_ = false;
+  // We cannot hide the animation when the button is hovered or focused.
+  bool should_reset_user_email_when_no_longer_hovered_or_focused_ = false;
 
   ScopedObserver<ProfileAttributesStorage, ProfileAttributesStorage::Observer>
       profile_observer_{this};
diff --git a/chrome/browser/ui/views/simple_message_box_views.cc b/chrome/browser/ui/views/simple_message_box_views.cc
index 7128fa3..0a36db5 100644
--- a/chrome/browser/ui/views/simple_message_box_views.cc
+++ b/chrome/browser/ui/views/simple_message_box_views.cc
@@ -10,7 +10,7 @@
 #include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "base/macros.h"
-#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
 #include "base/run_loop.h"
 #include "build/build_config.h"
 #include "chrome/browser/ui/browser_dialogs.h"
diff --git a/chrome/browser/ui/views/toolbar/app_menu.cc b/chrome/browser/ui/views/toolbar/app_menu.cc
index 0a5201c..eea1608 100644
--- a/chrome/browser/ui/views/toolbar/app_menu.cc
+++ b/chrome/browser/ui/views/toolbar/app_menu.cc
@@ -471,13 +471,12 @@
     // the keyboard navigation to work.
     DCHECK(Button::AsButton(fullscreen_button_));
 
-    // TODO(https://crbug.com/957391): Do away with this bespoke color. Ideally
-    // this should be kColorId_EnabledMenuItemForegroundColor. The color here is
-    // ripped directly from the old PNG asset for this image.
     fullscreen_button_->SetImage(
         ImageButton::STATE_NORMAL,
-        gfx::CreateVectorIcon(kFullscreenIcon,
-                              SkColorSetRGB(0x98, 0x98, 0x98)));
+        gfx::CreateVectorIcon(
+            kFullscreenIcon,
+            GetNativeTheme()->GetSystemColor(
+                ui::NativeTheme::kColorId_EnabledMenuItemForegroundColor)));
 
     // Since |fullscreen_button_| will reside in a menu, make it ALWAYS
     // focusable regardless of the platform.
@@ -548,18 +547,16 @@
     zoom_label_max_width_valid_ = false;
 
     ui::NativeTheme* theme = GetNativeTheme();
-    if (theme) {
-      zoom_label_->SetEnabledColor(theme->GetSystemColor(
-          ui::NativeTheme::kColorId_EnabledMenuItemForegroundColor));
-      gfx::ImageSkia hovered_fullscreen_image = gfx::CreateVectorIcon(
-          kFullscreenIcon,
-          theme->GetSystemColor(
-              ui::NativeTheme::kColorId_SelectedMenuItemForegroundColor));
-      fullscreen_button_->SetImage(ImageButton::STATE_HOVERED,
-                                   hovered_fullscreen_image);
-      fullscreen_button_->SetImage(ImageButton::STATE_PRESSED,
-                                   hovered_fullscreen_image);
-    }
+    zoom_label_->SetEnabledColor(theme->GetSystemColor(
+        ui::NativeTheme::kColorId_EnabledMenuItemForegroundColor));
+    gfx::ImageSkia hovered_fullscreen_image = gfx::CreateVectorIcon(
+        kFullscreenIcon,
+        theme->GetSystemColor(
+            ui::NativeTheme::kColorId_SelectedMenuItemForegroundColor));
+    fullscreen_button_->SetImage(ImageButton::STATE_HOVERED,
+                                 hovered_fullscreen_image);
+    fullscreen_button_->SetImage(ImageButton::STATE_PRESSED,
+                                 hovered_fullscreen_image);
   }
 
   // Overridden from ButtonListener.
diff --git a/chrome/browser/ui/views/toolbar/toolbar_button.cc b/chrome/browser/ui/views/toolbar/toolbar_button.cc
index 3b9380bf..d621e6f 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_button.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_button.cc
@@ -120,10 +120,7 @@
 
 void ToolbarButton::ClearHighlight() {
   highlight_color_animation_.Hide();
-  // TODO(crbug.com/1002160): Support AnimatingLayoutManager by reporting
-  // preferred size without the label, clear the label only once the layout
-  // animation is completed.
-  LabelButton::SetText(base::string16());
+  ShrinkDownThenClearText();
 }
 
 void ToolbarButton::UpdateColorsAndInsets() {
diff --git a/chrome/browser/ui/webui/chromeos/account_manager_error_ui.cc b/chrome/browser/ui/webui/chromeos/account_manager_error_ui.cc
index 6db2f476..ed686a24 100644
--- a/chrome/browser/ui/webui/chromeos/account_manager_error_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/account_manager_error_ui.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/webui/chromeos/account_manager_error_ui.h"
 
 #include "base/bind.h"
+#include "build/branding_buildflags.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/common/webui_url_constants.h"
@@ -31,7 +32,7 @@
   html_source->AddLocalizedString(
       "errorMessage", IDS_ACCOUNT_MANAGER_SECONDARY_ACCOUNTS_DISABLED_TEXT);
   html_source->AddLocalizedString("okButton", IDS_APP_OK);
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   html_source->AddResourcePath("googleg.svg",
                                IDR_ACCOUNT_MANAGER_WELCOME_GOOGLE_LOGO_SVG);
 #endif
diff --git a/chrome/browser/ui/webui/discards/graph_dump_impl.cc b/chrome/browser/ui/webui/discards/graph_dump_impl.cc
index 4b1e847..9e19520 100644
--- a/chrome/browser/ui/webui/discards/graph_dump_impl.cc
+++ b/chrome/browser/ui/webui/discards/graph_dump_impl.cc
@@ -249,10 +249,10 @@
   StartPageFaviconRequest(page_node);
 }
 
-void DiscardsGraphDumpImpl::OnMainFrameNavigationCommitted(
+void DiscardsGraphDumpImpl::OnMainFrameUrlChanged(
     const performance_manager::PageNode* page_node) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   SendPageNotification(page_node, false);
-  StartPageFaviconRequest(page_node);
 }
 
 void DiscardsGraphDumpImpl::OnProcessNodeAdded(
diff --git a/chrome/browser/ui/webui/discards/graph_dump_impl.h b/chrome/browser/ui/webui/discards/graph_dump_impl.h
index f158ba6..c5c85ad3 100644
--- a/chrome/browser/ui/webui/discards/graph_dump_impl.h
+++ b/chrome/browser/ui/webui/discards/graph_dump_impl.h
@@ -98,11 +98,13 @@
   // Ignored.
   void OnPageOriginTrialFreezePolicyChanged(
       const performance_manager::PageNode* page_node) override {}
+  void OnMainFrameUrlChanged(
+      const performance_manager::PageNode* page_node) override;
   // Ignored.
   void OnPageAlmostIdleChanged(
       const performance_manager::PageNode* page_node) override {}
-  void OnMainFrameNavigationCommitted(
-      const performance_manager::PageNode* page_node) override;
+  void OnMainFrameDocumentChanged(
+      const performance_manager::PageNode* page_node) override {}
   void OnTitleUpdated(const performance_manager::PageNode* page_node) override {
   }  // Ignored.
   void OnFaviconUpdated(
diff --git a/chrome/browser/ui/webui/discards/graph_dump_impl_unittest.cc b/chrome/browser/ui/webui/discards/graph_dump_impl_unittest.cc
index 1f804827..ee07948 100644
--- a/chrome/browser/ui/webui/discards/graph_dump_impl_unittest.cc
+++ b/chrome/browser/ui/webui/discards/graph_dump_impl_unittest.cc
@@ -133,8 +133,11 @@
   base::TimeTicks now = base::TimeTicks::Now();
 
   const GURL kExampleUrl("http://www.example.org");
-  mock_graph.page->OnMainFrameNavigationCommitted(now, 1, kExampleUrl);
-  mock_graph.other_page->OnMainFrameNavigationCommitted(now, 2, kExampleUrl);
+  int64_t next_navigation_id = 1;
+  mock_graph.page->OnMainFrameNavigationCommitted(
+      false, now, next_navigation_id++, kExampleUrl);
+  mock_graph.other_page->OnMainFrameNavigationCommitted(
+      false, now, next_navigation_id++, kExampleUrl);
 
   auto* main_frame = mock_graph.page->GetMainFrameNodeImpl();
   main_frame->OnNavigationCommitted(kExampleUrl, /* same_document */ false);
@@ -193,7 +196,8 @@
 
   // Test change notifications.
   const GURL kAnotherURL("http://www.google.com/");
-  mock_graph.page->OnMainFrameNavigationCommitted(now, 1, kAnotherURL);
+  mock_graph.page->OnMainFrameNavigationCommitted(
+      false, now, next_navigation_id++, kAnotherURL);
 
   size_t child_frame_id =
       NodeBase::GetSerializationId(mock_graph.child_frame.get());
@@ -201,6 +205,7 @@
 
   task_environment.RunUntilIdle();
 
+  // Main frame navigation results in a notification for the url.
   EXPECT_EQ(1u, change_stream.num_changes());
   EXPECT_FALSE(base::Contains(change_stream.id_set(), child_frame_id));
 
diff --git a/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc b/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc
index eab0779..0f326828 100644
--- a/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc
@@ -14,6 +14,7 @@
 #include "base/files/scoped_file.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop_current.h"
 #include "base/strings/string_split.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/chrome/browser/web_applications/proto/BUILD.gn b/chrome/browser/web_applications/proto/BUILD.gn
index eae2f64b..1a55541 100644
--- a/chrome/browser/web_applications/proto/BUILD.gn
+++ b/chrome/browser/web_applications/proto/BUILD.gn
@@ -5,7 +5,9 @@
 import("//third_party/protobuf/proto_library.gni")
 
 proto_library("proto") {
+  import_dirs = [ "//components/sync/protocol" ]
   sources = [
     "web_app.proto",
   ]
+  link_deps = [ "//components/sync/protocol" ]
 }
diff --git a/chrome/browser/web_applications/proto/web_app.proto b/chrome/browser/web_applications/proto/web_app.proto
index a093f0e..54cda05 100644
--- a/chrome/browser/web_applications/proto/web_app.proto
+++ b/chrome/browser/web_applications/proto/web_app.proto
@@ -4,6 +4,8 @@
 
 syntax = "proto2";
 
+import "web_app_specifics.proto";
+
 option optimize_for = LITE_RUNTIME;
 
 package web_app;
@@ -26,29 +28,19 @@
   required bool default = 5;
 }
 
-// WebApp class data. This should be a superset for WebAppSpecifics in
-// components/sync/protocol/web_app_specifics.proto
+// Full WebApp object data. Note on database identities:
+// app_id is a hash of launch_url. app_id is the client tag for sync system.
+// app_id is the storage key in ModelTypeStore.
 message WebAppProto {
-  // Keep in sync with WebAppSpecifics::LaunchContainer.
-  enum LaunchContainer {
-    TAB = 1;
-    WINDOW = 2;
-  }
+  // Synced data.
+  required sync_pb.WebAppSpecifics specifics = 1;
 
-  // app_id is a hash of launch_url. app_id is the client tag for sync system.
-  // app_id is the storage key in ModelTypeStore.
-  required string launch_url = 1;
-  required string name = 2;
-  required LaunchContainer launch_container = 3;
-  optional uint32 theme_color = 4;
-
-  // Local data members, not to be synced:
-  optional string description = 5;
-  optional string scope = 6;
-
-  required SourcesProto sources = 7;
-  required bool is_locally_installed = 8;
-
+  // Local data. Not to be synced.
+  //
+  optional string description = 2;
+  optional string scope = 3;
+  required SourcesProto sources = 4;
+  required bool is_locally_installed = 5;
   // A list of icon infos.
-  repeated WebAppIconInfoProto icons = 9;
+  repeated WebAppIconInfoProto icons = 6;
 }
diff --git a/chrome/browser/web_applications/system_web_app_manager.cc b/chrome/browser/web_applications/system_web_app_manager.cc
index 5469784..ed3ec02 100644
--- a/chrome/browser/web_applications/system_web_app_manager.cc
+++ b/chrome/browser/web_applications/system_web_app_manager.cc
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/run_loop.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/version.h"
diff --git a/chrome/browser/web_applications/test/test_web_app_registry_controller.cc b/chrome/browser/web_applications/test/test_web_app_registry_controller.cc
index 03b44559..845e569 100644
--- a/chrome/browser/web_applications/test/test_web_app_registry_controller.cc
+++ b/chrome/browser/web_applications/test/test_web_app_registry_controller.cc
@@ -7,7 +7,6 @@
 #include "base/run_loop.h"
 #include "base/test/bind_test_util.h"
 #include "chrome/browser/web_applications/test/test_web_app_database_factory.h"
-#include "chrome/browser/web_applications/web_app_registrar.h"
 #include "chrome/browser/web_applications/web_app_sync_bridge.h"
 
 namespace web_app {
@@ -18,10 +17,10 @@
 
 void TestWebAppRegistryController::SetUp(Profile* profile) {
   database_factory_ = std::make_unique<TestWebAppDatabaseFactory>();
-  registrar_ = std::make_unique<WebAppRegistrar>(profile);
+  mutable_registrar_ = std::make_unique<WebAppRegistrarMutable>(profile);
 
   sync_bridge_ = std::make_unique<WebAppSyncBridge>(
-      profile, database_factory_.get(), registrar_.get(),
+      profile, database_factory_.get(), mutable_registrar_.get(),
       mock_processor_.CreateForwardingProcessor());
 
   ON_CALL(processor(), IsTrackingMetadata())
@@ -35,7 +34,7 @@
 }
 
 void TestWebAppRegistryController::DestroySubsystems() {
-  registrar_.reset();
+  mutable_registrar_.reset();
   sync_bridge_.reset();
   database_factory_.reset();
 }
diff --git a/chrome/browser/web_applications/test/test_web_app_registry_controller.h b/chrome/browser/web_applications/test/test_web_app_registry_controller.h
index aa17d830..cf92ff1 100644
--- a/chrome/browser/web_applications/test/test_web_app_registry_controller.h
+++ b/chrome/browser/web_applications/test/test_web_app_registry_controller.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "chrome/browser/web_applications/web_app_registrar.h"
 #include "components/sync/model/mock_model_type_change_processor.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
@@ -15,7 +16,6 @@
 namespace web_app {
 
 class TestWebAppDatabaseFactory;
-class WebAppRegistrar;
 class WebAppSyncBridge;
 
 class TestWebAppRegistryController {
@@ -32,13 +32,14 @@
   void DestroySubsystems();
 
   TestWebAppDatabaseFactory& database_factory() { return *database_factory_; }
-  WebAppRegistrar& registrar() { return *registrar_; }
+  WebAppRegistrar& registrar() { return *mutable_registrar_; }
+  WebAppRegistrarMutable& mutable_registrar() { return *mutable_registrar_; }
   syncer::MockModelTypeChangeProcessor& processor() { return mock_processor_; }
   WebAppSyncBridge& sync_bridge() { return *sync_bridge_; }
 
  private:
   std::unique_ptr<TestWebAppDatabaseFactory> database_factory_;
-  std::unique_ptr<WebAppRegistrar> registrar_;
+  std::unique_ptr<WebAppRegistrarMutable> mutable_registrar_;
   testing::NiceMock<syncer::MockModelTypeChangeProcessor> mock_processor_;
   std::unique_ptr<WebAppSyncBridge> sync_bridge_;
 };
diff --git a/chrome/browser/web_applications/web_app_database.cc b/chrome/browser/web_applications/web_app_database.cc
index 7b007972..cc8edc7 100644
--- a/chrome/browser/web_applications/web_app_database.cc
+++ b/chrome/browser/web_applications/web_app_database.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/web_applications/web_app_database_factory.h"
 #include "components/sync/base/model_type.h"
 #include "components/sync/model/model_error.h"
+#include "components/sync/protocol/web_app_specifics.pb.h"
 
 namespace web_app {
 
@@ -25,16 +26,16 @@
 }
 
 void WebAppDatabase::OpenDatabase(RegistryOpenedCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!store_);
 
   syncer::OnceModelTypeStoreFactory store_factory =
       database_factory_->GetStoreFactory();
 
-  // CreateStore then ReadRegistry.
-  CreateStore(
-      std::move(store_factory),
-      base::BindOnce(&WebAppDatabase::ReadRegistry,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+  std::move(store_factory)
+      .Run(syncer::WEB_APPS,
+           base::BindOnce(&WebAppDatabase::OnDatabaseOpened,
+                          weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
 }
 
 void WebAppDatabase::WriteWebApps(AppsToWrite apps,
@@ -77,15 +78,17 @@
   DCHECK(!web_app.app_id().empty());
   DCHECK_EQ(web_app.app_id(), GenerateAppIdFromURL(launch_url));
 
-  proto->set_launch_url(launch_url.spec());
+  sync_pb::WebAppSpecifics* specifics = proto->mutable_specifics();
 
-  proto->set_name(web_app.name());
+  specifics->set_launch_url(launch_url.spec());
+
+  specifics->set_name(web_app.name());
 
   DCHECK_NE(LaunchContainer::kDefault, web_app.launch_container());
-  proto->set_launch_container(web_app.launch_container() ==
-                                      LaunchContainer::kWindow
-                                  ? WebAppProto::WINDOW
-                                  : WebAppProto::TAB);
+  specifics->set_launch_container(web_app.launch_container() ==
+                                          LaunchContainer::kWindow
+                                      ? sync_pb::WebAppSpecifics::WINDOW
+                                      : sync_pb::WebAppSpecifics::TAB);
 
   DCHECK(web_app.sources_.any());
   proto->mutable_sources()->set_system(web_app.sources_[Source::kSystem]);
@@ -102,7 +105,7 @@
   if (!web_app.scope().is_empty())
     proto->set_scope(web_app.scope().spec());
   if (web_app.theme_color().has_value())
-    proto->set_theme_color(web_app.theme_color().value());
+    specifics->set_theme_color(web_app.theme_color().value());
 
   for (const WebApp::IconInfo& icon : web_app.icons()) {
     WebAppIconInfoProto* icon_proto = proto->add_icons();
@@ -115,8 +118,15 @@
 
 // static
 std::unique_ptr<WebApp> WebAppDatabase::CreateWebApp(const WebAppProto& proto) {
+  if (!proto.has_specifics()) {
+    DLOG(ERROR) << "WebApp proto parse error: no specifics field";
+    return nullptr;
+  }
+
+  const sync_pb::WebAppSpecifics& specifics = proto.specifics();
+
   // AppId is a hash of launch_url. Read launch_url first:
-  GURL launch_url(proto.launch_url());
+  GURL launch_url(specifics.launch_url());
   if (launch_url.is_empty() || !launch_url.is_valid()) {
     DLOG(ERROR) << "WebApp proto launch_url parse error: "
                 << launch_url.possibly_invalid_spec();
@@ -146,17 +156,18 @@
   }
   web_app->sources_ = sources;
 
-  if (!proto.has_name()) {
+  if (!specifics.has_name()) {
     DLOG(ERROR) << "WebApp proto parse error: no name field";
     return nullptr;
   }
-  web_app->SetName(proto.name());
+  web_app->SetName(specifics.name());
 
-  if (!proto.has_launch_container()) {
+  if (!specifics.has_launch_container()) {
     DLOG(ERROR) << "WebApp proto parse error: no launch_container field";
     return nullptr;
   }
-  web_app->SetLaunchContainer(proto.launch_container() == WebAppProto::WINDOW
+  web_app->SetLaunchContainer(specifics.launch_container() ==
+                                      sync_pb::WebAppSpecifics::WINDOW
                                   ? LaunchContainer::kWindow
                                   : LaunchContainer::kTab);
 
@@ -180,8 +191,8 @@
     web_app->SetScope(scope);
   }
 
-  if (proto.has_theme_color())
-    web_app->SetThemeColor(proto.theme_color());
+  if (specifics.has_theme_color())
+    web_app->SetThemeColor(specifics.theme_color());
 
   WebApp::Icons icons;
   for (int i = 0; i < proto.icons_size(); ++i) {
@@ -201,27 +212,8 @@
   return web_app;
 }
 
-void WebAppDatabase::ReadRegistry(RegistryOpenedCallback callback) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(store_);
-  store_->ReadAllData(base::BindOnce(&WebAppDatabase::OnAllDataRead,
-                                     weak_ptr_factory_.GetWeakPtr(),
-                                     std::move(callback)));
-}
-
-void WebAppDatabase::CreateStore(
-    syncer::OnceModelTypeStoreFactory store_factory,
-    base::OnceClosure closure) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  std::move(store_factory)
-      .Run(syncer::WEB_APPS,
-           base::BindOnce(&WebAppDatabase::OnStoreCreated,
-                          weak_ptr_factory_.GetWeakPtr(), std::move(closure)));
-}
-
-void WebAppDatabase::OnStoreCreated(
-    base::OnceClosure closure,
+void WebAppDatabase::OnDatabaseOpened(
+    RegistryOpenedCallback callback,
     const base::Optional<syncer::ModelError>& error,
     std::unique_ptr<syncer::ModelTypeStore> store) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -231,7 +223,9 @@
   }
 
   store_ = std::move(store);
-  std::move(closure).Run();
+  store_->ReadAllData(base::BindOnce(&WebAppDatabase::OnAllDataRead,
+                                     weak_ptr_factory_.GetWeakPtr(),
+                                     std::move(callback)));
 }
 
 void WebAppDatabase::OnAllDataRead(
diff --git a/chrome/browser/web_applications/web_app_database.h b/chrome/browser/web_applications/web_app_database.h
index bf95c11..9ef4edf 100644
--- a/chrome/browser/web_applications/web_app_database.h
+++ b/chrome/browser/web_applications/web_app_database.h
@@ -45,19 +45,15 @@
   // Exposed for testing.
   static std::unique_ptr<WebAppProto> CreateWebAppProto(const WebApp& web_app);
   // Exposed for testing.
-  static std::unique_ptr<WebApp> CreateWebApp(const WebAppProto& proto);
-  // Exposed for testing.
-  void ReadRegistry(RegistryOpenedCallback callback);
-  // Exposed for testing.
   static std::unique_ptr<WebApp> ParseWebApp(const AppId& app_id,
                                              const std::string& value);
 
  private:
-  void CreateStore(syncer::OnceModelTypeStoreFactory store_factory,
-                   base::OnceClosure closure);
-  void OnStoreCreated(base::OnceClosure closure,
-                      const base::Optional<syncer::ModelError>& error,
-                      std::unique_ptr<syncer::ModelTypeStore> store);
+  static std::unique_ptr<WebApp> CreateWebApp(const WebAppProto& proto);
+
+  void OnDatabaseOpened(RegistryOpenedCallback callback,
+                        const base::Optional<syncer::ModelError>& error,
+                        std::unique_ptr<syncer::ModelTypeStore> store);
 
   void OnAllDataRead(
       RegistryOpenedCallback callback,
diff --git a/chrome/browser/web_applications/web_app_database_unittest.cc b/chrome/browser/web_applications/web_app_database_unittest.cc
index 763948c..3f6e4c68 100644
--- a/chrome/browser/web_applications/web_app_database_unittest.cc
+++ b/chrome/browser/web_applications/web_app_database_unittest.cc
@@ -10,11 +10,12 @@
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/test/bind_test_util.h"
-#include "base/test/task_environment.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "chrome/browser/web_applications/proto/web_app.pb.h"
 #include "chrome/browser/web_applications/test/test_web_app_database_factory.h"
+#include "chrome/browser/web_applications/test/test_web_app_registry_controller.h"
+#include "chrome/browser/web_applications/test/web_app_test.h"
 #include "chrome/browser/web_applications/web_app.h"
 #include "chrome/browser/web_applications/web_app_registrar.h"
 #include "chrome/browser/web_applications/web_app_sync_bridge.h"
@@ -24,21 +25,14 @@
 
 namespace web_app {
 
-class WebAppDatabaseTest : public testing::Test {
+class WebAppDatabaseTest : public WebAppTest {
  public:
-  WebAppDatabaseTest() {
-    database_factory_ = std::make_unique<TestWebAppDatabaseFactory>();
-    registrar_ = std::make_unique<WebAppRegistrar>(nullptr);
-    sync_bridge_ = std::make_unique<WebAppSyncBridge>(
-        nullptr, database_factory_.get(), registrar_.get());
-  }
+  void SetUp() override {
+    WebAppTest::SetUp();
 
-  void InitRegistrar() {
-    base::RunLoop run_loop;
-
-    sync_bridge().Init(base::BindLambdaForTesting([&]() { run_loop.Quit(); }));
-
-    run_loop.Run();
+    test_registry_controller_ =
+        std::make_unique<TestWebAppRegistryController>();
+    test_registry_controller_->SetUp(profile());
   }
 
   static std::unique_ptr<WebApp> CreateWebApp(const std::string& base_url,
@@ -91,14 +85,14 @@
 
   bool IsDatabaseRegistryEqualToRegistrar() {
     Registry registry = database_factory().ReadRegistry();
-    return IsRegistryEqual(registrar_->registry_for_testing(), registry);
+    return IsRegistryEqual(mutable_registrar().registry(), registry);
   }
 
   void WriteBatch(
       std::unique_ptr<syncer::ModelTypeStore::WriteBatch> write_batch) {
     base::RunLoop run_loop;
 
-    database_factory_->store()->CommitWriteBatch(
+    database_factory().store()->CommitWriteBatch(
         std::move(write_batch),
         base::BindLambdaForTesting(
             [&](const base::Optional<syncer::ModelError>& error) {
@@ -112,7 +106,7 @@
   Registry WriteWebApps(const std::string& base_url, int num_apps) {
     Registry registry;
 
-    auto write_batch = database_factory_->store()->CreateWriteBatch();
+    auto write_batch = database_factory().store()->CreateWriteBatch();
 
     for (int i = 0; i < num_apps; ++i) {
       auto app = CreateWebApp(base_url, i);
@@ -130,22 +124,32 @@
   }
 
  protected:
-  TestWebAppDatabaseFactory& database_factory() { return *database_factory_; }
-  WebAppDatabase& database() { return sync_bridge().database_for_testing(); }
-  WebAppSyncBridge& sync_bridge() { return *sync_bridge_; }
-  WebAppRegistrar& registrar() { return *registrar_; }
+  TestWebAppRegistryController& controller() {
+    return *test_registry_controller_;
+  }
+
+  TestWebAppDatabaseFactory& database_factory() {
+    return controller().database_factory();
+  }
+
+  WebAppDatabase& database() {
+    return controller().sync_bridge().database_for_testing();
+  }
+
+  WebAppRegistrar& registrar() { return controller().registrar(); }
+
+  WebAppRegistrarMutable& mutable_registrar() {
+    return controller().mutable_registrar();
+  }
+
+  WebAppSyncBridge& sync_bridge() { return controller().sync_bridge(); }
 
  private:
-  // Must be created before TestWebAppDatabaseFactory.
-  base::test::SingleThreadTaskEnvironment task_environment_;
-
-  std::unique_ptr<TestWebAppDatabaseFactory> database_factory_;
-  std::unique_ptr<WebAppSyncBridge> sync_bridge_;
-  std::unique_ptr<WebAppRegistrar> registrar_;
+  std::unique_ptr<TestWebAppRegistryController> test_registry_controller_;
 };
 
 TEST_F(WebAppDatabaseTest, WriteAndReadRegistry) {
-  InitRegistrar();
+  controller().Init();
   EXPECT_TRUE(registrar().is_empty());
 
   const int num_apps = 100;
@@ -170,7 +174,7 @@
 }
 
 TEST_F(WebAppDatabaseTest, WriteAndDeleteAppsWithCallbacks) {
-  InitRegistrar();
+  controller().Init();
   EXPECT_TRUE(registrar().is_empty());
 
   const int num_apps = 10;
@@ -217,12 +221,12 @@
 TEST_F(WebAppDatabaseTest, OpenDatabaseAndReadRegistry) {
   Registry registry = WriteWebApps("https://example.com/path", 100);
 
-  InitRegistrar();
-  EXPECT_TRUE(IsRegistryEqual(registrar().registry_for_testing(), registry));
+  controller().Init();
+  EXPECT_TRUE(IsRegistryEqual(mutable_registrar().registry(), registry));
 }
 
 TEST_F(WebAppDatabaseTest, WebAppWithoutOptionalFields) {
-  InitRegistrar();
+  controller().Init();
 
   const auto launch_url = GURL("https://example.com/");
   const AppId app_id = GenerateAppIdFromURL(GURL(launch_url));
@@ -276,7 +280,7 @@
 }
 
 TEST_F(WebAppDatabaseTest, WebAppWithManyIcons) {
-  InitRegistrar();
+  controller().Init();
 
   const int num_icons = 32;
   const std::string base_url = "https://example.com/path";
diff --git a/chrome/browser/web_applications/web_app_provider.cc b/chrome/browser/web_applications/web_app_provider.cc
index 8d7bb0f..3ef1905e 100644
--- a/chrome/browser/web_applications/web_app_provider.cc
+++ b/chrome/browser/web_applications/web_app_provider.cc
@@ -161,15 +161,28 @@
 
 void WebAppProvider::CreateWebAppsSubsystems(Profile* profile) {
   database_factory_ = std::make_unique<WebAppDatabaseFactory>(profile);
-  auto registrar = std::make_unique<WebAppRegistrar>(profile);
-  auto sync_bridge = std::make_unique<WebAppSyncBridge>(
-      profile, database_factory_.get(), registrar.get());
+
+  std::unique_ptr<WebAppRegistrar> registrar;
+  std::unique_ptr<WebAppSyncBridge> sync_bridge;
+
+  // Only WebAppSyncBridge must have an access to mutable WebAppRegistrar.
+  {
+    auto mutable_registrar = std::make_unique<WebAppRegistrarMutable>(profile);
+
+    sync_bridge = std::make_unique<WebAppSyncBridge>(
+        profile, database_factory_.get(), mutable_registrar.get());
+
+    // Upcast to read-only WebAppRegistrar.
+    registrar = std::move(mutable_registrar);
+  }
+
   auto icon_manager = std::make_unique<WebAppIconManager>(
       profile, *registrar, std::make_unique<FileUtilsWrapper>());
   install_finalizer_ = std::make_unique<WebAppInstallFinalizer>(
       sync_bridge.get(), icon_manager.get());
   file_handler_manager_ = std::make_unique<WebAppFileHandlerManager>(profile);
 
+  // Upcast to unified subsystem types:
   registrar_ = std::move(registrar);
   registry_controller_ = std::move(sync_bridge);
   icon_manager_ = std::move(icon_manager);
diff --git a/chrome/browser/web_applications/web_app_registrar.cc b/chrome/browser/web_applications/web_app_registrar.cc
index b202767..eaa3de8 100644
--- a/chrome/browser/web_applications/web_app_registrar.cc
+++ b/chrome/browser/web_applications/web_app_registrar.cc
@@ -25,11 +25,6 @@
   return it == registry_.end() ? nullptr : it->second.get();
 }
 
-void WebAppRegistrar::InitRegistry(Registry&& registry) {
-  DCHECK(is_empty());
-  registry_ = std::move(registry);
-}
-
 bool WebAppRegistrar::IsInstalled(const AppId& app_id) const {
   return GetAppById(app_id) != nullptr;
 }
@@ -162,12 +157,8 @@
   return AppSet(this);
 }
 
-WebApp* WebAppRegistrar::GetAppByIdMutable(const AppId& app_id) {
-  return const_cast<WebApp*>(GetAppById(app_id));
-}
-
-WebAppRegistrar::AppSet WebAppRegistrar::AllAppsMutable() {
-  return AppSet(this);
+void WebAppRegistrar::SetRegistry(Registry&& registry) {
+  registry_ = std::move(registry);
 }
 
 void WebAppRegistrar::CountMutation() {
@@ -176,6 +167,24 @@
 #endif
 }
 
+WebAppRegistrarMutable::WebAppRegistrarMutable(Profile* profile)
+    : WebAppRegistrar(profile) {}
+
+WebAppRegistrarMutable::~WebAppRegistrarMutable() = default;
+
+void WebAppRegistrarMutable::InitRegistry(Registry&& registry) {
+  DCHECK(is_empty());
+  SetRegistry(std::move(registry));
+}
+
+WebApp* WebAppRegistrarMutable::GetAppByIdMutable(const AppId& app_id) {
+  return const_cast<WebApp*>(GetAppById(app_id));
+}
+
+WebAppRegistrar::AppSet WebAppRegistrarMutable::AllAppsMutable() {
+  return AppSet(this);
+}
+
 bool IsRegistryEqual(const Registry& registry, const Registry& registry2) {
   if (registry.size() != registry2.size())
     return false;
diff --git a/chrome/browser/web_applications/web_app_registrar.h b/chrome/browser/web_applications/web_app_registrar.h
index 11206c9..5f61255 100644
--- a/chrome/browser/web_applications/web_app_registrar.h
+++ b/chrome/browser/web_applications/web_app_registrar.h
@@ -9,7 +9,6 @@
 #include <memory>
 #include <string>
 
-#include "base/gtest_prod_util.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/optional.h"
@@ -22,7 +21,7 @@
 
 using Registry = std::map<AppId, std::unique_ptr<WebApp>>;
 
-// A registry. This is a read-only container, which owns WebApp objects.
+// A registry model. This is a read-only container, which owns WebApp objects.
 class WebAppRegistrar : public AppRegistrar {
  public:
   explicit WebAppRegistrar(Profile* profile);
@@ -95,29 +94,34 @@
 
   const AppSet AllApps() const;
 
-  const Registry& registry_for_testing() const { return registry_; }
+ protected:
+  Registry& registry() { return registry_; }
+  void SetRegistry(Registry&& registry);
+
+  void CountMutation();
 
  private:
-  friend class WebAppSyncBridge;
-  FRIEND_TEST_ALL_PREFIXES(WebAppRegistrarTest, AllAppsMutable);
+  Registry registry_;
+#if DCHECK_IS_ON()
+  size_t mutations_count_ = 0;
+#endif
+  DISALLOW_COPY_AND_ASSIGN(WebAppRegistrar);
+};
+
+// A writable API for the registry model. Mutable WebAppRegistrar must be used
+// only by WebAppSyncBridge.
+class WebAppRegistrarMutable : public WebAppRegistrar {
+ public:
+  explicit WebAppRegistrarMutable(Profile* profile);
+  ~WebAppRegistrarMutable() override;
+
+  void InitRegistry(Registry&& registry);
 
   WebApp* GetAppByIdMutable(const AppId& app_id);
   AppSet AllAppsMutable();
 
-  void InitRegistry(Registry&& registry);
-
-  void CountMutation();
-
-  // Used by WebAppSyncBridge controller to to raw updates.
-  Registry& registry() { return registry_; }
-
-  Registry registry_;
-
-#if DCHECK_IS_ON()
-  size_t mutations_count_ = 0;
-#endif
-
-  DISALLOW_COPY_AND_ASSIGN(WebAppRegistrar);
+  using WebAppRegistrar::CountMutation;
+  using WebAppRegistrar::registry;
 };
 
 // For testing and debug purposes.
diff --git a/chrome/browser/web_applications/web_app_registrar_unittest.cc b/chrome/browser/web_applications/web_app_registrar_unittest.cc
index 735e5e0..b8374d7 100644
--- a/chrome/browser/web_applications/web_app_registrar_unittest.cc
+++ b/chrome/browser/web_applications/web_app_registrar_unittest.cc
@@ -237,7 +237,7 @@
 TEST_F(WebAppRegistrarTest, AllAppsMutable) {
   std::set<AppId> ids = InitRegistrarWithApps("https://example.com/path", 10);
 
-  for (WebApp& web_app : registrar().AllAppsMutable()) {
+  for (WebApp& web_app : controller().mutable_registrar().AllAppsMutable()) {
     web_app.SetLaunchContainer(LaunchContainer::kWindow);
     const size_t num_removed = ids.erase(web_app.app_id());
     EXPECT_EQ(1U, num_removed);
@@ -274,11 +274,11 @@
   sync_bridge().RegisterApp(std::move(web_app));
 
   EXPECT_EQ(101UL, database_factory().ReadAllAppIds().size());
-  EXPECT_EQ(101UL, registrar().registry_for_testing().size());
+  EXPECT_EQ(101UL, controller().mutable_registrar().registry().size());
 
   // Remove 1 app after Init.
   sync_bridge().UnregisterApp(app_id);
-  EXPECT_EQ(100UL, registrar().registry_for_testing().size());
+  EXPECT_EQ(100UL, controller().mutable_registrar().registry().size());
   EXPECT_EQ(100UL, database_factory().ReadAllAppIds().size());
 
   // Remove 100 apps after Init.
diff --git a/chrome/browser/web_applications/web_app_registry_update.cc b/chrome/browser/web_applications/web_app_registry_update.cc
index 02c650e..d747b50d 100644
--- a/chrome/browser/web_applications/web_app_registry_update.cc
+++ b/chrome/browser/web_applications/web_app_registry_update.cc
@@ -5,28 +5,36 @@
 #include "chrome/browser/web_applications/web_app_registry_update.h"
 
 #include "base/bind_helpers.h"
+#include "chrome/browser/web_applications/web_app_registrar.h"
 #include "chrome/browser/web_applications/web_app_sync_bridge.h"
 
 namespace web_app {
 
-WebAppRegistryUpdate::WebAppRegistryUpdate(WebAppSyncBridge* sync_bridge)
-    : sync_bridge_(sync_bridge) {}
+WebAppRegistryUpdate::WebAppRegistryUpdate(
+    WebAppRegistrarMutable* mutable_registrar)
+    : mutable_registrar_(mutable_registrar) {}
 
 WebAppRegistryUpdate::~WebAppRegistryUpdate() = default;
 
 WebApp* WebAppRegistryUpdate::UpdateApp(const AppId& app_id) {
-  WebApp* app = sync_bridge_->GetAppByIdMutable(app_id);
+  WebApp* app = mutable_registrar_->GetAppByIdMutable(app_id);
   if (app)
     apps_to_update_.insert(app);
 
   return app;
 }
 
+WebAppRegistryUpdate::AppsToUpdate WebAppRegistryUpdate::TakeAppsToUpdate() {
+  AppsToUpdate apps_to_update = std::move(apps_to_update_);
+  apps_to_update_.clear();
+  return apps_to_update;
+}
+
 ScopedRegistryUpdate::ScopedRegistryUpdate(WebAppSyncBridge* sync_bridge)
-    : update_(sync_bridge->BeginUpdate()) {}
+    : update_(sync_bridge->BeginUpdate()), sync_bridge_(sync_bridge) {}
 
 ScopedRegistryUpdate::~ScopedRegistryUpdate() {
-  update_->sync_bridge_->CommitUpdate(std::move(update_), base::DoNothing());
+  sync_bridge_->CommitUpdate(std::move(update_), base::DoNothing());
 }
 
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_registry_update.h b/chrome/browser/web_applications/web_app_registry_update.h
index 724a4a9..1bb1dd5 100644
--- a/chrome/browser/web_applications/web_app_registry_update.h
+++ b/chrome/browser/web_applications/web_app_registry_update.h
@@ -15,28 +15,29 @@
 namespace web_app {
 
 class WebApp;
+class WebAppRegistrarMutable;
 class WebAppSyncBridge;
 
 // An explicit writable "view" for the registry. Any write operations must be
-// batched as a part of WebAppRegistryUpdate object.
+// batched as a part of WebAppRegistryUpdate object. Effectively
+// WebAppRegistryUpdate is a part of WebAppSyncBridge class.
 //
 // TODO(loyso): Support creation and deletion of apps as a part of single
 // update (As in Database CRUD: Create/Update/Delete).
 class WebAppRegistryUpdate {
  public:
+  explicit WebAppRegistryUpdate(WebAppRegistrarMutable* mutable_registrar);
   ~WebAppRegistryUpdate();
 
   // Acquire a mutable app object to set new field values.
   WebApp* UpdateApp(const AppId& app_id);
 
+  using AppsToUpdate = base::flat_set<const WebApp*>;
+  AppsToUpdate TakeAppsToUpdate();
+
  private:
-  friend class WebAppSyncBridge;
-  friend class ScopedRegistryUpdate;
-
-  explicit WebAppRegistryUpdate(WebAppSyncBridge* sync_bridge);
-
-  base::flat_set<const WebApp*> apps_to_update_;
-  WebAppSyncBridge* sync_bridge_;
+  AppsToUpdate apps_to_update_;
+  WebAppRegistrarMutable* mutable_registrar_;
 
   DISALLOW_COPY_AND_ASSIGN(WebAppRegistryUpdate);
 };
@@ -52,6 +53,7 @@
 
  private:
   std::unique_ptr<WebAppRegistryUpdate> update_;
+  WebAppSyncBridge* sync_bridge_;
 
   DISALLOW_COPY_AND_ASSIGN(ScopedRegistryUpdate);
 };
diff --git a/chrome/browser/web_applications/web_app_sync_bridge.cc b/chrome/browser/web_applications/web_app_sync_bridge.cc
index 9aa2de54..6033368 100644
--- a/chrome/browser/web_applications/web_app_sync_bridge.cc
+++ b/chrome/browser/web_applications/web_app_sync_bridge.cc
@@ -24,7 +24,7 @@
 WebAppSyncBridge::WebAppSyncBridge(
     Profile* profile,
     AbstractWebAppDatabaseFactory* database_factory,
-    WebAppRegistrar* registrar)
+    WebAppRegistrarMutable* registrar)
     : WebAppSyncBridge(
           profile,
           database_factory,
@@ -37,7 +37,7 @@
 WebAppSyncBridge::WebAppSyncBridge(
     Profile* profile,
     AbstractWebAppDatabaseFactory* database_factory,
-    WebAppRegistrar* registrar,
+    WebAppRegistrarMutable* registrar,
     std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor)
     : AppRegistryController(profile),
       syncer::ModelTypeSyncBridge(std::move(change_processor)),
@@ -74,7 +74,7 @@
   DCHECK(it != registrar_->registry().end());
 
   auto web_app = std::move(it->second);
-  registrar_->registry_.erase(it);
+  registrar_->registry().erase(it);
   return web_app;
 }
 
@@ -90,7 +90,7 @@
   DCHECK(!is_in_update_);
   is_in_update_ = true;
 
-  return base::WrapUnique(new WebAppRegistryUpdate(this));
+  return base::WrapUnique(new WebAppRegistryUpdate(registrar_));
 }
 
 void WebAppSyncBridge::CommitUpdate(
@@ -98,18 +98,27 @@
     CommitCallback callback) {
   DCHECK(is_in_update_);
   is_in_update_ = false;
-  if (update == nullptr || update->apps_to_update_.empty()) {
+
+  if (update == nullptr) {
+    std::move(callback).Run(/*success*/ true);
+    return;
+  }
+
+  WebAppRegistryUpdate::AppsToUpdate apps_to_update =
+      update->TakeAppsToUpdate();
+
+  if (apps_to_update.empty()) {
     std::move(callback).Run(/*success*/ true);
     return;
   }
 
 #if DCHECK_IS_ON()
-  for (auto* app : update->apps_to_update_)
+  for (auto* app : apps_to_update)
     DCHECK(registrar_->GetAppById(app->app_id()));
 #endif
 
   database_->WriteWebApps(
-      std::move(update->apps_to_update_),
+      std::move(apps_to_update),
       base::BindOnce(&WebAppSyncBridge::OnDataWritten,
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
 }
@@ -132,10 +141,6 @@
   return this;
 }
 
-WebApp* WebAppSyncBridge::GetAppByIdMutable(const AppId& app_id) {
-  return registrar_->GetAppByIdMutable(app_id);
-}
-
 void WebAppSyncBridge::OnDatabaseOpened(base::OnceClosure callback,
                                         Registry registry) {
   registrar_->InitRegistry(std::move(registry));
diff --git a/chrome/browser/web_applications/web_app_sync_bridge.h b/chrome/browser/web_applications/web_app_sync_bridge.h
index f3eba0f..88b384a7 100644
--- a/chrome/browser/web_applications/web_app_sync_bridge.h
+++ b/chrome/browser/web_applications/web_app_sync_bridge.h
@@ -35,12 +35,12 @@
  public:
   WebAppSyncBridge(Profile* profile,
                    AbstractWebAppDatabaseFactory* database_factory,
-                   WebAppRegistrar* registrar);
+                   WebAppRegistrarMutable* registrar);
   // Tests may inject mocks using this ctor.
   WebAppSyncBridge(
       Profile* profile,
       AbstractWebAppDatabaseFactory* database_factory,
-      WebAppRegistrar* registrar,
+      WebAppRegistrarMutable* registrar,
       std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor);
   ~WebAppSyncBridge() override;
 
@@ -66,10 +66,6 @@
   WebAppDatabase& database_for_testing() { return *database_; }
 
  private:
-  friend class WebAppRegistryUpdate;
-
-  WebApp* GetAppByIdMutable(const AppId& app_id);
-
   void OnDatabaseOpened(base::OnceClosure callback, Registry registry);
   void OnDataWritten(CommitCallback callback, bool success);
 
@@ -88,7 +84,7 @@
   std::string GetStorageKey(const syncer::EntityData& entity_data) override;
 
   std::unique_ptr<WebAppDatabase> database_;
-  WebAppRegistrar* registrar_;
+  WebAppRegistrarMutable* registrar_;
 
   bool is_in_update_ = false;
 
diff --git a/chrome/chrome_cleaner/parsers/target/sandbox_setup.cc b/chrome/chrome_cleaner/parsers/target/sandbox_setup.cc
index d76775b..6ca95e1 100644
--- a/chrome/chrome_cleaner/parsers/target/sandbox_setup.cc
+++ b/chrome/chrome_cleaner/parsers/target/sandbox_setup.cc
@@ -6,10 +6,11 @@
 
 #include <utility>
 
+#include "base/run_loop.h"
 #include "base/task/single_thread_task_executor.h"
-#include "chrome/chrome_cleaner/mojom/parser_interface.mojom.h"
 #include "chrome/chrome_cleaner/ipc/mojo_sandbox_hooks.h"
 #include "chrome/chrome_cleaner/ipc/mojo_task_runner.h"
+#include "chrome/chrome_cleaner/mojom/parser_interface.mojom.h"
 #include "chrome/chrome_cleaner/os/early_exit.h"
 #include "chrome/chrome_cleaner/parsers/target/parser_impl.h"
 #include "components/chrome_cleaner/public/constants/result_codes.h"
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 4cf3935..febb1e8 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -513,6 +513,11 @@
                                        base::FEATURE_ENABLED_BY_DEFAULT};
 #endif  // OS_ANDROID
 
+// When kNoReferrers is enabled, most HTTP requests will provide empty
+// referrers instead of their ordinary behavior.
+const base::Feature kNoReferrers{"NoReferrers",
+                                 base::FEATURE_DISABLED_BY_DEFAULT};
+
 #if defined(OS_POSIX)
 // Enables NTLMv2, which implicitly disables NTLMv1.
 const base::Feature kNtlmV2Enabled{"NtlmV2Enabled",
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 1395ff2..48f9e8f0 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -331,6 +331,8 @@
 COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kNewNetErrorPageUI;
 #endif
 
+COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kNoReferrers;
+
 #if defined(OS_POSIX)
 COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kNtlmV2Enabled;
 #endif
diff --git a/chrome/common/importer/profile_import.mojom b/chrome/common/importer/profile_import.mojom
index a61e549..6ea9e8f 100644
--- a/chrome/common/importer/profile_import.mojom
+++ b/chrome/common/importer/profile_import.mojom
@@ -72,7 +72,7 @@
       SourceProfile source_profile,
       uint16 items,
       map<uint32, string> localized_strings,
-      ProfileImportObserver observer);
+      pending_remote<ProfileImportObserver> observer);
 
   // Stop the importer.
   CancelImport();
diff --git a/chrome/common/media_router/mojom/media_router.mojom b/chrome/common/media_router/mojom/media_router.mojom
index db3c481..d0a17b4 100644
--- a/chrome/common/media_router/mojom/media_router.mojom
+++ b/chrome/common/media_router/mojom/media_router.mojom
@@ -484,7 +484,7 @@
   // between error conditions for metrics/debugging.
   CreateMediaRouteController(string route_id,
                              pending_receiver<MediaController> media_controller,
-                             MediaStatusObserver observer) =>
+                             pending_remote<MediaStatusObserver> observer) =>
                                  (bool success);
 };
 
@@ -523,8 +523,8 @@
   // Returns a string that uniquely identifies the Media Router browser
   // process.
   RegisterMediaRouteProvider(MediaRouteProvider.Id provider_id,
-                             MediaRouteProvider media_router_provider) =>
-      (string instance_id, MediaRouteProviderConfig config);
+      pending_remote<MediaRouteProvider> media_router_provider) =>
+          (string instance_id, MediaRouteProviderConfig config);
 
   // Called when a MediaRouteProvider receives a new list of |sinks|
   // compatible with |media_source|. The result is only valid for |origins|. If
diff --git a/chrome/credential_provider/common/BUILD.gn b/chrome/credential_provider/common/BUILD.gn
index 69a9bf52..1c3689a 100644
--- a/chrome/credential_provider/common/BUILD.gn
+++ b/chrome/credential_provider/common/BUILD.gn
@@ -10,4 +10,7 @@
     "gcp_strings.cc",
     "gcp_strings.h",
   ]
+  deps = [
+    "//build:branding_buildflags",
+  ]
 }
diff --git a/chrome/credential_provider/common/gcp_strings.cc b/chrome/credential_provider/common/gcp_strings.cc
index cbe8d4b9..0b231a9 100644
--- a/chrome/credential_provider/common/gcp_strings.cc
+++ b/chrome/credential_provider/common/gcp_strings.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/credential_provider/common/gcp_strings.h"
 
+#include "build/branding_buildflags.h"
+
 namespace credential_provider {
 
 // Names of keys returned on json data from UI process.
@@ -81,10 +83,10 @@
 
 const wchar_t kRunAsCrashpadHandlerEntryPoint[] = L"RunAsCrashpadHandler";
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 const wchar_t kRegHkcuAccountsPath[] = L"Software\\Google\\Accounts";
 #else
 const wchar_t kRegHkcuAccountsPath[] = L"Software\\Chromium\\Accounts";
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
 }  // namespace credential_provider
diff --git a/chrome/credential_provider/gaiacp/BUILD.gn b/chrome/credential_provider/gaiacp/BUILD.gn
index 38c9123..2efc879 100644
--- a/chrome/credential_provider/gaiacp/BUILD.gn
+++ b/chrome/credential_provider/gaiacp/BUILD.gn
@@ -37,6 +37,7 @@
   deps = [
     ":string_resources",
     "//base",
+    "//build:branding_buildflags",
     "//chrome/common:version_header",
     "//components/crash/core/common",
     "//components/version_info",
@@ -105,6 +106,7 @@
     ":gaia_credential_provider_idl",
     ":static_resources",
     "../eventlog:gcp_eventlog_messages",
+    "//build:branding_buildflags",
     "//chrome/common:version_header",
     "//chrome/installer/launcher_support",
     "//components/crash/content/app:app",
@@ -212,6 +214,7 @@
     ":common",
     ":gaiacp_lib",
     ":version",
+    "//build:branding_buildflags",
     "//chrome/common:version_header",
   ]
   configs += [ "//build/config/win:windowed" ]
diff --git a/chrome/credential_provider/gaiacp/associated_user_validator_unittests.cc b/chrome/credential_provider/gaiacp/associated_user_validator_unittests.cc
index 109cbb0..e0100d7 100644
--- a/chrome/credential_provider/gaiacp/associated_user_validator_unittests.cc
+++ b/chrome/credential_provider/gaiacp/associated_user_validator_unittests.cc
@@ -9,6 +9,7 @@
 #include "base/synchronization/waitable_event.h"
 #include "base/test/test_reg_util_win.h"
 #include "base/time/time_override.h"
+#include "build/branding_buildflags.h"
 #include "chrome/credential_provider/common/gcp_strings.h"
 #include "chrome/credential_provider/gaiacp/associated_user_validator.h"
 #include "chrome/credential_provider/gaiacp/gaia_credential_provider.h"
@@ -377,7 +378,7 @@
   const bool contains_stored_password = std::get<6>(GetParam());
   GoogleMdmEnrolledStatusForTesting forced_status(mdm_enrolled);
 
-#if !defined(GOOGLE_CHROME_BUILD)
+#if !BUILDFLAG(GOOGLE_CHROME_BRANDING)
   GoogleMdmEscrowServiceEnablerForTesting escrow_service_enabler(true);
 #endif
 
@@ -513,7 +514,7 @@
 }
 
 TEST_F(AssociatedUserValidatorTest, InvalidTokenHandle_MissingPasswordLsaData) {
-#if !defined(GOOGLE_CHROME_BUILD)
+#if !BUILDFLAG(GOOGLE_CHROME_BRANDING)
   GoogleMdmEscrowServiceEnablerForTesting escrow_service_enabler(true);
 #endif
 
@@ -544,7 +545,7 @@
 }
 
 TEST_F(AssociatedUserValidatorTest, ValidTokenHandle_PresentPasswordLsaData) {
-#if !defined(GOOGLE_CHROME_BUILD)
+#if !BUILDFLAG(GOOGLE_CHROME_BRANDING)
   GoogleMdmEscrowServiceEnablerForTesting escrow_service_enabler(true);
 #endif
 
diff --git a/chrome/credential_provider/gaiacp/dllmain.cc b/chrome/credential_provider/gaiacp/dllmain.cc
index 0422735..b3eb9c0 100644
--- a/chrome/credential_provider/gaiacp/dllmain.cc
+++ b/chrome/credential_provider/gaiacp/dllmain.cc
@@ -24,6 +24,7 @@
 #include "base/win/current_module.h"
 #include "base/win/registry.h"
 #include "base/win/scoped_com_initializer.h"
+#include "build/branding_buildflags.h"
 #include "chrome/common/chrome_version.h"
 #include "chrome/credential_provider/common/gcp_strings.h"
 #include "chrome/credential_provider/gaiacp/gaia_credential.h"
@@ -99,7 +100,7 @@
     LOGFN(INFO) << "_AtlModule.DllRegisterServer hr=" << putHR(hr);
   }
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // Register with Google Update.
   if (SUCCEEDED(hr)) {
     base::win::RegKey key(HKEY_LOCAL_MACHINE,
@@ -119,14 +120,14 @@
       }
     }
   }
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
   return hr;
 }
 
 // DllUnregisterServer - Removes entries from the system registry.
 STDAPI DllUnregisterServer(void) {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // Unregister with Google Update.
   base::win::RegKey key(HKEY_LOCAL_MACHINE, L"", DELETE | KEY_WOW64_32KEY);
   LONG sts = key.DeleteKey(credential_provider::kRegUpdaterClientsAppPath);
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_base.cc b/chrome/credential_provider/gaiacp/gaia_credential_base.cc
index 60fd50d..a2328282 100644
--- a/chrome/credential_provider/gaiacp/gaia_credential_base.cc
+++ b/chrome/credential_provider/gaiacp/gaia_credential_base.cc
@@ -31,6 +31,7 @@
 #include "base/win/registry.h"
 #include "base/win/scoped_com_initializer.h"
 #include "base/win/scoped_handle.h"
+#include "build/branding_buildflags.h"
 #include "chrome/credential_provider/common/gcp_strings.h"
 #include "chrome/credential_provider/gaiacp/associated_user_validator.h"
 #include "chrome/credential_provider/gaiacp/auth_utils.h"
@@ -1116,7 +1117,7 @@
 
 // static
 void CGaiaCredentialBase::TellOmahaDidRun() {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // Tell omaha that product was used.  Best effort only.
   //
   // This code always runs as LocalSystem, which means that HKCU maps to
@@ -1132,7 +1133,7 @@
     if (sts != ERROR_SUCCESS)
       LOGFN(INFO) << "Unable to write omaha dr value sts=" << sts;
   }
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 }
 
 void CGaiaCredentialBase::PreventDenyAccessUpdate() {
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc b/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc
index 9fdc63b8..56840227 100644
--- a/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc
+++ b/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc
@@ -8,6 +8,7 @@
 
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/branding_buildflags.h"
 #include "chrome/credential_provider/common/gcp_strings.h"
 #include "chrome/credential_provider/gaiacp/gaia_credential_base.h"
 #include "chrome/credential_provider/gaiacp/gaia_resources.h"
@@ -1273,7 +1274,7 @@
 TEST_P(GcpGaiaCredentialBasePasswordRecoveryTest, PasswordRecovery) {
   // Enable standard escrow service features in non-Chrome builds so that
   // the escrow service code can be tested by the build machines.
-#if !defined(GOOGLE_CHROME_BUILD)
+#if !BUILDFLAG(GOOGLE_CHROME_BRANDING)
   GoogleMdmEscrowServiceEnablerForTesting escrow_service_enabler(true);
 #endif
   USES_CONVERSION;
@@ -1497,7 +1498,7 @@
        PasswordRecovery_Disabled) {
   // Enable standard escrow service features in non-Chrome builds so that
   // the escrow service code can be tested by the build machines.
-#if !defined(GOOGLE_CHROME_BUILD)
+#if !BUILDFLAG(GOOGLE_CHROME_BRANDING)
   GoogleMdmEscrowServiceEnablerForTesting escrow_service_enabler(true);
 #endif
   USES_CONVERSION;
diff --git a/chrome/credential_provider/gaiacp/gcp_crash_reporter_client.cc b/chrome/credential_provider/gaiacp/gcp_crash_reporter_client.cc
index 90e1d99c..6734218 100644
--- a/chrome/credential_provider/gaiacp/gcp_crash_reporter_client.cc
+++ b/chrome/credential_provider/gaiacp/gcp_crash_reporter_client.cc
@@ -8,6 +8,7 @@
 #include "base/files/file_path.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/win/registry.h"
+#include "build/branding_buildflags.h"
 #include "chrome/credential_provider/gaiacp/gcp_crash_reporting_utils.h"
 
 namespace credential_provider {
@@ -101,7 +102,7 @@
 }
 
 bool GcpCrashReporterClient::GetCollectStatsConsent() {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   return GetGCPWCollectStatsConsent();
 #else
   return false;
diff --git a/chrome/credential_provider/gaiacp/gcp_crash_reporting.cc b/chrome/credential_provider/gaiacp/gcp_crash_reporting.cc
index 82cb01f..5190f6f 100644
--- a/chrome/credential_provider/gaiacp/gcp_crash_reporting.cc
+++ b/chrome/credential_provider/gaiacp/gcp_crash_reporting.cc
@@ -8,6 +8,7 @@
 #include "base/debug/leak_annotations.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/win/current_module.h"
+#include "build/branding_buildflags.h"
 #include "chrome/credential_provider/common/gcp_strings.h"
 #include "chrome/credential_provider/gaiacp/gcp_crash_reporter_client.h"
 #include "chrome/credential_provider/gaiacp/gcp_crash_reporting_utils.h"
@@ -87,9 +88,9 @@
       process_type.empty(), "GCPW DLL", "", dll_main_cmd_line.GetProgram(),
       {base::UTF16ToUTF8(dll_main_cmd_line.GetArgs()[0])});
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   SetCommonCrashKeys(command_line);
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 }
 
 }  // namespace credential_provider
diff --git a/chrome/credential_provider/gaiacp/reg_utils.cc b/chrome/credential_provider/gaiacp/reg_utils.cc
index f253448..11a7d229 100644
--- a/chrome/credential_provider/gaiacp/reg_utils.cc
+++ b/chrome/credential_provider/gaiacp/reg_utils.cc
@@ -12,16 +12,17 @@
 #include "base/strings/stringprintf.h"
 #include "base/win/registry.h"
 #include "base/win/win_util.h"
+#include "build/branding_buildflags.h"
 #include "chrome/credential_provider/common/gcp_strings.h"
 
 namespace credential_provider {
 
 // Root registry key for GCP configuration and state.
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #define CREDENTIAL_PROVIDER_REGISTRY_KEY L"Software\\Google\\GCP"
 #else
 #define CREDENTIAL_PROVIDER_REGISTRY_KEY L"Software\\Chromium\\GCP"
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
 const wchar_t kGcpRootKeyName[] = CREDENTIAL_PROVIDER_REGISTRY_KEY;
 
diff --git a/chrome/credential_provider/setup/BUILD.gn b/chrome/credential_provider/setup/BUILD.gn
index 8906ae3..1bfacb7 100644
--- a/chrome/credential_provider/setup/BUILD.gn
+++ b/chrome/credential_provider/setup/BUILD.gn
@@ -70,6 +70,7 @@
     ":version",
     "../eventlog:gcp_eventlog_messages",
     "../gaiacp:common",
+    "//build:branding_buildflags",
     "//chrome/common:version_header",
     "//components/crash/content/app:app",
     "//components/crash/content/app:crash_export_thunks",
diff --git a/chrome/credential_provider/setup/gcp_installer_crash_reporting.cc b/chrome/credential_provider/setup/gcp_installer_crash_reporting.cc
index ba11420..7bce44be6 100644
--- a/chrome/credential_provider/setup/gcp_installer_crash_reporting.cc
+++ b/chrome/credential_provider/setup/gcp_installer_crash_reporting.cc
@@ -13,6 +13,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/version.h"
 #include "base/win/registry.h"
+#include "build/branding_buildflags.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/credential_provider/common/gcp_strings.h"
 #include "chrome/credential_provider/gaiacp/gcp_crash_reporter_client.h"
@@ -39,7 +40,7 @@
   crash_reporter::InitializeCrashpadWithEmbeddedHandler(true, "GCPW Installer",
                                                         "", base::FilePath());
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   SetCommonCrashKeys(command_line);
 
   static crash_reporter::CrashKeyString<64> operation("operation");
@@ -48,7 +49,7 @@
       command_line.HasSwitch(credential_provider::switches::kUninstall);
 
   operation.Set(is_uninstall ? "uninstall" : "install");
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 }
 
 }  // namespace credential_provider
diff --git a/chrome/credential_provider/test/BUILD.gn b/chrome/credential_provider/test/BUILD.gn
index 5455dcc..6ed135a 100644
--- a/chrome/credential_provider/test/BUILD.gn
+++ b/chrome/credential_provider/test/BUILD.gn
@@ -32,6 +32,7 @@
     "../gaiacp:version",
     "../setup:common",
     "//base",
+    "//build:branding_buildflags",
     "//chrome/test:credential_provider_test_utils",
     "//net:test_support",
     "//testing/gmock",
diff --git a/chrome/install_static/BUILD.gn b/chrome/install_static/BUILD.gn
index a9d691e..67301b6 100644
--- a/chrome/install_static/BUILD.gn
+++ b/chrome/install_static/BUILD.gn
@@ -11,6 +11,7 @@
 # Please don't add dependencies on other system libraries.
 static_library("install_static_util") {
   deps = [
+    "//build:branding_buildflags",
     "//components/nacl/common:buildflags",
     "//components/version_info:channel",
     "//components/version_info:generate_version_info",
@@ -94,6 +95,7 @@
     "//base",
     "//base/test:run_all_unittests",
     "//base/test:test_support",
+    "//build:branding_buildflags",
     "//chrome/install_static:install_static_util",
     "//chrome/install_static/test:test_support",
     "//testing/gmock",
diff --git a/chrome/install_static/install_util.cc b/chrome/install_static/install_util.cc
index 75a855f..07d4542 100644
--- a/chrome/install_static/install_util.cc
+++ b/chrome/install_static/install_util.cc
@@ -14,6 +14,7 @@
 #include <memory>
 #include <sstream>
 
+#include "build/branding_buildflags.h"
 #include "chrome/chrome_elf/nt_registry/nt_registry.h"
 #include "chrome/install_static/install_details.h"
 #include "chrome/install_static/install_modes.h"
@@ -664,7 +665,7 @@
 }
 
 version_info::Channel GetChromeChannel() {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   std::wstring channel_name(GetChromeChannelName());
   if (channel_name.empty()) {
     return version_info::Channel::STABLE;
diff --git a/chrome/install_static/install_util_unittest.cc b/chrome/install_static/install_util_unittest.cc
index 71081f0..e94e63d 100644
--- a/chrome/install_static/install_util_unittest.cc
+++ b/chrome/install_static/install_util_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/strings/string_util.h"
 #include "base/test/test_reg_util_win.h"
 #include "base/win/win_util.h"
+#include "build/branding_buildflags.h"
 #include "chrome/chrome_elf/nt_registry/nt_registry.h"
 #include "chrome/install_static/install_details.h"
 #include "chrome/install_static/install_modes.h"
@@ -318,7 +319,7 @@
   }
 
   void SetMetricsReportingPolicy(DWORD value) {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
     static constexpr wchar_t kPolicyKey[] =
         L"Software\\Policies\\Google\\Chrome";
 #else
@@ -360,7 +361,7 @@
 };
 
 TEST_P(InstallStaticUtilTest, GetChromeInstallSubDirectory) {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // The directory strings for the brand's install modes; parallel to
   // kInstallModes.
   static constexpr const wchar_t* kInstallDirs[] = {
@@ -381,7 +382,7 @@
 }
 
 TEST_P(InstallStaticUtilTest, GetRegistryPath) {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // The registry path strings for the brand's install modes; parallel to
   // kInstallModes.
   static constexpr const wchar_t* kRegistryPaths[] = {
@@ -402,7 +403,7 @@
 }
 
 TEST_P(InstallStaticUtilTest, GetUninstallRegistryPath) {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // The uninstall registry path strings for the brand's install modes; parallel
   // to kInstallModes.
   static constexpr const wchar_t* kUninstallRegistryPaths[] = {
@@ -435,7 +436,7 @@
     return;
   }
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // The app guids for the brand's install modes; parallel to kInstallModes.
   static constexpr const wchar_t* kAppGuids[] = {
       L"{8A69D345-D564-463c-AFF1-A69D9E530F96}",  // Google Chrome.
@@ -452,7 +453,7 @@
 }
 
 TEST_P(InstallStaticUtilTest, GetBaseAppId) {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // The base app ids for the brand's install modes; parallel to kInstallModes.
   static constexpr const wchar_t* kBaseAppIds[] = {
       L"Chrome", L"ChromeBeta", L"ChromeDev", L"ChromeCanary",
@@ -469,7 +470,7 @@
 }
 
 TEST_P(InstallStaticUtilTest, GetToastActivatorClsid) {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // The toast activator CLSIDs for the brand's install modes; parallel to
   // kInstallModes.
   static constexpr CLSID kToastActivatorClsids[] = {
@@ -527,7 +528,7 @@
 }
 
 TEST_P(InstallStaticUtilTest, GetElevatorClsid) {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // The Elevator CLSIDs, one for each of the kInstallModes.
   static constexpr CLSID kElevatorClsids[] = {
       {0x708860E0,
@@ -581,7 +582,7 @@
 }
 
 TEST_P(InstallStaticUtilTest, GetElevatorIid) {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // The Elevator IIDs, one for each of the kInstallModes.
   static constexpr IID kElevatorIids[] = {
       {0x463abecf,
@@ -710,7 +711,7 @@
 }
 
 TEST_P(InstallStaticUtilTest, GetSandboxSidPrefix) {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   static constexpr const wchar_t* kSandBoxSids[] = {
       L"S-1-15-2-3251537155-1984446955-2931258699-841473695-1938553385-"
       L"924012149-",  // Google Chrome.
@@ -730,7 +731,7 @@
   EXPECT_STREQ(GetSandboxSidPrefix(), kSandBoxSids[std::get<0>(GetParam())]);
 }
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 // Stable supports user and system levels.
 INSTANTIATE_TEST_SUITE_P(Stable,
                          InstallStaticUtilTest,
@@ -751,12 +752,12 @@
                          InstallStaticUtilTest,
                          testing::Combine(testing::Values(CANARY_INDEX),
                                           testing::Values("user")));
-#else   // GOOGLE_CHROME_BUILD
+#else   // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 // Chromium supports user and system levels.
 INSTANTIATE_TEST_SUITE_P(Chromium,
                          InstallStaticUtilTest,
                          testing::Combine(testing::Values(CHROMIUM_INDEX),
                                           testing::Values("user", "system")));
-#endif  // !GOOGLE_CHROME_BUILD
+#endif  // !BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
 }  // namespace install_static
diff --git a/chrome/install_static/product_install_details_unittest.cc b/chrome/install_static/product_install_details_unittest.cc
index b3213f2..641a568 100644
--- a/chrome/install_static/product_install_details_unittest.cc
+++ b/chrome/install_static/product_install_details_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/test/test_reg_util_win.h"
 #include "base/win/registry.h"
 #include "base/win/windows_version.h"
+#include "build/branding_buildflags.h"
 #include "chrome/chrome_elf/nt_registry/nt_registry.h"
 #include "chrome/install_static/install_constants.h"
 #include "chrome/install_static/install_details.h"
@@ -128,7 +129,7 @@
   const wchar_t* channel;
 };
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 constexpr TestData kTestData[] = {
     {
         L"C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
@@ -169,7 +170,7 @@
         CANARY_INDEX, false, L"canary",
     },
 };
-#else   // GOOGLE_CHROME_BUILD
+#else   // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 constexpr TestData kTestData[] = {
     {
         L"C:\\Program Files (x86)\\Chromium\\Application\\chrome.exe",
@@ -180,7 +181,7 @@
         CHROMIUM_INDEX, false, L"",
     },
 };
-#endif  // !GOOGLE_CHROME_BUILD
+#endif  // !BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
 }  // namespace
 
diff --git a/chrome/install_static/user_data_dir_win_unittest.cc b/chrome/install_static/user_data_dir_win_unittest.cc
index 2e987f0..54f86a3 100644
--- a/chrome/install_static/user_data_dir_win_unittest.cc
+++ b/chrome/install_static/user_data_dir_win_unittest.cc
@@ -5,6 +5,7 @@
 #include <algorithm>
 
 #include "base/test/test_reg_util_win.h"
+#include "build/branding_buildflags.h"
 #include "chrome/chrome_elf/nt_registry/nt_registry.h"
 #include "chrome/install_static/install_details.h"
 #include "chrome/install_static/user_data_dir.h"
@@ -19,7 +20,7 @@
   return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
 }
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 const wchar_t kPolicyRegistryKey[] = L"SOFTWARE\\Policies\\Google\\Chrome";
 const wchar_t kUserDataDirNameSuffix[] = L"\\Google\\Chrome\\User Data";
 #else
diff --git a/chrome/renderer/safe_browsing/phishing_classifier_delegate.cc b/chrome/renderer/safe_browsing/phishing_classifier_delegate.cc
index 37117f0a..b2a77bf4 100644
--- a/chrome/renderer/safe_browsing/phishing_classifier_delegate.cc
+++ b/chrome/renderer/safe_browsing/phishing_classifier_delegate.cc
@@ -21,6 +21,7 @@
 #include "content/public/renderer/document_state.h"
 #include "content/public/renderer/render_frame.h"
 #include "content/public/renderer/render_thread.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "third_party/blink/public/platform/web_url.h"
 #include "third_party/blink/public/web/web_document.h"
@@ -52,9 +53,9 @@
 
 // static
 void PhishingClassifierFilter::Create(
-    mojom::PhishingModelSetterRequest request) {
-  mojo::MakeStrongBinding(std::make_unique<PhishingClassifierFilter>(),
-                          std::move(request));
+    mojo::PendingReceiver<mojom::PhishingModelSetter> receiver) {
+  mojo::MakeSelfOwnedReceiver(std::make_unique<PhishingClassifierFilter>(),
+                              std::move(receiver));
 }
 
 PhishingClassifierFilter::PhishingClassifierFilter() {}
@@ -105,7 +106,7 @@
     SetPhishingScorer(g_phishing_scorer.Get().get());
 
   registry_.AddInterface(
-      base::BindRepeating(&PhishingClassifierDelegate::PhishingDetectorRequest,
+      base::BindRepeating(&PhishingClassifierDelegate::PhishingDetectorReceiver,
                           base::Unretained(this)));
 }
 
@@ -131,9 +132,9 @@
   MaybeStartClassification();
 }
 
-void PhishingClassifierDelegate::PhishingDetectorRequest(
-    mojom::PhishingDetectorRequest request) {
-  phishing_detector_bindings_.AddBinding(this, std::move(request));
+void PhishingClassifierDelegate::PhishingDetectorReceiver(
+    mojo::PendingReceiver<mojom::PhishingDetector> receiver) {
+  phishing_detector_receivers_.Add(this, std::move(receiver));
 }
 
 void PhishingClassifierDelegate::OnInterfaceRequestForFrame(
diff --git a/chrome/renderer/safe_browsing/phishing_classifier_delegate.h b/chrome/renderer/safe_browsing/phishing_classifier_delegate.h
index f052d725..91755fe 100644
--- a/chrome/renderer/safe_browsing/phishing_classifier_delegate.h
+++ b/chrome/renderer/safe_browsing/phishing_classifier_delegate.h
@@ -14,8 +14,8 @@
 #include "components/safe_browsing/common/safe_browsing.mojom.h"
 #include "content/public/renderer/render_frame_observer.h"
 #include "content/public/renderer/render_thread_observer.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
 #include "ui/base/page_transition_types.h"
 #include "url/gurl.h"
@@ -30,14 +30,13 @@
   PhishingClassifierFilter();
   ~PhishingClassifierFilter() override;
 
-  static void Create(mojom::PhishingModelSetterRequest request);
+  static void Create(
+      mojo::PendingReceiver<mojom::PhishingModelSetter> receiver);
 
  private:
   // mojom::PhishingModelSetter
   void SetPhishingModel(const std::string& model) override;
 
-  mojo::StrongBindingPtr<mojom::PhishingModelSetter> binding_;
-
   DISALLOW_COPY_AND_ASSIGN(PhishingClassifierFilter);
 };
 
@@ -86,7 +85,8 @@
     CANCEL_CLASSIFICATION_MAX  // Always add new values before this one.
   };
 
-  void PhishingDetectorRequest(mojom::PhishingDetectorRequest request);
+  void PhishingDetectorReceiver(
+      mojo::PendingReceiver<mojom::PhishingDetector> receiver);
 
   // Cancels any pending classification and frees the page text.
   void CancelPendingClassification(CancelClassificationReason reason);
@@ -153,7 +153,7 @@
   // The callback from the most recent call to StartPhishingDetection.
   StartPhishingDetectionCallback callback_;
 
-  mojo::BindingSet<mojom::PhishingDetector> phishing_detector_bindings_;
+  mojo::ReceiverSet<mojom::PhishingDetector> phishing_detector_receivers_;
 
   service_manager::BinderRegistry registry_;
 
diff --git a/chrome/test/base/memory_tracing_browsertest.cc b/chrome/test/base/memory_tracing_browsertest.cc
index 85ac8c74..f50cdae7 100644
--- a/chrome/test/base/memory_tracing_browsertest.cc
+++ b/chrome/test/base/memory_tracing_browsertest.cc
@@ -26,6 +26,7 @@
 
 namespace {
 
+using base::trace_event::MemoryDumpDeterminism;
 using base::trace_event::MemoryDumpManager;
 using base::trace_event::MemoryDumpType;
 using tracing::BeginTracingWithTraceConfig;
@@ -44,6 +45,7 @@
   memory_instrumentation::MemoryInstrumentation::GetInstance()
       ->RequestGlobalDumpAndAppendToTrace(
           MemoryDumpType::EXPLICITLY_TRIGGERED, explicit_dump_type,
+          MemoryDumpDeterminism::NONE,
           Bind(&RequestGlobalDumpCallback, quit_closure));
 }
 
diff --git a/chrome/test/data/webui/settings/chromeos/app_management/pwa_permission_view_test.js b/chrome/test/data/webui/settings/chromeos/app_management/pwa_permission_view_test.js
index c49f165..954b64f 100644
--- a/chrome/test/data/webui/settings/chromeos/app_management/pwa_permission_view_test.js
+++ b/chrome/test/data/webui/settings/chromeos/app_management/pwa_permission_view_test.js
@@ -8,20 +8,13 @@
   let pwaPermissionView;
   let fakeHandler;
 
-  function getPermissionToggleByType(permissionType) {
-    return pwaPermissionView.root
-        .querySelector('[permission-type=' + permissionType + ']')
-        .root.querySelector('app-management-permission-toggle')
-        .root.querySelector('cr-toggle');
-  }
-
   function getPermissionBoolByType(permissionType) {
     return app_management.util.getPermissionValueBool(
         pwaPermissionView.app_, permissionType);
   }
 
   async function clickToggle(permissionType) {
-    getPermissionToggleByType(permissionType).click();
+    getPermissionToggleByType(pwaPermissionView, permissionType).click();
     await fakeHandler.flushPipesForTesting();
   }
 
@@ -54,17 +47,20 @@
   test('toggle permissions', async function() {
     const checkToggle = async (permissionType) => {
       assertTrue(getPermissionBoolByType(permissionType));
-      assertTrue(getPermissionToggleByType(permissionType).checked);
+      assertTrue(getPermissionCrToggleByType(pwaPermissionView, permissionType)
+                     .checked);
 
       // Toggle off.
       await clickToggle(permissionType);
       assertFalse(getPermissionBoolByType(permissionType));
-      assertFalse(getPermissionToggleByType(permissionType).checked);
+      assertFalse(getPermissionCrToggleByType(pwaPermissionView, permissionType)
+                      .checked);
 
       // Toggle on.
       await clickToggle(permissionType);
       assertTrue(getPermissionBoolByType(permissionType));
-      assertTrue(getPermissionToggleByType(permissionType).checked);
+      assertTrue(getPermissionCrToggleByType(pwaPermissionView, permissionType)
+                     .checked);
     };
 
     await checkToggle('CONTENT_SETTINGS_TYPE_NOTIFICATIONS');
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
index 8f9dcb0..8612521 100644
--- a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
@@ -253,11 +253,9 @@
   }
 };
 
-TEST_F(
-    'OSSettingsAppManagementPwaPermissionViewTest', 'DISABLED_AllJsTests',
-    () => {
-      mocha.run();
-    });
+TEST_F('OSSettingsAppManagementPwaPermissionViewTest', 'AllJsTests', () => {
+  mocha.run();
+});
 
 // Test fixture for the app management arc permission view element.
 // eslint-disable-next-line no-var
@@ -276,11 +274,9 @@
   }
 };
 
-TEST_F(
-    'OSSettingsAppManagementArcPermissionViewTest', 'DISABLED_AllJsTests',
-    () => {
-      mocha.run();
-    });
+TEST_F('OSSettingsAppManagementArcPermissionViewTest', 'AllJsTests', () => {
+  mocha.run();
+});
 
 // Test fixture for the app management managed app view.
 // eslint-disable-next-line no-var
@@ -316,7 +312,7 @@
   }
 };
 
-TEST_F('OSSettingsAppManagementReducersTest', 'DISABLED_AllJsTests', () => {
+TEST_F('OSSettingsAppManagementReducersTest', 'AllJsTests', () => {
   mocha.run();
 });
 
diff --git a/chrome/test/media_router/media_router_ui_for_test.cc b/chrome/test/media_router/media_router_ui_for_test.cc
index 2c7c4aa..45ad243 100644
--- a/chrome/test/media_router/media_router_ui_for_test.cc
+++ b/chrome/test/media_router/media_router_ui_for_test.cc
@@ -5,6 +5,7 @@
 #include "chrome/test/media_router/media_router_ui_for_test.h"
 
 #include "base/bind.h"
+#include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/media/router/media_router_factory.h"
 #include "chrome/browser/media/router/media_routes_observer.h"
diff --git a/chrome/utility/importer/external_process_importer_bridge.cc b/chrome/utility/importer/external_process_importer_bridge.cc
index 9c9c671..cc684e1 100644
--- a/chrome/utility/importer/external_process_importer_bridge.cc
+++ b/chrome/utility/importer/external_process_importer_bridge.cc
@@ -4,6 +4,9 @@
 
 #include "chrome/utility/importer/external_process_importer_bridge.h"
 
+#include <algorithm>
+#include <utility>
+
 #include "base/bind.h"
 #include "base/debug/dump_without_crashing.h"
 #include "base/logging.h"
@@ -16,8 +19,6 @@
 #include "chrome/common/importer/importer_data_types.h"
 #include "components/autofill/core/common/password_form.h"
 
-using chrome::mojom::ProfileImportObserver;
-
 namespace {
 
 // Rather than sending all import items over IPC at once we chunk them into
@@ -32,14 +33,14 @@
 
 ExternalProcessImporterBridge::ExternalProcessImporterBridge(
     const base::flat_map<uint32_t, std::string>& localized_strings,
-    scoped_refptr<chrome::mojom::ThreadSafeProfileImportObserverPtr> observer)
+    mojo::SharedRemote<chrome::mojom::ProfileImportObserver> observer)
     : localized_strings_(std::move(localized_strings)),
       observer_(std::move(observer)) {}
 
 void ExternalProcessImporterBridge::AddBookmarks(
     const std::vector<ImportedBookmarkEntry>& bookmarks,
     const base::string16& first_folder_name) {
-  (*observer_)->OnBookmarksImportStart(first_folder_name, bookmarks.size());
+  observer_->OnBookmarksImportStart(first_folder_name, bookmarks.size());
 
   // |bookmarks_left| is required for the checks below as Windows has a
   // Debug bounds-check which prevents pushing an iterator beyond its end()
@@ -50,7 +51,7 @@
     auto end_group = it + std::min(bookmarks_left, kNumBookmarksToSend);
     bookmark_group.assign(it, end_group);
 
-    (*observer_)->OnBookmarksImportGroup(bookmark_group);
+    observer_->OnBookmarksImportGroup(bookmark_group);
     bookmarks_left -= end_group - it;
     it = end_group;
   }
@@ -58,12 +59,12 @@
 }
 
 void ExternalProcessImporterBridge::AddHomePage(const GURL& home_page) {
-  (*observer_)->OnHomePageImportReady(home_page);
+  observer_->OnHomePageImportReady(home_page);
 }
 
 void ExternalProcessImporterBridge::SetFavicons(
     const favicon_base::FaviconUsageDataList& favicons) {
-  (*observer_)->OnFaviconsImportStart(favicons.size());
+  observer_->OnFaviconsImportStart(favicons.size());
 
   // |favicons_left| is required for the checks below as Windows has a
   // Debug bounds-check which prevents pushing an iterator beyond its end()
@@ -74,7 +75,7 @@
     auto end_group = it + std::min(favicons_left, kNumFaviconsToSend);
     favicons_group.assign(it, end_group);
 
-    (*observer_)->OnFaviconsImportGroup(favicons_group);
+    observer_->OnFaviconsImportGroup(favicons_group);
     favicons_left -= end_group - it;
     it = end_group;
   }
@@ -84,7 +85,7 @@
 void ExternalProcessImporterBridge::SetHistoryItems(
     const std::vector<ImporterURLRow>& rows,
     importer::VisitSource visit_source) {
-  (*observer_)->OnHistoryImportStart(rows.size());
+  observer_->OnHistoryImportStart(rows.size());
 
   // |rows_left| is required for the checks below as Windows has a
   // Debug bounds-check which prevents pushing an iterator beyond its end()
@@ -95,7 +96,7 @@
     auto end_group = it + std::min(rows_left, kNumHistoryRowsToSend);
     row_group.assign(it, end_group);
 
-    (*observer_)->OnHistoryImportGroup(row_group, visit_source);
+    observer_->OnHistoryImportGroup(row_group, visit_source);
     rows_left -= end_group - it;
     it = end_group;
   }
@@ -105,22 +106,22 @@
 void ExternalProcessImporterBridge::SetKeywords(
     const std::vector<importer::SearchEngineInfo>& search_engines,
     bool unique_on_host_and_path) {
-  (*observer_)->OnKeywordsImportReady(search_engines, unique_on_host_and_path);
+  observer_->OnKeywordsImportReady(search_engines, unique_on_host_and_path);
 }
 
 void ExternalProcessImporterBridge::SetFirefoxSearchEnginesXMLData(
     const std::vector<std::string>& search_engine_data) {
-  (*observer_)->OnFirefoxSearchEngineDataReceived(search_engine_data);
+  observer_->OnFirefoxSearchEngineDataReceived(search_engine_data);
 }
 
 void ExternalProcessImporterBridge::SetPasswordForm(
     const autofill::PasswordForm& form) {
-  (*observer_)->OnPasswordFormImportReady(form);
+  observer_->OnPasswordFormImportReady(form);
 }
 
 void ExternalProcessImporterBridge::SetAutofillFormData(
     const std::vector<ImporterAutofillFormDataEntry>& entries) {
-  (*observer_)->OnAutofillFormDataImportStart(entries.size());
+  observer_->OnAutofillFormDataImportStart(entries.size());
 
   // |autofill_form_data_entries_left| is required for the checks below as
   // Windows has a Debug bounds-check which prevents pushing an iterator beyond
@@ -133,7 +134,7 @@
                                    kNumAutofillFormDataToSend);
     autofill_form_data_entry_group.assign(it, end_group);
 
-    (*observer_)->OnAutofillFormDataImportGroup(autofill_form_data_entry_group);
+    observer_->OnAutofillFormDataImportGroup(autofill_form_data_entry_group);
     autofill_form_data_entries_left -= end_group - it;
     it = end_group;
   }
@@ -141,20 +142,20 @@
 }
 
 void ExternalProcessImporterBridge::NotifyStarted() {
-  (*observer_)->OnImportStart();
+  observer_->OnImportStart();
 }
 
 void ExternalProcessImporterBridge::NotifyItemStarted(
     importer::ImportItem item) {
-  (*observer_)->OnImportItemStart(item);
+  observer_->OnImportItemStart(item);
 }
 
 void ExternalProcessImporterBridge::NotifyItemEnded(importer::ImportItem item) {
-  (*observer_)->OnImportItemFinished(item);
+  observer_->OnImportItemFinished(item);
 }
 
 void ExternalProcessImporterBridge::NotifyEnded() {
-  (*observer_)->OnImportFinished(true, std::string());
+  observer_->OnImportFinished(true, std::string());
 }
 
 base::string16 ExternalProcessImporterBridge::GetLocalizedString(
diff --git a/chrome/utility/importer/external_process_importer_bridge.h b/chrome/utility/importer/external_process_importer_bridge.h
index 5fd2913..58db1e3c5 100644
--- a/chrome/utility/importer/external_process_importer_bridge.h
+++ b/chrome/utility/importer/external_process_importer_bridge.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_UTILITY_IMPORTER_EXTERNAL_PROCESS_IMPORTER_BRIDGE_H_
 #define CHROME_UTILITY_IMPORTER_EXTERNAL_PROCESS_IMPORTER_BRIDGE_H_
 
-#include <memory>
 #include <string>
 #include <vector>
 
@@ -15,6 +14,7 @@
 #include "chrome/common/importer/importer_bridge.h"
 #include "chrome/common/importer/profile_import.mojom.h"
 #include "components/favicon_base/favicon_usage_data.h"
+#include "mojo/public/cpp/bindings/shared_remote.h"
 
 class GURL;
 struct ImportedBookmarkEntry;
@@ -38,8 +38,7 @@
   // |observer| must outlive this object.
   ExternalProcessImporterBridge(
       const base::flat_map<uint32_t, std::string>& localized_strings,
-      scoped_refptr<chrome::mojom::ThreadSafeProfileImportObserverPtr>
-          observer);
+      mojo::SharedRemote<chrome::mojom::ProfileImportObserver> observer);
 
   // Begin ImporterBridge implementation:
   void AddBookmarks(const std::vector<ImportedBookmarkEntry>& bookmarks,
@@ -79,7 +78,7 @@
   // bundle isn't available to the external process.
   base::flat_map<uint32_t, std::string> localized_strings_;
 
-  scoped_refptr<chrome::mojom::ThreadSafeProfileImportObserverPtr> observer_;
+  mojo::SharedRemote<chrome::mojom::ProfileImportObserver> observer_;
 
   DISALLOW_COPY_AND_ASSIGN(ExternalProcessImporterBridge);
 };
diff --git a/chrome/utility/importer/profile_import_impl.cc b/chrome/utility/importer/profile_import_impl.cc
index 98517c09..d5044a3 100644
--- a/chrome/utility/importer/profile_import_impl.cc
+++ b/chrome/utility/importer/profile_import_impl.cc
@@ -4,6 +4,9 @@
 
 #include "chrome/utility/importer/profile_import_impl.h"
 
+#include <string>
+#include <utility>
+
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/memory/ref_counted.h"
@@ -11,10 +14,13 @@
 #include "base/threading/thread.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
+#include "chrome/common/importer/profile_import.mojom.h"
 #include "chrome/utility/importer/external_process_importer_bridge.h"
 #include "chrome/utility/importer/importer.h"
 #include "chrome/utility/importer/importer_creator.h"
 #include "content/public/utility/utility_thread.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "mojo/public/cpp/bindings/shared_remote.h"
 
 #if defined(OS_MACOSX)
 #include <stdlib.h>
@@ -22,8 +28,6 @@
 #include "chrome/common/importer/firefox_importer_utils.h"
 #endif
 
-using chrome::mojom::ThreadSafeProfileImportObserverPtr;
-
 ProfileImportImpl::ProfileImportImpl(
     mojo::PendingReceiver<chrome::mojom::ProfileImport> receiver)
     : receiver_(this, std::move(receiver)) {
@@ -41,11 +45,12 @@
     const importer::SourceProfile& source_profile,
     uint16_t items,
     const base::flat_map<uint32_t, std::string>& localized_strings,
-    chrome::mojom::ProfileImportObserverPtr observer) {
+    mojo::PendingRemote<chrome::mojom::ProfileImportObserver> observer) {
   content::UtilityThread::Get()->EnsureBlinkInitialized();
   importer_ = importer::CreateImporterByType(source_profile.importer_type);
   if (!importer_.get()) {
-    observer->OnImportFinished(false, "Importer could not be created.");
+    mojo::Remote<chrome::mojom::ProfileImportObserver>(std::move(observer))
+        ->OnImportFinished(false, "Importer could not be created.");
     return;
   }
 
@@ -62,7 +67,8 @@
   }
   bridge_ = new ExternalProcessImporterBridge(
       localized_strings,
-      ThreadSafeProfileImportObserverPtr::Create(std::move(observer)));
+      mojo::SharedRemote<chrome::mojom::ProfileImportObserver>(
+          std::move(observer)));
   import_thread_->task_runner()->PostTask(
       FROM_HERE,
       base::BindOnce(&Importer::StartImport, importer_, source_profile, items,
diff --git a/chrome/utility/importer/profile_import_impl.h b/chrome/utility/importer/profile_import_impl.h
index ebd0986..081fc8f 100644
--- a/chrome/utility/importer/profile_import_impl.h
+++ b/chrome/utility/importer/profile_import_impl.h
@@ -8,11 +8,13 @@
 #include <stdint.h>
 
 #include <memory>
+#include <string>
 
 #include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "chrome/common/importer/profile_import.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 
 class ExternalProcessImporterBridge;
@@ -38,7 +40,8 @@
       const importer::SourceProfile& source_profile,
       uint16_t items,
       const base::flat_map<uint32_t, std::string>& localized_strings,
-      chrome::mojom::ProfileImportObserverPtr observer) override;
+      mojo::PendingRemote<chrome::mojom::ProfileImportObserver> observer)
+      override;
   void CancelImport() override;
   void ReportImportItemFinished(importer::ImportItem item) override;
 
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc
index 8ea4cb3..82363b1 100644
--- a/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -1362,34 +1362,7 @@
   CleanupOnDocumentShutdown();
 }
 
-void PasswordAutofillAgent::OnProbablyFormSubmitted() {
-  std::unique_ptr<RendererSavePasswordProgressLogger> logger;
-  if (logging_state_active_) {
-    logger.reset(new RendererSavePasswordProgressLogger(
-        GetPasswordManagerDriver().get()));
-    logger->LogMessage(Logger::STRING_DID_START_PROVISIONAL_LOAD_METHOD);
-  }
-
-  if (!FrameCanAccessPasswordManager()) {
-    if (logger)
-      logger->LogMessage(Logger::STRING_SECURITY_ORIGIN_FAILURE);
-    return;
-  }
-
-  // If onsubmit has been called, try and save that form.
-  if (provisionally_saved_form_.IsSet()) {
-    if (logger) {
-      logger->LogPasswordForm(Logger::STRING_PROVISIONALLY_SAVED_FORM_FOR_FRAME,
-                              provisionally_saved_form_.password_form());
-    }
-    provisionally_saved_form_.SetSubmissionIndicatorEvent(
-        SubmissionIndicatorEvent::
-            PROVISIONALLY_SAVED_FORM_ON_START_PROVISIONAL_LOAD);
-    GetPasswordManagerDriver()->PasswordFormSubmitted(
-        provisionally_saved_form_.password_form());
-    provisionally_saved_form_.Reset();
-  }
-}
+void PasswordAutofillAgent::OnProbablyFormSubmitted() {}
 
 // mojom::PasswordAutofillAgent:
 void PasswordAutofillAgent::FillPasswordForm(
diff --git a/components/autofill/core/common/form_field_data.cc b/components/autofill/core/common/form_field_data.cc
index 6aec9bf..fd68782 100644
--- a/components/autofill/core/common/form_field_data.cc
+++ b/components/autofill/core/common/form_field_data.cc
@@ -146,7 +146,7 @@
 
 FormFieldData::FormFieldData(const FormFieldData& other) = default;
 
-FormFieldData::~FormFieldData() {}
+FormFieldData::~FormFieldData() = default;
 
 bool FormFieldData::SameFieldAs(const FormFieldData& field) const {
 // TODO(crbug.com/896689): On iOS the unique_id member uniquely addresses
@@ -206,6 +206,22 @@
          form_control_type == "url" || form_control_type == "email";
 }
 
+bool FormFieldData::IsPasswordInputElement() const {
+  return form_control_type == "password";
+}
+
+bool FormFieldData::DidUserType() const {
+  return properties_mask & USER_TYPED;
+}
+
+bool FormFieldData::HadFocus() const {
+  return properties_mask & HAD_FOCUS;
+}
+
+bool FormFieldData::WasAutofilled() const {
+  return properties_mask & AUTOFILLED;
+}
+
 bool FormFieldData::operator==(const FormFieldData& field) const {
   return SameFieldAs(field) && unique_renderer_id == field.unique_renderer_id &&
          form_control_ax_id == field.form_control_ax_id &&
diff --git a/components/autofill/core/common/form_field_data.h b/components/autofill/core/common/form_field_data.h
index 301b200..c343c454 100644
--- a/components/autofill/core/common/form_field_data.h
+++ b/components/autofill/core/common/form_field_data.h
@@ -83,11 +83,19 @@
   // a textarea.
   bool IsTextInputElement() const;
 
+  bool IsPasswordInputElement() const;
+
   // Returns true if the field is visible to the user.
   bool IsVisible() const {
     return is_focusable && role != RoleAttribute::kPresentation;
   }
 
+  // These functions do not work for Autofill code.
+  // TODO(https://crbug.com/1006745): Fix this.
+  bool DidUserType() const;
+  bool HadFocus() const;
+  bool WasAutofilled() const;
+
   // Note: operator==() performs a full-field-comparison(byte by byte), this is
   // different from SameFieldAs(), which ignores comparison for those "values"
   // not regarded as part of identity of the field, such as is_autofilled and
diff --git a/components/crash/content/app/crashpad_linux.cc b/components/crash/content/app/crashpad_linux.cc
index 6378668..8df2da2 100644
--- a/components/crash/content/app/crashpad_linux.cc
+++ b/components/crash/content/app/crashpad_linux.cc
@@ -10,6 +10,7 @@
 #include "base/path_service.h"
 #include "base/posix/global_descriptors.h"
 #include "base/strings/string_number_conversions.h"
+#include "build/branding_buildflags.h"
 #include "components/crash/content/app/crash_reporter_client.h"
 #include "components/crash/content/app/crash_switches.h"
 #include "content/public/common/content_descriptors.h"
@@ -84,7 +85,7 @@
     // to ChromeOS's /sbin/crash_reporter which in turn passes the dump to
     // crash_sender which handles the upload.
     std::string url;
-#if defined(GOOGLE_CHROME_BUILD) && defined(OFFICIAL_BUILD) && \
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && defined(OFFICIAL_BUILD) && \
     !defined(OS_CHROMEOS)
     url = "https://clients2.google.com/cr/report";
 #else
@@ -99,7 +100,7 @@
     annotations["prod"] = product_name;
     annotations["ver"] = product_version;
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
     // Empty means stable.
     const bool allow_empty_channel = true;
 #else
diff --git a/components/cronet/cronet_url_request_context.h b/components/cronet/cronet_url_request_context.h
index 84ea2e5..eab25b5 100644
--- a/components/cronet/cronet_url_request_context.h
+++ b/components/cronet/cronet_url_request_context.h
@@ -15,6 +15,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/threading/thread.h"
+#include "base/threading/thread_checker.h"
 #include "components/prefs/json_pref_store.h"
 #include "net/nqe/effective_connection_type.h"
 #include "net/nqe/effective_connection_type_observer.h"
diff --git a/components/heap_profiling/supervisor.cc b/components/heap_profiling/supervisor.cc
index c4e153e5..4123812 100644
--- a/components/heap_profiling/supervisor.cc
+++ b/components/heap_profiling/supervisor.cc
@@ -153,6 +153,7 @@
             ->RequestGlobalDumpAndAppendToTrace(
                 base::trace_event::MemoryDumpType::EXPLICITLY_TRIGGERED,
                 base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND,
+                base::trace_event::MemoryDumpDeterminism::NONE,
                 base::AdaptCallbackForRepeating(
                     std::move(finished_dump_callback)));
       },
diff --git a/components/network_session_configurator/browser/network_session_configurator.cc b/components/network_session_configurator/browser/network_session_configurator.cc
index 3157ffec..237c7b3 100644
--- a/components/network_session_configurator/browser/network_session_configurator.cc
+++ b/components/network_session_configurator/browser/network_session_configurator.cc
@@ -321,6 +321,12 @@
       "true");
 }
 
+bool ShouldQuicAllowPortMigration(
+    const VariationParameters& quic_trial_params) {
+  return base::LowerCaseEqualsASCII(
+      GetVariationParam(quic_trial_params, "allow_port_migration"), "true");
+}
+
 bool ShouldQuicRetryOnAlternateNetworkBeforeHandshake(
     const VariationParameters& quic_trial_params) {
   return base::LowerCaseEqualsASCII(
@@ -404,12 +410,6 @@
   return 0;
 }
 
-bool ShouldQuicAllowServerMigration(
-    const VariationParameters& quic_trial_params) {
-  return base::LowerCaseEqualsASCII(
-      GetVariationParam(quic_trial_params, "allow_server_migration"), "true");
-}
-
 int GetQuicInitialRttForHandshakeMilliseconds(
     const VariationParameters& quic_trial_params) {
   int value;
@@ -533,6 +533,8 @@
         ShouldQuicMigrateSessionsOnNetworkChangeV2(quic_trial_params);
     params->quic_params.migrate_sessions_early_v2 =
         ShouldQuicMigrateSessionsEarlyV2(quic_trial_params);
+    params->quic_params.allow_port_migration =
+        ShouldQuicAllowPortMigration(quic_trial_params);
     params->quic_params.retry_on_alternate_network_before_handshake =
         ShouldQuicRetryOnAlternateNetworkBeforeHandshake(quic_trial_params);
     params->quic_params.go_away_on_path_degrading =
@@ -580,8 +582,6 @@
           .max_migrations_to_non_default_network_on_path_degrading =
           max_migrations_to_non_default_network_on_path_degrading;
     }
-    params->quic_params.allow_server_migration =
-        ShouldQuicAllowServerMigration(quic_trial_params);
     params->quic_host_allowlist = GetQuicHostAllowlist(quic_trial_params);
 
     SetQuicFlags(quic_trial_params);
diff --git a/components/network_session_configurator/browser/network_session_configurator_unittest.cc b/components/network_session_configurator/browser/network_session_configurator_unittest.cc
index e6deb28..7049d68 100644
--- a/components/network_session_configurator/browser/network_session_configurator_unittest.cc
+++ b/components/network_session_configurator/browser/network_session_configurator_unittest.cc
@@ -458,15 +458,15 @@
 }
 
 TEST_F(NetworkSessionConfiguratorTest,
-       QuicAllowServerMigrationFromFieldTrialParams) {
+       QuicAllowPortMigrationFromFieldTrialParams) {
   std::map<std::string, std::string> field_trial_params;
-  field_trial_params["allow_server_migration"] = "true";
+  field_trial_params["allow_port_migration"] = "true";
   variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
   base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
 
   ParseFieldTrials();
 
-  EXPECT_TRUE(params_.quic_params.allow_server_migration);
+  EXPECT_TRUE(params_.quic_params.allow_port_migration);
 }
 
 TEST_F(NetworkSessionConfiguratorTest, PacketLengthFromFieldTrialParams) {
diff --git a/components/password_manager/core/browser/credentials_filter.h b/components/password_manager/core/browser/credentials_filter.h
index 13b83d6..21b4520 100644
--- a/components/password_manager/core/browser/credentials_filter.h
+++ b/components/password_manager/core/browser/credentials_filter.h
@@ -10,7 +10,7 @@
 
 namespace password_manager {
 
-class PasswordFormManagerInterface;
+class PasswordFormManager;
 
 // This interface is used to filter credentials during saving, retrieval from
 // PasswordStore, etc.
@@ -35,7 +35,7 @@
   // Call this if the form associated with |form_manager| was filled, and the
   // subsequent sign-in looked like a success.
   virtual void ReportFormLoginSuccess(
-      const PasswordFormManagerInterface& form_manager) const {}
+      const PasswordFormManager& form_manager) const {}
 
   // If |username| matches Chrome sync account email. For incognito profile,
   // it matches |username| against the sync account email used in its original
diff --git a/components/password_manager/core/browser/password_form_manager.h b/components/password_manager/core/browser/password_form_manager.h
index 762e7f05..668ce74 100644
--- a/components/password_manager/core/browser/password_form_manager.h
+++ b/components/password_manager/core/browser/password_form_manager.h
@@ -36,10 +36,8 @@
 struct PossibleUsernameData;
 
 // This class helps with filling the observed form and with saving/updating the
-// stored information about it. It is aimed to replace PasswordFormManager and
-// to be renamed in new Password Manager design. Details
-// go/new-cpm-design-refactoring.
-class PasswordFormManager : public PasswordFormManagerInterface,
+// stored information about it.
+class PasswordFormManager : public PasswordFormManagerForUI,
                             public FormFetcher::Consumer {
  public:
   // TODO(crbug.com/621355): So far, |form_fetcher| can be null. In that case
@@ -159,20 +157,19 @@
   void PermanentlyBlacklist() override;
   void OnPasswordsRevealed() override;
 
-  // PasswordFormManagerInterface:
-  bool IsNewLogin() const override;
-  FormFetcher* GetFormFetcher() override;
-  bool IsPendingCredentialsPublicSuffixMatch() const override;
-  void PresaveGeneratedPassword(const autofill::PasswordForm& form) override;
-  void PasswordNoLongerGenerated() override;
-  bool HasGeneratedPassword() const override;
+  bool IsNewLogin() const;
+  FormFetcher* GetFormFetcher();
+  bool IsPendingCredentialsPublicSuffixMatch() const;
+  void PresaveGeneratedPassword(const autofill::PasswordForm& form);
+  void PasswordNoLongerGenerated();
+  bool HasGeneratedPassword() const;
   void SetGenerationPopupWasShown(bool generation_popup_was_shown,
-                                  bool is_manual_generation) override;
-  void SetGenerationElement(const base::string16& generation_element) override;
-  bool IsPossibleChangePasswordFormWithoutUsername() const override;
-  bool IsPasswordUpdate() const override;
-  std::vector<base::WeakPtr<PasswordManagerDriver>> GetDrivers() const override;
-  const autofill::PasswordForm* GetSubmittedForm() const override;
+                                  bool is_manual_generation);
+  void SetGenerationElement(const base::string16& generation_element);
+  bool IsPossibleChangePasswordFormWithoutUsername() const;
+  bool IsPasswordUpdate() const;
+  std::vector<base::WeakPtr<PasswordManagerDriver>> GetDrivers() const;
+  const autofill::PasswordForm* GetSubmittedForm() const;
 
 #if defined(OS_IOS)
   // Presaves the form with |generated_password|. This function is called once
diff --git a/components/password_manager/core/browser/password_form_manager_for_ui.h b/components/password_manager/core/browser/password_form_manager_for_ui.h
index e92b81b..a859769 100644
--- a/components/password_manager/core/browser/password_form_manager_for_ui.h
+++ b/components/password_manager/core/browser/password_form_manager_for_ui.h
@@ -19,7 +19,6 @@
 
 namespace password_manager {
 
-class FormFetcher;
 struct InteractionsStats;
 class PasswordFormMetricsRecorder;
 
@@ -98,64 +97,6 @@
   virtual void OnPasswordsRevealed() = 0;
 };
 
-class PasswordManagerDriver;
-
-// This is a temporary class for unification of processing of old an new
-// PasswordFormManager in PasswordManager.
-// TODO(https://crbug.com/831123): Remove when the old PasswordFormManager is
-// gone.
-class PasswordFormManagerInterface : public PasswordFormManagerForUI {
- public:
-  // Returns whether it is a new (i.e. not saved yet) credentials.
-  virtual bool IsNewLogin() const = 0;
-
-  // Returns the form fetcher which is responsible for fetching saved matches
-  // from the store for the observed from.
-  virtual FormFetcher* GetFormFetcher() = 0;
-
-  // Returns true if the current pending credentials were found using
-  // origin matching of the public suffix, instead of the signon realm of the
-  // form.
-  virtual bool IsPendingCredentialsPublicSuffixMatch() const = 0;
-
-  // Called when generated password is accepted or changed by user.
-  virtual void PresaveGeneratedPassword(const autofill::PasswordForm& form) = 0;
-
-  // Called when user removed a generated password.
-  virtual void PasswordNoLongerGenerated() = 0;
-
-  // Returns if the password was generated.
-  virtual bool HasGeneratedPassword() const = 0;
-
-  // Called when the generation popup is shown. |is_manual_generation| true if
-  // the generation was initiated by the user. It is used for metrics and votes
-  // uploading.
-  // TODO(https://crbug.com/831123): Remove |generation_popup_was_shown| it is
-  // always true.
-  virtual void SetGenerationPopupWasShown(bool generation_popup_was_shown,
-                                          bool is_manual_generation) = 0;
-
-  // Called when the generation element with identifier |generation_element| is
-  // found on the page. It is used for metrics and votes uploading.
-  virtual void SetGenerationElement(
-      const base::string16& generation_element) = 0;
-
-  // True if we consider this form to be a change password form without username
-  // field. We use only client heuristics, so it could include signup forms.
-  virtual bool IsPossibleChangePasswordFormWithoutUsername() const = 0;
-
-  // Helper function that determines whether update or save prompt should be
-  // shown for credentials in |provisional_save_manager|.
-  virtual bool IsPasswordUpdate() const = 0;
-
-  // Returns the drivers representing all the frames for the form.
-  virtual std::vector<base::WeakPtr<PasswordManagerDriver>> GetDrivers()
-      const = 0;
-
-  // Returns the submitted form, if it exists, otherwise nullptr.
-  virtual const autofill::PasswordForm* GetSubmittedForm() const = 0;
-};
-
 }  // namespace  password_manager
 
 #endif  // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_FORM_MANAGER_FOR_UI_H_
diff --git a/components/password_manager/core/browser/password_form_metrics_recorder.cc b/components/password_manager/core/browser/password_form_metrics_recorder.cc
index c55f3ff..9390846 100644
--- a/components/password_manager/core/browser/password_form_metrics_recorder.cc
+++ b/components/password_manager/core/browser/password_form_metrics_recorder.cc
@@ -268,6 +268,11 @@
     }
   }
 
+  if (submit_result_ == kSubmitResultPassed && js_only_input_) {
+    UMA_HISTOGRAM_ENUMERATION(
+        "PasswordManager.JavaScriptOnlyValueInSubmittedForm", *js_only_input_);
+  }
+
   if (user_typed_password_on_chrome_sign_in_page_ ||
       password_hash_saved_on_chrome_sing_in_page_) {
     auto value = password_hash_saved_on_chrome_sing_in_page_
@@ -495,6 +500,8 @@
     const std::set<base::string16>& saved_passwords,
     bool is_blacklisted,
     const std::vector<InteractionsStats>& interactions_stats) {
+  CalculateJsOnlyInput(submitted_form);
+
   if (saved_passwords.empty() && is_blacklisted) {
     filling_assistance_ = FillingAssistance::kNoSavedCredentialsAndBlacklisted;
     return;
@@ -551,6 +558,25 @@
   NOTREACHED();
 }
 
+void PasswordFormMetricsRecorder::CalculateJsOnlyInput(
+    const FormData& submitted_form) {
+  bool had_focus = false;
+  bool had_user_input_or_autofill_on_password = false;
+  for (const auto& field : submitted_form.fields) {
+    if (field.HadFocus())
+      had_focus = true;
+    if (field.IsPasswordInputElement() &&
+        (field.DidUserType() || field.WasAutofilled())) {
+      had_user_input_or_autofill_on_password = true;
+    }
+  }
+
+  js_only_input_ = had_user_input_or_autofill_on_password
+                       ? JsOnlyInput::kAutofillOrUserInput
+                       : (had_focus ? JsOnlyInput::kOnlyJsInputWithFocus
+                                    : JsOnlyInput::kOnlyJsInputNoFocus);
+}
+
 int PasswordFormMetricsRecorder::GetActionsTaken() const {
   return static_cast<int>(user_action_) +
          static_cast<int>(UserAction::kMax) *
diff --git a/components/password_manager/core/browser/password_form_metrics_recorder.h b/components/password_manager/core/browser/password_form_metrics_recorder.h
index aecca7b3..cd083d0 100644
--- a/components/password_manager/core/browser/password_form_metrics_recorder.h
+++ b/components/password_manager/core/browser/password_form_metrics_recorder.h
@@ -276,6 +276,15 @@
     kMaxValue = kNotSaved,
   };
 
+  // Used in UMA histogram, please do NOT reorder.
+  // Metric: "PasswordManager.JavaScriptOnlyValueInSubmittedForm"
+  enum class JsOnlyInput {
+    kOnlyJsInputNoFocus = 0,
+    kOnlyJsInputWithFocus = 1,
+    kAutofillOrUserInput = 2,
+    kMaxValue = kAutofillOrUserInput,
+  };
+
   // The maximum number of combinations of the ManagerAction, UserAction and
   // SubmitResult enums.
   // This is used when recording the actions taken by the form in UMA.
@@ -394,6 +403,10 @@
       bool is_blacklisted,
       const std::vector<InteractionsStats>& interactions_stats);
 
+  // Calculates whether all field values in |submitted_form| came from
+  // JavaScript. The result is stored in |js_only_input_|.
+  void CalculateJsOnlyInput(const autofill::FormData& submitted_form);
+
   void set_user_typed_password_on_chrome_sign_in_page() {
     user_typed_password_on_chrome_sign_in_page_ = true;
   }
@@ -501,6 +514,8 @@
   bool possible_username_used_ = false;
   bool username_updated_in_bubble_ = false;
 
+  base::Optional<JsOnlyInput> js_only_input_;
+
   DISALLOW_COPY_AND_ASSIGN(PasswordFormMetricsRecorder);
 };
 
diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc
index f65a24c..dc3c32f3 100644
--- a/components/password_manager/core/browser/password_manager.cc
+++ b/components/password_manager/core/browser/password_manager.cc
@@ -120,8 +120,7 @@
 // Returns true if the user needs to be prompted before a password can be
 // saved (instead of automatically saving the password), based on inspecting
 // the state of |manager|.
-bool ShouldPromptUserToSavePassword(
-    const PasswordFormManagerInterface& manager) {
+bool ShouldPromptUserToSavePassword(const PasswordFormManager& manager) {
   if (manager.IsPasswordUpdate()) {
     // Updating a credential might erase a useful stored value by accident.
     // Always ask the user to confirm.
@@ -275,7 +274,7 @@
 void PasswordManager::OnPresaveGeneratedPassword(PasswordManagerDriver* driver,
                                                  const PasswordForm& form) {
   DCHECK(client_->IsSavingAndFillingEnabled(form.origin));
-  PasswordFormManagerInterface* form_manager = GetMatchedManager(driver, form);
+  PasswordFormManager* form_manager = GetMatchedManager(driver, form);
   UMA_HISTOGRAM_BOOLEAN("PasswordManager.GeneratedFormHasNoFormManager",
                         !form_manager);
   if (form_manager)
@@ -286,7 +285,7 @@
                                                   const PasswordForm& form) {
   DCHECK(client_->IsSavingAndFillingEnabled(form.origin));
 
-  PasswordFormManagerInterface* form_manager = GetMatchedManager(driver, form);
+  PasswordFormManager* form_manager = GetMatchedManager(driver, form);
   if (form_manager)
     form_manager->PasswordNoLongerGenerated();
 }
@@ -298,7 +297,7 @@
     bool is_manually_triggered) {
   DCHECK(client_->IsSavingAndFillingEnabled(form.origin));
 
-  PasswordFormManagerInterface* form_manager = GetMatchedManager(driver, form);
+  PasswordFormManager* form_manager = GetMatchedManager(driver, form);
   if (form_manager) {
     form_manager->SetGenerationElement(generation_element);
     form_manager->SetGenerationPopupWasShown(true, is_manually_triggered);
@@ -321,7 +320,7 @@
     // (ntp). OnPasswordFormsRendered is not called on ntp. That is why the
     // standard flow for saving hash does not work. Save a password hash now
     // since a navigation to ntp is the sign of successful sign-in.
-    PasswordFormManagerInterface* manager = GetSubmittedManager();
+    PasswordFormManager* manager = GetSubmittedManager();
     if (manager && manager->GetSubmittedForm()
                        ->form_data.is_gaia_with_skip_save_password_form) {
       MaybeSavePasswordHash(manager);
@@ -340,14 +339,14 @@
 }
 
 void PasswordManager::UpdateFormManagers() {
-  std::vector<PasswordFormManagerInterface*> form_managers;
+  std::vector<PasswordFormManager*> form_managers;
   for (const auto& form_manager : form_managers_)
     form_managers.push_back(form_manager.get());
 
   // Get the fetchers and all the drivers.
   std::vector<FormFetcher*> fetchers;
   std::vector<PasswordManagerDriver*> drivers;
-  for (PasswordFormManagerInterface* form_manager : form_managers) {
+  for (PasswordFormManager* form_manager : form_managers) {
     fetchers.push_back(form_manager->GetFormFetcher());
     for (const auto& driver : form_manager->GetDrivers()) {
       if (driver)
@@ -707,7 +706,7 @@
     logger->LogMessage(Logger::STRING_CAN_PROVISIONAL_MANAGER_SAVE_METHOD);
   }
 
-  PasswordFormManagerInterface* submitted_manager = GetSubmittedManager();
+  PasswordFormManager* submitted_manager = GetSubmittedManager();
 
   if (!submitted_manager) {
     if (logger) {
@@ -751,7 +750,7 @@
   if (!IsAutomaticSavePromptAvailable())
     return;
 
-  PasswordFormManagerInterface* submitted_manager = GetSubmittedManager();
+  PasswordFormManager* submitted_manager = GetSubmittedManager();
 
   // If the server throws an internal error, access denied page, page not
   // found etc. after a login attempt, we do not save the credentials.
@@ -828,7 +827,7 @@
     logger->LogMessage(Logger::STRING_ON_ASK_USER_OR_SAVE_PASSWORD);
   }
 
-  PasswordFormManagerInterface* submitted_manager = GetSubmittedManager();
+  PasswordFormManager* submitted_manager = GetSubmittedManager();
   DCHECK(submitted_manager);
   DCHECK(submitted_manager->GetSubmittedForm());
 
@@ -907,7 +906,7 @@
 }
 
 void PasswordManager::MaybeSavePasswordHash(
-    PasswordFormManagerInterface* submitted_manager) {
+    PasswordFormManager* submitted_manager) {
 #if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
   const PasswordForm* submitted_form = submitted_manager->GetSubmittedForm();
   // When |username_value| is empty, it's not clear whether the submitted
@@ -1003,7 +1002,7 @@
 
 }
 
-PasswordFormManagerInterface* PasswordManager::GetSubmittedManager() const {
+PasswordFormManager* PasswordManager::GetSubmittedManager() const {
   if (owned_submitted_form_manager_)
     return owned_submitted_form_manager_.get();
 
@@ -1045,7 +1044,7 @@
 
 // TODO(https://crbug.com/831123): Implement creating missing
 // PasswordFormManager when PasswordFormManager is gone.
-PasswordFormManagerInterface* PasswordManager::GetMatchedManager(
+PasswordFormManager* PasswordManager::GetMatchedManager(
     const PasswordManagerDriver* driver,
     const PasswordForm& form) {
   return GetMatchedManager(driver, form.form_data);
diff --git a/components/password_manager/core/browser/password_manager.h b/components/password_manager/core/browser/password_manager.h
index b08c907..a9e5ca0 100644
--- a/components/password_manager/core/browser/password_manager.h
+++ b/components/password_manager/core/browser/password_manager.h
@@ -43,9 +43,8 @@
 class PasswordManagerClient;
 class PasswordManagerDriver;
 class PasswordFormManagerForUI;
-class PasswordFormManagerInterface;
-class PasswordManagerMetricsRecorder;
 class PasswordFormManager;
+class PasswordManagerMetricsRecorder;
 struct PossibleUsernameData;
 
 // Per-tab password manager. Handles creation and management of UI elements,
@@ -151,7 +150,7 @@
     return form_managers_;
   }
 
-  PasswordFormManagerInterface* GetSubmittedManagerForTest() const {
+  PasswordFormManager* GetSubmittedManagerForTest() const {
     return GetSubmittedManager();
   }
 #if !defined(OS_IOS)
@@ -227,7 +226,7 @@
 
   // Helper function called inside OnLoginSuccessful() to save password hash
   // data from |submitted_manager| for password reuse detection purpose.
-  void MaybeSavePasswordHash(PasswordFormManagerInterface* submitted_manager);
+  void MaybeSavePasswordHash(PasswordFormManager* submitted_manager);
 
   // Checks for every form in |forms| whether |pending_login_managers_| already
   // contain a manager for that form. If not, adds a manager for each such form.
@@ -262,7 +261,7 @@
   // be nullptr if there is no submitted form.
   // TODO(https://crbug.com/831123): Remove when the old PasswordFormManager is
   // gone.
-  PasswordFormManagerInterface* GetSubmittedManager() const;
+  PasswordFormManager* GetSubmittedManager() const;
 
   // Returns the form manager that corresponds to the submitted form. It also
   // sets |submitted_form_manager_| to nullptr.
@@ -279,9 +278,8 @@
 
   // Returns the manager which manages |form|. |driver| is needed to determine
   // the match. Returns nullptr when no matched manager is found.
-  PasswordFormManagerInterface* GetMatchedManager(
-      const PasswordManagerDriver* driver,
-      const autofill::PasswordForm& form);
+  PasswordFormManager* GetMatchedManager(const PasswordManagerDriver* driver,
+                                         const autofill::PasswordForm& form);
 
   // Returns the manager which manages |form|. |driver| is needed to determine
   // the match. Returns nullptr when no matched manager is found.
diff --git a/components/password_manager/core/browser/password_manager_unittest.cc b/components/password_manager/core/browser/password_manager_unittest.cc
index ba3308e..e9943a9d 100644
--- a/components/password_manager/core/browser/password_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_manager_unittest.cc
@@ -110,7 +110,7 @@
  public:
   MOCK_CONST_METHOD1(ShouldSave, bool(const autofill::PasswordForm& form));
   MOCK_CONST_METHOD1(ReportFormLoginSuccess,
-                     void(const PasswordFormManagerInterface& form_manager));
+                     void(const PasswordFormManager& form_manager));
   MOCK_CONST_METHOD1(IsSyncAccountEmail, bool(const std::string&));
   MOCK_CONST_METHOD1(ShouldSaveGaiaPasswordHash,
                      bool(const autofill::PasswordForm&));
@@ -2123,7 +2123,7 @@
   EXPECT_CALL(*store_, AddLogin(_));
   manager()->OnPresaveGeneratedPassword(&driver_, form);
 
-  const PasswordFormManagerInterface* form_manager =
+  const PasswordFormManager* form_manager =
       manager()->form_managers().front().get();
 
   EXPECT_TRUE(form_manager->HasGeneratedPassword());
diff --git a/components/password_manager/core/browser/stub_credentials_filter.cc b/components/password_manager/core/browser/stub_credentials_filter.cc
index e00176f..8b06737 100644
--- a/components/password_manager/core/browser/stub_credentials_filter.cc
+++ b/components/password_manager/core/browser/stub_credentials_filter.cc
@@ -26,7 +26,7 @@
 }
 
 void StubCredentialsFilter::ReportFormLoginSuccess(
-    const PasswordFormManagerInterface& form_manager) const {}
+    const PasswordFormManager& form_manager) const {}
 
 bool StubCredentialsFilter::IsSyncAccountEmail(
     const std::string& username) const {
diff --git a/components/password_manager/core/browser/stub_credentials_filter.h b/components/password_manager/core/browser/stub_credentials_filter.h
index 4a6d98e..b85a14b 100644
--- a/components/password_manager/core/browser/stub_credentials_filter.h
+++ b/components/password_manager/core/browser/stub_credentials_filter.h
@@ -25,7 +25,7 @@
   bool ShouldSaveEnterprisePasswordHash(
       const autofill::PasswordForm& form) const override;
   void ReportFormLoginSuccess(
-      const PasswordFormManagerInterface& form_manager) const override;
+      const PasswordFormManager& form_manager) const override;
   bool IsSyncAccountEmail(const std::string& username) const override;
 
  private:
diff --git a/components/password_manager/core/browser/sync_credentials_filter.cc b/components/password_manager/core/browser/sync_credentials_filter.cc
index 7b8155a9..a453c4b 100644
--- a/components/password_manager/core/browser/sync_credentials_filter.cc
+++ b/components/password_manager/core/browser/sync_credentials_filter.cc
@@ -10,7 +10,7 @@
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
-#include "components/password_manager/core/browser/password_form_manager_for_ui.h"
+#include "components/password_manager/core/browser/password_form_manager.h"
 #include "components/password_manager/core/browser/password_manager_util.h"
 #include "components/password_manager/core/browser/password_sync_util.h"
 #include "components/password_manager/core/common/password_manager_features.h"
@@ -61,7 +61,7 @@
 }
 
 void SyncCredentialsFilter::ReportFormLoginSuccess(
-    const PasswordFormManagerInterface& form_manager) const {
+    const PasswordFormManager& form_manager) const {
   if (!form_manager.IsNewLogin() &&
       sync_util::IsSyncAccountCredential(form_manager.GetPendingCredentials(),
                                          sync_service_factory_function_.Run(),
diff --git a/components/password_manager/core/browser/sync_credentials_filter.h b/components/password_manager/core/browser/sync_credentials_filter.h
index ba17e12..b29c030 100644
--- a/components/password_manager/core/browser/sync_credentials_filter.h
+++ b/components/password_manager/core/browser/sync_credentials_filter.h
@@ -39,7 +39,7 @@
   bool ShouldSaveEnterprisePasswordHash(
       const autofill::PasswordForm& form) const override;
   void ReportFormLoginSuccess(
-      const PasswordFormManagerInterface& form_manager) const override;
+      const PasswordFormManager& form_manager) const override;
   bool IsSyncAccountEmail(const std::string& username) const override;
 
  private:
diff --git a/components/plugins/renderer/webview_plugin.cc b/components/plugins/renderer/webview_plugin.cc
index b632d29..967bb3a7d 100644
--- a/components/plugins/renderer/webview_plugin.cc
+++ b/components/plugins/renderer/webview_plugin.cc
@@ -21,6 +21,7 @@
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "skia/ext/platform_canvas.h"
 #include "third_party/blink/public/mojom/frame/document_interface_broker.mojom.h"
+#include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
 #include "third_party/blink/public/platform/web_coalesced_input_event.h"
 #include "third_party/blink/public/platform/web_url.h"
 #include "third_party/blink/public/platform/web_url_response.h"
@@ -192,10 +193,12 @@
 
   // Plugin updates are forbidden during Blink layout. Therefore,
   // UpdatePluginForNewGeometry must be posted to a task to run asynchronously.
-  GetTaskRunner()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&WebViewPlugin::UpdatePluginForNewGeometry,
-                     weak_factory_.GetWeakPtr(), window_rect, unobscured_rect));
+  blink::scheduler::WebThreadScheduler::MainThreadScheduler()
+      ->CompositorTaskRunner()
+      ->PostTask(FROM_HERE,
+                 base::BindOnce(&WebViewPlugin::UpdatePluginForNewGeometry,
+                                weak_factory_.GetWeakPtr(), window_rect,
+                                unobscured_rect));
 }
 
 void WebViewPlugin::UpdateFocus(bool focused, blink::WebFocusType focus_type) {
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 2862bc0..811b274 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -17753,7 +17753,7 @@
       'id': 601,
       'caption': '''List of names that will bypass the HSTS policy check''',
       'tags': ['system-security'],
-      'desc': '''Hostnames specified in this list will be exempt from the HSTS policy check that could potentially upgrade requests from http to https. Only single-label hostnames are allowed in this policy. Hostnames must be canonicalized: any IDNs must be convered to their A-label format, and all ASCII letters must be lowercase. This policy only applies to the specific hostnames specified; it does not apply to subdomains of the names specified.''',
+      'desc': '''Hostnames specified in this list will be exempt from the HSTS policy check that could potentially upgrade requests from http to https. Only single-label hostnames are allowed in this policy. Hostnames must be canonicalized: any IDNs must be converted to their A-label format, and all ASCII letters must be lowercase. This policy only applies to the specific hostnames specified; it does not apply to subdomains of the names specified.''',
     },
     {
       'name': 'AllowSyncXHRInPageDismissal',
diff --git a/components/safe_browsing/password_protection/password_protection_request.h b/components/safe_browsing/password_protection/password_protection_request.h
index bf23783..c9612c3 100644
--- a/components/safe_browsing/password_protection/password_protection_request.h
+++ b/components/safe_browsing/password_protection/password_protection_request.h
@@ -19,6 +19,7 @@
 #include "components/safe_browsing/proto/csd.pb.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_contents_observer.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 
 class GURL;
@@ -257,7 +258,7 @@
   base::TimeTicks visual_feature_start_time_;
 
   // The Mojo pipe used for extracting DOM features from the renderer.
-  safe_browsing::mojom::PhishingDetectorPtr phishing_detector_;
+  mojo::Remote<safe_browsing::mojom::PhishingDetector> phishing_detector_;
 
   // When we start extracting DOM features. Used to compute the duration of DOM
   // feature extraction, which is logged at
diff --git a/components/safe_browsing/password_protection/password_protection_service.cc b/components/safe_browsing/password_protection/password_protection_service.cc
index 3a54056..a100ae3 100644
--- a/components/safe_browsing/password_protection/password_protection_service.cc
+++ b/components/safe_browsing/password_protection/password_protection_service.cc
@@ -560,8 +560,8 @@
 #if BUILDFLAG(FULL_SAFE_BROWSING)
 void PasswordProtectionService::GetPhishingDetector(
     service_manager::InterfaceProvider* provider,
-    mojom::PhishingDetectorPtr* phishing_detector) {
-  provider->GetInterface(phishing_detector);
+    mojo::Remote<mojom::PhishingDetector>* phishing_detector) {
+  provider->GetInterface(phishing_detector->BindNewPipeAndPassReceiver());
 }
 #endif
 
diff --git a/components/safe_browsing/password_protection/password_protection_service.h b/components/safe_browsing/password_protection/password_protection_service.h
index 420e1b8a..e436282 100644
--- a/components/safe_browsing/password_protection/password_protection_service.h
+++ b/components/safe_browsing/password_protection/password_protection_service.h
@@ -28,6 +28,7 @@
 #include "components/safe_browsing/proto/csd.pb.h"
 #include "components/sessions/core/session_id.h"
 #include "components/signin/public/identity_manager/account_info.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "third_party/protobuf/src/google/protobuf/repeated_field.h"
@@ -411,7 +412,7 @@
   // |provider|.
   virtual void GetPhishingDetector(
       service_manager::InterfaceProvider* provider,
-      mojom::PhishingDetectorPtr* phishing_detector);
+      mojo::Remote<mojom::PhishingDetector>* phishing_detector);
 #endif
 
   // The username of the account which password has been reused on. It is only
diff --git a/components/safe_browsing/password_protection/password_protection_service_unittest.cc b/components/safe_browsing/password_protection/password_protection_service_unittest.cc
index 50548b7..f889410 100644
--- a/components/safe_browsing/password_protection/password_protection_service_unittest.cc
+++ b/components/safe_browsing/password_protection/password_protection_service_unittest.cc
@@ -34,6 +34,8 @@
 #include "content/public/test/test_browser_context.h"
 #include "content/public/test/test_renderer_host.h"
 #include "content/public/test/web_contents_tester.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/system/message_pipe.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/network/test/test_url_loader_factory.h"
@@ -81,11 +83,12 @@
 
 class TestPhishingDetector : public mojom::PhishingDetector {
  public:
-  TestPhishingDetector() : should_timeout_(false), binding_(this) {}
+  TestPhishingDetector() : should_timeout_(false) {}
   ~TestPhishingDetector() override {}
 
   void Bind(mojo::ScopedMessagePipeHandle handle) {
-    binding_.Bind(mojom::PhishingDetectorRequest(std::move(handle)));
+    receiver_.Bind(
+        mojo::PendingReceiver<mojom::PhishingDetector>(std::move(handle)));
   }
 
   void StartPhishingDetection(
@@ -110,7 +113,7 @@
  private:
   bool should_timeout_;
   std::vector<StartPhishingDetectionCallback> deferred_callbacks_;
-  mojo::Binding<mojom::PhishingDetector> binding_;
+  mojo::Receiver<mojom::PhishingDetector> receiver_{this};
 
   DISALLOW_COPY_AND_ASSIGN(TestPhishingDetector);
 };
@@ -153,13 +156,13 @@
 
   void GetPhishingDetector(
       service_manager::InterfaceProvider* provider,
-      mojom::PhishingDetectorPtr* phishing_detector) override {
+      mojo::Remote<mojom::PhishingDetector>* phishing_detector) override {
     service_manager::InterfaceProvider::TestApi test_api(provider);
     test_api.SetBinderForName(
         mojom::PhishingDetector::Name_,
         base::BindRepeating(&TestPhishingDetector::Bind,
                             base::Unretained(&test_phishing_detector_)));
-    provider->GetInterface(phishing_detector);
+    provider->GetInterface(phishing_detector->BindNewPipeAndPassReceiver());
     test_api.ClearBinderForName(mojom::PhishingDetector::Name_);
   }
 
diff --git a/components/signin/internal/identity_manager/fake_profile_oauth2_token_service.cc b/components/signin/internal/identity_manager/fake_profile_oauth2_token_service.cc
index feffe3b..f3aa3e0 100644
--- a/components/signin/internal/identity_manager/fake_profile_oauth2_token_service.cc
+++ b/components/signin/internal/identity_manager/fake_profile_oauth2_token_service.cc
@@ -10,14 +10,9 @@
 
 FakeProfileOAuth2TokenService::FakeProfileOAuth2TokenService(
     PrefService* user_prefs)
-    : FakeProfileOAuth2TokenService(
+    : ProfileOAuth2TokenService(
           user_prefs,
-          std::make_unique<FakeProfileOAuth2TokenServiceDelegate>()) {}
-
-FakeProfileOAuth2TokenService::FakeProfileOAuth2TokenService(
-    PrefService* user_prefs,
-    std::unique_ptr<ProfileOAuth2TokenServiceDelegate> delegate)
-    : ProfileOAuth2TokenService(user_prefs, std::move(delegate)) {
+          std::make_unique<FakeProfileOAuth2TokenServiceDelegate>()) {
   OverrideAccessTokenManagerForTesting(
       std::make_unique<FakeOAuth2AccessTokenManager>(
           this /* OAuth2AccessTokenManager::Delegate* */));
diff --git a/components/signin/internal/identity_manager/fake_profile_oauth2_token_service.h b/components/signin/internal/identity_manager/fake_profile_oauth2_token_service.h
index 09d09e1..dc8f4ba 100644
--- a/components/signin/internal/identity_manager/fake_profile_oauth2_token_service.h
+++ b/components/signin/internal/identity_manager/fake_profile_oauth2_token_service.h
@@ -36,9 +36,6 @@
 class FakeProfileOAuth2TokenService : public ProfileOAuth2TokenService {
  public:
   explicit FakeProfileOAuth2TokenService(PrefService* user_prefs);
-  FakeProfileOAuth2TokenService(
-      PrefService* user_prefs,
-      std::unique_ptr<ProfileOAuth2TokenServiceDelegate> delegate);
   ~FakeProfileOAuth2TokenService() override;
 
   // Gets a list of active requests (can be used by tests to validate that the
diff --git a/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate.cc b/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate.cc
index 46b5457..6b8be382 100644
--- a/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate.cc
+++ b/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate.cc
@@ -438,6 +438,7 @@
     set_load_credentials_state(
         signin::LoadCredentialsState::
             LOAD_CREDENTIALS_FINISHED_WITH_UNKNOWN_ERRORS);
+    MaybeDeletePreDiceTokens();
     FinishLoadingCredentials();
     return;
   }
@@ -476,6 +477,7 @@
     set_load_credentials_state(
         signin::LoadCredentialsState::
             LOAD_CREDENTIALS_FINISHED_WITH_DB_CANNOT_BE_OPENED);
+    MaybeDeletePreDiceTokens();
   }
 
   // Make sure that we have an entry for |loading_primary_account_id_| in the
@@ -848,6 +850,10 @@
 }
 
 void MutableProfileOAuth2TokenServiceDelegate::FinishLoadingCredentials() {
+#if !defined(OS_CHROMEOS)
+  if (account_consistency_ == signin::AccountConsistencyMethod::kDice)
+    DCHECK(client_->GetPrefs()->GetBoolean(prefs::kTokenServiceDiceCompatible));
+#endif
   FireRefreshTokensLoaded();
 }
 
@@ -868,3 +874,18 @@
     FireRefreshTokenRevoked(account_id);
   }
 }
+
+void MutableProfileOAuth2TokenServiceDelegate::MaybeDeletePreDiceTokens() {
+  DCHECK(load_credentials_state() ==
+             signin::LoadCredentialsState::
+                 LOAD_CREDENTIALS_FINISHED_WITH_UNKNOWN_ERRORS ||
+         load_credentials_state() ==
+             signin::LoadCredentialsState::
+                 LOAD_CREDENTIALS_FINISHED_WITH_DB_CANNOT_BE_OPENED);
+
+  if (account_consistency_ == signin::AccountConsistencyMethod::kDice &&
+      !client_->GetPrefs()->GetBoolean(prefs::kTokenServiceDiceCompatible)) {
+    RevokeAllCredentials();
+    client_->GetPrefs()->SetBoolean(prefs::kTokenServiceDiceCompatible, true);
+  }
+}
diff --git a/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate.h b/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate.h
index 5f0380d..41b71cd 100644
--- a/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate.h
+++ b/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate.h
@@ -189,6 +189,11 @@
   void RevokeCredentialsImpl(const CoreAccountId& account_id,
                              bool revoke_on_server);
 
+  // If the Dice migration happened before the tokens could be migrated, delete
+  // all the tokens. This is only called if the tokens could not be loaded
+  // successfully.
+  void MaybeDeletePreDiceTokens();
+
   // Maps the |account_id| of accounts known to ProfileOAuth2TokenService
   // to information about the account.
   typedef std::map<CoreAccountId, AccountStatus> AccountStatusMap;
diff --git a/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate_unittest.cc b/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate_unittest.cc
index 2df7204..336de645 100644
--- a/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate_unittest.cc
+++ b/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate_unittest.cc
@@ -708,6 +708,51 @@
   EXPECT_TRUE(pref_service_.GetBoolean(prefs::kTokenServiceDiceCompatible));
 }
 
+// Checks that tokens are loaded and prefs::kTokenServiceDiceCompatible is set
+// to true if the tokens are loaded after the Dice migration.
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, LoadAfterDiceMigration) {
+  InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kDice);
+  ASSERT_FALSE(pref_service_.GetBoolean(prefs::kTokenServiceDiceCompatible));
+
+  // Add account info to the account tracker.
+  AccountInfo primary_account = CreateTestAccountInfo(
+      "primary_account", false /* is_hosted_domain*/, true /* is_valid*/);
+  account_tracker_service_.SeedAccountInfo(primary_account);
+  AddAuthTokenManually("AccountId-" + primary_account.account_id.id,
+                       "refresh_token");
+
+  oauth2_service_delegate_->LoadCredentials(std::string());
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable(
+      primary_account.account_id));
+  EXPECT_EQ(
+      signin::LoadCredentialsState::LOAD_CREDENTIALS_FINISHED_WITH_SUCCESS,
+      oauth2_service_delegate_->load_credentials_state());
+
+  ASSERT_TRUE(pref_service_.GetBoolean(prefs::kTokenServiceDiceCompatible));
+}
+
+// Checks that prefs::kTokenServiceDiceCompatible is set to true if the tokens
+// are loaded after the Dice migration, even if there was a database read error.
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest,
+       LoadAfterDiceMigrationWithError) {
+  InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kDice);
+  ASSERT_FALSE(pref_service_.GetBoolean(prefs::kTokenServiceDiceCompatible));
+
+  // Shutdown the database to trigger a database read error.
+  token_web_data_->ShutdownDatabase();
+
+  oauth2_service_delegate_->LoadCredentials(std::string());
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(0u, oauth2_service_delegate_->GetAccounts().size());
+  EXPECT_EQ(signin::LoadCredentialsState::
+                LOAD_CREDENTIALS_FINISHED_WITH_DB_CANNOT_BE_OPENED,
+            oauth2_service_delegate_->load_credentials_state());
+
+  ASSERT_TRUE(pref_service_.GetBoolean(prefs::kTokenServiceDiceCompatible));
+}
 #endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)
 
 #if !defined(OS_CHROMEOS)
diff --git a/components/signin/internal/identity_manager/primary_account_manager.cc b/components/signin/internal/identity_manager/primary_account_manager.cc
index 10a91ae..4628e18 100644
--- a/components/signin/internal/identity_manager/primary_account_manager.cc
+++ b/components/signin/internal/identity_manager/primary_account_manager.cc
@@ -153,22 +153,6 @@
   return authenticated_account_info_.has_value();
 }
 
-void PrimaryAccountManager::SetGoogleSigninSucceededCallback(
-    AccountSigninCallback callback) {
-  DCHECK(!on_google_signin_succeeded_callback_)
-      << "GoogleSigninSucceededCallback shouldn't be set multiple times.";
-  on_google_signin_succeeded_callback_ = callback;
-}
-
-#if !defined(OS_CHROMEOS)
-void PrimaryAccountManager::SetGoogleSignedOutCallback(
-    AccountSigninCallback callback) {
-  DCHECK(!on_google_signed_out_callback_)
-      << "GoogleSignedOutCallback shouldn't be set multiple times.";
-  on_google_signed_out_callback_ = callback;
-}
-#endif  // !defined(OS_CHROMEOS)
-
 void PrimaryAccountManager::SignIn(const std::string& username) {
   CoreAccountInfo info =
       account_tracker_service_->FindAccountInfoByEmail(username);
@@ -184,8 +168,8 @@
 
   SetAuthenticatedAccountInfo(info);
 
-  if (on_google_signin_succeeded_callback_)
-    on_google_signin_succeeded_callback_.Run(GetAuthenticatedAccountInfo());
+  for (Observer& observer : observers_)
+    observer.GoogleSigninSucceeded(info);
 }
 
 void PrimaryAccountManager::UpdateAuthenticatedAccountInfo() {
@@ -196,6 +180,14 @@
   authenticated_account_info_ = info;
 }
 
+void PrimaryAccountManager::AddObserver(Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void PrimaryAccountManager::RemoveObserver(const Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
 #if !defined(OS_CHROMEOS)
 void PrimaryAccountManager::SignOut(
     signin_metrics::ProfileSignout signout_source_metric,
@@ -283,8 +275,8 @@
       break;
   }
 
-  if (on_google_signed_out_callback_)
-    on_google_signed_out_callback_.Run(account_info);
+  for (Observer& observer : observers_)
+    observer.GoogleSignedOut(account_info);
 }
 
 void PrimaryAccountManager::OnRefreshTokensLoaded() {
diff --git a/components/signin/internal/identity_manager/primary_account_manager.h b/components/signin/internal/identity_manager/primary_account_manager.h
index a5aebf54..128a47a7 100644
--- a/components/signin/internal/identity_manager/primary_account_manager.h
+++ b/components/signin/internal/identity_manager/primary_account_manager.h
@@ -21,9 +21,9 @@
 #include <memory>
 #include <string>
 
-#include "base/callback.h"
-#include "base/callback_list.h"
 #include "base/macros.h"
+#include "base/observer_list.h"
+#include "base/observer_list_types.h"
 #include "base/optional.h"
 #include "components/signin/internal/identity_manager/profile_oauth2_token_service_observer.h"
 #include "components/signin/public/base/account_consistency_method.h"
@@ -43,8 +43,17 @@
 
 class PrimaryAccountManager : public ProfileOAuth2TokenServiceObserver {
  public:
-  typedef base::RepeatingCallback<void(const CoreAccountInfo&)>
-      AccountSigninCallback;
+  class Observer : public base::CheckedObserver {
+   public:
+    // Called whenever a user signs into Google services such as sync.
+    // Not called during a reauth.
+    virtual void GoogleSigninSucceeded(const CoreAccountInfo& info) {}
+
+#if !defined(OS_CHROMEOS)
+    // Called whenever the currently signed-in user has been signed out.
+    virtual void GoogleSignedOut(const CoreAccountInfo& info) {}
+#endif
+  };
 
 #if !defined(OS_CHROMEOS)
   // Used to remove accounts from the token service and the account tracker.
@@ -95,16 +104,6 @@
   // Returns true if there is an authenticated user.
   bool IsAuthenticated() const;
 
-  // If set, this callback will be invoked whenever a user signs into Google
-  // services such as sync. This callback is not called during a reauth.
-  void SetGoogleSigninSucceededCallback(AccountSigninCallback callback);
-
-#if !defined(OS_CHROMEOS)
-  // If set, this callback will be invoked whenever the currently signed-in user
-  // for a user has been signed out.
-  void SetGoogleSignedOutCallback(AccountSigninCallback callback);
-#endif
-
   // Signs a user in. PrimaryAccountManager assumes that |username| can be used
   // to look up the corresponding account_id and gaia_id for this email.
   void SignIn(const std::string& username);
@@ -140,6 +139,10 @@
       signin_metrics::SignoutDelete signout_delete_metric);
 #endif
 
+  // Adds and removes observers.
+  void AddObserver(Observer* observer);
+  void RemoveObserver(const Observer* observer);
+
  private:
   // Sets the authenticated user's account id.
   // If the user is already authenticated with the same account id, then this
@@ -179,20 +182,12 @@
   // Account id after successful authentication.
   base::Optional<CoreAccountInfo> authenticated_account_info_;
 
-  // Callbacks which will be invoked, if set, for signin-related events.
-  AccountSigninCallback on_google_signin_succeeded_callback_;
-#if !defined(OS_CHROMEOS)
-  AccountSigninCallback on_google_signed_out_callback_;
-#endif
-
-  // The list of callbacks notified on shutdown.
-  base::CallbackList<void()> on_shutdown_callback_list_;
-
 #if !defined(OS_CHROMEOS)
   signin::AccountConsistencyMethod account_consistency_;
 #endif
 
   std::unique_ptr<PrimaryAccountPolicyManager> policy_manager_;
+  base::ObserverList<Observer> observers_;
 
   DISALLOW_COPY_AND_ASSIGN(PrimaryAccountManager);
 };
diff --git a/components/signin/internal/identity_manager/primary_account_manager_unittest.cc b/components/signin/internal/identity_manager/primary_account_manager_unittest.cc
index 8a5d236..76f9a6f 100644
--- a/components/signin/internal/identity_manager/primary_account_manager_unittest.cc
+++ b/components/signin/internal/identity_manager/primary_account_manager_unittest.cc
@@ -31,7 +31,8 @@
 #include "components/signin/internal/identity_manager/primary_account_policy_manager_impl.h"
 #endif
 
-class PrimaryAccountManagerTest : public testing::Test {
+class PrimaryAccountManagerTest : public testing::Test,
+                                  public PrimaryAccountManager::Observer {
  public:
   PrimaryAccountManagerTest()
       : test_signin_client_(&user_prefs_),
@@ -94,21 +95,13 @@
         &test_signin_client_, &token_service_, &account_tracker_,
         account_consistency_, std::move(policy_manager));
     manager_->Initialize(&local_state_);
-
-    // PrimaryAccountManagerTest will outlive the PrimaryAccountManager, so
-    // base::Unretained is safe.
-    manager_->SetGoogleSigninSucceededCallback(
-        base::BindRepeating(&PrimaryAccountManagerTest::GoogleSigninSucceeded,
-                            base::Unretained(this)));
-#if !defined(OS_CHROMEOS)
-    manager_->SetGoogleSignedOutCallback(base::BindRepeating(
-        &PrimaryAccountManagerTest::GoogleSignedOut, base::Unretained(this)));
-#endif
+    manager_->AddObserver(this);
   }
 
   // Shuts down |manager_|.
   void ShutDownManager() {
     DCHECK(manager_);
+    manager_->RemoveObserver(this);
     manager_.reset();
   }
 
@@ -124,11 +117,15 @@
     EXPECT_EQ(1, num_successful_signins_);
   }
 
-  void GoogleSigninSucceeded(const CoreAccountInfo& account_info) {
+  void GoogleSigninSucceeded(const CoreAccountInfo& account_info) override {
     num_successful_signins_++;
   }
 
-  void GoogleSignedOut(const CoreAccountInfo& account_info) { num_signouts_++; }
+#if !defined(OS_CHROMEOS)
+  void GoogleSignedOut(const CoreAccountInfo& account_info) override {
+    num_signouts_++;
+  }
+#endif
 
   base::test::TaskEnvironment task_environment_;
   sync_preferences::TestingPrefServiceSyncable user_prefs_;
diff --git a/components/signin/public/identity_manager/identity_manager.cc b/components/signin/public/identity_manager/identity_manager.cc
index 4e6987a4..a5cd63c 100644
--- a/components/signin/public/identity_manager/identity_manager.cc
+++ b/components/signin/public/identity_manager/identity_manager.cc
@@ -11,7 +11,6 @@
 #include "components/signin/internal/identity_manager/account_fetcher_service.h"
 #include "components/signin/internal/identity_manager/account_tracker_service.h"
 #include "components/signin/internal/identity_manager/gaia_cookie_manager_service.h"
-#include "components/signin/internal/identity_manager/primary_account_manager.h"
 #include "components/signin/internal/identity_manager/profile_oauth2_token_service.h"
 #include "components/signin/internal/identity_manager/ubertoken_fetcher_impl.h"
 #include "components/signin/public/identity_manager/accounts_cookie_mutator.h"
@@ -52,21 +51,14 @@
                         std::move(accounts_mutator),
                         std::move(accounts_cookie_mutator),
                         std::move(device_accounts_synchronizer)),
-      diagnostics_provider_(std::move(diagnostics_provider)) {
+      diagnostics_provider_(std::move(diagnostics_provider)),
+      primary_account_manager_observer_(this),
+      token_service_observer_(this) {
   DCHECK(account_fetcher_service_);
   DCHECK(diagnostics_provider_);
 
-  // IdentityManager will outlive the PrimaryAccountManager, so base::Unretained
-  // is safe.
-  primary_account_manager_->SetGoogleSigninSucceededCallback(
-      base::BindRepeating(&IdentityManager::GoogleSigninSucceeded,
-                          base::Unretained(this)));
-#if !defined(OS_CHROMEOS)
-  primary_account_manager_->SetGoogleSignedOutCallback(base::BindRepeating(
-      &IdentityManager::GoogleSignedOut, base::Unretained(this)));
-#endif
-
-  token_service_->AddObserver(this);
+  primary_account_manager_observer_.Add(primary_account_manager_.get());
+  token_service_observer_.Add(token_service_.get());
   token_service_->AddAccessTokenDiagnosticsObserver(this);
 
   // IdentityManager owns the ATS, GCMS and PO2TS instances and will outlive
@@ -106,7 +98,6 @@
   token_service_->Shutdown();
   account_tracker_service_->Shutdown();
 
-  token_service_->RemoveObserver(this);
   token_service_->RemoveAccessTokenDiagnosticsObserver(this);
 
 #if defined(OS_ANDROID)
@@ -526,6 +517,7 @@
 #endif
 }
 
+#if !defined(OS_CHROMEOS)
 void IdentityManager::GoogleSignedOut(const CoreAccountInfo& account_info) {
   DCHECK(!HasPrimaryAccount());
   DCHECK(!account_info.IsEmpty());
@@ -542,6 +534,7 @@
   }
 #endif
 }
+#endif  // !defined(OS_CHROMEOS)
 
 void IdentityManager::OnRefreshTokenAvailable(const CoreAccountId& account_id) {
   UpdateUnconsentedPrimaryAccount();
diff --git a/components/signin/public/identity_manager/identity_manager.h b/components/signin/public/identity_manager/identity_manager.h
index 7d2ecb1c..1bd4ecd 100644
--- a/components/signin/public/identity_manager/identity_manager.h
+++ b/components/signin/public/identity_manager/identity_manager.h
@@ -10,8 +10,10 @@
 
 #include "base/macros.h"
 #include "base/observer_list.h"
+#include "base/scoped_observer.h"
 #include "build/build_config.h"
 #include "components/keyed_service/core/keyed_service.h"
+#include "components/signin/internal/identity_manager/primary_account_manager.h"
 #include "components/signin/internal/identity_manager/profile_oauth2_token_service_observer.h"
 #include "components/signin/public/identity_manager/access_token_fetcher.h"
 #include "components/signin/public/identity_manager/account_info.h"
@@ -55,6 +57,7 @@
 // ./README.md for detailed documentation.
 class IdentityManager : public KeyedService,
                         public OAuth2AccessTokenManager::DiagnosticsObserver,
+                        public PrimaryAccountManager::Observer,
                         public ProfileOAuth2TokenServiceObserver {
  public:
   class Observer {
@@ -596,9 +599,11 @@
   // current cookies.
   base::Optional<CoreAccountInfo> ComputeUnconsentedPrimaryAccountInfo() const;
 
-  // PrimaryAccountManager callbacks:
-  void GoogleSigninSucceeded(const CoreAccountInfo& account_info);
-  void GoogleSignedOut(const CoreAccountInfo& account_info);
+  // PrimaryAccountManager::Observer:
+  void GoogleSigninSucceeded(const CoreAccountInfo& account_info) override;
+#if !defined(OS_CHROMEOS)
+  void GoogleSignedOut(const CoreAccountInfo& account_info) override;
+#endif
 
   // ProfileOAuth2TokenServiceObserver:
   void OnRefreshTokenAvailable(const CoreAccountId& account_id) override;
@@ -650,6 +655,12 @@
   // DiagnosticsProvider instance.
   std::unique_ptr<DiagnosticsProvider> diagnostics_provider_;
 
+  // Scoped observers.
+  ScopedObserver<PrimaryAccountManager, IdentityManager>
+      primary_account_manager_observer_;
+  ScopedObserver<ProfileOAuth2TokenService, IdentityManager>
+      token_service_observer_;
+
   // Lists of observers.
   // Makes sure lists are empty on destruction.
   base::ObserverList<Observer, true>::Unchecked observer_list_;
diff --git a/components/sync/BUILD.gn b/components/sync/BUILD.gn
index 0c0e3a30..d360d64 100644
--- a/components/sync/BUILD.gn
+++ b/components/sync/BUILD.gn
@@ -344,6 +344,8 @@
     "syncable/directory_backing_store.cc",
     "syncable/directory_backing_store.h",
     "syncable/directory_change_delegate.h",
+    "syncable/directory_cryptographer.cc",
+    "syncable/directory_cryptographer.h",
     "syncable/entry.cc",
     "syncable/entry.h",
     "syncable/entry_kernel.cc",
@@ -640,7 +642,6 @@
     "model_impl/model_type_store_impl_unittest.cc",
     "model_impl/processor_entity_unittest.cc",
     "model_impl/syncable_service_based_bridge_unittest.cc",
-    "nigori/cryptographer_unittest.cc",
     "nigori/nigori_key_bag_unittest.cc",
     "nigori/nigori_model_type_processor_unittest.cc",
     "nigori/nigori_storage_impl_unittest.cc",
@@ -650,6 +651,7 @@
     "protocol/proto_value_conversions_unittest.cc",
     "syncable/change_record_unittest.cc",
     "syncable/directory_backing_store_unittest.cc",
+    "syncable/directory_cryptographer_unittest.cc",
     "syncable/directory_unittest.cc",
     "syncable/directory_unittest.h",
     "syncable/entry_kernel_unittest.cc",
diff --git a/components/sync/driver/generic_change_processor.cc b/components/sync/driver/generic_change_processor.cc
index 52d9d87e..c3e3082 100644
--- a/components/sync/driver/generic_change_processor.cc
+++ b/components/sync/driver/generic_change_processor.cc
@@ -575,7 +575,7 @@
   // We only access the cryptographer while holding a transaction.
   ReadTransaction trans(FROM_HERE, share_handle());
   const ModelTypeSet encrypted_types = trans.GetEncryptedTypes();
-  return !encrypted_types.Has(type_) || trans.GetCryptographer()->is_ready();
+  return !encrypted_types.Has(type_) || trans.GetCryptographer()->CanEncrypt();
 }
 
 void GenericChangeProcessor::StartImpl() {}
diff --git a/components/sync/engine_impl/all_status.h b/components/sync/engine_impl/all_status.h
index 4fade76..48cb51c 100644
--- a/components/sync/engine_impl/all_status.h
+++ b/components/sync/engine_impl/all_status.h
@@ -55,6 +55,8 @@
   void IncrementNotificationsReceived();
 
   void SetEncryptedTypes(ModelTypeSet types);
+  // TODO(crbug.com/967417): Rename Ready->CanEncrypt in consistency with
+  // Cryptographer's API.
   void SetCryptographerReady(bool ready);
   void SetCryptoHasPendingKeys(bool has_pending_keys);
   void SetPassphraseType(PassphraseType type);
diff --git a/components/sync/engine_impl/apply_control_data_updates.cc b/components/sync/engine_impl/apply_control_data_updates.cc
index ebd59ab..6da24e5e 100644
--- a/components/sync/engine_impl/apply_control_data_updates.cc
+++ b/components/sync/engine_impl/apply_control_data_updates.cc
@@ -12,8 +12,8 @@
 #include "components/sync/engine_impl/conflict_resolver.h"
 #include "components/sync/engine_impl/conflict_util.h"
 #include "components/sync/engine_impl/syncer_util.h"
-#include "components/sync/nigori/cryptographer.h"
 #include "components/sync/syncable/directory.h"
+#include "components/sync/syncable/directory_cryptographer.h"
 #include "components/sync/syncable/mutable_entry.h"
 #include "components/sync/syncable/nigori_handler.h"
 #include "components/sync/syncable/nigori_util.h"
@@ -35,7 +35,14 @@
 void ApplyNigoriUpdate(syncable::Directory* dir) {
   syncable::WriteTransaction trans(FROM_HERE, syncable::SYNCER, dir);
   syncable::MutableEntry entry(&trans, syncable::GET_TYPE_ROOT, NIGORI);
-  const Cryptographer* cryptographer = dir->GetCryptographer(&trans);
+  const DirectoryCryptographer* cryptographer =
+      dir->GetNigoriHandler()->GetDirectoryCryptographerForNigori(&trans);
+
+  if (!cryptographer) {
+    // This indicates that the USS implementation of NIGORI is active, hence
+    // there's nothing to do here.
+    return;
+  }
 
   if (!entry.good()) {
     return;
@@ -59,7 +66,7 @@
   // re-encrypted at SetDecryptionPassphrase time (via ReEncryptEverything).
   // This logic covers the case where the nigori update marked new datatypes
   // for encryption, but didn't change the passphrase.
-  if (cryptographer->is_ready()) {
+  if (cryptographer->CanEncrypt()) {
     // Note that we don't bother to encrypt any data for which IS_UNSYNCED
     // == false here. The machine that turned on encryption should know about
     // and re-encrypt all synced data. It's possible it could get interrupted
@@ -97,7 +104,7 @@
     // Note: we only update the encryption keybag if we're sure that we aren't
     // invalidating the keystore_decryptor_token (i.e. we're either
     // not migrated or we copying over all local state).
-    if (cryptographer->is_ready()) {
+    if (cryptographer->CanEncrypt()) {
       if (local_nigori.has_passphrase_type() &&
           server_nigori.has_passphrase_type()) {
         // They're both migrated, preserve the local nigori if the passphrase
diff --git a/components/sync/engine_impl/apply_control_data_updates_unittest.cc b/components/sync/engine_impl/apply_control_data_updates_unittest.cc
index 98e738ad..56d642b 100644
--- a/components/sync/engine_impl/apply_control_data_updates_unittest.cc
+++ b/components/sync/engine_impl/apply_control_data_updates_unittest.cc
@@ -53,7 +53,8 @@
 
   void TearDown() override { dir_maker_.TearDown(); }
 
-  Cryptographer* GetCryptographer(const syncable::BaseTransaction* trans) {
+  DirectoryCryptographer* GetCryptographer(
+      const syncable::BaseTransaction* trans) {
     return dir_maker_.GetCryptographer(trans);
   }
 
@@ -75,7 +76,7 @@
 TEST_F(ApplyControlDataUpdatesTest, NigoriUpdate) {
   // Storing the cryptographer separately is bad, but for this test we
   // know it's safe.
-  Cryptographer* cryptographer;
+  DirectoryCryptographer* cryptographer;
   ModelTypeSet encrypted_types;
   encrypted_types.PutAll(SyncEncryptionHandler::SensitiveTypes());
 
@@ -87,7 +88,7 @@
   }
 
   // Nigori node updates should update the Cryptographer.
-  Cryptographer other_cryptographer;
+  DirectoryCryptographer other_cryptographer;
   KeyParams params = {KeyDerivationParams::CreateForPbkdf2(), "foobar"};
   other_cryptographer.AddKey(params);
 
@@ -101,7 +102,7 @@
 
   ApplyNigoriUpdate(directory());
 
-  EXPECT_FALSE(cryptographer->is_ready());
+  EXPECT_FALSE(cryptographer->CanEncrypt());
   EXPECT_TRUE(cryptographer->has_pending_keys());
   {
     syncable::ReadTransaction trans(FROM_HERE, directory());
@@ -118,7 +119,7 @@
 TEST_F(ApplyControlDataUpdatesTest, EncryptUnsyncedChanges) {
   // Storing the cryptographer separately is bad, but for this test we
   // know it's safe.
-  Cryptographer* cryptographer;
+  DirectoryCryptographer* cryptographer;
   ModelTypeSet encrypted_types;
   encrypted_types.PutAll(SyncEncryptionHandler::SensitiveTypes());
   {
@@ -165,7 +166,7 @@
   entry_factory_->CreateUnappliedNewItem(ModelTypeToRootTag(NIGORI), specifics,
                                          true);
   EXPECT_FALSE(cryptographer->has_pending_keys());
-  EXPECT_TRUE(cryptographer->is_ready());
+  EXPECT_TRUE(cryptographer->CanEncrypt());
 
   {
     // Ensure we have unsynced nodes that aren't properly encrypted.
@@ -180,7 +181,7 @@
   ApplyNigoriUpdate(directory());
 
   EXPECT_FALSE(cryptographer->has_pending_keys());
-  EXPECT_TRUE(cryptographer->is_ready());
+  EXPECT_TRUE(cryptographer->CanEncrypt());
   {
     syncable::ReadTransaction trans(FROM_HERE, directory());
 
@@ -207,7 +208,7 @@
   ApplyNigoriUpdate(directory());
 
   EXPECT_FALSE(cryptographer->has_pending_keys());
-  EXPECT_TRUE(cryptographer->is_ready());
+  EXPECT_TRUE(cryptographer->CanEncrypt());
   {
     syncable::ReadTransaction trans(FROM_HERE, directory());
 
@@ -229,7 +230,7 @@
 TEST_F(ApplyControlDataUpdatesTest, CannotEncryptUnsyncedChanges) {
   // Storing the cryptographer separately is bad, but for this test we
   // know it's safe.
-  Cryptographer* cryptographer;
+  DirectoryCryptographer* cryptographer;
   ModelTypeSet encrypted_types;
   encrypted_types.PutAll(SyncEncryptionHandler::SensitiveTypes());
   {
@@ -268,7 +269,7 @@
 
   // We encrypt with new keys, triggering the local cryptographer to be unready
   // and unable to decrypt data (once updated).
-  Cryptographer other_cryptographer;
+  DirectoryCryptographer other_cryptographer;
   KeyParams params = {KeyDerivationParams::CreateForPbkdf2(), "foobar"};
   other_cryptographer.AddKey(params);
   sync_pb::EntitySpecifics specifics;
@@ -291,7 +292,7 @@
 
   ApplyNigoriUpdate(directory());
 
-  EXPECT_FALSE(cryptographer->is_ready());
+  EXPECT_FALSE(cryptographer->CanEncrypt());
   EXPECT_TRUE(cryptographer->has_pending_keys());
   {
     syncable::ReadTransaction trans(FROM_HERE, directory());
@@ -301,7 +302,7 @@
     EXPECT_FALSE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
     EXPECT_EQ(ModelTypeSet::All(),
               directory()->GetNigoriHandler()->GetEncryptedTypes(&trans));
-    EXPECT_FALSE(cryptographer->is_ready());
+    EXPECT_FALSE(cryptographer->CanEncrypt());
     EXPECT_TRUE(cryptographer->has_pending_keys());
 
     syncable::Directory::Metahandles handles;
@@ -315,7 +316,7 @@
 // Initial sync ended should be set.
 TEST_F(ApplyControlDataUpdatesTest,
        NigoriConflictPendingKeysServerEncryptEverythingCustom) {
-  Cryptographer* cryptographer;
+  DirectoryCryptographer* cryptographer;
   ModelTypeSet encrypted_types(SyncEncryptionHandler::SensitiveTypes());
   KeyParams other_params = {KeyDerivationParams::CreateForPbkdf2(), "foobar"};
   KeyParams local_params = {KeyDerivationParams::CreateForPbkdf2(), "local"};
@@ -327,7 +328,7 @@
   }
 
   // Set up a temporary cryptographer to generate new keys with.
-  Cryptographer other_cryptographer;
+  DirectoryCryptographer other_cryptographer;
   other_cryptographer.AddKey(other_params);
 
   // Create server specifics with pending keys, new encrypted types,
@@ -342,7 +343,7 @@
 
   // Initialize the local cryptographer with the local keys.
   cryptographer->AddKey(local_params);
-  EXPECT_TRUE(cryptographer->is_ready());
+  EXPECT_TRUE(cryptographer->CanEncrypt());
 
   // Set up a local nigori with the local encryption keys and default encrypted
   // types.
@@ -367,7 +368,7 @@
   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
   EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
 
-  EXPECT_FALSE(cryptographer->is_ready());
+  EXPECT_FALSE(cryptographer->CanEncrypt());
   EXPECT_TRUE(cryptographer->is_initialized());
   EXPECT_TRUE(cryptographer->has_pending_keys());
   EXPECT_TRUE(other_cryptographer.CanDecryptUsingDefaultKey(
@@ -392,7 +393,7 @@
 // Initial sync ended should be set.
 TEST_F(ApplyControlDataUpdatesTest,
        NigoriConflictPendingKeysLocalEncryptEverythingCustom) {
-  Cryptographer* cryptographer;
+  DirectoryCryptographer* cryptographer;
   ModelTypeSet encrypted_types(SyncEncryptionHandler::SensitiveTypes());
   KeyParams other_params = {KeyDerivationParams::CreateForPbkdf2(), "foobar"};
   KeyParams local_params = {KeyDerivationParams::CreateForPbkdf2(), "local"};
@@ -404,7 +405,7 @@
   }
 
   // Set up a temporary cryptographer to generate new keys with.
-  Cryptographer other_cryptographer;
+  DirectoryCryptographer other_cryptographer;
   other_cryptographer.AddKey(other_params);
 
   // Create server specifics with pending keys, new encrypted types,
@@ -419,7 +420,7 @@
 
   // Initialize the local cryptographer with the local keys.
   cryptographer->AddKey(local_params);
-  EXPECT_TRUE(cryptographer->is_ready());
+  EXPECT_TRUE(cryptographer->CanEncrypt());
 
   // Set up a local nigori with the local encryption keys and default encrypted
   // types.
@@ -444,7 +445,7 @@
   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
   EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
 
-  EXPECT_FALSE(cryptographer->is_ready());
+  EXPECT_FALSE(cryptographer->CanEncrypt());
   EXPECT_TRUE(cryptographer->is_initialized());
   EXPECT_TRUE(cryptographer->has_pending_keys());
   EXPECT_TRUE(other_cryptographer.CanDecryptUsingDefaultKey(
@@ -468,7 +469,7 @@
 // resolution should preserve the full local keys. Initial sync ended should be
 // set.
 TEST_F(ApplyControlDataUpdatesTest, NigoriConflictOldKeys) {
-  Cryptographer* cryptographer;
+  DirectoryCryptographer* cryptographer;
   ModelTypeSet encrypted_types(SyncEncryptionHandler::SensitiveTypes());
   KeyParams old_params = {KeyDerivationParams::CreateForPbkdf2(), "old"};
   KeyParams new_params = {KeyDerivationParams::CreateForPbkdf2(), "new"};
@@ -492,7 +493,7 @@
 
   // Add the new keys to the cryptogrpaher
   cryptographer->AddKey(new_params);
-  EXPECT_TRUE(cryptographer->is_ready());
+  EXPECT_TRUE(cryptographer->CanEncrypt());
 
   // Set up a local nigori with the superset of keys.
   sync_pb::EntitySpecifics local_specifics;
@@ -515,7 +516,7 @@
   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
   EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
 
-  EXPECT_TRUE(cryptographer->is_ready());
+  EXPECT_TRUE(cryptographer->CanEncrypt());
   EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey(
       entry_factory_->GetLocalSpecificsForItem(nigori_handle)
           .nigori()
@@ -536,7 +537,7 @@
 // If both nigoris are migrated, but we also set a custom passphrase locally,
 // the local nigori should be preserved.
 TEST_F(ApplyControlDataUpdatesTest, NigoriConflictBothMigratedLocalCustom) {
-  Cryptographer* cryptographer;
+  DirectoryCryptographer* cryptographer;
   ModelTypeSet encrypted_types(SyncEncryptionHandler::SensitiveTypes());
   KeyParams old_params = {KeyDerivationParams::CreateForPbkdf2(), "old"};
   KeyParams new_params = {KeyDerivationParams::CreateForPbkdf2(), "new"};
@@ -548,7 +549,7 @@
   }
 
   // Set up the cryptographer with new keys
-  Cryptographer other_cryptographer;
+  DirectoryCryptographer other_cryptographer;
   other_cryptographer.AddKey(old_params);
 
   // Create server specifics with a migrated keystore passphrase type.
@@ -566,7 +567,7 @@
   // Add the new keys to the cryptographer.
   cryptographer->AddKey(old_params);
   cryptographer->AddKey(new_params);
-  EXPECT_TRUE(cryptographer->is_ready());
+  EXPECT_TRUE(cryptographer->CanEncrypt());
 
   // Set up a local nigori with a migrated custom passphrase type
   sync_pb::EntitySpecifics local_specifics;
@@ -592,7 +593,7 @@
   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
   EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
 
-  EXPECT_TRUE(cryptographer->is_ready());
+  EXPECT_TRUE(cryptographer->CanEncrypt());
   EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey(
       entry_factory_->GetLocalSpecificsForItem(nigori_handle)
           .nigori()
@@ -617,7 +618,7 @@
 // If both nigoris are migrated, but a custom passphrase with a new key was
 // set remotely, the remote nigori should be preserved.
 TEST_F(ApplyControlDataUpdatesTest, NigoriConflictBothMigratedServerCustom) {
-  Cryptographer* cryptographer;
+  DirectoryCryptographer* cryptographer;
   ModelTypeSet encrypted_types(SyncEncryptionHandler::SensitiveTypes());
   KeyParams old_params = {KeyDerivationParams::CreateForPbkdf2(), "old"};
   KeyParams new_params = {KeyDerivationParams::CreateForPbkdf2(), "new"};
@@ -629,7 +630,7 @@
   }
 
   // Set up the cryptographer with both new keys and old keys.
-  Cryptographer other_cryptographer;
+  DirectoryCryptographer other_cryptographer;
   other_cryptographer.AddKey(old_params);
   other_cryptographer.AddKey(new_params);
 
@@ -646,7 +647,7 @@
 
   // Add the old keys to the cryptographer.
   cryptographer->AddKey(old_params);
-  EXPECT_TRUE(cryptographer->is_ready());
+  EXPECT_TRUE(cryptographer->CanEncrypt());
 
   // Set up a local nigori with a migrated keystore passphrase type
   sync_pb::EntitySpecifics local_specifics;
@@ -699,7 +700,7 @@
 // If the local nigori is migrated but the server is not, preserve the local
 // nigori.
 TEST_F(ApplyControlDataUpdatesTest, NigoriConflictLocalMigrated) {
-  Cryptographer* cryptographer;
+  DirectoryCryptographer* cryptographer;
   ModelTypeSet encrypted_types(SyncEncryptionHandler::SensitiveTypes());
   KeyParams old_params = {KeyDerivationParams::CreateForPbkdf2(), "old"};
   KeyParams new_params = {KeyDerivationParams::CreateForPbkdf2(), "new"};
@@ -711,7 +712,7 @@
   }
 
   // Set up the cryptographer with both new keys and old keys.
-  Cryptographer other_cryptographer;
+  DirectoryCryptographer other_cryptographer;
   other_cryptographer.AddKey(old_params);
 
   // Create server specifics with an unmigrated implicit passphrase type.
@@ -726,7 +727,7 @@
   // Add the old keys to the cryptographer.
   cryptographer->AddKey(old_params);
   cryptographer->AddKey(new_params);
-  EXPECT_TRUE(cryptographer->is_ready());
+  EXPECT_TRUE(cryptographer->CanEncrypt());
 
   // Set up a local nigori with a migrated custom passphrase type
   sync_pb::EntitySpecifics local_specifics;
@@ -752,7 +753,7 @@
   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
   EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
 
-  EXPECT_TRUE(cryptographer->is_ready());
+  EXPECT_TRUE(cryptographer->CanEncrypt());
   EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey(
       entry_factory_->GetLocalSpecificsForItem(nigori_handle)
           .nigori()
@@ -777,7 +778,7 @@
 // If the server nigori is migrated but the local is not, preserve the server
 // nigori.
 TEST_F(ApplyControlDataUpdatesTest, NigoriConflictServerMigrated) {
-  Cryptographer* cryptographer;
+  DirectoryCryptographer* cryptographer;
   ModelTypeSet encrypted_types(SyncEncryptionHandler::SensitiveTypes());
   KeyParams old_params = {KeyDerivationParams::CreateForPbkdf2(), "old"};
   KeyParams new_params = {KeyDerivationParams::CreateForPbkdf2(), "new"};
@@ -789,7 +790,7 @@
   }
 
   // Set up the cryptographer with both new keys and old keys.
-  Cryptographer other_cryptographer;
+  DirectoryCryptographer other_cryptographer;
   other_cryptographer.AddKey(old_params);
 
   // Create server specifics with an migrated keystore passphrase type.
@@ -807,7 +808,7 @@
   // Add the old keys to the cryptographer.
   cryptographer->AddKey(old_params);
   cryptographer->AddKey(new_params);
-  EXPECT_TRUE(cryptographer->is_ready());
+  EXPECT_TRUE(cryptographer->CanEncrypt());
 
   // Set up a local nigori with a migrated custom passphrase type
   sync_pb::EntitySpecifics local_specifics;
@@ -831,7 +832,7 @@
   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
   EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
 
-  EXPECT_TRUE(cryptographer->is_ready());
+  EXPECT_TRUE(cryptographer->CanEncrypt());
   // Note: we didn't overwrite the encryption keybag with the local keys. The
   // sync encryption handler will do that when it detects that the new
   // keybag is out of date (and update the keystore bootstrap if necessary).
@@ -860,7 +861,7 @@
 TEST_F(ApplyControlDataUpdatesTest, NigoriApplyMarksDownloadCompleted) {
   EXPECT_FALSE(directory()->InitialSyncEndedForType(NIGORI));
 
-  Cryptographer* cryptographer;
+  DirectoryCryptographer* cryptographer;
 
   {
     syncable::ReadTransaction trans(FROM_HERE, directory());
diff --git a/components/sync/engine_impl/conflict_resolver.cc b/components/sync/engine_impl/conflict_resolver.cc
index f64c178..43b00a8 100644
--- a/components/sync/engine_impl/conflict_resolver.cc
+++ b/components/sync/engine_impl/conflict_resolver.cc
@@ -20,11 +20,21 @@
 
 namespace syncer {
 
+namespace {
+
 using syncable::Directory;
 using syncable::Entry;
 using syncable::Id;
 using syncable::MutableEntry;
 
+bool CanDecryptUsingDefaultKey(const Cryptographer& cryptographer,
+                               const sync_pb::EncryptedData& encrypted) {
+  return !encrypted.key_name().empty() &&
+         encrypted.key_name() == cryptographer.GetDefaultEncryptionKeyName();
+}
+
+}  // namespace
+
 ConflictResolver::ConflictResolver() {}
 
 ConflictResolver::~ConflictResolver() {}
@@ -112,7 +122,7 @@
     bool specifics_match = false;
     bool server_encrypted_with_default_key = false;
     if (specifics.has_encrypted()) {
-      DCHECK(cryptographer->CanDecryptUsingDefaultKey(specifics.encrypted()));
+      DCHECK(CanDecryptUsingDefaultKey(*cryptographer, specifics.encrypted()));
       // TODO(crbug.com/908391): what if the decryption below fails?
       cryptographer->DecryptToString(specifics.encrypted(),
                                      &decrypted_specifics);
@@ -120,9 +130,8 @@
       decrypted_specifics = specifics.SerializeAsString();
     }
     if (server_specifics.has_encrypted()) {
-      server_encrypted_with_default_key =
-          cryptographer->CanDecryptUsingDefaultKey(
-              server_specifics.encrypted());
+      server_encrypted_with_default_key = CanDecryptUsingDefaultKey(
+          *cryptographer, server_specifics.encrypted());
       // TODO(crbug.com/908391): what if the decryption below fails?
       cryptographer->DecryptToString(server_specifics.encrypted(),
                                      &decrypted_server_specifics);
diff --git a/components/sync/engine_impl/debug_info_event_listener.cc b/components/sync/engine_impl/debug_info_event_listener.cc
index db935e6..7be9e73 100644
--- a/components/sync/engine_impl/debug_info_event_listener.cc
+++ b/components/sync/engine_impl/debug_info_event_listener.cc
@@ -102,7 +102,7 @@
     Cryptographer* cryptographer) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   cryptographer_has_pending_keys_ = cryptographer->has_pending_keys();
-  cryptographer_ready_ = cryptographer->is_ready();
+  cryptographer_ready_ = cryptographer->CanEncrypt();
 }
 
 void DebugInfoEventListener::OnPassphraseTypeChanged(
diff --git a/components/sync/engine_impl/directory_update_handler.cc b/components/sync/engine_impl/directory_update_handler.cc
index bd234cd..b470a92 100644
--- a/components/sync/engine_impl/directory_update_handler.cc
+++ b/components/sync/engine_impl/directory_update_handler.cc
@@ -16,6 +16,7 @@
 #include "components/sync/engine_impl/cycle/status_controller.h"
 #include "components/sync/engine_impl/update_applicator.h"
 #include "components/sync/syncable/directory.h"
+#include "components/sync/syncable/directory_cryptographer.h"
 #include "components/sync/syncable/model_neutral_mutable_entry.h"
 #include "components/sync/syncable/syncable_changes_version.h"
 #include "components/sync/syncable/syncable_model_neutral_write_transaction.h"
diff --git a/components/sync/engine_impl/directory_update_handler_unittest.cc b/components/sync/engine_impl/directory_update_handler_unittest.cc
index 6e5f1f4..0340b0e 100644
--- a/components/sync/engine_impl/directory_update_handler_unittest.cc
+++ b/components/sync/engine_impl/directory_update_handler_unittest.cc
@@ -528,7 +528,8 @@
     return articles_emitter_.GetUpdateCounters();
   }
 
-  Cryptographer* GetCryptographer(const syncable::BaseTransaction* trans) {
+  DirectoryCryptographer* GetCryptographer(
+      const syncable::BaseTransaction* trans) {
     return dir_maker_.GetCryptographer(trans);
   }
 
@@ -947,7 +948,7 @@
 // Attempt application of password upates where the passphrase is known.
 TEST_F(DirectoryUpdateHandlerApplyUpdateTest, DecryptablePassword) {
   // Decryptable password updates should be applied.
-  Cryptographer* cryptographer;
+  DirectoryCryptographer* cryptographer;
   {
     // Storing the cryptographer separately is bad, but for this test we
     // know it's safe.
@@ -1031,7 +1032,7 @@
 
 // Test a mix of decryptable and undecryptable updates.
 TEST_F(DirectoryUpdateHandlerApplyUpdateTest, SomeUndecryptablePassword) {
-  Cryptographer* cryptographer;
+  DirectoryCryptographer* cryptographer;
 
   int64_t decryptable_handle = -1;
   int64_t undecryptable_handle = -1;
@@ -1056,7 +1057,7 @@
   }
   {
     // Create a new cryptographer, independent of the one in the cycle.
-    Cryptographer other_cryptographer;
+    DirectoryCryptographer other_cryptographer;
     KeyParams params = {KeyDerivationParams::CreateForPbkdf2(), "bazqux"};
     other_cryptographer.AddKey(params);
 
diff --git a/components/sync/engine_impl/js_sync_encryption_handler_observer.cc b/components/sync/engine_impl/js_sync_encryption_handler_observer.cc
index 005f27c3..6c285580 100644
--- a/components/sync/engine_impl/js_sync_encryption_handler_observer.cc
+++ b/components/sync/engine_impl/js_sync_encryption_handler_observer.cc
@@ -86,7 +86,7 @@
     return;
   }
   base::DictionaryValue details;
-  details.SetBoolean("ready", cryptographer->is_ready());
+  details.SetBoolean("canEncrypt", cryptographer->CanEncrypt());
   details.SetBoolean("hasPendingKeys", cryptographer->has_pending_keys());
   HandleJsEvent(FROM_HERE, "onCryptographerStateChanged",
                 JsEventDetails(&details));
diff --git a/components/sync/engine_impl/js_sync_encryption_handler_observer_unittest.cc b/components/sync/engine_impl/js_sync_encryption_handler_observer_unittest.cc
index 9afa1cf..5bf74a2 100644
--- a/components/sync/engine_impl/js_sync_encryption_handler_observer_unittest.cc
+++ b/components/sync/engine_impl/js_sync_encryption_handler_observer_unittest.cc
@@ -17,7 +17,7 @@
 #include "components/sync/engine/sync_string_conversions.h"
 #include "components/sync/js/js_event_details.h"
 #include "components/sync/js/js_test_util.h"
-#include "components/sync/nigori/cryptographer.h"
+#include "components/sync/syncable/directory_cryptographer.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace syncer {
@@ -136,7 +136,7 @@
   base::DictionaryValue expected_details;
   bool expected_ready = false;
   bool expected_pending = false;
-  expected_details.SetBoolean("ready", expected_ready);
+  expected_details.SetBoolean("canEncrypt", expected_ready);
   expected_details.SetBoolean("hasPendingKeys", expected_pending);
   ModelTypeSet encrypted_types;
 
@@ -144,7 +144,7 @@
               HandleJsEvent("onCryptographerStateChanged",
                             HasDetailsAsDictionary(expected_details)));
 
-  Cryptographer cryptographer;
+  DirectoryCryptographer cryptographer;
   js_sync_encryption_handler_observer_.OnCryptographerStateChanged(
       &cryptographer);
   PumpLoop();
diff --git a/components/sync/engine_impl/model_type_registry.cc b/components/sync/engine_impl/model_type_registry.cc
index 4535273..2946fa1 100644
--- a/components/sync/engine_impl/model_type_registry.cc
+++ b/components/sync/engine_impl/model_type_registry.cc
@@ -101,7 +101,7 @@
 
   std::unique_ptr<Cryptographer> cryptographer_copy;
   if (encrypted_types_.Has(type))
-    cryptographer_copy = std::make_unique<Cryptographer>(*cryptographer_);
+    cryptographer_copy = cryptographer_->Clone();
 
   DataTypeDebugInfoEmitter* emitter = GetEmitter(type);
   if (emitter == nullptr) {
@@ -352,7 +352,7 @@
 
 void ModelTypeRegistry::OnCryptographerStateChanged(
     Cryptographer* cryptographer) {
-  cryptographer_ = std::make_unique<Cryptographer>(*cryptographer);
+  cryptographer_ = cryptographer->Clone();
   OnEncryptionStateChanged();
 }
 
@@ -369,8 +369,7 @@
 void ModelTypeRegistry::OnEncryptionStateChanged() {
   for (const auto& worker : model_type_workers_) {
     if (encrypted_types_.Has(worker->GetModelType())) {
-      worker->UpdateCryptographer(
-          std::make_unique<Cryptographer>(*cryptographer_));
+      worker->UpdateCryptographer(cryptographer_->Clone());
     }
   }
 }
diff --git a/components/sync/engine_impl/model_type_worker.cc b/components/sync/engine_impl/model_type_worker.cc
index deedc58..40cbeef0 100644
--- a/components/sync/engine_impl/model_type_worker.cc
+++ b/components/sync/engine_impl/model_type_worker.cc
@@ -125,9 +125,9 @@
   // around, and we're not going to receive the normal UpdateCryptographer() or
   // EncryptionAcceptedApplyUpdates() calls to drive this process.
   //
-  // If |cryptographer_->is_ready()| is false, all the rest of this logic can be
-  // safely skipped, since |UpdateCryptographer(...)| must be called first and
-  // things should be driven normally after that.
+  // If |cryptographer_->CanEncrypt()| is false, all the rest of this logic can
+  // be safely skipped, since |UpdateCryptographer(...)| must be called first
+  // and things should be driven normally after that.
   //
   // If |model_type_state_.initial_sync_done()| is false, |model_type_state_|
   // may still need to be updated, since UpdateCryptographer() is never going to
@@ -135,7 +135,7 @@
   // the processor, and we should not push it now. In fact, doing so now would
   // violate the processor's assumption that the first OnUpdateReceived is will
   // be changing initial sync done to true.
-  if (cryptographer_ && cryptographer_->is_ready() &&
+  if (cryptographer_ && cryptographer_->CanEncrypt() &&
       UpdateEncryptionKeyName() && model_type_state_.initial_sync_done()) {
     ApplyPendingUpdates();
   }
@@ -387,10 +387,16 @@
     // Legacy clients don't populate the guid field in the BookmarkSpecifics, so
     // we use the originator_client_item_id instead, if it is a valid GUID.
     // Otherwise, we leave the field empty.
-    if (model_type == BOOKMARKS && !data->specifics.bookmark().has_guid() &&
-        base::IsValidGUID(update_entity.originator_client_item_id())) {
-      data->specifics.mutable_bookmark()->set_guid(
-          update_entity.originator_client_item_id());
+    if (model_type == BOOKMARKS) {
+      if (data->specifics.bookmark().has_guid()) {
+        LogGUIDSource(BookmarkGUIDSource::kSpecifics);
+      } else if (base::IsValidGUID(update_entity.originator_client_item_id())) {
+        data->specifics.mutable_bookmark()->set_guid(
+            update_entity.originator_client_item_id());
+        LogGUIDSource(BookmarkGUIDSource::kValidOCII);
+      } else {
+        LogGUIDSource(BookmarkGUIDSource::kLeftEmpty);
+      }
     }
     response_data->entity = std::move(data);
     response_data->encryption_key_name = specifics.encrypted().key_name();
@@ -423,7 +429,7 @@
 
 void ModelTypeWorker::EncryptionAcceptedMaybeApplyUpdates() {
   DCHECK(cryptographer_);
-  DCHECK(cryptographer_->is_ready());
+  DCHECK(cryptographer_->CanEncrypt());
 
   // Only push the encryption to the processor if we're already connected.
   // Otherwise this information can wait for the initial sync's first apply.
@@ -566,11 +572,12 @@
     return true;
 
   // Should be using encryption, but we do not have the keys.
-  return cryptographer_ && !cryptographer_->is_ready();
+  return cryptographer_ && !cryptographer_->CanEncrypt();
 }
 
 bool ModelTypeWorker::UpdateEncryptionKeyName() {
-  const std::string& new_key_name = cryptographer_->GetDefaultNigoriKeyName();
+  const std::string& new_key_name =
+      cryptographer_->GetDefaultEncryptionKeyName();
   const std::string& old_key_name = model_type_state_.encryption_key_name();
   if (old_key_name == new_key_name) {
     return false;
diff --git a/components/sync/engine_impl/model_type_worker_unittest.cc b/components/sync/engine_impl/model_type_worker_unittest.cc
index 61d631dd..654d59e 100644
--- a/components/sync/engine_impl/model_type_worker_unittest.cc
+++ b/components/sync/engine_impl/model_type_worker_unittest.cc
@@ -21,6 +21,7 @@
 #include "components/sync/engine_impl/commit_contribution.h"
 #include "components/sync/engine_impl/cycle/non_blocking_type_debug_info_emitter.h"
 #include "components/sync/engine_impl/cycle/status_controller.h"
+#include "components/sync/syncable/directory_cryptographer.h"
 #include "components/sync/test/engine/mock_model_type_processor.h"
 #include "components/sync/test/engine/mock_nudge_handler.h"
 #include "components/sync/test/engine/single_type_mock_server.h"
@@ -218,7 +219,7 @@
 
     std::unique_ptr<Cryptographer> cryptographer_copy;
     if (cryptographer_) {
-      cryptographer_copy = std::make_unique<Cryptographer>(*cryptographer_);
+      cryptographer_copy = cryptographer_->Clone();
     }
 
     worker_ = std::make_unique<ModelTypeWorker>(
@@ -229,7 +230,7 @@
 
   void InitializeCryptographer() {
     if (!cryptographer_) {
-      cryptographer_ = std::make_unique<Cryptographer>();
+      cryptographer_ = std::make_unique<DirectoryCryptographer>();
     }
   }
 
@@ -271,8 +272,7 @@
 
     // Update the worker with the latest cryptographer.
     if (worker()) {
-      worker()->UpdateCryptographer(
-          std::make_unique<Cryptographer>(*cryptographer_));
+      worker()->UpdateCryptographer(cryptographer_->Clone());
     }
   }
 
@@ -286,8 +286,7 @@
 
     // Update the worker with the latest cryptographer.
     if (worker()) {
-      worker()->UpdateCryptographer(
-          std::make_unique<Cryptographer>(*cryptographer_));
+      worker()->UpdateCryptographer(cryptographer_->Clone());
       worker()->EncryptionAcceptedMaybeApplyUpdates();
     }
   }
@@ -488,7 +487,7 @@
     if (!cryptographer_) {
       return std::string();
     }
-    return cryptographer_->GetDefaultNigoriKeyName();
+    return cryptographer_->GetDefaultEncryptionKeyName();
   }
 
   MockModelTypeProcessor* processor() { return mock_type_processor_; }
@@ -502,7 +501,7 @@
   const ModelType model_type_;
 
   // The cryptographer itself. Null if we're not encrypting the type.
-  std::unique_ptr<Cryptographer> cryptographer_;
+  std::unique_ptr<DirectoryCryptographer> cryptographer_;
 
   // The number of the most recent foreign encryption key known to our
   // cryptographer. Note that not all of these will be decryptable.
@@ -1305,7 +1304,6 @@
   const SyncEntity entity =
       server()->GetNthCommitMessage(0).commit().entries(0);
 
-  EXPECT_EQ(0, entity.attachment_id_size());
   EXPECT_FALSE(entity.has_ctime());
   EXPECT_FALSE(entity.has_deleted());
   EXPECT_FALSE(entity.has_folder());
@@ -1344,7 +1342,7 @@
   *entity.mutable_specifics() = GenerateSpecifics(kTag1, kValue1);
   UpdateResponseData response_data;
 
-  Cryptographer cryptographer;
+  DirectoryCryptographer cryptographer;
   base::HistogramTester histogram_tester;
 
   EXPECT_EQ(ModelTypeWorker::SUCCESS,
@@ -1385,7 +1383,7 @@
   // Add default value field for a Bookmark.
   entity.mutable_specifics()->mutable_bookmark();
 
-  Cryptographer cryptographer;
+  DirectoryCryptographer cryptographer;
 
   UpdateResponseData response_data;
   EXPECT_EQ(ModelTypeWorker::SUCCESS,
@@ -1407,7 +1405,7 @@
   *entity.mutable_specifics() = GenerateSpecifics(kTag1, kValue1);
 
   UpdateResponseData response_data;
-  Cryptographer cryptographer;
+  DirectoryCryptographer cryptographer;
   base::HistogramTester histogram_tester;
 
   EXPECT_EQ(ModelTypeWorker::SUCCESS,
@@ -1434,7 +1432,7 @@
   *entity.mutable_specifics() = GenerateSpecifics(kTag1, kValue1);
 
   UpdateResponseData response_data;
-  Cryptographer cryptographer;
+  DirectoryCryptographer cryptographer;
   base::HistogramTester histogram_tester;
 
   EXPECT_EQ(ModelTypeWorker::SUCCESS,
@@ -1463,7 +1461,7 @@
   *entity.mutable_specifics() = specifics;
 
   UpdateResponseData response_data;
-  Cryptographer cryptographer;
+  DirectoryCryptographer cryptographer;
   base::HistogramTester histogram_tester;
 
   EXPECT_EQ(ModelTypeWorker::SUCCESS,
@@ -1487,7 +1485,7 @@
   *entity.mutable_specifics() = GenerateSpecifics(kTag1, kValue1);
 
   UpdateResponseData response_data;
-  Cryptographer cryptographer;
+  DirectoryCryptographer cryptographer;
   base::HistogramTester histogram_tester;
 
   EXPECT_EQ(ModelTypeWorker::SUCCESS,
@@ -1514,7 +1512,7 @@
       UniquePosition::InitialPosition(UniquePosition::RandomSuffix()).ToProto();
 
   UpdateResponseData response_data;
-  Cryptographer cryptographer;
+  DirectoryCryptographer cryptographer;
 
   EXPECT_EQ(ModelTypeWorker::SUCCESS,
             ModelTypeWorker::PopulateUpdateResponseData(
@@ -1538,7 +1536,7 @@
       UniquePosition::InitialPosition(UniquePosition::RandomSuffix()).ToProto();
 
   UpdateResponseData response_data;
-  Cryptographer cryptographer;
+  DirectoryCryptographer cryptographer;
 
   EXPECT_EQ(ModelTypeWorker::SUCCESS,
             ModelTypeWorker::PopulateUpdateResponseData(
@@ -1564,7 +1562,7 @@
       UniquePosition::InitialPosition(UniquePosition::RandomSuffix()).ToProto();
 
   UpdateResponseData response_data;
-  Cryptographer cryptographer;
+  DirectoryCryptographer cryptographer;
 
   EXPECT_EQ(ModelTypeWorker::SUCCESS,
             ModelTypeWorker::PopulateUpdateResponseData(
diff --git a/components/sync/engine_impl/non_blocking_type_commit_contribution_unittest.cc b/components/sync/engine_impl/non_blocking_type_commit_contribution_unittest.cc
index 5066bea..9c6dee7 100644
--- a/components/sync/engine_impl/non_blocking_type_commit_contribution_unittest.cc
+++ b/components/sync/engine_impl/non_blocking_type_commit_contribution_unittest.cc
@@ -13,7 +13,7 @@
 #include "components/sync/base/hash_util.h"
 #include "components/sync/base/model_type.h"
 #include "components/sync/base/unique_position.h"
-#include "components/sync/nigori/cryptographer.h"
+#include "components/sync/syncable/directory_cryptographer.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace syncer {
@@ -165,7 +165,7 @@
   base::ObserverList<TypeDebugInfoObserver>::Unchecked observers;
   DataTypeDebugInfoEmitter debug_info_emitter(PASSWORDS, &observers);
 
-  Cryptographer cryptographer;
+  DirectoryCryptographer cryptographer;
   cryptographer.AddKey({KeyDerivationParams::CreateForPbkdf2(), "dummy"});
 
   CommitRequestDataList requests_data;
@@ -226,7 +226,7 @@
   base::ObserverList<TypeDebugInfoObserver>::Unchecked observers;
   DataTypeDebugInfoEmitter debug_info_emitter(PASSWORDS, &observers);
 
-  Cryptographer cryptographer;
+  DirectoryCryptographer cryptographer;
   cryptographer.AddKey({KeyDerivationParams::CreateForPbkdf2(), "dummy"});
 
   CommitRequestDataList requests_data;
diff --git a/components/sync/engine_impl/sync_encryption_handler_impl.cc b/components/sync/engine_impl/sync_encryption_handler_impl.cc
index 3e727e5c..bf795d1 100644
--- a/components/sync/engine_impl/sync_encryption_handler_impl.cc
+++ b/components/sync/engine_impl/sync_encryption_handler_impl.cc
@@ -302,7 +302,7 @@
 bool CanDecryptKeybagWithBase64DecodedKeys(
     const std::vector<std::string>& keystore_keys,
     const sync_pb::NigoriSpecifics& specifics) {
-  Cryptographer cryptographer;
+  DirectoryCryptographer cryptographer;
   for (const std::string& keystore_key : keystore_keys) {
     std::string decoded_key;
     base::Base64Decode(keystore_key, &decoded_key);
@@ -404,7 +404,8 @@
 
   bool has_pending_keys =
       UnlockVault(trans.GetWrappedTrans()).cryptographer.has_pending_keys();
-  bool is_ready = UnlockVault(trans.GetWrappedTrans()).cryptographer.is_ready();
+  bool is_ready =
+      UnlockVault(trans.GetWrappedTrans()).cryptographer.CanEncrypt();
   // Log the state of the cryptographer regardless of migration state.
   UMA_HISTOGRAM_BOOLEAN("Sync.CryptographerReady", is_ready);
   UMA_HISTOGRAM_BOOLEAN("Sync.CryptographerPendingKeys", has_pending_keys);
@@ -472,7 +473,7 @@
   // failed to initialize it), we don't want to try and re-encrypt the data.
   // If we had encrypted types, the DataTypeManager will block, preventing
   // sync from happening until the the passphrase is provided.
-  if (UnlockVault(trans.GetWrappedTrans()).cryptographer.is_ready())
+  if (UnlockVault(trans.GetWrappedTrans()).cryptographer.CanEncrypt())
     ReEncryptEverything(&trans);
 
   return true;
@@ -495,7 +496,7 @@
     return;
   }
 
-  Cryptographer* cryptographer =
+  DirectoryCryptographer* cryptographer =
       &UnlockVaultMutable(trans.GetWrappedTrans())->cryptographer;
 
   // Once we've migrated to keystore, the only way to set a passphrase for
@@ -644,7 +645,7 @@
     return;
   }
 
-  Cryptographer* cryptographer =
+  DirectoryCryptographer* cryptographer =
       &UnlockVaultMutable(trans.GetWrappedTrans())->cryptographer;
   if (!cryptographer->has_pending_keys()) {
     // Note that this *can* happen in a rare situation where data is
@@ -684,7 +685,7 @@
       // Otherwise, we're in a situation where the pending keys are
       // encrypted with an old gaia passphrase, while the default is the
       // current gaia passphrase. In that case, we preserve the default.
-      Cryptographer temp_cryptographer;
+      DirectoryCryptographer temp_cryptographer;
       temp_cryptographer.SetPendingKeys(cryptographer->GetPendingKeys());
       if (temp_cryptographer.DecryptPendingKeys(key_params)) {
         // Check to see if the pending bag of keys contains the current
@@ -773,7 +774,7 @@
   EnableEncryptEverythingImpl(trans.GetWrappedTrans());
   WriteEncryptionStateToNigori(
       &trans, NigoriMigrationTrigger::kEnableEncryptEverything);
-  if (UnlockVault(trans.GetWrappedTrans()).cryptographer.is_ready())
+  if (UnlockVault(trans.GetWrappedTrans()).cryptographer.CanEncrypt())
     ReEncryptEverything(&trans);
 }
 
@@ -871,7 +872,8 @@
   for (size_t i = 0; i < keys.size() - 1; ++i)
     base::Base64Encode(keys[i], &old_keystore_keys_[i]);
 
-  Cryptographer* cryptographer = &UnlockVaultMutable(&trans)->cryptographer;
+  DirectoryCryptographer* cryptographer =
+      &UnlockVaultMutable(&trans)->cryptographer;
 
   // Update the bootstrap token. If this fails, we persist an empty string,
   // which will force us to download the keystore keys again on the next
@@ -920,6 +922,12 @@
   return &UnlockVault(trans).cryptographer;
 }
 
+const DirectoryCryptographer*
+SyncEncryptionHandlerImpl::GetDirectoryCryptographerForNigori(
+    const syncable::BaseTransaction* const trans) const {
+  return &UnlockVault(trans).cryptographer;
+}
+
 ModelTypeSet SyncEncryptionHandlerImpl::GetEncryptedTypes(
     const syncable::BaseTransaction* const trans) const {
   return UnlockVault(trans).encrypted_types;
@@ -979,7 +987,8 @@
   ApplyNigoriUpdate(nigori_state.nigori_specifics, trans.GetWrappedTrans());
 }
 
-Cryptographer* SyncEncryptionHandlerImpl::GetMutableCryptographerForTesting() {
+DirectoryCryptographer*
+SyncEncryptionHandlerImpl::GetMutableCryptographerForTesting() {
   return &vault_unsafe_.cryptographer;
 }
 
@@ -989,7 +998,7 @@
 // type.
 void SyncEncryptionHandlerImpl::ReEncryptEverything(WriteTransaction* trans) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(UnlockVault(trans->GetWrappedTrans()).cryptographer.is_ready());
+  DCHECK(UnlockVault(trans->GetWrappedTrans()).cryptographer.CanEncrypt());
   for (ModelType type : UnlockVault(trans->GetWrappedTrans()).encrypted_types) {
     if (type == PASSWORDS || type == WIFI_CONFIGURATIONS || IsControlType(type))
       continue;  // These types handle encryption differently.
@@ -1145,7 +1154,8 @@
     }
   }
 
-  Cryptographer* cryptographer = &UnlockVaultMutable(trans)->cryptographer;
+  DirectoryCryptographer* cryptographer =
+      &UnlockVaultMutable(trans)->cryptographer;
   bool nigori_needs_new_keys = false;
   if (!nigori.encryption_keybag().blob().empty()) {
     // We only update the default key if this was a new explicit passphrase.
@@ -1210,7 +1220,7 @@
       observer.OnPassphraseRequired(REASON_DECRYPTION, key_derivation_params,
                                     pending_keys);
     }
-  } else if (!cryptographer->is_ready()) {
+  } else if (!cryptographer->CanEncrypt()) {
     DVLOG(1) << "OnPassphraseRequired sent because cryptographer is not "
              << "ready";
     for (auto& observer : observers_) {
@@ -1258,14 +1268,14 @@
     return;
 
   sync_pb::NigoriSpecifics nigori = nigori_node.GetNigoriSpecifics();
-  const Cryptographer& cryptographer =
+  const DirectoryCryptographer& cryptographer =
       UnlockVault(trans->GetWrappedTrans()).cryptographer;
 
   // Will not do anything if we shouldn't or can't migrate. Otherwise
   // migrates, writing the full encryption state as it does.
   if (!AttemptToMigrateNigoriToKeystore(trans, &nigori_node,
                                         migration_trigger)) {
-    if (cryptographer.is_ready() &&
+    if (cryptographer.CanEncrypt() &&
         nigori_overwrite_count_ < kNigoriOverwriteLimit) {
       // Does not modify the encrypted blob if the unencrypted data already
       // matches what is about to be written.
@@ -1396,7 +1406,7 @@
     return;
   }
 
-  Cryptographer* cryptographer =
+  DirectoryCryptographer* cryptographer =
       &UnlockVaultMutable(trans->GetWrappedTrans())->cryptographer;
   if (cryptographer->has_pending_keys()) {
     // This theoretically shouldn't happen, because the only way to have pending
@@ -1468,7 +1478,7 @@
   }
   KeyParams key_params = {key_derivation_params, passphrase};
 
-  Cryptographer* cryptographer =
+  DirectoryCryptographer* cryptographer =
       &UnlockVaultMutable(trans->GetWrappedTrans())->cryptographer;
   if (!cryptographer->has_pending_keys()) {
     // Note that this *can* happen in a rare situation where data is
@@ -1531,7 +1541,7 @@
     }
   }
 
-  const Cryptographer& cryptographer =
+  const DirectoryCryptographer& cryptographer =
       UnlockVault(trans->GetWrappedTrans()).cryptographer;
   if (!success) {
     // If we have not set an explicit method, fall back to PBKDF2 to ensure
@@ -1544,7 +1554,7 @@
       key_derivation_params = custom_passphrase_key_derivation_params_.value();
     }
 
-    if (cryptographer.is_ready()) {
+    if (cryptographer.CanEncrypt()) {
       LOG(ERROR) << "Attempt to change passphrase failed while cryptographer "
                  << "was ready.";
     } else if (cryptographer.has_pending_keys()) {
@@ -1561,7 +1571,7 @@
     return;
   }
   DCHECK(success);
-  DCHECK(cryptographer.is_ready());
+  DCHECK(cryptographer.CanEncrypt());
 
   // Will do nothing if we're already properly migrated or unable to migrate
   // (in otherwords, if GetMigrationReason returns kNoReason).
@@ -1649,7 +1659,7 @@
 SyncEncryptionHandlerImpl::NigoriMigrationReason
 SyncEncryptionHandlerImpl::GetMigrationReason(
     const sync_pb::NigoriSpecifics& nigori,
-    const Cryptographer& cryptographer,
+    const DirectoryCryptographer& cryptographer,
     PassphraseType passphrase_type) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // Don't migrate if there are pending encryption keys (because data
@@ -1689,7 +1699,7 @@
       encrypt_everything_) {
     return NigoriMigrationReason::kEncryptEverythingWithKeystorePassphrase;
   }
-  if (cryptographer.is_ready() &&
+  if (cryptographer.CanEncrypt() &&
       !cryptographer.CanDecryptUsingDefaultKey(nigori.encryption_keybag())) {
     // We need to overwrite the keybag. This might involve overwriting the
     // keystore decryptor too.
@@ -1701,7 +1711,7 @@
     // Note that once a key rotation has been performed, we no longer
     // preserve backwards compatibility, and the keybag will therefore be
     // encrypted with the current keystore key.
-    Cryptographer temp_cryptographer;
+    DirectoryCryptographer temp_cryptographer;
     KeyParams keystore_params = {KeyDerivationParams::CreateForPbkdf2(),
                                  keystore_key_};
     temp_cryptographer.AddKey(keystore_params);
@@ -1720,7 +1730,7 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   const sync_pb::NigoriSpecifics& old_nigori =
       nigori_node->GetNigoriSpecifics();
-  Cryptographer* cryptographer =
+  DirectoryCryptographer* cryptographer =
       &UnlockVaultMutable(trans->GetWrappedTrans())->cryptographer;
   PassphraseType* passphrase_type =
       &UnlockVaultMutable(trans->GetWrappedTrans())->passphrase_type;
@@ -1786,7 +1796,7 @@
       // cryptographer is not initialized), so we can't support backwards
       // compatibility. Ensure the keystore key is the default key.
       DVLOG(1) << "Migrating keybag to keystore key.";
-      bool cryptographer_was_ready = cryptographer->is_ready();
+      bool cryptographer_was_ready = cryptographer->CanEncrypt();
       if (!cryptographer->AddKey(key_params)) {
         LOG(ERROR) << "Failed to add keystore key as default key";
         UMA_HISTOGRAM_ENUMERATION("Sync.AttemptNigoriMigration",
@@ -1794,7 +1804,7 @@
                                   MIGRATION_RESULT_SIZE);
         return false;
       }
-      if (!cryptographer_was_ready && cryptographer->is_ready()) {
+      if (!cryptographer_was_ready && cryptographer->CanEncrypt()) {
         for (auto& observer : observers_) {
           observer.OnPassphraseAccepted();
         }
@@ -1918,19 +1928,19 @@
 }
 
 bool SyncEncryptionHandlerImpl::GetKeystoreDecryptor(
-    const Cryptographer& cryptographer,
+    const DirectoryCryptographer& cryptographer,
     const std::string& keystore_key,
     sync_pb::EncryptedData* encrypted_blob) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!keystore_key.empty());
-  DCHECK(cryptographer.is_ready());
+  DCHECK(cryptographer.CanEncrypt());
   std::string serialized_nigori;
   serialized_nigori = cryptographer.GetDefaultNigoriKeyData();
   if (serialized_nigori.empty()) {
     LOG(ERROR) << "Failed to get cryptographer bootstrap token.";
     return false;
   }
-  Cryptographer temp_cryptographer;
+  DirectoryCryptographer temp_cryptographer;
   KeyParams key_params = {KeyDerivationParams::CreateForPbkdf2(), keystore_key};
   if (!temp_cryptographer.AddKey(key_params))
     return false;
@@ -1942,7 +1952,7 @@
 bool SyncEncryptionHandlerImpl::AttemptToInstallKeybag(
     const sync_pb::EncryptedData& keybag,
     bool update_default,
-    Cryptographer* cryptographer) {
+    DirectoryCryptographer* cryptographer) {
   if (!cryptographer->CanDecrypt(keybag))
     return false;
   cryptographer->InstallKeys(keybag);
@@ -1967,11 +1977,11 @@
 
 bool SyncEncryptionHandlerImpl::DecryptPendingKeysWithKeystoreKey(
     const sync_pb::EncryptedData& keystore_decryptor_token,
-    Cryptographer* cryptographer) {
+    DirectoryCryptographer* cryptographer) {
   DCHECK(cryptographer->has_pending_keys());
   if (keystore_decryptor_token.blob().empty())
     return false;
-  Cryptographer temp_cryptographer;
+  DirectoryCryptographer temp_cryptographer;
 
   // First, go through and all all the old keystore keys to the temporary
   // cryptographer.
@@ -2022,7 +2032,7 @@
       DVLOG(1) << "Pending keys based on newest keystore key.";
       cryptographer->AddNonDefaultKey(keystore_params);
     }
-    if (cryptographer->is_ready()) {
+    if (cryptographer->CanEncrypt()) {
       std::string bootstrap_token;
       cryptographer->GetBootstrapToken(*encryptor_, &bootstrap_token);
       DVLOG(1) << "Keystore decryptor token decrypted pending keys.";
diff --git a/components/sync/engine_impl/sync_encryption_handler_impl.h b/components/sync/engine_impl/sync_encryption_handler_impl.h
index 8f9c75c8..9a30acab 100644
--- a/components/sync/engine_impl/sync_encryption_handler_impl.h
+++ b/components/sync/engine_impl/sync_encryption_handler_impl.h
@@ -18,8 +18,8 @@
 #include "base/sequence_checker.h"
 #include "base/time/time.h"
 #include "components/sync/engine/sync_encryption_handler.h"
-#include "components/sync/nigori/cryptographer.h"
 #include "components/sync/nigori/keystore_keys_handler.h"
+#include "components/sync/syncable/directory_cryptographer.h"
 #include "components/sync/syncable/nigori_handler.h"
 
 namespace syncer {
@@ -82,6 +82,8 @@
   // Can be called from any thread.
   const Cryptographer* GetCryptographer(
       const syncable::BaseTransaction* const trans) const override;
+  const DirectoryCryptographer* GetDirectoryCryptographerForNigori(
+      const syncable::BaseTransaction* const trans) const override;
   ModelTypeSet GetEncryptedTypes(
       const syncable::BaseTransaction* const trans) const override;
   PassphraseType GetPassphraseType(
@@ -104,9 +106,9 @@
   // Writes the nigori to the Directory and updates the Cryptographer.
   void RestoreNigori(const SyncEncryptionHandler::NigoriState& nigori_state);
 
-  // Returns mutable Cryptographer, used only in tests to manipulate it
+  // Returns mutable DirectoryCryptographer, used only in tests to manipulate it
   // directly.
-  Cryptographer* GetMutableCryptographerForTesting();
+  DirectoryCryptographer* GetMutableCryptographerForTesting();
 
  private:
   friend class SyncEncryptionHandlerImplTest;
@@ -147,7 +149,7 @@
     ~Vault();
 
     // Sync's cryptographer. Used for encrypting and decrypting sync data.
-    Cryptographer cryptographer;
+    DirectoryCryptographer cryptographer;
     // The set of types that require encryption.
     ModelTypeSet encrypted_types;
     // The current state of the passphrase required to decrypt the encryption
@@ -301,7 +303,7 @@
   // CUSTOM_PASSPHRASE).
   NigoriMigrationReason GetMigrationReason(
       const sync_pb::NigoriSpecifics& nigori,
-      const Cryptographer& cryptographer,
+      const DirectoryCryptographer& cryptographer,
       PassphraseType passphrase_type) const;
 
   // Tries to perform the actual migration of the |nigori_node| to support
@@ -316,7 +318,7 @@
   // |encrypted_blob|'s contents didn't already contain the key.
   // The keystore decryptor token is the serialized current default encryption
   // key, encrypted with the keystore key.
-  bool GetKeystoreDecryptor(const Cryptographer& cryptographer,
+  bool GetKeystoreDecryptor(const DirectoryCryptographer& cryptographer,
                             const std::string& keystore_key,
                             sync_pb::EncryptedData* encrypted_blob);
 
@@ -326,14 +328,14 @@
   // Will not update the default key.
   bool AttemptToInstallKeybag(const sync_pb::EncryptedData& keybag,
                               bool update_default,
-                              Cryptographer* cryptographer);
+                              DirectoryCryptographer* cryptographer);
 
   // Helper method for decrypting pending keys with the keystore bootstrap.
   // If successful, the default will become the key encrypted in the keystore
   // bootstrap, and will return true. Else will return false.
   bool DecryptPendingKeysWithKeystoreKey(
       const sync_pb::EncryptedData& keystore_bootstrap,
-      Cryptographer* cryptographer);
+      DirectoryCryptographer* cryptographer);
 
   // Helper to enable encrypt everything, notifying observers if necessary.
   // Will not perform re-encryption.
diff --git a/components/sync/engine_impl/sync_encryption_handler_impl_unittest.cc b/components/sync/engine_impl/sync_encryption_handler_impl_unittest.cc
index 7ac4101..2ff865e 100644
--- a/components/sync/engine_impl/sync_encryption_handler_impl_unittest.cc
+++ b/components/sync/engine_impl/sync_encryption_handler_impl_unittest.cc
@@ -169,7 +169,7 @@
     return encryption_handler_.get();
   }
   SyncEncryptionHandlerObserverMock* observer() { return &observer_; }
-  Cryptographer* GetCryptographer() {
+  DirectoryCryptographer* GetCryptographer() {
     return encryption_handler_->GetMutableCryptographerForTesting();
   }
 
@@ -239,14 +239,14 @@
       EXPECT_EQ(sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE,
                 nigori.passphrase_type());
       EXPECT_FALSE(nigori.has_custom_passphrase_key_derivation_method());
-      Cryptographer keystore_cryptographer;
+      DirectoryCryptographer keystore_cryptographer;
       KeyParams params = {KeyDerivationParams::CreateForPbkdf2(), kKeystoreKey};
       keystore_cryptographer.AddKey(params);
       EXPECT_TRUE(keystore_cryptographer.CanDecryptUsingDefaultKey(
           nigori.keystore_decryptor_token()));
     }
 
-    Cryptographer temp_cryptographer;
+    DirectoryCryptographer temp_cryptographer;
     if (key_derivation_params.has_value() &&
         passphrase_type == PassphraseType::kCustomPassphrase) {
       temp_cryptographer.AddKey({key_derivation_params.value(), passphrase});
@@ -267,7 +267,7 @@
       const std::string& keystore_key,
       const base::Optional<std::string>& key_derivation_salt) {
     DCHECK_NE(passphrase_type, PassphraseType::kImplicitPassphrase);
-    Cryptographer other_cryptographer;
+    DirectoryCryptographer other_cryptographer;
 
     std::string default_key = default_passphrase;
     if (default_key.empty()) {
@@ -315,7 +315,7 @@
       }
     }
 
-    EXPECT_TRUE(other_cryptographer.is_ready());
+    EXPECT_TRUE(other_cryptographer.CanEncrypt());
 
     sync_pb::NigoriSpecifics nigori;
     other_cryptographer.GetKeys(nigori.mutable_encryption_keybag());
@@ -509,11 +509,11 @@
   void InitUnmigratedNigori(const std::string& default_passphrase,
                             PassphraseType passphrase_type) {
     DCHECK_NE(passphrase_type, PassphraseType::kFrozenImplicitPassphrase);
-    Cryptographer other_cryptographer;
+    DirectoryCryptographer other_cryptographer;
     KeyParams default_key = {KeyDerivationParams::CreateForPbkdf2(),
                              default_passphrase};
     other_cryptographer.AddKey(default_key);
-    EXPECT_TRUE(other_cryptographer.is_ready());
+    EXPECT_TRUE(other_cryptographer.CanEncrypt());
 
     {
       WriteTransaction trans(FROM_HERE, user_share());
@@ -761,7 +761,7 @@
   KeyParams current_key = {KeyDerivationParams::CreateForPbkdf2(), "cur"};
 
   // Data for testing encryption/decryption.
-  Cryptographer other_cryptographer;
+  DirectoryCryptographer other_cryptographer;
   other_cryptographer.AddKey(old_key);
   sync_pb::EntitySpecifics other_encrypted_specifics;
   other_encrypted_specifics.mutable_bookmark()->set_title("title");
@@ -804,7 +804,7 @@
     encryption_handler()->ApplyNigoriUpdate(old_nigori,
                                             trans.GetWrappedTrans());
   }
-  EXPECT_TRUE(GetCryptographer()->is_ready());
+  EXPECT_TRUE(GetCryptographer()->CanEncrypt());
   EXPECT_FALSE(GetCryptographer()->has_pending_keys());
 
   // Encryption handler should have posted a task to overwrite the old
@@ -904,10 +904,10 @@
 TEST_F(SyncEncryptionHandlerImplTest, GetKeystoreDecryptor) {
   const char kCurKey[] = "cur";
   sync_pb::EncryptedData encrypted;
-  Cryptographer other_cryptographer;
+  DirectoryCryptographer other_cryptographer;
   KeyParams cur_key = {KeyDerivationParams::CreateForPbkdf2(), kCurKey};
   other_cryptographer.AddKey(cur_key);
-  EXPECT_TRUE(other_cryptographer.is_ready());
+  EXPECT_TRUE(other_cryptographer.CanEncrypt());
   EXPECT_TRUE(encryption_handler()->GetKeystoreDecryptor(
       other_cryptographer, kKeystoreKey, &encrypted));
   std::string serialized = encrypted.SerializeAsString();
@@ -932,7 +932,7 @@
     WriteTransaction trans(FROM_HERE, user_share());
     WriteNode nigori_node(&trans);
     ASSERT_EQ(nigori_node.InitTypeRoot(NIGORI), BaseNode::INIT_OK);
-    Cryptographer other_cryptographer;
+    DirectoryCryptographer other_cryptographer;
     KeyParams other_key = {KeyDerivationParams::CreateForPbkdf2(), kOtherKey};
     other_cryptographer.AddKey(other_key);
 
@@ -981,7 +981,7 @@
     WriteTransaction trans(FROM_HERE, user_share());
     WriteNode nigori_node(&trans);
     ASSERT_EQ(nigori_node.InitTypeRoot(NIGORI), BaseNode::INIT_OK);
-    Cryptographer other_cryptographer;
+    DirectoryCryptographer other_cryptographer;
     KeyParams other_key = {KeyDerivationParams::CreateForPbkdf2(), kOtherKey};
     other_cryptographer.AddKey(other_key);
 
@@ -1217,14 +1217,14 @@
 TEST_F(SyncEncryptionHandlerImplTest, ReceiveMigratedNigoriKeystorePass) {
   const char kCurKey[] = "cur";
   sync_pb::EncryptedData keystore_decryptor_token;
-  Cryptographer other_cryptographer;
+  DirectoryCryptographer other_cryptographer;
   KeyParams cur_key = {KeyDerivationParams::CreateForPbkdf2(), kCurKey};
   other_cryptographer.AddKey(cur_key);
-  EXPECT_TRUE(other_cryptographer.is_ready());
+  EXPECT_TRUE(other_cryptographer.CanEncrypt());
   EXPECT_TRUE(encryption_handler()->GetKeystoreDecryptor(
       other_cryptographer, kKeystoreKey, &keystore_decryptor_token));
   EXPECT_FALSE(encryption_handler()->MigratedToKeystore());
-  EXPECT_FALSE(GetCryptographer()->is_ready());
+  EXPECT_FALSE(GetCryptographer()->CanEncrypt());
   {
     ReadTransaction trans(FROM_HERE, user_share());
     EXPECT_NE(encryption_handler()->GetPassphraseType(trans.GetWrappedTrans()),
@@ -1260,7 +1260,7 @@
   Mock::VerifyAndClearExpectations(observer());
 
   EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
-  EXPECT_TRUE(GetCryptographer()->is_ready());
+  EXPECT_TRUE(GetCryptographer()->CanEncrypt());
   VerifyPassphraseType(PassphraseType::kKeystorePassphrase);
   EXPECT_FALSE(encryption_handler()->IsEncryptEverythingEnabled());
   VerifyMigratedNigoriWithTimestamp(1, PassphraseType::kKeystorePassphrase,
@@ -1273,7 +1273,7 @@
   EXPECT_TRUE(GetCryptographer()->CanDecryptUsingDefaultKey(current_encrypted));
 
   // Check that the cryptographer can decrypt keystore key based encryption.
-  Cryptographer keystore_cryptographer;
+  DirectoryCryptographer keystore_cryptographer;
   KeyParams keystore_key = {KeyDerivationParams::CreateForPbkdf2(),
                             kKeystoreKey};
   keystore_cryptographer.AddKey(keystore_key);
@@ -1289,7 +1289,7 @@
 TEST_F(SyncEncryptionHandlerImplTest, ReceiveMigratedNigoriFrozenImplicitPass) {
   const char kCurKey[] = "cur";
   sync_pb::EncryptedData encrypted;
-  Cryptographer other_cryptographer;
+  DirectoryCryptographer other_cryptographer;
   KeyParams cur_key = {KeyDerivationParams::CreateForPbkdf2(), kCurKey};
   other_cryptographer.AddKey(cur_key);
   EXPECT_FALSE(encryption_handler()->MigratedToKeystore());
@@ -1334,7 +1334,7 @@
   EXPECT_CALL(*observer(), OnPassphraseAccepted());
   encryption_handler()->SetDecryptionPassphrase(kCurKey);
   EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
-  EXPECT_TRUE(GetCryptographer()->is_ready());
+  EXPECT_TRUE(GetCryptographer()->CanEncrypt());
   VerifyMigratedNigoriWithTimestamp(
       1, PassphraseType::kFrozenImplicitPassphrase, kCurKey,
       /*key_derivation_method=*/base::nullopt);
@@ -1345,7 +1345,7 @@
   EXPECT_TRUE(GetCryptographer()->CanDecryptUsingDefaultKey(current_encrypted));
 
   // Check that the cryptographer can decrypt keystore key based encryption.
-  Cryptographer keystore_cryptographer;
+  DirectoryCryptographer keystore_cryptographer;
   KeyParams keystore_key = {KeyDerivationParams::CreateForPbkdf2(),
                             kKeystoreKey};
   keystore_cryptographer.AddKey(keystore_key);
@@ -1361,7 +1361,7 @@
 TEST_F(SyncEncryptionHandlerImplTest, ReceiveMigratedNigoriCustomPass) {
   const char kCurKey[] = "cur";
   sync_pb::EncryptedData encrypted;
-  Cryptographer other_cryptographer;
+  DirectoryCryptographer other_cryptographer;
   KeyParams cur_key = {KeyDerivationParams::CreateForPbkdf2(), kCurKey};
   other_cryptographer.AddKey(cur_key);
   EXPECT_FALSE(encryption_handler()->MigratedToKeystore());
@@ -1405,7 +1405,7 @@
   EXPECT_CALL(*observer(), OnPassphraseAccepted());
   encryption_handler()->SetDecryptionPassphrase(kCurKey);
   EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
-  EXPECT_TRUE(GetCryptographer()->is_ready());
+  EXPECT_TRUE(GetCryptographer()->CanEncrypt());
   VerifyMigratedNigoriWithTimestamp(1, PassphraseType::kCustomPassphrase,
                                     kCurKey,
                                     {KeyDerivationParams::CreateForPbkdf2()});
@@ -1416,7 +1416,7 @@
   EXPECT_TRUE(GetCryptographer()->CanDecryptUsingDefaultKey(current_encrypted));
 
   // Check that the cryptographer can decrypt keystore key based encryption.
-  Cryptographer keystore_cryptographer;
+  DirectoryCryptographer keystore_cryptographer;
   KeyParams keystore_key = {KeyDerivationParams::CreateForPbkdf2(),
                             kKeystoreKey};
   keystore_cryptographer.AddKey(keystore_key);
@@ -1459,7 +1459,7 @@
   EXPECT_CALL(*observer(), OnEncryptionComplete());
   encryption_handler()->Init();
   EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
-  EXPECT_TRUE(GetCryptographer()->is_ready());
+  EXPECT_TRUE(GetCryptographer()->CanEncrypt());
   VerifyPassphraseType(PassphraseType::kCustomPassphrase);
   EXPECT_TRUE(encryption_handler()->IsEncryptEverythingEnabled());
   VerifyMigratedNigoriWithTimestamp(migration_time,
@@ -1480,7 +1480,7 @@
       .WillOnce(testing::SaveArg<0>(&captured_nigori_state));
   EXPECT_CALL(*observer(), OnEncryptionComplete());
   {
-    Cryptographer other_cryptographer;
+    DirectoryCryptographer other_cryptographer;
     other_cryptographer.AddKey(old_key);
     WriteTransaction trans(FROM_HERE, user_share());
     WriteNode nigori_node(&trans);
@@ -1496,7 +1496,7 @@
 
   // Verify we're still migrated and have proper encryption state.
   EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
-  EXPECT_TRUE(GetCryptographer()->is_ready());
+  EXPECT_TRUE(GetCryptographer()->CanEncrypt());
   VerifyPassphraseType(PassphraseType::kCustomPassphrase);
   EXPECT_TRUE(encryption_handler()->IsEncryptEverythingEnabled());
   VerifyMigratedNigoriWithTimestamp(1, PassphraseType::kCustomPassphrase,
@@ -1548,7 +1548,7 @@
   EXPECT_CALL(*observer(), OnEncryptionComplete());
   encryption_handler()->Init();
   EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
-  EXPECT_TRUE(GetCryptographer()->is_ready());
+  EXPECT_TRUE(GetCryptographer()->CanEncrypt());
   VerifyPassphraseType(PassphraseType::kCustomPassphrase);
   EXPECT_TRUE(encryption_handler()->IsEncryptEverythingEnabled());
   VerifyMigratedNigoriWithTimestamp(1, PassphraseType::kCustomPassphrase,
@@ -1574,7 +1574,7 @@
     WriteNode nigori_node(&trans);
     ASSERT_EQ(nigori_node.InitTypeRoot(NIGORI), BaseNode::INIT_OK);
     sync_pb::NigoriSpecifics nigori;
-    Cryptographer other_cryptographer;
+    DirectoryCryptographer other_cryptographer;
     other_cryptographer.AddKey(old_key);
     encryption_handler()->GetKeystoreDecryptor(
         other_cryptographer, kKeystoreKey,
@@ -1591,7 +1591,7 @@
 
   // Verify we're still migrated and have proper encryption state.
   EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
-  EXPECT_TRUE(GetCryptographer()->is_ready());
+  EXPECT_TRUE(GetCryptographer()->CanEncrypt());
   VerifyPassphraseType(PassphraseType::kCustomPassphrase);
   EXPECT_TRUE(encryption_handler()->IsEncryptEverythingEnabled());
   VerifyMigratedNigoriWithTimestamp(migration_time,
@@ -1615,14 +1615,14 @@
 TEST_F(SyncEncryptionHandlerImplTest, SetKeystoreAfterReceivingMigratedNigori) {
   const char kCurKey[] = "cur";
   sync_pb::EncryptedData keystore_decryptor_token;
-  Cryptographer other_cryptographer;
+  DirectoryCryptographer other_cryptographer;
   KeyParams cur_key = {KeyDerivationParams::CreateForPbkdf2(), kCurKey};
   other_cryptographer.AddKey(cur_key);
-  EXPECT_TRUE(other_cryptographer.is_ready());
+  EXPECT_TRUE(other_cryptographer.CanEncrypt());
   EXPECT_TRUE(encryption_handler()->GetKeystoreDecryptor(
       other_cryptographer, kKeystoreKey, &keystore_decryptor_token));
   EXPECT_FALSE(encryption_handler()->MigratedToKeystore());
-  EXPECT_FALSE(GetCryptographer()->is_ready());
+  EXPECT_FALSE(GetCryptographer()->CanEncrypt());
   {
     ReadTransaction trans(FROM_HERE, user_share());
     EXPECT_NE(encryption_handler()->GetPassphraseType(trans.GetWrappedTrans()),
@@ -1668,7 +1668,7 @@
 
   PumpLoop();
   EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
-  EXPECT_TRUE(GetCryptographer()->is_ready());
+  EXPECT_TRUE(GetCryptographer()->CanEncrypt());
   VerifyPassphraseType(PassphraseType::kKeystorePassphrase);
   EXPECT_FALSE(encryption_handler()->IsEncryptEverythingEnabled());
   VerifyMigratedNigoriWithTimestamp(1, PassphraseType::kKeystorePassphrase,
@@ -1681,7 +1681,7 @@
   EXPECT_TRUE(GetCryptographer()->CanDecryptUsingDefaultKey(current_encrypted));
 
   // Check that the cryptographer can decrypt keystore key based encryption.
-  Cryptographer keystore_cryptographer;
+  DirectoryCryptographer keystore_cryptographer;
   KeyParams keystore_key = {KeyDerivationParams::CreateForPbkdf2(),
                             kKeystoreKey};
   keystore_cryptographer.AddKey(keystore_key);
@@ -1696,10 +1696,10 @@
 TEST_F(SyncEncryptionHandlerImplTest, SetCustomPassAfterMigration) {
   const char kOldKey[] = "old";
   sync_pb::EncryptedData keystore_decryptor_token;
-  Cryptographer other_cryptographer;
+  DirectoryCryptographer other_cryptographer;
   KeyParams cur_key = {KeyDerivationParams::CreateForPbkdf2(), kOldKey};
   other_cryptographer.AddKey(cur_key);
-  EXPECT_TRUE(other_cryptographer.is_ready());
+  EXPECT_TRUE(other_cryptographer.CanEncrypt());
   EXPECT_TRUE(encryption_handler()->GetKeystoreDecryptor(
       other_cryptographer, kKeystoreKey, &keystore_decryptor_token));
 
@@ -1734,7 +1734,7 @@
   EXPECT_CALL(*observer(), OnEncryptionComplete());
   encryption_handler()->Init();
   EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
-  EXPECT_TRUE(GetCryptographer()->is_ready());
+  EXPECT_TRUE(GetCryptographer()->CanEncrypt());
   VerifyPassphraseType(PassphraseType::kKeystorePassphrase);
   EXPECT_FALSE(encryption_handler()->IsEncryptEverythingEnabled());
   Mock::VerifyAndClearExpectations(observer());
@@ -1758,7 +1758,7 @@
 
   EXPECT_FALSE(captured_bootstrap_token.empty());
   EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
-  EXPECT_TRUE(GetCryptographer()->is_ready());
+  EXPECT_TRUE(GetCryptographer()->CanEncrypt());
   VerifyPassphraseType(PassphraseType::kCustomPassphrase);
   EXPECT_TRUE(encryption_handler()->IsEncryptEverythingEnabled());
   EXPECT_FALSE(encryption_handler()->custom_passphrase_time().is_null());
@@ -1772,7 +1772,7 @@
   EXPECT_TRUE(GetCryptographer()->CanDecrypt(old_encrypted));
 
   // Check that the cryptographer can decrypt keystore key based encryption.
-  Cryptographer keystore_cryptographer;
+  DirectoryCryptographer keystore_cryptographer;
   KeyParams keystore_key = {KeyDerivationParams::CreateForPbkdf2(),
                             kKeystoreKey};
   keystore_cryptographer.AddKey(keystore_key);
@@ -1783,7 +1783,7 @@
   // Check that the cryptographer is encrypting with the new key.
   KeyParams new_key = {KeyDerivationParams::CreateForScrypt(kScryptSalt),
                        kNewKey};
-  Cryptographer new_cryptographer;
+  DirectoryCryptographer new_cryptographer;
   new_cryptographer.AddKey(new_key);
   sync_pb::EncryptedData new_encrypted;
   new_cryptographer.EncryptString("string", &new_encrypted);
@@ -1805,13 +1805,13 @@
        SetCustomPassAfterMigrationNoKeystoreKey) {
   const char kOldKey[] = "old";
   sync_pb::EncryptedData keystore_decryptor_token;
-  Cryptographer other_cryptographer;
+  DirectoryCryptographer other_cryptographer;
   KeyParams cur_key = {KeyDerivationParams::CreateForPbkdf2(), kOldKey};
   other_cryptographer.AddKey(cur_key);
   KeyParams keystore_key = {KeyDerivationParams::CreateForPbkdf2(),
                             kKeystoreKey};
   other_cryptographer.AddNonDefaultKey(keystore_key);
-  EXPECT_TRUE(other_cryptographer.is_ready());
+  EXPECT_TRUE(other_cryptographer.CanEncrypt());
   EXPECT_TRUE(encryption_handler()->GetKeystoreDecryptor(
       other_cryptographer, kKeystoreKey, &keystore_decryptor_token));
 
@@ -1851,7 +1851,7 @@
               OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN));
   EXPECT_CALL(*observer(), OnEncryptionComplete());
   encryption_handler()->SetDecryptionPassphrase(kOldKey);
-  EXPECT_TRUE(GetCryptographer()->is_ready());
+  EXPECT_TRUE(GetCryptographer()->CanEncrypt());
   EXPECT_FALSE(encryption_handler()->IsEncryptEverythingEnabled());
   Mock::VerifyAndClearExpectations(observer());
 
@@ -1871,7 +1871,7 @@
   EXPECT_CALL(*observer(), OnEncryptionComplete()).Times(2);
   encryption_handler()->SetEncryptionPassphrase(kNewKey);
   EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
-  EXPECT_TRUE(GetCryptographer()->is_ready());
+  EXPECT_TRUE(GetCryptographer()->CanEncrypt());
   VerifyPassphraseType(PassphraseType::kCustomPassphrase);
   EXPECT_TRUE(encryption_handler()->IsEncryptEverythingEnabled());
   EXPECT_FALSE(encryption_handler()->custom_passphrase_time().is_null());
@@ -1886,7 +1886,7 @@
 
   // Check that the cryptographer can still decrypt keystore key based
   // encryption (should have been extracted from the encryption keybag).
-  Cryptographer keystore_cryptographer;
+  DirectoryCryptographer keystore_cryptographer;
   keystore_cryptographer.AddKey(keystore_key);
   sync_pb::EncryptedData keystore_encrypted;
   keystore_cryptographer.EncryptString("string", &keystore_encrypted);
@@ -1895,7 +1895,7 @@
   // Check that the cryptographer is encrypting with the new key.
   KeyParams new_key = {KeyDerivationParams::CreateForScrypt(kScryptSalt),
                        kNewKey};
-  Cryptographer new_cryptographer;
+  DirectoryCryptographer new_cryptographer;
   new_cryptographer.AddKey(new_key);
   sync_pb::EncryptedData new_encrypted;
   new_cryptographer.EncryptString("string", &new_encrypted);
@@ -1917,13 +1917,13 @@
        MigrateOnEncryptEverythingKeystorePassphrase) {
   const char kCurKey[] = "cur";
   sync_pb::EncryptedData keystore_decryptor_token;
-  Cryptographer other_cryptographer;
+  DirectoryCryptographer other_cryptographer;
   KeyParams cur_key = {KeyDerivationParams::CreateForPbkdf2(), kCurKey};
   other_cryptographer.AddKey(cur_key);
   KeyParams keystore_key = {KeyDerivationParams::CreateForPbkdf2(),
                             kKeystoreKey};
   other_cryptographer.AddNonDefaultKey(keystore_key);
-  EXPECT_TRUE(other_cryptographer.is_ready());
+  EXPECT_TRUE(other_cryptographer.CanEncrypt());
   EXPECT_TRUE(encryption_handler()->GetKeystoreDecryptor(
       other_cryptographer, kKeystoreKey, &keystore_decryptor_token));
 
@@ -1978,7 +1978,7 @@
   Mock::VerifyAndClearExpectations(observer());
 
   EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
-  EXPECT_TRUE(GetCryptographer()->is_ready());
+  EXPECT_TRUE(GetCryptographer()->CanEncrypt());
   VerifyPassphraseType(PassphraseType::kFrozenImplicitPassphrase);
   EXPECT_TRUE(encryption_handler()->IsEncryptEverythingEnabled());
   VerifyMigratedNigoriWithTimestamp(
@@ -1992,7 +1992,7 @@
 
   // Check that the cryptographer can still decrypt keystore key based
   // encryption (due to extracting the keystore key from the encryption keybag).
-  Cryptographer keystore_cryptographer;
+  DirectoryCryptographer keystore_cryptographer;
   keystore_cryptographer.AddKey(keystore_key);
   sync_pb::EncryptedData keystore_encrypted;
   keystore_cryptographer.EncryptString("string", &keystore_encrypted);
@@ -2016,15 +2016,15 @@
   GetCryptographer()->AddKey(old_key);
   GetCryptographer()->AddKey(cur_key);
 
-  Cryptographer other_cryptographer;
+  DirectoryCryptographer other_cryptographer;
   other_cryptographer.AddKey(old_key);
-  EXPECT_TRUE(other_cryptographer.is_ready());
+  EXPECT_TRUE(other_cryptographer.CanEncrypt());
 
   EXPECT_CALL(*observer(), OnCryptographerStateChanged(_)).Times(AnyNumber());
   EXPECT_CALL(*observer(), OnEncryptedTypesChanged(_, false));
   EXPECT_CALL(*observer(), OnEncryptionComplete());
   encryption_handler()->Init();
-  EXPECT_TRUE(GetCryptographer()->is_ready());
+  EXPECT_TRUE(GetCryptographer()->CanEncrypt());
   EXPECT_FALSE(encryption_handler()->IsEncryptEverythingEnabled());
 
   EXPECT_CALL(*observer(),
@@ -2048,7 +2048,7 @@
     WriteNode nigori_node(&trans);
     ASSERT_EQ(nigori_node.InitTypeRoot(NIGORI), BaseNode::INIT_OK);
     sync_pb::NigoriSpecifics nigori;
-    Cryptographer other_cryptographer;
+    DirectoryCryptographer other_cryptographer;
     other_cryptographer.AddKey(old_key);
     encryption_handler()->GetKeystoreDecryptor(
         other_cryptographer, kKeystoreKey,
@@ -2065,7 +2065,7 @@
 
   // Verify we're still migrated and have proper encryption state.
   EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
-  EXPECT_TRUE(GetCryptographer()->is_ready());
+  EXPECT_TRUE(GetCryptographer()->CanEncrypt());
   VerifyPassphraseType(PassphraseType::kKeystorePassphrase);
   EXPECT_FALSE(encryption_handler()->IsEncryptEverythingEnabled());
   VerifyMigratedNigori(PassphraseType::kKeystorePassphrase, kCurKey,
@@ -2099,7 +2099,7 @@
   // have rotated the keybag so that it's now encrypted with the newest keystore
   // key (instead of the old gaia key).
   EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
-  EXPECT_TRUE(GetCryptographer()->is_ready());
+  EXPECT_TRUE(GetCryptographer()->CanEncrypt());
   VerifyPassphraseType(PassphraseType::kKeystorePassphrase);
   EXPECT_FALSE(encryption_handler()->IsEncryptEverythingEnabled());
   VerifyMigratedNigori(PassphraseType::kKeystorePassphrase, kKeystoreKey,
@@ -2134,7 +2134,7 @@
   // have rotated the keybag so that it's now encrypted with the newest keystore
   // key (instead of the old gaia key).
   EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
-  EXPECT_TRUE(GetCryptographer()->is_ready());
+  EXPECT_TRUE(GetCryptographer()->CanEncrypt());
   VerifyPassphraseType(PassphraseType::kKeystorePassphrase);
   EXPECT_FALSE(encryption_handler()->IsEncryptEverythingEnabled());
   VerifyMigratedNigori(PassphraseType::kKeystorePassphrase, kKeystoreKey,
@@ -2196,7 +2196,7 @@
   // have rotated the keybag so that it's now encrypted with the newest keystore
   // key (instead of the old gaia key).
   EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
-  EXPECT_TRUE(GetCryptographer()->is_ready());
+  EXPECT_TRUE(GetCryptographer()->CanEncrypt());
   VerifyPassphraseType(PassphraseType::kKeystorePassphrase);
   EXPECT_FALSE(encryption_handler()->IsEncryptEverythingEnabled());
   VerifyMigratedNigori(PassphraseType::kKeystorePassphrase, kKeystoreKey,
@@ -2610,7 +2610,7 @@
   EXPECT_EQ(GetSerializedNigoriKeyForCustomPassphrase(
                 KeyDerivationParams::CreateForPbkdf2(), kCustomPassphrase),
             GetCryptographer()->GetDefaultNigoriKeyData());
-  EXPECT_TRUE(GetCryptographer()->is_ready());
+  EXPECT_TRUE(GetCryptographer()->CanEncrypt());
 }
 
 TEST_F(SyncEncryptionHandlerImplTest,
@@ -2626,7 +2626,7 @@
   EXPECT_EQ(GetSerializedNigoriKeyForCustomPassphrase(
                 KeyDerivationParams::CreateForPbkdf2(), kCustomPassphrase),
             GetCryptographer()->GetDefaultNigoriKeyData());
-  EXPECT_TRUE(GetCryptographer()->is_ready());
+  EXPECT_TRUE(GetCryptographer()->CanEncrypt());
 }
 
 // If we receive data encrypted using a key derivation method that we don't know
@@ -2668,7 +2668,7 @@
       GetSerializedNigoriKeyForCustomPassphrase(
           KeyDerivationParams::CreateForScrypt(kScryptSalt), kCustomPassphrase),
       GetCryptographer()->GetDefaultNigoriKeyData());
-  EXPECT_TRUE(GetCryptographer()->is_ready());
+  EXPECT_TRUE(GetCryptographer()->CanEncrypt());
 }
 
 // If scrypt support is explicitly disabled, we should treat it exactly as an
@@ -2689,7 +2689,7 @@
                   _, KeyDerivationParams::CreateWithUnsupportedMethod(), _));
   encryption_handler()->SetDecryptionPassphrase(kCustomPassphrase);
 
-  EXPECT_FALSE(GetCryptographer()->is_ready());
+  EXPECT_FALSE(GetCryptographer()->CanEncrypt());
 }
 
 TEST_F(SyncEncryptionHandlerImplTest,
diff --git a/components/sync/engine_impl/sync_manager_impl.cc b/components/sync/engine_impl/sync_manager_impl.cc
index b173d2e..be4da4d 100644
--- a/components/sync/engine_impl/sync_manager_impl.cc
+++ b/components/sync/engine_impl/sync_manager_impl.cc
@@ -448,7 +448,7 @@
 
 void SyncManagerImpl::OnCryptographerStateChanged(
     Cryptographer* cryptographer) {
-  allstatus_.SetCryptographerReady(cryptographer->is_ready());
+  allstatus_.SetCryptographerReady(cryptographer->CanEncrypt());
   allstatus_.SetCryptoHasPendingKeys(cryptographer->has_pending_keys());
   allstatus_.SetKeystoreMigrationTime(
       sync_encryption_handler_->GetKeystoreMigrationTime());
diff --git a/components/sync/engine_impl/sync_manager_impl_unittest.cc b/components/sync/engine_impl/sync_manager_impl_unittest.cc
index 4e7efe4e..49b8ec3 100644
--- a/components/sync/engine_impl/sync_manager_impl_unittest.cc
+++ b/components/sync/engine_impl/sync_manager_impl_unittest.cc
@@ -250,7 +250,7 @@
   syncable::Directory* dir();
   SyncEncryptionHandler* encryption_handler();
   PassphraseType GetPassphraseType(BaseTransaction* trans);
-  Cryptographer* GetCryptographer(BaseTransaction* trans);
+  DirectoryCryptographer* GetCryptographer(BaseTransaction* trans);
 
  private:
   base::test::SingleThreadTaskEnvironment task_environment_;
@@ -273,7 +273,7 @@
   return dir()->GetNigoriHandler()->GetPassphraseType(trans->GetWrappedTrans());
 }
 
-Cryptographer* SyncApiTest::GetCryptographer(BaseTransaction* trans) {
+DirectoryCryptographer* SyncApiTest::GetCryptographer(BaseTransaction* trans) {
   return test_user_share_.GetCryptographer(trans->GetWrappedTrans());
 }
 
@@ -1044,7 +1044,7 @@
       sync_manager_.GetEncryptionHandler()->EnableEncryptEverything();
 
     WriteTransaction trans(FROM_HERE, share);
-    Cryptographer* cryptographer = GetCryptographer(&trans);
+    DirectoryCryptographer* cryptographer = GetCryptographer(&trans);
     if (!cryptographer)
       return false;
     if (encryption_status != UNINITIALIZED) {
@@ -1062,7 +1062,7 @@
       EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(nigori_id));
       node.SetNigoriSpecifics(nigori);
     }
-    return cryptographer->is_ready();
+    return cryptographer->CanEncrypt();
   }
 
   int64_t GetIdForDataType(ModelType type) {
@@ -1164,7 +1164,7 @@
     return mock_unrecoverable_error_handler_.invocation_count() > 0;
   }
 
-  Cryptographer* GetCryptographer(const BaseTransaction* trans) {
+  DirectoryCryptographer* GetCryptographer(const BaseTransaction* trans) {
     DCHECK_EQ(user_share_.directory.get(), trans->GetDirectory());
     return encryption_handler_->GetMutableCryptographerForTesting();
   }
@@ -1214,7 +1214,7 @@
     sync_pb::NigoriSpecifics nigori = node.GetNigoriSpecifics();
     EXPECT_TRUE(nigori.has_encryption_keybag());
     Cryptographer* cryptographer = GetCryptographer(&trans);
-    EXPECT_TRUE(cryptographer->is_ready());
+    EXPECT_TRUE(cryptographer->CanEncrypt());
     EXPECT_TRUE(cryptographer->CanDecrypt(nigori.encryption_keybag()));
   }
 }
@@ -1258,7 +1258,7 @@
     sync_pb::NigoriSpecifics nigori = node.GetNigoriSpecifics();
     EXPECT_TRUE(nigori.has_encryption_keybag());
     Cryptographer* cryptographer = GetCryptographer(&trans);
-    EXPECT_TRUE(cryptographer->is_ready());
+    EXPECT_TRUE(cryptographer->CanEncrypt());
     EXPECT_TRUE(cryptographer->CanDecrypt(nigori.encryption_keybag()));
   }
 }
@@ -1357,12 +1357,12 @@
 // and re-encrypt everything.
 // (case 2 in SyncManager::SyncInternal::SetEncryptionPassphrase)
 TEST_F(SyncManagerTest, SetPassphraseWithPassword) {
-  Cryptographer verifier;
+  DirectoryCryptographer verifier;
   EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
   {
     WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
     // Store the default (soon to be old) key.
-    Cryptographer* cryptographer = GetCryptographer(&trans);
+    DirectoryCryptographer* cryptographer = GetCryptographer(&trans);
     std::string bootstrap_token;
     cryptographer->GetBootstrapToken(encryptor_, &bootstrap_token);
     verifier.Bootstrap(encryptor_, bootstrap_token);
@@ -1385,8 +1385,8 @@
   EXPECT_FALSE(IsEncryptEverythingEnabledForTest());
   {
     ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
-    Cryptographer* cryptographer = GetCryptographer(&trans);
-    EXPECT_TRUE(cryptographer->is_ready());
+    DirectoryCryptographer* cryptographer = GetCryptographer(&trans);
+    EXPECT_TRUE(cryptographer->CanEncrypt());
     // Verify the default key has changed.
     sync_pb::EncryptedData encrypted;
     cryptographer->GetKeys(&encrypted);
@@ -1407,10 +1407,10 @@
 // (case 7 in SyncManager::SyncInternal::SetDecryptionPassphrase)
 TEST_F(SyncManagerTest, SupplyPendingGAIAPass) {
   EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
-  Cryptographer other_cryptographer;
+  DirectoryCryptographer other_cryptographer;
   {
     WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
-    Cryptographer* cryptographer = GetCryptographer(&trans);
+    DirectoryCryptographer* cryptographer = GetCryptographer(&trans);
     std::string bootstrap_token;
     cryptographer->GetBootstrapToken(encryptor_, &bootstrap_token);
     other_cryptographer.Bootstrap(encryptor_, bootstrap_token);
@@ -1435,8 +1435,8 @@
   EXPECT_FALSE(IsEncryptEverythingEnabledForTest());
   {
     ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
-    Cryptographer* cryptographer = GetCryptographer(&trans);
-    EXPECT_TRUE(cryptographer->is_ready());
+    DirectoryCryptographer* cryptographer = GetCryptographer(&trans);
+    EXPECT_TRUE(cryptographer->CanEncrypt());
     // Verify we're encrypting with the new key.
     sync_pb::EncryptedData encrypted;
     cryptographer->GetKeys(&encrypted);
@@ -1450,10 +1450,10 @@
 // (case 9 in SyncManager::SyncInternal::SetDecryptionPassphrase)
 TEST_F(SyncManagerTest, SupplyPendingExplicitPass) {
   EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
-  Cryptographer other_cryptographer;
+  DirectoryCryptographer other_cryptographer;
   {
     WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
-    Cryptographer* cryptographer = GetCryptographer(&trans);
+    DirectoryCryptographer* cryptographer = GetCryptographer(&trans);
     std::string bootstrap_token;
     cryptographer->GetBootstrapToken(encryptor_, &bootstrap_token);
     other_cryptographer.Bootstrap(encryptor_, bootstrap_token);
@@ -1485,8 +1485,8 @@
   EXPECT_FALSE(IsEncryptEverythingEnabledForTest());
   {
     ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
-    Cryptographer* cryptographer = GetCryptographer(&trans);
-    EXPECT_TRUE(cryptographer->is_ready());
+    DirectoryCryptographer* cryptographer = GetCryptographer(&trans);
+    EXPECT_TRUE(cryptographer->CanEncrypt());
     // Verify we're encrypting with the new key.
     sync_pb::EncryptedData encrypted;
     cryptographer->GetKeys(&encrypted);
@@ -1699,8 +1699,8 @@
     const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics();
     EXPECT_TRUE(specifics.has_encrypted());
     EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName());
-    Cryptographer* cryptographer = GetCryptographer(&trans);
-    EXPECT_TRUE(cryptographer->is_ready());
+    DirectoryCryptographer* cryptographer = GetCryptographer(&trans);
+    EXPECT_TRUE(cryptographer->CanEncrypt());
     EXPECT_TRUE(
         cryptographer->CanDecryptUsingDefaultKey(specifics.encrypted()));
   }
@@ -1721,8 +1721,8 @@
     const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics();
     EXPECT_TRUE(specifics.has_encrypted());
     EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName());
-    Cryptographer* cryptographer = GetCryptographer(&trans);
-    EXPECT_TRUE(cryptographer->is_ready());
+    DirectoryCryptographer* cryptographer = GetCryptographer(&trans);
+    EXPECT_TRUE(cryptographer->CanEncrypt());
     EXPECT_TRUE(
         cryptographer->CanDecryptUsingDefaultKey(specifics.encrypted()));
   }
@@ -1746,7 +1746,7 @@
     const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics();
     EXPECT_TRUE(specifics.has_encrypted());
     EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName());
-    Cryptographer* cryptographer = GetCryptographer(&trans);
+    DirectoryCryptographer* cryptographer = GetCryptographer(&trans);
     EXPECT_TRUE(
         cryptographer->CanDecryptUsingDefaultKey(specifics.encrypted()));
   }
@@ -1764,7 +1764,7 @@
     EXPECT_TRUE(specifics.has_encrypted());
     EXPECT_FALSE(node_entry->GetIsUnsynced());
     EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName());
-    Cryptographer* cryptographer = GetCryptographer(&trans);
+    DirectoryCryptographer* cryptographer = GetCryptographer(&trans);
     EXPECT_TRUE(
         cryptographer->CanDecryptUsingDefaultKey(specifics.encrypted()));
   }
@@ -1784,7 +1784,7 @@
     EXPECT_TRUE(specifics.has_encrypted());
     EXPECT_TRUE(node_entry->GetIsUnsynced());
     EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName());
-    Cryptographer* cryptographer = GetCryptographer(&trans);
+    DirectoryCryptographer* cryptographer = GetCryptographer(&trans);
     EXPECT_TRUE(
         cryptographer->CanDecryptUsingDefaultKey(specifics.encrypted()));
   }
@@ -1798,7 +1798,7 @@
   sync_pb::EntitySpecifics entity_specifics;
   {
     ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
-    Cryptographer* cryptographer = GetCryptographer(&trans);
+    DirectoryCryptographer* cryptographer = GetCryptographer(&trans);
     sync_pb::PasswordSpecificsData data;
     data.set_password_value("secret");
     cryptographer->Encrypt(
@@ -1829,7 +1829,7 @@
   sync_pb::EntitySpecifics entity_specifics;
   {
     ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
-    Cryptographer* cryptographer = GetCryptographer(&trans);
+    DirectoryCryptographer* cryptographer = GetCryptographer(&trans);
     sync_pb::PasswordSpecificsData data;
     data.set_password_value("secret");
     cryptographer->Encrypt(
@@ -1857,7 +1857,7 @@
     WriteNode node(&trans);
     EXPECT_EQ(BaseNode::INIT_OK,
               node.InitByClientTagLookup(PASSWORDS, client_tag));
-    Cryptographer* cryptographer = GetCryptographer(&trans);
+    DirectoryCryptographer* cryptographer = GetCryptographer(&trans);
     sync_pb::PasswordSpecificsData data;
     data.set_password_value("secret2");
     cryptographer->Encrypt(
@@ -1875,7 +1875,7 @@
   sync_pb::EntitySpecifics entity_specifics;
   {
     ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
-    Cryptographer* cryptographer = GetCryptographer(&trans);
+    DirectoryCryptographer* cryptographer = GetCryptographer(&trans);
     sync_pb::PasswordSpecificsData data;
     data.set_password_value(kPasswordValue);
     entity_specifics.mutable_password()
@@ -1898,8 +1898,8 @@
   SetCustomPassphraseAndCheck("new_passphrase");
   {
     ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
-    Cryptographer* cryptographer = GetCryptographer(&trans);
-    EXPECT_TRUE(cryptographer->is_ready());
+    DirectoryCryptographer* cryptographer = GetCryptographer(&trans);
+    EXPECT_TRUE(cryptographer->CanEncrypt());
     ReadNode password_node(&trans);
     EXPECT_EQ(BaseNode::INIT_OK,
               password_node.InitByClientTagLookup(PASSWORDS, kClientTag));
@@ -1930,8 +1930,8 @@
   }
   {
     ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
-    Cryptographer* cryptographer = GetCryptographer(&trans);
-    EXPECT_TRUE(cryptographer->is_ready());
+    DirectoryCryptographer* cryptographer = GetCryptographer(&trans);
+    EXPECT_TRUE(cryptographer->CanEncrypt());
     ReadNode password_node(&trans);
     EXPECT_EQ(BaseNode::INIT_OK,
               password_node.InitByClientTagLookup(PASSWORDS, tag));
@@ -1951,7 +1951,7 @@
   sync_pb::EntitySpecifics entity_specifics;
   {
     ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
-    Cryptographer* cryptographer = GetCryptographer(&trans);
+    DirectoryCryptographer* cryptographer = GetCryptographer(&trans);
     sync_pb::PasswordSpecificsData data;
     data.set_password_value("secret");
     cryptographer->Encrypt(
@@ -1982,7 +1982,7 @@
   sync_pb::EntitySpecifics entity_specifics;
   {
     ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
-    Cryptographer* cryptographer = GetCryptographer(&trans);
+    DirectoryCryptographer* cryptographer = GetCryptographer(&trans);
     sync_pb::PasswordSpecificsData data;
     data.set_password_value("secret");
     data.set_signon_realm(kUrl);
@@ -2004,8 +2004,8 @@
   // Check that unencrypted metadata field was set.
   {
     ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
-    Cryptographer* cryptographer = GetCryptographer(&trans);
-    EXPECT_TRUE(cryptographer->is_ready());
+    DirectoryCryptographer* cryptographer = GetCryptographer(&trans);
+    EXPECT_TRUE(cryptographer->CanEncrypt());
     ReadNode password_node(&trans);
     EXPECT_EQ(BaseNode::INIT_OK,
               password_node.InitByClientTagLookup(PASSWORDS, kClientTag));
@@ -2028,7 +2028,7 @@
   sync_pb::EntitySpecifics entity_specifics;
   {
     ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
-    Cryptographer* cryptographer = GetCryptographer(&trans);
+    DirectoryCryptographer* cryptographer = GetCryptographer(&trans);
     sync_pb::PasswordSpecificsData data;
     data.set_password_value("secret");
     data.set_signon_realm(kUrl);
@@ -2063,7 +2063,7 @@
     // Create a synced bookmark with undecryptable data.
     ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
 
-    Cryptographer other_cryptographer;
+    DirectoryCryptographer other_cryptographer;
     KeyParams fake_params = {KeyDerivationParams::CreateForPbkdf2(),
                              "fake_key"};
     other_cryptographer.AddKey(fake_params);
@@ -2106,7 +2106,7 @@
     // Create a synced bookmark with undecryptable data.
     ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
 
-    Cryptographer other_cryptographer;
+    DirectoryCryptographer other_cryptographer;
     KeyParams fake_params = {KeyDerivationParams::CreateForPbkdf2(),
                              "fake_key"};
     other_cryptographer.AddKey(fake_params);
@@ -2378,7 +2378,7 @@
   EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
   {
     ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
-    Cryptographer* crypto = GetCryptographer(&trans);
+    DirectoryCryptographer* crypto = GetCryptographer(&trans);
     sync_pb::EntitySpecifics bm_specifics;
     bm_specifics.mutable_bookmark()->set_title("title");
     bm_specifics.mutable_bookmark()->set_url("url");
@@ -2487,8 +2487,8 @@
     EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(GetIdForDataType(NIGORI)));
     sync_pb::NigoriSpecifics nigori = node.GetNigoriSpecifics();
     EXPECT_TRUE(nigori.has_encryption_keybag());
-    Cryptographer* cryptographer = GetCryptographer(&trans);
-    EXPECT_TRUE(cryptographer->is_ready());
+    DirectoryCryptographer* cryptographer = GetCryptographer(&trans);
+    EXPECT_TRUE(cryptographer->CanEncrypt());
     EXPECT_TRUE(cryptographer->CanDecrypt(nigori.encryption_keybag()));
   }
 }
diff --git a/components/sync/engine_impl/syncer_unittest.cc b/components/sync/engine_impl/syncer_unittest.cc
index bc688cf..9129af5 100644
--- a/components/sync/engine_impl/syncer_unittest.cc
+++ b/components/sync/engine_impl/syncer_unittest.cc
@@ -39,10 +39,10 @@
 #include "components/sync/engine_impl/net/server_connection_manager.h"
 #include "components/sync/engine_impl/sync_scheduler_impl.h"
 #include "components/sync/engine_impl/syncer_proto_util.h"
-#include "components/sync/nigori/cryptographer.h"
 #include "components/sync/protocol/bookmark_specifics.pb.h"
 #include "components/sync/protocol/nigori_specifics.pb.h"
 #include "components/sync/protocol/preference_specifics.pb.h"
+#include "components/sync/syncable/directory_cryptographer.h"
 #include "components/sync/syncable/mutable_entry.h"
 #include "components/sync/syncable/nigori_util.h"
 #include "components/sync/syncable/syncable_delete_journal.h"
@@ -505,7 +505,7 @@
     mock_server_->ExpectGetUpdatesRequestTypes(enabled_datatypes_);
   }
 
-  Cryptographer* GetCryptographer(syncable::BaseTransaction* trans) {
+  DirectoryCryptographer* GetCryptographer(syncable::BaseTransaction* trans) {
     return test_user_share_.GetCryptographer(trans);
   }
 
@@ -659,7 +659,7 @@
     // Mark bookmarks as encrypted and set the cryptographer to have pending
     // keys.
     syncable::WriteTransaction wtrans(FROM_HERE, UNITTEST, directory());
-    Cryptographer other_cryptographer;
+    DirectoryCryptographer other_cryptographer;
     other_cryptographer.AddKey(other_params);
     sync_pb::EntitySpecifics specifics;
     sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori();
@@ -1014,7 +1014,7 @@
 
 TEST_F(SyncerTest, EncryptionAwareConflicts) {
   KeyParams key_params = {KeyDerivationParams::CreateForPbkdf2(), "foobar"};
-  Cryptographer other_cryptographer;
+  DirectoryCryptographer other_cryptographer;
   other_cryptographer.AddKey(key_params);
   sync_pb::EntitySpecifics bookmark, encrypted_bookmark, modified_bookmark;
   bookmark.mutable_bookmark()->set_title("title");
diff --git a/components/sync/nigori/DEPS b/components/sync/nigori/DEPS
index c2ee8b4..999730c 100644
--- a/components/sync/nigori/DEPS
+++ b/components/sync/nigori/DEPS
@@ -4,5 +4,8 @@
   "+components/sync/model",
   "+components/sync/model_impl",
   "+components/sync/protocol",
+  # TODO(crbug.com/967417): Remove once the USS code doesn't use the legacy
+  # cryptographer.
+  "+components/sync/syncable",
   "+crypto",
 ]
diff --git a/components/sync/nigori/cryptographer.cc b/components/sync/nigori/cryptographer.cc
index 15f6a32..af56260 100644
--- a/components/sync/nigori/cryptographer.cc
+++ b/components/sync/nigori/cryptographer.cc
@@ -1,367 +1,40 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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.
 
 #include "components/sync/nigori/cryptographer.h"
 
-#include <stddef.h>
-
-#include <algorithm>
-#include <utility>
-
-#include "base/base64.h"
 #include "base/logging.h"
-#include "components/sync/base/encryptor.h"
-#include "components/sync/protocol/nigori_specifics.pb.h"
 
 namespace syncer {
 
-KeyParams::KeyParams(KeyDerivationParams derivation_params,
-                     const std::string& password)
-    : derivation_params(derivation_params), password(password) {}
+Cryptographer::Cryptographer() = default;
 
-KeyParams::KeyParams(const KeyParams& other) = default;
-KeyParams::KeyParams(KeyParams&& other) = default;
-KeyParams::~KeyParams() = default;
-
-CryptographerDataWithPendingKeys::CryptographerDataWithPendingKeys() = default;
-CryptographerDataWithPendingKeys::CryptographerDataWithPendingKeys(
-    CryptographerDataWithPendingKeys&& other) = default;
-CryptographerDataWithPendingKeys::~CryptographerDataWithPendingKeys() = default;
-
-// static
-Cryptographer Cryptographer::CreateFromCryptographerDataWithPendingKeys(
-    const CryptographerDataWithPendingKeys& serialized_state) {
-  std::unique_ptr<sync_pb::EncryptedData> pending_keys;
-  if (serialized_state.pending_keys.has_value()) {
-    pending_keys = std::make_unique<sync_pb::EncryptedData>(
-        *serialized_state.pending_keys);
-  }
-  return Cryptographer(NigoriKeyBag::CreateFromProto(
-                           serialized_state.cryptographer_data.key_bag()),
-                       serialized_state.cryptographer_data.default_key_name(),
-                       std::move(pending_keys));
-}
-
-Cryptographer::Cryptographer() : key_bag_(NigoriKeyBag::CreateEmpty()) {}
-
-Cryptographer::Cryptographer(const Cryptographer& other)
-    : key_bag_(other.key_bag_.Clone()),
-      default_nigori_name_(other.default_nigori_name_) {
-  if (other.pending_keys_) {
-    pending_keys_ =
-        std::make_unique<sync_pb::EncryptedData>(*(other.pending_keys_));
-  }
-}
-
-Cryptographer::~Cryptographer() {}
-
-void Cryptographer::CopyFrom(const Cryptographer& other) {
-  key_bag_.CopyFrom(other.key_bag_);
-  default_nigori_name_ = other.default_nigori_name_;
-  if (other.pending_keys_) {
-    pending_keys_ =
-        std::make_unique<sync_pb::EncryptedData>(*other.pending_keys_);
-  }
-}
-
-CryptographerDataWithPendingKeys
-Cryptographer::ToCryptographerDataWithPendingKeys() const {
-  CryptographerDataWithPendingKeys output;
-  *output.cryptographer_data.mutable_key_bag() = key_bag_.ToProto();
-  output.cryptographer_data.set_default_key_name(default_nigori_name_);
-  if (pending_keys_) {
-    output.pending_keys = *pending_keys_;
-  }
-  return output;
-}
-
-void Cryptographer::Bootstrap(const Encryptor& encryptor,
-                              const std::string& restored_bootstrap_token) {
-  if (is_initialized()) {
-    NOTREACHED();
-    return;
-  }
-
-  std::string serialized_nigori_key =
-      UnpackBootstrapToken(encryptor, restored_bootstrap_token);
-  if (serialized_nigori_key.empty())
-    return;
-  ImportNigoriKey(serialized_nigori_key);
-}
-
-bool Cryptographer::CanDecrypt(const sync_pb::EncryptedData& data) const {
-  return key_bag_.HasKey(data.key_name());
-}
-
-bool Cryptographer::CanDecryptUsingDefaultKey(
-    const sync_pb::EncryptedData& data) const {
-  return !default_nigori_name_.empty() &&
-         data.key_name() == default_nigori_name_;
-}
+Cryptographer::~Cryptographer() = default;
 
 bool Cryptographer::Encrypt(const ::google::protobuf::MessageLite& message,
                             sync_pb::EncryptedData* encrypted) const {
   DCHECK(encrypted);
-  if (default_nigori_name_.empty()) {
-    LOG(ERROR) << "Cryptographer not ready, failed to encrypt.";
-    return false;
-  }
 
   std::string serialized;
   if (!message.SerializeToString(&serialized)) {
-    LOG(ERROR) << "Message is invalid/missing a required field.";
+    DLOG(ERROR) << "Message is invalid/missing a required field.";
     return false;
   }
 
   return EncryptString(serialized, encrypted);
 }
 
-bool Cryptographer::EncryptString(const std::string& serialized,
-                                  sync_pb::EncryptedData* encrypted) const {
-  if (CanDecryptUsingDefaultKey(*encrypted)) {
-    std::string original_serialized;
-    if (DecryptToString(*encrypted, &original_serialized) &&
-        original_serialized == serialized) {
-      DVLOG(2) << "Re-encryption unnecessary, encrypted data already matches.";
-      return true;
-    }
-  }
-
-  if (!key_bag_.HasKey(default_nigori_name_)) {
-    LOG(ERROR) << "Corrupt default key.";
-    return false;
-  }
-
-  return key_bag_.EncryptWithKey(default_nigori_name_, serialized, encrypted);
-}
-
 bool Cryptographer::Decrypt(const sync_pb::EncryptedData& encrypted,
                             ::google::protobuf::MessageLite* message) const {
   DCHECK(message);
+
   std::string plaintext;
   if (!DecryptToString(encrypted, &plaintext)) {
     return false;
   }
+
   return message->ParseFromString(plaintext);
 }
 
-bool Cryptographer::DecryptToString(const sync_pb::EncryptedData& encrypted,
-                                    std::string* decrypted) const {
-  return key_bag_.Decrypt(encrypted, decrypted);
-}
-
-bool Cryptographer::GetKeys(sync_pb::EncryptedData* encrypted) const {
-  DCHECK(encrypted);
-  DCHECK_NE(size_t(0), key_bag_.size());
-
-  // Create a bag of all the Nigori parameters we know about.
-  sync_pb::NigoriKeyBag bag = key_bag_.ToProto();
-
-  // Encrypt the bag with the default Nigori.
-  return Encrypt(bag, encrypted);
-}
-
-bool Cryptographer::AddKey(const KeyParams& params) {
-  return AddKeyImpl(
-      Nigori::CreateByDerivation(params.derivation_params, params.password),
-      /*set_as_default=*/true);
-}
-
-bool Cryptographer::AddNonDefaultKey(const KeyParams& params) {
-  DCHECK(is_initialized());
-  return AddKeyImpl(
-      Nigori::CreateByDerivation(params.derivation_params, params.password),
-      /*set_as_default=*/false);
-}
-
-bool Cryptographer::AddKeyFromBootstrapToken(
-    const Encryptor& encryptor,
-    const std::string& restored_bootstrap_token) {
-  // Create the new Nigori and make it the default encryptor.
-  std::string serialized_nigori_key =
-      UnpackBootstrapToken(encryptor, restored_bootstrap_token);
-  return ImportNigoriKey(serialized_nigori_key);
-}
-
-bool Cryptographer::AddKeyImpl(std::unique_ptr<Nigori> nigori,
-                               bool set_as_default) {
-  DCHECK(nigori);
-  std::string key_name = key_bag_.AddKey(std::move(nigori));
-  if (key_name.empty()) {
-    NOTREACHED();
-    return false;
-  }
-
-  // Check if the key we just added can decrypt the pending keys and add them
-  // too if so.
-  if (pending_keys_.get() && CanDecrypt(*pending_keys_)) {
-    sync_pb::NigoriKeyBag pending_bag;
-    Decrypt(*pending_keys_, &pending_bag);
-    InstallKeyBag(pending_bag);
-    SetDefaultKey(pending_keys_->key_name());
-    pending_keys_.reset();
-  }
-
-  // The just-added key takes priority over the pending keys as default.
-  if (set_as_default)
-    SetDefaultKey(key_name);
-  return true;
-}
-
-void Cryptographer::InstallKeys(const sync_pb::EncryptedData& encrypted) {
-  DCHECK(CanDecrypt(encrypted));
-
-  sync_pb::NigoriKeyBag bag;
-  if (!Decrypt(encrypted, &bag))
-    return;
-  InstallKeyBag(bag);
-}
-
-void Cryptographer::SetDefaultKey(const std::string& key_name) {
-  DCHECK(key_bag_.HasKey(key_name));
-  default_nigori_name_ = key_name;
-}
-
-bool Cryptographer::is_initialized() const {
-  return !default_nigori_name_.empty();
-}
-
-void Cryptographer::SetPendingKeys(const sync_pb::EncryptedData& encrypted) {
-  DCHECK(!CanDecrypt(encrypted));
-  DCHECK(!encrypted.blob().empty());
-  pending_keys_ = std::make_unique<sync_pb::EncryptedData>(encrypted);
-}
-
-const sync_pb::EncryptedData& Cryptographer::GetPendingKeys() const {
-  DCHECK(has_pending_keys());
-  return *(pending_keys_.get());
-}
-
-bool Cryptographer::DecryptPendingKeys(const KeyParams& params) {
-  DCHECK_NE(KeyDerivationMethod::UNSUPPORTED,
-            params.derivation_params.method());
-
-  std::unique_ptr<Nigori> nigori =
-      Nigori::CreateByDerivation(params.derivation_params, params.password);
-
-  std::string plaintext;
-  if (!nigori->Decrypt(pending_keys_->blob(), &plaintext))
-    return false;
-
-  sync_pb::NigoriKeyBag bag;
-  if (!bag.ParseFromString(plaintext)) {
-    NOTREACHED();
-    return false;
-  }
-  InstallKeyBag(bag);
-  const std::string& new_default_key_name = pending_keys_->key_name();
-  SetDefaultKey(new_default_key_name);
-  pending_keys_.reset();
-  return true;
-}
-
-bool Cryptographer::GetBootstrapToken(const Encryptor& encryptor,
-                                      std::string* token) const {
-  DCHECK(token);
-  std::string unencrypted_token = GetDefaultNigoriKeyData();
-  if (unencrypted_token.empty())
-    return false;
-
-  std::string encrypted_token;
-  if (!encryptor.EncryptString(unencrypted_token, &encrypted_token)) {
-    return false;
-  }
-
-  base::Base64Encode(encrypted_token, token);
-
-  return true;
-}
-
-std::string Cryptographer::UnpackBootstrapToken(
-    const Encryptor& encryptor,
-    const std::string& token) const {
-  if (token.empty())
-    return std::string();
-
-  std::string encrypted_data;
-  if (!base::Base64Decode(token, &encrypted_data)) {
-    DLOG(WARNING) << "Could not decode token.";
-    return std::string();
-  }
-
-  std::string unencrypted_token;
-  if (!encryptor.DecryptString(encrypted_data, &unencrypted_token)) {
-    DLOG(WARNING) << "Decryption of bootstrap token failed.";
-    return std::string();
-  }
-  return unencrypted_token;
-}
-
-void Cryptographer::InstallKeyBag(const sync_pb::NigoriKeyBag& bag) {
-  key_bag_.AddAllUnknownKeysFrom(NigoriKeyBag::CreateFromProto(bag));
-}
-
-bool Cryptographer::KeybagIsStale(
-    const sync_pb::EncryptedData& encrypted_bag) const {
-  if (!is_ready())
-    return false;
-  if (encrypted_bag.blob().empty())
-    return true;
-  if (!CanDecrypt(encrypted_bag))
-    return false;
-  if (!CanDecryptUsingDefaultKey(encrypted_bag))
-    return true;
-  sync_pb::NigoriKeyBag bag;
-  if (!Decrypt(encrypted_bag, &bag)) {
-    LOG(ERROR) << "Failed to decrypt keybag for stale check. "
-               << "Assuming keybag is corrupted.";
-    return true;
-  }
-  if (static_cast<size_t>(bag.key_size()) < key_bag_.size())
-    return true;
-  return false;
-}
-
-std::string Cryptographer::GetDefaultNigoriKeyName() const {
-  return default_nigori_name_;
-}
-
-std::string Cryptographer::GetDefaultNigoriKeyData() const {
-  if (!is_initialized())
-    return std::string();
-  sync_pb::NigoriKey key = key_bag_.ExportKey(default_nigori_name_);
-  key.clear_name();
-  return key.SerializeAsString();
-}
-
-bool Cryptographer::ImportNigoriKey(const std::string& serialized_nigori_key) {
-  if (serialized_nigori_key.empty())
-    return false;
-
-  sync_pb::NigoriKey key;
-  if (!key.ParseFromString(serialized_nigori_key))
-    return false;
-
-  std::unique_ptr<Nigori> nigori = Nigori::CreateByImport(
-      key.user_key(), key.encryption_key(), key.mac_key());
-
-  if (!nigori) {
-    DLOG(ERROR) << "Ignoring invalid Nigori when importing";
-    return false;
-  }
-
-  if (!AddKeyImpl(std::move(nigori), true))
-    return false;
-  return true;
-}
-
-Cryptographer::Cryptographer(
-    NigoriKeyBag key_bag,
-    const std::string& default_nigori_name,
-    std::unique_ptr<sync_pb::EncryptedData> pending_keys)
-    : key_bag_(std::move(key_bag)),
-      default_nigori_name_(std::move(default_nigori_name)),
-      pending_keys_(std::move(pending_keys)) {}
-
 }  // namespace syncer
diff --git a/components/sync/nigori/cryptographer.h b/components/sync/nigori/cryptographer.h
index 42e3491..7781cb9 100644
--- a/components/sync/nigori/cryptographer.h
+++ b/components/sync/nigori/cryptographer.h
@@ -1,244 +1,65 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
+// 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.
 
 #ifndef COMPONENTS_SYNC_NIGORI_CRYPTOGRAPHER_H_
 #define COMPONENTS_SYNC_NIGORI_CRYPTOGRAPHER_H_
 
-#include <map>
 #include <memory>
 #include <string>
 
 #include "base/macros.h"
-#include "base/optional.h"
-#include "components/sync/base/passphrase_enums.h"
-#include "components/sync/nigori/nigori.h"
-#include "components/sync/nigori/nigori_key_bag.h"
 #include "components/sync/protocol/encryption.pb.h"
-#include "components/sync/protocol/nigori_local_data.pb.h"
-
-namespace sync_pb {
-class NigoriKeyBag;
-}  // namespace sync_pb
 
 namespace syncer {
 
-class Encryptor;
-
-// The parameters used to initialize a Nigori instance.
-// TODO(davidovic): Stop relying on KeyParams and inline it, because it's now
-// just a pair of KeyDerivationParams and passphrase.
-struct KeyParams {
-  KeyParams(KeyDerivationParams derivation_params, const std::string& password);
-  KeyParams(const KeyParams& other);
-  KeyParams(KeyParams&& other);
-  ~KeyParams();
-
-  KeyDerivationParams derivation_params;
-  std::string password;
-};
-
-struct CryptographerDataWithPendingKeys {
-  CryptographerDataWithPendingKeys();
-  CryptographerDataWithPendingKeys(CryptographerDataWithPendingKeys&& other);
-  ~CryptographerDataWithPendingKeys();
-
-  sync_pb::CryptographerData cryptographer_data;
-  base::Optional<sync_pb::EncryptedData> pending_keys;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(CryptographerDataWithPendingKeys);
-};
-
-// This class manages the Nigori objects used to encrypt and decrypt sensitive
-// sync data (eg. passwords). Each Nigori object knows how to handle data
-// protected with a particular passphrase.
-//
-// Whenever an update to the Nigori sync node is received from the server,
-// SetPendingKeys should be called with the encrypted contents of that node.
-// Most likely, an updated Nigori node means that a new passphrase has been set
-// and that future node updates won't be decryptable. To remedy this, the user
-// should be prompted for the new passphrase and DecryptPendingKeys be called.
-//
-// Whenever a update to an encrypted node is received from the server,
-// CanDecrypt should be used to verify whether the Cryptographer can decrypt
-// that node. If it cannot, then the application of that update should be
-// delayed until after it can be decrypted.
+// Interface used to encrypt and decrypt sensitive sync data (eg. passwords).
 class Cryptographer {
  public:
-  // Deserialization.
-  static Cryptographer CreateFromCryptographerDataWithPendingKeys(
-      const CryptographerDataWithPendingKeys& serialized_state);
-
   Cryptographer();
-  Cryptographer(const Cryptographer& other);
-  ~Cryptographer();
+  virtual ~Cryptographer();
 
-  void CopyFrom(const Cryptographer& other);
+  virtual std::unique_ptr<Cryptographer> Clone() const = 0;
 
-  // Serialization.
-  CryptographerDataWithPendingKeys ToCryptographerDataWithPendingKeys() const;
+  // Returns whether this cryptographer is ready to encrypt data, using
+  // EncryptString(). This usually means that a default encryption key is
+  // available and there are no pending keys.
+  virtual bool CanEncrypt() const = 0;
 
-  // |restored_bootstrap_token| can be provided via this method to bootstrap
-  // Cryptographer instance into the ready state (is_ready will be true).
-  // It must be a string that was previously built by the
-  // GetSerializedBootstrapToken function.  It is possible that the token is no
-  // longer valid (due to server key change), in which case the normal
-  // decryption code paths will fail and the user will need to provide a new
-  // passphrase.
-  // It is an error to call this if is_ready() == true, though it is fair to
-  // never call Bootstrap at all.
-  void Bootstrap(const Encryptor& encryptor,
-                 const std::string& restored_bootstrap_token);
+  // Returns whether this cryptographer can decrypt |encrypted| using any of
+  // the known keys.
+  virtual bool CanDecrypt(const sync_pb::EncryptedData& encrypted) const = 0;
 
-  // Returns whether we can decrypt |encrypted| using the keys we currently know
-  // about.
-  bool CanDecrypt(const sync_pb::EncryptedData& encrypted) const;
+  // Returns a name that uniquely identifies the key used for encryption.
+  virtual std::string GetDefaultEncryptionKeyName() const = 0;
 
-  // Returns whether |encrypted| can be decrypted using the default encryption
-  // key.
-  bool CanDecryptUsingDefaultKey(const sync_pb::EncryptedData& encrypted) const;
+  // Encrypted |decrypted| into |*encrypted|. |encrypted| must not be null.
+  // Returns false in case of error, which most notably includes the case
+  // where CanEncrypt() returns false.
+  virtual bool EncryptString(const std::string& decrypted,
+                             sync_pb::EncryptedData* encrypted) const = 0;
 
-  // Encrypts |message| into |encrypted|. Does not overwrite |encrypted| if
-  // |message| already matches the decrypted data within |encrypted| and
-  // |encrypted| was encrypted with the current default key. This avoids
-  // unnecessarily modifying |encrypted| if the change had no practical effect.
-  // Returns true unless encryption fails or |message| isn't valid (e.g. a
-  // required field isn't set).
+  // Decrypts |encrypted| as a plaintext decrypted data into |*decrypted|.
+  // |decrypted| must not be null. Returns false in case of error, which most
+  // notably includes the case where CanDecrypt() would have returned false.
+  virtual bool DecryptToString(const sync_pb::EncryptedData& encrypted,
+                               std::string* decrypted) const = 0;
+
+  // Convenience function to deal with protocol buffers. It uses EncryptString()
+  // after serialization.
   bool Encrypt(const ::google::protobuf::MessageLite& message,
                sync_pb::EncryptedData* encrypted) const;
 
-  // Encrypted |serialized| into |encrypted|. Does not overwrite |encrypted| if
-  // |message| already matches the decrypted data within |encrypted| and
-  // |encrypted| was encrypted with the current default key. This avoids
-  // unnecessarily modifying |encrypted| if the change had no practical effect.
-  // Returns true unless encryption fails or |message| isn't valid (e.g. a
-  // required field isn't set).
-  bool EncryptString(const std::string& serialized,
-                     sync_pb::EncryptedData* encrypted) const;
-
-  // Decrypts |encrypted| into |message|. Returns true unless decryption fails,
-  // or |message| fails to parse the decrypted data.
+  // Convenience function to deal with protocol buffers. After decryption, it
+  // parses the decrypted content into a protocol buffer.
   bool Decrypt(const sync_pb::EncryptedData& encrypted,
                ::google::protobuf::MessageLite* message) const;
 
-  // Decrypts |encrypted| as a plaintext decrypted data in |decrypted|. If
-  // decryption fails, returns false otherwise returns true.
-  bool DecryptToString(const sync_pb::EncryptedData& encrypted,
-                       std::string* decrypted) const;
-
-  // Encrypts the set of currently known keys into |encrypted|. Returns true if
-  // successful.
-  bool GetKeys(sync_pb::EncryptedData* encrypted) const;
-
-  // Creates a new Nigori instance using |params|. If successful, |params| will
-  // become the default encryption key and be used for all future calls to
-  // Encrypt.
-  // Will decrypt the pending keys and install them if possible (pending key
-  // will not overwrite default).
-  bool AddKey(const KeyParams& params);
-
-  // Same as AddKey(..), but builds the new Nigori from a previously persisted
-  // bootstrap token. This can be useful when consuming a bootstrap token
-  // with a cryptographer that has already been initialized.
-  // Updates the default key.
-  // Will decrypt the pending keys and install them if possible (pending key
-  // will not overwrite default).
-  bool AddKeyFromBootstrapToken(const Encryptor& encryptor,
-                                const std::string& restored_bootstrap_token);
-
-  // Creates a new Nigori instance using |params|. If successful, |params|
-  // will be added to the nigori keybag, but will not be the default encryption
-  // key (default_nigori_ will remain the same).
-  // Prereq: is_initialized() must be true.
-  // Will decrypt the pending keys and install them if possible (pending key
-  // will become the new default).
-  bool AddNonDefaultKey(const KeyParams& params);
-
-  // Decrypts |encrypted| and uses its contents to initialize Nigori instances.
-  // Returns true unless decryption of |encrypted| fails. The caller is
-  // responsible for checking that CanDecrypt(encrypted) == true.
-  // Does not modify the default key.
-  void InstallKeys(const sync_pb::EncryptedData& encrypted);
-
-  // Makes a local copy of |encrypted| to later be decrypted by
-  // DecryptPendingKeys. This should only be used if CanDecrypt(encrypted) ==
-  // false.
-  void SetPendingKeys(const sync_pb::EncryptedData& encrypted);
-
-  // Makes |pending_keys_| available to callers that may want to cache its
-  // value for later use on the UI thread. It is illegal to call this if the
-  // cryptographer has no pending keys. Like other calls that access the
-  // cryptographer, this method must be called from within a transaction.
-  const sync_pb::EncryptedData& GetPendingKeys() const;
-
-  // Attempts to decrypt the set of keys that was copied in the previous call to
-  // SetPendingKeys using |params|. Returns true if the pending keys were
-  // successfully decrypted and installed. If successful, the default key
-  // is updated.
-  bool DecryptPendingKeys(const KeyParams& params);
-
-  // Sets the default key to the nigori with name |key_name|. |key_name| must
-  // correspond to a nigori that has already been installed into the keybag.
-  void SetDefaultKey(const std::string& key_name);
-
-  bool is_initialized() const;
-
-  // Returns whether this Cryptographer is ready to encrypt and decrypt data.
-  bool is_ready() const { return is_initialized() && !has_pending_keys(); }
-
   // Returns whether there is a pending set of keys that needs to be decrypted.
-  bool has_pending_keys() const { return nullptr != pending_keys_.get(); }
-
-  // Obtain a token that can be provided on construction to a future
-  // Cryptographer instance to bootstrap itself.  Returns false if such a token
-  // can't be created (i.e. if this Cryptograhper doesn't have valid keys).
-  bool GetBootstrapToken(const Encryptor& encryptor, std::string* token) const;
-
-  // Returns true if |keybag| is decryptable and either is a subset of
-  // |key_bag_| and/or has a different default key.
-  bool KeybagIsStale(const sync_pb::EncryptedData& keybag) const;
-
-  // Returns the name of the Nigori key currently used for encryption.
-  std::string GetDefaultNigoriKeyName() const;
-
-  // Returns a serialized sync_pb::NigoriKey version of current default
-  // encryption key. Returns empty string if Cryptographer is not initialized
-  // or protobuf serialization error occurs.
-  std::string GetDefaultNigoriKeyData() const;
-
-  // Generates a new Nigori from |serialized_nigori_key|, and if successful
-  // installs the new nigori as the default key.
-  bool ImportNigoriKey(const std::string& serialized_nigori_key);
+  // TODO(crbug.com/967417): Remove from cryptographer API.
+  virtual bool has_pending_keys() const = 0;
 
  private:
-  // Initializes cryptographer with completely provided state.
-  Cryptographer(NigoriKeyBag key_bag,
-                const std::string& default_nigori_name,
-                std::unique_ptr<sync_pb::EncryptedData> pending_keys);
-
-  // Helper method to instantiate Nigori instances for each set of key
-  // parameters in |bag|.
-  // Does not update the default nigori.
-  void InstallKeyBag(const sync_pb::NigoriKeyBag& bag);
-
-  // Helper method to add a nigori to the keybag, optionally making it the
-  // default as well.
-  bool AddKeyImpl(std::unique_ptr<Nigori> nigori, bool set_as_default);
-
-  // Helper to unencrypt a bootstrap token into a serialized sync_pb::NigoriKey.
-  std::string UnpackBootstrapToken(const Encryptor& encryptor,
-                                   const std::string& token) const;
-
-  // The actual keys we know about.
-  NigoriKeyBag key_bag_;
-
-  // The key name associated with the default nigori. If non-empty, must
-  // correspond to a nigori within |key_bag_|.
-  std::string default_nigori_name_;
-
-  std::unique_ptr<sync_pb::EncryptedData> pending_keys_;
-
   DISALLOW_ASSIGN(Cryptographer);
 };
 
diff --git a/components/sync/nigori/nigori_sync_bridge_impl.cc b/components/sync/nigori/nigori_sync_bridge_impl.cc
index b55794bc..4ee5f636 100644
--- a/components/sync/nigori/nigori_sync_bridge_impl.cc
+++ b/components/sync/nigori/nigori_sync_bridge_impl.cc
@@ -38,7 +38,7 @@
     return base::nullopt;
   }
 
-  Cryptographer cryptographer;
+  DirectoryCryptographer cryptographer;
   for (const std::string& key : keystore_keys) {
     KeyParams key_params = {KeyDerivationParams::CreateForPbkdf2(), key};
     // TODO(crbug.com/922900): possible behavioral change. Old implementation
@@ -75,7 +75,7 @@
     const std::vector<std::string>& keystore_keys) {
   DCHECK(!keystore_keys.empty());
 
-  Cryptographer cryptographer;
+  DirectoryCryptographer cryptographer;
   // The last keystore key will become default.
   for (const std::string& key : keystore_keys) {
     // This check and checks below theoretically should never fail, but in case
@@ -390,8 +390,9 @@
 // Packs explicit passphrase key in order to persist it. Should be aligned with
 // Directory implementation (Cryptographer::GetBootstrapToken()) unless it is
 // removed. Returns empty string in case of errors.
-std::string PackExplicitPassphraseKey(const Encryptor& encryptor,
-                                      const Cryptographer& cryptographer) {
+std::string PackExplicitPassphraseKey(
+    const Encryptor& encryptor,
+    const DirectoryCryptographer& cryptographer) {
   // Explicit passphrase key should always be default one.
   std::string serialized_key = cryptographer.GetDefaultNigoriKeyData();
   if (serialized_key.empty()) {
@@ -440,7 +441,7 @@
   if (serialized_key.empty()) {
     return false;
   }
-  Cryptographer cryptographer;
+  DirectoryCryptographer cryptographer;
   cryptographer.ImportNigoriKey(serialized_key);
   return cryptographer.CanDecrypt(encrypted_data);
 }
@@ -533,9 +534,8 @@
   if (nigori_model.has_pending_keys()) {
     serialized_cryptographer.pending_keys = nigori_model.pending_keys();
   }
-  cryptographer_.CopyFrom(
-      Cryptographer::CreateFromCryptographerDataWithPendingKeys(
-          serialized_cryptographer));
+  cryptographer_.InitFromCryptographerDataWithPendingKeys(
+      serialized_cryptographer);
 
   // Restore rest of the state.
   passphrase_type_ = nigori_model.passphrase_type();
@@ -606,7 +606,7 @@
     }
     UMA_HISTOGRAM_ENUMERATION("Sync.PassphraseType", enum_passphrase_type);
   }
-  UMA_HISTOGRAM_BOOLEAN("Sync.CryptographerReady", cryptographer_.is_ready());
+  UMA_HISTOGRAM_BOOLEAN("Sync.CryptographerReady", cryptographer_.CanEncrypt());
   UMA_HISTOGRAM_BOOLEAN("Sync.CryptographerPendingKeys",
                         cryptographer_.has_pending_keys());
   if (cryptographer_.has_pending_keys() &&
@@ -643,7 +643,7 @@
     case NigoriSpecifics::TRUSTED_VAULT_PASSPHRASE:
       break;
   }
-  DCHECK(cryptographer_.is_ready());
+  DCHECK(cryptographer_.CanEncrypt());
   passphrase_type_ = NigoriSpecifics::CUSTOM_PASSPHRASE;
   custom_passphrase_key_derivation_params_ =
       CreateKeyDerivationParamsForCustomPassphrase(random_salt_generator_);
@@ -942,7 +942,7 @@
       DecryptKeystoreDecryptor(keystore_keys_, keystore_decryptor_token);
   if (!serialized_keystore_decryptor ||
       !cryptographer_.ImportNigoriKey(*serialized_keystore_decryptor) ||
-      !cryptographer_.is_ready()) {
+      !cryptographer_.CanEncrypt()) {
     return ModelError(FROM_HERE,
                       "Failed to decrypt pending keys using the keystore "
                       "decryptor token.");
@@ -982,7 +982,7 @@
 
 std::unique_ptr<EntityData> NigoriSyncBridgeImpl::GetData() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(cryptographer_.is_ready());
+  DCHECK(cryptographer_.CanEncrypt());
   DCHECK_NE(passphrase_type_, NigoriSpecifics::UNKNOWN);
 
   NigoriSpecifics specifics;
@@ -1041,7 +1041,7 @@
   // solution.
   storage_->ClearData();
   keystore_keys_.clear();
-  cryptographer_.CopyFrom(Cryptographer());
+  cryptographer_.CopyFrom(DirectoryCryptographer());
   passphrase_type_ = NigoriSpecifics::UNKNOWN;
   encrypt_everything_ = false;
   custom_passphrase_time_ = base::Time();
@@ -1055,7 +1055,8 @@
   }
 }
 
-const Cryptographer& NigoriSyncBridgeImpl::GetCryptographerForTesting() const {
+const DirectoryCryptographer& NigoriSyncBridgeImpl::GetCryptographerForTesting()
+    const {
   return cryptographer_;
 }
 
@@ -1070,7 +1071,7 @@
 
 std::string NigoriSyncBridgeImpl::PackExplicitPassphraseKeyForTesting(
     const Encryptor& encryptor,
-    const Cryptographer& cryptographer) {
+    const DirectoryCryptographer& cryptographer) {
   return PackExplicitPassphraseKey(encryptor, cryptographer);
 }
 
diff --git a/components/sync/nigori/nigori_sync_bridge_impl.h b/components/sync/nigori/nigori_sync_bridge_impl.h
index a1a986d..06003023 100644
--- a/components/sync/nigori/nigori_sync_bridge_impl.h
+++ b/components/sync/nigori/nigori_sync_bridge_impl.h
@@ -18,10 +18,10 @@
 #include "components/sync/engine/sync_encryption_handler.h"
 #include "components/sync/model/conflict_resolution.h"
 #include "components/sync/model/model_error.h"
-#include "components/sync/nigori/cryptographer.h"
 #include "components/sync/nigori/keystore_keys_handler.h"
 #include "components/sync/nigori/nigori_local_change_processor.h"
 #include "components/sync/nigori/nigori_sync_bridge.h"
+#include "components/sync/syncable/directory_cryptographer.h"
 
 namespace sync_pb {
 class NigoriLocalData;
@@ -81,13 +81,13 @@
   // TODO(crbug.com/922900): investigate whether we need this getter outside of
   // tests and decide whether this method should be a part of
   // SyncEncryptionHandler interface.
-  const Cryptographer& GetCryptographerForTesting() const;
+  const DirectoryCryptographer& GetCryptographerForTesting() const;
   sync_pb::NigoriSpecifics::PassphraseType GetPassphraseTypeForTesting() const;
   ModelTypeSet GetEncryptedTypesForTesting() const;
 
   static std::string PackExplicitPassphraseKeyForTesting(
       const Encryptor& encryptor,
-      const Cryptographer& cryptographer);
+      const DirectoryCryptographer& cryptographer);
 
  private:
   base::Optional<ModelError> UpdateLocalState(
@@ -134,7 +134,7 @@
   // separately. Should be encrypted with OSCrypt before persisting.
   std::vector<std::string> keystore_keys_;
 
-  Cryptographer cryptographer_;
+  DirectoryCryptographer cryptographer_;
   // TODO(mmoskvitin): Consider adopting the C++ enum PassphraseType here and
   // if so remove function ProtoPassphraseInt32ToProtoEnum() from
   // passphrase_enums.h.
diff --git a/components/sync/nigori/nigori_sync_bridge_impl_unittest.cc b/components/sync/nigori/nigori_sync_bridge_impl_unittest.cc
index 1355f403..c502e9d 100644
--- a/components/sync/nigori/nigori_sync_bridge_impl_unittest.cc
+++ b/components/sync/nigori/nigori_sync_bridge_impl_unittest.cc
@@ -45,7 +45,8 @@
   std::string expected_default_key_name;
   EXPECT_TRUE(expected_default_nigori->Permute(
       Nigori::Type::Password, kNigoriKeyName, &expected_default_key_name));
-  return cryptographer.GetDefaultNigoriKeyName() == expected_default_key_name;
+  return cryptographer.GetDefaultEncryptionKeyName() ==
+         expected_default_key_name;
 }
 
 MATCHER(HasKeystoreNigori, "") {
@@ -143,7 +144,7 @@
 
 std::string PackKeyAsExplicitPassphrase(const KeyParams& key_params,
                                         const Encryptor& encryptor) {
-  Cryptographer cryptographer;
+  DirectoryCryptographer cryptographer;
   cryptographer.AddKey(key_params);
   return NigoriSyncBridgeImpl::PackExplicitPassphraseKeyForTesting(
       encryptor, cryptographer);
@@ -165,7 +166,7 @@
     const KeyParams& keystore_key_params) {
   sync_pb::NigoriSpecifics specifics;
 
-  Cryptographer cryptographer;
+  DirectoryCryptographer cryptographer;
   cryptographer.AddKey(keystore_decryptor_params);
   for (const KeyParams& key_params : keybag_keys_params) {
     cryptographer.AddNonDefaultKey(key_params);
@@ -174,7 +175,7 @@
 
   std::string serialized_keystore_decryptor =
       cryptographer.GetDefaultNigoriKeyData();
-  Cryptographer keystore_cryptographer;
+  DirectoryCryptographer keystore_cryptographer;
   keystore_cryptographer.AddKey(keystore_key_params);
   EXPECT_TRUE(keystore_cryptographer.EncryptString(
       serialized_keystore_decryptor,
@@ -186,7 +187,7 @@
 
 sync_pb::NigoriSpecifics BuildTrustedVaultNigoriSpecifics(
     const std::vector<KeyParams>& trusted_vault_key_params) {
-  syncer::Cryptographer cryptographer;
+  DirectoryCryptographer cryptographer;
   for (const KeyParams& key_params : trusted_vault_key_params) {
     cryptographer.AddKey(key_params);
   }
@@ -211,7 +212,7 @@
     const base::Optional<KeyParams>& old_key_params = base::nullopt) {
   sync_pb::NigoriSpecifics specifics;
 
-  Cryptographer cryptographer;
+  DirectoryCryptographer cryptographer;
   cryptographer.AddKey(passphrase_key_params);
   if (old_key_params) {
     cryptographer.AddNonDefaultKey(*old_key_params);
diff --git a/components/sync/protocol/client_debug_info.proto b/components/sync/protocol/client_debug_info.proto
index 34852545..62c5063 100644
--- a/components/sync/protocol/client_debug_info.proto
+++ b/components/sync/protocol/client_debug_info.proto
@@ -28,24 +28,15 @@
   optional bool has_valid_hint = 2;
 }
 
-// A dummy message definition for deprecated fields. Never add any fields to
-// this message.
-message DeprecatedMessage {}
-
 // The additional info here is from the StatusController. They get sent when
 // the event SYNC_CYCLE_COMPLETED  is sent.
 message SyncCycleCompletedEventInfo {
-  // optional bool syncer_stuck = 1; // Was always false, now obsolete.
-
-  // The client has never set these values correctly.  It set
-  // num_blocking_conflicts to the total number of conflicts detected and set
-  // num_non_blocking_conflicts to the number of blocking (aka. simple)
-  // conflicts.
-  //
-  // These counters have been deprecated to avoid further confusion.  The newer
-  // counters provide more detail and are less buggy.
-  optional int32 num_blocking_conflicts = 2 [deprecated = true];
-  optional int32 num_non_blocking_conflicts = 3 [deprecated = true];
+  reserved 1;
+  reserved "syncer_stuck";
+  reserved 2;
+  reserved "num_blocking_conflicts";
+  reserved 3;
+  reserved "num_non_blocking_conflicts";
 
   // These new conflict counters replace the ones above.
   optional int32 num_encryption_conflicts = 4;
@@ -61,8 +52,9 @@
   // contains the |notifications_enabled| flag.
   optional GetUpdatesCallerInfo caller_info = 10;
 
-  // |source_info| was unused and marked deprecated in M67.
-  repeated DeprecatedMessage source_info = 11 [deprecated = true];
+  // Deprecated in M67.
+  reserved 11;
+  reserved "source_info";
 
   optional SyncEnums.GetUpdatesOrigin get_updates_origin = 12;
 }
diff --git a/components/sync/protocol/sync.proto b/components/sync/protocol/sync.proto
index 4868cff..807cc5e7 100644
--- a/components/sync/protocol/sync.proto
+++ b/components/sync/protocol/sync.proto
@@ -311,10 +311,8 @@
   // include |position_in_parent| instead.
   optional string insert_after_item_id = 16;
 
-  // Arbitrary key/value pairs associated with this item.
-  // Present in both GetUpdatesResponse and CommitMessage.
-  // Deprecated.
-  // optional ExtendedAttributes extended_attributes = 17;
+  reserved 17;
+  reserved "extended_attributes";
 
   // If true, indicates that this item has been (or should be) deleted.
   // Present in both GetUpdatesResponse and CommitMessage.
@@ -401,7 +399,8 @@
 
   // This used to be a list of sync attachment IDs, but it was never launched
   // and the code has been removed as of M66.
-  repeated DeprecatedMessage attachment_id = 26 [deprecated = true];
+  reserved 26;
+  reserved "attachment_id";
 };
 
 // This message contains diagnostic information used to correlate
@@ -565,11 +564,8 @@
   // based on last modified time.
   optional int32 age_watermark_in_days = 3;
 
-  // This field specifies the max number of items that the client should keep
-  // for a specific datatype.  If the number of items exceeds this limit, the
-  // client should purge the extra sync entities based on the LRU rule.
-  // Deprecated in M76.
-  optional int32 deprecated_max_number_of_items = 4 [deprecated = true];
+  reserved 4;
+  reserved "max_number_of_items";
 }
 
 message DataTypeProgressMarker {
@@ -700,15 +696,7 @@
   reserved "requested_types";
 };
 
-message AuthenticateMessage {
-  required string auth_token = 1;
-};
-
 // Message from a client asking the server to clear its data.
-//
-// A client makes a ClearServerData request when it transitions to passphrase
-// encryption to ensure the server deletes any plaintext data that may have been
-// synced previously.
 message ClearServerDataMessage {
   // No arguments needed as the store birthday and user identifier are part of
   // an enclosing message.
@@ -775,7 +763,7 @@
   enum Contents {
     COMMIT = 1;
     GET_UPDATES = 2;
-    AUTHENTICATE = 3;
+    DEPRECATED_3 = 3;
     DEPRECATED_4 = 4;
     CLEAR_SERVER_DATA = 5;
   }
@@ -787,9 +775,10 @@
   required Contents message_contents = 3;
   optional CommitMessage commit = 4;
   optional GetUpdatesMessage get_updates = 5;
-  optional AuthenticateMessage authenticate = 6;
+  reserved 6;
+  reserved "authenticate";
 
-  optional DeprecatedMessage deprecated_field_9 = 9 [deprecated = true];
+  reserved 9;
 
   optional string store_birthday = 7;  // Opaque store ID; if it changes, duck!
   // The client sets this if it detects a sync issue. The server will tell it
@@ -865,9 +854,8 @@
     // should be filled if our parent was assigned a new ID.
     optional string parent_id_string = 4;
 
-    // This used to be set to the same as the position_in_parent value in
-    // the SyncEntity message in GetUpdatesResponse, but it's not set anymore.
-    optional int64 deprecated_position_in_parent = 5 [deprecated = true];
+    reserved 5;
+    reserved "position_in_parent";
 
     // The item's current version.
     optional int64 version = 6;
@@ -903,8 +891,8 @@
   // instead.
   optional int64 new_timestamp = 2;
 
-  // DEPRECATED FIELD - server does not set this anymore.
-  optional int64 deprecated_newest_timestamp = 3;
+  reserved 3;
+  reserved "newest_timestamp";
 
   // Approximate count of changes remaining - use this for UI feedback.
   // If present and zero, this estimate is firm: the server has no changes
@@ -965,25 +953,11 @@
   repeated SyncEntity entries = 1;
 };
 
-// A user-identifying struct.  For a given Google account the email and display
-// name can change, but obfuscated_id should be constant.
-// The obfuscated id is optional because at least one planned use of the proto
-// (sharing) does not require it.
-message UserIdentification {
-  required string email = 1;          // the user's full primary email address.
-  optional string display_name = 2;   // the user's display name.
-  optional string obfuscated_id = 3;  // an obfuscated, opaque user id.
-};
-
-message AuthenticateResponse {
-  // Optional only for backward compatibility.
-  optional UserIdentification user = 1;
-};
-
 message ClientToServerResponse {
   optional CommitResponse commit = 1;
   optional GetUpdatesResponse get_updates = 2;
-  optional AuthenticateResponse authenticate = 3;
+  reserved 3;
+  reserved "authenticate";
 
   // Up until protocol_version 24, the default was SUCCESS which made it
   // impossible to add new enum values since older clients would parse any
@@ -1003,7 +977,7 @@
 
   optional ClientCommand client_command = 7;
   optional ProfilingData profiling_data = 8;
-  optional DeprecatedMessage deprecated_field_9 = 9 [deprecated = true];
+  reserved 9;
   optional GetUpdatesMetadataResponse stream_metadata = 10;
   // If GetUpdatesStreamingResponse is contained in the ClientToServerResponse,
   // none of the other fields (error_code and etc) will be set.
diff --git a/components/sync/protocol/web_app_specifics.proto b/components/sync/protocol/web_app_specifics.proto
index 7358e68..3fbd803 100644
--- a/components/sync/protocol/web_app_specifics.proto
+++ b/components/sync/protocol/web_app_specifics.proto
@@ -11,10 +11,9 @@
 
 package sync_pb;
 
-// WebApp data. This should be a subset of WebAppProto in
-// chrome/browser/web_applications/proto/web_app.proto
+// WebApp data. This is a synced part of
+// chrome/browser/web_applications/proto/web_app.proto data.
 message WebAppSpecifics {
-  // Keep in sync with WebAppProto::LaunchContainer.
   enum LaunchContainer {
     TAB = 1;
     WINDOW = 2;
diff --git a/components/sync/syncable/directory_cryptographer.cc b/components/sync/syncable/directory_cryptographer.cc
new file mode 100644
index 0000000..61982e0
--- /dev/null
+++ b/components/sync/syncable/directory_cryptographer.cc
@@ -0,0 +1,359 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/sync/syncable/directory_cryptographer.h"
+
+#include <stddef.h>
+
+#include <algorithm>
+#include <utility>
+
+#include "base/base64.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "components/sync/base/encryptor.h"
+#include "components/sync/protocol/nigori_specifics.pb.h"
+
+namespace syncer {
+
+KeyParams::KeyParams(KeyDerivationParams derivation_params,
+                     const std::string& password)
+    : derivation_params(derivation_params), password(password) {}
+
+KeyParams::KeyParams(const KeyParams& other) = default;
+KeyParams::KeyParams(KeyParams&& other) = default;
+KeyParams::~KeyParams() = default;
+
+CryptographerDataWithPendingKeys::CryptographerDataWithPendingKeys() = default;
+CryptographerDataWithPendingKeys::CryptographerDataWithPendingKeys(
+    CryptographerDataWithPendingKeys&& other) = default;
+CryptographerDataWithPendingKeys::~CryptographerDataWithPendingKeys() = default;
+
+DirectoryCryptographer::DirectoryCryptographer()
+    : key_bag_(NigoriKeyBag::CreateEmpty()) {}
+
+DirectoryCryptographer::~DirectoryCryptographer() {}
+
+void DirectoryCryptographer::CopyFrom(const DirectoryCryptographer& other) {
+  key_bag_.CopyFrom(other.key_bag_);
+  default_nigori_name_ = other.default_nigori_name_;
+  if (other.pending_keys_) {
+    pending_keys_ =
+        std::make_unique<sync_pb::EncryptedData>(*other.pending_keys_);
+  }
+}
+
+void DirectoryCryptographer::InitFromCryptographerDataWithPendingKeys(
+    const CryptographerDataWithPendingKeys& serialized_state) {
+  std::unique_ptr<sync_pb::EncryptedData> pending_keys;
+  if (serialized_state.pending_keys.has_value()) {
+    pending_keys = std::make_unique<sync_pb::EncryptedData>(
+        *serialized_state.pending_keys);
+  }
+  CopyFrom(DirectoryCryptographer(
+      NigoriKeyBag::CreateFromProto(
+          serialized_state.cryptographer_data.key_bag()),
+      serialized_state.cryptographer_data.default_key_name(),
+      std::move(pending_keys)));
+}
+
+CryptographerDataWithPendingKeys
+DirectoryCryptographer::ToCryptographerDataWithPendingKeys() const {
+  CryptographerDataWithPendingKeys output;
+  *output.cryptographer_data.mutable_key_bag() = key_bag_.ToProto();
+  output.cryptographer_data.set_default_key_name(default_nigori_name_);
+  if (pending_keys_) {
+    output.pending_keys = *pending_keys_;
+  }
+  return output;
+}
+
+void DirectoryCryptographer::Bootstrap(
+    const Encryptor& encryptor,
+    const std::string& restored_bootstrap_token) {
+  if (is_initialized()) {
+    NOTREACHED();
+    return;
+  }
+
+  std::string serialized_nigori_key =
+      UnpackBootstrapToken(encryptor, restored_bootstrap_token);
+  if (serialized_nigori_key.empty())
+    return;
+  ImportNigoriKey(serialized_nigori_key);
+}
+
+std::unique_ptr<Cryptographer> DirectoryCryptographer::Clone() const {
+  auto cryptographer = base::WrapUnique(new DirectoryCryptographer());
+  cryptographer->CopyFrom(*this);
+  return cryptographer;
+}
+
+bool DirectoryCryptographer::CanEncrypt() const {
+  return is_initialized() && !has_pending_keys();
+}
+
+bool DirectoryCryptographer::CanDecrypt(
+    const sync_pb::EncryptedData& data) const {
+  return key_bag_.HasKey(data.key_name());
+}
+
+bool DirectoryCryptographer::CanDecryptUsingDefaultKey(
+    const sync_pb::EncryptedData& data) const {
+  return !default_nigori_name_.empty() &&
+         data.key_name() == default_nigori_name_;
+}
+
+bool DirectoryCryptographer::EncryptString(
+    const std::string& serialized,
+    sync_pb::EncryptedData* encrypted) const {
+  if (default_nigori_name_.empty()) {
+    LOG(ERROR) << "Cryptographer not ready, failed to encrypt.";
+    return false;
+  }
+
+  if (CanDecryptUsingDefaultKey(*encrypted)) {
+    std::string original_serialized;
+    if (DecryptToString(*encrypted, &original_serialized) &&
+        original_serialized == serialized) {
+      DVLOG(2) << "Re-encryption unnecessary, encrypted data already matches.";
+      return true;
+    }
+  }
+
+  if (!key_bag_.HasKey(default_nigori_name_)) {
+    LOG(ERROR) << "Corrupt default key.";
+    return false;
+  }
+
+  return key_bag_.EncryptWithKey(default_nigori_name_, serialized, encrypted);
+}
+
+bool DirectoryCryptographer::DecryptToString(
+    const sync_pb::EncryptedData& encrypted,
+    std::string* decrypted) const {
+  return key_bag_.Decrypt(encrypted, decrypted);
+}
+
+bool DirectoryCryptographer::has_pending_keys() const {
+  return nullptr != pending_keys_.get();
+}
+
+bool DirectoryCryptographer::GetKeys(sync_pb::EncryptedData* encrypted) const {
+  DCHECK(encrypted);
+  DCHECK_NE(size_t(0), key_bag_.size());
+
+  // Create a bag of all the Nigori parameters we know about.
+  sync_pb::NigoriKeyBag bag = key_bag_.ToProto();
+
+  // Encrypt the bag with the default Nigori.
+  return Encrypt(bag, encrypted);
+}
+
+bool DirectoryCryptographer::AddKey(const KeyParams& params) {
+  return AddKeyImpl(
+      Nigori::CreateByDerivation(params.derivation_params, params.password),
+      /*set_as_default=*/true);
+}
+
+bool DirectoryCryptographer::AddNonDefaultKey(const KeyParams& params) {
+  DCHECK(is_initialized());
+  return AddKeyImpl(
+      Nigori::CreateByDerivation(params.derivation_params, params.password),
+      /*set_as_default=*/false);
+}
+
+bool DirectoryCryptographer::AddKeyFromBootstrapToken(
+    const Encryptor& encryptor,
+    const std::string& restored_bootstrap_token) {
+  // Create the new Nigori and make it the default encryptor.
+  std::string serialized_nigori_key =
+      UnpackBootstrapToken(encryptor, restored_bootstrap_token);
+  return ImportNigoriKey(serialized_nigori_key);
+}
+
+bool DirectoryCryptographer::AddKeyImpl(std::unique_ptr<Nigori> nigori,
+                                        bool set_as_default) {
+  DCHECK(nigori);
+  std::string key_name = key_bag_.AddKey(std::move(nigori));
+  if (key_name.empty()) {
+    NOTREACHED();
+    return false;
+  }
+
+  // Check if the key we just added can decrypt the pending keys and add them
+  // too if so.
+  if (pending_keys_.get() && CanDecrypt(*pending_keys_)) {
+    sync_pb::NigoriKeyBag pending_bag;
+    Decrypt(*pending_keys_, &pending_bag);
+    InstallKeyBag(pending_bag);
+    SetDefaultKey(pending_keys_->key_name());
+    pending_keys_.reset();
+  }
+
+  // The just-added key takes priority over the pending keys as default.
+  if (set_as_default)
+    SetDefaultKey(key_name);
+  return true;
+}
+
+void DirectoryCryptographer::InstallKeys(
+    const sync_pb::EncryptedData& encrypted) {
+  DCHECK(CanDecrypt(encrypted));
+
+  sync_pb::NigoriKeyBag bag;
+  if (!Decrypt(encrypted, &bag))
+    return;
+  InstallKeyBag(bag);
+}
+
+void DirectoryCryptographer::SetDefaultKey(const std::string& key_name) {
+  DCHECK(key_bag_.HasKey(key_name));
+  default_nigori_name_ = key_name;
+}
+
+bool DirectoryCryptographer::is_initialized() const {
+  return !default_nigori_name_.empty();
+}
+
+void DirectoryCryptographer::SetPendingKeys(
+    const sync_pb::EncryptedData& encrypted) {
+  DCHECK(!CanDecrypt(encrypted));
+  DCHECK(!encrypted.blob().empty());
+  pending_keys_ = std::make_unique<sync_pb::EncryptedData>(encrypted);
+}
+
+const sync_pb::EncryptedData& DirectoryCryptographer::GetPendingKeys() const {
+  DCHECK(has_pending_keys());
+  return *(pending_keys_.get());
+}
+
+bool DirectoryCryptographer::DecryptPendingKeys(const KeyParams& params) {
+  DCHECK_NE(KeyDerivationMethod::UNSUPPORTED,
+            params.derivation_params.method());
+
+  std::unique_ptr<Nigori> nigori =
+      Nigori::CreateByDerivation(params.derivation_params, params.password);
+
+  std::string plaintext;
+  if (!nigori->Decrypt(pending_keys_->blob(), &plaintext))
+    return false;
+
+  sync_pb::NigoriKeyBag bag;
+  if (!bag.ParseFromString(plaintext)) {
+    NOTREACHED();
+    return false;
+  }
+  InstallKeyBag(bag);
+  const std::string& new_default_key_name = pending_keys_->key_name();
+  SetDefaultKey(new_default_key_name);
+  pending_keys_.reset();
+  return true;
+}
+
+bool DirectoryCryptographer::GetBootstrapToken(const Encryptor& encryptor,
+                                               std::string* token) const {
+  DCHECK(token);
+  std::string unencrypted_token = GetDefaultNigoriKeyData();
+  if (unencrypted_token.empty())
+    return false;
+
+  std::string encrypted_token;
+  if (!encryptor.EncryptString(unencrypted_token, &encrypted_token)) {
+    return false;
+  }
+
+  base::Base64Encode(encrypted_token, token);
+
+  return true;
+}
+
+std::string DirectoryCryptographer::UnpackBootstrapToken(
+    const Encryptor& encryptor,
+    const std::string& token) const {
+  if (token.empty())
+    return std::string();
+
+  std::string encrypted_data;
+  if (!base::Base64Decode(token, &encrypted_data)) {
+    DLOG(WARNING) << "Could not decode token.";
+    return std::string();
+  }
+
+  std::string unencrypted_token;
+  if (!encryptor.DecryptString(encrypted_data, &unencrypted_token)) {
+    DLOG(WARNING) << "Decryption of bootstrap token failed.";
+    return std::string();
+  }
+  return unencrypted_token;
+}
+
+void DirectoryCryptographer::InstallKeyBag(const sync_pb::NigoriKeyBag& bag) {
+  key_bag_.AddAllUnknownKeysFrom(NigoriKeyBag::CreateFromProto(bag));
+}
+
+bool DirectoryCryptographer::KeybagIsStale(
+    const sync_pb::EncryptedData& encrypted_bag) const {
+  if (!CanEncrypt())
+    return false;
+  if (encrypted_bag.blob().empty())
+    return true;
+  if (!CanDecrypt(encrypted_bag))
+    return false;
+  if (!CanDecryptUsingDefaultKey(encrypted_bag))
+    return true;
+  sync_pb::NigoriKeyBag bag;
+  if (!Decrypt(encrypted_bag, &bag)) {
+    LOG(ERROR) << "Failed to decrypt keybag for stale check. "
+               << "Assuming keybag is corrupted.";
+    return true;
+  }
+  if (static_cast<size_t>(bag.key_size()) < key_bag_.size())
+    return true;
+  return false;
+}
+
+std::string DirectoryCryptographer::GetDefaultEncryptionKeyName() const {
+  return default_nigori_name_;
+}
+
+std::string DirectoryCryptographer::GetDefaultNigoriKeyData() const {
+  if (!is_initialized())
+    return std::string();
+  sync_pb::NigoriKey key = key_bag_.ExportKey(default_nigori_name_);
+  key.clear_name();
+  return key.SerializeAsString();
+}
+
+bool DirectoryCryptographer::ImportNigoriKey(
+    const std::string& serialized_nigori_key) {
+  if (serialized_nigori_key.empty())
+    return false;
+
+  sync_pb::NigoriKey key;
+  if (!key.ParseFromString(serialized_nigori_key))
+    return false;
+
+  std::unique_ptr<Nigori> nigori = Nigori::CreateByImport(
+      key.user_key(), key.encryption_key(), key.mac_key());
+
+  if (!nigori) {
+    DLOG(ERROR) << "Ignoring invalid Nigori when importing";
+    return false;
+  }
+
+  if (!AddKeyImpl(std::move(nigori), true))
+    return false;
+  return true;
+}
+
+DirectoryCryptographer::DirectoryCryptographer(
+    NigoriKeyBag key_bag,
+    const std::string& default_nigori_name,
+    std::unique_ptr<sync_pb::EncryptedData> pending_keys)
+    : key_bag_(std::move(key_bag)),
+      default_nigori_name_(std::move(default_nigori_name)),
+      pending_keys_(std::move(pending_keys)) {}
+
+}  // namespace syncer
diff --git a/components/sync/syncable/directory_cryptographer.h b/components/sync/syncable/directory_cryptographer.h
new file mode 100644
index 0000000..9f9c058b
--- /dev/null
+++ b/components/sync/syncable/directory_cryptographer.h
@@ -0,0 +1,219 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SYNC_SYNCABLE_DIRECTORY_CRYPTOGRAPHER_H_
+#define COMPONENTS_SYNC_SYNCABLE_DIRECTORY_CRYPTOGRAPHER_H_
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "base/optional.h"
+#include "components/sync/base/passphrase_enums.h"
+#include "components/sync/nigori/cryptographer.h"
+#include "components/sync/nigori/nigori.h"
+#include "components/sync/nigori/nigori_key_bag.h"
+#include "components/sync/protocol/encryption.pb.h"
+#include "components/sync/protocol/nigori_local_data.pb.h"
+
+namespace sync_pb {
+class NigoriKeyBag;
+}  // namespace sync_pb
+
+namespace syncer {
+
+class Encryptor;
+
+// The parameters used to initialize a Nigori instance.
+// TODO(davidovic): Stop relying on KeyParams and inline it, because it's now
+// just a pair of KeyDerivationParams and passphrase.
+struct KeyParams {
+  KeyParams(KeyDerivationParams derivation_params, const std::string& password);
+  KeyParams(const KeyParams& other);
+  KeyParams(KeyParams&& other);
+  ~KeyParams();
+
+  KeyDerivationParams derivation_params;
+  std::string password;
+};
+
+struct CryptographerDataWithPendingKeys {
+  CryptographerDataWithPendingKeys();
+  CryptographerDataWithPendingKeys(CryptographerDataWithPendingKeys&& other);
+  ~CryptographerDataWithPendingKeys();
+
+  sync_pb::CryptographerData cryptographer_data;
+  base::Optional<sync_pb::EncryptedData> pending_keys;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CryptographerDataWithPendingKeys);
+};
+
+// This class manages the Nigori objects used to encrypt and decrypt sensitive
+// sync data (eg. passwords). Each Nigori object knows how to handle data
+// protected with a particular passphrase.
+//
+// Whenever an update to the Nigori sync node is received from the server,
+// SetPendingKeys should be called with the encrypted contents of that node.
+// Most likely, an updated Nigori node means that a new passphrase has been set
+// and that future node updates won't be decryptable. To remedy this, the user
+// should be prompted for the new passphrase and DecryptPendingKeys be called.
+//
+// Whenever a update to an encrypted node is received from the server,
+// CanDecrypt should be used to verify whether the Cryptographer can decrypt
+// that node. If it cannot, then the application of that update should be
+// delayed until after it can be decrypted.
+class DirectoryCryptographer : public Cryptographer {
+ public:
+  DirectoryCryptographer();
+  ~DirectoryCryptographer() override;
+
+  void CopyFrom(const DirectoryCryptographer& other);
+
+  // Deserialization.
+  void InitFromCryptographerDataWithPendingKeys(
+      const CryptographerDataWithPendingKeys& serialized_state);
+
+  // Serialization.
+  CryptographerDataWithPendingKeys ToCryptographerDataWithPendingKeys() const;
+
+  // |restored_bootstrap_token| can be provided via this method to bootstrap
+  // Cryptographer instance into the ready state (is_ready will be true).
+  // It must be a string that was previously built by the
+  // GetSerializedBootstrapToken function.  It is possible that the token is no
+  // longer valid (due to server key change), in which case the normal
+  // decryption code paths will fail and the user will need to provide a new
+  // passphrase.
+  // It is an error to call this if is_ready() == true, though it is fair to
+  // never call Bootstrap at all.
+  void Bootstrap(const Encryptor& encryptor,
+                 const std::string& restored_bootstrap_token);
+
+  // Returns whether |encrypted| can be decrypted using the default encryption
+  // key.
+  bool CanDecryptUsingDefaultKey(const sync_pb::EncryptedData& encrypted) const;
+
+  // Encrypts the set of currently known keys into |encrypted|. Returns true if
+  // successful.
+  bool GetKeys(sync_pb::EncryptedData* encrypted) const;
+
+  // Creates a new Nigori instance using |params|. If successful, |params| will
+  // become the default encryption key and be used for all future calls to
+  // Encrypt.
+  // Will decrypt the pending keys and install them if possible (pending key
+  // will not overwrite default).
+  bool AddKey(const KeyParams& params);
+
+  // Same as AddKey(..), but builds the new Nigori from a previously persisted
+  // bootstrap token. This can be useful when consuming a bootstrap token
+  // with a cryptographer that has already been initialized.
+  // Updates the default key.
+  // Will decrypt the pending keys and install them if possible (pending key
+  // will not overwrite default).
+  bool AddKeyFromBootstrapToken(const Encryptor& encryptor,
+                                const std::string& restored_bootstrap_token);
+
+  // Creates a new Nigori instance using |params|. If successful, |params|
+  // will be added to the nigori keybag, but will not be the default encryption
+  // key (default_nigori_ will remain the same).
+  // Prereq: is_initialized() must be true.
+  // Will decrypt the pending keys and install them if possible (pending key
+  // will become the new default).
+  bool AddNonDefaultKey(const KeyParams& params);
+
+  // Decrypts |encrypted| and uses its contents to initialize Nigori instances.
+  // Returns true unless decryption of |encrypted| fails. The caller is
+  // responsible for checking that CanDecrypt(encrypted) == true.
+  // Does not modify the default key.
+  void InstallKeys(const sync_pb::EncryptedData& encrypted);
+
+  // Makes a local copy of |encrypted| to later be decrypted by
+  // DecryptPendingKeys. This should only be used if CanDecrypt(encrypted) ==
+  // false.
+  void SetPendingKeys(const sync_pb::EncryptedData& encrypted);
+
+  // Makes |pending_keys_| available to callers that may want to cache its
+  // value for later use on the UI thread. It is illegal to call this if the
+  // cryptographer has no pending keys. Like other calls that access the
+  // cryptographer, this method must be called from within a transaction.
+  const sync_pb::EncryptedData& GetPendingKeys() const;
+
+  // Attempts to decrypt the set of keys that was copied in the previous call to
+  // SetPendingKeys using |params|. Returns true if the pending keys were
+  // successfully decrypted and installed. If successful, the default key
+  // is updated.
+  bool DecryptPendingKeys(const KeyParams& params);
+
+  // Sets the default key to the nigori with name |key_name|. |key_name| must
+  // correspond to a nigori that has already been installed into the keybag.
+  void SetDefaultKey(const std::string& key_name);
+
+  bool is_initialized() const;
+
+  // Obtain a token that can be provided on construction to a future
+  // Cryptographer instance to bootstrap itself.  Returns false if such a token
+  // can't be created (i.e. if this Cryptograhper doesn't have valid keys).
+  bool GetBootstrapToken(const Encryptor& encryptor, std::string* token) const;
+
+  // Returns true if |keybag| is decryptable and either is a subset of
+  // |key_bag_| and/or has a different default key.
+  bool KeybagIsStale(const sync_pb::EncryptedData& keybag) const;
+
+  // Returns the name of the Nigori key currently used for encryption.
+  std::string GetDefaultEncryptionKeyName() const override;
+
+  // Returns a serialized sync_pb::NigoriKey version of current default
+  // encryption key. Returns empty string if Cryptographer is not initialized
+  // or protobuf serialization error occurs.
+  std::string GetDefaultNigoriKeyData() const;
+
+  // Generates a new Nigori from |serialized_nigori_key|, and if successful
+  // installs the new nigori as the default key.
+  bool ImportNigoriKey(const std::string& serialized_nigori_key);
+
+  // Cryptographer overrides.
+  std::unique_ptr<Cryptographer> Clone() const override;
+  bool CanEncrypt() const override;
+  bool CanDecrypt(const sync_pb::EncryptedData& encrypted) const override;
+  bool EncryptString(const std::string& serialized,
+                     sync_pb::EncryptedData* encrypted) const override;
+  bool DecryptToString(const sync_pb::EncryptedData& encrypted,
+                       std::string* decrypted) const override;
+  bool has_pending_keys() const override;
+
+ private:
+  // Initializes cryptographer with completely provided state.
+  DirectoryCryptographer(NigoriKeyBag key_bag,
+                         const std::string& default_nigori_name,
+                         std::unique_ptr<sync_pb::EncryptedData> pending_keys);
+
+  // Helper method to instantiate Nigori instances for each set of key
+  // parameters in |bag|.
+  // Does not update the default nigori.
+  void InstallKeyBag(const sync_pb::NigoriKeyBag& bag);
+
+  // Helper method to add a nigori to the keybag, optionally making it the
+  // default as well.
+  bool AddKeyImpl(std::unique_ptr<Nigori> nigori, bool set_as_default);
+
+  // Helper to unencrypt a bootstrap token into a serialized sync_pb::NigoriKey.
+  std::string UnpackBootstrapToken(const Encryptor& encryptor,
+                                   const std::string& token) const;
+
+  // The actual keys we know about.
+  NigoriKeyBag key_bag_;
+
+  // The key name associated with the default nigori. If non-empty, must
+  // correspond to a nigori within |key_bag_|.
+  std::string default_nigori_name_;
+
+  std::unique_ptr<sync_pb::EncryptedData> pending_keys_;
+
+  DISALLOW_ASSIGN(DirectoryCryptographer);
+};
+
+}  // namespace syncer
+
+#endif  // COMPONENTS_SYNC_SYNCABLE_DIRECTORY_CRYPTOGRAPHER_H_
diff --git a/components/sync/nigori/cryptographer_unittest.cc b/components/sync/syncable/directory_cryptographer_unittest.cc
similarity index 83%
rename from components/sync/nigori/cryptographer_unittest.cc
rename to components/sync/syncable/directory_cryptographer_unittest.cc
index 9e0224ac..737d1a3 100644
--- a/components/sync/nigori/cryptographer_unittest.cc
+++ b/components/sync/syncable/directory_cryptographer_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/sync/nigori/cryptographer.h"
+#include "components/sync/syncable/directory_cryptographer.h"
 
 #include "base/strings/string_util.h"
 #include "components/sync/base/fake_encryptor.h"
@@ -22,16 +22,16 @@
 
 }  // namespace
 
-class CryptographerTest : public ::testing::Test {
+class DirectoryCryptographerTest : public ::testing::Test {
  protected:
-  CryptographerTest() = default;
+  DirectoryCryptographerTest() = default;
 
   FakeEncryptor encryptor_;
-  Cryptographer cryptographer_;
+  DirectoryCryptographer cryptographer_;
 };
 
-TEST_F(CryptographerTest, EmptyCantDecrypt) {
-  EXPECT_FALSE(cryptographer_.is_ready());
+TEST_F(DirectoryCryptographerTest, EmptyCantDecrypt) {
+  EXPECT_FALSE(cryptographer_.CanEncrypt());
 
   sync_pb::EncryptedData encrypted;
   encrypted.set_key_name("foo");
@@ -40,18 +40,18 @@
   EXPECT_FALSE(cryptographer_.CanDecrypt(encrypted));
 }
 
-TEST_F(CryptographerTest, EmptyCantEncrypt) {
-  EXPECT_FALSE(cryptographer_.is_ready());
+TEST_F(DirectoryCryptographerTest, EmptyCantEncrypt) {
+  EXPECT_FALSE(cryptographer_.CanEncrypt());
 
   sync_pb::EncryptedData encrypted;
   sync_pb::PasswordSpecificsData original;
   EXPECT_FALSE(cryptographer_.Encrypt(original, &encrypted));
 }
 
-TEST_F(CryptographerTest, MissingCantDecrypt) {
+TEST_F(DirectoryCryptographerTest, MissingCantDecrypt) {
   KeyParams params = {KeyDerivationParams::CreateForPbkdf2(), "dummy"};
   cryptographer_.AddKey(params);
-  EXPECT_TRUE(cryptographer_.is_ready());
+  EXPECT_TRUE(cryptographer_.CanEncrypt());
 
   sync_pb::EncryptedData encrypted;
   encrypted.set_key_name("foo");
@@ -60,10 +60,10 @@
   EXPECT_FALSE(cryptographer_.CanDecrypt(encrypted));
 }
 
-TEST_F(CryptographerTest, CanEncryptAndDecrypt) {
+TEST_F(DirectoryCryptographerTest, CanEncryptAndDecrypt) {
   KeyParams params = {KeyDerivationParams::CreateForPbkdf2(), "dummy"};
   EXPECT_TRUE(cryptographer_.AddKey(params));
-  EXPECT_TRUE(cryptographer_.is_ready());
+  EXPECT_TRUE(cryptographer_.CanEncrypt());
 
   sync_pb::PasswordSpecificsData original;
   original.set_origin("http://example.com");
@@ -79,10 +79,10 @@
   EXPECT_EQ(original.SerializeAsString(), decrypted.SerializeAsString());
 }
 
-TEST_F(CryptographerTest, EncryptOnlyIfDifferent) {
+TEST_F(DirectoryCryptographerTest, EncryptOnlyIfDifferent) {
   KeyParams params = {KeyDerivationParams::CreateForPbkdf2(), "dummy"};
   EXPECT_TRUE(cryptographer_.AddKey(params));
-  EXPECT_TRUE(cryptographer_.is_ready());
+  EXPECT_TRUE(cryptographer_.CanEncrypt());
 
   sync_pb::PasswordSpecificsData original;
   original.set_origin("http://example.com");
@@ -110,10 +110,10 @@
   EXPECT_EQ(original.SerializeAsString(), decrypted.SerializeAsString());
 }
 
-TEST_F(CryptographerTest, AddKeySetsDefault) {
+TEST_F(DirectoryCryptographerTest, AddKeySetsDefault) {
   KeyParams params1 = {KeyDerivationParams::CreateForPbkdf2(), "dummy1"};
   EXPECT_TRUE(cryptographer_.AddKey(params1));
-  EXPECT_TRUE(cryptographer_.is_ready());
+  EXPECT_TRUE(cryptographer_.CanEncrypt());
 
   sync_pb::PasswordSpecificsData original;
   original.set_origin("http://example.com");
@@ -127,7 +127,7 @@
 
   KeyParams params2 = {KeyDerivationParams::CreateForPbkdf2(), "dummy2"};
   EXPECT_TRUE(cryptographer_.AddKey(params2));
-  EXPECT_TRUE(cryptographer_.is_ready());
+  EXPECT_TRUE(cryptographer_.CanEncrypt());
 
   sync_pb::EncryptedData encrypted3;
   EXPECT_TRUE(cryptographer_.Encrypt(original, &encrypted3));
@@ -139,7 +139,7 @@
   EXPECT_EQ(encrypted3.key_name(), encrypted4.key_name());
 }
 
-TEST_F(CryptographerTest, EncryptExportDecrypt) {
+TEST_F(DirectoryCryptographerTest, EncryptExportDecrypt) {
   sync_pb::EncryptedData nigori;
   sync_pb::EncryptedData encrypted;
 
@@ -149,27 +149,27 @@
   original.set_password_value("hunter2");
 
   {
-    Cryptographer cryptographer;
+    DirectoryCryptographer cryptographer;
 
     KeyParams params = {KeyDerivationParams::CreateForPbkdf2(), "dummy"};
     cryptographer.AddKey(params);
-    EXPECT_TRUE(cryptographer.is_ready());
+    EXPECT_TRUE(cryptographer.CanEncrypt());
 
     EXPECT_TRUE(cryptographer.Encrypt(original, &encrypted));
     EXPECT_TRUE(cryptographer.GetKeys(&nigori));
   }
 
   {
-    Cryptographer cryptographer;
+    DirectoryCryptographer cryptographer;
     EXPECT_FALSE(cryptographer.CanDecrypt(nigori));
 
     cryptographer.SetPendingKeys(nigori);
-    EXPECT_FALSE(cryptographer.is_ready());
+    EXPECT_FALSE(cryptographer.CanEncrypt());
     EXPECT_TRUE(cryptographer.has_pending_keys());
 
     KeyParams params = {KeyDerivationParams::CreateForPbkdf2(), "dummy"};
     EXPECT_TRUE(cryptographer.DecryptPendingKeys(params));
-    EXPECT_TRUE(cryptographer.is_ready());
+    EXPECT_TRUE(cryptographer.CanEncrypt());
     EXPECT_FALSE(cryptographer.has_pending_keys());
 
     sync_pb::PasswordSpecificsData decrypted;
@@ -178,7 +178,7 @@
   }
 }
 
-TEST_F(CryptographerTest, Bootstrap) {
+TEST_F(DirectoryCryptographerTest, Bootstrap) {
   KeyParams params = {KeyDerivationParams::CreateForPbkdf2(), "dummy"};
   cryptographer_.AddKey(params);
 
@@ -186,9 +186,9 @@
   EXPECT_TRUE(cryptographer_.GetBootstrapToken(encryptor_, &token));
   EXPECT_TRUE(base::IsStringUTF8(token));
 
-  Cryptographer other_cryptographer;
+  DirectoryCryptographer other_cryptographer;
   other_cryptographer.Bootstrap(encryptor_, token);
-  EXPECT_TRUE(other_cryptographer.is_ready());
+  EXPECT_TRUE(other_cryptographer.CanEncrypt());
 
   const char secret[] = "secret";
   sync_pb::EncryptedData encrypted;
@@ -203,7 +203,7 @@
 //
 // Then copy the original cryptographer and ensure it can also decrypt these
 // items and encrypt them with the most recent key.
-TEST_F(CryptographerTest, CopyConstructor) {
+TEST_F(DirectoryCryptographerTest, CopyConstructor) {
   sync_pb::PasswordSpecificsData original;
   original.set_origin("http://example.com");
   original.set_username_value("luser");
@@ -212,14 +212,14 @@
   // Start by testing the original cryptogprapher.
   KeyParams params1 = {KeyDerivationParams::CreateForPbkdf2(), "dummy"};
   EXPECT_TRUE(cryptographer_.AddKey(params1));
-  EXPECT_TRUE(cryptographer_.is_ready());
+  EXPECT_TRUE(cryptographer_.CanEncrypt());
 
   sync_pb::EncryptedData encrypted_k1;
   EXPECT_TRUE(cryptographer_.Encrypt(original, &encrypted_k1));
 
   KeyParams params2 = {KeyDerivationParams::CreateForPbkdf2(), "fatuous"};
   EXPECT_TRUE(cryptographer_.AddKey(params2));
-  EXPECT_TRUE(cryptographer_.is_ready());
+  EXPECT_TRUE(cryptographer_.CanEncrypt());
 
   sync_pb::EncryptedData encrypted_k2;
   EXPECT_TRUE(cryptographer_.Encrypt(original, &encrypted_k2));
@@ -233,13 +233,13 @@
   EXPECT_EQ(original.SerializeAsString(), decrypted_k2.SerializeAsString());
 
   // Clone the cryptographer and test that it behaves the same.
-  Cryptographer cryptographer_clone(cryptographer_);
+  std::unique_ptr<Cryptographer> cryptographer_clone = cryptographer_.Clone();
 
   // The clone should be able to decrypt with old and new keys.
   sync_pb::PasswordSpecificsData decrypted_k1_clone;
   sync_pb::PasswordSpecificsData decrypted_k2_clone;
-  EXPECT_TRUE(cryptographer_clone.Decrypt(encrypted_k1, &decrypted_k1_clone));
-  EXPECT_TRUE(cryptographer_clone.Decrypt(encrypted_k2, &decrypted_k2_clone));
+  EXPECT_TRUE(cryptographer_clone->Decrypt(encrypted_k1, &decrypted_k1_clone));
+  EXPECT_TRUE(cryptographer_clone->Decrypt(encrypted_k2, &decrypted_k2_clone));
 
   EXPECT_EQ(original.SerializeAsString(),
             decrypted_k1_clone.SerializeAsString());
@@ -249,7 +249,7 @@
   // The old cryptographer should be able to decrypt things encrypted by the
   // new.
   sync_pb::EncryptedData encrypted_c;
-  EXPECT_TRUE(cryptographer_clone.Encrypt(original, &encrypted_c));
+  EXPECT_TRUE(cryptographer_clone->Encrypt(original, &encrypted_c));
 
   sync_pb::PasswordSpecificsData decrypted_c;
   EXPECT_TRUE(cryptographer_.Decrypt(encrypted_c, &decrypted_c));
@@ -262,7 +262,7 @@
 // Test verifies that GetBootstrapToken/Bootstrap only transfers default
 // key. Additional call to GetKeys/InstallKeys is needed to transfer keybag
 // to decrypt messages encrypted with old keys.
-TEST_F(CryptographerTest, GetKeysThenInstall) {
+TEST_F(DirectoryCryptographerTest, GetKeysThenInstall) {
   sync_pb::PasswordSpecificsData original;
   original.set_origin("http://example.com");
   original.set_username_value("luser");
@@ -271,20 +271,20 @@
   // First, encrypt the same value using two different keys.
   KeyParams params1 = {KeyDerivationParams::CreateForPbkdf2(), "dummy"};
   EXPECT_TRUE(cryptographer_.AddKey(params1));
-  EXPECT_TRUE(cryptographer_.is_ready());
+  EXPECT_TRUE(cryptographer_.CanEncrypt());
 
   sync_pb::EncryptedData encrypted_k1;
   EXPECT_TRUE(cryptographer_.Encrypt(original, &encrypted_k1));
 
   KeyParams params2 = {KeyDerivationParams::CreateForPbkdf2(), "dummy2"};
   EXPECT_TRUE(cryptographer_.AddKey(params2));
-  EXPECT_TRUE(cryptographer_.is_ready());
+  EXPECT_TRUE(cryptographer_.CanEncrypt());
 
   sync_pb::EncryptedData encrypted_k2;
   EXPECT_TRUE(cryptographer_.Encrypt(original, &encrypted_k2));
 
   // Then construct second cryptographer and bootstrap it from the first one.
-  Cryptographer another_cryptographer;
+  DirectoryCryptographer another_cryptographer;
   std::string bootstrap_token;
   EXPECT_TRUE(cryptographer_.GetBootstrapToken(encryptor_, &bootstrap_token));
   another_cryptographer.Bootstrap(encryptor_, bootstrap_token);
@@ -305,7 +305,8 @@
   EXPECT_TRUE(another_cryptographer.CanDecrypt(encrypted_k2));
 }
 
-TEST_F(CryptographerTest, ShouldConvertToCryptographerDataWithPendingKeys) {
+TEST_F(DirectoryCryptographerTest,
+       ShouldConvertToCryptographerDataWithPendingKeys) {
   const KeyParams kKeyParams = {KeyDerivationParams::CreateForPbkdf2(),
                                 "password1"};
   ASSERT_TRUE(cryptographer_.AddKey(kKeyParams));
diff --git a/components/sync/syncable/nigori_handler.h b/components/sync/syncable/nigori_handler.h
index a437273..7241b15 100644
--- a/components/sync/syncable/nigori_handler.h
+++ b/components/sync/syncable/nigori_handler.h
@@ -16,6 +16,7 @@
 namespace syncer {
 
 class Cryptographer;
+class DirectoryCryptographer;
 enum class PassphraseType;
 
 namespace syncable {
@@ -45,6 +46,11 @@
   virtual const Cryptographer* GetCryptographer(
       const syncable::BaseTransaction* const trans) const = 0;
 
+  // Returns the full-blown DirectoryCryptographer API, available only if the
+  // legacy directory-based implementation of NIGORI is active.
+  virtual const DirectoryCryptographer* GetDirectoryCryptographerForNigori(
+      const syncable::BaseTransaction* const trans) const = 0;
+
   // Returns the set of currently encrypted types.
   virtual ModelTypeSet GetEncryptedTypes(
       const syncable::BaseTransaction* const trans) const = 0;
diff --git a/components/sync/syncable/nigori_handler_proxy.cc b/components/sync/syncable/nigori_handler_proxy.cc
index 86ad6a50..88c5213d 100644
--- a/components/sync/syncable/nigori_handler_proxy.cc
+++ b/components/sync/syncable/nigori_handler_proxy.cc
@@ -4,6 +4,7 @@
 
 #include "components/sync/syncable/nigori_handler_proxy.h"
 
+#include "components/sync/syncable/directory_cryptographer.h"
 #include "components/sync/syncable/syncable_base_transaction.h"
 #include "components/sync/syncable/user_share.h"
 #include "components/sync/syncable/write_transaction.h"
@@ -14,6 +15,7 @@
 
 NigoriHandlerProxy::NigoriHandlerProxy(UserShare* user_share)
     : user_share_(user_share),
+      cryptographer_(std::make_unique<DirectoryCryptographer>()),
       encrypted_types_(SyncEncryptionHandler::SensitiveTypes()),
       passphrase_type_(SyncEncryptionHandler::kInitialPassphraseType) {
   DCHECK(user_share);
@@ -55,7 +57,7 @@
     Cryptographer* cryptographer) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   syncer::WriteTransaction trans(FROM_HERE, user_share_);
-  cryptographer_.CopyFrom(*cryptographer);
+  cryptographer_ = cryptographer->Clone();
 }
 
 void NigoriHandlerProxy::OnPassphraseTypeChanged(PassphraseType type,
@@ -81,7 +83,14 @@
 const Cryptographer* NigoriHandlerProxy::GetCryptographer(
     const syncable::BaseTransaction* const trans) const {
   DCHECK_EQ(user_share_->directory.get(), trans->directory());
-  return &cryptographer_;
+  DCHECK(cryptographer_);
+  return cryptographer_.get();
+}
+
+const DirectoryCryptographer*
+NigoriHandlerProxy::GetDirectoryCryptographerForNigori(
+    const syncable::BaseTransaction* const trans) const {
+  return nullptr;
 }
 
 ModelTypeSet NigoriHandlerProxy::GetEncryptedTypes(
diff --git a/components/sync/syncable/nigori_handler_proxy.h b/components/sync/syncable/nigori_handler_proxy.h
index b4b397c4..d9df74a 100644
--- a/components/sync/syncable/nigori_handler_proxy.h
+++ b/components/sync/syncable/nigori_handler_proxy.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_SYNC_SYNCABLE_NIGORI_HANDLER_PROXY_H_
 #define COMPONENTS_SYNC_SYNCABLE_NIGORI_HANDLER_PROXY_H_
 
+#include <memory>
 #include <string>
 
 #include "base/macros.h"
@@ -59,6 +60,8 @@
       const syncable::BaseTransaction* const trans) const override;
   const Cryptographer* GetCryptographer(
       const syncable::BaseTransaction* const trans) const override;
+  const DirectoryCryptographer* GetDirectoryCryptographerForNigori(
+      const syncable::BaseTransaction* const trans) const override;
   ModelTypeSet GetEncryptedTypes(
       const syncable::BaseTransaction* const trans) const override;
   PassphraseType GetPassphraseType(
@@ -67,7 +70,7 @@
  private:
   UserShare* user_share_;
 
-  Cryptographer cryptographer_;
+  std::unique_ptr<Cryptographer> cryptographer_;
   ModelTypeSet encrypted_types_;
   PassphraseType passphrase_type_;
 
diff --git a/components/sync/syncable/nigori_util.cc b/components/sync/syncable/nigori_util.cc
index 5f4477c..4d2fb24 100644
--- a/components/sync/syncable/nigori_util.cc
+++ b/components/sync/syncable/nigori_util.cc
@@ -25,13 +25,22 @@
 
 namespace syncer {
 namespace syncable {
+namespace {
+
+bool CanDecryptUsingDefaultKey(const Cryptographer& cryptographer,
+                               const sync_pb::EncryptedData& encrypted) {
+  return !encrypted.key_name().empty() &&
+         encrypted.key_name() == cryptographer.GetDefaultEncryptionKeyName();
+}
+
+}  // namespace
 
 bool ProcessUnsyncedChangesForEncryption(WriteTransaction* const trans) {
   NigoriHandler* nigori_handler = trans->directory()->GetNigoriHandler();
   ModelTypeSet encrypted_types = nigori_handler->GetEncryptedTypes(trans);
   const Cryptographer* cryptographer =
       trans->directory()->GetCryptographer(trans);
-  DCHECK(cryptographer->is_ready());
+  DCHECK(cryptographer->CanEncrypt());
 
   // Get list of all datatypes with unsynced changes. It's possible that our
   // local changes need to be encrypted if encryption for that datatype was
@@ -139,7 +148,7 @@
       if (specifics.has_encrypted()) {
         if (child.GetNonUniqueName() != kEncryptedString)
           return false;
-        if (!cryptographer->CanDecryptUsingDefaultKey(specifics.encrypted()))
+        if (!CanDecryptUsingDefaultKey(*cryptographer, specifics.encrypted()))
           return false;
       }
     }
@@ -169,10 +178,14 @@
     NOTREACHED() << "New specifics already has an encrypted blob.";
     return false;
   }
-  if ((!SpecificsNeedsEncryption(encrypted_types, new_specifics) &&
-       !was_encrypted) ||
-      !cryptographer || !cryptographer->is_initialized()) {
-    // No encryption required or we are unable to encrypt.
+  if (!SpecificsNeedsEncryption(encrypted_types, new_specifics) &&
+      !was_encrypted) {
+    // No encryption required.
+    generated_specifics.CopyFrom(new_specifics);
+  } else if (!cryptographer || !cryptographer->CanEncrypt()) {
+    // We are currently unable to encrypt, so store unencrypted. The data will
+    // be reencrypted when the encryption key becomes available, via
+    // SyncEncryptionHandlerImpl::ReEncryptEverything().
     generated_specifics.CopyFrom(new_specifics);
   } else {
     // Encrypt new_specifics into generated_specifics.
diff --git a/components/sync/syncable/test_user_share.cc b/components/sync/syncable/test_user_share.cc
index 8c2140c..78cc401 100644
--- a/components/sync/syncable/test_user_share.cc
+++ b/components/sync/syncable/test_user_share.cc
@@ -58,7 +58,7 @@
   return true;
 }
 
-Cryptographer* TestUserShare::GetCryptographer(
+DirectoryCryptographer* TestUserShare::GetCryptographer(
     const syncable::BaseTransaction* trans) {
   return dir_maker_->GetCryptographer(trans);
 }
diff --git a/components/sync/syncable/test_user_share.h b/components/sync/syncable/test_user_share.h
index b60da8c6..dc5654d 100644
--- a/components/sync/syncable/test_user_share.h
+++ b/components/sync/syncable/test_user_share.h
@@ -15,7 +15,7 @@
 
 namespace syncer {
 
-class Cryptographer;
+class DirectoryCryptographer;
 class KeystoreKeysHandler;
 class SyncEncryptionHandler;
 class TestDirectorySetterUpper;
@@ -67,7 +67,8 @@
   // Save and reload Directory to clear out temporary data in memory.
   bool Reload();
 
-  Cryptographer* GetCryptographer(const syncable::BaseTransaction* trans);
+  DirectoryCryptographer* GetCryptographer(
+      const syncable::BaseTransaction* trans);
 
   // Non-null iff called between a call to SetUp() and TearDown().
   UserShare* user_share();
diff --git a/components/sync/test/engine/mock_connection_manager.cc b/components/sync/test/engine/mock_connection_manager.cc
index cec1ac5..fc954be 100644
--- a/components/sync/test/engine/mock_connection_manager.cc
+++ b/components/sync/test/engine/mock_connection_manager.cc
@@ -146,7 +146,6 @@
   }
   bool result = true;
   EXPECT_TRUE(!store_birthday_sent_ || post.has_store_birthday() ||
-              post.message_contents() == ClientToServerMessage::AUTHENTICATE ||
               post.message_contents() ==
                   ClientToServerMessage::CLEAR_SERVER_DATA);
   store_birthday_sent_ = true;
diff --git a/components/sync/test/engine/mock_connection_manager.h b/components/sync/test/engine/mock_connection_manager.h
index 4640e9f..011dadb 100644
--- a/components/sync/test/engine/mock_connection_manager.h
+++ b/components/sync/test/engine/mock_connection_manager.h
@@ -371,11 +371,6 @@
   // The keystore key we return for a GetUpdates with need_encryption_key set.
   std::string keystore_key_;
 
-  // The AUTHENTICATE response we'll return for auth requests.
-  sync_pb::AuthenticateResponse auth_response_;
-  // What we use to determine if we should return SUCCESS or BAD_AUTH_TOKEN.
-  std::string valid_access_token_;
-
   // Whether we are faking a server mandating clients to throttle requests.
   // Protected by |response_code_override_lock_|.
   bool throttling_;
diff --git a/components/sync/test/engine/test_directory_setter_upper.cc b/components/sync/test/engine/test_directory_setter_upper.cc
index 8d6ecc7..7e15897 100644
--- a/components/sync/test/engine/test_directory_setter_upper.cc
+++ b/components/sync/test/engine/test_directory_setter_upper.cc
@@ -78,7 +78,7 @@
   directory()->FullyCheckTreeInvariants(&trans);
 }
 
-Cryptographer* TestDirectorySetterUpper::GetCryptographer(
+DirectoryCryptographer* TestDirectorySetterUpper::GetCryptographer(
     const syncable::BaseTransaction* trans) {
   DCHECK_EQ(directory_.get(), trans->directory());
   return encryption_handler_.GetMutableCryptographer();
diff --git a/components/sync/test/engine/test_directory_setter_upper.h b/components/sync/test/engine/test_directory_setter_upper.h
index a7cf5b7b1..9d7a8b8 100644
--- a/components/sync/test/engine/test_directory_setter_upper.h
+++ b/components/sync/test/engine/test_directory_setter_upper.h
@@ -65,7 +65,8 @@
   virtual void TearDown();
 
   // Returns mutable version of Cryptographer owned by |encryption_handler_|.
-  Cryptographer* GetCryptographer(const syncable::BaseTransaction* trans);
+  DirectoryCryptographer* GetCryptographer(
+      const syncable::BaseTransaction* trans);
 
   syncable::Directory* directory() { return directory_.get(); }
 
diff --git a/components/sync/test/fake_sync_encryption_handler.cc b/components/sync/test/fake_sync_encryption_handler.cc
index ab37d9f..31afc99 100644
--- a/components/sync/test/fake_sync_encryption_handler.cc
+++ b/components/sync/test/fake_sync_encryption_handler.cc
@@ -45,7 +45,7 @@
       observer.OnPassphraseRequired(REASON_DECRYPTION,
                                     KeyDerivationParams::CreateForPbkdf2(),
                                     pending_keys);
-  } else if (!cryptographer_.is_ready()) {
+  } else if (!cryptographer_.CanEncrypt()) {
     DVLOG(1) << "OnPassphraseRequired sent because cryptographer is not "
              << "ready";
     for (auto& observer : observers_) {
@@ -90,6 +90,12 @@
   return &cryptographer_;
 }
 
+const DirectoryCryptographer*
+FakeSyncEncryptionHandler::GetDirectoryCryptographerForNigori(
+    const syncable::BaseTransaction* const trans) const {
+  return &cryptographer_;
+}
+
 ModelTypeSet FakeSyncEncryptionHandler::GetEncryptedTypes(
     const syncable::BaseTransaction* const trans) const {
   return encrypted_types_;
@@ -139,7 +145,7 @@
   return this;
 }
 
-Cryptographer* FakeSyncEncryptionHandler::GetMutableCryptographer() {
+DirectoryCryptographer* FakeSyncEncryptionHandler::GetMutableCryptographer() {
   return &cryptographer_;
 }
 
diff --git a/components/sync/test/fake_sync_encryption_handler.h b/components/sync/test/fake_sync_encryption_handler.h
index da420dc1..4a341b1 100644
--- a/components/sync/test/fake_sync_encryption_handler.h
+++ b/components/sync/test/fake_sync_encryption_handler.h
@@ -12,8 +12,8 @@
 #include "base/observer_list.h"
 #include "base/time/time.h"
 #include "components/sync/engine/sync_encryption_handler.h"
-#include "components/sync/nigori/cryptographer.h"
 #include "components/sync/nigori/keystore_keys_handler.h"
+#include "components/sync/syncable/directory_cryptographer.h"
 #include "components/sync/syncable/nigori_handler.h"
 
 namespace syncer {
@@ -50,6 +50,8 @@
       const syncable::BaseTransaction* const trans) const override;
   const Cryptographer* GetCryptographer(
       const syncable::BaseTransaction* const trans) const override;
+  const DirectoryCryptographer* GetDirectoryCryptographerForNigori(
+      const syncable::BaseTransaction* const trans) const override;
   ModelTypeSet GetEncryptedTypes(
       const syncable::BaseTransaction* const trans) const override;
   PassphraseType GetPassphraseType(
@@ -60,7 +62,7 @@
   bool SetKeystoreKeys(const std::vector<std::string>& keys) override;
 
   // Own method, used in some tests to manipulate cryptographer directly.
-  Cryptographer* GetMutableCryptographer();
+  DirectoryCryptographer* GetMutableCryptographer();
 
  private:
   base::ObserverList<SyncEncryptionHandler::Observer>::Unchecked observers_;
@@ -68,7 +70,7 @@
   bool encrypt_everything_;
   PassphraseType passphrase_type_;
 
-  Cryptographer cryptographer_;
+  DirectoryCryptographer cryptographer_;
   std::string keystore_key_;
 };
 
diff --git a/components/sync_bookmarks/bookmark_model_associator.cc b/components/sync_bookmarks/bookmark_model_associator.cc
index 649e3ec..1a5fefc8 100644
--- a/components/sync_bookmarks/bookmark_model_associator.cc
+++ b/components/sync_bookmarks/bookmark_model_associator.cc
@@ -940,7 +940,7 @@
   syncer::ReadTransaction trans(FROM_HERE, user_share_);
   const syncer::ModelTypeSet encrypted_types = trans.GetEncryptedTypes();
   return !encrypted_types.Has(syncer::BOOKMARKS) ||
-      trans.GetCryptographer()->is_ready();
+         trans.GetCryptographer()->CanEncrypt();
 }
 
 syncer::SyncError BookmarkModelAssociator::CheckModelSyncState(
diff --git a/components/test/data/payments/render_tests/MicrotransactionRenderTest.button_error_resource.Nexus_5-19.png.sha1 b/components/test/data/payments/render_tests/MicrotransactionRenderTest.button_error_resource.Nexus_5-19.png.sha1
new file mode 100644
index 0000000..2fc1d59
--- /dev/null
+++ b/components/test/data/payments/render_tests/MicrotransactionRenderTest.button_error_resource.Nexus_5-19.png.sha1
@@ -0,0 +1 @@
+2ffcb95d98413c66e0a3effc40e7209795b0e83a
\ No newline at end of file
diff --git a/components/test/data/payments/render_tests/MicrotransactionRenderTest.button_error_resource_expanded.Nexus_5-19.png.sha1 b/components/test/data/payments/render_tests/MicrotransactionRenderTest.button_error_resource_expanded.Nexus_5-19.png.sha1
new file mode 100644
index 0000000..4a76a1b
--- /dev/null
+++ b/components/test/data/payments/render_tests/MicrotransactionRenderTest.button_error_resource_expanded.Nexus_5-19.png.sha1
@@ -0,0 +1 @@
+e1ddf2d0bc4b70ec45ae1eaa47191af60d2b9588
\ No newline at end of file
diff --git a/components/test/data/payments/render_tests/MicrotransactionRenderTest.button_error_string.Nexus_5-19.png.sha1 b/components/test/data/payments/render_tests/MicrotransactionRenderTest.button_error_string.Nexus_5-19.png.sha1
new file mode 100644
index 0000000..56f22eb
--- /dev/null
+++ b/components/test/data/payments/render_tests/MicrotransactionRenderTest.button_error_string.Nexus_5-19.png.sha1
@@ -0,0 +1 @@
+a0799e2686eab6cd19fb3bed34c62e1e25a137a8
\ No newline at end of file
diff --git a/components/test/data/payments/render_tests/MicrotransactionRenderTest.button_error_string_expanded.Nexus_5-19.png.sha1 b/components/test/data/payments/render_tests/MicrotransactionRenderTest.button_error_string_expanded.Nexus_5-19.png.sha1
new file mode 100644
index 0000000..a4524ef
--- /dev/null
+++ b/components/test/data/payments/render_tests/MicrotransactionRenderTest.button_error_string_expanded.Nexus_5-19.png.sha1
@@ -0,0 +1 @@
+362b6166f2477a40d0237ecc170ef3f7f37ace64
\ No newline at end of file
diff --git a/components/test/data/payments/render_tests/MicrotransactionRenderTest.button_initial.Nexus_5-19.png.sha1 b/components/test/data/payments/render_tests/MicrotransactionRenderTest.button_initial.Nexus_5-19.png.sha1
new file mode 100644
index 0000000..7822493
--- /dev/null
+++ b/components/test/data/payments/render_tests/MicrotransactionRenderTest.button_initial.Nexus_5-19.png.sha1
@@ -0,0 +1 @@
+f71440a596cf9b0b089402573e0125e2372a170a
\ No newline at end of file
diff --git a/components/test/data/payments/render_tests/MicrotransactionRenderTest.button_initial_expanded.Nexus_5-19.png.sha1 b/components/test/data/payments/render_tests/MicrotransactionRenderTest.button_initial_expanded.Nexus_5-19.png.sha1
new file mode 100644
index 0000000..75bf03d
--- /dev/null
+++ b/components/test/data/payments/render_tests/MicrotransactionRenderTest.button_initial_expanded.Nexus_5-19.png.sha1
@@ -0,0 +1 @@
+ce49a8a3419025d7ea50a07d8b70731873ada4b4
\ No newline at end of file
diff --git a/components/test/data/payments/render_tests/MicrotransactionRenderTest.button_processing.Nexus_5-19.png.sha1 b/components/test/data/payments/render_tests/MicrotransactionRenderTest.button_processing.Nexus_5-19.png.sha1
new file mode 100644
index 0000000..b6024ac
--- /dev/null
+++ b/components/test/data/payments/render_tests/MicrotransactionRenderTest.button_processing.Nexus_5-19.png.sha1
@@ -0,0 +1 @@
+050b33e82d278745080ec9fe87272fb485148a35
\ No newline at end of file
diff --git a/components/test/data/payments/render_tests/MicrotransactionRenderTest.button_processing_expanded.Nexus_5-19.png.sha1 b/components/test/data/payments/render_tests/MicrotransactionRenderTest.button_processing_expanded.Nexus_5-19.png.sha1
new file mode 100644
index 0000000..ef200e4
--- /dev/null
+++ b/components/test/data/payments/render_tests/MicrotransactionRenderTest.button_processing_expanded.Nexus_5-19.png.sha1
@@ -0,0 +1 @@
+4f97844b18a4bb5de49e9905a483f782855a0512
\ No newline at end of file
diff --git a/components/test/data/payments/render_tests/MicrotransactionRenderTest.button_success.Nexus_5-19.png.sha1 b/components/test/data/payments/render_tests/MicrotransactionRenderTest.button_success.Nexus_5-19.png.sha1
new file mode 100644
index 0000000..8d21e27a
--- /dev/null
+++ b/components/test/data/payments/render_tests/MicrotransactionRenderTest.button_success.Nexus_5-19.png.sha1
@@ -0,0 +1 @@
+4ee5d58a05ea1df7e21428d3c071f3533dcb4320
\ No newline at end of file
diff --git a/components/test/data/payments/render_tests/MicrotransactionRenderTest.button_success_expanded.Nexus_5-19.png.sha1 b/components/test/data/payments/render_tests/MicrotransactionRenderTest.button_success_expanded.Nexus_5-19.png.sha1
new file mode 100644
index 0000000..44807813
--- /dev/null
+++ b/components/test/data/payments/render_tests/MicrotransactionRenderTest.button_success_expanded.Nexus_5-19.png.sha1
@@ -0,0 +1 @@
+e07f3ca6aec1bc7a48ac62df908eb1bbc2f9967e
\ No newline at end of file
diff --git a/components/test/data/payments/render_tests/MicrotransactionRenderTest.fingerprint_error_resource.Nexus_5-19.png.sha1 b/components/test/data/payments/render_tests/MicrotransactionRenderTest.fingerprint_error_resource.Nexus_5-19.png.sha1
new file mode 100644
index 0000000..eaf0958b
--- /dev/null
+++ b/components/test/data/payments/render_tests/MicrotransactionRenderTest.fingerprint_error_resource.Nexus_5-19.png.sha1
@@ -0,0 +1 @@
+01f5b5212714fea6108aa75cd1a763a5c5d2c5fa
\ No newline at end of file
diff --git a/components/test/data/payments/render_tests/MicrotransactionRenderTest.fingerprint_error_resource_expanded.Nexus_5-19.png.sha1 b/components/test/data/payments/render_tests/MicrotransactionRenderTest.fingerprint_error_resource_expanded.Nexus_5-19.png.sha1
new file mode 100644
index 0000000..169cc70
--- /dev/null
+++ b/components/test/data/payments/render_tests/MicrotransactionRenderTest.fingerprint_error_resource_expanded.Nexus_5-19.png.sha1
@@ -0,0 +1 @@
+059a58733a525f89492e1d06541dd595b64e2674
\ No newline at end of file
diff --git a/components/test/data/payments/render_tests/MicrotransactionRenderTest.fingerprint_error_string.Nexus_5-19.png.sha1 b/components/test/data/payments/render_tests/MicrotransactionRenderTest.fingerprint_error_string.Nexus_5-19.png.sha1
new file mode 100644
index 0000000..70e1d181
--- /dev/null
+++ b/components/test/data/payments/render_tests/MicrotransactionRenderTest.fingerprint_error_string.Nexus_5-19.png.sha1
@@ -0,0 +1 @@
+597dedb5aa98d1c7985fd815632477848c435412
\ No newline at end of file
diff --git a/components/test/data/payments/render_tests/MicrotransactionRenderTest.fingerprint_error_string_expanded.Nexus_5-19.png.sha1 b/components/test/data/payments/render_tests/MicrotransactionRenderTest.fingerprint_error_string_expanded.Nexus_5-19.png.sha1
new file mode 100644
index 0000000..2da2fba0
--- /dev/null
+++ b/components/test/data/payments/render_tests/MicrotransactionRenderTest.fingerprint_error_string_expanded.Nexus_5-19.png.sha1
@@ -0,0 +1 @@
+56d31b38e22da4c2399c5491cccd397c27945196
\ No newline at end of file
diff --git a/components/test/data/payments/render_tests/MicrotransactionRenderTest.fingerprint_initial.Nexus_5-19.png.sha1 b/components/test/data/payments/render_tests/MicrotransactionRenderTest.fingerprint_initial.Nexus_5-19.png.sha1
new file mode 100644
index 0000000..3369e0b1
--- /dev/null
+++ b/components/test/data/payments/render_tests/MicrotransactionRenderTest.fingerprint_initial.Nexus_5-19.png.sha1
@@ -0,0 +1 @@
+12c6daa5fbfea11eb7a7c239440b2585eae3d777
\ No newline at end of file
diff --git a/components/test/data/payments/render_tests/MicrotransactionRenderTest.fingerprint_initial_expanded.Nexus_5-19.png.sha1 b/components/test/data/payments/render_tests/MicrotransactionRenderTest.fingerprint_initial_expanded.Nexus_5-19.png.sha1
new file mode 100644
index 0000000..37e9d8f
--- /dev/null
+++ b/components/test/data/payments/render_tests/MicrotransactionRenderTest.fingerprint_initial_expanded.Nexus_5-19.png.sha1
@@ -0,0 +1 @@
+cbcc9055beee80114ba66035ba34f473ae168467
\ No newline at end of file
diff --git a/components/test/data/payments/render_tests/MicrotransactionRenderTest.fingerprint_processing.Nexus_5-19.png.sha1 b/components/test/data/payments/render_tests/MicrotransactionRenderTest.fingerprint_processing.Nexus_5-19.png.sha1
new file mode 100644
index 0000000..e3a6605
--- /dev/null
+++ b/components/test/data/payments/render_tests/MicrotransactionRenderTest.fingerprint_processing.Nexus_5-19.png.sha1
@@ -0,0 +1 @@
+792edcbad644e560aab2e309daf3ea9fe3166ada
\ No newline at end of file
diff --git a/components/test/data/payments/render_tests/MicrotransactionRenderTest.fingerprint_processing_expanded.Nexus_5-19.png.sha1 b/components/test/data/payments/render_tests/MicrotransactionRenderTest.fingerprint_processing_expanded.Nexus_5-19.png.sha1
new file mode 100644
index 0000000..aee05d4
--- /dev/null
+++ b/components/test/data/payments/render_tests/MicrotransactionRenderTest.fingerprint_processing_expanded.Nexus_5-19.png.sha1
@@ -0,0 +1 @@
+fdd6f1becf73f7f50bd8eec9c530ccb65c95414c
\ No newline at end of file
diff --git a/components/test/data/payments/render_tests/MicrotransactionRenderTest.fingerprint_success.Nexus_5-19.png.sha1 b/components/test/data/payments/render_tests/MicrotransactionRenderTest.fingerprint_success.Nexus_5-19.png.sha1
new file mode 100644
index 0000000..342cde3
--- /dev/null
+++ b/components/test/data/payments/render_tests/MicrotransactionRenderTest.fingerprint_success.Nexus_5-19.png.sha1
@@ -0,0 +1 @@
+7b74244d173e0b7540671faab1f8047812b8a8d6
\ No newline at end of file
diff --git a/components/test/data/payments/render_tests/MicrotransactionRenderTest.fingerprint_success_expanded.Nexus_5-19.png.sha1 b/components/test/data/payments/render_tests/MicrotransactionRenderTest.fingerprint_success_expanded.Nexus_5-19.png.sha1
new file mode 100644
index 0000000..d1200af
--- /dev/null
+++ b/components/test/data/payments/render_tests/MicrotransactionRenderTest.fingerprint_success_expanded.Nexus_5-19.png.sha1
@@ -0,0 +1 @@
+c513c5a353ac108a5499454a404f23d491b0a434
\ No newline at end of file
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
index 5af4454..e114ed06 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -784,26 +784,8 @@
 
 void SkiaOutputSurfaceImplOnGpu::ScheduleOutputSurfaceAsOverlay(
     const OverlayProcessor::OutputSurfaceOverlayPlane& output_surface_plane) {
-  DCHECK(!is_using_vulkan());
-
-  if (!MakeCurrent(!dependency_->IsOffscreen() /* need_fbo0 */))
-    return;
-
-  gl::GLImage* image = output_device_->GetOverlayImage();
-  std::unique_ptr<gfx::GpuFence> gpu_fence =
-      output_device_->SubmitOverlayGpuFence();
-
-  if (image) {
-    // Output surface is also z-order 0.
-    int plane_z_order = 0;
-    // Output surface always uses the full texture.
-    gfx::RectF uv_rect(0.f, 0.f, 1.f, 1.f);
-
-    gl_surface_->ScheduleOverlayPlane(
-        plane_z_order, output_surface_plane.transform, image,
-        ToNearestRect(output_surface_plane.display_rect), uv_rect,
-        output_surface_plane.enable_blending, std::move(gpu_fence));
-  }
+  DCHECK(!output_surface_plane_);
+  output_surface_plane_ = output_surface_plane;
 }
 
 void SkiaOutputSurfaceImplOnGpu::SwapBuffers(
@@ -824,6 +806,25 @@
 
   scoped_output_device_paint_.reset();
 
+  if (output_surface_plane_) {
+    DCHECK(!is_using_vulkan());
+    if (gl::GLImage* image = output_device_->GetOverlayImage()) {
+      std::unique_ptr<gfx::GpuFence> gpu_fence =
+          output_device_->SubmitOverlayGpuFence();
+
+      // Output surface is also z-order 0.
+      int plane_z_order = 0;
+      // Output surface always uses the full texture.
+      gfx::RectF uv_rect(0.f, 0.f, 1.f, 1.f);
+
+      gl_surface_->ScheduleOverlayPlane(
+          plane_z_order, output_surface_plane_->transform, image,
+          ToNearestRect(output_surface_plane_->display_rect), uv_rect,
+          output_surface_plane_->enable_blending, std::move(gpu_fence));
+    }
+    output_surface_plane_.reset();
+  }
+
   if (frame.sub_buffer_rect && frame.sub_buffer_rect->IsEmpty()) {
     // Call SwapBuffers() to present overlays.
     output_device_->SwapBuffers(buffer_presented_callback_,
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
index ac48dab8..d229302 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
@@ -241,6 +241,9 @@
   std::unique_ptr<SkiaOutputDevice> output_device_;
   base::Optional<SkiaOutputDevice::ScopedPaint> scoped_output_device_paint_;
 
+  base::Optional<OverlayProcessor::OutputSurfaceOverlayPlane>
+      output_surface_plane_;
+
   // Offscreen surfaces for render passes. It can only be accessed on GPU
   // thread.
   class OffscreenSurface {
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
index ae504a5..ca88cdf6 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -9,6 +9,8 @@
 #include <stdint.h>
 #include <string.h>
 
+#include <algorithm>
+#include <iterator>
 #include <map>
 #include <memory>
 #include <utility>
@@ -370,6 +372,38 @@
   return AXPlatformRange(std::move(anchor), std::move(focus));
 }
 
+AXPlatformRange GetSelectedRange(BrowserAccessibility& owner) {
+  const BrowserAccessibilityManager* manager = owner.manager();
+  if (!manager)
+    return {};
+
+  const ui::AXTree::Selection unignored_selection =
+      manager->ax_tree()->GetUnignoredSelection();
+  int32_t anchor_id = unignored_selection.anchor_object_id;
+  const BrowserAccessibility* anchor_object = manager->GetFromID(anchor_id);
+  if (!anchor_object)
+    return {};
+
+  int32_t focus_id = unignored_selection.focus_object_id;
+  const BrowserAccessibility* focus_object = manager->GetFromID(focus_id);
+  if (!focus_object)
+    return {};
+
+  // |anchor_offset| and / or |focus_offset| refer to a character offset if
+  // |anchor_object| / |focus_object| are text-only objects or native text
+  // fields. Otherwise, they should be treated as child indices.
+  int anchor_offset = unignored_selection.anchor_offset;
+  int focus_offset = unignored_selection.focus_offset;
+  DCHECK_GE(anchor_offset, 0);
+  DCHECK_GE(focus_offset, 0);
+
+  ax::mojom::TextAffinity anchor_affinity = unignored_selection.anchor_affinity;
+  ax::mojom::TextAffinity focus_affinity = unignored_selection.focus_affinity;
+
+  return CreateAXPlatformRange(*anchor_object, anchor_offset, anchor_affinity,
+                               *focus_object, focus_offset, focus_affinity);
+}
+
 void AddMisspelledTextAttributes(const AXPlatformRange& ax_range,
                                  NSMutableAttributedString* attributed_string) {
   int anchor_start_offset = 0;
@@ -826,11 +860,10 @@
 - (NSNumber*)ariaColumnIndex {
   if (![self instanceActive])
     return nil;
-  base::Optional<int> aria_col_index =
-      owner_->node()->GetTableCellAriaColIndex();
-  if (!aria_col_index)
+  base::Optional<int> ariaColIndex = owner_->node()->GetTableCellAriaColIndex();
+  if (!ariaColIndex)
     return nil;
-  return [NSNumber numberWithInt:*aria_col_index];
+  return [NSNumber numberWithInt:*ariaColIndex];
 }
 
 - (NSString*)ariaLive {
@@ -843,10 +876,10 @@
 - (NSNumber*)ariaPosInSet {
   if (![self instanceActive])
     return nil;
-  base::Optional<int> pos_in_set = owner_->node()->GetPosInSet();
-  if (!pos_in_set)
+  base::Optional<int> posInSet = owner_->node()->GetPosInSet();
+  if (!posInSet)
     return nil;
-  return [NSNumber numberWithInt:*pos_in_set];
+  return [NSNumber numberWithInt:*posInSet];
 }
 
 - (NSString*)ariaRelevant {
@@ -859,29 +892,28 @@
 - (NSNumber*)ariaRowCount {
   if (![self instanceActive])
     return nil;
-  base::Optional<int> aria_row_count = owner_->node()->GetTableAriaRowCount();
-  if (!aria_row_count)
+  base::Optional<int> ariaRowCount = owner_->node()->GetTableAriaRowCount();
+  if (!ariaRowCount)
     return nil;
-  return [NSNumber numberWithInt:*aria_row_count];
+  return [NSNumber numberWithInt:*ariaRowCount];
 }
 
 - (NSNumber*)ariaRowIndex {
   if (![self instanceActive])
     return nil;
-  base::Optional<int> aria_row_index =
-      owner_->node()->GetTableCellAriaRowIndex();
-  if (!aria_row_index)
+  base::Optional<int> ariaRowIndex = owner_->node()->GetTableCellAriaRowIndex();
+  if (!ariaRowIndex)
     return nil;
-  return [NSNumber numberWithInt:*aria_row_index];
+  return [NSNumber numberWithInt:*ariaRowIndex];
 }
 
 - (NSNumber*)ariaSetSize {
   if (![self instanceActive])
     return nil;
-  base::Optional<int> set_size = owner_->node()->GetSetSize();
-  if (!set_size)
+  base::Optional<int> setSize = owner_->node()->GetSetSize();
+  if (!setSize)
     return nil;
-  return [NSNumber numberWithInt:*set_size];
+  return [NSNumber numberWithInt:*setSize];
 }
 
 - (NSString*)autocompleteValue {
@@ -1396,25 +1428,24 @@
 - (NSNumber*)insertionPointLineNumber {
   if (![self instanceActive])
     return nil;
-
-  // TODO(nektar): Deprecate sel_start and sel_end attributes.
-  int selStart, selEnd;
-  if (!owner_->GetIntAttribute(ax::mojom::IntAttribute::kTextSelStart,
-                               &selStart) ||
-      !owner_->GetIntAttribute(ax::mojom::IntAttribute::kTextSelEnd, &selEnd)) {
+  if (!owner_->HasVisibleCaretOrSelection())
     return nil;
-  }
 
-  if (selStart > selEnd)
-    std::swap(selStart, selEnd);
+  const AXPlatformRange range = GetSelectedRange(*owner_);
+  // If the selection is not collapsed, then there is no visible caret.
+  if (!range.IsCollapsed())
+    return nil;
 
-  const std::vector<int> line_breaks = owner_->GetLineStartOffsets();
-  for (int i = 0; i < static_cast<int>(line_breaks.size()); ++i) {
-    if (line_breaks[i] > selStart)
-      return [NSNumber numberWithInt:i];
-  }
-
-  return [NSNumber numberWithInt:static_cast<int>(line_breaks.size())];
+  const BrowserAccessibilityPositionInstance caretPosition =
+      range.focus()->LowestCommonAncestor(*owner_->CreatePositionAt(0));
+  DCHECK(!caretPosition->IsNullPosition())
+      << "Calling HasVisibleCaretOrSelection() should have ensured that there "
+         "is a valid selection focus inside the current object.";
+  const std::vector<int> lineBreaks = owner_->GetLineStartOffsets();
+  auto iterator =
+      std::upper_bound(lineBreaks.begin(), lineBreaks.end(),
+                       caretPosition->AsTextPosition()->text_offset());
+  return @(std::distance(lineBreaks.begin(), iterator));
 }
 
 // Returns whether or not this node should be ignored in the
@@ -2083,79 +2114,44 @@
 - (NSString*)selectedText {
   if (![self instanceActive])
     return nil;
-
-  // TODO(nektar): Deprecate sel_start and sel_end attributes.
-  int selStart, selEnd;
-  if (!owner_->GetIntAttribute(ax::mojom::IntAttribute::kTextSelStart,
-                               &selStart) ||
-      !owner_->GetIntAttribute(ax::mojom::IntAttribute::kTextSelEnd, &selEnd)) {
+  if (!owner_->HasVisibleCaretOrSelection())
     return nil;
-  }
 
-  if (selStart > selEnd)
-    std::swap(selStart, selEnd);
-
-  int selLength = selEnd - selStart;
-  base::string16 value = owner_->GetValue();
-  return base::SysUTF16ToNSString(value.substr(selStart, selLength));
+  const AXPlatformRange range = GetSelectedRange(*owner_);
+  if (range.IsNull())
+    return nil;
+  return base::SysUTF16ToNSString(range.GetText());
 }
 
+// Returns range of text under the current object that is selected.
+//
 // Example, caret at offset 5:
-// AXSelectedTextRange:  “pos=5 len=0”
+// NSRange:  “pos=5 len=0”
 - (NSValue*)selectedTextRange {
   if (![self instanceActive])
     return nil;
-
-  // TODO(nektar): Deprecate sel_start and sel_end attributes.
-  int selStart, selEnd;
-  if (!owner_->GetIntAttribute(ax::mojom::IntAttribute::kTextSelStart,
-                               &selStart) ||
-      !owner_->GetIntAttribute(ax::mojom::IntAttribute::kTextSelEnd, &selEnd)) {
-    // TODO(accessibility) Incorrectly reaches this line in a rich text area.
+  if (!owner_->HasVisibleCaretOrSelection())
     return nil;
-  }
 
-  if (selStart > selEnd)
-    std::swap(selStart, selEnd);
+  const AXPlatformRange range = GetSelectedRange(*owner_).AsForwardRange();
+  if (range.IsNull())
+    return nil;
 
-  int selLength = selEnd - selStart;
+  const BrowserAccessibilityPositionInstance startPosition =
+      range.anchor()->LowestCommonAncestor(*owner_->CreatePositionAt(0));
+  DCHECK(!startPosition->IsNullPosition())
+      << "Calling HasVisibleCaretOrSelection() should have ensured that there "
+         "is a valid selection anchor inside the current object.";
+  int selStart = startPosition->AsTextPosition()->text_offset();
+  DCHECK_GE(selStart, 0);
+  int selLength = range.GetText().length();
   return [NSValue valueWithRange:NSMakeRange(selStart, selLength)];
 }
 
 - (id)selectedTextMarkerRange {
   if (![self instanceActive])
     return nil;
-
-  BrowserAccessibilityManager* manager = owner_->manager();
-  if (!manager)
-    return nil;
-
-  ui::AXTree::Selection unignored_selection =
-      manager->ax_tree()->GetUnignoredSelection();
-  int32_t anchorId = unignored_selection.anchor_object_id;
-  const BrowserAccessibility* anchorObject = manager->GetFromID(anchorId);
-  if (!anchorObject)
-    return nil;
-
-  int32_t focusId = unignored_selection.focus_object_id;
-  const BrowserAccessibility* focusObject = manager->GetFromID(focusId);
-  if (!focusObject)
-    return nil;
-
-  // |anchorOffset| and / or |focusOffset| refer to a character offset if
-  // |anchorObject| / |focusObject| are text-only objects. Otherwise, they
-  // should be treated as child indices.
-  int anchorOffset = unignored_selection.anchor_offset;
-  int focusOffset = unignored_selection.focus_offset;
-  if (anchorOffset < 0 || focusOffset < 0)
-    return nil;
-
-  ax::mojom::TextAffinity anchorAffinity = unignored_selection.anchor_affinity;
-  ax::mojom::TextAffinity focusAffinity = unignored_selection.focus_affinity;
-
-  return CreateTextMarkerRange(
-      CreateAXPlatformRange(*anchorObject, anchorOffset, anchorAffinity,
-                            *focusObject, focusOffset, focusAffinity));
+  return CreateTextMarkerRange(GetSelectedRange(*owner_));
 }
 
 - (NSValue*)size {
@@ -2519,9 +2515,11 @@
   if (![self instanceActive])
     return nil;
 
-  const std::vector<int> line_breaks = owner_->GetLineStartOffsets();
+  const std::vector<int> lineBreaks = owner_->GetLineStartOffsets();
   base::string16 value = owner_->GetValue();
-  int len = static_cast<int>(value.size());
+  if (owner_->IsTextOnlyObject() && value.empty())
+    value = owner_->GetText();
+  int valueLength = static_cast<int>(value.size());
 
   if ([attribute isEqualToString:
                      NSAccessibilityStringForRangeParameterizedAttribute]) {
@@ -2536,22 +2534,21 @@
 
   if ([attribute
           isEqualToString:NSAccessibilityLineForIndexParameterizedAttribute]) {
-    int index = [(NSNumber*)parameter intValue];
-    for (int i = 0; i < static_cast<int>(line_breaks.size()); ++i) {
-      if (line_breaks[i] > index)
-        return [NSNumber numberWithInt:i];
-    }
-    return [NSNumber numberWithInt:static_cast<int>(line_breaks.size())];
+    int lineIndex = [(NSNumber*)parameter intValue];
+    auto iterator =
+        std::upper_bound(lineBreaks.begin(), lineBreaks.end(), lineIndex);
+    return @(std::distance(lineBreaks.begin(), iterator));
   }
 
   if ([attribute
           isEqualToString:NSAccessibilityRangeForLineParameterizedAttribute]) {
-    int line_index = [(NSNumber*)parameter intValue];
-    int line_count = static_cast<int>(line_breaks.size()) + 1;
-    if (line_index < 0 || line_index >= line_count)
+    int lineIndex = [(NSNumber*)parameter intValue];
+    int lineCount = static_cast<int>(lineBreaks.size()) + 1;
+    if (lineIndex < 0 || lineIndex >= lineCount)
       return nil;
-    int start = line_index > 0 ? line_breaks[line_index - 1] : 0;
-    int end = line_index < line_count - 1 ? line_breaks[line_index] : len;
+    int start = (lineIndex > 0) ? lineBreaks[lineIndex - 1] : 0;
+    int end =
+        (lineIndex < (lineCount - 1)) ? lineBreaks[lineIndex] : valueLength;
     return [NSValue valueWithRange:NSMakeRange(start, end - start)];
   }
 
@@ -2568,11 +2565,11 @@
     int column = [[array objectAtIndex:0] intValue];
     int row = [[array objectAtIndex:1] intValue];
 
-    ui::AXNode* cell_node = owner_->node()->GetTableCellFromCoords(row, column);
-    if (!cell_node)
+    ui::AXNode* cellNode = owner_->node()->GetTableCellFromCoords(row, column);
+    if (!cellNode)
       return nil;
 
-    BrowserAccessibility* cell = owner_->manager()->GetFromID(cell_node->id());
+    BrowserAccessibility* cell = owner_->manager()->GetFromID(cellNode->id());
     if (cell)
       return ToBrowserAccessibilityCocoa(cell);
   }
@@ -2696,21 +2693,42 @@
         ui::AXBoundaryBehavior::CrossBoundary));
   }
 
-  if ([attribute
-          isEqualToString:
-              NSAccessibilityTextMarkerRangeForLineParameterizedAttribute]) {
+  if ([attribute isEqualToString:
+                     NSAccessibilityLineForTextMarkerParameterizedAttribute]) {
     BrowserAccessibilityPositionInstance position =
         CreatePositionFromTextMarker(parameter);
     if (position->IsNullPosition())
       return nil;
 
-    BrowserAccessibilityPositionInstance startPosition =
-        position->CreatePreviousLineStartPosition(
-            ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary);
-    BrowserAccessibilityPositionInstance endPosition =
-        position->CreateNextLineEndPosition(
-            ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary);
-    AXPlatformRange range(std::move(startPosition), std::move(endPosition));
+    int textOffset = position->AsTextPosition()->text_offset();
+    const auto iterator =
+        std::upper_bound(lineBreaks.begin(), lineBreaks.end(), textOffset);
+    return @(std::distance(lineBreaks.begin(), iterator));
+  }
+
+  if ([attribute
+          isEqualToString:
+              NSAccessibilityTextMarkerRangeForLineParameterizedAttribute]) {
+    int lineIndex = [(NSNumber*)parameter intValue];
+    int lineCount = static_cast<int>(lineBreaks.size()) + 1;
+    if (lineIndex < 0 || lineIndex >= lineCount)
+      return nil;
+
+    int lineStartOffset = (lineIndex > 0) ? lineBreaks[lineIndex - 1] : 0;
+    BrowserAccessibilityPositionInstance lineStartPosition = CreateTextPosition(
+        *owner_, lineStartOffset, ax::mojom::TextAffinity::kDownstream);
+    if (lineStartPosition->IsNullPosition())
+      return nil;
+
+    // Make sure that the line start position is really at the start of the
+    // current line.
+    lineStartPosition = lineStartPosition->CreatePreviousLineStartPosition(
+        ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+    BrowserAccessibilityPositionInstance lineEndPosition =
+        lineStartPosition->CreateNextLineEndPosition(
+            ui::AXBoundaryBehavior::StopAtAnchorBoundary);
+    AXPlatformRange range(std::move(lineStartPosition),
+                          std::move(lineEndPosition));
     return CreateTextMarkerRange(std::move(range));
   }
 
@@ -2948,14 +2966,14 @@
     if (![parameter isKindOfClass:[NSArray class]])
       return nil;
 
-    NSArray* text_marker_array = parameter;
-    if ([text_marker_array count] != 2)
+    NSArray* textMarkerArray = parameter;
+    if ([textMarkerArray count] != 2)
       return nil;
 
     BrowserAccessibilityPositionInstance startPosition =
-        CreatePositionFromTextMarker([text_marker_array objectAtIndex:0]);
+        CreatePositionFromTextMarker([textMarkerArray objectAtIndex:0]);
     BrowserAccessibilityPositionInstance endPosition =
-        CreatePositionFromTextMarker([text_marker_array objectAtIndex:1]);
+        CreatePositionFromTextMarker([textMarkerArray objectAtIndex:1]);
     if (*startPosition <= *endPosition) {
       return CreateTextMarkerRange(
           AXPlatformRange(std::move(startPosition), std::move(endPosition)));
diff --git a/content/browser/background_sync/background_sync_manager.cc b/content/browser/background_sync/background_sync_manager.cc
index a93f4dd..3566b94 100644
--- a/content/browser/background_sync/background_sync_manager.cc
+++ b/content/browser/background_sync/background_sync_manager.cc
@@ -2331,6 +2331,9 @@
 void BackgroundSyncManager::OnNetworkChanged() {
   DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
 
+  if (!AreOptionConditionsMet())
+    return;
+
   FireReadyEvents(BackgroundSyncType::ONE_SHOT, /* reschedule= */ true,
                   base::DoNothing::Once());
   FireReadyEvents(BackgroundSyncType::PERIODIC, /* reschedule= */ true,
diff --git a/content/browser/browser_interface_binders.cc b/content/browser/browser_interface_binders.cc
index 858ce3ba..b1d73727 100644
--- a/content/browser/browser_interface_binders.cc
+++ b/content/browser/browser_interface_binders.cc
@@ -4,7 +4,9 @@
 
 #include "content/browser/browser_interface_binders.h"
 
+#include "build/build_config.h"
 #include "content/browser/background_fetch/background_fetch_service_impl.h"
+#include "content/browser/content_index/content_index_service_impl.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/image_capture/image_capture_impl.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
@@ -17,6 +19,8 @@
 #include "media/capture/mojom/image_capture.mojom.h"
 #include "third_party/blink/public/mojom/appcache/appcache.mojom.h"
 #include "third_party/blink/public/mojom/background_fetch/background_fetch.mojom.h"
+#include "third_party/blink/public/mojom/bluetooth/web_bluetooth.mojom.h"
+#include "third_party/blink/public/mojom/content_index/content_index.mojom.h"
 #include "third_party/blink/public/mojom/filesystem/file_system.mojom.h"
 #include "third_party/blink/public/mojom/idle/idle_manager.mojom.h"
 #include "third_party/blink/public/mojom/locks/lock_manager.mojom.h"
@@ -24,6 +28,10 @@
 #include "third_party/blink/public/mojom/speech/speech_synthesis.mojom.h"
 #include "third_party/blink/public/mojom/webaudio/audio_context_manager.mojom.h"
 
+#if !defined(OS_ANDROID)
+#include "third_party/blink/public/mojom/hid/hid.mojom.h"
+#endif
+
 namespace content {
 namespace internal {
 
@@ -36,9 +44,17 @@
   map->Add<blink::mojom::AudioContextManager>(base::BindRepeating(
       &RenderFrameHostImpl::GetAudioContextManager, base::Unretained(host)));
 
+  map->Add<blink::mojom::ContactsManager>(base::BindRepeating(
+      &RenderFrameHostImpl::GetContactsManager, base::Unretained(host)));
+
   map->Add<blink::mojom::FileSystemManager>(base::BindRepeating(
       &RenderFrameHostImpl::GetFileSystemManager, base::Unretained(host)));
 
+#if !defined(OS_ANDROID)
+  map->Add<blink::mojom::HidService>(base::BindRepeating(
+      &RenderFrameHostImpl::GetHidService, base::Unretained(host)));
+#endif
+
   map->Add<blink::mojom::IdleManager>(base::BindRepeating(
       &RenderFrameHostImpl::GetIdleManager, base::Unretained(host)));
 
@@ -59,6 +75,9 @@
 
   map->Add<media::mojom::ImageCapture>(
       base::BindRepeating(&ImageCaptureImpl::Create));
+
+  map->Add<blink::mojom::WebBluetoothService>(base::BindRepeating(
+      &RenderFrameHostImpl::CreateWebBluetoothService, base::Unretained(host)));
 }
 
 void PopulateBinderMapWithContext(
@@ -66,6 +85,8 @@
     service_manager::BinderMapWithContext<RenderFrameHost*>* map) {
   map->Add<blink::mojom::BackgroundFetchService>(
       base::BindRepeating(&BackgroundFetchServiceImpl::CreateForFrame));
+  map->Add<blink::mojom::ContentIndexService>(
+      base::BindRepeating(&ContentIndexServiceImpl::CreateForFrame));
   GetContentClient()->browser()->RegisterBrowserInterfaceBindersForFrame(map);
 }
 
@@ -168,10 +189,15 @@
   if (ServiceWorkerContext::IsServiceWorkerOnUIEnabled()) {
     map->Add<blink::mojom::BackgroundFetchService>(
         base::BindRepeating(&BackgroundFetchServiceImpl::CreateForWorker));
+    map->Add<blink::mojom::ContentIndexService>(
+        base::BindRepeating(&ContentIndexServiceImpl::CreateForWorker));
   } else {
     map->Add<blink::mojom::BackgroundFetchService>(
         base::BindRepeating(&BackgroundFetchServiceImpl::CreateForWorker),
         base::CreateSingleThreadTaskRunner(BrowserThread::UI));
+    map->Add<blink::mojom::ContentIndexService>(
+        base::BindRepeating(&ContentIndexServiceImpl::CreateForWorker),
+        base::CreateSingleThreadTaskRunner(BrowserThread::UI));
   }
 }
 
diff --git a/content/browser/content_index/content_index_service_impl.cc b/content/browser/content_index/content_index_service_impl.cc
index feab6d2..314dc6a 100644
--- a/content/browser/content_index/content_index_service_impl.cc
+++ b/content/browser/content_index/content_index_service_impl.cc
@@ -19,18 +19,40 @@
 namespace content {
 
 // static
-void ContentIndexServiceImpl::Create(
-    mojo::PendingReceiver<blink::mojom::ContentIndexService> receiver,
-    RenderProcessHost* render_process_host,
-    const url::Origin& origin) {
+void ContentIndexServiceImpl::CreateForFrame(
+    RenderFrameHost* render_frame_host,
+    mojo::PendingReceiver<blink::mojom::ContentIndexService> receiver) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
+  RenderProcessHost* render_process_host = render_frame_host->GetProcess();
+  DCHECK(render_process_host);
+  auto* storage_partition = static_cast<StoragePartitionImpl*>(
+      render_process_host->GetStoragePartition());
+
+  mojo::MakeSelfOwnedReceiver(std::make_unique<ContentIndexServiceImpl>(
+                                  render_frame_host->GetLastCommittedOrigin(),
+                                  storage_partition->GetContentIndexContext()),
+                              std::move(receiver));
+}
+
+// static
+void ContentIndexServiceImpl::CreateForWorker(
+    const ServiceWorkerVersionInfo& info,
+    mojo::PendingReceiver<blink::mojom::ContentIndexService> receiver) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  RenderProcessHost* render_process_host =
+      RenderProcessHost::FromID(info.process_id);
+
+  if (!render_process_host)
+    return;
+
   auto* storage_partition = static_cast<StoragePartitionImpl*>(
       render_process_host->GetStoragePartition());
 
   mojo::MakeSelfOwnedReceiver(
       std::make_unique<ContentIndexServiceImpl>(
-          origin, storage_partition->GetContentIndexContext()),
+          info.script_origin, storage_partition->GetContentIndexContext()),
       std::move(receiver));
 }
 
diff --git a/content/browser/content_index/content_index_service_impl.h b/content/browser/content_index/content_index_service_impl.h
index 172936a..863bbe6 100644
--- a/content/browser/content_index/content_index_service_impl.h
+++ b/content/browser/content_index/content_index_service_impl.h
@@ -15,17 +15,21 @@
 
 namespace content {
 
-class RenderProcessHost;
+class RenderFrameHost;
+struct ServiceWorkerVersionInfo;
 
 // Lazily constructed by the corresponding renderer when the Content Index API
 // is triggered.
 class CONTENT_EXPORT ContentIndexServiceImpl
     : public blink::mojom::ContentIndexService {
  public:
-  static void Create(
-      mojo::PendingReceiver<blink::mojom::ContentIndexService> receiver,
-      RenderProcessHost* render_process_host,
-      const url::Origin& origin);
+  static void CreateForFrame(
+      RenderFrameHost* render_frame_host,
+      mojo::PendingReceiver<blink::mojom::ContentIndexService> receiver);
+
+  static void CreateForWorker(
+      const ServiceWorkerVersionInfo& info,
+      mojo::PendingReceiver<blink::mojom::ContentIndexService> receiver);
 
   ContentIndexServiceImpl(
       const url::Origin& origin,
diff --git a/content/browser/devtools/protocol/tracing_handler.cc b/content/browser/devtools/protocol/tracing_handler.cc
index 51069f5..7730d55d 100644
--- a/content/browser/devtools/protocol/tracing_handler.cc
+++ b/content/browser/devtools/protocol/tracing_handler.cc
@@ -985,6 +985,7 @@
       ->RequestGlobalDumpAndAppendToTrace(
           base::trace_event::MemoryDumpType::EXPLICITLY_TRIGGERED,
           base::trace_event::MemoryDumpLevelOfDetail::DETAILED,
+          base::trace_event::MemoryDumpDeterminism::NONE,
           std::move(on_memory_dump_finished));
 }
 
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index 441f632..61336b0 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -451,74 +451,103 @@
     RenderFrameHostImpl* new_rfh,
     const mojom::CommonNavigationParams& common_params,
     base::TimeTicks ready_to_commit_time) {
+  bool is_main_frame = !new_rfh->GetParent();
   bool is_same_process =
       old_rfh->GetProcess()->GetID() == new_rfh->GetProcess()->GetID();
 
-  bool is_same_browsing_instance =
-      old_rfh->GetSiteInstance()->IsRelatedSiteInstance(
-          new_rfh->GetSiteInstance());
+  // Navigation.IsSameBrowsingInstance
+  if (is_main_frame) {
+    bool is_same_browsing_instance =
+        old_rfh->GetSiteInstance()->IsRelatedSiteInstance(
+            new_rfh->GetSiteInstance());
 
-  bool is_same_site_instance =
-      old_rfh->GetSiteInstance() == new_rfh->GetSiteInstance();
-
-  // Log overall value, then log specific value per type of navigation.
-  UMA_HISTOGRAM_BOOLEAN("Navigation.IsSameProcess", is_same_process);
-  UMA_HISTOGRAM_BOOLEAN("Navigation.IsSameSiteInstance", is_same_site_instance);
-  UMA_HISTOGRAM_BOOLEAN("Navigation.IsSameBrowsingInstance",
-                        is_same_browsing_instance);
-
-  UMA_HISTOGRAM_BOOLEAN("Navigation.RequiresDedicatedProcess",
-                        new_rfh->GetSiteInstance()->RequiresDedicatedProcess());
-  if (common_params.url.SchemeIsHTTPOrHTTPS()) {
-    UMA_HISTOGRAM_BOOLEAN(
-        "Navigation.RequiresDedicatedProcess.HTTPOrHTTPS",
-        new_rfh->GetSiteInstance()->RequiresDedicatedProcess());
+    UMA_HISTOGRAM_BOOLEAN("Navigation.IsSameBrowsingInstance",
+                          is_same_browsing_instance);
   }
 
-  ChildProcessSecurityPolicyImpl* policy =
-      ChildProcessSecurityPolicyImpl::GetInstance();
-  GURL process_lock = policy->GetOriginLock(new_rfh->GetProcess()->GetID());
-  UMA_HISTOGRAM_BOOLEAN("Navigation.IsLockedProcess", !process_lock.is_empty());
-  if (common_params.url.SchemeIsHTTPOrHTTPS()) {
-    UMA_HISTOGRAM_BOOLEAN("Navigation.IsLockedProcess.HTTPOrHTTPS",
+  // Navigation.IsSameSiteInstance
+  {
+    bool is_same_site_instance =
+        old_rfh->GetSiteInstance() == new_rfh->GetSiteInstance();
+    UMA_HISTOGRAM_BOOLEAN("Navigation.IsSameSiteInstance",
+                          is_same_site_instance);
+    if (is_main_frame) {
+      UMA_HISTOGRAM_BOOLEAN("Navigation.IsSameSiteInstance.MainFrame",
+                            is_same_site_instance);
+    } else {
+      UMA_HISTOGRAM_BOOLEAN("Navigation.IsSameSiteInstance.Subframe",
+                            is_same_site_instance);
+    }
+  }
+
+  // Navigation.IsLockedProcess
+  {
+    ChildProcessSecurityPolicyImpl* policy =
+        ChildProcessSecurityPolicyImpl::GetInstance();
+    GURL process_lock = policy->GetOriginLock(new_rfh->GetProcess()->GetID());
+    UMA_HISTOGRAM_BOOLEAN("Navigation.IsLockedProcess",
                           !process_lock.is_empty());
+    if (common_params.url.SchemeIsHTTPOrHTTPS()) {
+      UMA_HISTOGRAM_BOOLEAN("Navigation.IsLockedProcess.HTTPOrHTTPS",
+                            !process_lock.is_empty());
+    }
   }
 
-  if (common_params.transition & ui::PAGE_TRANSITION_FORWARD_BACK) {
-    UMA_HISTOGRAM_BOOLEAN("Navigation.IsSameProcess.BackForward",
-                          is_same_process);
-  } else if (ui::PageTransitionCoreTypeIs(common_params.transition,
-                                          ui::PAGE_TRANSITION_RELOAD)) {
-    UMA_HISTOGRAM_BOOLEAN("Navigation.IsSameProcess.Reload", is_same_process);
-  } else if (ui::PageTransitionIsNewNavigation(common_params.transition)) {
-    UMA_HISTOGRAM_BOOLEAN("Navigation.IsSameProcess.NewNavigation",
-                          is_same_process);
-  } else {
-    NOTREACHED() << "Invalid page transition: " << common_params.transition;
+  // Navigation.RequiresDedicatedProcess
+  {
+    UMA_HISTOGRAM_BOOLEAN(
+        "Navigation.RequiresDedicatedProcess",
+        new_rfh->GetSiteInstance()->RequiresDedicatedProcess());
+    if (common_params.url.SchemeIsHTTPOrHTTPS()) {
+      UMA_HISTOGRAM_BOOLEAN(
+          "Navigation.RequiresDedicatedProcess.HTTPOrHTTPS",
+          new_rfh->GetSiteInstance()->RequiresDedicatedProcess());
+    }
   }
 
-  constexpr base::Optional<bool> kIsBackground = base::nullopt;
-  base::TimeDelta delta = ready_to_commit_time - common_params.navigation_start;
-
-  LOG_NAVIGATION_TIMING_HISTOGRAM(
-      "TimeToReadyToCommit2", common_params.transition, kIsBackground, delta);
-  if (!old_rfh->GetParent()) {
-    LOG_NAVIGATION_TIMING_HISTOGRAM("TimeToReadyToCommit2.MainFrame",
-                                    common_params.transition, kIsBackground,
-                                    delta);
-  } else {
-    LOG_NAVIGATION_TIMING_HISTOGRAM("TimeToReadyToCommit2.Subframe",
-                                    common_params.transition, kIsBackground,
-                                    delta);
+  // Navigation.IsSameProcess
+  {
+    UMA_HISTOGRAM_BOOLEAN("Navigation.IsSameProcess", is_same_process);
+    if (common_params.transition & ui::PAGE_TRANSITION_FORWARD_BACK) {
+      UMA_HISTOGRAM_BOOLEAN("Navigation.IsSameProcess.BackForward",
+                            is_same_process);
+    } else if (ui::PageTransitionCoreTypeIs(common_params.transition,
+                                            ui::PAGE_TRANSITION_RELOAD)) {
+      UMA_HISTOGRAM_BOOLEAN("Navigation.IsSameProcess.Reload", is_same_process);
+    } else if (ui::PageTransitionIsNewNavigation(common_params.transition)) {
+      UMA_HISTOGRAM_BOOLEAN("Navigation.IsSameProcess.NewNavigation",
+                            is_same_process);
+    } else {
+      NOTREACHED() << "Invalid page transition: " << common_params.transition;
+    }
   }
-  if (is_same_process) {
-    LOG_NAVIGATION_TIMING_HISTOGRAM("TimeToReadyToCommit2.SameProcess",
-                                    common_params.transition, kIsBackground,
-                                    delta);
-  } else {
-    LOG_NAVIGATION_TIMING_HISTOGRAM("TimeToReadyToCommit2.CrossProcess",
-                                    common_params.transition, kIsBackground,
-                                    delta);
+
+  // TimeToReadyToCommit2
+  {
+    constexpr base::Optional<bool> kIsBackground = base::nullopt;
+    base::TimeDelta delta =
+        ready_to_commit_time - common_params.navigation_start;
+
+    LOG_NAVIGATION_TIMING_HISTOGRAM(
+        "TimeToReadyToCommit2", common_params.transition, kIsBackground, delta);
+    if (is_main_frame) {
+      LOG_NAVIGATION_TIMING_HISTOGRAM("TimeToReadyToCommit2.MainFrame",
+                                      common_params.transition, kIsBackground,
+                                      delta);
+    } else {
+      LOG_NAVIGATION_TIMING_HISTOGRAM("TimeToReadyToCommit2.Subframe",
+                                      common_params.transition, kIsBackground,
+                                      delta);
+    }
+    if (is_same_process) {
+      LOG_NAVIGATION_TIMING_HISTOGRAM("TimeToReadyToCommit2.SameProcess",
+                                      common_params.transition, kIsBackground,
+                                      delta);
+    } else {
+      LOG_NAVIGATION_TIMING_HISTOGRAM("TimeToReadyToCommit2.CrossProcess",
+                                      common_params.transition, kIsBackground,
+                                      delta);
+    }
   }
 }
 
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index d8c9d8c..92e5d7cb 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -4338,10 +4338,6 @@
   registry_->AddInterface(
       base::Bind(&MediaSessionServiceImpl::Create, base::Unretained(this)));
 
-  registry_->AddInterface(base::Bind(
-      base::IgnoreResult(&RenderFrameHostImpl::CreateWebBluetoothService),
-      base::Unretained(this)));
-
   registry_->AddInterface(base::BindRepeating(
       &RenderFrameHostImpl::CreateWebUsbService, base::Unretained(this)));
 
@@ -4413,8 +4409,6 @@
     registry_->AddInterface(
         base::BindRepeating(&RenderFrameHostImpl::BindSerialServiceReceiver,
                             base::Unretained(this)));
-    registry_->AddInterface(
-        base::BindRepeating(&HidService::Create, base::Unretained(this)));
   }
 #endif  // !defined(OS_ANDROID)
 
@@ -4482,9 +4476,6 @@
       GetProcess()->GetStoragePartition()->GetFileSystemContext(),
       ChromeBlobStorageContext::GetFor(GetProcess()->GetBrowserContext())));
 
-  registry_->AddInterface(base::BindRepeating(&ContactsManagerImpl::Create,
-                                              base::Unretained(this)));
-
   registry_->AddInterface(base::BindRepeating(&WakeLockServiceImpl::Create,
                                               base::Unretained(this)));
 
@@ -6186,7 +6177,7 @@
   dst->focused_tree_id = focused_frame->GetAXTreeID();
 }
 
-WebBluetoothServiceImpl* RenderFrameHostImpl::CreateWebBluetoothService(
+void RenderFrameHostImpl::CreateWebBluetoothService(
     mojo::PendingReceiver<blink::mojom::WebBluetoothService> receiver) {
   // RFHI owns |web_bluetooth_services_| and |web_bluetooth_service| owns the
   // |receiver_| which may run the error handler. |receiver_| can't run the
@@ -6198,6 +6189,11 @@
       base::BindOnce(&RenderFrameHostImpl::DeleteWebBluetoothService,
                      base::Unretained(this), web_bluetooth_service.get()));
   web_bluetooth_services_.push_back(std::move(web_bluetooth_service));
+}
+
+WebBluetoothServiceImpl*
+RenderFrameHostImpl::GetWebBluetoothServiceForTesting() {
+  DCHECK(web_bluetooth_services_.back());
   return web_bluetooth_services_.back().get();
 }
 
@@ -6342,6 +6338,11 @@
 
   authenticator_impl_->Bind(std::move(receiver));
 }
+
+void RenderFrameHostImpl::GetHidService(
+    mojo::PendingReceiver<blink::mojom::HidService> receiver) {
+  HidService::Create(this, std::move(receiver));
+}
 #endif
 
 void RenderFrameHostImpl::GetIdleManager(
@@ -6443,6 +6444,11 @@
   AudioContextManagerImpl::Create(this, std::move(receiver));
 }
 
+void RenderFrameHostImpl::GetContactsManager(
+    mojo::PendingReceiver<blink::mojom::ContactsManager> receiver) {
+  ContactsManagerImpl::Create(this, std::move(receiver));
+}
+
 void RenderFrameHostImpl::GetFileSystemManager(
     mojo::PendingReceiver<blink::mojom::FileSystemManager> receiver) {
   // This is safe because file_system_manager_ is deleted on the IO thread
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 6cb54e0..bfb8fa8 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -77,6 +77,7 @@
 #include "third_party/blink/public/mojom/bluetooth/web_bluetooth.mojom.h"
 #include "third_party/blink/public/mojom/choosers/file_chooser.mojom.h"
 #include "third_party/blink/public/mojom/commit_result/commit_result.mojom.h"
+#include "third_party/blink/public/mojom/contacts/contacts_manager.mojom.h"
 #include "third_party/blink/public/mojom/devtools/devtools_agent.mojom.h"
 #include "third_party/blink/public/mojom/frame/document_interface_broker.mojom.h"
 #include "third_party/blink/public/mojom/frame/find_in_page.mojom.h"
@@ -108,6 +109,7 @@
 #if defined(OS_ANDROID)
 #include "services/device/public/mojom/nfc.mojom.h"
 #else
+#include "third_party/blink/public/mojom/hid/hid.mojom.h"
 #include "third_party/blink/public/mojom/serial/serial.mojom.h"
 #endif
 
@@ -1047,9 +1049,16 @@
   void GetAudioContextManager(
       mojo::PendingReceiver<blink::mojom::AudioContextManager> receiver);
 
+  void GetContactsManager(
+      mojo::PendingReceiver<blink::mojom::ContactsManager> receiver);
+
   void GetFileSystemManager(
       mojo::PendingReceiver<blink::mojom::FileSystemManager> receiver);
 
+#if !defined(OS_ANDROID)
+  void GetHidService(mojo::PendingReceiver<blink::mojom::HidService> receiver);
+#endif
+
   void GetIdleManager(
       mojo::PendingReceiver<blink::mojom::IdleManager> receiver);
 
@@ -1064,6 +1073,9 @@
   void GetFileChooser(
       mojo::PendingReceiver<blink::mojom::FileChooser> receiver);
 
+  void CreateWebBluetoothService(
+      mojo::PendingReceiver<blink::mojom::WebBluetoothService> receiver);
+
   // https://mikewest.github.io/corpp/#initialize-embedder-policy-for-global
   network::mojom::CrossOriginEmbedderPolicy cross_origin_embedder_policy()
       const {
@@ -1522,10 +1534,9 @@
   FrameTreeNode* FindAndVerifyChild(int32_t child_frame_routing_id,
                                     bad_message::BadMessageReason reason);
 
-  // Creates Web Bluetooth Service owned by the frame. Returns a raw pointer
-  // to it.
-  WebBluetoothServiceImpl* CreateWebBluetoothService(
-      mojo::PendingReceiver<blink::mojom::WebBluetoothService> receiver);
+  // Returns a raw pointer to the Web Bluetooth Service owned by the frame. Used
+  // for testing purposes only (see |TestRenderFrameHost|).
+  WebBluetoothServiceImpl* GetWebBluetoothServiceForTesting();
 
   // Deletes the Web Bluetooth Service owned by the frame.
   void DeleteWebBluetoothService(
diff --git a/content/browser/hid/hid_service.cc b/content/browser/hid/hid_service.cc
index 7810d13..3655454 100644
--- a/content/browser/hid/hid_service.cc
+++ b/content/browser/hid/hid_service.cc
@@ -12,21 +12,21 @@
 #include "content/public/browser/hid_chooser.h"
 #include "content/public/browser/hid_delegate.h"
 #include "content/public/browser/render_frame_host.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
 #include "mojo/public/cpp/bindings/message.h"
 #include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom.h"
 
 namespace content {
 
 HidService::HidService(RenderFrameHost* render_frame_host,
-                       blink::mojom::HidServiceRequest request)
-    : FrameServiceBase(render_frame_host, std::move(request)) {}
+                       mojo::PendingReceiver<blink::mojom::HidService> receiver)
+    : FrameServiceBase(render_frame_host, std::move(receiver)) {}
 
 HidService::~HidService() = default;
 
 // static
-void HidService::Create(RenderFrameHost* render_frame_host,
-                        blink::mojom::HidServiceRequest request) {
+void HidService::Create(
+    RenderFrameHost* render_frame_host,
+    mojo::PendingReceiver<blink::mojom::HidService> receiver) {
   DCHECK(render_frame_host);
 
   if (!render_frame_host->IsFeatureEnabled(
@@ -43,7 +43,7 @@
   // HidService owns itself. It will self-destruct when a mojo interface error
   // occurs, the render frame host is deleted, or the render frame host
   // navigates to a new document.
-  new HidService(render_frame_host, std::move(request));
+  new HidService(render_frame_host, std::move(receiver));
 }
 
 void HidService::GetDevices(GetDevicesCallback callback) {
diff --git a/content/browser/hid/hid_service.h b/content/browser/hid/hid_service.h
index 8792d8db..471eb53 100644
--- a/content/browser/hid/hid_service.h
+++ b/content/browser/hid/hid_service.h
@@ -12,7 +12,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "content/public/browser/frame_service_base.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "services/device/public/mojom/hid.mojom.h"
 #include "third_party/blink/public/mojom/hid/hid.mojom.h"
@@ -26,7 +26,8 @@
 // interface is used by Blink to implement the WebHID API.
 class HidService : public content::FrameServiceBase<blink::mojom::HidService> {
  public:
-  static void Create(RenderFrameHost*, blink::mojom::HidServiceRequest);
+  static void Create(RenderFrameHost*,
+                     mojo::PendingReceiver<blink::mojom::HidService>);
 
   // blink::mojom::HidService:
   void GetDevices(GetDevicesCallback callback) override;
@@ -37,7 +38,7 @@
                ConnectCallback callback) override;
 
  private:
-  HidService(RenderFrameHost*, blink::mojom::HidServiceRequest);
+  HidService(RenderFrameHost*, mojo::PendingReceiver<blink::mojom::HidService>);
   ~HidService() override;
 
   void FinishGetDevices(GetDevicesCallback callback,
diff --git a/content/browser/hid/hid_service_unittest.cc b/content/browser/hid/hid_service_unittest.cc
index e8a3c24..7a87119 100644
--- a/content/browser/hid/hid_service_unittest.cc
+++ b/content/browser/hid/hid_service_unittest.cc
@@ -86,10 +86,9 @@
 TEST_F(HidServiceTest, GetDevicesWithPermission) {
   NavigateAndCommit(GURL(kTestUrl));
 
-  blink::mojom::HidServicePtr service;
-  contents()->GetMainFrame()->BinderRegistryForTesting().BindInterface(
-      blink::mojom::HidService::Name_,
-      mojo::MakeRequest(&service).PassMessagePipe());
+  mojo::Remote<blink::mojom::HidService> service;
+  contents()->GetMainFrame()->GetHidService(
+      service.BindNewPipeAndPassReceiver());
 
   auto device_info = device::mojom::HidDeviceInfo::New();
   device_info->guid = kTestGuid;
@@ -112,10 +111,9 @@
 TEST_F(HidServiceTest, GetDevicesWithoutPermission) {
   NavigateAndCommit(GURL(kTestUrl));
 
-  blink::mojom::HidServicePtr service;
-  contents()->GetMainFrame()->BinderRegistryForTesting().BindInterface(
-      blink::mojom::HidService::Name_,
-      mojo::MakeRequest(&service).PassMessagePipe());
+  mojo::Remote<blink::mojom::HidService> service;
+  contents()->GetMainFrame()->GetHidService(
+      service.BindNewPipeAndPassReceiver());
 
   auto device_info = device::mojom::HidDeviceInfo::New();
   device_info->guid = kTestGuid;
@@ -138,10 +136,9 @@
 TEST_F(HidServiceTest, RequestDevice) {
   NavigateAndCommit(GURL(kTestUrl));
 
-  blink::mojom::HidServicePtr service;
-  contents()->GetMainFrame()->BinderRegistryForTesting().BindInterface(
-      blink::mojom::HidService::Name_,
-      mojo::MakeRequest(&service).PassMessagePipe());
+  mojo::Remote<blink::mojom::HidService> service;
+  contents()->GetMainFrame()->GetHidService(
+      service.BindNewPipeAndPassReceiver());
 
   auto device_info = device::mojom::HidDeviceInfo::New();
   device_info->guid = kTestGuid;
@@ -168,10 +165,9 @@
 TEST_F(HidServiceTest, OpenAndCloseHidConnection) {
   NavigateAndCommit(GURL(kTestUrl));
 
-  blink::mojom::HidServicePtr service;
-  contents()->GetMainFrame()->BinderRegistryForTesting().BindInterface(
-      blink::mojom::HidService::Name_,
-      mojo::MakeRequest(&service).PassMessagePipe());
+  mojo::Remote<blink::mojom::HidService> service;
+  contents()->GetMainFrame()->GetHidService(
+      service.BindNewPipeAndPassReceiver());
 
   auto device_info = device::mojom::HidDeviceInfo::New();
   device_info->guid = kTestGuid;
diff --git a/content/browser/navigation_browsertest.cc b/content/browser/navigation_browsertest.cc
index 163fc3f..5f9b3be 100644
--- a/content/browser/navigation_browsertest.cc
+++ b/content/browser/navigation_browsertest.cc
@@ -2514,8 +2514,6 @@
 
   // 5. Start history cross-document navigation, cancelling 4.
   EXPECT_TRUE(ExecJs(shell()->web_contents(), "history.back()"));
-  // TODO(arthursonzogni): The embedder_url_tracker should update the visible
-  // URL here.
   {
     EXPECT_EQ(url_b, shell()->web_contents()->GetVisibleURL());
     EXPECT_EQ(url_b, embedder_url_tracker.url());
@@ -2537,9 +2535,6 @@
     EXPECT_EQ(url_b, shell()->web_contents()->GetVisibleURL());
     EXPECT_EQ(url_b, embedder_url_tracker.url());
   }
-
-  // TODO(https://crbug.com/998284): The URL tracked by the embedder should have
-  // been invalidated. At some point, |url_b| should be displayed, not |url_c|.
 }
 
 // Regression test for https://crbug.com/1001283
diff --git a/content/browser/renderer_interface_binders.cc b/content/browser/renderer_interface_binders.cc
index cf4be3849..7a834a2 100644
--- a/content/browser/renderer_interface_binders.cc
+++ b/content/browser/renderer_interface_binders.cc
@@ -12,7 +12,6 @@
 #include "base/no_destructor.h"
 #include "base/task/post_task.h"
 #include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/content_index/content_index_service_impl.h"
 #include "content/browser/cookie_store/cookie_store_context.h"
 #include "content/browser/gpu/gpu_process_host.h"
 #include "content/browser/native_file_system/native_file_system_manager_impl.h"
@@ -248,8 +247,6 @@
         host->GetBrowserContext()->GetVideoDecodePerfHistory()->BindRequest(
             std::move(request));
       }));
-  parameterized_binder_registry_.AddInterface(
-      base::BindRepeating(&ContentIndexServiceImpl::Create));
 }
 
 RendererInterfaceBinders& GetRendererInterfaceBinders() {
diff --git a/content/browser/scheduler/browser_io_thread_delegate.cc b/content/browser/scheduler/browser_io_thread_delegate.cc
index ec65f10a..cb4233c 100644
--- a/content/browser/scheduler/browser_io_thread_delegate.cc
+++ b/content/browser/scheduler/browser_io_thread_delegate.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/scheduler/browser_io_thread_delegate.h"
 
+#include "base/message_loop/message_pump.h"
 #include "base/message_loop/message_pump_type.h"
 #include "base/task/sequence_manager/sequence_manager.h"
 #include "base/task/sequence_manager/task_queue.h"
diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc
index 0b458608..2278bb9 100644
--- a/content/browser/service_worker/service_worker_context_wrapper.cc
+++ b/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -18,6 +18,7 @@
 #include "base/lazy_instance.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/task/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index 1ede4ab..bf608031 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -18,6 +18,7 @@
 #include "base/command_line.h"
 #include "base/location.h"
 #include "base/optional.h"
+#include "base/run_loop.h"
 #include "base/sequenced_task_runner.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/content/browser/tracing/background_memory_tracing_observer.cc b/content/browser/tracing/background_memory_tracing_observer.cc
index cf1f294..29c7996 100644
--- a/content/browser/tracing/background_memory_tracing_observer.cc
+++ b/content/browser/tracing/background_memory_tracing_observer.cc
@@ -34,6 +34,7 @@
       ->RequestGlobalDumpAndAppendToTrace(
           base::trace_event::MemoryDumpType::EXPLICITLY_TRIGGERED,
           base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND,
+          base::trace_event::MemoryDumpDeterminism::NONE,
           memory_instrumentation::MemoryInstrumentation::
               RequestGlobalMemoryDumpAndAppendToTraceCallback());
 }
diff --git a/content/browser/tracing/memory_tracing_browsertest.cc b/content/browser/tracing/memory_tracing_browsertest.cc
index a5041492..8409d63f 100644
--- a/content/browser/tracing/memory_tracing_browsertest.cc
+++ b/content/browser/tracing/memory_tracing_browsertest.cc
@@ -27,6 +27,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 
 using base::trace_event::MemoryDumpArgs;
+using base::trace_event::MemoryDumpDeterminism;
 using base::trace_event::MemoryDumpLevelOfDetail;
 using base::trace_event::MemoryDumpManager;
 using base::trace_event::MemoryDumpType;
@@ -85,10 +86,12 @@
               RequestGlobalDumpAndAppendToTrace,
           base::Unretained(
               memory_instrumentation::MemoryInstrumentation::GetInstance()),
-          dump_type, level_of_detail, std::move(callback)));
+          dump_type, level_of_detail, MemoryDumpDeterminism::NONE,
+          std::move(callback)));
     } else {
       memory_instrumentation::MemoryInstrumentation::GetInstance()
           ->RequestGlobalDumpAndAppendToTrace(dump_type, level_of_detail,
+                                              MemoryDumpDeterminism::NONE,
                                               std::move(callback));
     }
   }
diff --git a/content/browser/tracing/tracing_controller_impl.cc b/content/browser/tracing/tracing_controller_impl.cc
index a0226541..0123f12 100644
--- a/content/browser/tracing/tracing_controller_impl.cc
+++ b/content/browser/tracing/tracing_controller_impl.cc
@@ -14,6 +14,7 @@
 #include "base/cpu.h"
 #include "base/files/file_tracing.h"
 #include "base/logging.h"
+#include "base/run_loop.h"
 #include "base/strings/string_split.h"
 #include "base/strings/stringprintf.h"
 #include "base/system/sys_info.h"
diff --git a/content/browser/url_loader_factory_getter.cc b/content/browser/url_loader_factory_getter.cc
index 377ac68..9f06bfc 100644
--- a/content/browser/url_loader_factory_getter.cc
+++ b/content/browser/url_loader_factory_getter.cc
@@ -12,6 +12,7 @@
 #include "base/command_line.h"
 #include "base/feature_list.h"
 #include "base/lazy_instance.h"
+#include "base/run_loop.h"
 #include "base/task/post_task.h"
 #include "content/browser/storage_partition_impl.h"
 #include "content/common/service_worker/service_worker_utils.h"
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc
index 62b55d15..ba9df57 100644
--- a/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -3430,15 +3430,8 @@
   EXPECT_TRUE(delete_rfh_c.deleted());
 }
 
-// http://crbug.com/990854
-#if defined(OS_ANDROID)
-#define MAYBE_PopupWindowBrowserNavResumeLoad \
-  DISABLED_PopupWindowBrowserNavResumeLoad
-#else
-#define MAYBE_PopupWindowBrowserNavResumeLoad PopupWindowBrowserNavResumeLoad
-#endif
 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
-                       MAYBE_PopupWindowBrowserNavResumeLoad) {
+                       PopupWindowBrowserNavResumeLoad) {
   // This test verifies a pop up that requires navigation from browser side
   // works with a delegate that delays navigations of pop ups.
   // Create a file: scheme pop up from a file: scheme page, which requires
@@ -3460,8 +3453,7 @@
     ShellAddedObserver new_shell_observer;
     bool success = false;
     EXPECT_TRUE(ExecuteScriptAndExtractBool(
-        shell(),
-        "window.domAutomationController.send(clickDeadFileNewWindowLink());",
+        shell(), "window.domAutomationController.send(clickLinkToSelf());",
         &success));
     new_shell = new_shell_observer.GetShell();
     new_contents = new_shell->web_contents();
@@ -3472,10 +3464,8 @@
   EXPECT_FALSE(new_contents->GetDelegate());
   new_contents->SetDelegate(new_shell);
   new_contents->ResumeLoadingCreatedWebContents();
-  // Dead file link may or may not load depending on OS. The result is not
-  // relevant for this test, so not checking the the result.
   WaitForLoadStop(new_contents);
-  EXPECT_TRUE(new_contents->GetLastCommittedURL().SchemeIs("file"));
+  EXPECT_EQ(url, new_contents->GetLastCommittedURL());
 }
 
 namespace {
diff --git a/content/child/blink_platform_impl.cc b/content/child/blink_platform_impl.cc
index ba8cff1..8616e38 100644
--- a/content/child/blink_platform_impl.cc
+++ b/content/child/blink_platform_impl.cc
@@ -160,10 +160,6 @@
       return IDS_AX_MEDIA_TOUCHLESS_SEEK_ACTION;
     case WebLocalizedString::kAXMediaTouchLessVolumeAction:
       return IDS_AX_MEDIA_TOUCHLESS_VOLUME_ACTION;
-    case WebLocalizedString::kCalendarClear:
-      return IDS_FORM_CALENDAR_CLEAR;
-    case WebLocalizedString::kCalendarToday:
-      return IDS_FORM_CALENDAR_TODAY;
     case WebLocalizedString::kDetailsLabel:
       return IDS_DETAILS_WITHOUT_SUMMARY_LABEL;
     case WebLocalizedString::kFileButtonNoFileSelectedLabel:
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index eb46ac8d..f77550f 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -515,9 +515,6 @@
   WebRuntimeFeatures::EnableSkipTouchEventFilter(
       base::FeatureList::IsEnabled(features::kSkipTouchEventFilter));
 
-  WebRuntimeFeatures::EnableStaleWhileRevalidate(
-      base::FeatureList::IsEnabled(features::kStaleWhileRevalidate));
-
   if (!base::FeatureList::IsEnabled(features::kSmsReceiver))
     WebRuntimeFeatures::EnableSmsReceiver(false);
 
diff --git a/content/public/app/content_browser_manifest.cc b/content/public/app/content_browser_manifest.cc
index fbd3e3d..d3e7bf7 100644
--- a/content/public/app/content_browser_manifest.cc
+++ b/content/public/app/content_browser_manifest.cc
@@ -199,7 +199,7 @@
               "navigation:service_worker", "renderer",
               std::set<const char*>{
                   "blink.mojom.CacheStorage", "blink.mojom.CookieStore",
-                  "blink.mojom.ContentIndexService", "blink.mojom.IDBFactory",
+                  "blink.mojom.IDBFactory",
                   "blink.mojom.NativeFileSystemManager",
                   "blink.mojom.NotificationService",
                   "blink.mojom.PermissionService",
@@ -219,13 +219,10 @@
                   "blink.mojom.AnchorElementMetricsHost",
                   "blink.mojom.CacheStorage",
                   "blink.mojom.ColorChooserFactory",
-                  "blink.mojom.ContactsManager",
-                  "blink.mojom.ContentIndexService",
                   "blink.mojom.DateTimeChooser",
                   "blink.mojom.DisplayCutoutHost",
                   "blink.mojom.DedicatedWorkerHostFactory",
                   "blink.mojom.GeolocationService",
-                  "blink.mojom.HidService",
                   "blink.mojom.IDBFactory",
                   "blink.mojom.InsecureInputService",
                   "blink.mojom.KeyboardLockService",
@@ -246,7 +243,6 @@
                   "blink.mojom.TextSuggestionHost",
                   "blink.mojom.UnhandledTapNotifier",
                   "blink.mojom.WakeLockService",
-                  "blink.mojom.WebBluetoothService",
                   "blink.mojom.WebUsbService",
                   "content.mojom.BrowserTarget",
                   "content.mojom.InputInjector",
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index ee197275..5bb008c71 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -525,11 +525,6 @@
 const base::Feature kSpareRendererForSitePerProcess{
     "SpareRendererForSitePerProcess", base::FEATURE_ENABLED_BY_DEFAULT};
 
-// Enables StaleWhileRevalidate support.
-// https://www.chromestatus.com/features/5050913014153216
-const base::Feature kStaleWhileRevalidate{"StaleWhileRevalidate",
-                                          base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Enables Storage Pressure notifications and settings pages.
 const base::Feature kStoragePressureUI{"StoragePressureUI",
                                        base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index a63f89e1..b8aaa14 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -118,7 +118,6 @@
 CONTENT_EXPORT extern const base::Feature kSignedHTTPExchangePingValidity;
 CONTENT_EXPORT extern const base::Feature kSmsReceiver;
 CONTENT_EXPORT extern const base::Feature kSpareRendererForSitePerProcess;
-CONTENT_EXPORT extern const base::Feature kStaleWhileRevalidate;
 CONTENT_EXPORT extern const base::Feature kStoragePressureUI;
 CONTENT_EXPORT extern const base::Feature kStrictOriginIsolation;
 CONTENT_EXPORT extern const base::Feature kSyntheticPointerActions;
diff --git a/content/public/test/content_browser_test.cc b/content/public/test/content_browser_test.cc
index 834fc446..d912fc4 100644
--- a/content/public/test/content_browser_test.cc
+++ b/content/public/test/content_browser_test.cc
@@ -6,7 +6,7 @@
 
 #include "base/command_line.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "build/build_config.h"
diff --git a/content/public/test/test_download_http_response.cc b/content/public/test/test_download_http_response.cc
index 5235b06..02cffd5 100644
--- a/content/public/test/test_download_http_response.cc
+++ b/content/public/test/test_download_http_response.cc
@@ -11,6 +11,7 @@
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/numerics/ranges.h"
+#include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
diff --git a/content/public/test/url_loader_interceptor.cc b/content/public/test/url_loader_interceptor.cc
index 848b0de..a548ec10 100644
--- a/content/public/test/url_loader_interceptor.cc
+++ b/content/public/test/url_loader_interceptor.cc
@@ -12,6 +12,7 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/path_service.h"
+#include "base/run_loop.h"
 #include "base/synchronization/lock.h"
 #include "base/task/post_task.h"
 #include "base/test/bind_test_util.h"
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index cd93266..fd1a5da 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -199,19 +199,6 @@
                                        std::move(receiver));
 }
 
-void ServiceWorkerContextClient::WorkerContextFailedToStartOnInitiatorThread() {
-  DCHECK(initiator_thread_task_runner_->RunsTasksInCurrentSequence());
-  DCHECK(!proxy_);
-
-  instance_host_->OnStopped();
-
-  TRACE_EVENT_NESTABLE_ASYNC_END1(
-      "ServiceWorker", "ServiceWorkerContextClient", this, "Status",
-      "WorkerContextFailedToStartOnInitiatorThread");
-
-  owner_->WorkerContextDestroyed();
-}
-
 void ServiceWorkerContextClient::FailedToLoadClassicScript() {
   DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
   TRACE_EVENT_NESTABLE_ASYNC_END1("ServiceWorker", "LOAD_SCRIPT", this,
diff --git a/content/renderer/service_worker/service_worker_context_client.h b/content/renderer/service_worker/service_worker_context_client.h
index 645c59f..2e0336e9 100644
--- a/content/renderer/service_worker/service_worker_context_client.h
+++ b/content/renderer/service_worker/service_worker_context_client.h
@@ -125,7 +125,6 @@
   void WorkerReadyForInspectionOnInitiatorThread(
       mojo::ScopedMessagePipeHandle devtools_agent_ptr_info,
       mojo::ScopedMessagePipeHandle devtools_agent_host_request) override;
-  void WorkerContextFailedToStartOnInitiatorThread() override;
   void FailedToLoadClassicScript() override;
   void FailedToFetchModuleScript() override;
   void WorkerScriptLoadedOnWorkerThread() override;
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 379681f..58862874 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -414,6 +414,7 @@
     "//storage/common",
     "//testing/gmock",
     "//testing/gtest",
+    "//third_party/blink/public/strings:strings_grit",
     "//third_party/webrtc/api:libjingle_peerconnection_api",
     "//third_party/webrtc/api:media_stream_interface",
     "//third_party/webrtc/api:rtc_stats_api",
diff --git a/content/test/data/simple_links.html b/content/test/data/simple_links.html
index 44c7db3..7703605 100644
--- a/content/test/data/simple_links.html
+++ b/content/test/data/simple_links.html
@@ -40,8 +40,8 @@
     return simulateClick(document.getElementById("view_source_link"));
   }
 
-  function clickDeadFileNewWindowLink() {
-    return simulateClick(document.getElementById("dead_file_new_window_link"));
+  function clickLinkToSelf() {
+    return simulateClick(document.getElementById("linkToSelf"));
   }
 
   function clickGoogleChromeLink() {
@@ -55,6 +55,9 @@
 <a href="view-source:about:blank" id="view_source_link">view-source:</a><br>
 <a href="title2.html" id="same_site_new_window_link" target="_blank">same-site new window</a>
 <a href="http://foo.com/title2.html" id="cross_site_new_window_link" target="_blank">cross-site new window</a>
-<a href="file://" id="dead_file_new_window_link" target="_blank">dead-file new window</a>
+<a href="" id="linkToSelf" target="_blank">self new window</a>
+<script>
+  document.getElementById("linkToSelf").href = window.location.toString();
+</script>
 <a href="googlechrome://" id="google_chrome_link">googlechrome:</a></br>
 </html>
diff --git a/content/test/test_blink_web_unit_test_support.cc b/content/test/test_blink_web_unit_test_support.cc
index d0785d60..97ffa0d5 100644
--- a/content/test/test_blink_web_unit_test_support.cc
+++ b/content/test/test_blink_web_unit_test_support.cc
@@ -40,6 +40,7 @@
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/platform/web_url.h"
 #include "third_party/blink/public/platform/web_url_loader_factory.h"
+#include "third_party/blink/public/strings/grit/blink_strings.h"
 #include "third_party/blink/public/web/blink.h"
 #include "v8/include/v8.h"
 
@@ -230,9 +231,9 @@
       return WebString::FromASCII("<<OtherMonthLabel>>");
     case blink::WebLocalizedString::kOtherWeekLabel:
       return WebString::FromASCII("<<OtherWeekLabel>>");
-    case blink::WebLocalizedString::kCalendarClear:
+    case IDS_FORM_CALENDAR_CLEAR:
       return WebString::FromASCII("<<CalendarClear>>");
-    case blink::WebLocalizedString::kCalendarToday:
+    case IDS_FORM_CALENDAR_TODAY:
       return WebString::FromASCII("<<CalendarToday>>");
     case blink::WebLocalizedString::kThisMonthButtonLabel:
       return WebString::FromASCII("<<ThisMonthLabel>>");
diff --git a/content/test/test_render_frame_host.cc b/content/test/test_render_frame_host.cc
index bd02bab..a0e07f7 100644
--- a/content/test/test_render_frame_host.cc
+++ b/content/test/test_render_frame_host.cc
@@ -527,10 +527,9 @@
 
 WebBluetoothServiceImpl*
 TestRenderFrameHost::CreateWebBluetoothServiceForTesting() {
-  WebBluetoothServiceImpl* service =
-      RenderFrameHostImpl::CreateWebBluetoothService(
-          dummy_web_bluetooth_service_remote_.InitWithNewPipeAndPassReceiver());
-  return service;
+  RenderFrameHostImpl::CreateWebBluetoothService(
+      dummy_web_bluetooth_service_remote_.InitWithNewPipeAndPassReceiver());
+  return RenderFrameHostImpl::GetWebBluetoothServiceForTesting();
 }
 
 void TestRenderFrameHost::SendFramePolicy(
diff --git a/extensions/browser/api/networking_private/networking_private_linux.h b/extensions/browser/api/networking_private/networking_private_linux.h
index 4950a14..e5f9939 100644
--- a/extensions/browser/api/networking_private/networking_private_linux.h
+++ b/extensions/browser/api/networking_private/networking_private_linux.h
@@ -11,6 +11,7 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "base/observer_list.h"
 #include "base/threading/thread.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "extensions/browser/api/networking_private/networking_private_delegate.h"
diff --git a/extensions/shell/test/shell_test.cc b/extensions/shell/test/shell_test.cc
index c7e70435..0498606 100644
--- a/extensions/shell/test/shell_test.cc
+++ b/extensions/shell/test/shell_test.cc
@@ -7,7 +7,7 @@
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
 #include "base/run_loop.h"
 #include "content/public/common/content_switches.h"
 #include "extensions/browser/extension_system.h"
diff --git a/fuchsia/http/http_service_unittest.cc b/fuchsia/http/http_service_unittest.cc
index 628e2ef..3d024ea5 100644
--- a/fuchsia/http/http_service_unittest.cc
+++ b/fuchsia/http/http_service_unittest.cc
@@ -7,6 +7,7 @@
 
 #include "base/fuchsia/scoped_service_binding.h"
 #include "base/fuchsia/service_directory.h"
+#include "base/message_loop/message_loop_current.h"
 #include "base/run_loop.h"
 #include "base/test/task_environment.h"
 #include "fuchsia/http/http_service_impl.h"
diff --git a/gin/test/v8_test.h b/gin/test/v8_test.h
index 62796a8..73fdb3a3 100644
--- a/gin/test/v8_test.h
+++ b/gin/test/v8_test.h
@@ -30,7 +30,7 @@
  protected:
   // This is used during SetUp() to initialize instance_.
   virtual std::unique_ptr<IsolateHolder> CreateIsolateHolder() const;
-  base::test::SingleThreadTaskEnvironment task_environment_;
+  base::test::TaskEnvironment task_environment_;
   std::unique_ptr<IsolateHolder> instance_;
   v8::Persistent<v8::Context> context_;
 
diff --git a/gin/v8_isolate_memory_dump_provider.cc b/gin/v8_isolate_memory_dump_provider.cc
index fe14263..4e328f1 100644
--- a/gin/v8_isolate_memory_dump_provider.cc
+++ b/gin/v8_isolate_memory_dump_provider.cc
@@ -156,6 +156,10 @@
 void V8IsolateMemoryDumpProvider::DumpHeapStatistics(
     const base::trace_event::MemoryDumpArgs& args,
     base::trace_event::ProcessMemoryDump* process_memory_dump) {
+  if (args.determinism == base::trace_event::MemoryDumpDeterminism::FORCE_GC) {
+    // Force GC in V8 using the same API as DevTools uses in "collectGarbage".
+    isolate_holder_->isolate()->LowMemoryNotification();
+  }
   std::string isolate_name = base::StringPrintf(
       "isolate_0x%" PRIXPTR,
       reinterpret_cast<uintptr_t>(isolate_holder_->isolate()));
diff --git a/gin/v8_isolate_memory_dump_provider_unittest.cc b/gin/v8_isolate_memory_dump_provider_unittest.cc
index 26962ee..b003a234 100644
--- a/gin/v8_isolate_memory_dump_provider_unittest.cc
+++ b/gin/v8_isolate_memory_dump_provider_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "base/task/thread_pool/thread_pool_instance.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/process_memory_dump.h"
 #include "base/trace_event/trace_event.h"
@@ -159,4 +160,29 @@
   ASSERT_TRUE(did_dump_external_scripts_size);
 }
 
+// Tests that a deterministic memory dump request performs a GC.
+TEST_F(V8MemoryDumpProviderTest, Deterministic) {
+  base::trace_event::MemoryDumpArgs dump_args = {
+      base::trace_event::MemoryDumpLevelOfDetail::LIGHT,
+      base::trace_event::MemoryDumpDeterminism::FORCE_GC};
+  std::unique_ptr<base::trace_event::ProcessMemoryDump> process_memory_dump(
+      new base::trace_event::ProcessMemoryDump(dump_args));
+
+  // Allocate an object that has only a weak reference.
+  v8::Global<v8::Object> weak_ref;
+  {
+    v8::HandleScope scope(instance_->isolate());
+    v8::Local<v8::Object> object = v8::Object::New(instance_->isolate());
+    weak_ref.Reset(instance_->isolate(), object);
+    weak_ref.SetWeak();
+  }
+
+  // Deterministic memory dump should trigger GC.
+  instance_->isolate_memory_dump_provider_for_testing()->OnMemoryDump(
+      dump_args, process_memory_dump.get());
+
+  // GC reclaimed the object.
+  ASSERT_TRUE(weak_ref.IsEmpty());
+}
+
 }  // namespace gin
diff --git a/gpu/ipc/service/gpu_watchdog_thread_unittest.cc b/gpu/ipc/service/gpu_watchdog_thread_unittest.cc
index 407c9b5..6beb6aa 100644
--- a/gpu/ipc/service/gpu_watchdog_thread_unittest.cc
+++ b/gpu/ipc/service/gpu_watchdog_thread_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "gpu/ipc/service/gpu_watchdog_thread_v2.h"
 
+#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
 #include "base/power_monitor/power_monitor.h"
 #include "base/power_monitor/power_monitor_source.h"
 #include "base/test/power_monitor_test_base.h"
diff --git a/ios/chrome/app/application_delegate/BUILD.gn b/ios/chrome/app/application_delegate/BUILD.gn
index 7027368..3cb6f0c 100644
--- a/ios/chrome/app/application_delegate/BUILD.gn
+++ b/ios/chrome/app/application_delegate/BUILD.gn
@@ -102,6 +102,7 @@
   deps = [
     ":application_delegate",
     "//base",
+    "//build:branding_buildflags",
     "//components/crash/core/common",
     "//components/feature_engagement",
     "//components/handoff",
diff --git a/ios/chrome/app/application_delegate/app_state.mm b/ios/chrome/app/application_delegate/app_state.mm
index a97ba2a2..1f6ab47 100644
--- a/ios/chrome/app/application_delegate/app_state.mm
+++ b/ios/chrome/app/application_delegate/app_state.mm
@@ -30,8 +30,8 @@
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/chrome_constants.h"
-#include "ios/chrome/browser/crash_loop_detection_util.h"
 #include "ios/chrome/browser/crash_report/breakpad_helper.h"
+#include "ios/chrome/browser/crash_report/crash_loop_detection_util.h"
 #import "ios/chrome/browser/device_sharing/device_sharing_manager.h"
 #include "ios/chrome/browser/feature_engagement/tracker_factory.h"
 #import "ios/chrome/browser/geolocation/omnibox_geolocation_config.h"
diff --git a/ios/chrome/app/application_delegate/metrics_mediator.mm b/ios/chrome/app/application_delegate/metrics_mediator.mm
index 1d2506c9b..98a1a74 100644
--- a/ios/chrome/app/application_delegate/metrics_mediator.mm
+++ b/ios/chrome/app/application_delegate/metrics_mediator.mm
@@ -9,6 +9,7 @@
 #include "base/metrics/user_metrics_action.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/task/post_task.h"
+#include "build/branding_buildflags.h"
 #include "components/crash/core/common/crash_keys.h"
 #include "components/metrics/metrics_pref_names.h"
 #include "components/metrics/metrics_service.h"
@@ -191,7 +192,7 @@
 - (BOOL)areMetricsEnabled {
 // If this if-def changes, it needs to be changed in
 // IOSChromeMainParts::IsMetricsReportingEnabled and settings_egtest.mm.
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   BOOL optIn = GetApplicationContext()->GetLocalState()->GetBoolean(
       metrics::prefs::kMetricsReportingEnabled);
 #else
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index 026f93f..f1640ff6 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -72,8 +72,8 @@
 #include "ios/chrome/browser/chrome_url_constants.h"
 #import "ios/chrome/browser/chrome_url_util.h"
 #include "ios/chrome/browser/content_settings/host_content_settings_map_factory.h"
-#include "ios/chrome/browser/crash_loop_detection_util.h"
 #include "ios/chrome/browser/crash_report/breakpad_helper.h"
+#include "ios/chrome/browser/crash_report/crash_loop_detection_util.h"
 #import "ios/chrome/browser/crash_report/crash_restore_helper.h"
 #include "ios/chrome/browser/download/download_directory_util.h"
 #import "ios/chrome/browser/external_files/external_file_remover_factory.h"
diff --git a/ios/chrome/app/strings/ios_chromium_strings.grd b/ios/chrome/app/strings/ios_chromium_strings.grd
index 4e1504b..166b803 100644
--- a/ios/chrome/app/strings/ios_chromium_strings.grd
+++ b/ios/chrome/app/strings/ios_chromium_strings.grd
@@ -190,7 +190,7 @@
         Your account does not work on Chromium. Please contact your domain administrator or use a regular Google Account to sign in.
       </message>
       <message name="IDS_IOS_LONG_PRESS_TOOLBAR_IPH_PROMOTION_VOICE_OVER" desc="Text to be read by VoiceOver when the LongPress Toolbar Tip is presented to the user. Read by Text-to-Speech.">
-        Chromium tip. For more tab options, press and hold the Show Tabs button in the toolbar, which is at the bottom or top of your screen.
+        Chromium tip. For more tab options, touch &amp; hold the Show Tabs button in the toolbar, which is at the bottom or top of your screen.
       </message>
       <message name="IDS_IOS_MANAGE_SYNC_DATA_FROM_CHROME_SYNC_TITLE" desc="Title for the cell to open 'Data from Chromium sync' web page where the user can control all their data data from sync.">
         Data from Chromium sync
diff --git a/ios/chrome/app/strings/ios_google_chrome_strings.grd b/ios/chrome/app/strings/ios_google_chrome_strings.grd
index a6c44dd..5057cbc 100644
--- a/ios/chrome/app/strings/ios_google_chrome_strings.grd
+++ b/ios/chrome/app/strings/ios_google_chrome_strings.grd
@@ -190,7 +190,7 @@
         Your account does not work on Google Chrome. Please contact your domain administrator or use a regular Google Account to sign in.
       </message>
       <message name="IDS_IOS_LONG_PRESS_TOOLBAR_IPH_PROMOTION_VOICE_OVER" desc="Text to be read by VoiceOver when the LongPress Toolbar Tip is presented to the user. Read by Text-to-Speech.">
-        Chrome tip. For more tab options, press and hold the Show Tabs button in the toolbar, which is at the bottom or top of your screen.
+        Chrome tip. For more tab options, touch &amp; hold the Show Tabs button in the toolbar, which is at the bottom or top of your screen.
       </message>
       <message name="IDS_IOS_MANAGE_SYNC_DATA_FROM_CHROME_SYNC_TITLE" desc="Title for the cell to open 'Data from Chrome sync' web page where the user can control all their data data from sync.">
         Data from Chrome sync
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index 2175231f7..6c9f0fc 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -846,7 +846,7 @@
         Reopen Closed Tab
       </message>
       <message name="IDS_IOS_LONG_PRESS_TOOLBAR_IPH_PROMOTION_TEXT" desc="Text for the LongPress Toolbar Tip in-product help promotion, explaining that the user can long press on the toolbar's button to display more options. [iOS only]">
-        Press and hold for more tab options
+        Touch &amp; hold for more tab options
       </message>
       <message name="IDS_IOS_MANAGE_YOUR_GOOGLE_ACCOUNT_TITLE" desc="Title for the view in the Settings to open 'Google Account' web page.">
         Manage Your Google Account
diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn
index c72886e..fd91500 100644
--- a/ios/chrome/browser/BUILD.gn
+++ b/ios/chrome/browser/BUILD.gn
@@ -41,8 +41,6 @@
     "chrome_switches.h",
     "chrome_url_util.h",
     "chrome_url_util.mm",
-    "crash_loop_detection_util.h",
-    "crash_loop_detection_util.mm",
     "file_metadata_util.h",
     "file_metadata_util.mm",
     "install_time_util.h",
@@ -255,7 +253,6 @@
     "browser_about_rewriter_unittest.cc",
     "chrome_browser_provider_observer_bridge_unittest.mm",
     "chrome_url_util_unittest.mm",
-    "crash_loop_detection_util_unittest.mm",
     "install_time_util_unittest.mm",
     "installation_notifier_unittest.mm",
     "notification_promo_unittest.cc",
diff --git a/ios/chrome/browser/crash_report/BUILD.gn b/ios/chrome/browser/crash_report/BUILD.gn
index 1f29f88b..fca86732 100644
--- a/ios/chrome/browser/crash_report/BUILD.gn
+++ b/ios/chrome/browser/crash_report/BUILD.gn
@@ -6,6 +6,8 @@
   sources = [
     "breakpad_helper.h",
     "breakpad_helper.mm",
+    "crash_loop_detection_util.h",
+    "crash_loop_detection_util.mm",
     "crash_report_multi_parameter.h",
     "crash_report_multi_parameter.mm",
     "crash_report_user_application_state.h",
@@ -73,6 +75,7 @@
   testonly = true
   sources = [
     "breakpad_helper_unittest.mm",
+    "crash_loop_detection_util_unittest.mm",
     "crash_restore_helper_unittest.mm",
   ]
   deps = [
diff --git a/ios/chrome/browser/crash_loop_detection_util.h b/ios/chrome/browser/crash_report/crash_loop_detection_util.h
similarity index 86%
rename from ios/chrome/browser/crash_loop_detection_util.h
rename to ios/chrome/browser/crash_report/crash_loop_detection_util.h
index ec8692f..2077ec53 100644
--- a/ios/chrome/browser/crash_loop_detection_util.h
+++ b/ios/chrome/browser/crash_report/crash_loop_detection_util.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_CHROME_BROWSER_CRASH_LOOP_DETECTION_UTIL_H_
-#define IOS_CHROME_BROWSER_CRASH_LOOP_DETECTION_UTIL_H_
+#ifndef IOS_CHROME_BROWSER_CRASH_REPORT_CRASH_LOOP_DETECTION_UTIL_H_
+#define IOS_CHROME_BROWSER_CRASH_REPORT_CRASH_LOOP_DETECTION_UTIL_H_
 
 namespace crash_util {
 
@@ -30,4 +30,4 @@
 
 }  // namespace crash_util
 
-#endif  // IOS_CHROME_BROWSER_CRASH_LOOP_DETECTION_UTIL_H_
+#endif  // IOS_CHROME_BROWSER_CRASH_REPORT_CRASH_LOOP_DETECTION_UTIL_H_
diff --git a/ios/chrome/browser/crash_loop_detection_util.mm b/ios/chrome/browser/crash_report/crash_loop_detection_util.mm
similarity index 95%
rename from ios/chrome/browser/crash_loop_detection_util.mm
rename to ios/chrome/browser/crash_report/crash_loop_detection_util.mm
index 0de92d6c..dd72964 100644
--- a/ios/chrome/browser/crash_loop_detection_util.mm
+++ b/ios/chrome/browser/crash_report/crash_loop_detection_util.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ios/chrome/browser/crash_loop_detection_util.h"
+#include "ios/chrome/browser/crash_report/crash_loop_detection_util.h"
 
 #import <Foundation/Foundation.h>
 
diff --git a/ios/chrome/browser/crash_loop_detection_util_unittest.mm b/ios/chrome/browser/crash_report/crash_loop_detection_util_unittest.mm
similarity index 95%
rename from ios/chrome/browser/crash_loop_detection_util_unittest.mm
rename to ios/chrome/browser/crash_report/crash_loop_detection_util_unittest.mm
index 4fa5fcd..0720bf5f5 100644
--- a/ios/chrome/browser/crash_loop_detection_util_unittest.mm
+++ b/ios/chrome/browser/crash_report/crash_loop_detection_util_unittest.mm
@@ -4,7 +4,7 @@
 
 #import <Foundation/Foundation.h>
 
-#include "ios/chrome/browser/crash_loop_detection_util.h"
+#include "ios/chrome/browser/crash_report/crash_loop_detection_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
diff --git a/ios/chrome/browser/history/history_tab_helper_unittest.mm b/ios/chrome/browser/history/history_tab_helper_unittest.mm
index d2ad8c0..f58ffee 100644
--- a/ios/chrome/browser/history/history_tab_helper_unittest.mm
+++ b/ios/chrome/browser/history/history_tab_helper_unittest.mm
@@ -202,3 +202,23 @@
   QueryURL(ntp_url);
   EXPECT_NE(ntp_url, latest_row_result_.url());
 }
+
+// Tests that a file:// URL isn't added to history.
+TEST_F(HistoryTabHelperTest, TestFileNotAdded) {
+  HistoryTabHelper* helper = HistoryTabHelper::FromWebState(&web_state_);
+  ASSERT_TRUE(helper);
+
+  std::unique_ptr<web::NavigationItem> item = web::NavigationItem::Create();
+  GURL test_url("https://www.google.com/");
+  item->SetVirtualURL(test_url);
+  AddVisitForURL(test_url);
+  QueryURL(test_url);
+  EXPECT_EQ(test_url, latest_row_result_.url());
+
+  item = web::NavigationItem::Create();
+  GURL file_url("file://path/to/file");
+  item->SetVirtualURL(file_url);
+  AddVisitForURL(file_url);
+  QueryURL(file_url);
+  EXPECT_NE(file_url, latest_row_result_.url());
+}
diff --git a/ios/chrome/browser/history/history_utils.cc b/ios/chrome/browser/history/history_utils.cc
index 59aeec1..1cc3dd7 100644
--- a/ios/chrome/browser/history/history_utils.cc
+++ b/ios/chrome/browser/history/history_utils.cc
@@ -17,16 +17,17 @@
   if (!url.is_valid())
     return false;
 
+  // TODO(crbug.com/1007192): Don't store the URL as we aren't persiting the
+  // files. Maybe we should start persisting the files and store the URL.
   // TODO: We should allow ChromeUIScheme URLs if they have been explicitly
   // typed.  Right now, however, these are marked as typed even when triggered
   // by a shortcut or menu action.
   if (url.SchemeIs(url::kJavaScriptScheme) ||
       url.SchemeIs(dom_distiller::kDomDistillerScheme) ||
-      url.SchemeIs(kChromeUIScheme))
+      url.SchemeIs(kChromeUIScheme) || url.SchemeIs(url::kFileScheme))
     return false;
 
-  // Allow all about: and chrome: URLs except about:blank|newtab, since the user
-  // may like to see "chrome://version", etc. in their history and autocomplete.
+  // Allow all about: URLs except about:blank|newtab.
   if (url == url::kAboutBlankURL || url == kChromeUIAboutNewTabURL)
     return false;
 
diff --git a/ios/chrome/browser/signin/authentication_service.h b/ios/chrome/browser/signin/authentication_service.h
index 2628a49..33b9bb7 100644
--- a/ios/chrome/browser/signin/authentication_service.h
+++ b/ios/chrome/browser/signin/authentication_service.h
@@ -145,9 +145,9 @@
   // |should_store_accounts_| is true, it will also store the available accounts
   // in the  browser state prefs.
   //
-  // |should_prompt| indicates whether the user should be prompted with the
-  // resign-in infobar if the method signs out.
-  void HandleIdentityListChanged(bool should_prompt);
+  // |in_foreground| indicates whether the application was in foreground when
+  // the identity list change notification was received.
+  void HandleIdentityListChanged(bool in_foreground);
 
   // Verifies that the authenticated user is still associated with a valid
   // ChromeIdentity. This method must only be called when the user is
@@ -172,9 +172,10 @@
 
   // Computes whether the available accounts have changed since the last time
   // they were stored in the  browser state prefs.
-  // |should_prompt| indicates whether the user should be prompted if the
-  // authenticated identity was removed.
-  void ComputeHaveAccountsChanged(bool should_prompt);
+  //
+  // This method should only be called when the application is in background
+  // or when the application is entering foregorund.
+  void UpdateHaveAccountsChangedWhileInBackground();
 
   // signin::IdentityManager::Observer implementation.
   void OnEndBatchOfRefreshTokenStateChanges() override;
diff --git a/ios/chrome/browser/signin/authentication_service.mm b/ios/chrome/browser/signin/authentication_service.mm
index 7dfb493..f2837852 100644
--- a/ios/chrome/browser/signin/authentication_service.mm
+++ b/ios/chrome/browser/signin/authentication_service.mm
@@ -130,9 +130,10 @@
 
   // As the SSO library does not send notification when the app is in the
   // background, reload the credentials and check whether any accounts have
-  // changed (both are done by calling ComputeHaveAccountsChanged). After
-  // that, save the current list of accounts.
-  ComputeHaveAccountsChanged(/*should_prompt=*/true);
+  // changed (both are done by |UpdateHaveAccountsChangedWhileInBackground|).
+  // After that, save the current list of accounts.
+  UpdateHaveAccountsChangedWhileInBackground();
+  StoreAccountsInPrefs();
 
   if (IsAuthenticated()) {
     bool sync_enabled = sync_setup_service_->IsSyncEnabled();
@@ -186,7 +187,7 @@
   return pref_service_->GetBoolean(prefs::kSigninShouldPromptForSigninAgain);
 }
 
-void AuthenticationService::ComputeHaveAccountsChanged(bool should_prompt) {
+void AuthenticationService::UpdateHaveAccountsChangedWhileInBackground() {
   // Load accounts from preference before synchronizing the accounts with
   // the system, otherwiser we would never detect any changes to the list
   // of accounts.
@@ -195,7 +196,10 @@
 
   // Reload credentials to ensure the accounts from the token service are
   // up-to-date.
-  ReloadCredentialsFromIdentities(should_prompt);
+  // As UpdateHaveAccountsChangedWhileInBackground is only called while the
+  // application is in background or when it enters foreground, |should_prompt|
+  // must be set to true.
+  ReloadCredentialsFromIdentities(/*should_prompt=*/true);
 
   std::vector<CoreAccountInfo> new_accounts_info =
       identity_manager_->GetAccountsWithRefreshTokens();
@@ -422,13 +426,11 @@
   // the authenticated user at this time may lead to crashes (e.g.
   // http://crbug.com/398431 ).
   // Handle the change of the identity list on the next message loop cycle.
-  // If the identity list changed while the authentication service was in
-  // background, the user should be warned about it.
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(&AuthenticationService::HandleIdentityListChanged,
                      GetWeakPtr(),
-                     !identity_manager_observer_.IsObservingSources()));
+                     identity_manager_observer_.IsObservingSources()));
 }
 
 bool AuthenticationService::HandleMDMNotification(ChromeIdentity* identity,
@@ -492,8 +494,16 @@
   identity_service_observer_.RemoveAll();
 }
 
-void AuthenticationService::HandleIdentityListChanged(bool should_prompt) {
-  ComputeHaveAccountsChanged(should_prompt);
+void AuthenticationService::HandleIdentityListChanged(bool in_foreground) {
+  // Only notify the user about an identity change notification if the
+  // application was in background.
+  if (in_foreground) {
+    // Do not update the have accounts change state when in foreground.
+    ReloadCredentialsFromIdentities(/*should_prompt=*/false);
+    return;
+  }
+
+  UpdateHaveAccountsChangedWhileInBackground();
 }
 
 void AuthenticationService::HandleForgottenIdentity(
diff --git a/ios/chrome/browser/signin/authentication_service_unittest.mm b/ios/chrome/browser/signin/authentication_service_unittest.mm
index 74d6866..52dd32a 100644
--- a/ios/chrome/browser/signin/authentication_service_unittest.mm
+++ b/ios/chrome/browser/signin/authentication_service_unittest.mm
@@ -301,11 +301,11 @@
       EXPECT_EQ("fooID", accounts[2].account_id);
 }
 
-TEST_F(AuthenticationServiceTest, HaveAccountsNotChangedDefault) {
+TEST_F(AuthenticationServiceTest, HaveAccountsChanged_Default) {
   EXPECT_FALSE(authentication_service()->HaveAccountsChanged());
 }
 
-TEST_F(AuthenticationServiceTest, HaveAccountsNotChanged) {
+TEST_F(AuthenticationServiceTest, HaveAccountsChanged_NoChange) {
   SetExpectationsForSignIn();
   authentication_service()->SignIn(identity(0));
 
@@ -313,45 +313,87 @@
   FireIdentityListChanged();
   base::RunLoop().RunUntilIdle();
 
-  // Simulate a switching to background and back to foreground.
+  // If an account is added while the application is in foreground, then the
+  // have accounts changed state should stay false.
+  EXPECT_FALSE(authentication_service()->HaveAccountsChanged());
+
+  // Backgrounding the app should not change the have accounts changed state.
   FireApplicationDidEnterBackground();
-  FireApplicationWillEnterForeground();
+  EXPECT_FALSE(authentication_service()->HaveAccountsChanged());
 
+  // Foregrounding the app should not change the have accounts changed state.
+  FireApplicationWillEnterForeground();
   EXPECT_FALSE(authentication_service()->HaveAccountsChanged());
 }
 
-TEST_F(AuthenticationServiceTest, HaveAccountsChanged) {
+TEST_F(AuthenticationServiceTest, HaveAccountsChanged_ChangedInBackground) {
   SetExpectationsForSignIn();
   authentication_service()->SignIn(identity(0));
 
   identity_service()->AddIdentities(@[ @"foo3" ]);
   FireIdentityListChanged();
   base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(authentication_service()->HaveAccountsChanged());
 
   // Simulate a switching to background and back to foreground, changing the
-  // accounts while in background.
+  // accounts while in background (no notification fired by |identity_service|).
   FireApplicationDidEnterBackground();
   identity_service()->AddIdentities(@[ @"foo4" ]);
   FireApplicationWillEnterForeground();
-
   EXPECT_TRUE(authentication_service()->HaveAccountsChanged());
 }
 
-TEST_F(AuthenticationServiceTest, HaveAccountsChangedBackground) {
+TEST_F(AuthenticationServiceTest, HaveAccountsChanged_CalledInBackground) {
   SetExpectationsForSignIn();
   authentication_service()->SignIn(identity(0));
 
   identity_service()->AddIdentities(@[ @"foo3" ]);
   FireIdentityListChanged();
   base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(authentication_service()->HaveAccountsChanged());
 
   // Simulate a switching to background, changing the accounts while in
   // background.
   FireApplicationDidEnterBackground();
   identity_service()->AddIdentities(@[ @"foo4" ]);
+  FireIdentityListChanged();
   base::RunLoop().RunUntilIdle();
-
   EXPECT_TRUE(authentication_service()->HaveAccountsChanged());
+
+  // Entering foreground should not change the have accounts changed state.
+  FireApplicationWillEnterForeground();
+  EXPECT_TRUE(authentication_service()->HaveAccountsChanged());
+}
+
+// Regression test for http://crbug.com/1006717
+TEST_F(AuthenticationServiceTest, HaveAccountsChanged_ResetOntwoBackgrounds) {
+  SetExpectationsForSignIn();
+  authentication_service()->SignIn(identity(0));
+
+  identity_service()->AddIdentities(@[ @"foo3" ]);
+  FireIdentityListChanged();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(authentication_service()->HaveAccountsChanged());
+
+  // Simulate a switching to background, changing the accounts while in
+  // background.
+  FireApplicationDidEnterBackground();
+
+  // Clear |kSigninLastAccounts| pref to simulate a case when the list of
+  // accounts in pref |kSigninLastAccounts| are no the same as the ones
+  browser_state_->GetPrefs()->ClearPref(prefs::kSigninLastAccounts);
+
+  // When entering foreground, the have accounts changed state should be
+  // updated.
+  FireApplicationWillEnterForeground();
+  EXPECT_TRUE(authentication_service()->HaveAccountsChanged());
+
+  // Backgrounding and foregrounding the application a second time should update
+  // the list of accounts in |kSigninLastAccounts| and should reset the have
+  // account changed state.
+  FireApplicationDidEnterBackground();
+  FireApplicationWillEnterForeground();
+  EXPECT_FALSE(authentication_service()->HaveAccountsChanged());
 }
 
 TEST_F(AuthenticationServiceTest, IsAuthenticatedBackground) {
diff --git a/ios/chrome/browser/tabs/BUILD.gn b/ios/chrome/browser/tabs/BUILD.gn
index 96c2a12..e07ce23 100644
--- a/ios/chrome/browser/tabs/BUILD.gn
+++ b/ios/chrome/browser/tabs/BUILD.gn
@@ -62,6 +62,7 @@
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/browser_state_metrics",
     "//ios/chrome/browser/complex_tasks",
+    "//ios/chrome/browser/crash_report",
     "//ios/chrome/browser/download",
     "//ios/chrome/browser/favicon",
     "//ios/chrome/browser/find_in_page",
diff --git a/ios/chrome/browser/tabs/tab_model.mm b/ios/chrome/browser/tabs/tab_model.mm
index a351dde8..d58b598 100644
--- a/ios/chrome/browser/tabs/tab_model.mm
+++ b/ios/chrome/browser/tabs/tab_model.mm
@@ -29,7 +29,7 @@
 #include "ios/chrome/browser/browser_state_metrics/browser_state_metrics.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
 #import "ios/chrome/browser/chrome_url_util.h"
-#include "ios/chrome/browser/crash_loop_detection_util.h"
+#include "ios/chrome/browser/crash_report/crash_loop_detection_util.h"
 #import "ios/chrome/browser/geolocation/omnibox_geolocation_controller.h"
 #import "ios/chrome/browser/main/browser_web_state_list_delegate.h"
 #import "ios/chrome/browser/metrics/tab_usage_recorder.h"
diff --git a/ios/chrome/browser/ui/bubble/bubble_presenter.mm b/ios/chrome/browser/ui/bubble/bubble_presenter.mm
index dd7b716..211e870 100644
--- a/ios/chrome/browser/ui/bubble/bubble_presenter.mm
+++ b/ios/chrome/browser/ui/bubble/bubble_presenter.mm
@@ -181,8 +181,8 @@
 
   BubbleArrowDirection arrowDirection =
       IsSplitToolbarMode() ? BubbleArrowDirectionDown : BubbleArrowDirectionUp;
-  NSString* text = l10n_util::GetNSStringWithFixup(
-      IDS_IOS_LONG_PRESS_TOOLBAR_IPH_PROMOTION_TEXT);
+  NSString* text =
+      l10n_util::GetNSString(IDS_IOS_LONG_PRESS_TOOLBAR_IPH_PROMOTION_TEXT);
   CGPoint searchButtonAnchor =
       IsRegularXRegularSizeClass()
           ? [self anchorPointToGuide:kTabStripTabSwitcherGuide
diff --git a/ios/chrome/browser/ui/safe_mode/safe_mode_coordinator.mm b/ios/chrome/browser/ui/safe_mode/safe_mode_coordinator.mm
index 9006d74..bb63ccd 100644
--- a/ios/chrome/browser/ui/safe_mode/safe_mode_coordinator.mm
+++ b/ios/chrome/browser/ui/safe_mode/safe_mode_coordinator.mm
@@ -5,7 +5,7 @@
 #import "ios/chrome/browser/ui/safe_mode/safe_mode_coordinator.h"
 
 #include "base/logging.h"
-#include "ios/chrome/browser/crash_loop_detection_util.h"
+#include "ios/chrome/browser/crash_report/crash_loop_detection_util.h"
 #import "ios/chrome/browser/ui/safe_mode/safe_mode_view_controller.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/web/navigation/navigation_context_impl.h b/ios/web/navigation/navigation_context_impl.h
index a59d5b2..57bd959 100644
--- a/ios/web/navigation/navigation_context_impl.h
+++ b/ios/web/navigation/navigation_context_impl.h
@@ -11,6 +11,7 @@
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "base/timer/elapsed_timer.h"
 #import "ios/web/public/navigation/navigation_context.h"
 #include "url/gurl.h"
 
@@ -61,6 +62,9 @@
   void SetResponseHeaders(
       const scoped_refptr<net::HttpResponseHeaders>& response_headers);
 
+  // Get elapsed time since context was created.
+  base::TimeDelta GetElapsedTimeSinceCreation() const;
+
   // Optional unique id of the navigation item associated with this navigaiton.
   int GetNavigationItemUniqueID() const;
   void SetNavigationItemUniqueID(int unique_id);
@@ -133,6 +137,7 @@
   bool is_native_content_presented_ = false;
   bool is_placeholder_navigation_ = false;
   NSString* mime_type_ = nil;
+  base::ElapsedTimer elapsed_timer_;
 
   // Holds pending navigation item in this object. Pending item is stored in
   // NavigationContext after context is created. The item is still stored in
diff --git a/ios/web/navigation/navigation_context_impl.mm b/ios/web/navigation/navigation_context_impl.mm
index 2aa5f702..04715c7 100644
--- a/ios/web/navigation/navigation_context_impl.mm
+++ b/ios/web/navigation/navigation_context_impl.mm
@@ -207,6 +207,10 @@
   item_ = std::move(item);
 }
 
+base::TimeDelta NavigationContextImpl::GetElapsedTimeSinceCreation() const {
+  return elapsed_timer_.Elapsed();
+}
+
 NavigationContextImpl::NavigationContextImpl(WebState* web_state,
                                              const GURL& url,
                                              bool has_user_gesture,
@@ -220,7 +224,8 @@
       is_same_document_(false),
       error_(nil),
       response_headers_(nullptr),
-      is_renderer_initiated_(is_renderer_initiated) {}
+      is_renderer_initiated_(is_renderer_initiated),
+      elapsed_timer_(base::ElapsedTimer()) {}
 
 NavigationContextImpl::~NavigationContextImpl() = default;
 
diff --git a/ios/web/web_state/ui/crw_web_request_controller.mm b/ios/web/web_state/ui/crw_web_request_controller.mm
index 29d10fd..8f79bee 100644
--- a/ios/web/web_state/ui/crw_web_request_controller.mm
+++ b/ios/web/web_state/ui/crw_web_request_controller.mm
@@ -481,7 +481,18 @@
   } else {
     // There is another pending navigation, so the state is still loading.
   }
+
   self.webState->OnPageLoaded(currentURL, YES);
+
+  if (context) {
+    if (context->IsRendererInitiated()) {
+      UMA_HISTOGRAM_TIMES("PLT.iOS.RendererInitiatedPageLoadTime",
+                          context->GetElapsedTimeSinceCreation());
+    } else {
+      UMA_HISTOGRAM_TIMES("PLT.iOS.BrowserInitiatedPageLoadTime",
+                          context->GetElapsedTimeSinceCreation());
+    }
+  }
 }
 
 // Reports Navigation.IOSWKWebViewSlowFastBackForward UMA. No-op if pending
diff --git a/ios/web_view/internal/passwords/mock_credentials_filter.h b/ios/web_view/internal/passwords/mock_credentials_filter.h
index 324ead0..79f536d1 100644
--- a/ios/web_view/internal/passwords/mock_credentials_filter.h
+++ b/ios/web_view/internal/passwords/mock_credentials_filter.h
@@ -25,8 +25,7 @@
   bool ShouldSaveEnterprisePasswordHash(
       const autofill::PasswordForm& form) const override;
   void ReportFormLoginSuccess(
-      const password_manager::PasswordFormManagerInterface& form_manager)
-      const override;
+      const password_manager::PasswordFormManager& form_manager) const override;
   bool IsSyncAccountEmail(const std::string& username) const override;
 
  private:
diff --git a/ios/web_view/internal/passwords/mock_credentials_filter.mm b/ios/web_view/internal/passwords/mock_credentials_filter.mm
index 20f7775..a650253 100644
--- a/ios/web_view/internal/passwords/mock_credentials_filter.mm
+++ b/ios/web_view/internal/passwords/mock_credentials_filter.mm
@@ -30,7 +30,7 @@
 }
 
 void MockCredentialsFilter::ReportFormLoginSuccess(
-    const password_manager::PasswordFormManagerInterface& form_manager) const {}
+    const password_manager::PasswordFormManager& form_manager) const {}
 
 bool MockCredentialsFilter::IsSyncAccountEmail(
     const std::string& username) const {
diff --git a/media/gpu/test/video_player/video_decoder_client.h b/media/gpu/test/video_player/video_decoder_client.h
index 1d6fd5f..ad2003c7 100644
--- a/media/gpu/test/video_player/video_decoder_client.h
+++ b/media/gpu/test/video_player/video_decoder_client.h
@@ -11,6 +11,7 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
 #include "base/threading/thread.h"
 #include "media/base/decode_status.h"
diff --git a/media/gpu/v4l2/v4l2_slice_video_decoder.cc b/media/gpu/v4l2/v4l2_slice_video_decoder.cc
index 8fbfe7b..66e6595c 100644
--- a/media/gpu/v4l2/v4l2_slice_video_decoder.cc
+++ b/media/gpu/v4l2/v4l2_slice_video_decoder.cc
@@ -227,14 +227,11 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
   DVLOGF(2);
 
-  if (avd_) {
-    avd_->Reset();
-    avd_ = nullptr;
-  }
-
   // Call all pending decode callback.
   ClearPendingRequests(DecodeStatus::ABORTED);
 
+  avd_ = nullptr;
+
   // Stop and Destroy device.
   StopStreamV4L2Queue();
   if (input_queue_) {
@@ -543,9 +540,6 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
   DVLOGF(3);
 
-  if (avd_)
-    avd_->Reset();
-
   // Call all pending decode callback.
   ClearPendingRequests(DecodeStatus::ABORTED);
 
@@ -568,6 +562,9 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
   DVLOGF(3);
 
+  if (avd_)
+    avd_->Reset();
+
   // Clear output_request_queue_.
   while (!output_request_queue_.empty())
     output_request_queue_.pop();
@@ -601,7 +598,12 @@
 
 void V4L2SliceVideoDecoder::EnqueueDecodeTask(DecodeRequest request) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
-  DCHECK(state_ == State::kDecoding || state_ == State::kFlushing);
+  DCHECK_NE(state_, State::kUninitialized);
+
+  if (state_ == State::kError) {
+    std::move(request.decode_cb).Run(DecodeStatus::DECODE_ERROR);
+    return;
+  }
 
   if (!request.buffer->end_of_stream()) {
     bitstream_id_to_timestamp_.Put(request.bitstream_id,
@@ -615,11 +617,10 @@
 
 void V4L2SliceVideoDecoder::PumpDecodeTask() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
-  DCHECK(state_ == State::kDecoding || state_ == State::kFlushing);
   DVLOGF(3) << "state_:" << static_cast<int>(state_)
             << " Number of Decode requests: " << decode_request_queue_.size();
 
-  if (state_ == State::kFlushing)
+  if (state_ != State::kDecoding)
     return;
 
   pause_reason_ = PauseReason::kNone;
diff --git a/media/gpu/v4l2/v4l2_slice_video_decoder.h b/media/gpu/v4l2/v4l2_slice_video_decoder.h
index 6e39049a..bb6eb9c3 100644
--- a/media/gpu/v4l2/v4l2_slice_video_decoder.h
+++ b/media/gpu/v4l2/v4l2_slice_video_decoder.h
@@ -173,8 +173,8 @@
   void DestroyTask();
   // Reset on decoder thread.
   void ResetTask(base::OnceClosure closure);
-  // Clear all pending requests, and call all pending decode callback with
-  // |status| argument.
+  // Reset |avd_|, clear all pending requests, and call all pending decode
+  // callback with |status| argument.
   void ClearPendingRequests(DecodeStatus status);
 
   // Enqueue |request| to the pending decode request queue, and try to decode
diff --git a/remoting/host/native_messaging/pipe_messaging_channel.cc b/remoting/host/native_messaging/pipe_messaging_channel.cc
index 54f89e0..e13fb78 100644
--- a/remoting/host/native_messaging/pipe_messaging_channel.cc
+++ b/remoting/host/native_messaging/pipe_messaging_channel.cc
@@ -10,6 +10,7 @@
 #include "base/callback.h"
 #include "base/callback_helpers.h"
 #include "base/location.h"
+#include "base/process/process_info.h"
 #include "base/values.h"
 #include "build/build_config.h"
 
@@ -19,6 +20,10 @@
 #include "base/posix/eintr_wrapper.h"
 #endif
 
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
 namespace {
 
 base::File DuplicatePlatformFile(base::File file) {
diff --git a/services/network/public/cpp/cors/cors_error_status.cc b/services/network/public/cpp/cors/cors_error_status.cc
index e1a21928..684de47 100644
--- a/services/network/public/cpp/cors/cors_error_status.cc
+++ b/services/network/public/cpp/cors/cors_error_status.cc
@@ -5,6 +5,7 @@
 #include "services/network/public/cpp/cors/cors_error_status.h"
 
 #include "net/base/net_errors.h"
+#include "services/network/public/mojom/cors.mojom-shared.h"
 
 namespace network {
 
diff --git a/services/network/public/cpp/cors/cors_error_status.h b/services/network/public/cpp/cors/cors_error_status.h
index 3e79c69..32d4018 100644
--- a/services/network/public/cpp/cors/cors_error_status.h
+++ b/services/network/public/cpp/cors/cors_error_status.h
@@ -10,10 +10,13 @@
 #include "base/component_export.h"
 #include "base/memory/scoped_refptr.h"
 #include "net/http/http_response_headers.h"
-#include "services/network/public/mojom/cors.mojom-shared.h"
 
 namespace network {
 
+namespace mojom {
+enum class CorsError : int32_t;
+}
+
 struct COMPONENT_EXPORT(NETWORK_CPP_BASE) CorsErrorStatus {
   // This constructor is used by generated IPC serialization code.
   // Should not use this explicitly.
diff --git a/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc b/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc
index 0659a2d..92b72a1a 100644
--- a/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc
+++ b/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc
@@ -33,6 +33,7 @@
 #include "base/mac/mac_util.h"
 #endif
 
+using base::trace_event::MemoryDumpDeterminism;
 using base::trace_event::MemoryDumpLevelOfDetail;
 using base::trace_event::MemoryDumpType;
 
@@ -118,6 +119,7 @@
 void CoordinatorImpl::RequestGlobalMemoryDump(
     MemoryDumpType dump_type,
     MemoryDumpLevelOfDetail level_of_detail,
+    MemoryDumpDeterminism determinism,
     const std::vector<std::string>& allocator_dump_names,
     RequestGlobalMemoryDumpCallback callback) {
   // This merely strips out the |dump_guid| argument.
@@ -126,8 +128,9 @@
     std::move(callback).Run(success, std::move(global_memory_dump));
   };
 
-  QueuedRequest::Args args(dump_type, level_of_detail, allocator_dump_names,
-                           false /* add_to_trace */, base::kNullProcessId,
+  QueuedRequest::Args args(dump_type, level_of_detail, determinism,
+                           allocator_dump_names, false /* add_to_trace */,
+                           base::kNullProcessId,
                            /*memory_footprint_only=*/false);
   RequestGlobalMemoryDumpInternal(args,
                                   base::BindOnce(adapter, std::move(callback)));
@@ -155,7 +158,8 @@
   QueuedRequest::Args args(
       base::trace_event::MemoryDumpType::SUMMARY_ONLY,
       base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND,
-      allocator_dump_names, false /* add_to_trace */, pid,
+      base::trace_event::MemoryDumpDeterminism::NONE, allocator_dump_names,
+      false /* add_to_trace */, pid,
       /*memory_footprint_only=*/false);
   RequestGlobalMemoryDumpInternal(args,
                                   base::BindOnce(adapter, std::move(callback)));
@@ -174,7 +178,8 @@
 
   QueuedRequest::Args args(
       base::trace_event::MemoryDumpType::SUMMARY_ONLY,
-      base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND, {},
+      base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND,
+      base::trace_event::MemoryDumpDeterminism::NONE, {},
       false /* add_to_trace */, pid, /*memory_footprint_only=*/true);
   RequestGlobalMemoryDumpInternal(args,
                                   base::BindOnce(adapter, std::move(callback)));
@@ -183,6 +188,7 @@
 void CoordinatorImpl::RequestGlobalMemoryDumpAndAppendToTrace(
     MemoryDumpType dump_type,
     MemoryDumpLevelOfDetail level_of_detail,
+    MemoryDumpDeterminism determinism,
     RequestGlobalMemoryDumpAndAppendToTraceCallback callback) {
   // This merely strips out the |dump_ptr| argument.
   auto adapter = [](RequestGlobalMemoryDumpAndAppendToTraceCallback callback,
@@ -191,7 +197,7 @@
     std::move(callback).Run(success, dump_guid);
   };
 
-  QueuedRequest::Args args(dump_type, level_of_detail, {},
+  QueuedRequest::Args args(dump_type, level_of_detail, determinism, {},
                            true /* add_to_trace */, base::kNullProcessId,
                            /*memory_footprint_only=*/false);
   RequestGlobalMemoryDumpInternal(args,
diff --git a/services/resource_coordinator/memory_instrumentation/coordinator_impl.h b/services/resource_coordinator/memory_instrumentation/coordinator_impl.h
index 8b18b2c..2395d75 100644
--- a/services/resource_coordinator/memory_instrumentation/coordinator_impl.h
+++ b/services/resource_coordinator/memory_instrumentation/coordinator_impl.h
@@ -59,6 +59,7 @@
   void RequestGlobalMemoryDump(
       base::trace_event::MemoryDumpType,
       base::trace_event::MemoryDumpLevelOfDetail,
+      base::trace_event::MemoryDumpDeterminism,
       const std::vector<std::string>& allocator_dump_names,
       RequestGlobalMemoryDumpCallback) override;
   void RequestGlobalMemoryDumpForPid(
@@ -71,6 +72,7 @@
   void RequestGlobalMemoryDumpAndAppendToTrace(
       base::trace_event::MemoryDumpType,
       base::trace_event::MemoryDumpLevelOfDetail,
+      base::trace_event::MemoryDumpDeterminism,
       RequestGlobalMemoryDumpAndAppendToTraceCallback) override;
 
   // mojom::HeapProfilerHelper implementation.
diff --git a/services/resource_coordinator/memory_instrumentation/coordinator_impl_unittest.cc b/services/resource_coordinator/memory_instrumentation/coordinator_impl_unittest.cc
index 09d740e..1f55838 100644
--- a/services/resource_coordinator/memory_instrumentation/coordinator_impl_unittest.cc
+++ b/services/resource_coordinator/memory_instrumentation/coordinator_impl_unittest.cc
@@ -89,18 +89,20 @@
   }
 
   void RequestGlobalMemoryDump(RequestGlobalMemoryDumpCallback callback) {
-    RequestGlobalMemoryDump(MemoryDumpType::SUMMARY_ONLY,
-                            MemoryDumpLevelOfDetail::BACKGROUND, {},
-                            std::move(callback));
+    RequestGlobalMemoryDump(
+        MemoryDumpType::SUMMARY_ONLY, MemoryDumpLevelOfDetail::BACKGROUND,
+        MemoryDumpDeterminism::NONE, {}, std::move(callback));
   }
 
   void RequestGlobalMemoryDump(
       MemoryDumpType dump_type,
       MemoryDumpLevelOfDetail level_of_detail,
+      MemoryDumpDeterminism determinism,
       const std::vector<std::string>& allocator_dump_names,
       RequestGlobalMemoryDumpCallback callback) {
-    coordinator_->RequestGlobalMemoryDump(
-        dump_type, level_of_detail, allocator_dump_names, std::move(callback));
+    coordinator_->RequestGlobalMemoryDump(dump_type, level_of_detail,
+                                          determinism, allocator_dump_names,
+                                          std::move(callback));
   }
 
   void RequestGlobalMemoryDumpForPid(
@@ -115,7 +117,7 @@
       RequestGlobalMemoryDumpAndAppendToTraceCallback callback) {
     coordinator_->RequestGlobalMemoryDumpAndAppendToTrace(
         MemoryDumpType::EXPLICITLY_TRIGGERED, MemoryDumpLevelOfDetail::DETAILED,
-        std::move(callback));
+        MemoryDumpDeterminism::NONE, std::move(callback));
   }
 
   void GetVmRegionsForHeapProfiler(
@@ -805,8 +807,8 @@
 
   trace_analyzer::Start(MemoryDumpManager::kTraceCategory);
   RequestGlobalMemoryDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                          MemoryDumpLevelOfDetail::DETAILED, {},
-                          callback.Get());
+                          MemoryDumpLevelOfDetail::DETAILED,
+                          MemoryDumpDeterminism::NONE, {}, callback.Get());
   run_loop.Run();
   auto analyzer = trace_analyzer::Stop();
 
diff --git a/services/resource_coordinator/memory_instrumentation/queued_request.cc b/services/resource_coordinator/memory_instrumentation/queued_request.cc
index 40e97d44..f22dc41 100644
--- a/services/resource_coordinator/memory_instrumentation/queued_request.cc
+++ b/services/resource_coordinator/memory_instrumentation/queued_request.cc
@@ -8,12 +8,14 @@
 
 QueuedRequest::Args::Args(MemoryDumpType dump_type,
                           MemoryDumpLevelOfDetail level_of_detail,
+                          MemoryDumpDeterminism determinism,
                           const std::vector<std::string>& allocator_dump_names,
                           bool add_to_trace,
                           base::ProcessId pid,
                           bool memory_footprint_only)
     : dump_type(dump_type),
       level_of_detail(level_of_detail),
+      determinism(determinism),
       allocator_dump_names(allocator_dump_names),
       add_to_trace(add_to_trace),
       pid(pid),
@@ -45,6 +47,7 @@
   request_args.dump_guid = dump_guid;
   request_args.dump_type = args.dump_type;
   request_args.level_of_detail = args.level_of_detail;
+  request_args.determinism = args.determinism;
   return request_args;
 }
 
diff --git a/services/resource_coordinator/memory_instrumentation/queued_request.h b/services/resource_coordinator/memory_instrumentation/queued_request.h
index a0df132..f51e232 100644
--- a/services/resource_coordinator/memory_instrumentation/queued_request.h
+++ b/services/resource_coordinator/memory_instrumentation/queued_request.h
@@ -15,6 +15,7 @@
 #include "base/trace_event/memory_dump_request_args.h"
 #include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
 
+using base::trace_event::MemoryDumpDeterminism;
 using base::trace_event::MemoryDumpLevelOfDetail;
 using base::trace_event::MemoryDumpType;
 
@@ -32,6 +33,7 @@
   struct Args {
     Args(MemoryDumpType dump_type,
          MemoryDumpLevelOfDetail level_of_detail,
+         MemoryDumpDeterminism determinism,
          const std::vector<std::string>& allocator_dump_names,
          bool add_to_trace,
          base::ProcessId pid,
@@ -41,6 +43,7 @@
 
     const MemoryDumpType dump_type;
     const MemoryDumpLevelOfDetail level_of_detail;
+    const MemoryDumpDeterminism determinism;
     const std::vector<std::string> allocator_dump_names;
     const bool add_to_trace;
     const base::ProcessId pid;
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.cc b/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.cc
index 0d9ca71..279ef11 100644
--- a/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.cc
+++ b/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.cc
@@ -128,6 +128,7 @@
     coordinator = MemoryInstrumentation::GetInstance()->GetCoordinator();
   coordinator->RequestGlobalMemoryDumpAndAppendToTrace(
       dump_type, level_of_detail,
+      base::trace_event::MemoryDumpDeterminism::NONE,
       mojom::Coordinator::RequestGlobalMemoryDumpAndAppendToTraceCallback());
 }
 
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.cc b/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.cc
index ea896a00..c81d5f8 100644
--- a/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.cc
+++ b/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.cc
@@ -45,7 +45,7 @@
     RequestGlobalDumpCallback callback) {
   coordinator_->RequestGlobalMemoryDump(
       MemoryDumpType::SUMMARY_ONLY, MemoryDumpLevelOfDetail::BACKGROUND,
-      allocator_dump_names,
+      MemoryDumpDeterminism::NONE, allocator_dump_names,
       base::BindOnce(&WrapGlobalMemoryDump, std::move(callback)));
 }
 
@@ -68,9 +68,10 @@
 void MemoryInstrumentation::RequestGlobalDumpAndAppendToTrace(
     MemoryDumpType dump_type,
     MemoryDumpLevelOfDetail level_of_detail,
+    MemoryDumpDeterminism determinism,
     RequestGlobalMemoryDumpAndAppendToTraceCallback callback) {
   coordinator_->RequestGlobalMemoryDumpAndAppendToTrace(
-      dump_type, level_of_detail, std::move(callback));
+      dump_type, level_of_detail, determinism, std::move(callback));
 }
 
 }  // namespace memory_instrumentation
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h b/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h
index fd429c3..3264917 100644
--- a/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h
+++ b/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h
@@ -25,6 +25,7 @@
  public:
   using MemoryDumpType = base::trace_event::MemoryDumpType;
   using MemoryDumpLevelOfDetail = base::trace_event::MemoryDumpLevelOfDetail;
+  using MemoryDumpDeterminism = base::trace_event::MemoryDumpDeterminism;
   using RequestGlobalDumpCallback =
       base::OnceCallback<void(bool success,
                               std::unique_ptr<GlobalMemoryDump> dump)>;
@@ -93,6 +94,7 @@
   void RequestGlobalDumpAndAppendToTrace(
       MemoryDumpType,
       MemoryDumpLevelOfDetail,
+      MemoryDumpDeterminism,
       RequestGlobalMemoryDumpAndAppendToTraceCallback);
 
  private:
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.typemap b/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.typemap
index 04a084f2..421b6ee 100644
--- a/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.typemap
+++ b/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.typemap
@@ -21,6 +21,7 @@
 type_mappings = [
   "memory_instrumentation.mojom.DumpType=::base::trace_event::MemoryDumpType",
   "memory_instrumentation.mojom.LevelOfDetail=::base::trace_event::MemoryDumpLevelOfDetail",
+  "memory_instrumentation.mojom.Determinism=::base::trace_event::MemoryDumpDeterminism",
   "memory_instrumentation.mojom.RequestArgs=::base::trace_event::MemoryDumpRequestArgs",
   "memory_instrumentation.mojom.RawAllocatorDumpEdge=::base::trace_event::ProcessMemoryDump::MemoryAllocatorDumpEdge",
   "memory_instrumentation.mojom.RawAllocatorDumpEntry=::base::trace_event::MemoryAllocatorDump::Entry[move_only]",
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_mojom_traits.cc b/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_mojom_traits.cc
index a20880a..a7ab6f8 100644
--- a/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_mojom_traits.cc
+++ b/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_mojom_traits.cc
@@ -89,6 +89,42 @@
 }
 
 // static
+memory_instrumentation::mojom::Determinism
+EnumTraits<memory_instrumentation::mojom::Determinism,
+           base::trace_event::MemoryDumpDeterminism>::
+    ToMojom(base::trace_event::MemoryDumpDeterminism determinism) {
+  switch (determinism) {
+    case base::trace_event::MemoryDumpDeterminism::NONE:
+      return memory_instrumentation::mojom::Determinism::NONE;
+    case base::trace_event::MemoryDumpDeterminism::FORCE_GC:
+      return memory_instrumentation::mojom::Determinism::FORCE_GC;
+    default:
+      CHECK(false) << "Invalid type: " << static_cast<uint8_t>(determinism);
+      // This should not be reached. Just return a random value.
+      return memory_instrumentation::mojom::Determinism::NONE;
+  }
+}
+
+// static
+bool EnumTraits<memory_instrumentation::mojom::Determinism,
+                base::trace_event::MemoryDumpDeterminism>::
+    FromMojom(memory_instrumentation::mojom::Determinism input,
+              base::trace_event::MemoryDumpDeterminism* out) {
+  switch (input) {
+    case memory_instrumentation::mojom::Determinism::NONE:
+      *out = base::trace_event::MemoryDumpDeterminism::NONE;
+      break;
+    case memory_instrumentation::mojom::Determinism::FORCE_GC:
+      *out = base::trace_event::MemoryDumpDeterminism::FORCE_GC;
+      break;
+    default:
+      NOTREACHED() << "Invalid type: " << static_cast<uint8_t>(input);
+      return false;
+  }
+  return true;
+}
+
+// static
 bool StructTraits<memory_instrumentation::mojom::RequestArgsDataView,
                   base::trace_event::MemoryDumpRequestArgs>::
     Read(memory_instrumentation::mojom::RequestArgsDataView input,
@@ -98,6 +134,8 @@
     return false;
   if (!input.ReadLevelOfDetail(&out->level_of_detail))
     return false;
+  if (!input.ReadDeterminism(&out->determinism))
+    return false;
   return true;
 }
 
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_mojom_traits.h b/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_mojom_traits.h
index a048719..6493fee 100644
--- a/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_mojom_traits.h
+++ b/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_mojom_traits.h
@@ -35,6 +35,16 @@
 
 template <>
 struct COMPONENT_EXPORT(RESOURCE_COORDINATOR_PUBLIC_MOJOM)
+    EnumTraits<memory_instrumentation::mojom::Determinism,
+               base::trace_event::MemoryDumpDeterminism> {
+  static memory_instrumentation::mojom::Determinism ToMojom(
+      base::trace_event::MemoryDumpDeterminism determinism);
+  static bool FromMojom(memory_instrumentation::mojom::Determinism input,
+                        base::trace_event::MemoryDumpDeterminism* out);
+};
+
+template <>
+struct COMPONENT_EXPORT(RESOURCE_COORDINATOR_PUBLIC_MOJOM)
     StructTraits<memory_instrumentation::mojom::RequestArgsDataView,
                  base::trace_event::MemoryDumpRequestArgs> {
   static uint64_t dump_guid(
@@ -49,6 +59,10 @@
       const base::trace_event::MemoryDumpRequestArgs& args) {
     return args.level_of_detail;
   }
+  static base::trace_event::MemoryDumpDeterminism determinism(
+      const base::trace_event::MemoryDumpRequestArgs& args) {
+    return args.determinism;
+  }
   static bool Read(memory_instrumentation::mojom::RequestArgsDataView input,
                    base::trace_event::MemoryDumpRequestArgs* out);
 };
@@ -191,6 +205,10 @@
       const std::unique_ptr<base::trace_event::ProcessMemoryDump>& pmd) {
     return pmd->dump_args().level_of_detail;
   }
+  static base::trace_event::MemoryDumpDeterminism determinism(
+      const std::unique_ptr<base::trace_event::ProcessMemoryDump>& pmd) {
+    return pmd->dump_args().determinism;
+  }
 
   static void SetToNull(
       std::unique_ptr<base::trace_event::ProcessMemoryDump>* out) {
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_integration_unittest.cc b/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_integration_unittest.cc
index b210007..38590f67 100644
--- a/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_integration_unittest.cc
+++ b/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_integration_unittest.cc
@@ -35,6 +35,7 @@
 
 using base::trace_event::MemoryAllocatorDump;
 using base::trace_event::MemoryDumpArgs;
+using base::trace_event::MemoryDumpDeterminism;
 using base::trace_event::MemoryDumpLevelOfDetail;
 using base::trace_event::MemoryDumpManager;
 using base::trace_event::MemoryDumpProvider;
@@ -110,6 +111,7 @@
   void RequestGlobalMemoryDump(
       MemoryDumpType dump_type,
       MemoryDumpLevelOfDetail level_of_detail,
+      MemoryDumpDeterminism determinism,
       const std::vector<std::string>& allocator_dump_names,
       RequestGlobalMemoryDumpCallback) override;
 
@@ -125,6 +127,7 @@
   void RequestGlobalMemoryDumpAndAppendToTrace(
       MemoryDumpType dump_type,
       MemoryDumpLevelOfDetail level_of_detail,
+      MemoryDumpDeterminism determinism,
       RequestGlobalMemoryDumpAndAppendToTraceCallback) override;
 
  private:
@@ -193,9 +196,11 @@
   }
 
   void RequestChromeDump(MemoryDumpType dump_type,
-                         MemoryDumpLevelOfDetail level_of_detail) {
+                         MemoryDumpLevelOfDetail level_of_detail,
+                         MemoryDumpDeterminism determinism) {
     uint64_t req_guid = ++guid_counter_;
-    MemoryDumpRequestArgs request_args{req_guid, dump_type, level_of_detail};
+    MemoryDumpRequestArgs request_args{req_guid, dump_type, level_of_detail,
+                                       determinism};
     ClientProcessImpl::RequestChromeMemoryDumpCallback callback =
         base::BindOnce(
             [](bool success, uint64_t dump_guid,
@@ -251,17 +256,19 @@
 void MockCoordinator::RequestGlobalMemoryDump(
     MemoryDumpType dump_type,
     MemoryDumpLevelOfDetail level_of_detail,
+    MemoryDumpDeterminism determinism,
     const std::vector<std::string>& allocator_dump_names,
     RequestGlobalMemoryDumpCallback callback) {
-  client_->RequestChromeDump(dump_type, level_of_detail);
+  client_->RequestChromeDump(dump_type, level_of_detail, determinism);
   std::move(callback).Run(true, mojom::GlobalMemoryDumpPtr());
 }
 
 void MockCoordinator::RequestGlobalMemoryDumpAndAppendToTrace(
     MemoryDumpType dump_type,
     MemoryDumpLevelOfDetail level_of_detail,
+    MemoryDumpDeterminism determinism,
     RequestGlobalMemoryDumpAndAppendToTraceCallback callback) {
-  client_->RequestChromeDump(dump_type, level_of_detail);
+  client_->RequestChromeDump(dump_type, level_of_detail, determinism);
   std::move(callback).Run(1, true);
 }
 
diff --git a/services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom b/services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom
index 3a3c1b1..d12e4d9 100644
--- a/services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom
+++ b/services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom
@@ -22,6 +22,13 @@
   DETAILED
 };
 
+// Tells the MemoryDumpProvider(s) if they should try to make the result
+// more deterministic by forcing garbage collection.
+enum Determinism {
+  NONE,
+  FORCE_GC
+};
+
 enum ProcessType {
   OTHER,
   BROWSER,
@@ -53,6 +60,7 @@
   uint64 dump_guid;
   DumpType dump_type;
   LevelOfDetail level_of_detail;
+  Determinism determinism;
 };
 
 struct RawAllocatorDumpEdge {
@@ -301,6 +309,7 @@
   // entries which contain fields such as "size" and "effective_size".
   RequestGlobalMemoryDump(DumpType dump_type,
                           LevelOfDetail level_of_detail,
+                          Determinism determinsm,
                           array<string> allocator_dump_names) =>
       (bool success, GlobalMemoryDump? global_memory_dump);
 
@@ -319,7 +328,8 @@
   // Broadcasts a dump request to all registered client processes and injects the
   // dump in the trace buffer (if tracing is enabled).
   RequestGlobalMemoryDumpAndAppendToTrace(DumpType dump_type,
-                                          LevelOfDetail level_of_detail) =>
+                                          LevelOfDetail level_of_detail,
+                                          Determinism determinism) =>
       (bool success, uint64 dump_id);
 };
 
diff --git a/services/viz/public/cpp/gpu/gpu.cc b/services/viz/public/cpp/gpu/gpu.cc
index eae7764..307cf41 100644
--- a/services/viz/public/cpp/gpu/gpu.cc
+++ b/services/viz/public/cpp/gpu/gpu.cc
@@ -11,6 +11,7 @@
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/threading/thread_checker.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
diff --git a/skia/BUILD.gn b/skia/BUILD.gn
index 3fda6d4..1f9e7c1 100644
--- a/skia/BUILD.gn
+++ b/skia/BUILD.gn
@@ -314,6 +314,7 @@
       "//third_party/skia/src/codec/SkJpegUtility.cpp",
       "//third_party/skia/src/codec/SkMaskSwizzler.cpp",
       "//third_party/skia/src/codec/SkMasks.cpp",
+      "//third_party/skia/src/codec/SkParseEncodedOrigin.cpp",
       "//third_party/skia/src/codec/SkPngCodec.cpp",
       "//third_party/skia/src/codec/SkSampler.cpp",
       "//third_party/skia/src/codec/SkStreamBuffer.cpp",
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index c519d0a..4d806ff0 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -4053,27 +4053,6 @@
             ]
         }
     ],
-    "OutOfBlinkCors": [
-        {
-            "platforms": [
-                "android",
-                "android_webview",
-                "chromeos",
-                "ios",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "OutOfBlinkCors"
-                    ]
-                }
-            ]
-        }
-    ],
     "OutOfProcessQuarantine": [
         {
             "platforms": [
@@ -4108,6 +4087,21 @@
             ]
         }
     ],
+    "OverlayNewLayout": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "OverlayNewLayout",
+                    "enable_features": [
+                        "OverlayNewLayout"
+                    ]
+                }
+            ]
+        }
+    ],
     "PDFClickToOpen": [
         {
             "platforms": [
diff --git a/third_party/blink/public/platform/web_localized_string.h b/third_party/blink/public/platform/web_localized_string.h
index e62672e..61028d0 100644
--- a/third_party/blink/public/platform/web_localized_string.h
+++ b/third_party/blink/public/platform/web_localized_string.h
@@ -72,8 +72,6 @@
     kAXMediaTouchLessSeekAction,
     kAXMediaTouchLessVolumeAction,
     kBlockedPluginText,
-    kCalendarClear,
-    kCalendarToday,
     kDetailsLabel,
     kFileButtonNoFileSelectedLabel,
     kInputElementAltText,
diff --git a/third_party/blink/public/platform/web_runtime_features.h b/third_party/blink/public/platform/web_runtime_features.h
index 7fc1ca3..f7c993b 100644
--- a/third_party/blink/public/platform/web_runtime_features.h
+++ b/third_party/blink/public/platform/web_runtime_features.h
@@ -235,7 +235,6 @@
       bool);
   BLINK_PLATFORM_EXPORT static void EnableIdleDetection(bool);
   BLINK_PLATFORM_EXPORT static void EnableSkipTouchEventFilter(bool);
-  BLINK_PLATFORM_EXPORT static void EnableStaleWhileRevalidate(bool);
   BLINK_PLATFORM_EXPORT static void EnableSmsReceiver(bool);
   BLINK_PLATFORM_EXPORT static void EnableDisplayLocking(bool);
   BLINK_PLATFORM_EXPORT static void
diff --git a/third_party/blink/public/platform/web_url_loader.h b/third_party/blink/public/platform/web_url_loader.h
index 7bb0b6b..17d09c8 100644
--- a/third_party/blink/public/platform/web_url_loader.h
+++ b/third_party/blink/public/platform/web_url_loader.h
@@ -37,6 +37,10 @@
 #include "third_party/blink/public/platform/web_common.h"
 #include "third_party/blink/public/platform/web_url_request.h"
 
+namespace base {
+class SingleThreadTaskRunner;
+}
+
 namespace blink {
 
 class WebData;
diff --git a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h
index 98de584..c893f39 100644
--- a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h
+++ b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h
@@ -81,11 +81,6 @@
       mojo::ScopedMessagePipeHandle devtools_agent_ptr_info,
       mojo::ScopedMessagePipeHandle devtools_agent_host_request) {}
 
-  // Starting the worker failed. This could happen when loading the worker
-  // script failed, or the worker was asked to terminate before startup
-  // completed. Called on the initiator thread.
-  virtual void WorkerContextFailedToStartOnInitiatorThread() {}
-
   // The worker started but it could not execute because loading the classic
   // script failed on the worker thread. This is called only for installed
   // scripts fetch or off-the-main-thread classic worker script fetch.
diff --git a/third_party/blink/renderer/bindings/core/v8/DEPS b/third_party/blink/renderer/bindings/core/v8/DEPS
new file mode 100644
index 0000000..c386e5e
--- /dev/null
+++ b/third_party/blink/renderer/bindings/core/v8/DEPS
@@ -0,0 +1,5 @@
+specific_include_rules = {
+  "script_promise_resolver_test.cc": [
+    "+base/run_loop.h",
+  ]
+}
\ No newline at end of file
diff --git a/third_party/blink/renderer/bindings/core/v8/js_event_handler.cc b/third_party/blink/renderer/bindings/core/v8/js_event_handler.cc
index 8e525d16..b5062cc 100644
--- a/third_party/blink/renderer/bindings/core/v8/js_event_handler.cc
+++ b/third_party/blink/renderer/bindings/core/v8/js_event_handler.cc
@@ -99,9 +99,10 @@
     // https://html.spec.whatwg.org/C/#runtime-script-errors-2
     ScriptValue error_attribute = error_event->error(script_state_of_listener);
     if (error_attribute.IsEmpty() ||
-        error_event->target()->InterfaceName() == event_target_names::kWorker)
-      error_attribute = ScriptValue::CreateNull(script_state_of_listener);
-
+        error_event->target()->InterfaceName() == event_target_names::kWorker) {
+      error_attribute =
+          ScriptValue::CreateNull(script_state_of_listener->GetIsolate());
+    }
     arguments = {
         ScriptValue::From(script_state_of_listener, error_event->message()),
         ScriptValue::From(script_state_of_listener, error_event->filename()),
diff --git a/third_party/blink/renderer/bindings/core/v8/script_promise.cc b/third_party/blink/renderer/bindings/core/v8/script_promise.cc
index 2efdbb19a..54ba036 100644
--- a/third_party/blink/renderer/bindings/core/v8/script_promise.cc
+++ b/third_party/blink/renderer/bindings/core/v8/script_promise.cc
@@ -168,7 +168,7 @@
 
 ScriptPromise::InternalResolver::InternalResolver(ScriptState* script_state)
     : script_state_(script_state),
-      resolver_(script_state,
+      resolver_(script_state->GetIsolate(),
                 v8::Promise::Resolver::New(script_state->GetContext())) {
   // |resolver| can be empty when the thread is being terminated. We ignore such
   // errors.
@@ -219,7 +219,7 @@
     return;
 
   if (!value->IsPromise()) {
-    promise_ = ScriptValue(script_state, v8::Local<v8::Value>());
+    promise_ = ScriptValue();
     V8ThrowException::ThrowTypeError(script_state->GetIsolate(),
                                      "the given value is not a Promise");
     return;
diff --git a/third_party/blink/renderer/bindings/core/v8/script_promise_resolver_test.cc b/third_party/blink/renderer/bindings/core/v8/script_promise_resolver_test.cc
index 0243503..7d92626 100644
--- a/third_party/blink/renderer/bindings/core/v8/script_promise_resolver_test.cc
+++ b/third_party/blink/renderer/bindings/core/v8/script_promise_resolver_test.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "base/run_loop.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_function.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
diff --git a/third_party/blink/renderer/bindings/core/v8/script_value.cc b/third_party/blink/renderer/bindings/core/v8/script_value.cc
index 4df0bae..ee44862 100644
--- a/third_party/blink/renderer/bindings/core/v8/script_value.cc
+++ b/third_party/blink/renderer/bindings/core/v8/script_value.cc
@@ -35,43 +35,13 @@
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 
 namespace blink {
-namespace {
-
-v8::Local<v8::Value> ToWorldSafeValue(ScriptState* target_script_state,
-                                      v8::Local<v8::Value> value) {
-  if (value.IsEmpty() || !value->IsObject())
-    return value;
-
-  v8::Local<v8::Context> creation_context =
-      value.As<v8::Object>()->CreationContext();
-  v8::Isolate* isolate = target_script_state->GetIsolate();
-  if (&ScriptState::From(creation_context)->World() ==
-      &target_script_state->World()) {
-    return value;
-  }
-
-  v8::Context::Scope target_context_scope(target_script_state->GetContext());
-  scoped_refptr<SerializedScriptValue> serialized =
-      SerializedScriptValue::SerializeAndSwallowExceptions(isolate, value);
-  return serialized->Deserialize(isolate);
-}
-
-}  // namespace
 
 v8::Local<v8::Value> ScriptValue::V8Value() const {
   if (IsEmpty())
     return v8::Local<v8::Value>();
 
   DCHECK(GetIsolate()->InContext());
-
-  // This is a check to validate that you don't return a ScriptValue to a world
-  // different from the world that created the ScriptValue.
-  // Probably this could be:
-  //   if (&script_state_->world() == &DOMWrapperWorld::current(isolate()))
-  //       return v8::Local<v8::Value>();
-  // instead of triggering CHECK.
-  CHECK_EQ(&script_state_->World(), &DOMWrapperWorld::Current(GetIsolate()));
-  return value_->NewLocal(GetIsolate());
+  return value_.Get(ScriptState::From(isolate_->GetCurrentContext()));
 }
 
 v8::Local<v8::Value> ScriptValue::V8ValueFor(
@@ -79,15 +49,13 @@
   if (IsEmpty())
     return v8::Local<v8::Value>();
 
-  return ToWorldSafeValue(target_script_state,
-                          value_->NewLocal(target_script_state->GetIsolate()));
+  return value_.GetAcrossWorld(target_script_state);
 }
 
 bool ScriptValue::ToString(String& result) const {
   if (IsEmpty())
     return false;
 
-  ScriptState::Scope scope(script_state_);
   v8::Local<v8::Value> string = V8Value();
   if (string.IsEmpty() || !string->IsString())
     return false;
@@ -95,8 +63,8 @@
   return true;
 }
 
-ScriptValue ScriptValue::CreateNull(ScriptState* script_state) {
-  return ScriptValue(script_state, v8::Null(script_state->GetIsolate()));
+ScriptValue ScriptValue::CreateNull(v8::Isolate* isolate) {
+  return ScriptValue(isolate, v8::Null(isolate));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/bindings/core/v8/script_value.h b/third_party/blink/renderer/bindings/core/v8/script_value.h
index 5076538..134d872e 100644
--- a/third_party/blink/renderer/bindings/core/v8/script_value.h
+++ b/third_party/blink/renderer/bindings/core/v8/script_value.h
@@ -33,9 +33,11 @@
 
 #include "base/memory/scoped_refptr.h"
 #include "third_party/blink/renderer/bindings/core/v8/native_value_traits.h"
+#include "third_party/blink/renderer/bindings/core/v8/world_safe_v8_reference.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/bindings/shared_persistent.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "v8/include/v8.h"
@@ -69,51 +71,66 @@
 
   ScriptValue() = default;
 
+  // TODO(rikaf): Forbid passing empty v8::Local<v8::Value> to ScriptValue's
+  // ctor.
+
+  // TODO(crbug.com/998994): Remove ScriptValue(ScriptState*,
+  // v8::Local<v8::Value>) once we finish replacing with ScriptValue(Isolate*,
+  // v8::Local<v8::Value>)
   ScriptValue(ScriptState* script_state, v8::Local<v8::Value> value)
-      : script_state_(script_state),
-        value_(value.IsEmpty() ? nullptr
-                               : SharedPersistent<v8::Value>::Create(
-                                     value,
-                                     script_state->GetIsolate())) {
-    DCHECK(IsEmpty() || script_state_);
+      : isolate_(script_state->GetIsolate()),
+        value_(value.IsEmpty()
+                   ? WorldSafeV8Reference<v8::Value>()
+                   : WorldSafeV8Reference<v8::Value>(script_state->GetIsolate(),
+                                                     value)) {
+    DCHECK(isolate_);
+  }
+
+  ScriptValue(v8::Isolate* isolate, v8::Local<v8::Value> value)
+      : isolate_(isolate),
+        value_(value.IsEmpty()
+                   ? WorldSafeV8Reference<v8::Value>()
+                   : WorldSafeV8Reference<v8::Value>(isolate, value)) {
+    DCHECK(isolate_);
   }
 
   template <typename T>
-  ScriptValue(ScriptState* script_state, v8::MaybeLocal<T> value)
-      : script_state_(script_state),
-        value_(value.IsEmpty() ? nullptr
-                               : SharedPersistent<v8::Value>::Create(
-                                     value.ToLocalChecked(),
-                                     script_state->GetIsolate())) {
-    DCHECK(IsEmpty() || script_state_);
+  ScriptValue(v8::Isolate* isolate, v8::MaybeLocal<T> value)
+      : isolate_(isolate),
+        value_(value.IsEmpty()
+                   ? WorldSafeV8Reference<v8::Value>()
+                   : WorldSafeV8Reference<v8::Value>(isolate,
+                                                     value.ToLocalChecked())) {
+    DCHECK(isolate_);
   }
 
-  ScriptValue(const ScriptValue& value)
-      : script_state_(value.script_state_), value_(value.value_) {
-    DCHECK(IsEmpty() || script_state_);
+  ScriptValue(v8::Isolate* isolate, WorldSafeV8Reference<v8::Value> value)
+      : isolate_(isolate), value_(value) {
+    DCHECK(isolate_);
   }
 
-  ScriptState* GetScriptState() const { return script_state_; }
-
-  v8::Isolate* GetIsolate() const {
-    return script_state_ ? script_state_->GetIsolate()
-                         : v8::Isolate::GetCurrent();
-  }
-
-  ScriptValue& operator=(const ScriptValue& value) {
-    if (this != &value) {
-      script_state_ = value.script_state_;
+  ScriptValue(const ScriptValue& value) {
+    // TODO(crbug.com/v8/9773): Deal with null value at the side of v8.
+    if (value.IsEmpty()) {
+      isolate_ = nullptr;
+      value_.Reset();
+    } else {
+      isolate_ = value.isolate_;
       value_ = value.value_;
+      DCHECK(isolate_);
     }
-    return *this;
   }
 
+  // Use this GetIsolate() to do DCHECK inside ScriptValue.
+  v8::Isolate* GetIsolate() const {
+    DCHECK(isolate_);
+    return isolate_;
+  }
+
+  ScriptValue& operator=(const ScriptValue& value) = default;
+
   bool operator==(const ScriptValue& value) const {
-    if (IsEmpty())
-      return value.IsEmpty();
-    if (value.IsEmpty())
-      return false;
-    return *value_ == *value.value_;
+    return value_ == value.value_;
   }
 
   bool operator!=(const ScriptValue& value) const { return !operator==(value); }
@@ -150,9 +167,12 @@
     return !value.IsEmpty() && value->IsObject();
   }
 
-  bool IsEmpty() const { return !value_.get() || value_->IsEmpty(); }
+  bool IsEmpty() const { return value_.IsEmpty(); }
 
-  void Clear() { value_ = nullptr; }
+  void Clear() {
+    isolate_ = nullptr;
+    value_.Reset();
+  }
 
   v8::Local<v8::Value> V8Value() const;
   // Returns v8Value() if a given ScriptState is the same as the
@@ -160,15 +180,19 @@
   // this "clones" the v8 value and returns it.
   v8::Local<v8::Value> V8ValueFor(ScriptState*) const;
 
+  const WorldSafeV8Reference<v8::Value>& ToWorldSafeV8Reference() const {
+    return value_;
+  }
+
   bool ToString(String&) const;
 
-  static ScriptValue CreateNull(ScriptState*);
+  static ScriptValue CreateNull(v8::Isolate*);
 
-  void Trace(Visitor* visitor) { visitor->Trace(script_state_); }
+  void Trace(Visitor* visitor) { visitor->Trace(value_); }
 
  private:
-  Member<ScriptState> script_state_;
-  scoped_refptr<SharedPersistent<v8::Value>> value_;
+  v8::Isolate* isolate_ = nullptr;
+  WorldSafeV8Reference<v8::Value> value_;
 };
 
 template <>
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_extras_test_utils.cc b/third_party/blink/renderer/bindings/core/v8/v8_extras_test_utils.cc
index 7623ed7..16a021bd 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_extras_test_utils.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_extras_test_utils.cc
@@ -33,7 +33,7 @@
     ADD_FAILURE() << "Compilation fails";
     return ScriptValue();
   }
-  return ScriptValue(scope->GetScriptState(), script->Run(scope->GetContext()));
+  return ScriptValue(scope->GetIsolate(), script->Run(scope->GetContext()));
 }
 
 ScriptValue EvalWithPrintingError(V8TestingScope* scope, const char* script) {
diff --git a/third_party/blink/renderer/bindings/core/v8/world_safe_v8_reference.cc b/third_party/blink/renderer/bindings/core/v8/world_safe_v8_reference.cc
index 7ee67ac..6bc84e4 100644
--- a/third_party/blink/renderer/bindings/core/v8/world_safe_v8_reference.cc
+++ b/third_party/blink/renderer/bindings/core/v8/world_safe_v8_reference.cc
@@ -40,6 +40,9 @@
     v8::Local<v8::Value> value) {
   if (!value->IsObject())
     return;
+  // TODO(crbug.com/v8/9713): Let JSModuleNamespaceObject have CreationContext.
+  if (value->IsModuleNamespaceObject())
+    return;
 
   ScriptState* script_state =
       ScriptState::From(value.As<v8::Object>()->CreationContext());
diff --git a/third_party/blink/renderer/bindings/core/v8/world_safe_v8_reference.h b/third_party/blink/renderer/bindings/core/v8/world_safe_v8_reference.h
index 85b3e32..f3bb51bc 100644
--- a/third_party/blink/renderer/bindings/core/v8/world_safe_v8_reference.h
+++ b/third_party/blink/renderer/bindings/core/v8/world_safe_v8_reference.h
@@ -107,14 +107,19 @@
 
   void Trace(blink::Visitor* visitor) { visitor->Trace(v8_reference_); }
 
+  WorldSafeV8Reference& operator=(const WorldSafeV8Reference<V8Type>& other) =
+      default;
+
+  bool operator==(const WorldSafeV8Reference<V8Type>& other) const {
+    return v8_reference_ == other.v8_reference_;
+  }
+
  private:
   TraceWrapperV8Reference<V8Type> v8_reference_;
   // The world of the current context at the time when |v8_reference_| was set.
   // It's guaranteed that, if |v8_reference_| is a v8::Object, the world of the
   // creation context of |v8_reference_| is the same as |world_|.
   scoped_refptr<const DOMWrapperWorld> world_;
-
-  DISALLOW_COPY_AND_ASSIGN(WorldSafeV8Reference);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/bindings/modules/v8/generated.gni b/third_party/blink/renderer/bindings/modules/v8/generated.gni
index 88ea668..f933cbd 100644
--- a/third_party/blink/renderer/bindings/modules/v8/generated.gni
+++ b/third_party/blink/renderer/bindings/modules/v8/generated.gni
@@ -52,8 +52,8 @@
   "$bindings_modules_v8_output_dir/gpu_load_op_or_gpu_color.h",
   "$bindings_modules_v8_output_dir/gpu_load_op_or_float.cc",
   "$bindings_modules_v8_output_dir/gpu_load_op_or_float.h",
-  "$bindings_modules_v8_output_dir/gpu_load_op_or_long.cc",
-  "$bindings_modules_v8_output_dir/gpu_load_op_or_long.h",
+  "$bindings_modules_v8_output_dir/gpu_load_op_or_unsigned_long.cc",
+  "$bindings_modules_v8_output_dir/gpu_load_op_or_unsigned_long.h",
   "$bindings_modules_v8_output_dir/gpu_sampler_or_gpu_texture_view_or_gpu_buffer_binding.cc",
   "$bindings_modules_v8_output_dir/gpu_sampler_or_gpu_texture_view_or_gpu_buffer_binding.h",
   "$bindings_modules_v8_output_dir/html_canvas_element_or_offscreen_canvas.cc",
diff --git a/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.cc b/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.cc
index 965f6ec..8e1db2c 100644
--- a/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.cc
+++ b/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.cc
@@ -724,7 +724,7 @@
   v8::Isolate* isolate = script_state->GetIsolate();
   v8::HandleScope handle_scope(isolate);
   if (!serialized_value)
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
 
   SerializedScriptValue::DeserializeOptions options;
   options.blob_info = blob_info;
diff --git a/third_party/blink/renderer/bindings/scripts/v8_types.py b/third_party/blink/renderer/bindings/scripts/v8_types.py
index f14420c..cd9eef5 100644
--- a/third_party/blink/renderer/bindings/scripts/v8_types.py
+++ b/third_party/blink/renderer/bindings/scripts/v8_types.py
@@ -1051,7 +1051,7 @@
     """Converts an expression that is a valid C++ literal for this type."""
     # FIXME: add validation that idl_type and idl_literal are compatible
     if idl_type.base_type in ('any', 'object') and idl_literal.is_null:
-        return 'ScriptValue::CreateNull(script_state)'
+        return 'ScriptValue::CreateNull(script_state->GetIsolate())'
     literal_value = str(idl_literal)
     if idl_type.base_type in ('octet', 'unsigned short', 'unsigned long'):
         return literal_value + 'u'
diff --git a/third_party/blink/renderer/core/animation/animation.h b/third_party/blink/renderer/core/animation/animation.h
index e4ebcaf..313f50c7 100644
--- a/third_party/blink/renderer/core/animation/animation.h
+++ b/third_party/blink/renderer/core/animation/animation.h
@@ -461,6 +461,8 @@
 
   FRIEND_TEST_ALL_PREFIXES(AnimationAnimationTestCompositeAfterPaint,
                            NoCompositeWithoutCompositedElementId);
+  FRIEND_TEST_ALL_PREFIXES(AnimationAnimationTestNoCompositing,
+                           PendingActivityWithFinishedEventListener);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/animation/animation_test.cc b/third_party/blink/renderer/core/animation/animation_test.cc
index 98853f0..21a6051 100644
--- a/third_party/blink/renderer/core/animation/animation_test.cc
+++ b/third_party/blink/renderer/core/animation/animation_test.cc
@@ -33,6 +33,7 @@
 #include <memory>
 
 #include "base/bits.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/core/animation/animation_clock.h"
 #include "third_party/blink/renderer/core/animation/css/compositor_keyframe_double.h"
@@ -45,6 +46,8 @@
 #include "third_party/blink/renderer/core/animation/scroll_timeline.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/dom_node_ids.h"
+#include "third_party/blink/renderer/core/dom/events/event.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
 #include "third_party/blink/renderer/core/dom/qualified_name.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
@@ -1349,4 +1352,120 @@
   EXPECT_FALSE(is_null);
 }
 
+TEST_F(AnimationAnimationTestNoCompositing,
+       RemoveCanceledAnimationFromActiveSet) {
+  EXPECT_EQ("running", animation->playState());
+  EXPECT_TRUE(animation->Update(kTimingUpdateForAnimationFrame));
+  SimulateFrame(1000);
+  EXPECT_TRUE(animation->Update(kTimingUpdateForAnimationFrame));
+  animation->cancel();
+  EXPECT_EQ("idle", animation->playState());
+  EXPECT_FALSE(animation->Update(kTimingUpdateForAnimationFrame));
+}
+
+TEST_F(AnimationAnimationTestNoCompositing,
+       RemoveFinishedAnimationFromActiveSet) {
+  EXPECT_EQ("running", animation->playState());
+  EXPECT_TRUE(animation->Update(kTimingUpdateForAnimationFrame));
+  SimulateFrame(1000);
+  EXPECT_TRUE(animation->Update(kTimingUpdateForAnimationFrame));
+
+  // Synchronous completion.
+  animation->finish();
+  EXPECT_EQ("finished", animation->playState());
+  EXPECT_FALSE(animation->Update(kTimingUpdateForAnimationFrame));
+
+  // Play creates a new pending finished promise.
+  animation->play();
+  EXPECT_EQ("running", animation->playState());
+  EXPECT_TRUE(animation->Update(kTimingUpdateForAnimationFrame));
+
+  // Asynchronous completion.
+  animation->setCurrentTime(50000, false);
+  EXPECT_EQ("finished", animation->playState());
+  EXPECT_FALSE(animation->Update(kTimingUpdateForAnimationFrame));
+}
+
+TEST_F(AnimationAnimationTestNoCompositing,
+       PendingActivityWithFinishedPromise) {
+  // No pending activity even when running if there is no finished promise
+  // or event listener.
+  EXPECT_EQ("running", animation->playState());
+  SimulateFrame(1000);
+  EXPECT_FALSE(animation->HasPendingActivity());
+
+  // An unresolved finished promise indicates pending activity.
+  ScriptState* script_state =
+      ToScriptStateForMainWorld(GetDocument().GetFrame());
+  animation->finished(script_state);
+  EXPECT_TRUE(animation->HasPendingActivity());
+
+  // Resolving the finished promise clears the pending activity.
+  animation->setCurrentTime(50000, false);
+  EXPECT_EQ("finished", animation->playState());
+  EXPECT_FALSE(animation->Update(kTimingUpdateForAnimationFrame));
+  EXPECT_FALSE(animation->HasPendingActivity());
+
+  // Playing an already finished animation creates a new pending finished
+  // promise.
+  animation->play();
+  EXPECT_EQ("running", animation->playState());
+  SimulateFrame(2000);
+  EXPECT_TRUE(animation->HasPendingActivity());
+  // Cancel rejects the finished promise and creates a new pending finished
+  // promise.
+  // TODO(crbug.com/960944): Investigate if this should return false to prevent
+  // holding onto the animation indefinitely.
+  animation->cancel();
+  EXPECT_TRUE(animation->HasPendingActivity());
+}
+
+class MockEventListener final : public NativeEventListener {
+ public:
+  MOCK_METHOD2(Invoke, void(ExecutionContext*, Event*));
+};
+
+TEST_F(AnimationAnimationTestNoCompositing,
+       PendingActivityWithFinishedEventListener) {
+  EXPECT_EQ("running", animation->playState());
+  EXPECT_FALSE(animation->HasPendingActivity());
+
+  // Attaching a listener for the finished event indicates pending activity.
+  Persistent<MockEventListener> event_listener =
+      MakeGarbageCollected<MockEventListener>();
+  animation->addEventListener(event_type_names::kFinish, event_listener);
+  EXPECT_TRUE(animation->HasPendingActivity());
+
+  // Synchronous finish clears pending activity.
+  animation->finish();
+  EXPECT_EQ("finished", animation->playState());
+  EXPECT_FALSE(animation->Update(kTimingUpdateForAnimationFrame));
+  EXPECT_TRUE(animation->HasPendingActivity());
+  animation->pending_finished_event_ = nullptr;
+  EXPECT_FALSE(animation->HasPendingActivity());
+
+  // Playing an already finished animation resets the finished state.
+  animation->play();
+  EXPECT_EQ("running", animation->playState());
+  SimulateFrame(2000);
+  EXPECT_TRUE(animation->HasPendingActivity());
+
+  // Finishing the animation asynchronously clears the pending activity.
+  animation->setCurrentTime(50000, false);
+  EXPECT_EQ("finished", animation->playState());
+  EXPECT_FALSE(animation->Update(kTimingUpdateForAnimationFrame));
+  EXPECT_TRUE(animation->HasPendingActivity());
+  animation->pending_finished_event_ = nullptr;
+  EXPECT_FALSE(animation->HasPendingActivity());
+
+  // Canceling an animation clears the pending activity.
+  animation->play();
+  EXPECT_EQ("running", animation->playState());
+  SimulateFrame(2000);
+  animation->cancel();
+  EXPECT_EQ("idle", animation->playState());
+  EXPECT_FALSE(animation->Update(kTimingUpdateForAnimationFrame));
+  EXPECT_FALSE(animation->HasPendingActivity());
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/animation/keyframe_effect_test.cc b/third_party/blink/renderer/core/animation/keyframe_effect_test.cc
index 7283904..50440af 100644
--- a/third_party/blink/renderer/core/animation/keyframe_effect_test.cc
+++ b/third_party/blink/renderer/core/animation/keyframe_effect_test.cc
@@ -168,7 +168,7 @@
                                   effect_options_dictionary, exception_state);
   EXPECT_FALSE(exception_state.HadException());
 
-  ScriptValue js_keyframes = ScriptValue::CreateNull(script_state);
+  ScriptValue js_keyframes = ScriptValue::CreateNull(scope.GetIsolate());
   KeyframeEffect* effect = CreateAnimationFromOption(
       script_state, element.Get(), js_keyframes, effect_options_dictionary);
   EXPECT_EQ("add", effect->composite());
@@ -220,7 +220,7 @@
 TEST_F(AnimationKeyframeEffectV8Test, CanSetDuration) {
   V8TestingScope scope;
   ScriptState* script_state = scope.GetScriptState();
-  ScriptValue js_keyframes = ScriptValue::CreateNull(script_state);
+  ScriptValue js_keyframes = ScriptValue::CreateNull(scope.GetIsolate());
   double duration = 2000;
 
   KeyframeEffect* animation = CreateAnimationFromTiming(
@@ -233,7 +233,7 @@
 TEST_F(AnimationKeyframeEffectV8Test, CanOmitSpecifiedDuration) {
   V8TestingScope scope;
   ScriptState* script_state = scope.GetScriptState();
-  ScriptValue js_keyframes = ScriptValue::CreateNull(script_state);
+  ScriptValue js_keyframes = ScriptValue::CreateNull(scope.GetIsolate());
   KeyframeEffect* animation =
       CreateAnimation(script_state, element.Get(), js_keyframes);
   EXPECT_FALSE(animation->SpecifiedTiming().iteration_duration);
@@ -242,7 +242,7 @@
 TEST_F(AnimationKeyframeEffectV8Test, SpecifiedGetters) {
   V8TestingScope scope;
   ScriptState* script_state = scope.GetScriptState();
-  ScriptValue js_keyframes = ScriptValue::CreateNull(script_state);
+  ScriptValue js_keyframes = ScriptValue::CreateNull(scope.GetIsolate());
 
   v8::Local<v8::Object> timing_input = v8::Object::New(scope.GetIsolate());
   SetV8ObjectPropertyAsNumber(scope.GetIsolate(), timing_input, "delay", 2);
@@ -281,7 +281,7 @@
 TEST_F(AnimationKeyframeEffectV8Test, SpecifiedDurationGetter) {
   V8TestingScope scope;
   ScriptState* script_state = scope.GetScriptState();
-  ScriptValue js_keyframes = ScriptValue::CreateNull(script_state);
+  ScriptValue js_keyframes = ScriptValue::CreateNull(scope.GetIsolate());
 
   v8::Local<v8::Object> timing_input_with_duration =
       v8::Object::New(scope.GetIsolate());
@@ -329,7 +329,7 @@
   ScopedCSSAdditiveAnimationsForTest css_additive_animation(false);
   V8TestingScope scope;
   ScriptState* script_state = scope.GetScriptState();
-  ScriptValue js_keyframes = ScriptValue::CreateNull(script_state);
+  ScriptValue js_keyframes = ScriptValue::CreateNull(scope.GetIsolate());
   v8::Local<v8::Object> timing_input = v8::Object::New(scope.GetIsolate());
   KeyframeEffectOptions* timing_input_dictionary =
       KeyframeEffectOptions::Create();
diff --git a/third_party/blink/renderer/core/css/BUILD.gn b/third_party/blink/renderer/core/css/BUILD.gn
index 5372cf79..1cf96b76b 100644
--- a/third_party/blink/renderer/core/css/BUILD.gn
+++ b/third_party/blink/renderer/core/css/BUILD.gn
@@ -353,6 +353,8 @@
     "layout_tree_rebuild_root.h",
     "local_font_face_source.cc",
     "local_font_face_source.h",
+    "media_feature_overrides.cc",
+    "media_feature_overrides.h",
     "media_list.cc",
     "media_list.h",
     "media_query.cc",
@@ -621,6 +623,7 @@
     "invalidation/invalidation_set_test.cc",
     "invalidation/pending_invalidations_test.cc",
     "invalidation/style_invalidator_test.cc",
+    "media_feature_overrides_test.cc",
     "media_query_evaluator_test.cc",
     "media_query_list_test.cc",
     "media_query_matcher_test.cc",
diff --git a/third_party/blink/renderer/core/css/media_feature_overrides.cc b/third_party/blink/renderer/core/css/media_feature_overrides.cc
new file mode 100644
index 0000000..c6a0850
--- /dev/null
+++ b/third_party/blink/renderer/core/css/media_feature_overrides.cc
@@ -0,0 +1,25 @@
+// 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.
+
+#include "third_party/blink/renderer/core/css/media_feature_overrides.h"
+
+#include "third_party/blink/renderer/core/css/parser/css_parser_token_range.h"
+#include "third_party/blink/renderer/core/css/parser/css_tokenizer.h"
+
+namespace blink {
+
+void MediaFeatureOverrides::SetOverride(const AtomicString& feature,
+                                        const String& value_string) {
+  CSSTokenizer tokenizer(value_string);
+  const auto tokens = tokenizer.TokenizeToEOF();
+  CSSParserTokenRange range(tokens);
+  auto value = MediaQueryExp::Create(feature, range).ExpValue();
+
+  if (value.IsValid())
+    overrides_.Set(feature, value);
+  else
+    overrides_.erase(feature);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/css/media_feature_overrides.h b/third_party/blink/renderer/core/css/media_feature_overrides.h
new file mode 100644
index 0000000..96e2e1d
--- /dev/null
+++ b/third_party/blink/renderer/core/css/media_feature_overrides.h
@@ -0,0 +1,27 @@
+// 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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_MEDIA_FEATURE_OVERRIDES_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_MEDIA_FEATURE_OVERRIDES_H_
+
+#include "third_party/blink/renderer/core/css/media_query_exp.h"
+#include "third_party/blink/renderer/platform/wtf/hash_map.h"
+#include "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h"
+
+namespace blink {
+
+class CORE_EXPORT MediaFeatureOverrides {
+ public:
+  void SetOverride(const AtomicString& feature, const String& value_string);
+  MediaQueryExpValue GetOverride(const AtomicString& feature) const {
+    return overrides_.at(feature);
+  }
+
+ private:
+  HashMap<AtomicString, MediaQueryExpValue> overrides_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_MEDIA_FEATURE_OVERRIDES_H_
diff --git a/third_party/blink/renderer/core/css/media_feature_overrides_test.cc b/third_party/blink/renderer/core/css/media_feature_overrides_test.cc
new file mode 100644
index 0000000..573d6f0c
--- /dev/null
+++ b/third_party/blink/renderer/core/css/media_feature_overrides_test.cc
@@ -0,0 +1,59 @@
+// 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.
+
+#include "third_party/blink/renderer/core/css/media_feature_overrides.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+
+TEST(MediaFeatureOverrides, GetOverrideInitial) {
+  MediaFeatureOverrides overrides;
+
+  EXPECT_FALSE(overrides.GetOverride("unknown").IsValid());
+  EXPECT_FALSE(overrides.GetOverride("prefers-color-scheme").IsValid());
+  EXPECT_FALSE(overrides.GetOverride("display-mode").IsValid());
+}
+
+TEST(MediaFeatureOverrides, SetOverrideInvalid) {
+  MediaFeatureOverrides overrides;
+
+  overrides.SetOverride("prefers-color-scheme", "1px");
+  EXPECT_FALSE(overrides.GetOverride("prefers-color-scheme").IsValid());
+
+  overrides.SetOverride("prefers-color-scheme", "orange");
+  EXPECT_FALSE(overrides.GetOverride("prefers-color-scheme").IsValid());
+}
+
+TEST(MediaFeatureOverrides, SetOverrideValid) {
+  MediaFeatureOverrides overrides;
+
+  overrides.SetOverride("prefers-color-scheme", "light");
+  auto light_override = overrides.GetOverride("prefers-color-scheme");
+  EXPECT_TRUE(light_override.IsValid());
+  EXPECT_TRUE(light_override.is_id);
+  EXPECT_EQ(CSSValueID::kLight, light_override.id);
+
+  overrides.SetOverride("prefers-color-scheme", "dark");
+  auto dark_override = overrides.GetOverride("prefers-color-scheme");
+  EXPECT_TRUE(dark_override.IsValid());
+  EXPECT_TRUE(dark_override.is_id);
+  EXPECT_EQ(CSSValueID::kDark, dark_override.id);
+}
+
+TEST(MediaFeatureOverrides, ResetOverride) {
+  MediaFeatureOverrides overrides;
+
+  overrides.SetOverride("prefers-color-scheme", "light");
+  EXPECT_TRUE(overrides.GetOverride("prefers-color-scheme").IsValid());
+  overrides.SetOverride("prefers-color-scheme", "");
+  EXPECT_FALSE(overrides.GetOverride("prefers-color-scheme").IsValid());
+
+  overrides.SetOverride("prefers-color-scheme", "light");
+  EXPECT_TRUE(overrides.GetOverride("prefers-color-scheme").IsValid());
+  overrides.SetOverride("prefers-color-scheme", "invalid");
+  EXPECT_FALSE(overrides.GetOverride("prefers-color-scheme").IsValid());
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/css/media_values.cc b/third_party/blink/renderer/core/css/media_values.cc
index c31ccf3..63f27de 100644
--- a/third_party/blink/renderer/core/css/media_values.cc
+++ b/third_party/blink/renderer/core/css/media_values.cc
@@ -6,6 +6,7 @@
 
 #include "third_party/blink/public/platform/web_screen_info.h"
 #include "third_party/blink/renderer/core/css/css_resolution_units.h"
+#include "third_party/blink/renderer/core/css/media_feature_overrides.h"
 #include "third_party/blink/renderer/core/css/media_values_cached.h"
 #include "third_party/blink/renderer/core/css/media_values_dynamic.h"
 #include "third_party/blink/renderer/core/dom/document.h"
@@ -22,6 +23,20 @@
 
 namespace blink {
 
+PreferredColorScheme CSSValueIDToPreferredColorScheme(CSSValueID id) {
+  switch (id) {
+    case CSSValueID::kNoPreference:
+      return PreferredColorScheme::kNoPreference;
+    case CSSValueID::kLight:
+      return PreferredColorScheme::kLight;
+    case CSSValueID::kDark:
+      return PreferredColorScheme::kDark;
+    default:
+      NOTREACHED();
+      return PreferredColorScheme::kNoPreference;
+  }
+}
+
 MediaValues* MediaValues::CreateDynamicIfFrameExists(LocalFrame* frame) {
   if (frame)
     return MediaValuesDynamic::Create(frame);
@@ -181,12 +196,23 @@
   DCHECK(frame);
   DCHECK(frame->GetSettings());
   DCHECK(frame->GetDocument());
+  DCHECK(frame->GetPage());
+  if (const auto* overrides = frame->GetPage()->GetMediaFeatureOverrides()) {
+    MediaQueryExpValue value = overrides->GetOverride("prefers-color-scheme");
+    if (value.IsValid())
+      return CSSValueIDToPreferredColorScheme(value.id);
+  }
   return frame->GetDocument()->GetStyleEngine().GetPreferredColorScheme();
 }
 
 bool MediaValues::CalculatePrefersReducedMotion(LocalFrame* frame) {
   DCHECK(frame);
   DCHECK(frame->GetSettings());
+  if (const auto* overrides = frame->GetPage()->GetMediaFeatureOverrides()) {
+    MediaQueryExpValue value = overrides->GetOverride("prefers-reduced-motion");
+    if (value.IsValid())
+      return value.id == CSSValueID::kReduce;
+  }
   return frame->GetSettings()->GetPrefersReducedMotion();
 }
 
diff --git a/third_party/blink/renderer/core/css/media_values.h b/third_party/blink/renderer/core/css/media_values.h
index 9ec41d4..ef3a352 100644
--- a/third_party/blink/renderer/core/css/media_values.h
+++ b/third_party/blink/renderer/core/css/media_values.h
@@ -17,10 +17,13 @@
 class Document;
 class CSSPrimitiveValue;
 class LocalFrame;
+enum class CSSValueID;
 enum class ColorSpaceGamut;
 enum class PreferredColorScheme;
 enum class ForcedColors;
 
+PreferredColorScheme CSSValueIDToPreferredColorScheme(CSSValueID id);
+
 class CORE_EXPORT MediaValues : public GarbageCollected<MediaValues> {
  public:
   virtual ~MediaValues() = default;
diff --git a/third_party/blink/renderer/core/css/style_engine.cc b/third_party/blink/renderer/core/css/style_engine.cc
index e31b232..65a3531 100644
--- a/third_party/blink/renderer/core/css/style_engine.cc
+++ b/third_party/blink/renderer/core/css/style_engine.cc
@@ -39,6 +39,8 @@
 #include "third_party/blink/renderer/core/css/document_style_sheet_collector.h"
 #include "third_party/blink/renderer/core/css/font_face_cache.h"
 #include "third_party/blink/renderer/core/css/invalidation/invalidation_set.h"
+#include "third_party/blink/renderer/core/css/media_feature_overrides.h"
+#include "third_party/blink/renderer/core/css/media_values.h"
 #include "third_party/blink/renderer/core/css/property_registration.h"
 #include "third_party/blink/renderer/core/css/property_registry.h"
 #include "third_party/blink/renderer/core/css/resolver/scoped_style_resolver.h"
@@ -1863,6 +1865,12 @@
 
   PreferredColorScheme old_preferred_color_scheme = preferred_color_scheme_;
   preferred_color_scheme_ = settings->GetPreferredColorScheme();
+  if (const auto* overrides =
+          GetDocument().GetPage()->GetMediaFeatureOverrides()) {
+    MediaQueryExpValue value = overrides->GetOverride("prefers-color-scheme");
+    if (value.IsValid())
+      preferred_color_scheme_ = CSSValueIDToPreferredColorScheme(value.id);
+  }
   bool use_dark_scheme =
       preferred_color_scheme_ == PreferredColorScheme::kDark &&
       SupportsDarkColorScheme();
diff --git a/third_party/blink/renderer/core/css/style_engine_test.cc b/third_party/blink/renderer/core/css/style_engine_test.cc
index 3722659..5af643f6 100644
--- a/third_party/blink/renderer/core/css/style_engine_test.cc
+++ b/third_party/blink/renderer/core/css/style_engine_test.cc
@@ -1656,6 +1656,73 @@
                 GetCSSPropertyColor()));
 }
 
+TEST_F(StyleEngineTest, MediaQueriesColorSchemeOverride) {
+  ScopedMediaQueryPrefersColorSchemeForTest feature_scope(true);
+
+  EXPECT_EQ(PreferredColorScheme::kNoPreference,
+            GetDocument().GetSettings()->GetPreferredColorScheme());
+
+  GetDocument().body()->SetInnerHTMLFromString(R"HTML(
+    <style>
+      body { color: red }
+      @media (prefers-color-scheme: dark) {
+        body { color: green }
+      }
+    </style>
+    <body></body>
+  )HTML");
+
+  UpdateAllLifecyclePhases();
+  EXPECT_EQ(MakeRGB(255, 0, 0),
+            GetDocument().body()->GetComputedStyle()->VisitedDependentColor(
+                GetCSSPropertyColor()));
+
+  GetDocument().GetPage()->SetMediaFeatureOverride("prefers-color-scheme",
+                                                   "dark");
+  UpdateAllLifecyclePhases();
+  EXPECT_EQ(MakeRGB(0, 128, 0),
+            GetDocument().body()->GetComputedStyle()->VisitedDependentColor(
+                GetCSSPropertyColor()));
+
+  GetDocument().GetPage()->ClearMediaFeatureOverrides();
+  UpdateAllLifecyclePhases();
+  EXPECT_EQ(MakeRGB(255, 0, 0),
+            GetDocument().body()->GetComputedStyle()->VisitedDependentColor(
+                GetCSSPropertyColor()));
+}
+
+TEST_F(StyleEngineTest, MediaQueriesReducedMotionOverride) {
+  EXPECT_FALSE(GetDocument().GetSettings()->GetPrefersReducedMotion());
+
+  GetDocument().body()->SetInnerHTMLFromString(R"HTML(
+    <style>
+      body { color: red }
+      @media (prefers-reduced-motion: reduce) {
+        body { color: green }
+      }
+    </style>
+    <body></body>
+  )HTML");
+
+  UpdateAllLifecyclePhases();
+  EXPECT_EQ(MakeRGB(255, 0, 0),
+            GetDocument().body()->GetComputedStyle()->VisitedDependentColor(
+                GetCSSPropertyColor()));
+
+  GetDocument().GetPage()->SetMediaFeatureOverride("prefers-reduced-motion",
+                                                   "reduce");
+  UpdateAllLifecyclePhases();
+  EXPECT_EQ(MakeRGB(0, 128, 0),
+            GetDocument().body()->GetComputedStyle()->VisitedDependentColor(
+                GetCSSPropertyColor()));
+
+  GetDocument().GetPage()->ClearMediaFeatureOverrides();
+  UpdateAllLifecyclePhases();
+  EXPECT_EQ(MakeRGB(255, 0, 0),
+            GetDocument().body()->GetComputedStyle()->VisitedDependentColor(
+                GetCSSPropertyColor()));
+}
+
 TEST_F(StyleEngineTest, ShadowRootStyleRecalcCrash) {
   GetDocument().body()->SetInnerHTMLFromString("<div id=host></div>");
   auto* host = To<HTMLElement>(GetDocument().getElementById("host"));
@@ -2035,6 +2102,26 @@
   EXPECT_EQ(Color::kBlack, GetDocument().View()->BaseBackgroundColor());
 }
 
+TEST_F(StyleEngineTest, ColorSchemeOverride) {
+  ScopedCSSColorSchemeForTest enable_color_scheme(true);
+
+  GetDocument().documentElement()->SetInlineStyleProperty(
+      CSSPropertyID::kColorScheme, "light dark");
+  UpdateAllLifecyclePhases();
+
+  EXPECT_EQ(
+      WebColorScheme::kLight,
+      GetDocument().documentElement()->GetComputedStyle()->UsedColorScheme());
+
+  GetDocument().GetPage()->SetMediaFeatureOverride("prefers-color-scheme",
+                                                   "dark");
+
+  UpdateAllLifecyclePhases();
+  EXPECT_EQ(
+      WebColorScheme::kDark,
+      GetDocument().documentElement()->GetComputedStyle()->UsedColorScheme());
+}
+
 TEST_F(StyleEngineTest, PseudoElementBaseComputedStyle) {
   GetDocument().body()->SetInnerHTMLFromString(R"HTML(
     <style>
diff --git a/third_party/blink/renderer/core/events/error_event.cc b/third_party/blink/renderer/core/events/error_event.cc
index 2a9f4bc6..eb1f2e7 100644
--- a/third_party/blink/renderer/core/events/error_event.cc
+++ b/third_party/blink/renderer/core/events/error_event.cc
@@ -44,7 +44,8 @@
   return MakeGarbageCollected<ErrorEvent>(
       "Script error.",
       std::make_unique<SourceLocation>(String(), 0, 0, nullptr),
-      ScriptValue::CreateNull(script_state), &script_state->World());
+      ScriptValue::CreateNull(script_state->GetIsolate()),
+      &script_state->World());
 }
 
 ErrorEvent::ErrorEvent()
@@ -65,7 +66,7 @@
       initializer->hasLineno() ? initializer->lineno() : 0,
       initializer->hasColno() ? initializer->colno() : 0, nullptr);
   if (initializer->hasError()) {
-    error_.Set(script_state->GetIsolate(), initializer->error().V8Value());
+    error_ = initializer->error().ToWorldSafeV8Reference();
   }
 }
 
@@ -78,7 +79,7 @@
       location_(std::move(location)),
       world_(world) {
   if (!error.IsEmpty())
-    error_.Set(error.GetIsolate(), error.V8Value());
+    error_ = error.ToWorldSafeV8Reference();
 }
 
 void ErrorEvent::SetUnsanitizedMessage(const String& message) {
@@ -108,7 +109,7 @@
   //    thus passing it around would cause leakage.
   // 2) Errors cannot be cloned (or serialized):
   if (World() != &script_state->World() || error_.IsEmpty())
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   return ScriptValue(script_state, error_.Get(script_state));
 }
 
diff --git a/third_party/blink/renderer/core/events/message_event.cc b/third_party/blink/renderer/core/events/message_event.cc
index f941210..fc2e77b1 100644
--- a/third_party/blink/renderer/core/events/message_event.cc
+++ b/third_party/blink/renderer/core/events/message_event.cc
@@ -73,8 +73,7 @@
       data_type_(kDataTypeScriptValue),
       source_(nullptr) {
   if (initializer->hasData()) {
-    data_as_v8_value_.Set(initializer->data().GetIsolate(),
-                          initializer->data().V8Value());
+    data_as_v8_value_ = initializer->data().ToWorldSafeV8Reference();
   }
   if (initializer->hasOrigin())
     origin_ = initializer->origin();
@@ -195,7 +194,7 @@
   initEvent(type, bubbles, cancelable);
 
   data_type_ = kDataTypeScriptValue;
-  data_as_v8_value_.Set(data.GetIsolate(), data.V8Value());
+  data_as_v8_value_ = data.ToWorldSafeV8Reference();
   is_data_dirty_ = true;
   origin_ = origin;
   last_event_id_ = last_event_id;
diff --git a/third_party/blink/renderer/core/feature_policy/feature_policy_features.json5 b/third_party/blink/renderer/core/feature_policy/feature_policy_features.json5
index 299b6a94..abc6f09 100644
--- a/third_party/blink/renderer/core/feature_policy/feature_policy_features.json5
+++ b/third_party/blink/renderer/core/feature_policy/feature_policy_features.json5
@@ -45,62 +45,62 @@
     {
       name: "ClientHintDPR",
       feature_policy_name: "ch-dpr",
-      depends_on: ["ClientHintsFeaturePolicy"],
+      depends_on: ["FeaturePolicyForClientHints"],
     },
     {
       name: "ClientHintDeviceMemory",
       feature_policy_name: "ch-device-memory",
-      depends_on: ["ClientHintsFeaturePolicy"],
+      depends_on: ["FeaturePolicyForClientHints"],
     },
     {
       name: "ClientHintDownlink",
       feature_policy_name: "ch-downlink",
-      depends_on: ["ClientHintsFeaturePolicy"],
+      depends_on: ["FeaturePolicyForClientHints"],
     },
     {
       name: "ClientHintECT",
       feature_policy_name: "ch-ect",
-      depends_on: ["ClientHintsFeaturePolicy"],
+      depends_on: ["FeaturePolicyForClientHints"],
     },
     {
       name: "ClientHintLang",
       feature_policy_name: "ch-lang",
-      depends_on: ["ClientHintsFeaturePolicy"],
+      depends_on: ["FeaturePolicyForClientHints"],
     },
     {
       name: "ClientHintRTT",
       feature_policy_name: "ch-rtt",
-      depends_on: ["ClientHintsFeaturePolicy"],
+      depends_on: ["FeaturePolicyForClientHints"],
     },
     {
       name: "ClientHintUA",
       feature_policy_name: "ch-ua",
-      depends_on: ["ClientHintsFeaturePolicy"],
+      depends_on: ["FeaturePolicyForClientHints"],
     },
     {
       name: "ClientHintUAArch",
       feature_policy_name: "ch-ua-arch",
-      depends_on: ["ClientHintsFeaturePolicy"],
+      depends_on: ["FeaturePolicyForClientHints"],
     },
     {
       name: "ClientHintUAPlatform",
       feature_policy_name: "ch-ua-platform",
-      depends_on: ["ClientHintsFeaturePolicy"],
+      depends_on: ["FeaturePolicyForClientHints"],
     },
     {
       name: "ClientHintUAModel",
       feature_policy_name: "ch-ua-model",
-      depends_on: ["ClientHintsFeaturePolicy"],
+      depends_on: ["FeaturePolicyForClientHints"],
     },
     {
       name: "ClientHintViewportWidth",
       feature_policy_name: "ch-viewport-width",
-      depends_on: ["ClientHintsFeaturePolicy"],
+      depends_on: ["FeaturePolicyForClientHints"],
     },
     {
       name: "ClientHintWidth",
       feature_policy_name: "ch-width",
-      depends_on: ["ClientHintsFeaturePolicy"],
+      depends_on: ["FeaturePolicyForClientHints"],
     },
     {
       name: "DocumentAccess",
diff --git a/third_party/blink/renderer/core/fetch/body_stream_buffer_test.cc b/third_party/blink/renderer/core/fetch/body_stream_buffer_test.cc
index 4c795238..1ef31be4 100644
--- a/third_party/blink/renderer/core/fetch/body_stream_buffer_test.cc
+++ b/third_party/blink/renderer/core/fetch/body_stream_buffer_test.cc
@@ -59,7 +59,8 @@
       ADD_FAILURE() << "Compilation fails";
       return ScriptValue();
     }
-    return ScriptValue(script_state, script->Run(script_state->GetContext()));
+    return ScriptValue(script_state->GetIsolate(),
+                       script->Run(script_state->GetContext()));
   }
   ScriptValue EvalWithPrintingError(ScriptState* script_state, const char* s) {
     v8::TryCatch block(script_state->GetIsolate());
diff --git a/third_party/blink/renderer/core/frame/DEPS b/third_party/blink/renderer/core/frame/DEPS
new file mode 100644
index 0000000..974ea72
--- /dev/null
+++ b/third_party/blink/renderer/core/frame/DEPS
@@ -0,0 +1,5 @@
+specific_include_rules = {
+  "local_frame_back_forward_cache_test.cc": [
+    "+base/run_loop.h",
+  ]
+}
\ No newline at end of file
diff --git a/third_party/blink/renderer/core/frame/local_frame_back_forward_cache_test.cc b/third_party/blink/renderer/core/frame/local_frame_back_forward_cache_test.cc
index ab5e3cf..53e94ed 100644
--- a/third_party/blink/renderer/core/frame/local_frame_back_forward_cache_test.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_back_forward_cache_test.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 
+#include "base/run_loop.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
diff --git a/third_party/blink/renderer/core/html/BUILD.gn b/third_party/blink/renderer/core/html/BUILD.gn
index da50720..7e64691 100644
--- a/third_party/blink/renderer/core/html/BUILD.gn
+++ b/third_party/blink/renderer/core/html/BUILD.gn
@@ -584,6 +584,7 @@
   deps = [
     "//services/metrics/public/cpp:metrics_cpp",
     "//skia:skcms",
+    "//third_party/blink/public/strings",
     "//third_party/blink/renderer/core/html/parser:parser",
   ]
 }
diff --git a/third_party/blink/renderer/core/html/forms/DEPS b/third_party/blink/renderer/core/html/forms/DEPS
new file mode 100644
index 0000000..4a90b3a
--- /dev/null
+++ b/third_party/blink/renderer/core/html/forms/DEPS
@@ -0,0 +1,5 @@
+specific_include_rules = {
+  "file_input_type_test.cc": [
+    "+base/run_loop.h",
+  ]
+}
\ No newline at end of file
diff --git a/third_party/blink/renderer/core/html/forms/date_time_chooser_impl.cc b/third_party/blink/renderer/core/html/forms/date_time_chooser_impl.cc
index d50788a..74478dc8 100644
--- a/third_party/blink/renderer/core/html/forms/date_time_chooser_impl.cc
+++ b/third_party/blink/renderer/core/html/forms/date_time_chooser_impl.cc
@@ -117,8 +117,7 @@
     other_date_label_string =
         GetLocale().QueryString(WebLocalizedString::kOtherWeekLabel);
   } else {
-    today_label_string =
-        GetLocale().QueryString(WebLocalizedString::kCalendarToday);
+    today_label_string = GetLocale().QueryString(IDS_FORM_CALENDAR_TODAY);
     other_date_label_string =
         GetLocale().QueryString(WebLocalizedString::kOtherDateLabel);
   }
@@ -155,8 +154,7 @@
       data);
   AddProperty("locale", parameters_->locale.GetString(), data);
   AddProperty("todayLabel", today_label_string, data);
-  AddProperty("clearLabel",
-              GetLocale().QueryString(WebLocalizedString::kCalendarClear),
+  AddProperty("clearLabel", GetLocale().QueryString(IDS_FORM_CALENDAR_CLEAR),
               data);
   AddProperty("weekLabel",
               GetLocale().QueryString(WebLocalizedString::kWeekNumberLabel),
diff --git a/third_party/blink/renderer/core/html/forms/file_input_type_test.cc b/third_party/blink/renderer/core/html/forms/file_input_type_test.cc
index bdf321a..76fc73e 100644
--- a/third_party/blink/renderer/core/html/forms/file_input_type_test.cc
+++ b/third_party/blink/renderer/core/html/forms/file_input_type_test.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/html/forms/file_input_type.h"
 
+#include "base/run_loop.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/core/clipboard/data_object.h"
 #include "third_party/blink/renderer/core/dom/document.h"
diff --git a/third_party/blink/renderer/core/inspector/inspector_performance_agent.cc b/third_party/blink/renderer/core/inspector/inspector_performance_agent.cc
index a2b2823..c8222ba0 100644
--- a/third_party/blink/renderer/core/inspector/inspector_performance_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_performance_agent.cc
@@ -16,6 +16,7 @@
 #include "third_party/blink/renderer/core/probe/core_probes.h"
 #include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
 #include "third_party/blink/renderer/platform/instrumentation/instance_counters.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/layout/BUILD.gn b/third_party/blink/renderer/core/layout/BUILD.gn
index a93d0d54..47330337 100644
--- a/third_party/blink/renderer/core/layout/BUILD.gn
+++ b/third_party/blink/renderer/core/layout/BUILD.gn
@@ -444,6 +444,7 @@
     "ng/ng_constraint_space_builder.h",
     "ng/ng_container_fragment_builder.cc",
     "ng/ng_container_fragment_builder.h",
+    "ng/ng_early_break.h",
     "ng/ng_fieldset_layout_algorithm.cc",
     "ng/ng_fieldset_layout_algorithm.h",
     "ng/ng_flex_layout_algorithm.cc",
diff --git a/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc b/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc
index 8d6b0ecc..b052acc1 100644
--- a/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc
@@ -135,6 +135,10 @@
     return false;
   }
   LayoutUnit FreeSpaceForStretchAutoTracksStep() const override;
+  LayoutUnit MinContentForChild(LayoutBox&) const override;
+  LayoutUnit MinLogicalSizeForChild(LayoutBox&,
+                                    const Length& child_min_size,
+                                    LayoutUnit available_size) const override;
   bool IsComputingSizeContainment() const override { return false; }
 };
 
@@ -149,10 +153,18 @@
       GridLayoutUtils::FlowAwareDirectionForChild(grid, child, kForColumns);
   if (direction == child_inline_direction) {
     return child.HasRelativeLogicalWidth() ||
-           child.StyleRef().LogicalWidth().IsIntrinsicOrAuto();
+           child.StyleRef().LogicalWidth().IsIntrinsicOrAuto() ||
+           child.StyleRef().MarginStart().IsPercentOrCalc() ||
+           child.StyleRef().MarginEnd().IsPercentOrCalc() ||
+           child.StyleRef().PaddingStart().IsPercentOrCalc() ||
+           child.StyleRef().PaddingEnd().IsPercentOrCalc();
   }
   return child.HasRelativeLogicalHeight() ||
-         child.StyleRef().LogicalHeight().IsIntrinsicOrAuto();
+         child.StyleRef().LogicalHeight().IsIntrinsicOrAuto() ||
+         child.StyleRef().MarginBefore().IsPercentOrCalc() ||
+         child.StyleRef().MarginAfter().IsPercentOrCalc() ||
+         child.StyleRef().PaddingBefore().IsPercentOrCalc() ||
+         child.StyleRef().PaddingAfter().IsPercentOrCalc();
 }
 
 void GridTrackSizingAlgorithmStrategy::
@@ -404,21 +416,8 @@
 
   LayoutUnit grid_area_size =
       algorithm_.GridAreaBreadthForChild(child, child_inline_direction);
-
-  if (is_row_axis) {
-    return MinLogicalWidthForChild(child, child_min_size, grid_area_size) +
-           baseline_shim;
-  }
-
-  bool override_size_has_changed =
-      UpdateOverrideContainingBlockContentSizeForChild(
-          child, child_inline_direction, grid_area_size);
-  LayoutGridItemForMinSizeComputation(child, override_size_has_changed);
-
-  return child.ComputeLogicalHeightUsing(kMinSize, child_min_size,
-                                         child.IntrinsicLogicalHeight()) +
-         GridLayoutUtils::MarginLogicalHeightForChild(*GetLayoutGrid(), child) +
-         child.ScrollbarLogicalHeight() + baseline_shim;
+  return MinLogicalSizeForChild(child, child_min_size, grid_area_size) +
+         baseline_shim;
 }
 
 bool GridTrackSizingAlgorithm::CanParticipateInBaselineAlignment(
@@ -526,13 +525,47 @@
                                                       available_logical_space);
 }
 
-LayoutUnit GridTrackSizingAlgorithmStrategy::MinLogicalWidthForChild(
+LayoutUnit GridTrackSizingAlgorithmStrategy::MinLogicalSizeForChild(
     LayoutBox& child,
     const Length& child_min_size,
     LayoutUnit available_size) const {
-  return child.ComputeLogicalWidthUsing(kMinSize, child_min_size,
-                                        available_size, GetLayoutGrid()) +
-         GridLayoutUtils::MarginLogicalWidthForChild(*GetLayoutGrid(), child);
+  GridTrackSizingDirection child_inline_direction =
+      GridLayoutUtils::FlowAwareDirectionForChild(*GetLayoutGrid(), child,
+                                                  kForColumns);
+  bool is_row_axis = Direction() == child_inline_direction;
+
+  if (is_row_axis) {
+    return child.ComputeLogicalWidthUsing(kMinSize, child_min_size,
+                                          available_size, GetLayoutGrid()) +
+           GridLayoutUtils::MarginLogicalWidthForChild(*GetLayoutGrid(), child);
+  }
+
+  bool override_size_has_changed =
+      UpdateOverrideContainingBlockContentSizeForChild(
+          child, child_inline_direction, available_size);
+  LayoutGridItemForMinSizeComputation(child, override_size_has_changed);
+
+  return child.ComputeLogicalHeightUsing(kMinSize, child_min_size,
+                                         child.IntrinsicLogicalHeight()) +
+         GridLayoutUtils::MarginLogicalHeightForChild(*GetLayoutGrid(), child);
+}
+
+LayoutUnit DefiniteSizeStrategy::MinLogicalSizeForChild(
+    LayoutBox& child,
+    const Length& child_min_size,
+    LayoutUnit available_size) const {
+  GridTrackSizingDirection child_inline_direction =
+      GridLayoutUtils::FlowAwareDirectionForChild(*GetLayoutGrid(), child,
+                                                  kForColumns);
+  LayoutUnit indefinite_size =
+      Direction() == child_inline_direction ? LayoutUnit() : LayoutUnit(-1);
+  if (ShouldClearOverrideContainingBlockContentSizeForChild(
+          *GetLayoutGrid(), child, Direction())) {
+    SetOverrideContainingBlockContentSizeForChild(child, Direction(),
+                                                  indefinite_size);
+  }
+  return GridTrackSizingAlgorithmStrategy::MinLogicalSizeForChild(
+      child, child_min_size, available_size);
 }
 
 void DefiniteSizeStrategy::LayoutGridItemForMinSizeComputation(
@@ -577,6 +610,21 @@
   return algorithm_.FreeSpace(Direction()).value();
 }
 
+DISABLE_CFI_PERF
+LayoutUnit DefiniteSizeStrategy::MinContentForChild(LayoutBox& child) const {
+  GridTrackSizingDirection child_inline_direction =
+      GridLayoutUtils::FlowAwareDirectionForChild(*GetLayoutGrid(), child,
+                                                  kForColumns);
+  if (Direction() == child_inline_direction && child.NeedsLayout() &&
+      ShouldClearOverrideContainingBlockContentSizeForChild(
+          *GetLayoutGrid(), child, child_inline_direction)) {
+    SetOverrideContainingBlockContentSizeForChild(child, child_inline_direction,
+                                                  LayoutUnit());
+  }
+
+  return GridTrackSizingAlgorithmStrategy::MinContentForChild(child);
+}
+
 void IndefiniteSizeStrategy::LayoutGridItemForMinSizeComputation(
     LayoutBox& child,
     bool override_size_has_changed) const {
diff --git a/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.h b/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.h
index 1f81a76..6107043 100644
--- a/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.h
+++ b/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.h
@@ -293,9 +293,9 @@
   GridTrackSizingAlgorithmStrategy(GridTrackSizingAlgorithm& algorithm)
       : algorithm_(algorithm) {}
 
-  virtual LayoutUnit MinLogicalWidthForChild(LayoutBox&,
-                                             const Length& child_min_size,
-                                             LayoutUnit available_size) const;
+  virtual LayoutUnit MinLogicalSizeForChild(LayoutBox&,
+                                            const Length& child_min_size,
+                                            LayoutUnit available_size) const;
   virtual void LayoutGridItemForMinSizeComputation(
       LayoutBox&,
       bool override_size_has_changed) const = 0;
diff --git a/third_party/blink/renderer/core/layout/layout_grid.cc b/third_party/blink/renderer/core/layout/layout_grid.cc
index a418fdb..6599466 100644
--- a/third_party/blink/renderer/core/layout/layout_grid.cc
+++ b/third_party/blink/renderer/core/layout/layout_grid.cc
@@ -1247,6 +1247,9 @@
 }
 
 void LayoutGrid::LayoutGridItems() {
+  if (LayoutBlockedByDisplayLock(DisplayLockLifecycleTarget::kChildren))
+    return;
+
   PopulateGridPositionsForDirection(kForColumns);
   PopulateGridPositionsForDirection(kForRows);
 
@@ -1325,6 +1328,9 @@
 
 void LayoutGrid::LayoutPositionedObjects(bool relayout_children,
                                          PositionedLayoutBehavior info) {
+  if (LayoutBlockedByDisplayLock(DisplayLockLifecycleTarget::kChildren))
+    return;
+
   column_of_positioned_item_.clear();
   row_of_positioned_item_.clear();
 
diff --git a/third_party/blink/renderer/core/layout/ng/custom/custom_layout_constraints.cc b/third_party/blink/renderer/core/layout/ng/custom/custom_layout_constraints.cc
index 2bb3946..3ff221a 100644
--- a/third_party/blink/renderer/core/layout/ng/custom/custom_layout_constraints.cc
+++ b/third_party/blink/renderer/core/layout/ng/custom/custom_layout_constraints.cc
@@ -43,7 +43,7 @@
   DCHECK(script_state->World().IsWorkerWorld());
 
   if (layout_worklet_world_v8_data_.IsEmpty())
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
 
   return ScriptValue(script_state, layout_worklet_world_v8_data_.NewLocal(
                                        script_state->GetIsolate()));
diff --git a/third_party/blink/renderer/core/layout/ng/custom/custom_layout_fragment.cc b/third_party/blink/renderer/core/layout/ng/custom/custom_layout_fragment.cc
index 83ea4e1..ce90299 100644
--- a/third_party/blink/renderer/core/layout/ng/custom/custom_layout_fragment.cc
+++ b/third_party/blink/renderer/core/layout/ng/custom/custom_layout_fragment.cc
@@ -44,7 +44,7 @@
   DCHECK(script_state->World().IsWorkerWorld());
 
   if (layout_worklet_world_v8_data_.IsEmpty())
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
 
   return ScriptValue(script_state, layout_worklet_world_v8_data_.NewLocal(
                                        script_state->GetIsolate()));
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
index ce3ceb09..b12baeb 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
@@ -19,6 +19,7 @@
 #include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_early_break.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_floats_utils.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_fragment.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h"
@@ -137,6 +138,11 @@
           child_bfc_offset.block_offset - parent_bfc_offset.block_offset};
 }
 
+inline bool IsEarlyBreakpoint(const NGEarlyBreak& breakpoint,
+                              const NGBoxFragmentBuilder& builder) {
+  return breakpoint.LineNumber() == builder.LineCount();
+}
+
 }  // namespace
 
 NGBlockLayoutAlgorithm::NGBlockLayoutAlgorithm(
@@ -326,12 +332,22 @@
 }
 
 scoped_refptr<const NGLayoutResult> NGBlockLayoutAlgorithm::Layout() {
+  scoped_refptr<const NGLayoutResult> result;
   // Inline children require an inline child layout context to be
   // passed between siblings. We want to stack-allocate that one, but
   // only on demand, as it's quite big.
   if (Node().ChildrenInline())
-    return LayoutWithInlineChildLayoutContext();
-  return Layout(nullptr);
+    result = LayoutWithInlineChildLayoutContext();
+  else
+    result = Layout(nullptr);
+  if (UNLIKELY(result->Status() == NGLayoutResult::kNeedsEarlierBreak)) {
+    // If we found a good break somewhere inside this block, re-layout and break
+    // at that location.
+    DCHECK(!early_break_);
+    DCHECK(result->GetEarlyBreak());
+    return RelayoutAndBreakEarlier(*result->GetEarlyBreak());
+  }
+  return result;
 }
 
 NOINLINE scoped_refptr<const NGLayoutResult>
@@ -357,6 +373,23 @@
   return result;
 }
 
+NOINLINE scoped_refptr<const NGLayoutResult>
+NGBlockLayoutAlgorithm::RelayoutAndBreakEarlier(
+    const NGEarlyBreak& breakpoint) {
+  NGLayoutAlgorithmParams params(Node(),
+                                 container_builder_.InitialFragmentGeometry(),
+                                 ConstraintSpace(), BreakToken());
+  NGBlockLayoutAlgorithm algorithm_with_break(params);
+  algorithm_with_break.early_break_ = &breakpoint;
+  NGBoxFragmentBuilder& new_builder = algorithm_with_break.container_builder_;
+  new_builder.SetBoxType(container_builder_.BoxType());
+  // We're not going to run out of space in the next layout pass, since we're
+  // breaking earlier, so no space shortage will be detected. Repeat what we
+  // found in this pass.
+  new_builder.PropagateSpaceShortage(container_builder_.MinimalSpaceShortage());
+  return algorithm_with_break.Layout();
+}
+
 inline scoped_refptr<const NGLayoutResult> NGBlockLayoutAlgorithm::Layout(
     NGInlineChildLayoutContext* inline_child_layout_context) {
   const LogicalSize border_box_size = container_builder_.InitialBorderBoxSize();
@@ -526,6 +559,10 @@
       }
       break;
     } else {
+      if (UNLIKELY(early_break_ &&
+                   FindEarlyBreakpoint(child, &previous_inflow_position)))
+        break;
+
       bool abort;
       if (child.CreatesNewFormattingContext()) {
         abort = !HandleNewFormattingContext(child, child_break_token,
@@ -726,8 +763,10 @@
   // This may occur with a zero block size fragment. We need to know the BFC
   // block offset to determine where the fragmentation line is relative to us.
   if (container_builder_.BfcBlockOffset() &&
-      ConstraintSpace().HasBlockFragmentation())
-    FinalizeForFragmentation();
+      ConstraintSpace().HasBlockFragmentation()) {
+    if (!FinalizeForFragmentation())
+      return container_builder_.Abort(NGLayoutResult::kNeedsEarlierBreak);
+  }
 
   NGOutOfFlowLayoutPart(
       Node(), ConstraintSpace(),
@@ -755,6 +794,19 @@
   return container_builder_.ToBoxFragment();
 }
 
+bool NGBlockLayoutAlgorithm::FindEarlyBreakpoint(
+    NGLayoutInputNode child,
+    NGPreviousInflowPosition* previous_inflow_position) {
+  DCHECK(early_break_);
+  if (!IsEarlyBreakpoint(*early_break_, container_builder_))
+    return false;
+
+  container_builder_.AddBreakBeforeChild(child, /* is_forced_break */ false);
+  previous_inflow_position->logical_block_offset =
+      FragmentainerSpaceAvailable();
+  return true;
+}
+
 const NGInlineBreakToken* NGBlockLayoutAlgorithm::TryReuseFragmentsFromCache(
     NGInlineNode inline_node,
     NGPreviousInflowPosition* previous_inflow_position,
@@ -1879,7 +1931,7 @@
   return block_offset >= FragmentainerSpaceAvailable();
 }
 
-void NGBlockLayoutAlgorithm::FinalizeForFragmentation() {
+bool NGBlockLayoutAlgorithm::FinalizeForFragmentation() {
   if (first_overflowing_line_ && !fit_all_lines_) {
     // A line box overflowed the fragmentainer, but we continued layout anyway,
     // in order to determine where to break in order to honor the widows
@@ -1913,26 +1965,36 @@
     // detect that there's no room for a fragment for this node, and drop the
     // fragment on the floor. Therefore it doesn't matter how we set up the
     // container builder, so just return.
-    return;
+    return true;
   }
 
-  if (container_builder_.DidBreak() && first_overflowing_line_) {
-    int line_number;
-    if (fit_all_lines_) {
-      line_number = first_overflowing_line_;
-    } else {
-      // We managed to finish layout of all the lines for the node, which means
-      // that we won't have enough widows, unless we break earlier than where we
-      // overflowed.
-      int line_count = container_builder_.LineCount();
-      line_number = std::max(line_count - Style().Widows(),
-                             std::min(line_count, int(Style().Orphans())));
+  if (Node().ChildrenInline()) {
+    if (container_builder_.DidBreak() || first_overflowing_line_) {
+      if (first_overflowing_line_ &&
+          first_overflowing_line_ < container_builder_.LineCount()) {
+        int line_number;
+        if (fit_all_lines_) {
+          line_number = first_overflowing_line_;
+        } else {
+          // We managed to finish layout of all the lines for the node, which
+          // means that we won't have enough widows, unless we break earlier
+          // than where we overflowed.
+          int line_count = container_builder_.LineCount();
+          line_number = std::max(line_count - Style().Widows(),
+                                 std::min(line_count, int(Style().Orphans())));
+        }
+        // We need to layout again, and stop at the right line number.
+        NGEarlyBreak breakpoint(line_number);
+        container_builder_.SetEarlyBreak(breakpoint);
+        return false;
+      }
     }
-    container_builder_.AddBreakBeforeLine(line_number);
   }
 
   FinishFragmentation(&container_builder_, block_size, intrinsic_block_size_,
                       consumed_block_size, space_left);
+
+  return true;
 }
 
 bool NGBlockLayoutAlgorithm::BreakBeforeChild(
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h
index edd2d5b9..7e144a1 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h
@@ -20,6 +20,7 @@
 namespace blink {
 
 class NGConstraintSpace;
+class NGEarlyBreak;
 class NGFragment;
 class NGLayoutResult;
 class NGPhysicalLineBoxFragment;
@@ -66,11 +67,22 @@
   NOINLINE scoped_refptr<const NGLayoutResult> LayoutWithItemsBuilder(
       NGInlineChildLayoutContext* context);
 
+  // Lay out again, this time with a predefined good breakpoint that we
+  // discovered in the first pass. This happens when we run out of space in a
+  // fragmentainer at an less-than-ideal location, due to breaking restrictions,
+  // such as orphans or widows.
+  NOINLINE scoped_refptr<const NGLayoutResult> RelayoutAndBreakEarlier(
+      const NGEarlyBreak&);
+
   inline scoped_refptr<const NGLayoutResult> Layout(
       NGInlineChildLayoutContext* inline_child_layout_context);
 
   scoped_refptr<const NGLayoutResult> FinishLayout(NGPreviousInflowPosition*);
 
+  // If the child is the one we have already determined to break before, do so
+  // and return true. Otherwise, return false.
+  bool FindEarlyBreakpoint(NGLayoutInputNode child, NGPreviousInflowPosition*);
+
   // Return the BFC block offset of this block.
   LayoutUnit BfcBlockOffset() const {
     // If we have resolved our BFC block offset, use that.
@@ -230,10 +242,13 @@
                                  LayoutUnit block_offset,
                                  bool is_pushed_by_floats) const;
 
-  // Final adjustments before fragment creation. We need to prevent the
-  // fragment from crossing fragmentainer boundaries, and rather create a break
-  // token if we're out of space.
-  void FinalizeForFragmentation();
+  // Final adjustments before fragment creation. We need to prevent the fragment
+  // from crossing fragmentainer boundaries, and rather create a break token if
+  // we're out of space. As part of finalizing we may also discover that we need
+  // to abort layout, because we've run out of space at a less-than-ideal
+  // location. In this case, false will be returned. Otherwise, true will be
+  // returned.
+  bool FinalizeForFragmentation();
 
   void PropagateBaselinesFromChildren();
   bool AddBaseline(const NGBaselineRequest&,
@@ -364,6 +379,9 @@
   bool has_processed_first_child_ = false;
 
   NGExclusionSpace exclusion_space_;
+
+  // When set, this will specify where to break before or inside.
+  const NGEarlyBreak* early_break_ = nullptr;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
index c3fe64c..2771884 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
@@ -100,33 +100,6 @@
   child_break_tokens_.push_back(token);
 }
 
-void NGBoxFragmentBuilder::AddBreakBeforeLine(int line_number) {
-  DCHECK(has_block_fragmentation_);
-  DCHECK_GT(line_number, 0);
-  DCHECK_LE(unsigned(line_number), inline_break_tokens_.size());
-  SetDidBreak();
-  int lines_to_remove = inline_break_tokens_.size() - line_number;
-  if (lines_to_remove > 0) {
-    // Remove widows that should be pushed to the next fragment. We'll also
-    // remove all other child fragments than line boxes (typically floats) that
-    // come after the first line that's moved, as those also have to be re-laid
-    // out in the next fragment.
-    inline_break_tokens_.resize(line_number);
-    DCHECK_GT(children_.size(), 0UL);
-    for (int i = children_.size() - 1; i >= 0; i--) {
-      DCHECK_NE(i, 0);
-      if (!children_[i].fragment->IsLineBox())
-        continue;
-      if (!--lines_to_remove) {
-        // This is the first line that is going to the next fragment. Remove it,
-        // and everything after it.
-        children_.resize(i);
-        break;
-      }
-    }
-  }
-}
-
 void NGBoxFragmentBuilder::AddResult(const NGLayoutResult& child_layout_result,
                                      const LogicalOffset offset,
                                      const LayoutInline* inline_container) {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
index 8f8dd37..ca29d37 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
@@ -63,6 +63,11 @@
     is_initial_block_size_indefinite_ = size_.block_size == kIndefiniteSize;
   }
 
+  const NGFragmentGeometry& InitialFragmentGeometry() const {
+    DCHECK(initial_fragment_geometry_);
+    return *initial_fragment_geometry_;
+  }
+
   void SetIntrinsicBlockSize(LayoutUnit intrinsic_block_size) {
     intrinsic_block_size_ = intrinsic_block_size;
   }
@@ -89,9 +94,6 @@
   // add a break token for the child, but no fragment.
   void AddBreakBeforeChild(NGLayoutInputNode child, bool is_forced_break);
 
-  // Prepare for a break token before the specified line.
-  void AddBreakBeforeLine(int line_number);
-
   // Add a layout result. This involves appending the fragment and its relative
   // offset to the builder, but also keeping track of out-of-flow positioned
   // descendants, propagating fragmentainer breaks, and more.
@@ -128,6 +130,7 @@
     if (minimal_space_shortage_ > space_shortage)
       minimal_space_shortage_ = space_shortage;
   }
+  LayoutUnit MinimalSpaceShortage() const { return minimal_space_shortage_; }
 
   void SetInitialBreakBefore(EBreakBetween break_before) {
     initial_break_before_ = break_before;
@@ -164,6 +167,9 @@
   void SetColumnSpanner(NGBlockNode spanner) { column_spanner_ = spanner; }
   bool FoundColumnSpanner() const { return !!column_spanner_; }
 
+  void SetEarlyBreak(NGEarlyBreak breakpoint) { early_break_ = breakpoint; }
+  bool HasEarlyBreak() const { return early_break_.has_value(); }
+
   // Offsets are not supposed to be set during fragment construction, so we
   // do not provide a setter here.
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc b/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc
index 18edf3f..310a86f 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc
@@ -1876,6 +1876,57 @@
   EXPECT_EQ(expectation, dump);
 }
 
+TEST_F(NGColumnLayoutAlgorithmTest, WidowsAndAbspos) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      #parent {
+        columns: 3;
+        column-fill: auto;
+        column-gap: 10px;
+        width: 320px;
+        height: 70px;
+        line-height: 20px;
+        orphans: 1;
+        widows: 3;
+      }
+    </style>
+    <div id="container">
+      <div id="parent">
+        <div style="position:relative;">
+          <br>
+          <br>
+          <br>
+          <br>
+          <div style="position:absolute; width:33px; height:33px;"></div>
+          <br>
+        </div>
+      </div>
+    </div>
+  )HTML");
+
+  String dump = DumpFragmentTree(GetElementById("container"));
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:1000x70
+    offset:0,0 size:320x70
+      offset:0,0 size:100x70
+        offset:0,0 size:100x70
+          offset:0,0 size:0x20
+            offset:0,9 size:0x1
+          offset:0,20 size:0x20
+            offset:0,9 size:0x1
+      offset:110,0 size:100x60
+        offset:0,0 size:100x60
+          offset:0,0 size:0x20
+            offset:0,9 size:0x1
+          offset:0,20 size:0x20
+            offset:0,9 size:0x1
+          offset:0,40 size:0x20
+            offset:0,9 size:0x1
+          offset:0,40 size:33x33
+)DUMP";
+  EXPECT_EQ(expectation, dump);
+}
+
 // TODO(crbug.com/915929): Fix inline-level float fragmentation.
 TEST_F(NGColumnLayoutAlgorithmTest, DISABLED_FloatInBlockMovedByOrphans) {
   SetBodyInnerHTML(R"HTML(
diff --git a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
index 9fc1edd..38d558f 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
@@ -13,6 +13,7 @@
 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_margin_strut.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
 #include "third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_early_break.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_floats_utils.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_link.h"
@@ -214,6 +215,8 @@
   NGBreakTokenVector child_break_tokens_;
   NGBreakTokenVector inline_break_tokens_;
 
+  base::Optional<NGEarlyBreak> early_break_;
+
   NGAdjoiningObjectTypes adjoining_object_types_ = kAdjoiningNone;
   bool has_adjoining_object_descendants_ = false;
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_early_break.h b/third_party/blink/renderer/core/layout/ng/ng_early_break.h
new file mode 100644
index 0000000..4e8880f
--- /dev/null
+++ b/third_party/blink/renderer/core/layout/ng/ng_early_break.h
@@ -0,0 +1,25 @@
+// 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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_EARLY_BREAK_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_EARLY_BREAK_H_
+
+namespace blink {
+
+// Possible early unforced breakpoint. This represents a possible (and good)
+// location to break. In cases where we run out of space at an unideal location,
+// we may want to go back and break here instead.
+class NGEarlyBreak {
+ public:
+  explicit NGEarlyBreak(int line_number) : line_number_(line_number) {}
+
+  int LineNumber() const { return line_number_; }
+
+ private:
+  int line_number_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_EARLY_BREAK_H_
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc b/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc
index 495711087..d991ccd 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc
@@ -155,6 +155,11 @@
     space_.ExclusionSpace().MoveDerivedGeometry(builder->exclusion_space_);
   }
 
+  // If we found an early breakpoint inside that we need to break at, we're
+  // going to re-layout now, and break at the early breakpoint.
+  if (builder->early_break_ && !physical_fragment_)
+    EnsureRareData()->early_break = *builder->early_break_;
+
   if (HasRareData()) {
     rare_data_->bfc_line_offset = builder->bfc_line_offset_;
     rare_data_->bfc_block_offset = builder->bfc_block_offset_;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_result.h b/third_party/blink/renderer/core/layout/ng/ng_layout_result.h
index ae90f2a..f30903d 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_layout_result.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_layout_result.h
@@ -13,6 +13,7 @@
 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_margin_strut.h"
 #include "third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_early_break.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_floats_utils.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_fragment.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_link.h"
@@ -38,6 +39,7 @@
   enum NGLayoutResultStatus {
     kSuccess = 0,
     kBfcBlockOffsetResolved = 1,
+    kNeedsEarlierBreak = 2,
     // When adding new values, make sure the bit size of |Bitfields::status| is
     // large enough to store.
   };
@@ -75,6 +77,12 @@
     return HasRareData() ? rare_data_->column_spanner : NGBlockNode(nullptr);
   }
 
+  const NGEarlyBreak* GetEarlyBreak() const {
+    if (!HasRareData())
+      return nullptr;
+    return &rare_data_->early_break.value();
+  }
+
   const NGExclusionSpace& ExclusionSpace() const {
     if (bitfields_.has_rare_data_exclusion_space) {
       DCHECK(HasRareData());
@@ -294,6 +302,7 @@
     LayoutUnit bfc_line_offset;
     base::Optional<LayoutUnit> bfc_block_offset;
 
+    base::Optional<NGEarlyBreak> early_break;
     LogicalOffset oof_positioned_offset;
     NGMarginStrut end_margin_strut;
     NGUnpositionedListMarker unpositioned_list_marker;
@@ -362,7 +371,7 @@
     unsigned initial_break_before : 4;  // EBreakBetween
     unsigned final_break_after : 4;     // EBreakBetween
 
-    unsigned status : 1;  // NGLayoutResultStatus
+    unsigned status : 2;  // NGLayoutResultStatus
   };
 
   // The constraint space which generated this layout result, may not be valid
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc
index e2786f2..940cc33 100644
--- a/third_party/blink/renderer/core/loader/document_loader.cc
+++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -1637,10 +1637,6 @@
     OriginTrialContext::ActivateNavigationFeaturesFromInitiator(
         document, &initiator_origin_trial_features_);
   }
-  bool stale_while_revalidate_enabled =
-      RuntimeEnabledFeatures::StaleWhileRevalidateEnabled(document);
-  document->Fetcher()->SetStaleWhileRevalidateEnabled(
-      stale_while_revalidate_enabled);
 
   bool opted_out_mixed_autoupgrade = EqualIgnoringASCIICase(
       response_.HttpHeaderField("mixed-content"), "noupgrade");
@@ -1651,11 +1647,6 @@
   UMA_HISTOGRAM_BOOLEAN("MixedAutoupgrade.Navigation.OptedOut",
                         opted_out_mixed_autoupgrade);
 
-  // If stale while revalidate is enabled via Origin Trials count it as such.
-  if (stale_while_revalidate_enabled &&
-      !RuntimeEnabledFeatures::StaleWhileRevalidateEnabledByRuntimeFlag())
-    UseCounter::Count(document, WebFeature::kStaleWhileRevalidateEnabled);
-
   parser_ = document->OpenForNavigation(parsing_policy, mime_type, encoding);
 
   // If this is a scriptable parser and there is a resource, register the
diff --git a/third_party/blink/renderer/core/loader/idleness_detector.cc b/third_party/blink/renderer/core/loader/idleness_detector.cc
index a0348835..dd1f4ce89 100644
--- a/third_party/blink/renderer/core/loader/idleness_detector.cc
+++ b/third_party/blink/renderer/core/loader/idleness_detector.cc
@@ -18,6 +18,7 @@
 #include "third_party/blink/renderer/core/probe/core_probes.h"
 #include "third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.cc b/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.cc
index 4d12ca0..e2c000bc 100644
--- a/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.cc
+++ b/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.cc
@@ -342,6 +342,8 @@
 void ModuleTreeLinker::FetchDescendants(const ModuleScript* module_script) {
   DCHECK(module_script);
 
+  v8::Isolate* isolate = modulator_->GetScriptState()->GetIsolate();
+  v8::HandleScope scope(isolate);
   // [nospec] Abort the steps if the browsing context is discarded.
   if (!modulator_->HasValidContext()) {
     result_ = nullptr;
@@ -349,9 +351,6 @@
     return;
   }
 
-  // TODO(crbug.com/1000152): Replace ScriptState::Scope with v8::HandleScope
-  ScriptState::Scope scope(modulator_->GetScriptState());
-
   // <spec step="2">Let record be module script's record.</spec>
   v8::Local<v8::Module> record = module_script->V8Module();
 
diff --git a/third_party/blink/renderer/core/loader/resource/script_resource.h b/third_party/blink/renderer/core/loader/resource/script_resource.h
index 4e31c0c..010d122 100644
--- a/third_party/blink/renderer/core/loader/resource/script_resource.h
+++ b/third_party/blink/renderer/core/loader/resource/script_resource.h
@@ -37,6 +37,10 @@
 #include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
 #include "third_party/blink/renderer/platform/loader/fetch/text_resource_decoder_options.h"
 
+namespace mojo {
+class SimpleWatcher;
+}
+
 namespace blink {
 
 class FetchParameters;
diff --git a/third_party/blink/renderer/core/loader/threaded_icon_loader.cc b/third_party/blink/renderer/core/loader/threaded_icon_loader.cc
index 06a30a5..5a9c983 100644
--- a/third_party/blink/renderer/core/loader/threaded_icon_loader.cc
+++ b/third_party/blink/renderer/core/loader/threaded_icon_loader.cc
@@ -16,6 +16,7 @@
 #include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
 #include "third_party/blink/renderer/platform/scheduler/public/worker_pool.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
diff --git a/third_party/blink/renderer/core/loader/web_associated_url_loader_impl.cc b/third_party/blink/renderer/core/loader/web_associated_url_loader_impl.cc
index 23db6c7..4b89d66 100644
--- a/third_party/blink/renderer/core/loader/web_associated_url_loader_impl.cc
+++ b/third_party/blink/renderer/core/loader/web_associated_url_loader_impl.cc
@@ -58,6 +58,7 @@
 #include "third_party/blink/renderer/platform/loader/fetch/resource_error.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
 #include "third_party/blink/renderer/platform/network/http_parsers.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
 #include "third_party/blink/renderer/platform/timer.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
diff --git a/third_party/blink/renderer/core/page/page.cc b/third_party/blink/renderer/core/page/page.cc
index a071c23..4e8dcaf 100644
--- a/third_party/blink/renderer/core/page/page.cc
+++ b/third_party/blink/renderer/core/page/page.cc
@@ -25,6 +25,7 @@
 #include "third_party/blink/public/web/blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
 #include "third_party/blink/renderer/bindings/core/v8/source_location.h"
+#include "third_party/blink/renderer/core/css/media_feature_overrides.h"
 #include "third_party/blink/renderer/core/css/style_change_reason.h"
 #include "third_party/blink/renderer/core/css/style_engine.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
@@ -977,6 +978,26 @@
   }
 }
 
+void Page::SetMediaFeatureOverride(const AtomicString& media_feature,
+                                   const String& value) {
+  if (!media_feature_overrides_) {
+    if (value.IsEmpty())
+      return;
+    media_feature_overrides_ = std::make_unique<MediaFeatureOverrides>();
+  }
+  media_feature_overrides_->SetOverride(media_feature, value);
+  if (media_feature == "prefers-color-scheme")
+    SettingsChanged(SettingsDelegate::kColorSchemeChange);
+  else
+    SettingsChanged(SettingsDelegate::kMediaQueryChange);
+}
+
+void Page::ClearMediaFeatureOverrides() {
+  media_feature_overrides_.reset();
+  SettingsChanged(SettingsDelegate::kMediaQueryChange);
+  SettingsChanged(SettingsDelegate::kColorSchemeChange);
+}
+
 Page::PageClients::PageClients() : chrome_client(nullptr) {}
 
 Page::PageClients::~PageClients() = default;
diff --git a/third_party/blink/renderer/core/page/page.h b/third_party/blink/renderer/core/page/page.h
index f916d59..734027e 100644
--- a/third_party/blink/renderer/core/page/page.h
+++ b/third_party/blink/renderer/core/page/page.h
@@ -63,6 +63,7 @@
 class LinkHighlights;
 class LocalFrame;
 class LocalFrameView;
+class MediaFeatureOverrides;
 class OverscrollController;
 struct PageScaleConstraints;
 class PageScaleConstraintsSet;
@@ -323,6 +324,13 @@
     return web_text_autosizer_page_info_;
   }
 
+  void SetMediaFeatureOverride(const AtomicString& media_feature,
+                               const String& value);
+  const MediaFeatureOverrides* GetMediaFeatureOverrides() const {
+    return media_feature_overrides_.get();
+  }
+  void ClearMediaFeatureOverrides();
+
  private:
   friend class ScopedPagePauser;
 
@@ -419,6 +427,9 @@
 
   std::unique_ptr<PageScheduler> page_scheduler_;
 
+  // Overrides for various media features set from the devtools.
+  std::unique_ptr<MediaFeatureOverrides> media_feature_overrides_;
+
   int32_t autoplay_flags_;
 
   // Accessed by frames to determine whether to expose the PortalHost object.
diff --git a/third_party/blink/renderer/core/script/module_script.cc b/third_party/blink/renderer/core/script/module_script.cc
index b742a27..3c4b687 100644
--- a/third_party/blink/renderer/core/script/module_script.cc
+++ b/third_party/blink/renderer/core/script/module_script.cc
@@ -50,27 +50,23 @@
   DCHECK(!error.IsEmpty());
 
   record_.Clear();
-  parse_error_.Set(error.GetIsolate(), error.V8Value());
+  parse_error_ = error.ToWorldSafeV8Reference();
 }
 
 ScriptValue ModuleScript::CreateParseError() const {
-  ScriptState* script_state = settings_object_->GetScriptState();
-  v8::Isolate* isolate = script_state->GetIsolate();
-  ScriptState::Scope scope(script_state);
-  ScriptValue error(script_state, parse_error_.NewLocal(isolate));
+  v8::Isolate* isolate = settings_object_->GetScriptState()->GetIsolate();
+  ScriptValue error(isolate, parse_error_);
   DCHECK(!error.IsEmpty());
   return error;
 }
 
 void ModuleScript::SetErrorToRethrow(ScriptValue error) {
-  error_to_rethrow_.Set(error.GetIsolate(), error.V8Value());
+  error_to_rethrow_ = error.ToWorldSafeV8Reference();
 }
 
 ScriptValue ModuleScript::CreateErrorToRethrow() const {
-  ScriptState* script_state = settings_object_->GetScriptState();
-  v8::Isolate* isolate = script_state->GetIsolate();
-  ScriptState::Scope scope(script_state);
-  ScriptValue error(script_state, error_to_rethrow_.NewLocal(isolate));
+  v8::Isolate* isolate = settings_object_->GetScriptState()->GetIsolate();
+  ScriptValue error(isolate, error_to_rethrow_);
   DCHECK(!error.IsEmpty());
   return error;
 }
diff --git a/third_party/blink/renderer/core/script/module_script.h b/third_party/blink/renderer/core/script/module_script.h
index b949655..aabe3a6c 100644
--- a/third_party/blink/renderer/core/script/module_script.h
+++ b/third_party/blink/renderer/core/script/module_script.h
@@ -7,6 +7,7 @@
 
 #include "third_party/blink/renderer/bindings/core/v8/module_record.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
+#include "third_party/blink/renderer/bindings/core/v8/world_safe_v8_reference.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/script/modulator.h"
 #include "third_party/blink/renderer/core/script/script.h"
@@ -115,10 +116,10 @@
   //   https://github.com/whatwg/html/pull/2991. This shouldn't cause any
   //   observable functional changes, and updating the classic script handling
   //   will require moderate code changes (e.g. to move compilation timing).
-  TraceWrapperV8Reference<v8::Value> parse_error_;
+  WorldSafeV8Reference<v8::Value> parse_error_;
 
   // https://html.spec.whatwg.org/C/#concept-script-error-to-rethrow
-  TraceWrapperV8Reference<v8::Value> error_to_rethrow_;
+  WorldSafeV8Reference<v8::Value> error_to_rethrow_;
 
   mutable HashMap<String, KURL> specifier_to_url_cache_;
   KURL source_url_;
diff --git a/third_party/blink/renderer/core/script/pending_import_map.cc b/third_party/blink/renderer/core/script/pending_import_map.cc
index 5e762238..d5fd6dc 100644
--- a/third_party/blink/renderer/core/script/pending_import_map.cc
+++ b/third_party/blink/renderer/core/script/pending_import_map.cc
@@ -37,9 +37,7 @@
       import_map_(import_map),
       original_context_document_(&original_context_document) {
   if (!error_to_rethrow.IsEmpty()) {
-    ScriptState::Scope scope(error_to_rethrow.GetScriptState());
-    error_to_rethrow_.Set(error_to_rethrow.GetIsolate(),
-                          error_to_rethrow.V8Value());
+    error_to_rethrow_ = error_to_rethrow.ToWorldSafeV8Reference();
   }
 }
 
@@ -83,10 +81,8 @@
 
   Modulator* modulator = Modulator::From(ToScriptStateForMainWorld(frame));
 
-  ScriptState* script_state = modulator->GetScriptState();
-  ScriptState::Scope scope(script_state);
-  ScriptValue error(script_state,
-                    error_to_rethrow_.NewLocal(script_state->GetIsolate()));
+  v8::Isolate* isolate = modulator->GetScriptState()->GetIsolate();
+  ScriptValue error(isolate, error_to_rethrow_);
   modulator->RegisterImportMap(import_map_, error);
 
   // <spec step="9">If element is from an external file, then fire an event
diff --git a/third_party/blink/renderer/core/script/pending_import_map.h b/third_party/blink/renderer/core/script/pending_import_map.h
index 99a3578d..5fb56f7 100644
--- a/third_party/blink/renderer/core/script/pending_import_map.h
+++ b/third_party/blink/renderer/core/script/pending_import_map.h
@@ -5,8 +5,8 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_SCRIPT_PENDING_IMPORT_MAP_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_SCRIPT_PENDING_IMPORT_MAP_H_
 
+#include "third_party/blink/renderer/bindings/core/v8/world_safe_v8_reference.h"
 #include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -57,7 +57,7 @@
 
   // https://wicg.github.io/import-maps/#import-map-parse-result-error-to-rethrow
   // The error is TypeError if the string is non-null, or null otherwise.
-  TraceWrapperV8Reference<v8::Value> error_to_rethrow_;
+  WorldSafeV8Reference<v8::Value> error_to_rethrow_;
 
   // https://wicg.github.io/import-maps/#import-map-parse-result-settings-object
   // The context document at the time when PrepareScript() is executed.
diff --git a/third_party/blink/renderer/core/streams/readable_stream_operations.cc b/third_party/blink/renderer/core/streams/readable_stream_operations.cc
index 3012abf..a387185a 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_operations.cc
+++ b/third_party/blink/renderer/core/streams/readable_stream_operations.cc
@@ -87,7 +87,7 @@
   v8::Local<v8::Value> js_strategy = strategy.V8Value();
   v8::Local<v8::Value> args[] = {js_underlying_source, js_strategy};
   return ScriptValue(
-      script_state,
+      script_state->GetIsolate(),
       V8ScriptRunner::CallExtra(
           script_state, "createReadableStreamWithExternalController", args));
 }
@@ -122,7 +122,7 @@
   v8::Local<v8::Value> args[] = {
       v8::Number::New(script_state->GetIsolate(), high_water_mark)};
   return ScriptValue(
-      script_state,
+      script_state->GetIsolate(),
       V8ScriptRunner::CallExtra(script_state,
                                 "createBuiltInCountQueuingStrategy", args));
 }
@@ -136,7 +136,7 @@
   v8::TryCatch block(script_state->GetIsolate());
   v8::Local<v8::Value> args[] = {stream.V8Value()};
   ScriptValue result(
-      script_state,
+      script_state->GetIsolate(),
       V8ScriptRunner::CallExtra(script_state,
                                 "AcquireReadableStreamDefaultReader", args));
   if (block.HasCaught()) {
@@ -276,7 +276,7 @@
   DCHECK(!port_v8_value.IsEmpty());
   v8::Local<v8::Value> args[] = {stream.V8Value(), port_v8_value};
   ScriptValue result(
-      script_state,
+      script_state->GetIsolate(),
       V8ScriptRunner::CallExtra(script_state, "ReadableStreamSerialize", args));
   if (block.HasCaught()) {
     exception_state.RethrowV8Exception(block.Exception());
@@ -296,7 +296,7 @@
   v8::Local<v8::Value> port_v8 = ToV8(port, script_state);
   DCHECK(!port_v8.IsEmpty());
   v8::Local<v8::Value> args[] = {port_v8};
-  ScriptValue result(script_state,
+  ScriptValue result(script_state->GetIsolate(),
                      V8ScriptRunner::CallExtra(
                          script_state, "ReadableStreamDeserialize", args));
   if (block.HasCaught()) {
diff --git a/third_party/blink/renderer/core/streams/readable_stream_operations_test.cc b/third_party/blink/renderer/core/streams/readable_stream_operations_test.cc
index 467820d..b047091b 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_operations_test.cc
+++ b/third_party/blink/renderer/core/streams/readable_stream_operations_test.cc
@@ -143,7 +143,7 @@
                    .value_or(true));
   EXPECT_FALSE(ReadableStreamOperations::IsReadableStream(
                    scope.GetScriptState(),
-                   ScriptValue::CreateNull(scope.GetScriptState()),
+                   ScriptValue::CreateNull(scope.GetIsolate()),
                    ASSERT_NO_EXCEPTION)
                    .value_or(true));
   EXPECT_FALSE(ReadableStreamOperations::IsReadableStream(
@@ -181,7 +181,7 @@
                    .value_or(true));
   EXPECT_FALSE(ReadableStreamOperations::IsReadableStreamDefaultReader(
                    scope.GetScriptState(),
-                   ScriptValue::CreateNull(scope.GetScriptState()),
+                   ScriptValue::CreateNull(scope.GetIsolate()),
                    ASSERT_NO_EXCEPTION)
                    .value_or(true));
   EXPECT_FALSE(ReadableStreamOperations::IsReadableStreamDefaultReader(
diff --git a/third_party/blink/renderer/core/streams/transferable_streams_test.cc b/third_party/blink/renderer/core/streams/transferable_streams_test.cc
index 3811b05..e8f7de5 100644
--- a/third_party/blink/renderer/core/streams/transferable_streams_test.cc
+++ b/third_party/blink/renderer/core/streams/transferable_streams_test.cc
@@ -49,7 +49,7 @@
           .V8Value()
           .As<v8::Object>());
 
-  writer->write(script_state, ScriptValue::CreateNull(script_state));
+  writer->write(script_state, ScriptValue::CreateNull(scope.GetIsolate()));
 
   class ExpectNullResponse : public ScriptFunction {
    public:
diff --git a/third_party/blink/renderer/core/streams/writable_stream_test.cc b/third_party/blink/renderer/core/streams/writable_stream_test.cc
index e87946d1..109a4de 100644
--- a/third_party/blink/renderer/core/streams/writable_stream_test.cc
+++ b/third_party/blink/renderer/core/streams/writable_stream_test.cc
@@ -52,7 +52,7 @@
   EXPECT_EQ(stream->IsLocked(script_state, ASSERT_NO_EXCEPTION),
             base::make_optional(false));
 
-  ScriptValue writer = stream->getWriter(script_state, ASSERT_NO_EXCEPTION);
+  stream->getWriter(script_state, ASSERT_NO_EXCEPTION);
 
   EXPECT_TRUE(stream->locked(script_state, ASSERT_NO_EXCEPTION));
   EXPECT_EQ(stream->IsLocked(script_state, ASSERT_NO_EXCEPTION),
diff --git a/third_party/blink/renderer/core/streams/writable_stream_wrapper.cc b/third_party/blink/renderer/core/streams/writable_stream_wrapper.cc
index 6e6ffcd..8ed9eff1 100644
--- a/third_party/blink/renderer/core/streams/writable_stream_wrapper.cc
+++ b/third_party/blink/renderer/core/streams/writable_stream_wrapper.cc
@@ -233,8 +233,8 @@
   DCHECK(!port_v8.IsEmpty());
   v8::Local<v8::Value> args[] = {port_v8};
   ScriptValue internal_stream(
-      script_state, V8ScriptRunner::CallExtra(
-                        script_state, "WritableStreamDeserialize", args));
+      isolate, V8ScriptRunner::CallExtra(script_state,
+                                         "WritableStreamDeserialize", args));
   if (block.HasCaught()) {
     exception_state.RethrowV8Exception(block.Exception());
     return nullptr;
diff --git a/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc b/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
index bcf78ac5..3f82428 100644
--- a/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
+++ b/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
@@ -1261,7 +1261,7 @@
   DispatchEvent(*Event::Create(event_type));
 }
 
-bool SVGSMILElement::HasValidTarget() {
+bool SVGSMILElement::HasValidTarget() const {
   return targetElement() && targetElement()->InActiveDocument();
 }
 
diff --git a/third_party/blink/renderer/core/svg/animation/svg_smil_element.h b/third_party/blink/renderer/core/svg/animation/svg_smil_element.h
index a7bd8c3..fd11d50 100644
--- a/third_party/blink/renderer/core/svg/animation/svg_smil_element.h
+++ b/third_party/blink/renderer/core/svg/animation/svg_smil_element.h
@@ -55,7 +55,7 @@
   InsertionNotificationRequest InsertedInto(ContainerNode&) override;
   void RemovedFrom(ContainerNode&) override;
 
-  virtual bool HasValidTarget();
+  virtual bool HasValidTarget() const;
   virtual void AnimationAttributeChanged() = 0;
 
   SMILTimeContainer* TimeContainer() const { return time_container_.Get(); }
@@ -115,7 +115,7 @@
   // Returns true if this animation "sets" the
   // value of the animation. Thus all previous
   // animations are rendered useless.
-  virtual bool OverwritesUnderlyingAnimationValue() = 0;
+  virtual bool OverwritesUnderlyingAnimationValue() const = 0;
 
   bool AnimatedTypeIsLocked() const { return animated_property_locked_; }
   void LockAnimatedType() {
diff --git a/third_party/blink/renderer/core/svg/svg_animate_element.cc b/third_party/blink/renderer/core/svg/svg_animate_element.cc
index 72a2abc9..c4c8633 100644
--- a/third_party/blink/renderer/core/svg/svg_animate_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_animate_element.cc
@@ -203,19 +203,23 @@
   css_property_id_ = CSSPropertyID::kInvalid;
 }
 
-AnimatedPropertyType SVGAnimateElement::GetAnimatedPropertyType() {
-  if (!targetElement())
-    return kAnimatedUnknown;
-  ResolveTargetProperty();
-  return type_;
+void SVGAnimateElement::UpdateTargetProperty() {
+  if (SVGElement* target = targetElement())
+    ResolveTargetProperty();
+  else
+    ClearTargetProperty();
 }
 
-bool SVGAnimateElement::HasValidTarget() {
+AnimatedPropertyType SVGAnimateElement::GetAnimatedPropertyType() const {
+  // TODO(fs): Should be possible to DCHECK targetElement() here instead.
+  return !targetElement() ? kAnimatedUnknown : type_;
+}
+
+bool SVGAnimateElement::HasValidTarget() const {
   if (!SVGAnimationElement::HasValidTarget())
     return false;
   if (AttributeName() == AnyQName())
     return false;
-  ResolveTargetProperty();
   if (type_ == kAnimatedUnknown)
     return false;
   // Always animate CSS properties using the ApplyCSSAnimation code path,
@@ -227,8 +231,7 @@
 }
 
 bool SVGAnimateElement::ShouldApplyAnimation(
-    const SVGElement& target_element,
-    const QualifiedName& attribute_name) {
+    const SVGElement& target_element) const {
   return target_element.parentNode() && HasValidTarget();
 }
 
@@ -416,24 +419,20 @@
 }
 
 void SVGAnimateElement::ResetAnimatedType() {
-  ResolveTargetProperty();
-
   SVGElement* target_element = targetElement();
-  const QualifiedName& attribute_name = AttributeName();
-
-  if (!ShouldApplyAnimation(*target_element, attribute_name))
+  if (!ShouldApplyAnimation(*target_element))
     return;
   if (IsAnimatingSVGDom()) {
     // SVG DOM animVal animation code-path.
     animated_value_ = target_property_->CreateAnimatedValue();
     DCHECK_EQ(animated_value_->GetType(), type_);
-    target_element->SetAnimatedAttribute(attribute_name, animated_value_);
+    target_element->SetAnimatedAttribute(AttributeName(), animated_value_);
     return;
   }
   DCHECK(IsAnimatingCSSProperty());
   // Presentation attributes which has an SVG DOM representation should use the
   // "SVG DOM" code-path (above.)
-  DCHECK(SVGElement::IsAnimatableCSSProperty(attribute_name));
+  DCHECK(SVGElement::IsAnimatableCSSProperty(AttributeName()));
 
   // CSS properties animation code-path.
   String base_value = ComputeCSSPropertyValue(target_element, css_property_id_);
@@ -456,7 +455,7 @@
     return;
   }
 
-  bool should_apply = ShouldApplyAnimation(*target_element, AttributeName());
+  bool should_apply = ShouldApplyAnimation(*target_element);
   if (IsAnimatingCSSProperty()) {
     // CSS properties animation code-path.
     if (should_apply) {
@@ -477,7 +476,6 @@
   }
 
   animated_value_.Clear();
-  ClearTargetProperty();
 }
 
 void SVGAnimateElement::ApplyResultsToTarget() {
@@ -489,7 +487,7 @@
     return;
 
   SVGElement* target_element = targetElement();
-  if (!ShouldApplyAnimation(*target_element, AttributeName()))
+  if (!ShouldApplyAnimation(*target_element))
     return;
 
   // We do update the style and the animation property independent of each
@@ -520,7 +518,7 @@
   }
 }
 
-bool SVGAnimateElement::AnimatedPropertyTypeSupportsAddition() {
+bool SVGAnimateElement::AnimatedPropertyTypeSupportsAddition() const {
   // http://www.w3.org/TR/SVG/animate.html#AnimationAttributesAndProperties.
   switch (GetAnimatedPropertyType()) {
     case kAnimatedBoolean:
@@ -534,7 +532,7 @@
   }
 }
 
-bool SVGAnimateElement::IsAdditive() {
+bool SVGAnimateElement::IsAdditive() const {
   if (GetAnimationMode() == kByAnimation ||
       GetAnimationMode() == kFromByAnimation) {
     if (!AnimatedPropertyTypeSupportsAddition())
@@ -561,8 +559,11 @@
 }
 
 void SVGAnimateElement::DidChangeAnimationTarget() {
+  // Call this before calling the super-class, because it will check
+  // HasValidTarget() which depends on the animation type being resolved.
+  UpdateTargetProperty();
   SVGAnimationElement::DidChangeAnimationTarget();
-  ResetAnimatedPropertyType();
+  ResetCachedAnimationState();
 }
 
 void SVGAnimateElement::SetAttributeName(const QualifiedName& attribute_name) {
@@ -587,13 +588,12 @@
   DidChangeAnimationTarget();
 }
 
-void SVGAnimateElement::ResetAnimatedPropertyType() {
+void SVGAnimateElement::ResetCachedAnimationState() {
   DCHECK(!animated_value_);
   InvalidatedValuesCache();
   from_property_.Clear();
   to_property_.Clear();
   to_at_end_of_duration_property_.Clear();
-  ClearTargetProperty();
 }
 
 void SVGAnimateElement::Trace(blink::Visitor* visitor) {
diff --git a/third_party/blink/renderer/core/svg/svg_animate_element.h b/third_party/blink/renderer/core/svg/svg_animate_element.h
index 094435ae..5bd334bb 100644
--- a/third_party/blink/renderer/core/svg/svg_animate_element.h
+++ b/third_party/blink/renderer/core/svg/svg_animate_element.h
@@ -49,11 +49,11 @@
   bool IsSVGAnimationAttributeSettingJavaScriptURL(
       const Attribute&) const override;
 
-  AnimatedPropertyType GetAnimatedPropertyType();
-  bool AnimatedPropertyTypeSupportsAddition();
+  AnimatedPropertyType GetAnimatedPropertyType() const;
+  bool AnimatedPropertyTypeSupportsAddition() const;
 
  protected:
-  bool HasValidTarget() override;
+  bool HasValidTarget() const override;
 
   void WillChangeAnimationTarget() final;
   void DidChangeAnimationTarget() final;
@@ -73,7 +73,7 @@
   void ApplyResultsToTarget() final;
   float CalculateDistance(const String& from_string,
                           const String& to_string) final;
-  bool IsAdditive() final;
+  bool IsAdditive() const final;
 
   void ParseAttribute(const AttributeModificationParams&) override;
 
@@ -90,10 +90,9 @@
                            stringsShouldNotSupportAddition);
 
  private:
-  void ResetAnimatedPropertyType();
+  void ResetCachedAnimationState();
 
-  bool ShouldApplyAnimation(const SVGElement& target_element,
-                            const QualifiedName& attribute_name);
+  bool ShouldApplyAnimation(const SVGElement& target_element) const;
 
   void SetAttributeType(const AtomicString&);
 
@@ -102,6 +101,7 @@
 
   virtual void ResolveTargetProperty();
   void ClearTargetProperty();
+  void UpdateTargetProperty();
 
   virtual SVGPropertyBase* CreatePropertyForAnimation(const String&) const;
   SVGPropertyBase* CreatePropertyForAttributeAnimation(const String&) const;
diff --git a/third_party/blink/renderer/core/svg/svg_animate_motion_element.cc b/third_party/blink/renderer/core/svg/svg_animate_motion_element.cc
index c0c87d9..d2815ff 100644
--- a/third_party/blink/renderer/core/svg/svg_animate_motion_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_animate_motion_element.cc
@@ -64,7 +64,7 @@
 
 SVGAnimateMotionElement::~SVGAnimateMotionElement() = default;
 
-bool SVGAnimateMotionElement::HasValidTarget() {
+bool SVGAnimateMotionElement::HasValidTarget() const {
   return SVGAnimationElement::HasValidTarget() &&
          TargetCanHaveMotionTransform(*targetElement());
 }
diff --git a/third_party/blink/renderer/core/svg/svg_animate_motion_element.h b/third_party/blink/renderer/core/svg/svg_animate_motion_element.h
index 2b0eba2..6ccda14 100644
--- a/third_party/blink/renderer/core/svg/svg_animate_motion_element.h
+++ b/third_party/blink/renderer/core/svg/svg_animate_motion_element.h
@@ -36,7 +36,7 @@
   void UpdateAnimationPath();
 
  private:
-  bool HasValidTarget() override;
+  bool HasValidTarget() const override;
 
   void ParseAttribute(const AttributeModificationParams&) override;
 
diff --git a/third_party/blink/renderer/core/svg/svg_animate_transform_element.cc b/third_party/blink/renderer/core/svg/svg_animate_transform_element.cc
index c7a94f3..e1a8942 100644
--- a/third_party/blink/renderer/core/svg/svg_animate_transform_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_animate_transform_element.cc
@@ -33,7 +33,7 @@
     : SVGAnimateElement(svg_names::kAnimateTransformTag, document),
       transform_type_(SVGTransformType::kUnknown) {}
 
-bool SVGAnimateTransformElement::HasValidTarget() {
+bool SVGAnimateTransformElement::HasValidTarget() const {
   if (!SVGAnimateElement::HasValidTarget())
     return false;
   if (GetAttributeType() == kAttributeTypeCSS)
diff --git a/third_party/blink/renderer/core/svg/svg_animate_transform_element.h b/third_party/blink/renderer/core/svg/svg_animate_transform_element.h
index 102b4c3f..8260fab 100644
--- a/third_party/blink/renderer/core/svg/svg_animate_transform_element.h
+++ b/third_party/blink/renderer/core/svg/svg_animate_transform_element.h
@@ -35,7 +35,7 @@
   explicit SVGAnimateTransformElement(Document&);
 
  private:
-  bool HasValidTarget() override;
+  bool HasValidTarget() const override;
 
   void ParseAttribute(const AttributeModificationParams&) override;
 
diff --git a/third_party/blink/renderer/core/svg/svg_animation_element.cc b/third_party/blink/renderer/core/svg/svg_animation_element.cc
index 5e80887..17210de 100644
--- a/third_party/blink/renderer/core/svg/svg_animation_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_animation_element.cc
@@ -322,7 +322,7 @@
   return FastGetAttribute(svg_names::kFromAttr);
 }
 
-bool SVGAnimationElement::IsAdditive() {
+bool SVGAnimationElement::IsAdditive() const {
   DEFINE_STATIC_LOCAL(const AtomicString, sum, ("sum"));
   const AtomicString& value = FastGetAttribute(svg_names::kAdditiveAttr);
   return value == sum || GetAnimationMode() == kByAnimation;
@@ -633,7 +633,7 @@
   CalculateAnimatedValue(effective_percent, repeat_count, result_element);
 }
 
-bool SVGAnimationElement::OverwritesUnderlyingAnimationValue() {
+bool SVGAnimationElement::OverwritesUnderlyingAnimationValue() const {
   return !IsAdditive() && !IsAccumulated() &&
          GetAnimationMode() != kToAnimation &&
          GetAnimationMode() != kByAnimation &&
diff --git a/third_party/blink/renderer/core/svg/svg_animation_element.h b/third_party/blink/renderer/core/svg/svg_animation_element.h
index 3df1f11..92721a9 100644
--- a/third_party/blink/renderer/core/svg/svg_animation_element.h
+++ b/third_party/blink/renderer/core/svg/svg_animation_element.h
@@ -69,12 +69,12 @@
   DEFINE_ATTRIBUTE_EVENT_LISTENER(end, kEndEvent)
   DEFINE_ATTRIBUTE_EVENT_LISTENER(repeat, kRepeatEvent)
 
-  virtual bool IsAdditive();
+  virtual bool IsAdditive() const;
   bool IsAccumulated() const;
   AnimationMode GetAnimationMode() const { return animation_mode_; }
   CalcMode GetCalcMode() const { return calc_mode_; }
 
-  bool OverwritesUnderlyingAnimationValue() override;
+  bool OverwritesUnderlyingAnimationValue() const override;
 
   template <typename AnimatedType>
   void AnimateDiscreteType(float percentage,
diff --git a/third_party/blink/renderer/core/svg/svg_discard_element.h b/third_party/blink/renderer/core/svg/svg_discard_element.h
index 8b7b0263..ade098b 100644
--- a/third_party/blink/renderer/core/svg/svg_discard_element.h
+++ b/third_party/blink/renderer/core/svg/svg_discard_element.h
@@ -49,7 +49,7 @@
   void ApplyResultsToTarget() override {}
   void AnimationAttributeChanged() override {}
 
-  bool OverwritesUnderlyingAnimationValue() override { return false; }
+  bool OverwritesUnderlyingAnimationValue() const override { return false; }
 
   void StartedActiveInterval() override {}
   void UpdateAnimation(float percent,
diff --git a/third_party/blink/renderer/core/timing/performance.cc b/third_party/blink/renderer/core/timing/performance.cc
index dc44422..e5571db 100644
--- a/third_party/blink/renderer/core/timing/performance.cc
+++ b/third_party/blink/renderer/core/timing/performance.cc
@@ -755,7 +755,7 @@
         /* duration = */ base::nullopt,
         end_mark ? StringOrDouble::FromString(*end_mark)
                  : NativeValueTraits<StringOrDouble>::NullValue(),
-        ScriptValue::CreateNull(script_state), exception_state);
+        ScriptValue::CreateNull(script_state->GetIsolate()), exception_state);
   }
   // For consistency with UserTimingL2: the L2 API took |start| as a string,
   // so any object passed in became a string '[object, object]', null became
@@ -772,7 +772,8 @@
                     /* duration = */ base::nullopt,
                     end_mark ? StringOrDouble::FromString(*end_mark)
                              : NativeValueTraits<StringOrDouble>::NullValue(),
-                    ScriptValue::CreateNull(script_state), exception_state);
+                    ScriptValue::CreateNull(script_state->GetIsolate()),
+                    exception_state);
   // Return nullptr to distinguish from L3.
   return nullptr;
 }
diff --git a/third_party/blink/renderer/core/timing/performance_user_timing.cc b/third_party/blink/renderer/core/timing/performance_user_timing.cc
index ddabb64..c8fb44c 100644
--- a/third_party/blink/renderer/core/timing/performance_user_timing.cc
+++ b/third_party/blink/renderer/core/timing/performance_user_timing.cc
@@ -115,7 +115,7 @@
     start = performance_->now();
   }
 
-  ScriptValue detail = ScriptValue::CreateNull(script_state);
+  ScriptValue detail = ScriptValue::CreateNull(script_state->GetIsolate());
   if (RuntimeEnabledFeatures::CustomUserTimingEnabled() && mark_options)
     detail = mark_options->detail();
 
diff --git a/third_party/blink/renderer/devtools/front_end/coverage/CoverageDecorationManager.js b/third_party/blink/renderer/devtools/front_end/coverage/CoverageDecorationManager.js
index 44d43c8..9fd998f 100644
--- a/third_party/blink/renderer/devtools/front_end/coverage/CoverageDecorationManager.js
+++ b/third_party/blink/renderer/devtools/front_end/coverage/CoverageDecorationManager.js
@@ -201,6 +201,11 @@
  * @implements {SourceFrame.LineDecorator}
  */
 Coverage.CoverageView.LineDecorator = class {
+  constructor() {
+    /** @type {!WeakMap<!TextEditor.CodeMirrorTextEditor, function(!Common.Event)>} */
+    this._listeners = new WeakMap();
+  }
+
   /**
    * @override
    * @param {!Workspace.UISourceCode} uiSourceCode
@@ -209,31 +214,78 @@
   decorate(uiSourceCode, textEditor) {
     const decorations = uiSourceCode.decorationsForType(Coverage.CoverageDecorationManager._decoratorType);
     if (!decorations || !decorations.size) {
-      textEditor.uninstallGutter(Coverage.CoverageView.LineDecorator._gutterType);
+      this._uninstallGutter(textEditor);
       return;
     }
     const decorationManager =
         /** @type {!Coverage.CoverageDecorationManager} */ (decorations.values().next().value.data());
     decorationManager.usageByLine(uiSourceCode).then(lineUsage => {
-      textEditor.operation(() => this._innerDecorate(textEditor, lineUsage));
+      textEditor.operation(() => this._innerDecorate(uiSourceCode, textEditor, lineUsage));
     });
   }
 
   /**
+   * @param {!Workspace.UISourceCode} uiSourceCode
    * @param {!TextEditor.CodeMirrorTextEditor} textEditor
    * @param {!Array<boolean>} lineUsage
    */
-  _innerDecorate(textEditor, lineUsage) {
+  _innerDecorate(uiSourceCode, textEditor, lineUsage) {
     const gutterType = Coverage.CoverageView.LineDecorator._gutterType;
-    textEditor.uninstallGutter(gutterType);
+    this._uninstallGutter(textEditor);
     if (lineUsage.length)
-      textEditor.installGutter(gutterType, false);
+      this._installGutter(textEditor, uiSourceCode.url());
     for (let line = 0; line < lineUsage.length; ++line) {
       // Do not decorate the line if we don't have data.
       if (typeof lineUsage[line] !== 'boolean')
         continue;
       const className = lineUsage[line] ? 'text-editor-coverage-used-marker' : 'text-editor-coverage-unused-marker';
-      textEditor.setGutterDecoration(line, gutterType, createElementWithClass('div', className));
+      const gutterElement = createElementWithClass('div', className);
+      textEditor.setGutterDecoration(line, gutterType, gutterElement);
+    }
+  }
+
+  /**
+   * @param {string} url - the url of the file  this click handler will select in the coverage drawer
+   * @return {function(!Common.Event)}
+   */
+  makeGutterClickHandler(url) {
+    function handleGutterClick(event) {
+      const eventData = /** @type {!SourceFrame.SourcesTextEditor.GutterClickEventData} */ (event.data);
+      if (eventData.gutterType !== Coverage.CoverageView.LineDecorator._gutterType)
+        return;
+      const coverageViewId = 'coverage';
+      UI.viewManager.showView(coverageViewId).then(() => UI.viewManager.view(coverageViewId).widget()).then(widget => {
+        const matchFormattedSuffix = url.match(/(.*):formatted$/);
+        const urlWithoutFormattedSuffix = (matchFormattedSuffix && matchFormattedSuffix[1]) || url;
+        widget.selectCoverageItemByUrl(urlWithoutFormattedSuffix);
+      });
+    }
+    return handleGutterClick;
+  }
+
+  /**
+     * @param {!TextEditor.CodeMirrorTextEditor} textEditor - the text editor to install the gutter on
+     * @param {string} url - the url of the file in the text editor
+   */
+  _installGutter(textEditor, url) {
+    let listener = this._listeners.get(textEditor);
+    if (!listener) {
+      listener = this.makeGutterClickHandler(url);
+      this._listeners.set(textEditor, listener);
+    }
+    textEditor.installGutter(Coverage.CoverageView.LineDecorator._gutterType, false);
+    textEditor.addEventListener(SourceFrame.SourcesTextEditor.Events.GutterClick, listener, this);
+  }
+
+  /**
+     * @param {!TextEditor.CodeMirrorTextEditor} textEditor  - the text editor to uninstall the gutter from
+     */
+  _uninstallGutter(textEditor) {
+    textEditor.uninstallGutter(Coverage.CoverageView.LineDecorator._gutterType);
+    const listener = this._listeners.get(textEditor);
+    if (listener) {
+      textEditor.removeEventListener(SourceFrame.SourcesTextEditor.Events.GutterClick, listener, this);
+      this._listeners.delete(textEditor);
     }
   }
 };
diff --git a/third_party/blink/renderer/devtools/front_end/coverage/CoverageListView.js b/third_party/blink/renderer/devtools/front_end/coverage/CoverageListView.js
index c3ed61c..a2b0231 100644
--- a/third_party/blink/renderer/devtools/front_end/coverage/CoverageListView.js
+++ b/third_party/blink/renderer/devtools/front_end/coverage/CoverageListView.js
@@ -99,6 +99,15 @@
       this._sortingChanged();
   }
 
+  selectByUrl(url) {
+    for (const [info, node] of this._nodeForCoverageInfo.entries()) {
+      if (info.url() === url) {
+        node.revealAndSelect();
+        break;
+      }
+    }
+  }
+
   _onOpenedNode() {
     this._revealSourceForSelectedNode();
   }
diff --git a/third_party/blink/renderer/devtools/front_end/coverage/CoverageView.js b/third_party/blink/renderer/devtools/front_end/coverage/CoverageView.js
index ba45c2e..d2fd173 100644
--- a/third_party/blink/renderer/devtools/front_end/coverage/CoverageView.js
+++ b/third_party/blink/renderer/devtools/front_end/coverage/CoverageView.js
@@ -109,7 +109,14 @@
     if (enable)
       this._startRecording(false);
     else
-      this._stopRecording();
+      this.stopRecording();
+  }
+
+  async ensureRecordingStarted() {
+    const enable = !this._toggleRecordAction.toggled();
+
+    if (enable)
+      await this._startRecording(false);
   }
 
   /**
@@ -153,7 +160,7 @@
     this._updateViews(event.data);
   }
 
-  async _stopRecording() {
+  async stopRecording() {
     if (this._resourceTreeModel) {
       this._resourceTreeModel.removeEventListener(
           SDK.ResourceTreeModel.Events.MainFrameNavigated, this._onMainFrameNavigated, this);
@@ -232,6 +239,10 @@
       return;
     this._model.exportReport(fos);
   }
+
+  selectCoverageItemByUrl(url) {
+    this._listView.selectByUrl(url);
+  }
 };
 
 Coverage.CoverageView._extensionBindingsURLPrefix = 'extensions::';
diff --git a/third_party/blink/renderer/devtools/front_end/coverage/coverage_strings.grdp b/third_party/blink/renderer/devtools/front_end/coverage/coverage_strings.grdp
index eee29fb..94f74f0 100644
--- a/third_party/blink/renderer/devtools/front_end/coverage/coverage_strings.grdp
+++ b/third_party/blink/renderer/devtools/front_end/coverage/coverage_strings.grdp
@@ -38,9 +38,6 @@
     <ph name="NUMBER_BYTESTOSTRING_USED_">$1s<ex>1.5 MB</ex></ph> of <ph name="NUMBER_BYTESTOSTRING_TOTAL_">$2s<ex>2.1 MB</ex></ph> (<ph name="PERCENTUSED">$3s<ex>71%</ex></ph>%) used so far.
         <ph name="NUMBER_BYTESTOSTRING_UNUSED_">$4s<ex>29%</ex></ph> unused.
   </message>
-  <message name="IDS_DEVTOOLS_9841bdc50c4226cb6ec5db76494249e6" desc="Title of the 'Coverage' tool in the bottom drawer">
-    Coverage
-  </message>
   <message name="IDS_DEVTOOLS_bca27ccb808f436cd1ce828dd47604b7" desc="Title of an action in the coverage tool to start with reload">
     Start instrumenting coverage and reload page
   </message>
diff --git a/third_party/blink/renderer/devtools/front_end/coverage_test_runner/CoverageTestRunner.js b/third_party/blink/renderer/devtools/front_end/coverage_test_runner/CoverageTestRunner.js
index 1d13d37..8724d4a 100644
--- a/third_party/blink/renderer/devtools/front_end/coverage_test_runner/CoverageTestRunner.js
+++ b/third_party/blink/renderer/devtools/front_end/coverage_test_runner/CoverageTestRunner.js
@@ -18,7 +18,7 @@
  */
 CoverageTestRunner.stopCoverage = function() {
   const coverageView = self.runtime.sharedInstance(Coverage.CoverageView);
-  return coverageView._stopRecording();
+  return coverageView.stopRecording();
 };
 
 /**
diff --git a/third_party/blink/renderer/devtools/front_end/langpacks/shared_strings.grdp b/third_party/blink/renderer/devtools/front_end/langpacks/shared_strings.grdp
index 2314bfc..f8b16f8 100644
--- a/third_party/blink/renderer/devtools/front_end/langpacks/shared_strings.grdp
+++ b/third_party/blink/renderer/devtools/front_end/langpacks/shared_strings.grdp
@@ -334,6 +334,9 @@
   <message name="IDS_DEVTOOLS_96e9bc575b5d3ed541113a249da8bd24" desc="Text to take screenshots">
     Capture screenshots
   </message>
+  <message name="IDS_DEVTOOLS_9841bdc50c4226cb6ec5db76494249e6" desc="Title of the 'Coverage' tool in the bottom drawer">
+    Coverage
+  </message>
   <message name="IDS_DEVTOOLS_997a8c473db4f81c5fb3d5900030d44d" desc="Text that shows there is no recording">
     (no recordings)
   </message>
diff --git a/third_party/blink/renderer/devtools/front_end/main/Main.js b/third_party/blink/renderer/devtools/front_end/main/Main.js
index 0c17d6a..787c31a 100644
--- a/third_party/blink/renderer/devtools/front_end/main/Main.js
+++ b/third_party/blink/renderer/devtools/front_end/main/Main.js
@@ -121,6 +121,7 @@
     Runtime.experiments.register('liveHeapProfile', 'Live heap profile', true);
     Runtime.experiments.register('nativeHeapProfiler', 'Native memory sampling heap profiler', true);
     Runtime.experiments.register('protocolMonitor', 'Protocol Monitor');
+    Runtime.experiments.register('recordCoverageWithPerformanceTracing', 'Record coverage while performance tracing');
     Runtime.experiments.register('samplingHeapProfilerTimeline', 'Sampling heap profiler timeline', true);
     Runtime.experiments.register('sourceDiff', 'Source diff');
     Runtime.experiments.register('splitInDrawer', 'Split in drawer', true);
diff --git a/third_party/blink/renderer/devtools/front_end/source_frame/SourcesTextEditor.js b/third_party/blink/renderer/devtools/front_end/source_frame/SourcesTextEditor.js
index ec9551e..8b90bcee 100644
--- a/third_party/blink/renderer/devtools/front_end/source_frame/SourcesTextEditor.js
+++ b/third_party/blink/renderer/devtools/front_end/source_frame/SourcesTextEditor.js
@@ -46,7 +46,7 @@
     this._tokenHighlighter = new SourceFrame.SourcesTextEditor.TokenHighlighter(this, this.codeMirror());
 
     /** @type {!Array<string>} */
-    this._gutters = ['CodeMirror-linenumbers'];
+    this._gutters = [SourceFrame.SourcesTextEditor.lineNumbersGutterType];
     this.codeMirror().setOption('gutters', this._gutters.slice());
 
     this.codeMirror().setOption('electricChars', false);
@@ -323,11 +323,8 @@
     return classNames.indexOf(className) !== -1;
   }
 
-  _gutterClick(instance, lineNumber, gutter, event) {
-    if (gutter !== 'CodeMirror-linenumbers')
-      return;
-    this.dispatchEventToListeners(
-        SourceFrame.SourcesTextEditor.Events.GutterClick, {lineNumber: lineNumber, event: event});
+  _gutterClick(instance, lineNumber, gutterType, event) {
+    this.dispatchEventToListeners(SourceFrame.SourcesTextEditor.Events.GutterClick, {gutterType, lineNumber, event});
   }
 
   _contextMenu(event) {
@@ -634,7 +631,7 @@
   }
 };
 
-/** @typedef {{lineNumber: number, event: !Event}} */
+/** @typedef {{gutterType: string, lineNumber: number, event: !Event}} */
 SourceFrame.SourcesTextEditor.GutterClickEventData;
 
 /** @enum {symbol} */
@@ -935,3 +932,4 @@
 
 SourceFrame.SourcesTextEditor.LinesToScanForIndentationGuessing = 1000;
 SourceFrame.SourcesTextEditor.MaximumNumberOfWhitespacesPerSingleSpan = 16;
+SourceFrame.SourcesTextEditor.lineNumbersGutterType = 'CodeMirror-linenumbers';
diff --git a/third_party/blink/renderer/devtools/front_end/sources/DebuggerPlugin.js b/third_party/blink/renderer/devtools/front_end/sources/DebuggerPlugin.js
index 0ca3fb8..d3cc9a28 100644
--- a/third_party/blink/renderer/devtools/front_end/sources/DebuggerPlugin.js
+++ b/third_party/blink/renderer/devtools/front_end/sources/DebuggerPlugin.js
@@ -1453,6 +1453,8 @@
       return;
 
     const eventData = /** @type {!SourceFrame.SourcesTextEditor.GutterClickEventData} */ (event.data);
+    if (eventData.gutterType !== SourceFrame.SourcesTextEditor.lineNumbersGutterType)
+      return;
     const editorLineNumber = eventData.lineNumber;
     const eventObject = eventData.event;
 
diff --git a/third_party/blink/renderer/devtools/front_end/timeline/TimelineController.js b/third_party/blink/renderer/devtools/front_end/timeline/TimelineController.js
index 002dabe..92d4a31 100644
--- a/third_party/blink/renderer/devtools/front_end/timeline/TimelineController.js
+++ b/third_party/blink/renderer/devtools/front_end/timeline/TimelineController.js
@@ -373,7 +373,8 @@
  * @typedef {!{
  *   enableJSSampling: (boolean|undefined),
  *   capturePictures: (boolean|undefined),
- *   captureFilmStrip: (boolean|undefined)
+ *   captureFilmStrip: (boolean|undefined),
+ *   startCoverage: (boolean|undefined)
  * }}
  */
 Timeline.TimelineController.RecordingOptions;
diff --git a/third_party/blink/renderer/devtools/front_end/timeline/TimelinePanel.js b/third_party/blink/renderer/devtools/front_end/timeline/TimelinePanel.js
index 1182538..4311b1f 100644
--- a/third_party/blink/renderer/devtools/front_end/timeline/TimelinePanel.js
+++ b/third_party/blink/renderer/devtools/front_end/timeline/TimelinePanel.js
@@ -70,6 +70,13 @@
     this._showScreenshotsSetting.setTitle(Common.UIString('Screenshots'));
     this._showScreenshotsSetting.addChangeListener(this._updateOverviewControls, this);
 
+    this._startCoverage = Common.settings.createSetting('timelineStartCoverage', false);
+    this._startCoverage.setTitle(ls`Coverage`);
+
+    if (!Runtime.experiments.isEnabled('recordCoverageWithPerformanceTracing'))
+      this._startCoverage.set(false);
+
+
     this._showMemorySetting = Common.settings.createSetting('timelineShowMemory', false);
     this._showMemorySetting.setTitle(Common.UIString('Memory'));
     this._showMemorySetting.addChangeListener(this._onModeChanged, this);
@@ -226,6 +233,12 @@
         this._createSettingCheckbox(this._showMemorySetting, Common.UIString('Show memory timeline'));
     this._panelToolbar.appendToolbarItem(this._showMemoryToolbarCheckbox);
 
+    if (Runtime.experiments.isEnabled('recordCoverageWithPerformanceTracing')) {
+      this._startCoverageCheckbox =
+          this._createSettingCheckbox(this._startCoverage, ls`Record coverage with performance trace`);
+      this._panelToolbar.appendToolbarItem(this._startCoverageCheckbox);
+    }
+
     // GC
     this._panelToolbar.appendToolbarItem(UI.Toolbar.createActionButtonForId('components.collect-garbage'));
 
@@ -470,17 +483,25 @@
   async _startRecording() {
     console.assert(!this._statusPane, 'Status pane is already opened.');
     this._setState(Timeline.TimelinePanel.State.StartPending);
-    this._showRecordingStarted();
-
-    const enabledTraceProviders = Extensions.extensionServer.traceProviders().filter(
-        provider => Timeline.TimelinePanel._settingForTraceProvider(provider).get());
 
     const recordingOptions = {
       enableJSSampling: !this._disableCaptureJSProfileSetting.get(),
       capturePictures: this._captureLayersAndPicturesSetting.get(),
-      captureFilmStrip: this._showScreenshotsSetting.get()
+      captureFilmStrip: this._showScreenshotsSetting.get(),
+      startCoverage: this._startCoverage.get()
     };
 
+    if (recordingOptions.startCoverage) {
+      await UI.viewManager.showView('coverage')
+          .then(() => UI.viewManager.view('coverage').widget())
+          .then(widget => widget.ensureRecordingStarted());
+    }
+
+    this._showRecordingStarted();
+
+    const enabledTraceProviders = Extensions.extensionServer.traceProviders().filter(
+        provider => Timeline.TimelinePanel._settingForTraceProvider(provider).get());
+
     const mainTarget = /** @type {!SDK.Target} */ (SDK.targetManager.mainTarget());
     this._controller = new Timeline.TimelineController(mainTarget, this);
     this._setUIControlsEnabled(false);
@@ -746,6 +767,12 @@
     this._performanceModel.setTracingModel(tracingModel);
     this._setModel(this._performanceModel);
     this._historyManager.addRecording(this._performanceModel);
+
+    if (this._startCoverage.get()) {
+      UI.viewManager.showView('coverage')
+          .then(() => UI.viewManager.view('coverage').widget())
+          .then(widget => widget.stopRecording());
+    }
   }
 
   _showRecordingStarted() {
diff --git a/third_party/blink/renderer/devtools/front_end/timeline/TimelineTreeView.js b/third_party/blink/renderer/devtools/front_end/timeline/TimelineTreeView.js
index 2815c593..2b454dd 100644
--- a/third_party/blink/renderer/devtools/front_end/timeline/TimelineTreeView.js
+++ b/third_party/blink/renderer/devtools/front_end/timeline/TimelineTreeView.js
@@ -787,8 +787,7 @@
       {label: Common.UIString('Group by Subdomain'), value: groupBy.Subdomain},
       {label: Common.UIString('Group by URL'), value: groupBy.URL},
     ];
-    toolbar.appendToolbarItem(
-        new UI.ToolbarSettingComboBox(options, this._groupBySetting, undefined /* optGroup */, ls`Group by`));
+    toolbar.appendToolbarItem(new UI.ToolbarSettingComboBox(options, this._groupBySetting, ls`Group by`));
     toolbar.appendSpacer();
     toolbar.appendToolbarItem(this._splitWidget.createShowHideSidebarButton(Common.UIString('heaviest stack')));
   }
diff --git a/third_party/blink/renderer/devtools/front_end/timeline/timeline_strings.grdp b/third_party/blink/renderer/devtools/front_end/timeline/timeline_strings.grdp
index 389883b..9442d983 100644
--- a/third_party/blink/renderer/devtools/front_end/timeline/timeline_strings.grdp
+++ b/third_party/blink/renderer/devtools/front_end/timeline/timeline_strings.grdp
@@ -663,6 +663,9 @@
   <message name="IDS_DEVTOOLS_aed0e2bd848c2ac9dddb03d8c21c67b6" desc="Text in Timeline UIUtils of the Performance panel">
     Touch Cancel
   </message>
+  <message name="IDS_DEVTOOLS_af812f467030e02c8bc8a81b4db8e562" desc="Text in Timeline Panel of the Performance panel">
+    Record coverage with performance trace
+  </message>
   <message name="IDS_DEVTOOLS_b030f7d30297555390c6d2d23af55fa1" desc="Text in Timeline History Manager of the Performance panel">
     moments
   </message>
diff --git a/third_party/blink/renderer/devtools/front_end/ui/Toolbar.js b/third_party/blink/renderer/devtools/front_end/ui/Toolbar.js
index 5882bdf..ff51637 100644
--- a/third_party/blink/renderer/devtools/front_end/ui/Toolbar.js
+++ b/third_party/blink/renderer/devtools/front_end/ui/Toolbar.js
@@ -766,12 +766,10 @@
    * @param {!Common.Setting} setting
    * @param {string} glyph
    * @param {string} title
-   * @param {string=} toggledTitle
    */
-  constructor(setting, glyph, title, toggledTitle) {
+  constructor(setting, glyph, title) {
     super(title, glyph);
     this._defaultTitle = title;
-    this._toggledTitle = toggledTitle || title;
     this._setting = setting;
     this._settingChanged();
     this._setting.addChangeListener(this._settingChanged, this);
@@ -780,7 +778,7 @@
   _settingChanged() {
     const toggled = this._setting.get();
     this.setToggled(toggled);
-    this.setTitle(toggled ? this._toggledTitle : this._defaultTitle);
+    this.setTitle(this._defaultTitle);
   }
 
   /**
@@ -971,23 +969,15 @@
   /**
    * @param {!Array<!{value: string, label: string}>} options
    * @param {!Common.Setting} setting
-   * @param {string=} optGroup
    * @param {string=} accessibleName
    */
-  constructor(options, setting, optGroup, accessibleName) {
+  constructor(options, setting, accessibleName) {
     super(null);
-    this._setting = setting;
     this._options = options;
+    this._setting = setting;
     this._selectElement.addEventListener('change', this._valueChanged.bind(this), false);
     if (accessibleName)
       UI.ARIAUtils.setAccessibleName(this._selectElement, accessibleName);
-    if (optGroup) {
-      const optGroupElement = this._selectElement.createChild('optgroup');
-      optGroupElement.label = optGroup;
-      this._optionContainer = optGroupElement;
-    } else {
-      this._optionContainer = this._selectElement;
-    }
     this.setOptions(options);
     setting.addChangeListener(this._settingChanged, this);
   }
@@ -997,11 +987,11 @@
    */
   setOptions(options) {
     this._options = options;
-    this._optionContainer.removeChildren();
+    this._selectElement.removeChildren();
     for (let i = 0; i < options.length; ++i) {
       const dataOption = options[i];
       const option = this.createOption(dataOption.label, dataOption.value);
-      this._optionContainer.appendChild(option);
+      this._selectElement.appendChild(option);
       if (this._setting.get() === dataOption.value)
         this.setSelectedIndex(i);
     }
diff --git a/third_party/blink/renderer/devtools/karma.conf.js b/third_party/blink/renderer/devtools/karma.conf.js
index ceafc53..acc4d2be 100644
--- a/third_party/blink/renderer/devtools/karma.conf.js
+++ b/third_party/blink/renderer/devtools/karma.conf.js
@@ -13,6 +13,9 @@
     },{
       pattern: 'tests/**/*.ts',
       type: 'module'
+    }, {
+      pattern: 'tests/**/*.js',
+      type: 'module'
     }],
 
     reporters: ["dots"],
diff --git a/third_party/blink/renderer/devtools/scripts/localization_utils/localization_utils.js b/third_party/blink/renderer/devtools/scripts/localization_utils/localization_utils.js
index db48e8d..ee1a0a6 100644
--- a/third_party/blink/renderer/devtools/scripts/localization_utils/localization_utils.js
+++ b/third_party/blink/renderer/devtools/scripts/localization_utils/localization_utils.js
@@ -36,7 +36,7 @@
 const SRC_PATH = path.resolve(THIRD_PARTY_PATH, '..');
 const GRD_PATH = path.resolve(__dirname, '..', '..', 'front_end', 'langpacks', 'devtools_ui_strings.grd');
 const SHARED_STRINGS_PATH = path.resolve(__dirname, '..', '..', 'front_end', 'langpacks', 'shared_strings.grdp');
-const REPO_NODE_MODULES_PATH = path.resolve(THIRD_PARTY_PATH, 'node', 'node_modules');
+const REPO_NODE_MODULES_PATH = path.resolve(THIRD_PARTY_PATH, 'devtools-node-modules', 'third_party', 'node_modules');
 const escodegen = require(path.resolve(REPO_NODE_MODULES_PATH, 'escodegen'));
 const esprima = require(path.resolve(REPO_NODE_MODULES_PATH, 'esprima'));
 
diff --git a/third_party/blink/renderer/devtools/tests/front_end/platform/dom-extension.js b/third_party/blink/renderer/devtools/tests/front_end/platform/dom-extension.js
new file mode 100644
index 0000000..30510a7
--- /dev/null
+++ b/third_party/blink/renderer/devtools/tests/front_end/platform/dom-extension.js
@@ -0,0 +1,227 @@
+// 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.
+
+const { assert } = chai;
+import '../../../front_end/dom_extension/DOMExtension.js';
+
+
+function createSlot(parent, name) {
+    const slot = parent.createChild('slot');
+    if (name)
+        slot.name = name;
+    return slot;
+}
+
+function createChild(parent, tagName, name, text = '') {
+    const child = parent.createChild(tagName, name);
+    if (name)
+        child.slot = name;
+    child.textContent = text;
+    return child;
+}
+
+
+describe('DataGrid', () => {
+    it('Traverse Node with Children', () => {
+        let component1 = createElementWithClass('div', 'component1');
+        createChild(component1, 'div', 'component1-content', 'text 1');
+        createChild(component1, 'div', 'component2-content', 'text 2');
+        createChild(component1, 'span', undefined, 'text 3');
+        createChild(component1, 'span', 'component1-content', 'text 4');
+
+        // Now we have:
+        /*
+        * <div class="component1">
+        *    <div class="component1-content" slot="component1-content">text 1</div>
+        *    <div class="component2-content" slot="component2-content">text 2</div>
+        *    <span>text 3</span><span class="component1-content" slot="component1-content">text 4</span>
+        * </div>
+        */
+
+
+        let node = component1;
+        assert.equal(node.nodeValue, null, 'root node value is incorrect');
+        assert.equal(node.nodeName, 'DIV', 'root node name is incorrect');
+        assert.equal(node.className, 'component1', 'root node class is incorrect');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeName, 'DIV', 'first child node name is incorrect');
+        assert.equal(node.className, 'component1-content', 'first child class is incorrect');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeValue, "text 1", 'second child node value is incorrect');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeName, 'DIV', 'second child node name is incorrect');
+        assert.equal(node.className, 'component2-content', 'second child class is incorrect');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeValue, "text 2", 'second child node value is incorrect');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeName, 'SPAN', 'third child node name is incorrect');
+        assert.equal(node.className, '', 'third child class is incorrect');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeValue, "text 3", 'third child node value is incorrect');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeName, 'SPAN', 'forth child node name is incorrect');
+        assert.equal(node.className, 'component1-content', 'forth child class is incorrect');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeValue, "text 4", 'forth child node value is incorrect');
+    });
+
+    it('Traverse Node with Shadows',  () => {
+        var component1 = createElementWithClass('div', 'component1');
+        var shadow1 = component1.attachShadow({mode: 'open'});
+        var shadow1Content = createElementWithClass('div', 'shadow-component1');
+        shadow1.appendChild(shadow1Content);
+        var component2 = shadow1Content.createChild('div', 'component2');
+        var shadow2 = component2.attachShadow({mode: 'open'});
+        var shadow2Content = createElementWithClass('div', 'shadow-component1');
+        shadow2.appendChild(shadow2Content);
+        var midDiv = createChild(shadow2Content, 'div', 'mid-div');
+        createChild(midDiv, 'div', undefined, 'component2-text');
+
+        // Now we have:
+        /*
+        * <div class="component1"></div>
+        * <div class="shadow-component1"><div class="component2"></div></div>
+        * <div class="shadow-component1"><div class="mid-div" slot="mid-div"><div>component2-text</div></div></div>
+        */
+
+        let node = component1;
+        assert.equal(node.nodeName, 'DIV', 'root node name is incorrect');
+        assert.equal(node.className, 'component1', 'root node class is incorrect');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeName, '#document-fragment', 'first document fragment node name is incorrect');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeName, 'DIV', 'first document fragment child node name is incorrect');
+        assert.equal(node.className, 'shadow-component1', 'first document fragment child node name is incorrect');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeName, 'DIV');
+        assert.equal(node.className, 'component2');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeName, '#document-fragment');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeName, 'DIV');
+        assert.equal(node.className, 'shadow-component1');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeName, 'DIV');
+        assert.equal(node.className, 'mid-div');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeName, 'DIV');
+        assert.equal(node.className, '');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeName, '#text');
+        assert.equal(node.nodeValue, 'component2-text');
+    });
+
+    it('Traverse Node with Slots', () => {
+        var component1 = createElementWithClass('div', 'component1');
+        var shadow1 = component1.attachShadow({mode: 'open'});
+        var shadow1Content = createElementWithClass('div', 'shadow-component1');
+        shadow1.appendChild(shadow1Content);
+        createSlot(shadow1Content, 'component1-content');
+        createSlot(shadow1Content, null);
+        var component2 = shadow1Content.createChild('div', 'component2');
+        var shadow2 = component2.attachShadow({mode: 'open'});
+        createSlot(component2, 'component2-content');
+        createChild(
+            component2, 'div', 'component2-content', 'component2 light dom text');
+        var shadow2Content = createElementWithClass('div', 'shadow-component1');
+        shadow2.appendChild(shadow2Content);
+        var midDiv = createChild(shadow2Content, 'div', 'mid-div');
+        createChild(midDiv, 'div', undefined, 'component2-text');
+        createSlot(midDiv, null);
+        createSlot(midDiv, 'component2-content');
+
+        // Now we have:
+        /*
+        * <div class="component1"></div>
+        * <div class="shadow-component1">
+        *    <slot name="component1-content"></slot>
+        *    <slot></slot>
+        *    <div class="component2">
+        *       <slot name="component2-content"></slot>
+        *       <div class="component2-content" slot="component2-content">component2 light dom text</div>
+        *    </div>
+        * </div>
+        * <div class="shadow-component1">
+        *    <div class="mid-div" slot="mid-div">
+        *       <div>component2-text</div>
+        *       <slot></slot>
+        *       <slot name="component2-content"></slot>
+        *    </div>
+        * </div>
+        */
+
+        let node = component1;
+        assert.equal(node.nodeName, 'DIV', 'root node name is incorrect');
+        assert.equal(node.className, 'component1', 'root node class is incorrect');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeName, '#document-fragment', 'first document fragment node name is incorrect');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeName, 'DIV', 'first document fragment child node name is incorrect');
+        assert.equal(node.className, 'shadow-component1', 'first document fragment child node name is incorrect');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeName, 'SLOT', 'first slot node name is incorrect');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeName, 'SLOT', 'second slot node name is incorrect');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeName, 'DIV');
+        assert.equal(node.className, 'component2');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeName, '#document-fragment');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeName, 'DIV');
+        assert.equal(node.className, 'shadow-component1');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeName, 'DIV');
+        assert.equal(node.className, 'mid-div');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeName, 'DIV');
+        assert.equal(node.className, '');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeValue, 'component2-text');
+        assert.equal(node.nodeName, '#text');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeName, 'SLOT');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeName, 'SLOT');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeName, 'SLOT');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeName, 'DIV');
+        assert.equal(node.className, 'component2-content');
+
+        node = node.traverseNextNode(component1);
+        assert.equal(node.nodeValue, 'component2 light dom text');
+        assert.equal(node.nodeName, '#text');
+    });
+});
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/bluetooth/bluetooth.cc b/third_party/blink/renderer/modules/bluetooth/bluetooth.cc
index bfe0afa..44fb098 100644
--- a/third_party/blink/renderer/modules/bluetooth/bluetooth.cc
+++ b/third_party/blink/renderer/modules/bluetooth/bluetooth.cc
@@ -10,7 +10,7 @@
 #include "mojo/public/cpp/bindings/pending_associated_remote.h"
 #include "mojo/public/cpp/bindings/receiver_set.h"
 #include "mojo/public/cpp/bindings/remote.h"
-#include "services/service_manager/public/cpp/interface_provider.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
 #include "third_party/blink/public/mojom/bluetooth/web_bluetooth.mojom-blink.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
@@ -469,7 +469,7 @@
   if (!service_) {
     // See https://bit.ly/2S0zRAS for task types.
     auto task_runner = context->GetTaskRunner(TaskType::kMiscPlatformAPI);
-    context->GetInterfaceProvider()->GetInterface(
+    context->GetBrowserInterfaceBroker().GetInterface(
         service_.BindNewPipeAndPassReceiver(task_runner));
   }
 }
diff --git a/third_party/blink/renderer/modules/contacts_picker/contacts_manager.cc b/third_party/blink/renderer/modules/contacts_picker/contacts_manager.cc
index 9181ed7..55fcfe49 100644
--- a/third_party/blink/renderer/modules/contacts_picker/contacts_manager.cc
+++ b/third_party/blink/renderer/modules/contacts_picker/contacts_manager.cc
@@ -4,7 +4,7 @@
 
 #include "third_party/blink/renderer/modules/contacts_picker/contacts_manager.h"
 
-#include "services/service_manager/public/cpp/interface_provider.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
@@ -72,8 +72,8 @@
 ContactsManager::GetContactsManager(ScriptState* script_state) {
   if (!contacts_manager_) {
     ExecutionContext::From(script_state)
-        ->GetInterfaceProvider()
-        ->GetInterface(contacts_manager_.BindNewPipeAndPassReceiver());
+        ->GetBrowserInterfaceBroker()
+        .GetInterface(contacts_manager_.BindNewPipeAndPassReceiver());
   }
   return contacts_manager_;
 }
diff --git a/third_party/blink/renderer/modules/content_index/content_index.cc b/third_party/blink/renderer/modules/content_index/content_index.cc
index a8b4d6f7..3e0afe73 100644
--- a/third_party/blink/renderer/modules/content_index/content_index.cc
+++ b/third_party/blink/renderer/modules/content_index/content_index.cc
@@ -5,7 +5,7 @@
 #include "third_party/blink/renderer/modules/content_index/content_index.h"
 
 #include "base/optional.h"
-#include "services/service_manager/public/cpp/interface_provider.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
 #include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
@@ -279,8 +279,10 @@
 
 mojom::blink::ContentIndexService* ContentIndex::GetService() {
   if (!content_index_service_) {
-    registration_->GetExecutionContext()->GetInterfaceProvider()->GetInterface(
-        content_index_service_.BindNewPipeAndPassReceiver(task_runner_));
+    registration_->GetExecutionContext()
+        ->GetBrowserInterfaceBroker()
+        .GetInterface(
+            content_index_service_.BindNewPipeAndPassReceiver(task_runner_));
   }
   return content_index_service_.get();
 }
diff --git a/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc b/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc
index e16b3d83..9fd088b 100644
--- a/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc
+++ b/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc
@@ -167,15 +167,8 @@
   if (asked_to_terminate_)
     return;
   asked_to_terminate_ = true;
-  if (!worker_thread_) {
-    // The worker thread has not been created yet if the worker is asked to
-    // terminate during waiting for debugger.
-    DCHECK_EQ(WebEmbeddedWorkerStartData::kWaitForDebugger,
-              worker_start_data_.wait_for_debugger_mode);
-    // This deletes 'this'.
-    worker_context_client_->WorkerContextFailedToStartOnInitiatorThread();
-    return;
-  }
+  // StartWorkerThread() must be called before.
+  DCHECK(worker_thread_);
   worker_thread_->Terminate();
 }
 
diff --git a/third_party/blink/renderer/modules/hid/hid.cc b/third_party/blink/renderer/modules/hid/hid.cc
index 5168514..dd6d595 100644
--- a/third_party/blink/renderer/modules/hid/hid.cc
+++ b/third_party/blink/renderer/modules/hid/hid.cc
@@ -4,7 +4,7 @@
 
 #include "third_party/blink/renderer/modules/hid/hid.h"
 
-#include "services/service_manager/public/cpp/interface_provider.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
 #include "third_party/blink/public/mojom/feature_policy/feature_policy.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"
@@ -227,7 +227,7 @@
 
   auto task_runner =
       GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI);
-  GetExecutionContext()->GetInterfaceProvider()->GetInterface(
+  GetExecutionContext()->GetBrowserInterfaceBroker().GetInterface(
       service_.BindNewPipeAndPassReceiver(task_runner));
   service_.set_disconnect_handler(
       WTF::Bind(&HID::OnServiceConnectionError, WrapWeakPersistent(this)));
diff --git a/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.cc b/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.cc
index 56ff8283..e278a249 100644
--- a/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.cc
+++ b/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.cc
@@ -896,7 +896,8 @@
     ScriptState::Scope scope(script_state);
     DummyExceptionStateForTesting exception_state;
     IDBRequest* idb_request_get_entries_count = idb_object_store->count(
-        script_state, ScriptValue::CreateNull(script_state), exception_state);
+        script_state, ScriptValue::CreateNull(script_state->GetIsolate()),
+        exception_state);
     DCHECK(!exception_state.HadException());
     if (exception_state.HadException()) {
       ExceptionCode ec = exception_state.Code();
diff --git a/third_party/blink/renderer/modules/mediarecorder/vea_encoder.cc b/third_party/blink/renderer/modules/mediarecorder/vea_encoder.cc
index 8da2d01..38d5b42 100644
--- a/third_party/blink/renderer/modules/mediarecorder/vea_encoder.cc
+++ b/third_party/blink/renderer/modules/mediarecorder/vea_encoder.cc
@@ -41,6 +41,7 @@
     int32_t bits_per_second,
     media::VideoCodecProfile codec,
     const gfx::Size& size,
+    bool use_native_input,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
   auto encoder = base::AdoptRef(
       new VEAEncoder(on_encoded_video_callback, on_error_callback,
@@ -48,7 +49,7 @@
   PostCrossThreadTask(
       *encoder->encoding_task_runner_.get(), FROM_HERE,
       CrossThreadBindOnce(&VEAEncoder::ConfigureEncoderOnEncodingTaskRunner,
-                          encoder, size));
+                          encoder, size, use_native_input));
   return encoder;
 }
 
@@ -186,8 +187,12 @@
   if (input_visible_size_ != frame->visible_rect().size() && video_encoder_)
     video_encoder_.reset();
 
-  if (!video_encoder_)
-    ConfigureEncoderOnEncodingTaskRunner(frame->visible_rect().size());
+  if (!video_encoder_) {
+    bool use_native_input =
+        frame->storage_type() == media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER;
+    ConfigureEncoderOnEncodingTaskRunner(frame->visible_rect().size(),
+                                         use_native_input);
+  }
 
   if (error_notified_) {
     DVLOG(3) << "An error occurred in VEA encoder";
@@ -214,13 +219,16 @@
   // Therefore, a copy is necessary to release the current frame.
   // Only STORAGE_SHMEM backed frames can be shared with GPU process, therefore
   // a copy is required for other storage types.
+  // With STORAGE_GPU_MEMORY_BUFFER we delay the scaling of the frame to the end
+  // of the encoding pipeline.
   scoped_refptr<media::VideoFrame> video_frame = frame;
   bool can_share_frame =
       (video_frame->storage_type() == media::VideoFrame::STORAGE_SHMEM);
-  if (!can_share_frame ||
-      vea_requested_input_coded_size_ != frame->coded_size() ||
-      input_visible_size_.width() < kVEAEncoderMinResolutionWidth ||
-      input_visible_size_.height() < kVEAEncoderMinResolutionHeight) {
+  if (frame->storage_type() != media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER &&
+      (!can_share_frame ||
+       vea_requested_input_coded_size_ != frame->coded_size() ||
+       input_visible_size_.width() < kVEAEncoderMinResolutionWidth ||
+       input_visible_size_.height() < kVEAEncoderMinResolutionHeight)) {
     // Create SharedMemory backed input buffers as necessary. These SharedMemory
     // instances will be shared with GPU process.
     const size_t desired_mapped_size = media::VideoFrame::AllocationSize(
@@ -274,7 +282,8 @@
   force_next_frame_to_be_keyframe_ = false;
 }
 
-void VEAEncoder::ConfigureEncoderOnEncodingTaskRunner(const gfx::Size& size) {
+void VEAEncoder::ConfigureEncoderOnEncodingTaskRunner(const gfx::Size& size,
+                                                      bool use_native_input) {
   DVLOG(3) << __func__;
   DCHECK(encoding_task_runner_->BelongsToCurrentThread());
   DCHECK(gpu_factories_->GetTaskRunner()->BelongsToCurrentThread());
@@ -283,8 +292,20 @@
   input_visible_size_ = size;
   vea_requested_input_coded_size_ = gfx::Size();
   video_encoder_ = gpu_factories_->CreateVideoEncodeAccelerator();
+
+  auto pixel_format = media::VideoPixelFormat::PIXEL_FORMAT_I420;
+  auto storage_type =
+      media::VideoEncodeAccelerator::Config::StorageType::kShmem;
+  if (use_native_input) {
+    // Currently the VAAPI and V4L2 VEA support only native input mode with NV12
+    // DMA-buf buffers.
+    pixel_format = media::PIXEL_FORMAT_NV12;
+    storage_type = media::VideoEncodeAccelerator::Config::StorageType::kDmabuf;
+  }
   const media::VideoEncodeAccelerator::Config config(
-      media::PIXEL_FORMAT_I420, input_visible_size_, codec_, bits_per_second_);
+      pixel_format, input_visible_size_, codec_, bits_per_second_,
+      base::nullopt, base::nullopt, base::nullopt, storage_type,
+      media::VideoEncodeAccelerator::Config::ContentType::kCamera);
   if (!video_encoder_ || !video_encoder_->Initialize(config, this))
     NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
 }
diff --git a/third_party/blink/renderer/modules/mediarecorder/vea_encoder.h b/third_party/blink/renderer/modules/mediarecorder/vea_encoder.h
index 743ebe0..e7f63b7 100644
--- a/third_party/blink/renderer/modules/mediarecorder/vea_encoder.h
+++ b/third_party/blink/renderer/modules/mediarecorder/vea_encoder.h
@@ -35,6 +35,7 @@
       int32_t bits_per_second,
       media::VideoCodecProfile codec,
       const gfx::Size& size,
+      bool use_native_input,
       scoped_refptr<base::SingleThreadTaskRunner> task_runner);
 
   // media::VideoEncodeAccelerator::Client implementation.
@@ -73,7 +74,8 @@
   void EncodeOnEncodingTaskRunner(scoped_refptr<media::VideoFrame> frame,
                                   base::TimeTicks capture_timestamp) override;
 
-  void ConfigureEncoderOnEncodingTaskRunner(const gfx::Size& size);
+  void ConfigureEncoderOnEncodingTaskRunner(const gfx::Size& size,
+                                            bool use_native_input);
 
   void DestroyOnEncodingTaskRunner(base::WaitableEvent* async_waiter = nullptr);
 
diff --git a/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc b/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
index c84797f9..69e9535 100644
--- a/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
+++ b/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
@@ -243,7 +243,9 @@
     return;
   }
 
-  if (video_frame->HasTextures()) {
+  if (video_frame->HasTextures() &&
+      video_frame->storage_type() !=
+          media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER) {
     PostCrossThreadTask(
         *main_task_runner_.get(), FROM_HERE,
         CrossThreadBindOnce(&Encoder::RetrieveFrameOnMainThread,
@@ -253,28 +255,29 @@
     return;
   }
 
-  scoped_refptr<media::VideoFrame> wrapped_frame;
-  // Drop alpha channel if the encoder does not support it yet.
-  if (!CanEncodeAlphaChannel() &&
-      video_frame->format() == media::PIXEL_FORMAT_I420A) {
-    wrapped_frame = media::WrapAsI420VideoFrame(video_frame);
-  } else {
-    wrapped_frame = media::VideoFrame::WrapVideoFrame(
-        *video_frame, video_frame->format(), video_frame->visible_rect(),
-        video_frame->natural_size());
+  scoped_refptr<media::VideoFrame> frame = video_frame;
+  if (frame->storage_type() != media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER) {
+    // Drop alpha channel if the encoder does not support it yet.
+    if (!CanEncodeAlphaChannel() &&
+        video_frame->format() == media::PIXEL_FORMAT_I420A) {
+      frame = media::WrapAsI420VideoFrame(video_frame);
+    } else {
+      frame = media::VideoFrame::WrapVideoFrame(
+          *video_frame, video_frame->format(), video_frame->visible_rect(),
+          video_frame->natural_size());
+    }
+    frame->AddDestructionObserver(ConvertToBaseOnceCallback(CrossThreadBindOnce(
+        [](scoped_refptr<VideoFrame> video_frame) {}, std::move(video_frame))));
   }
-  wrapped_frame->AddDestructionObserver(media::BindToCurrentLoop(
+  frame->AddDestructionObserver(media::BindToCurrentLoop(
       WTF::Bind(&VideoTrackRecorder::Counter::DecreaseCount,
                 num_frames_in_encode_->GetWeakPtr())));
-  wrapped_frame->AddDestructionObserver(ConvertToBaseOnceCallback(
-      CrossThreadBindOnce([](scoped_refptr<VideoFrame> video_frame) {},
-                          std::move(video_frame))));
   num_frames_in_encode_->IncreaseCount();
 
-  PostCrossThreadTask(*encoding_task_runner_.get(), FROM_HERE,
-                      CrossThreadBindOnce(&Encoder::EncodeOnEncodingTaskRunner,
-                                          WrapRefCounted(this), wrapped_frame,
-                                          capture_timestamp));
+  PostCrossThreadTask(
+      *encoding_task_runner_.get(), FROM_HERE,
+      CrossThreadBindOnce(&Encoder::EncodeOnEncodingTaskRunner,
+                          WrapRefCounted(this), frame, capture_timestamp));
 }
 
 void VideoTrackRecorder::Encoder::RetrieveFrameOnMainThread(
@@ -505,11 +508,14 @@
     UMA_HISTOGRAM_BOOLEAN("Media.MediaRecorder.VEAUsed", true);
     const auto vea_profile =
         GetCodecEnumerator()->GetFirstSupportedVideoCodecProfile(codec);
+    bool use_import_mode =
+        frame->storage_type() == media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER;
     encoder_ = VEAEncoder::Create(
         on_encoded_video_callback,
         media::BindToCurrentLoop(WTF::BindRepeating(
             &VideoTrackRecorder::OnError, WrapWeakPersistent(this))),
-        bits_per_second, vea_profile, input_size, main_task_runner_);
+        bits_per_second, vea_profile, input_size, use_import_mode,
+        main_task_runner_);
   } else {
     UMA_HISTOGRAM_BOOLEAN("Media.MediaRecorder.VEAUsed", false);
     switch (codec) {
diff --git a/third_party/blink/renderer/modules/nfc/ndef_record.cc b/third_party/blink/renderer/modules/nfc/ndef_record.cc
index a4cedf4..4b2f74c 100644
--- a/third_party/blink/renderer/modules/nfc/ndef_record.cc
+++ b/third_party/blink/renderer/modules/nfc/ndef_record.cc
@@ -238,7 +238,7 @@
 ScriptValue NDEFRecord::toJSON(ScriptState* script_state,
                                ExceptionState& exception_state) const {
   if (record_type_ != "json" && record_type_ != "opaque") {
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 
   ScriptState::Scope scope(script_state);
@@ -247,7 +247,7 @@
       String::FromUTF8WithLatin1Fallback(data_.data(), data_.size()),
       exception_state);
   if (exception_state.HadException())
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   return ScriptValue(script_state, json_object);
 }
 
diff --git a/third_party/blink/renderer/modules/payments/payment_method_change_event.cc b/third_party/blink/renderer/modules/payments/payment_method_change_event.cc
index 1a3b8e6..633b3c7 100644
--- a/third_party/blink/renderer/modules/payments/payment_method_change_event.cc
+++ b/third_party/blink/renderer/modules/payments/payment_method_change_event.cc
@@ -28,7 +28,7 @@
 const ScriptValue PaymentMethodChangeEvent::methodDetails(
     ScriptState* script_state) const {
   if (method_details_.IsEmpty())
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   return ScriptValue(script_state,
                      method_details_.GetAcrossWorld(script_state));
 }
diff --git a/third_party/blink/renderer/modules/payments/payment_request_event.cc b/third_party/blink/renderer/modules/payments/payment_request_event.cc
index af4854a..d189e77 100644
--- a/third_party/blink/renderer/modules/payments/payment_request_event.cc
+++ b/third_party/blink/renderer/modules/payments/payment_request_event.cc
@@ -115,7 +115,7 @@
 const ScriptValue PaymentRequestEvent::paymentOptions(
     ScriptState* script_state) const {
   if (!payment_options_)
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   return ScriptValue::From(script_state, payment_options_);
 }
 
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_data_channel_test.cc b/third_party/blink/renderer/modules/peerconnection/rtc_data_channel_test.cc
index b0c1661..c7a6438 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_data_channel_test.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_data_channel_test.cc
@@ -10,6 +10,7 @@
 
 #include "base/memory/ptr_util.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/run_loop.h"
 #include "base/test/test_simple_task_runner.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
diff --git a/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc b/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc
index 90bc453..ed2e17c 100644
--- a/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc
+++ b/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc
@@ -30,6 +30,7 @@
 #include "third_party/blink/public/web/web_settings.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_error.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
 #include "third_party/blink/renderer/platform/scheduler/test/fake_task_runner.h"
 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
 #include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
@@ -124,7 +125,6 @@
   MOCK_METHOD2(WorkerReadyForInspectionOnInitiatorThread,
                void(mojo::ScopedMessagePipeHandle,
                     mojo::ScopedMessagePipeHandle));
-  MOCK_METHOD0(WorkerContextFailedToStartOnInitiatorThread, void());
 
   void WorkerContextStarted(WebServiceWorkerContextProxy* proxy,
                             scoped_refptr<base::SequencedTaskRunner>) override {
diff --git a/third_party/blink/renderer/modules/wake_lock/wake_lock_test_utils.cc b/third_party/blink/renderer/modules/wake_lock/wake_lock_test_utils.cc
index 35274834..b0099b16 100644
--- a/third_party/blink/renderer/modules/wake_lock/wake_lock_test_utils.cc
+++ b/third_party/blink/renderer/modules/wake_lock/wake_lock_test_utils.cc
@@ -315,8 +315,7 @@
   if (v8_promise->State() == v8::Promise::kPending) {
     return g_empty_string;
   }
-  ScriptValue promise_result(promise.GetScriptValue().GetScriptState(),
-                             v8_promise->Result());
+  ScriptValue promise_result(promise.GetIsolate(), v8_promise->Result());
   String value;
   if (!promise_result.ToString(value)) {
     return g_empty_string;
diff --git a/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query.cc b/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query.cc
index c671a2a..aa45e44 100644
--- a/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query.cc
+++ b/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query.cc
@@ -143,7 +143,7 @@
                                                GLenum pname) {
   WebGLExtensionScopedContext scoped(this);
   if (scoped.IsLost())
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
 
   if (pname == GL_QUERY_COUNTER_BITS_EXT) {
     if (target == GL_TIMESTAMP_EXT || target == GL_TIME_ELAPSED_EXT) {
@@ -153,22 +153,22 @@
     }
     scoped.Context()->SynthesizeGLError(GL_INVALID_ENUM, "getQuery",
                                         "invalid target/pname combination");
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 
   if (target == GL_TIME_ELAPSED_EXT && pname == GL_CURRENT_QUERY) {
     return current_elapsed_query_
                ? WebGLAny(script_state, current_elapsed_query_)
-               : ScriptValue::CreateNull(script_state);
+               : ScriptValue::CreateNull(script_state->GetIsolate());
   }
 
   if (target == GL_TIMESTAMP_EXT && pname == GL_CURRENT_QUERY) {
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 
   scoped.Context()->SynthesizeGLError(GL_INVALID_ENUM, "getQuery",
                                       "invalid target/pname combination");
-  return ScriptValue::CreateNull(script_state);
+  return ScriptValue::CreateNull(script_state->GetIsolate());
 }
 
 ScriptValue EXTDisjointTimerQuery::getQueryObjectEXT(ScriptState* script_state,
@@ -176,15 +176,15 @@
                                                      GLenum pname) {
   WebGLExtensionScopedContext scoped(this);
   if (scoped.IsLost())
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
 
   if (!scoped.Context()->ValidateWebGLObject("getQueryObjectEXT", query))
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
 
   if (current_elapsed_query_ == query) {
     scoped.Context()->SynthesizeGLError(
         GL_INVALID_OPERATION, "getQueryObjectEXT", "query is currently active");
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 
   switch (pname) {
@@ -202,7 +202,7 @@
       break;
   }
 
-  return ScriptValue::CreateNull(script_state);
+  return ScriptValue::CreateNull(script_state->GetIsolate());
 }
 
 void EXTDisjointTimerQuery::Trace(blink::Visitor* visitor) {
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.cc
index f6533df..0e4c2a1 100644
--- a/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.cc
@@ -75,15 +75,15 @@
     GLenum program_interface,
     GLenum pname) {
   if (!ValidateWebGLProgramOrShader("getProgramInterfaceParameter", program))
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   if (!ValidateProgramInterface(
       "getProgramInterfaceParameter", program_interface))
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   if (program_interface == GL_ATOMIC_COUNTER_BUFFER &&
       pname == GL_MAX_NAME_LENGTH) {
     SynthesizeGLError(GL_INVALID_OPERATION, "getProgramInterfaceParameter",
                       "atomic counter resources are not assigned name strings");
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   }
   if (program_interface != GL_ATOMIC_COUNTER_BUFFER &&
       program_interface != GL_SHADER_STORAGE_BLOCK &&
@@ -92,7 +92,7 @@
     SynthesizeGLError(
         GL_INVALID_OPERATION, "getProgramInterfaceParameter",
         "invalid parameter name for the specified program interface");
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 
   switch (pname) {
@@ -107,7 +107,7 @@
     default:
       SynthesizeGLError(GL_INVALID_ENUM, "getProgramInterfaceParameter",
                         "invalid parameter name");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 }
 
@@ -346,7 +346,7 @@
     ScriptState* script_state,
     GLenum pname) {
   if (isContextLost())
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   switch (pname) {
     case GL_SHADING_LANGUAGE_VERSION: {
       return WebGLAny(
@@ -397,14 +397,14 @@
     GLenum target,
     GLuint index) {
   if (isContextLost())
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
 
   switch (target) {
     case GL_ATOMIC_COUNTER_BUFFER_BINDING:
       if (index >= bound_indexed_atomic_counter_buffers_.size()) {
         SynthesizeGLError(GL_INVALID_VALUE, "getIndexedParameter",
                           "index out of range");
-        return ScriptValue::CreateNull(script_state);
+        return ScriptValue::CreateNull(script_state->GetIsolate());
       }
       return WebGLAny(script_state,
                       bound_indexed_atomic_counter_buffers_[index].Get());
@@ -412,7 +412,7 @@
       if (index >= bound_indexed_shader_storage_buffers_.size()) {
         SynthesizeGLError(GL_INVALID_VALUE, "getIndexedParameter",
                           "index out of range");
-        return ScriptValue::CreateNull(script_state);
+        return ScriptValue::CreateNull(script_state->GetIsolate());
       }
       return WebGLAny(script_state,
                       bound_indexed_shader_storage_buffers_[index].Get());
@@ -620,7 +620,7 @@
     }
     case GL_UNIFORM: {
       if (location == -1)
-        return ScriptValue::CreateNull(script_state);
+        return ScriptValue::CreateNull(script_state->GetIsolate());
       DCHECK_GE(location, 0);
       WebGLUniformLocation* uniform_location =
           WebGLUniformLocation::Create(program, location);
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
index 309a458..04915cb 100644
--- a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
@@ -487,12 +487,12 @@
     GLenum internalformat,
     GLenum pname) {
   if (isContextLost())
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
 
   if (target != GL_RENDERBUFFER) {
     SynthesizeGLError(GL_INVALID_ENUM, "getInternalformatParameter",
                       "invalid target");
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 
   switch (internalformat) {
@@ -549,13 +549,13 @@
         SynthesizeGLError(GL_INVALID_ENUM, "getInternalformatParameter",
                           "invalid internalformat when EXT_color_buffer_float "
                           "is not enabled");
-        return ScriptValue::CreateNull(script_state);
+        return ScriptValue::CreateNull(script_state->GetIsolate());
       }
       break;
     default:
       SynthesizeGLError(GL_INVALID_ENUM, "getInternalformatParameter",
                         "invalid internalformat");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 
   switch (pname) {
@@ -577,7 +577,7 @@
     default:
       SynthesizeGLError(GL_INVALID_ENUM, "getInternalformatParameter",
                         "invalid parameter name");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 }
 
@@ -3935,7 +3935,7 @@
                                                  GLenum target,
                                                  GLenum pname) {
   if (isContextLost())
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
 
   if (ExtensionEnabled(kEXTDisjointTimerQueryWebGL2Name)) {
     if (pname == GL_QUERY_COUNTER_BITS_EXT) {
@@ -3946,23 +3946,23 @@
       }
       SynthesizeGLError(GL_INVALID_ENUM, "getQuery",
                         "invalid target/pname combination");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
     }
 
     if (target == GL_TIME_ELAPSED_EXT && pname == GL_CURRENT_QUERY) {
       return current_elapsed_query_
                  ? WebGLAny(script_state, current_elapsed_query_)
-                 : ScriptValue::CreateNull(script_state);
+                 : ScriptValue::CreateNull(script_state->GetIsolate());
     }
 
     if (target == GL_TIMESTAMP_EXT && pname == GL_CURRENT_QUERY) {
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
     }
   }
 
   if (pname != GL_CURRENT_QUERY) {
     SynthesizeGLError(GL_INVALID_ENUM, "getQuery", "invalid parameter name");
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 
   switch (target) {
@@ -3977,9 +3977,9 @@
                       current_transform_feedback_primitives_written_query_);
     default:
       SynthesizeGLError(GL_INVALID_ENUM, "getQuery", "invalid target");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
   }
-  return ScriptValue::CreateNull(script_state);
+  return ScriptValue::CreateNull(script_state->GetIsolate());
 }
 
 ScriptValue WebGL2RenderingContextBase::getQueryParameter(
@@ -3987,21 +3987,21 @@
     WebGLQuery* query,
     GLenum pname) {
   if (!ValidateWebGLObject("getQueryParameter", query))
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
 
   // Query is non-null at this point.
   if (!query->GetTarget()) {
     SynthesizeGLError(GL_INVALID_OPERATION, "getQueryParameter",
                       "'query' is not a query object yet, since it has't been "
                       "used by beginQuery");
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   }
   if (query == current_boolean_occlusion_query_ ||
       query == current_transform_feedback_primitives_written_query_ ||
       query == current_elapsed_query_) {
     SynthesizeGLError(GL_INVALID_OPERATION, "getQueryParameter",
                       "query is currently active");
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 
   switch (pname) {
@@ -4016,7 +4016,7 @@
     default:
       SynthesizeGLError(GL_INVALID_ENUM, "getQueryParameter",
                         "invalid parameter name");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 }
 
@@ -4189,7 +4189,7 @@
     WebGLSampler* sampler,
     GLenum pname) {
   if (!ValidateWebGLObject("getSamplerParameter", sampler))
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
 
   switch (pname) {
     case GL_TEXTURE_COMPARE_FUNC:
@@ -4213,7 +4213,7 @@
       if (!ExtensionEnabled(kEXTTextureFilterAnisotropicName)) {
         SynthesizeGLError(GL_INVALID_ENUM, "samplerParameter",
                           "EXT_texture_filter_anisotropic not enabled");
-        return ScriptValue::CreateNull(script_state);
+        return ScriptValue::CreateNull(script_state->GetIsolate());
       }
       GLfloat value = 0.f;
       ContextGL()->GetSamplerParameterfv(ObjectOrZero(sampler), pname, &value);
@@ -4222,7 +4222,7 @@
     default:
       SynthesizeGLError(GL_INVALID_ENUM, "getSamplerParameter",
                         "invalid parameter name");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 }
 
@@ -4314,7 +4314,7 @@
     WebGLSync* sync,
     GLenum pname) {
   if (!ValidateWebGLObject("getSyncParameter", sync))
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
 
   switch (pname) {
     case GL_OBJECT_TYPE:
@@ -4327,7 +4327,7 @@
     default:
       SynthesizeGLError(GL_INVALID_ENUM, "getSyncParameter",
                         "invalid parameter name");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 }
 
@@ -4661,7 +4661,7 @@
     GLenum target,
     GLuint index) {
   if (isContextLost())
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
 
   switch (target) {
     case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: {
@@ -4670,7 +4670,7 @@
               index, &buffer)) {
         SynthesizeGLError(GL_INVALID_VALUE, "getIndexedParameter",
                           "index out of range");
-        return ScriptValue::CreateNull(script_state);
+        return ScriptValue::CreateNull(script_state->GetIsolate());
       }
       return WebGLAny(script_state, buffer);
     }
@@ -4678,7 +4678,7 @@
       if (index >= bound_indexed_uniform_buffers_.size()) {
         SynthesizeGLError(GL_INVALID_VALUE, "getIndexedParameter",
                           "index out of range");
-        return ScriptValue::CreateNull(script_state);
+        return ScriptValue::CreateNull(script_state->GetIsolate());
       }
       return WebGLAny(script_state,
                       bound_indexed_uniform_buffers_[index].Get());
@@ -4693,7 +4693,7 @@
     default:
       SynthesizeGLError(GL_INVALID_ENUM, "getIndexedParameter",
                         "invalid parameter name");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 }
 
@@ -4718,7 +4718,7 @@
     const Vector<GLuint>& uniform_indices,
     GLenum pname) {
   if (!ValidateWebGLProgramOrShader("getActiveUniforms", program))
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
 
   enum ReturnType { kEnumType, kUnsignedIntType, kIntType, kBoolType };
 
@@ -4742,7 +4742,7 @@
     default:
       SynthesizeGLError(GL_INVALID_ENUM, "getActiveUniforms",
                         "invalid parameter name");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 
   GLint active_uniforms = -1;
@@ -4755,7 +4755,7 @@
     if (index >= active_uniforms_unsigned) {
       SynthesizeGLError(GL_INVALID_VALUE, "getActiveUniforms",
                         "uniform index greater than ACTIVE_UNIFORMS");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
     }
   }
 
@@ -4787,7 +4787,7 @@
     }
     default:
       NOTREACHED();
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 }
 
@@ -4830,11 +4830,11 @@
     GLuint uniform_block_index,
     GLenum pname) {
   if (!ValidateWebGLProgramOrShader("getActiveUniformBlockParameter", program))
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
 
   if (!ValidateUniformBlockIndex("getActiveUniformBlockParameter", program,
                                  uniform_block_index))
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
 
   switch (pname) {
     case GL_UNIFORM_BLOCK_BINDING:
@@ -4869,7 +4869,7 @@
     default:
       SynthesizeGLError(GL_INVALID_ENUM, "getActiveUniformBlockParameter",
                         "invalid parameter name");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 }
 
@@ -5033,7 +5033,7 @@
 ScriptValue WebGL2RenderingContextBase::getParameter(ScriptState* script_state,
                                                      GLenum pname) {
   if (isContextLost())
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   switch (pname) {
     case GL_SHADING_LANGUAGE_VERSION: {
       return WebGLAny(
@@ -5155,7 +5155,7 @@
       if (!transform_feedback_binding_->IsDefaultObject()) {
         return WebGLAny(script_state, transform_feedback_binding_.Get());
       }
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
     case GL_TRANSFORM_FEEDBACK_PAUSED:
       return GetBooleanParameter(script_state, pname);
     case GL_UNIFORM_BUFFER_BINDING:
@@ -5179,7 +5179,7 @@
       SynthesizeGLError(GL_INVALID_ENUM, "getParameter",
                         "invalid parameter name, "
                         "EXT_disjoint_timer_query_webgl2 not enabled");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
     case GL_GPU_DISJOINT_EXT:
       if (ExtensionEnabled(kEXTDisjointTimerQueryWebGL2Name)) {
         return GetBooleanParameter(script_state, GL_GPU_DISJOINT_EXT);
@@ -5187,7 +5187,7 @@
       SynthesizeGLError(GL_INVALID_ENUM, "getParameter",
                         "invalid parameter name, "
                         "EXT_disjoint_timer_query_webgl2 not enabled");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
 
     default:
       return WebGLRenderingContextBase::getParameter(script_state, pname);
@@ -5574,7 +5574,7 @@
   const char kFunctionName[] = "getFramebufferAttachmentParameter";
   if (isContextLost() || !ValidateGetFramebufferAttachmentParameterFunc(
                              kFunctionName, target, attachment))
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
 
   WebGLFramebuffer* framebuffer_binding = GetFramebufferBinding(target);
   DCHECK(!framebuffer_binding || framebuffer_binding->Object());
@@ -5595,7 +5595,7 @@
         default:
           SynthesizeGLError(GL_INVALID_OPERATION, kFunctionName,
                             "invalid parameter name");
-          return ScriptValue::CreateNull(script_state);
+          return ScriptValue::CreateNull(script_state->GetIsolate());
       }
     }
     switch (pname) {
@@ -5629,17 +5629,17 @@
           return WebGLAny(script_state, 0);
         SynthesizeGLError(GL_INVALID_ENUM, kFunctionName,
                           "invalid parameter name, OVR_multiview2 not enabled");
-        return ScriptValue::CreateNull(script_state);
+        return ScriptValue::CreateNull(script_state->GetIsolate());
       case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR:
         if (ExtensionEnabled(kOVRMultiview2Name))
           return WebGLAny(script_state, 0);
         SynthesizeGLError(GL_INVALID_ENUM, kFunctionName,
                           "invalid parameter name, OVR_multiview2 not enabled");
-        return ScriptValue::CreateNull(script_state);
+        return ScriptValue::CreateNull(script_state->GetIsolate());
       default:
         SynthesizeGLError(GL_INVALID_ENUM, kFunctionName,
                           "invalid parameter name");
-        return ScriptValue::CreateNull(script_state);
+        return ScriptValue::CreateNull(script_state->GetIsolate());
     }
   }
 
@@ -5653,7 +5653,7 @@
       SynthesizeGLError(
           GL_INVALID_OPERATION, kFunctionName,
           "different objects bound to DEPTH_ATTACHMENT and STENCIL_ATTACHMENT");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
     }
     attachment_object = depth_attachment;
   } else {
@@ -5665,11 +5665,11 @@
       case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
         return WebGLAny(script_state, GL_NONE);
       case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
-        return ScriptValue::CreateNull(script_state);
+        return ScriptValue::CreateNull(script_state->GetIsolate());
       default:
         SynthesizeGLError(GL_INVALID_OPERATION, kFunctionName,
                           "invalid parameter name");
-        return ScriptValue::CreateNull(script_state);
+        return ScriptValue::CreateNull(script_state->GetIsolate());
     }
   }
   DCHECK(attachment_object->IsTexture() || attachment_object->IsRenderbuffer());
@@ -5703,7 +5703,7 @@
         SynthesizeGLError(
             GL_INVALID_OPERATION, kFunctionName,
             "COMPONENT_TYPE can't be queried for DEPTH_STENCIL_ATTACHMENT");
-        return ScriptValue::CreateNull(script_state);
+        return ScriptValue::CreateNull(script_state->GetIsolate());
       }
       FALLTHROUGH;
     case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: {
@@ -5717,7 +5717,7 @@
       if (!ExtensionEnabled(kOVRMultiview2Name)) {
         SynthesizeGLError(GL_INVALID_ENUM, kFunctionName,
                           "invalid parameter name, OVR_multiview2 not enabled");
-        return ScriptValue::CreateNull(script_state);
+        return ScriptValue::CreateNull(script_state->GetIsolate());
       }
       GLint value = 0;
       ContextGL()->GetFramebufferAttachmentParameteriv(target, attachment,
@@ -5728,7 +5728,7 @@
       break;
   }
   SynthesizeGLError(GL_INVALID_ENUM, kFunctionName, "invalid parameter name");
-  return ScriptValue::CreateNull(script_state);
+  return ScriptValue::CreateNull(script_state->GetIsolate());
 }
 
 void WebGL2RenderingContextBase::Trace(blink::Visitor* visitor) {
@@ -5786,7 +5786,7 @@
     GLenum target,
     GLenum pname) {
   if (isContextLost() || !ValidateTextureBinding("getTexParameter", target))
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
 
   switch (pname) {
     case GL_TEXTURE_WRAP_R:
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
index 2acb5bf..2eea4dd 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -2916,7 +2916,7 @@
     GLenum target,
     GLenum pname) {
   if (isContextLost() || !ValidateBufferTarget("getBufferParameter", target))
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
 
   switch (pname) {
     case GL_BUFFER_USAGE: {
@@ -2934,7 +2934,7 @@
     default:
       SynthesizeGLError(GL_INVALID_ENUM, "getBufferParameter",
                         "invalid parameter name");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 }
 
@@ -3049,18 +3049,18 @@
   if (isContextLost() ||
       !ValidateFramebufferFuncParameters("getFramebufferAttachmentParameter",
                                          target, attachment))
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
 
   if (!framebuffer_binding_ || !framebuffer_binding_->Object()) {
     SynthesizeGLError(GL_INVALID_OPERATION, "getFramebufferAttachmentParameter",
                       "no framebuffer bound");
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 
   if (framebuffer_binding_ && framebuffer_binding_->Opaque()) {
     SynthesizeGLError(GL_INVALID_OPERATION, "getFramebufferAttachmentParameter",
                       "cannot query parameters of an opaque framebuffer");
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 
   WebGLSharedObject* attachment_object =
@@ -3072,7 +3072,7 @@
     // specifies INVALID_OPERATION.
     SynthesizeGLError(GL_INVALID_ENUM, "getFramebufferAttachmentParameter",
                       "invalid parameter name");
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 
   DCHECK(attachment_object->IsTexture() || attachment_object->IsRenderbuffer());
@@ -3098,11 +3098,11 @@
         }
         SynthesizeGLError(GL_INVALID_ENUM, "getFramebufferAttachmentParameter",
                           "invalid parameter name for renderbuffer attachment");
-        return ScriptValue::CreateNull(script_state);
+        return ScriptValue::CreateNull(script_state->GetIsolate());
       default:
         SynthesizeGLError(GL_INVALID_ENUM, "getFramebufferAttachmentParameter",
                           "invalid parameter name for texture attachment");
-        return ScriptValue::CreateNull(script_state);
+        return ScriptValue::CreateNull(script_state->GetIsolate());
     }
   } else {
     switch (pname) {
@@ -3119,11 +3119,11 @@
         }
         SynthesizeGLError(GL_INVALID_ENUM, "getFramebufferAttachmentParameter",
                           "invalid parameter name for renderbuffer attachment");
-        return ScriptValue::CreateNull(script_state);
+        return ScriptValue::CreateNull(script_state->GetIsolate());
       default:
         SynthesizeGLError(GL_INVALID_ENUM, "getFramebufferAttachmentParameter",
                           "invalid parameter name for renderbuffer attachment");
-        return ScriptValue::CreateNull(script_state);
+        return ScriptValue::CreateNull(script_state->GetIsolate());
     }
   }
 }
@@ -3131,7 +3131,7 @@
 ScriptValue WebGLRenderingContextBase::getParameter(ScriptState* script_state,
                                                     GLenum pname) {
   if (isContextLost())
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   const int kIntZero = 0;
   switch (pname) {
     case GL_ACTIVE_TEXTURE:
@@ -3341,7 +3341,7 @@
       SynthesizeGLError(
           GL_INVALID_ENUM, "getParameter",
           "invalid parameter name, OES_standard_derivatives not enabled");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
     case WebGLDebugRendererInfo::kUnmaskedRendererWebgl:
       if (ExtensionEnabled(kWebGLDebugRendererInfoName))
         return WebGLAny(script_state,
@@ -3349,7 +3349,7 @@
       SynthesizeGLError(
           GL_INVALID_ENUM, "getParameter",
           "invalid parameter name, WEBGL_debug_renderer_info not enabled");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
     case WebGLDebugRendererInfo::kUnmaskedVendorWebgl:
       if (ExtensionEnabled(kWebGLDebugRendererInfoName))
         return WebGLAny(script_state,
@@ -3357,17 +3357,17 @@
       SynthesizeGLError(
           GL_INVALID_ENUM, "getParameter",
           "invalid parameter name, WEBGL_debug_renderer_info not enabled");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
     case GL_VERTEX_ARRAY_BINDING_OES:  // OES_vertex_array_object
       if (ExtensionEnabled(kOESVertexArrayObjectName) || IsWebGL2OrHigher()) {
         if (!bound_vertex_array_object_->IsDefaultObject())
           return WebGLAny(script_state, bound_vertex_array_object_.Get());
-        return ScriptValue::CreateNull(script_state);
+        return ScriptValue::CreateNull(script_state->GetIsolate());
       }
       SynthesizeGLError(
           GL_INVALID_ENUM, "getParameter",
           "invalid parameter name, OES_vertex_array_object not enabled");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
     case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT:  // EXT_texture_filter_anisotropic
       if (ExtensionEnabled(kEXTTextureFilterAnisotropicName)) {
         return GetFloatParameter(script_state,
@@ -3376,41 +3376,41 @@
       SynthesizeGLError(
           GL_INVALID_ENUM, "getParameter",
           "invalid parameter name, EXT_texture_filter_anisotropic not enabled");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
     case GL_MAX_COLOR_ATTACHMENTS_EXT:  // EXT_draw_buffers BEGIN
       if (ExtensionEnabled(kWebGLDrawBuffersName) || IsWebGL2OrHigher())
         return WebGLAny(script_state, MaxColorAttachments());
       SynthesizeGLError(
           GL_INVALID_ENUM, "getParameter",
           "invalid parameter name, WEBGL_draw_buffers not enabled");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
     case GL_MAX_DRAW_BUFFERS_EXT:
       if (ExtensionEnabled(kWebGLDrawBuffersName) || IsWebGL2OrHigher())
         return WebGLAny(script_state, MaxDrawBuffers());
       SynthesizeGLError(
           GL_INVALID_ENUM, "getParameter",
           "invalid parameter name, WEBGL_draw_buffers not enabled");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
     case GL_TIMESTAMP_EXT:
       if (ExtensionEnabled(kEXTDisjointTimerQueryName))
         return WebGLAny(script_state, 0);
       SynthesizeGLError(
           GL_INVALID_ENUM, "getParameter",
           "invalid parameter name, EXT_disjoint_timer_query not enabled");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
     case GL_GPU_DISJOINT_EXT:
       if (ExtensionEnabled(kEXTDisjointTimerQueryName))
         return GetBooleanParameter(script_state, GL_GPU_DISJOINT_EXT);
       SynthesizeGLError(
           GL_INVALID_ENUM, "getParameter",
           "invalid parameter name, EXT_disjoint_timer_query not enabled");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
     case GL_MAX_VIEWS_OVR:
       if (ExtensionEnabled(kOVRMultiview2Name))
         return GetIntParameter(script_state, pname);
       SynthesizeGLError(GL_INVALID_ENUM, "getParameter",
                         "invalid parameter name, OVR_multiview2 not enabled");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
     default:
       if ((ExtensionEnabled(kWebGLDrawBuffersName) || IsWebGL2OrHigher()) &&
           pname >= GL_DRAW_BUFFER0_EXT &&
@@ -3424,7 +3424,7 @@
       }
       SynthesizeGLError(GL_INVALID_ENUM, "getParameter",
                         "invalid parameter name");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 }
 
@@ -3433,7 +3433,7 @@
     WebGLProgram* program,
     GLenum pname) {
   if (!ValidateWebGLProgramOrShader("getProgramParamter", program)) {
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 
   GLint value = 0;
@@ -3449,7 +3449,7 @@
       if (!ExtensionEnabled(kKHRParallelShaderCompileName)) {
         SynthesizeGLError(GL_INVALID_ENUM, "getProgramParameter",
                           "invalid parameter name");
-        return ScriptValue::CreateNull(script_state);
+        return ScriptValue::CreateNull(script_state->GetIsolate());
       }
       bool completed;
       if (checkProgramCompletionQueryAvailable(program, &completed)) {
@@ -3461,7 +3461,7 @@
       if (!IsWebGL2OrHigher()) {
         SynthesizeGLError(GL_INVALID_ENUM, "getProgramParameter",
                           "invalid parameter name");
-        return ScriptValue::CreateNull(script_state);
+        return ScriptValue::CreateNull(script_state->GetIsolate());
       }
       FALLTHROUGH;
     case GL_ATTACHED_SHADERS:
@@ -3473,7 +3473,7 @@
       if (!IsWebGL2OrHigher()) {
         SynthesizeGLError(GL_INVALID_ENUM, "getProgramParameter",
                           "invalid parameter name");
-        return ScriptValue::CreateNull(script_state);
+        return ScriptValue::CreateNull(script_state->GetIsolate());
       }
       ContextGL()->GetProgramiv(ObjectOrZero(program), pname, &value);
       return WebGLAny(script_state, static_cast<unsigned>(value));
@@ -3486,7 +3486,7 @@
     default:
       SynthesizeGLError(GL_INVALID_ENUM, "getProgramParameter",
                         "invalid parameter name");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 }
 
@@ -3502,16 +3502,16 @@
     GLenum target,
     GLenum pname) {
   if (isContextLost())
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   if (target != GL_RENDERBUFFER) {
     SynthesizeGLError(GL_INVALID_ENUM, "getRenderbufferParameter",
                       "invalid target");
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   }
   if (!renderbuffer_binding_ || !renderbuffer_binding_->Object()) {
     SynthesizeGLError(GL_INVALID_OPERATION, "getRenderbufferParameter",
                       "no renderbuffer bound");
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 
   GLint value = 0;
@@ -3520,7 +3520,7 @@
       if (!IsWebGL2OrHigher()) {
         SynthesizeGLError(GL_INVALID_ENUM, "getRenderbufferParameter",
                           "invalid parameter name");
-        return ScriptValue::CreateNull(script_state);
+        return ScriptValue::CreateNull(script_state->GetIsolate());
       }
       FALLTHROUGH;
     case GL_RENDERBUFFER_WIDTH:
@@ -3540,7 +3540,7 @@
     default:
       SynthesizeGLError(GL_INVALID_ENUM, "getRenderbufferParameter",
                         "invalid parameter name");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 }
 
@@ -3549,7 +3549,7 @@
     WebGLShader* shader,
     GLenum pname) {
   if (!ValidateWebGLProgramOrShader("getShaderParameter", shader)) {
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   }
   GLint value = 0;
   switch (pname) {
@@ -3562,7 +3562,7 @@
       if (!ExtensionEnabled(kKHRParallelShaderCompileName)) {
         SynthesizeGLError(GL_INVALID_ENUM, "getShaderParameter",
                           "invalid parameter name");
-        return ScriptValue::CreateNull(script_state);
+        return ScriptValue::CreateNull(script_state->GetIsolate());
       }
       ContextGL()->GetShaderiv(ObjectOrZero(shader), pname, &value);
       return WebGLAny(script_state, static_cast<bool>(value));
@@ -3572,7 +3572,7 @@
     default:
       SynthesizeGLError(GL_INVALID_ENUM, "getShaderParameter",
                         "invalid parameter name");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 }
 
@@ -3643,9 +3643,9 @@
     GLenum target,
     GLenum pname) {
   if (isContextLost())
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   if (!ValidateTextureBinding("getTexParameter", target))
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   switch (pname) {
     case GL_TEXTURE_MAG_FILTER:
     case GL_TEXTURE_MIN_FILTER:
@@ -3664,11 +3664,11 @@
       SynthesizeGLError(
           GL_INVALID_ENUM, "getTexParameter",
           "invalid parameter name, EXT_texture_filter_anisotropic not enabled");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
     default:
       SynthesizeGLError(GL_INVALID_ENUM, "getTexParameter",
                         "invalid parameter name");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 }
 
@@ -3677,12 +3677,12 @@
     WebGLProgram* program,
     const WebGLUniformLocation* uniform_location) {
   if (!ValidateWebGLProgramOrShader("getUniform", program))
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   DCHECK(uniform_location);
   if (uniform_location->Program() != program) {
     SynthesizeGLError(GL_INVALID_OPERATION, "getUniform",
                       "no uniformlocation or not valid for this program");
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   }
   GLint location = uniform_location->Location();
 
@@ -3691,11 +3691,11 @@
   ContextGL()->GetProgramiv(program_id, GL_ACTIVE_UNIFORM_MAX_LENGTH,
                             &max_name_length);
   if (max_name_length < 0)
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   if (max_name_length == 0) {
     SynthesizeGLError(GL_INVALID_VALUE, "getUniform",
                       "no active uniforms exist");
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 
   // FIXME: make this more efficient using WebGLUniformLocation and caching
@@ -3713,7 +3713,7 @@
                                   &size, &type,
                                   reinterpret_cast<GLchar*>(name_ptr));
     if (size < 0)
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
     String name(name_impl->Substring(0, name_length));
     StringBuilder name_builder;
     // Strip "[0]" from the name if it's an array.
@@ -3808,7 +3808,7 @@
               SynthesizeGLError(
                   GL_INVALID_VALUE, "getUniform",
                   "unhandled type, WEBGL_video_texture extension not enabled");
-              return ScriptValue::CreateNull(script_state);
+              return ScriptValue::CreateNull(script_state->GetIsolate());
             }
             base_type = GL_INT;
             length = 1;
@@ -3818,7 +3818,7 @@
               // Can't handle this type
               SynthesizeGLError(GL_INVALID_VALUE, "getUniform",
                                 "unhandled type");
-              return ScriptValue::CreateNull(script_state);
+              return ScriptValue::CreateNull(script_state->GetIsolate());
             }
             // handle GLenums for WebGL 2.0 or higher
             switch (type) {
@@ -3893,7 +3893,7 @@
                 if (context_type_ != Platform::kWebGL2ComputeContextType) {
                   SynthesizeGLError(GL_INVALID_VALUE, "getUniform",
                                     "unhandled type");
-                  return ScriptValue::CreateNull(script_state);
+                  return ScriptValue::CreateNull(script_state->GetIsolate());
                 }
                 base_type = GL_INT;
                 length = 1;
@@ -3903,7 +3903,7 @@
                 // Can't handle this type
                 SynthesizeGLError(GL_INVALID_VALUE, "getUniform",
                                   "unhandled type");
-                return ScriptValue::CreateNull(script_state);
+                return ScriptValue::CreateNull(script_state->GetIsolate());
             }
         }
         switch (base_type) {
@@ -3950,7 +3950,7 @@
   // If we get here, something went wrong in our unfortunately complex logic
   // above
   SynthesizeGLError(GL_INVALID_VALUE, "getUniform", "unknown error");
-  return ScriptValue::CreateNull(script_state);
+  return ScriptValue::CreateNull(script_state->GetIsolate());
 }
 
 WebGLUniformLocation* WebGLRenderingContextBase::getUniformLocation(
@@ -3981,11 +3981,11 @@
     GLuint index,
     GLenum pname) {
   if (isContextLost())
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   if (index >= max_vertex_attribs_) {
     SynthesizeGLError(GL_INVALID_VALUE, "getVertexAttrib",
                       "index out of range");
-    return ScriptValue::CreateNull(script_state);
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 
   if ((ExtensionEnabled(kANGLEInstancedArraysName) || IsWebGL2OrHigher()) &&
@@ -4039,7 +4039,7 @@
           NOTREACHED();
           break;
       }
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
     }
     case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
       if (IsWebGL2OrHigher()) {
@@ -4051,7 +4051,7 @@
     default:
       SynthesizeGLError(GL_INVALID_ENUM, "getVertexAttrib",
                         "invalid parameter name");
-      return ScriptValue::CreateNull(script_state);
+      return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 }
 
@@ -6813,7 +6813,7 @@
         if (value == 0) {
           // This indicates read framebuffer is incomplete and an
           // INVALID_OPERATION has been generated.
-          return ScriptValue::CreateNull(script_state);
+          return ScriptValue::CreateNull(script_state->GetIsolate());
         }
         break;
       default:
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.cc b/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.cc
index 93252552..d2065677 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.cc
@@ -23,7 +23,7 @@
   dawn_binding.textureComponentType = AsDawnEnum<DawnTextureComponentType>(
       webgpu_binding->textureComponentType());
   dawn_binding.multisampled = webgpu_binding->multisampled();
-  dawn_binding.dynamic = webgpu_binding->dynamic();
+  dawn_binding.hasDynamicOffset = webgpu_binding->hasDynamicOffset();
 
   return dawn_binding;
 }
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout_binding.idl b/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout_binding.idl
index df5acb6..c13851c3 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout_binding.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout_binding.idl
@@ -11,7 +11,7 @@
     GPUTextureViewDimension textureDimension = "2d";
     GPUTextureComponentType textureComponentType = "float";
     boolean multisampled = false;
-    boolean dynamic = false;
+    boolean hasDynamicOffset = false;
 };
 
 enum GPUBindingType {
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc
index 5c5f063..773faf3 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc
@@ -80,4 +80,17 @@
   return swapchain_;
 }
 
+ScriptPromise GPUCanvasContext::getSwapChainPreferredFormat(
+    ScriptState* script_state,
+    const GPUDevice* device) {
+  ScriptPromiseResolver* resolver =
+      MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+  ScriptPromise promise = resolver->Promise();
+
+  // TODO(crbug.com/1007166): Return actual preferred format for the swap chain.
+  resolver->Resolve("bgra8unorm");
+
+  return promise;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.h b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.h
index 0360222..5e357b5 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.h
+++ b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.h
@@ -62,6 +62,8 @@
 
   // gpu_canvas_context.idl
   GPUSwapChain* configureSwapChain(const GPUSwapChainDescriptor* descriptor);
+  ScriptPromise getSwapChainPreferredFormat(ScriptState* script_state,
+                                            const GPUDevice* device);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(GPUCanvasContext);
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.idl b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.idl
index 5e4ac97..feb476c 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.idl
@@ -8,4 +8,6 @@
     RuntimeEnabled=WebGPU
 ] interface GPUCanvasContext {
     GPUSwapChain configureSwapChain(GPUSwapChainDescriptor descriptor);
+
+    [CallWith=ScriptState] Promise<GPUTextureFormat> getSwapChainPreferredFormat(GPUDevice device);
 };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.cc b/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.cc
index b3494aa..0060aaab 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.cc
@@ -82,9 +82,10 @@
     dawn_desc.stencilLoadOp = AsDawnEnum<DawnLoadOp>(gpuLoadOp);
     dawn_desc.clearStencil = 0;
 
-  } else if (webgpu_desc->stencilLoadValue().IsLong()) {
+  } else if (webgpu_desc->stencilLoadValue().IsUnsignedLong()) {
     dawn_desc.stencilLoadOp = DAWN_LOAD_OP_CLEAR;
-    dawn_desc.clearStencil = webgpu_desc->stencilLoadValue().GetAsLong();
+    dawn_desc.clearStencil =
+        webgpu_desc->stencilLoadValue().GetAsUnsignedLong();
 
   } else {
     NOTREACHED();
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_device.cc b/third_party/blink/renderer/modules/webgpu/gpu_device.cc
index 87bfcf4..bedd1100 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_device.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_device.cc
@@ -244,10 +244,10 @@
 void GPUDevice::OnPopErrorScopeCallback(ScriptPromiseResolver* resolver,
                                         DawnErrorType type,
                                         const char* message) {
-  ScriptState* script_state = resolver->GetScriptState();
+  v8::Isolate* isolate = resolver->GetScriptState()->GetIsolate();
   switch (type) {
     case DAWN_ERROR_TYPE_NO_ERROR:
-      resolver->Resolve(ScriptValue::CreateNull(script_state));
+      resolver->Resolve(ScriptValue::CreateNull(isolate));
       break;
     case DAWN_ERROR_TYPE_OUT_OF_MEMORY:
       resolver->Resolve(GPUOutOfMemoryError::Create());
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_pipeline_descriptor_base.idl b/third_party/blink/renderer/modules/webgpu/gpu_pipeline_descriptor_base.idl
index 417592f8..4557d05 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_pipeline_descriptor_base.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_pipeline_descriptor_base.idl
@@ -5,6 +5,5 @@
 // https://gpuweb.github.io/gpuweb/
 
 dictionary GPUPipelineDescriptorBase {
-    DOMString label;
     required GPUPipelineLayout layout;
 };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_render_pass_depth_stencil_attachment_descriptor.idl b/third_party/blink/renderer/modules/webgpu/gpu_render_pass_depth_stencil_attachment_descriptor.idl
index 63c9b326..3d32541 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_render_pass_depth_stencil_attachment_descriptor.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_render_pass_depth_stencil_attachment_descriptor.idl
@@ -10,6 +10,6 @@
     required (GPULoadOp or float) depthLoadValue;
     required GPUStoreOp depthStoreOp;
 
-    required (GPULoadOp or long) stencilLoadValue;
+    required (GPULoadOp or unsigned long) stencilLoadValue;
     required GPUStoreOp stencilStoreOp;
 };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_sampler.cc b/third_party/blink/renderer/modules/webgpu/gpu_sampler.cc
index 0b21805..e221ebb 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_sampler.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_sampler.cc
@@ -29,8 +29,7 @@
       AsDawnEnum<DawnFilterMode>(webgpu_desc->mipmapFilter());
   dawn_desc.lodMinClamp = webgpu_desc->lodMinClamp();
   dawn_desc.lodMaxClamp = webgpu_desc->lodMaxClamp();
-  dawn_desc.compare =
-      AsDawnEnum<DawnCompareFunction>(webgpu_desc->compareFunction());
+  dawn_desc.compare = AsDawnEnum<DawnCompareFunction>(webgpu_desc->compare());
 
   return dawn_desc;
 }
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_sampler_descriptor.idl b/third_party/blink/renderer/modules/webgpu/gpu_sampler_descriptor.idl
index 4eb8b2b..c987d631 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_sampler_descriptor.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_sampler_descriptor.idl
@@ -13,7 +13,7 @@
     GPUFilterMode mipmapFilter = "nearest";
     float lodMinClamp = 0;
     float lodMaxClamp = 0xffffffff;
-    GPUCompareFunction compareFunction = "never";
+    GPUCompareFunction compare = "never";
 };
 
 enum GPUAddressMode {
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_shader_module_descriptor.idl b/third_party/blink/renderer/modules/webgpu/gpu_shader_module_descriptor.idl
index 640d875..af9f707 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_shader_module_descriptor.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_shader_module_descriptor.idl
@@ -5,7 +5,6 @@
 // https://gpuweb.github.io/gpuweb/
 
 dictionary GPUShaderModuleDescriptor {
-    DOMString label;
     // TODO(kainino): should be:
     //   [AllowShared, FlexibleArrayBufferView] required ArrayBufferView code;
     // (or BufferSource?)
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_vertex_attribute_descriptor.idl b/third_party/blink/renderer/modules/webgpu/gpu_vertex_attribute_descriptor.idl
index 297b7f9e..bd18f3c5 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_vertex_attribute_descriptor.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_vertex_attribute_descriptor.idl
@@ -4,12 +4,10 @@
 
 // https://gpuweb.github.io/gpuweb/
 
-typedef unsigned long GPUShaderAttributeIndex;
-
 dictionary GPUVertexAttributeDescriptor {
     unsigned long long offset = 0;
     required GPUVertexFormat format;
-    required GPUShaderAttributeIndex shaderLocation;
+    required unsigned long shaderLocation;
 };
 
 enum GPUVertexFormat {
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index f72614d..decd2fd 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -1467,6 +1467,7 @@
     "//third_party/ced",
     "//third_party/emoji-segmenter",
     "//third_party/icu",
+    "//third_party/libyuv",
     "//third_party/webrtc/api:libjingle_logging_api",
     "//third_party/webrtc/api:packet_socket_factory",
     "//third_party/webrtc/api/audio_codecs/L16:audio_decoder_L16",
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 bd433b1..66cbb2e 100644
--- a/third_party/blink/renderer/platform/exported/web_runtime_features.cc
+++ b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
@@ -668,10 +668,6 @@
   RuntimeEnabledFeatures::SetSkipTouchEventFilterEnabled(enable);
 }
 
-void WebRuntimeFeatures::EnableStaleWhileRevalidate(bool enable) {
-  RuntimeEnabledFeatures::SetStaleWhileRevalidateEnabled(enable);
-}
-
 void WebRuntimeFeatures::EnableSmsReceiver(bool enable) {
   RuntimeEnabledFeatures::SetSmsReceiverEnabled(enable);
 }
diff --git a/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl_test.cc b/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl_test.cc
index 6537e49..a93063f7 100644
--- a/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl_test.cc
+++ b/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl_test.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h"
 
+#include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/simple_test_tick_clock.h"
diff --git a/third_party/blink/renderer/platform/graphics/image_decoding_store_test.cc b/third_party/blink/renderer/platform/graphics/image_decoding_store_test.cc
index bd064bbc..65787e1 100644
--- a/third_party/blink/renderer/platform/graphics/image_decoding_store_test.cc
+++ b/third_party/blink/renderer/platform/graphics/image_decoding_store_test.cc
@@ -27,6 +27,7 @@
 
 #include <memory>
 #include "base/memory/memory_pressure_listener.h"
+#include "base/run_loop.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/platform/graphics/image_frame_generator.h"
 #include "third_party/blink/renderer/platform/graphics/test/mock_image_decoder.h"
diff --git a/third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.h b/third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.h
index c6cbeea..de9f8d5 100644
--- a/third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.h
+++ b/third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.h
@@ -9,11 +9,12 @@
 #include "third_party/blink/public/platform/web_memory_pressure_level.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
 #include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
 
 namespace blink {
 
+class Thread;
+
 class PLATFORM_EXPORT MemoryPressureListener : public GarbageCollectedMixin {
  public:
   virtual ~MemoryPressureListener() = default;
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource.h b/third_party/blink/renderer/platform/loader/fetch/resource.h
index c5f00ea..ea72b29 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource.h
@@ -31,7 +31,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/time/time.h"
 #include "mojo/public/cpp/base/big_buffer.h"
-#include "third_party/blink/public/mojom/loader/code_cache.mojom-blink.h"
+#include "third_party/blink/public/mojom/loader/code_cache.mojom-blink-forward.h"
 #include "third_party/blink/public/platform/scheduler/web_scoped_virtual_time_pauser.h"
 #include "third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/web_process_memory_dump.h"
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_error.h b/third_party/blink/renderer/platform/loader/fetch/resource_error.h
index 61cbc35..592174ea 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_error.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_error.h
@@ -30,7 +30,6 @@
 #include <iosfwd>
 #include "base/optional.h"
 #include "services/network/public/cpp/cors/cors_error_status.h"
-#include "third_party/blink/public/platform/web_url_error.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -38,6 +37,7 @@
 
 namespace blink {
 
+struct WebURLError;
 enum class ResourceRequestBlockedReason;
 
 // ResourceError represents an error for loading a resource. There is no
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
index add32bc..ac8cbb11 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -573,8 +573,6 @@
       allow_stale_resources_(false),
       image_fetched_(false),
       should_log_request_as_invalid_in_imported_document_(false) {
-  stale_while_revalidate_enabled_ =
-      RuntimeEnabledFeatures::StaleWhileRevalidateEnabledByRuntimeFlag();
   InstanceCounters::IncrementCounter(InstanceCounters::kResourceFetcherCounter);
   if (IsMainThread())
     MainThreadFetchersSet().insert(this);
@@ -871,8 +869,7 @@
   // stale resource is returned a StaleRevalidation request will be scheduled.
   // Explicitly disallow stale responses for fetchers that don't have SWR
   // enabled (via origin trial), and non-GET requests.
-  resource_request.SetAllowStaleResponse(stale_while_revalidate_enabled_ &&
-                                         resource_request.HttpMethod() ==
+  resource_request.SetAllowStaleResponse(resource_request.HttpMethod() ==
                                              http_names::kGET &&
                                          !params.IsStaleRevalidation());
 
@@ -2075,10 +2072,6 @@
   StopFetchingIncludingKeepaliveLoaders();
 }
 
-void ResourceFetcher::SetStaleWhileRevalidateEnabled(bool enabled) {
-  stale_while_revalidate_enabled_ = enabled;
-}
-
 void ResourceFetcher::StopFetchingInternal(StopFetchingTarget target) {
   // TODO(toyoshim): May want to suspend scheduler while canceling loaders so
   // that the cancellations below do not awake unnecessary scheduling.
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
index cd2a647..e627b88 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
@@ -244,8 +244,6 @@
   // counting.
   void PrepareForLeakDetection();
 
-  void SetStaleWhileRevalidateEnabled(bool enabled);
-
   using ResourceFetcherSet = HeapHashSet<WeakMember<ResourceFetcher>>;
   static const ResourceFetcherSet& MainThreadFetchers();
 
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
index 58f00ce..f705847 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
@@ -945,7 +945,6 @@
   EXPECT_TRUE(resource->IsLoaded());
   EXPECT_TRUE(GetMemoryCache()->Contains(resource));
 
-  fetcher->SetStaleWhileRevalidateEnabled(true);
   ResourceRequest resource_request(url);
   resource_request.SetRequestContext(mojom::RequestContextType::INTERNAL);
   fetch_params = FetchParameters(resource_request);
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 88c9d2b..cc8669b1 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -285,10 +285,6 @@
       status: "experimental",
     },
     {
-      name: "ClientHintsFeaturePolicy",
-      status: "experimental",
-    },
-    {
       name: "ClientPlaceholdersForServerLoFi",
     },
     {
@@ -1569,11 +1565,6 @@
       status: "experimental",
     },
     {
-      name: "StaleWhileRevalidate",
-      origin_trial_feature_name: "StaleWhileRevalidate",
-      status: "stable",
-    },
-    {
       // Enabled when blink::features::kStorageAccessAPI is enabled.
       name: "StorageAccessAPI",
       status: "test",
diff --git a/third_party/blink/renderer/platform/scheduler/common/cooperative_scheduling_manager.cc b/third_party/blink/renderer/platform/scheduler/common/cooperative_scheduling_manager.cc
index 74cd66d..0413fe7 100644
--- a/third_party/blink/renderer/platform/scheduler/common/cooperative_scheduling_manager.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/cooperative_scheduling_manager.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/platform/scheduler/public/cooperative_scheduling_manager.h"
 
 #include "base/auto_reset.h"
+#include "base/run_loop.h"
 #include "base/time/default_tick_clock.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
diff --git a/third_party/blink/renderer/platform/scheduler/public/DEPS b/third_party/blink/renderer/platform/scheduler/public/DEPS
new file mode 100644
index 0000000..1361ae43
--- /dev/null
+++ b/third_party/blink/renderer/platform/scheduler/public/DEPS
@@ -0,0 +1,5 @@
+specific_include_rules = {
+  "thread.h": [
+    "+base/task/task_observer.h",
+  ]
+}
\ No newline at end of file
diff --git a/third_party/blink/renderer/platform/scheduler/public/thread.h b/third_party/blink/renderer/platform/scheduler/public/thread.h
index 9926c72..d02598f 100644
--- a/third_party/blink/renderer/platform/scheduler/public/thread.h
+++ b/third_party/blink/renderer/platform/scheduler/public/thread.h
@@ -29,6 +29,7 @@
 #include "base/callback_forward.h"
 #include "base/macros.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/task/task_observer.h"
 #include "base/threading/thread.h"
 #include "third_party/blink/public/platform/web_thread_type.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
diff --git a/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.cc b/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.cc
index f7708a9..11b6746 100644
--- a/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.cc
+++ b/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.cc
@@ -4,9 +4,12 @@
 
 #include "third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.h"
 
+#include "base/bind_helpers.h"
 #include "base/logging.h"
+#include "third_party/libyuv/include/libyuv.h"
 #include "third_party/webrtc/common_video/include/video_frame_buffer.h"
 #include "third_party/webrtc/rtc_base/ref_counted_object.h"
+#include "ui/gfx/gpu_memory_buffer.h"
 
 namespace {
 
@@ -78,6 +81,37 @@
   CHECK(frame.stride(media::VideoFrame::kVPlane));
 }
 
+scoped_refptr<media::VideoFrame> ConstructI420VideoFrame(
+    const media::VideoFrame& source_frame) {
+  // NV12 is the only supported format.
+  DCHECK_EQ(source_frame.format(), media::PIXEL_FORMAT_NV12);
+  gfx::GpuMemoryBuffer* gmb = source_frame.GetGpuMemoryBuffer();
+  if (!gmb || !gmb->Map()) {
+    return nullptr;
+  }
+  scoped_refptr<media::VideoFrame> i420_frame = media::VideoFrame::CreateFrame(
+      media::PIXEL_FORMAT_I420, source_frame.coded_size(),
+      source_frame.visible_rect(), source_frame.natural_size(),
+      source_frame.timestamp());
+  i420_frame->metadata()->MergeMetadataFrom(source_frame.metadata());
+  const auto& i420_planes = i420_frame->layout().planes();
+  int ret = libyuv::NV12ToI420(
+      reinterpret_cast<const uint8_t*>(gmb->memory(0)), gmb->stride(0),
+      reinterpret_cast<const uint8_t*>(gmb->memory(1)), gmb->stride(1),
+      i420_frame->data(media::VideoFrame::kYPlane),
+      i420_planes[media::VideoFrame::kYPlane].stride,
+      i420_frame->data(media::VideoFrame::kUPlane),
+      i420_planes[media::VideoFrame::kUPlane].stride,
+      i420_frame->data(media::VideoFrame::kVPlane),
+      i420_planes[media::VideoFrame::kVPlane].stride,
+      i420_frame->coded_size().width(), i420_frame->coded_size().height());
+  gmb->Unmap();
+  if (ret) {
+    return nullptr;
+  }
+  return i420_frame;
+}
+
 }  // anonymous namespace
 
 namespace blink {
@@ -102,6 +136,25 @@
 
 rtc::scoped_refptr<webrtc::I420BufferInterface>
 WebRtcVideoFrameAdapter::CreateFrameAdapter() const {
+  if (frame_->storage_type() ==
+      media::VideoFrame::StorageType::STORAGE_GPU_MEMORY_BUFFER) {
+    auto i420_frame = ConstructI420VideoFrame(*frame_);
+    if (!i420_frame) {
+      return new rtc::RefCountedObject<
+          FrameAdapter<webrtc::I420BufferInterface>>(
+          media::VideoFrame::CreateColorFrame(frame_->visible_rect().size(), 0u,
+                                              0x80, 0x80, frame_->timestamp()));
+    }
+
+    // Keep |frame_| alive until |i420_frame| is destroyed.
+    i420_frame->AddDestructionObserver(base::BindOnce(
+        base::DoNothing::Once<scoped_refptr<media::VideoFrame>>(), frame_));
+
+    IsValidFrame(*i420_frame);
+    return new rtc::RefCountedObject<FrameAdapter<webrtc::I420BufferInterface>>(
+        i420_frame);
+  }
+
   // We cant convert texture synchronously due to threading issues, see
   // https://crbug.com/663452. Instead, return a black frame (yuv = {0, 0x80,
   // 0x80}).
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 996ba8c..8b0e003 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -84,6 +84,8 @@
 crbug.com/906879 http/tests/inspector-protocol/network/navigation-blocking-xorigin-iframe.js [ Pass Failure ]
 crbug.com/949003 http/tests/printing/cross-site-frame-scrolled.html [ Pass Failure ]
 crbug.com/949003 http/tests/printing/cross-site-frame.html [ Pass Failure ]
+crbug.com/1007228 external/wpt/fullscreen/api/element-request-fullscreen-and-move-to-iframe-manual.html [ Pass Failure ]
+crbug.com/1007229 external/wpt/intersection-observer/same-origin-grand-child-iframe.sub.html [ Pass Failure ]
 # ====== Site Isolation failures until here ======
 
 # ====== Oilpan-only failures from here ======
@@ -3225,6 +3227,7 @@
 crbug.com/618969 external/wpt/css/css-grid/subgrid/ [ Skip ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 [ Win10 ] external/wpt/payment-request/payment-request-hasenrolledinstrument-method.tentative.https.html [ Failure Timeout ]
 crbug.com/626703 [ Linux ] external/wpt/css/motion/offset-path-ray-contain-003.html [ Failure ]
 crbug.com/626703 [ Mac ] external/wpt/css/motion/offset-path-ray-contain-003.html [ Failure ]
 crbug.com/626703 [ Win ] external/wpt/css/motion/offset-path-ray-contain-003.html [ Failure ]
@@ -5790,9 +5793,6 @@
 # Sheriff 2019-04-18
 crbug.com/954297 [ Linux Win ] http/tests/devtools/oopif/oopif-presentation-console-messages.js [ Pass Crash Timeout ]
 
-# Sheriff 2019-04-19
-crbug.com/954628 [ Win ] external/wpt/payment-request/payment-request-canmakepayment-method.https.html [ Pass Timeout ]
-
 # Sheriff 2019-04-22
 crbug.com/954319 [ Linux ] http/tests/devtools/sources/debugger-breakpoints/breakpoints-ui-in-multiple-workers.js [ Pass Timeout ]
 crbug.com/954998 [ Mac ] http/tests/devtools/tracing/timeline-js/timeline-js-line-level-profile-end-to-end.js [ Pass Timeout ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
index 7907bfa..afb1ae3 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
@@ -2059,369 +2059,333 @@
      {}
     ]
    ],
-   "css/css-transitions/transition-delay-000.html": [
+   "css/css-transitions/transition-delay-000-manual.html": [
     [
-     "css/css-transitions/transition-delay-000.html",
+     "css/css-transitions/transition-delay-000-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-delay-002.html": [
+   "css/css-transitions/transition-delay-002-manual.html": [
     [
-     "css/css-transitions/transition-delay-002.html",
+     "css/css-transitions/transition-delay-002-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-delay-003.html": [
+   "css/css-transitions/transition-delay-003-manual.html": [
     [
-     "css/css-transitions/transition-delay-003.html",
+     "css/css-transitions/transition-delay-003-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-duration-002.html": [
+   "css/css-transitions/transition-duration-002-manual.html": [
     [
-     "css/css-transitions/transition-duration-002.html",
+     "css/css-transitions/transition-duration-002-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-duration-003.html": [
+   "css/css-transitions/transition-duration-003-manual.html": [
     [
-     "css/css-transitions/transition-duration-003.html",
+     "css/css-transitions/transition-duration-003-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-duration-004.html": [
+   "css/css-transitions/transition-duration-004-manual.html": [
     [
-     "css/css-transitions/transition-duration-004.html",
+     "css/css-transitions/transition-duration-004-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-003.html": [
+   "css/css-transitions/transition-property-003-manual.html": [
     [
-     "css/css-transitions/transition-property-003.html",
+     "css/css-transitions/transition-property-003-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-004.html": [
+   "css/css-transitions/transition-property-004-manual.html": [
     [
-     "css/css-transitions/transition-property-004.html",
+     "css/css-transitions/transition-property-004-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-005.html": [
+   "css/css-transitions/transition-property-005-manual.html": [
     [
-     "css/css-transitions/transition-property-005.html",
+     "css/css-transitions/transition-property-005-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-006.html": [
+   "css/css-transitions/transition-property-006-manual.html": [
     [
-     "css/css-transitions/transition-property-006.html",
+     "css/css-transitions/transition-property-006-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-007.html": [
+   "css/css-transitions/transition-property-007-manual.html": [
     [
-     "css/css-transitions/transition-property-007.html",
+     "css/css-transitions/transition-property-007-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-008.html": [
+   "css/css-transitions/transition-property-008-manual.html": [
     [
-     "css/css-transitions/transition-property-008.html",
+     "css/css-transitions/transition-property-008-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-009.html": [
+   "css/css-transitions/transition-property-009-manual.html": [
     [
-     "css/css-transitions/transition-property-009.html",
+     "css/css-transitions/transition-property-009-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-010.html": [
+   "css/css-transitions/transition-property-010-manual.html": [
     [
-     "css/css-transitions/transition-property-010.html",
+     "css/css-transitions/transition-property-010-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-011.html": [
+   "css/css-transitions/transition-property-011-manual.html": [
     [
-     "css/css-transitions/transition-property-011.html",
+     "css/css-transitions/transition-property-011-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-012.html": [
+   "css/css-transitions/transition-property-012-manual.html": [
     [
-     "css/css-transitions/transition-property-012.html",
+     "css/css-transitions/transition-property-012-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-013.html": [
+   "css/css-transitions/transition-property-013-manual.html": [
     [
-     "css/css-transitions/transition-property-013.html",
+     "css/css-transitions/transition-property-013-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-014.html": [
+   "css/css-transitions/transition-property-014-manual.html": [
     [
-     "css/css-transitions/transition-property-014.html",
+     "css/css-transitions/transition-property-014-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-015.html": [
+   "css/css-transitions/transition-property-015-manual.html": [
     [
-     "css/css-transitions/transition-property-015.html",
+     "css/css-transitions/transition-property-015-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-016.html": [
+   "css/css-transitions/transition-property-016-manual.html": [
     [
-     "css/css-transitions/transition-property-016.html",
+     "css/css-transitions/transition-property-016-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-017.html": [
+   "css/css-transitions/transition-property-017-manual.html": [
     [
-     "css/css-transitions/transition-property-017.html",
+     "css/css-transitions/transition-property-017-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-018.html": [
+   "css/css-transitions/transition-property-018-manual.html": [
     [
-     "css/css-transitions/transition-property-018.html",
+     "css/css-transitions/transition-property-018-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-019.html": [
+   "css/css-transitions/transition-property-019-manual.html": [
     [
-     "css/css-transitions/transition-property-019.html",
+     "css/css-transitions/transition-property-019-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-020.html": [
+   "css/css-transitions/transition-property-020-manual.html": [
     [
-     "css/css-transitions/transition-property-020.html",
+     "css/css-transitions/transition-property-020-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-021.html": [
+   "css/css-transitions/transition-property-021-manual.html": [
     [
-     "css/css-transitions/transition-property-021.html",
+     "css/css-transitions/transition-property-021-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-022.html": [
+   "css/css-transitions/transition-property-022-manual.html": [
     [
-     "css/css-transitions/transition-property-022.html",
+     "css/css-transitions/transition-property-022-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-023.html": [
+   "css/css-transitions/transition-property-023-manual.html": [
     [
-     "css/css-transitions/transition-property-023.html",
+     "css/css-transitions/transition-property-023-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-024.html": [
+   "css/css-transitions/transition-property-024-manual.html": [
     [
-     "css/css-transitions/transition-property-024.html",
+     "css/css-transitions/transition-property-024-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-025.html": [
+   "css/css-transitions/transition-property-025-manual.html": [
     [
-     "css/css-transitions/transition-property-025.html",
+     "css/css-transitions/transition-property-025-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-026.html": [
+   "css/css-transitions/transition-property-026-manual.html": [
     [
-     "css/css-transitions/transition-property-026.html",
+     "css/css-transitions/transition-property-026-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-027.html": [
+   "css/css-transitions/transition-property-027-manual.html": [
     [
-     "css/css-transitions/transition-property-027.html",
+     "css/css-transitions/transition-property-027-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-028.html": [
+   "css/css-transitions/transition-property-028-manual.html": [
     [
-     "css/css-transitions/transition-property-028.html",
+     "css/css-transitions/transition-property-028-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-029.html": [
+   "css/css-transitions/transition-property-029-manual.html": [
     [
-     "css/css-transitions/transition-property-029.html",
+     "css/css-transitions/transition-property-029-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-030.html": [
+   "css/css-transitions/transition-property-030-manual.html": [
     [
-     "css/css-transitions/transition-property-030.html",
+     "css/css-transitions/transition-property-030-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-031.html": [
+   "css/css-transitions/transition-property-031-manual.html": [
     [
-     "css/css-transitions/transition-property-031.html",
+     "css/css-transitions/transition-property-031-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-032.html": [
+   "css/css-transitions/transition-property-032-manual.html": [
     [
-     "css/css-transitions/transition-property-032.html",
+     "css/css-transitions/transition-property-032-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-033.html": [
+   "css/css-transitions/transition-property-033-manual.html": [
     [
-     "css/css-transitions/transition-property-033.html",
+     "css/css-transitions/transition-property-033-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-034.html": [
+   "css/css-transitions/transition-property-034-manual.html": [
     [
-     "css/css-transitions/transition-property-034.html",
+     "css/css-transitions/transition-property-034-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-035.html": [
+   "css/css-transitions/transition-property-035-manual.html": [
     [
-     "css/css-transitions/transition-property-035.html",
+     "css/css-transitions/transition-property-035-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-036.html": [
+   "css/css-transitions/transition-property-036-manual.html": [
     [
-     "css/css-transitions/transition-property-036.html",
+     "css/css-transitions/transition-property-036-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-037.html": [
+   "css/css-transitions/transition-property-037-manual.html": [
     [
-     "css/css-transitions/transition-property-037.html",
+     "css/css-transitions/transition-property-037-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-038.html": [
+   "css/css-transitions/transition-property-038-manual.html": [
     [
-     "css/css-transitions/transition-property-038.html",
+     "css/css-transitions/transition-property-038-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-039.html": [
+   "css/css-transitions/transition-property-039-manual.html": [
     [
-     "css/css-transitions/transition-property-039.html",
+     "css/css-transitions/transition-property-039-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-040.html": [
+   "css/css-transitions/transition-property-040-manual.html": [
     [
-     "css/css-transitions/transition-property-040.html",
+     "css/css-transitions/transition-property-040-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-041.html": [
+   "css/css-transitions/transition-property-041-manual.html": [
     [
-     "css/css-transitions/transition-property-041.html",
+     "css/css-transitions/transition-property-041-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-042.html": [
+   "css/css-transitions/transition-property-042-manual.html": [
     [
-     "css/css-transitions/transition-property-042.html",
+     "css/css-transitions/transition-property-042-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-043.html": [
+   "css/css-transitions/transition-property-043-manual.html": [
     [
-     "css/css-transitions/transition-property-043.html",
+     "css/css-transitions/transition-property-043-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-044.html": [
+   "css/css-transitions/transition-property-044-manual.html": [
     [
-     "css/css-transitions/transition-property-044.html",
+     "css/css-transitions/transition-property-044-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-property-045.html": [
+   "css/css-transitions/transition-property-045-manual.html": [
     [
-     "css/css-transitions/transition-property-045.html",
+     "css/css-transitions/transition-property-045-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-timing-function-002.html": [
+   "css/css-transitions/transition-timing-function-002-manual.html": [
     [
-     "css/css-transitions/transition-timing-function-002.html",
+     "css/css-transitions/transition-timing-function-002-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-timing-function-003.html": [
+   "css/css-transitions/transition-timing-function-003-manual.html": [
     [
-     "css/css-transitions/transition-timing-function-003.html",
+     "css/css-transitions/transition-timing-function-003-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-timing-function-004.html": [
+   "css/css-transitions/transition-timing-function-004-manual.html": [
     [
-     "css/css-transitions/transition-timing-function-004.html",
+     "css/css-transitions/transition-timing-function-004-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-timing-function-005.html": [
+   "css/css-transitions/transition-timing-function-005-manual.html": [
     [
-     "css/css-transitions/transition-timing-function-005.html",
+     "css/css-transitions/transition-timing-function-005-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-timing-function-006.html": [
+   "css/css-transitions/transition-timing-function-006-manual.html": [
     [
-     "css/css-transitions/transition-timing-function-006.html",
+     "css/css-transitions/transition-timing-function-006-manual.html",
      {}
     ]
    ],
-   "css/css-transitions/transition-timing-function-007.html": [
+   "css/css-transitions/transition-timing-function-010-manual.html": [
     [
-     "css/css-transitions/transition-timing-function-007.html",
-     {}
-    ]
-   ],
-   "css/css-transitions/transition-timing-function-008.html": [
-    [
-     "css/css-transitions/transition-timing-function-008.html",
-     {}
-    ]
-   ],
-   "css/css-transitions/transition-timing-function-009.html": [
-    [
-     "css/css-transitions/transition-timing-function-009.html",
-     {}
-    ]
-   ],
-   "css/css-transitions/transition-timing-function-010.html": [
-    [
-     "css/css-transitions/transition-timing-function-010.html",
-     {}
-    ]
-   ],
-   "css/css-transitions/transition-timing-function-011.html": [
-    [
-     "css/css-transitions/transition-timing-function-011.html",
-     {}
-    ]
-   ],
-   "css/css-transitions/transition-timing-function-012.html": [
-    [
-     "css/css-transitions/transition-timing-function-012.html",
-     {}
-    ]
-   ],
-   "css/css-transitions/transition-timing-function-013.html": [
-    [
-     "css/css-transitions/transition-timing-function-013.html",
+     "css/css-transitions/transition-timing-function-010-manual.html",
      {}
     ]
    ],
@@ -11485,6 +11449,30 @@
      {}
     ]
    ],
+   "css/CSS2/floats/new-fc-beside-float-with-margin-rtl.html": [
+    [
+     "css/CSS2/floats/new-fc-beside-float-with-margin-rtl.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/CSS2/floats/new-fc-beside-float-with-margin.html": [
+    [
+     "css/CSS2/floats/new-fc-beside-float-with-margin.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/CSS2/floats/new-fc-relayout.html": [
     [
      "css/CSS2/floats/new-fc-relayout.html",
@@ -11569,9 +11557,9 @@
      {}
     ]
    ],
-   "css/CSS2/floats/zero-width-floats-positioning.html": [
+   "css/CSS2/floats/zero-width-floats-positioning.tentative.html": [
     [
-     "css/CSS2/floats/zero-width-floats-positioning.html",
+     "css/CSS2/floats/zero-width-floats-positioning.tentative.html",
      [
       [
        "/css/reference/ref-filled-green-100px-square-only.html",
@@ -36289,6 +36277,18 @@
      {}
     ]
    ],
+   "css/css-cascade/all-prop-initial-visited.html": [
+    [
+     "css/css-cascade/all-prop-initial-visited.html",
+     [
+      [
+       "/css/css-cascade/all-prop-initial-visited-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-cascade/important-prop.html": [
     [
      "css/css-cascade/important-prop.html",
@@ -50507,6 +50507,294 @@
      {}
     ]
    ],
+   "css/css-grid/grid-items/grid-items-percentage-margins-003.html": [
+    [
+     "css/css-grid/grid-items/grid-items-percentage-margins-003.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-items/grid-items-percentage-margins-004.html": [
+    [
+     "css/css-grid/grid-items/grid-items-percentage-margins-004.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-items/grid-items-percentage-margins-005.html": [
+    [
+     "css/css-grid/grid-items/grid-items-percentage-margins-005.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-items/grid-items-percentage-margins-006.html": [
+    [
+     "css/css-grid/grid-items/grid-items-percentage-margins-006.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-items/grid-items-percentage-margins-007.html": [
+    [
+     "css/css-grid/grid-items/grid-items-percentage-margins-007.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-items/grid-items-percentage-margins-008.html": [
+    [
+     "css/css-grid/grid-items/grid-items-percentage-margins-008.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-items/grid-items-percentage-margins-009.html": [
+    [
+     "css/css-grid/grid-items/grid-items-percentage-margins-009.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-items/grid-items-percentage-margins-010.html": [
+    [
+     "css/css-grid/grid-items/grid-items-percentage-margins-010.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-items/grid-items-percentage-margins-011.html": [
+    [
+     "css/css-grid/grid-items/grid-items-percentage-margins-011.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-items/grid-items-percentage-margins-012.html": [
+    [
+     "css/css-grid/grid-items/grid-items-percentage-margins-012.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-items/grid-items-percentage-margins-013.html": [
+    [
+     "css/css-grid/grid-items/grid-items-percentage-margins-013.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-items/grid-items-percentage-margins-014.html": [
+    [
+     "css/css-grid/grid-items/grid-items-percentage-margins-014.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-items/grid-items-percentage-paddings-003.html": [
+    [
+     "css/css-grid/grid-items/grid-items-percentage-paddings-003.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-items/grid-items-percentage-paddings-004.html": [
+    [
+     "css/css-grid/grid-items/grid-items-percentage-paddings-004.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-items/grid-items-percentage-paddings-005.html": [
+    [
+     "css/css-grid/grid-items/grid-items-percentage-paddings-005.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-items/grid-items-percentage-paddings-006.html": [
+    [
+     "css/css-grid/grid-items/grid-items-percentage-paddings-006.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-items/grid-items-percentage-paddings-007.html": [
+    [
+     "css/css-grid/grid-items/grid-items-percentage-paddings-007.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-items/grid-items-percentage-paddings-008.html": [
+    [
+     "css/css-grid/grid-items/grid-items-percentage-paddings-008.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-items/grid-items-percentage-paddings-009.html": [
+    [
+     "css/css-grid/grid-items/grid-items-percentage-paddings-009.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-items/grid-items-percentage-paddings-010.html": [
+    [
+     "css/css-grid/grid-items/grid-items-percentage-paddings-010.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-items/grid-items-percentage-paddings-011.html": [
+    [
+     "css/css-grid/grid-items/grid-items-percentage-paddings-011.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-items/grid-items-percentage-paddings-012.html": [
+    [
+     "css/css-grid/grid-items/grid-items-percentage-paddings-012.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-items/grid-items-percentage-paddings-013.html": [
+    [
+     "css/css-grid/grid-items/grid-items-percentage-paddings-013.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-items/grid-items-percentage-paddings-014.html": [
+    [
+     "css/css-grid/grid-items/grid-items-percentage-paddings-014.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-grid/grid-items/grid-items-sizing-alignment-001.html": [
     [
      "css/css-grid/grid-items/grid-items-sizing-alignment-001.html",
@@ -86671,6 +86959,18 @@
      {}
     ]
    ],
+   "css/css-values/min-max-percentage-length-interpolation.html": [
+    [
+     "css/css-values/min-max-percentage-length-interpolation.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square-only.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-values/q-unit-case-insensitivity-001.html": [
     [
      "css/css-values/q-unit-case-insensitivity-001.html",
@@ -112389,6 +112689,18 @@
      {}
     ]
    ],
+   "html/rendering/non-replaced-elements/tables/table-column-width.html": [
+    [
+     "html/rendering/non-replaced-elements/tables/table-column-width.html",
+     [
+      [
+       "/html/rendering/non-replaced-elements/tables/table-column-width-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "html/rendering/non-replaced-elements/tables/table-direction.html": [
     [
      "html/rendering/non-replaced-elements/tables/table-direction.html",
@@ -129547,6 +129859,9 @@
    "css/css-backgrounds/OWNERS": [
     []
    ],
+   "css/css-backgrounds/animations/border-image-outset-interpolation-expected.txt": [
+    []
+   ],
    "css/css-backgrounds/animations/border-image-source-interpolation-expected.txt": [
     []
    ],
@@ -129961,9 +130276,6 @@
    "css/css-backgrounds/parsing/background-image-computed.sub-expected.txt": [
     []
    ],
-   "css/css-backgrounds/parsing/background-invalid-expected.txt": [
-    []
-   ],
    "css/css-backgrounds/parsing/background-position-computed-expected.txt": [
     []
    ],
@@ -130483,6 +130795,9 @@
    "css/css-cascade/all-prop-001-ref.html": [
     []
    ],
+   "css/css-cascade/all-prop-initial-visited-ref.html": [
+    []
+   ],
    "css/css-cascade/important-prop-ref.html": [
     []
    ],
@@ -130975,6 +131290,9 @@
    "css/css-content/element-replacement-ref.html": [
     []
    ],
+   "css/css-content/inheritance-expected.txt": [
+    []
+   ],
    "css/css-content/pseudo-element-inline-box-ref.html": [
     []
    ],
@@ -143530,9 +143848,15 @@
    "css/css-transitions/event-dispatch.tentative-expected.txt": [
     []
    ],
+   "css/css-transitions/idlharness-expected.txt": [
+    []
+   ],
    "css/css-transitions/no-transition-from-ua-to-blocking-stylesheet-ref.html": [
     []
    ],
+   "css/css-transitions/parsing/transition-timing-function-valid-expected.txt": [
+    []
+   ],
    "css/css-transitions/properties-value-001-expected.txt": [
     []
    ],
@@ -147694,6 +148018,9 @@
    "css/mediaqueries/OWNERS": [
     []
    ],
+   "css/mediaqueries/aspect-ratio-serialization-expected.txt": [
+    []
+   ],
    "css/mediaqueries/forced-colors-expected.txt": [
     []
    ],
@@ -147772,6 +148099,9 @@
    "css/motion/offset-rotate-ref.html": [
     []
    ],
+   "css/motion/parsing/offset-parsing-valid-expected.txt": [
+    []
+   ],
    "css/motion/parsing/offset-path-computed-expected.txt": [
     []
    ],
@@ -157741,6 +158071,9 @@
    "html/rendering/non-replaced-elements/tables/table-cell-width-ref.html": [
     []
    ],
+   "html/rendering/non-replaced-elements/tables/table-column-width-ref.html": [
+    []
+   ],
    "html/rendering/non-replaced-elements/tables/table-direction-ref.html": [
     []
    ],
@@ -160966,6 +161299,9 @@
    "infrastructure/expected-fail/uncaught-exception-expected.txt": [
     []
    ],
+   "infrastructure/expected-fail/unhandled-rejection-expected.txt": [
+    []
+   ],
    "infrastructure/metadata/infrastructure/assumptions/allowed-to-play.html.ini": [
     []
    ],
@@ -160984,6 +161320,9 @@
    "infrastructure/metadata/infrastructure/expected-fail/uncaught-exception.html.ini": [
     []
    ],
+   "infrastructure/metadata/infrastructure/expected-fail/unhandled-rejection.html.ini": [
+    []
+   ],
    "infrastructure/metadata/infrastructure/reftest/reftest_and_fail.html.ini": [
     []
    ],
@@ -161554,6 +161893,12 @@
    "interfaces/webvtt.idl": [
     []
    ],
+   "interfaces/webxr-ar-module.idl": [
+    []
+   ],
+   "interfaces/webxr-gamepads-module.idl": [
+    []
+   ],
    "interfaces/webxr.idl": [
     []
    ],
@@ -161581,6 +161926,9 @@
    "intersection-observer/observer-in-iframe.html": [
     []
    ],
+   "intersection-observer/resources/cross-origin-child-iframe.sub.html": [
+    []
+   ],
    "intersection-observer/resources/cross-origin-subframe.html": [
     []
    ],
@@ -161593,6 +161941,9 @@
    "intersection-observer/resources/observer-in-iframe-subframe.html": [
     []
    ],
+   "intersection-observer/resources/same-origin-grand-child-iframe.html": [
+    []
+   ],
    "intersection-observer/resources/scaled-target-subframe.html": [
     []
    ],
@@ -163603,6 +163954,9 @@
    "payment-handler/can-make-payment-event.https-expected.txt": [
     []
    ],
+   "payment-handler/change-payment-method-manual.https-expected.txt": [
+    []
+   ],
    "payment-handler/idlharness.https.any.serviceworker-expected.txt": [
     []
    ],
@@ -163696,9 +164050,6 @@
    "payment-request/payment-request-hasenrolledinstrument-method-protection.tentative.https-expected.txt": [
     []
    ],
-   "payment-request/payment-request-hasenrolledinstrument-method.tentative.https-expected.txt": [
-    []
-   ],
    "payment-request/payment-request-show-method.https-expected.txt": [
     []
    ],
@@ -163741,6 +164092,12 @@
    "permissions/META.yml": [
     []
    ],
+   "permissions/feature-policy-permissions-query.html": [
+    []
+   ],
+   "permissions/permissions-query-feature-policy-attribute.https.sub-expected.txt": [
+    []
+   ],
    "picture-in-picture/META.yml": [
     []
    ],
@@ -163876,6 +164233,9 @@
    "portals/resources/portal-post-message-portal.html": [
     []
    ],
+   "portals/resources/portal-repeated-activate-window.html": [
+    []
+   ],
    "portals/resources/portals-adopt-predecessor-portal.html": [
     []
    ],
@@ -163891,6 +164251,9 @@
    "portals/resources/postmessage-referrer.sub.html": [
     []
    ],
+   "portals/resources/simple-portal-adopts-and-activates-predecessor.html": [
+    []
+   ],
    "portals/resources/simple-portal-adopts-predecessor.html": [
     []
    ],
@@ -168553,6 +168916,9 @@
    "shadow-dom/directionality-002-ref.html": [
     []
    ],
+   "shadow-dom/focus/focus-selector-delegatesFocus-expected.txt": [
+    []
+   ],
    "shadow-dom/focus/resources/shadow-utils.js": [
     []
    ],
@@ -174286,6 +174652,9 @@
    "web-animations/interfaces/KeyframeEffect/iterationComposite-expected.txt": [
     []
    ],
+   "web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-001-expected.txt": [
+    []
+   ],
    "web-animations/interfaces/KeyframeEffect/style-change-events-expected.txt": [
     []
    ],
@@ -177004,6 +177373,9 @@
    "webxr/resources/webxr_util.js": [
     []
    ],
+   "webxr/xrWebGLLayer_constructor.https-expected.txt": [
+    []
+   ],
    "workers/META.yml": [
     []
    ],
@@ -201624,6 +201996,12 @@
      {}
     ]
    ],
+   "css/css-animations/parsing/animation-invalid.html": [
+    [
+     "css/css-animations/parsing/animation-invalid.html",
+     {}
+    ]
+   ],
    "css/css-animations/parsing/animation-iteration-count-computed.html": [
     [
      "css/css-animations/parsing/animation-iteration-count-computed.html",
@@ -201678,6 +202056,12 @@
      {}
     ]
    ],
+   "css/css-animations/parsing/animation-shorthand.html": [
+    [
+     "css/css-animations/parsing/animation-shorthand.html",
+     {}
+    ]
+   ],
    "css/css-animations/parsing/animation-timing-function-computed.html": [
     [
      "css/css-animations/parsing/animation-timing-function-computed.html",
@@ -201696,6 +202080,12 @@
      {}
     ]
    ],
+   "css/css-animations/parsing/animation-valid.html": [
+    [
+     "css/css-animations/parsing/animation-valid.html",
+     {}
+    ]
+   ],
    "css/css-animations/pending-style-changes-001.html": [
     [
      "css/css-animations/pending-style-changes-001.html",
@@ -202332,6 +202722,12 @@
      {}
     ]
    ],
+   "css/css-box/parsing/margin-shorthand.html": [
+    [
+     "css/css-box/parsing/margin-shorthand.html",
+     {}
+    ]
+   ],
    "css/css-box/parsing/margin-valid.html": [
     [
      "css/css-box/parsing/margin-valid.html",
@@ -202410,6 +202806,12 @@
      {}
     ]
    ],
+   "css/css-box/parsing/padding-shorthand.html": [
+    [
+     "css/css-box/parsing/padding-shorthand.html",
+     {}
+    ]
+   ],
    "css/css-box/parsing/padding-valid.html": [
     [
      "css/css-box/parsing/padding-valid.html",
@@ -202790,6 +203192,12 @@
      {}
     ]
    ],
+   "css/css-content/inheritance.html": [
+    [
+     "css/css-content/inheritance.html",
+     {}
+    ]
+   ],
    "css/css-device-adapt/documentElement-clientWidth-on-minimum-scale-size.tentative.html": [
     [
      "css/css-device-adapt/documentElement-clientWidth-on-minimum-scale-size.tentative.html",
@@ -203534,6 +203942,12 @@
      {}
     ]
    ],
+   "css/css-flexbox/parsing/flex-flow-shorthand.html": [
+    [
+     "css/css-flexbox/parsing/flex-flow-shorthand.html",
+     {}
+    ]
+   ],
    "css/css-flexbox/parsing/flex-flow-valid.html": [
     [
      "css/css-flexbox/parsing/flex-flow-valid.html",
@@ -203564,6 +203978,12 @@
      {}
     ]
    ],
+   "css/css-flexbox/parsing/flex-shorthand.html": [
+    [
+     "css/css-flexbox/parsing/flex-shorthand.html",
+     {}
+    ]
+   ],
    "css/css-flexbox/parsing/flex-shrink-computed.html": [
     [
      "css/css-flexbox/parsing/flex-shrink-computed.html",
@@ -205872,6 +206292,12 @@
      {}
     ]
    ],
+   "css/css-grid/grid-items/grid-item-dynamic-min-contribution-001.html": [
+    [
+     "css/css-grid/grid-items/grid-item-dynamic-min-contribution-001.html",
+     {}
+    ]
+   ],
    "css/css-grid/grid-items/grid-item-min-auto-size-001.html": [
     [
      "css/css-grid/grid-items/grid-item-min-auto-size-001.html",
@@ -206184,6 +206610,12 @@
      {}
     ]
    ],
+   "css/css-grid/parsing/grid-area-shorthand.html": [
+    [
+     "css/css-grid/parsing/grid-area-shorthand.html",
+     {}
+    ]
+   ],
    "css/css-grid/parsing/grid-area-valid.html": [
     [
      "css/css-grid/parsing/grid-area-valid.html",
@@ -206286,6 +206718,12 @@
      {}
     ]
    ],
+   "css/css-grid/parsing/grid-template-shorthand.html": [
+    [
+     "css/css-grid/parsing/grid-template-shorthand.html",
+     {}
+    ]
+   ],
    "css/css-grid/placement/grid-auto-placement-implicit-tracks-001.html": [
     [
      "css/css-grid/placement/grid-auto-placement-implicit-tracks-001.html",
@@ -206688,6 +207126,12 @@
      {}
     ]
    ],
+   "css/css-lists/parsing/list-style-shorthand.sub.html": [
+    [
+     "css/css-lists/parsing/list-style-shorthand.sub.html",
+     {}
+    ]
+   ],
    "css/css-lists/parsing/list-style-type-computed.html": [
     [
      "css/css-lists/parsing/list-style-type-computed.html",
@@ -207024,6 +207468,12 @@
      {}
     ]
    ],
+   "css/css-logical/parsing/inset-shorthand.html": [
+    [
+     "css/css-logical/parsing/inset-shorthand.html",
+     {}
+    ]
+   ],
    "css/css-logical/parsing/inset-valid.html": [
     [
      "css/css-logical/parsing/inset-valid.html",
@@ -210798,6 +211248,12 @@
      {}
     ]
    ],
+   "css/css-text-decor/parsing/text-decoration-shorthand.html": [
+    [
+     "css/css-text-decor/parsing/text-decoration-shorthand.html",
+     {}
+    ]
+   ],
    "css/css-text-decor/parsing/text-decoration-skip-ink-computed.html": [
     [
      "css/css-text-decor/parsing/text-decoration-skip-ink-computed.html",
@@ -213192,6 +213648,12 @@
      {}
     ]
    ],
+   "css/css-transitions/parsing/transition-invalid.html": [
+    [
+     "css/css-transitions/parsing/transition-invalid.html",
+     {}
+    ]
+   ],
    "css/css-transitions/parsing/transition-property-computed.html": [
     [
      "css/css-transitions/parsing/transition-property-computed.html",
@@ -213210,6 +213672,12 @@
      {}
     ]
    ],
+   "css/css-transitions/parsing/transition-shorthand.html": [
+    [
+     "css/css-transitions/parsing/transition-shorthand.html",
+     {}
+    ]
+   ],
    "css/css-transitions/parsing/transition-timing-function-computed.html": [
     [
      "css/css-transitions/parsing/transition-timing-function-computed.html",
@@ -213228,6 +213696,12 @@
      {}
     ]
    ],
+   "css/css-transitions/parsing/transition-valid.html": [
+    [
+     "css/css-transitions/parsing/transition-valid.html",
+     {}
+    ]
+   ],
    "css/css-transitions/properties-value-001.html": [
     [
      "css/css-transitions/properties-value-001.html",
@@ -213346,12 +213820,6 @@
      {}
     ]
    ],
-   "css/css-transitions/transition-timing-function-001.html": [
-    [
-     "css/css-transitions/transition-timing-function-001.html",
-     {}
-    ]
-   ],
    "css/css-transitions/transitioncancel-001.html": [
     [
      "css/css-transitions/transitioncancel-001.html",
@@ -215586,6 +216054,12 @@
      {}
     ]
    ],
+   "css/css-ui/parsing/outline-shorthand.html": [
+    [
+     "css/css-ui/parsing/outline-shorthand.html",
+     {}
+    ]
+   ],
    "css/css-ui/parsing/outline-style-computed.html": [
     [
      "css/css-ui/parsing/outline-style-computed.html",
@@ -215832,6 +216306,24 @@
      {}
     ]
    ],
+   "css/css-values/clamp-length-computed.html": [
+    [
+     "css/css-values/clamp-length-computed.html",
+     {}
+    ]
+   ],
+   "css/css-values/clamp-length-invalid.html": [
+    [
+     "css/css-values/clamp-length-invalid.html",
+     {}
+    ]
+   ],
+   "css/css-values/clamp-length-serialize.html": [
+    [
+     "css/css-values/clamp-length-serialize.html",
+     {}
+    ]
+   ],
    "css/css-values/getComputedStyle-border-radius-001.html": [
     [
      "css/css-values/getComputedStyle-border-radius-001.html",
@@ -218260,6 +218752,12 @@
      {}
     ]
    ],
+   "css/mediaqueries/aspect-ratio-serialization.html": [
+    [
+     "css/mediaqueries/aspect-ratio-serialization.html",
+     {}
+    ]
+   ],
    "css/mediaqueries/forced-colors.html": [
     [
      "css/mediaqueries/forced-colors.html",
@@ -220917,6 +221415,12 @@
      {}
     ]
    ],
+   "dom/nodes/MutationObserver-sanity.html": [
+    [
+     "dom/nodes/MutationObserver-sanity.html",
+     {}
+    ]
+   ],
    "dom/nodes/MutationObserver-takeRecords.html": [
     [
      "dom/nodes/MutationObserver-takeRecords.html",
@@ -242302,6 +242806,12 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-remove-from-document-different-load.html": [
+    [
+     "html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-remove-from-document-different-load.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-remove-from-document-networkState.html": [
     [
      "html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-remove-from-document-networkState.html",
@@ -251929,6 +252439,12 @@
      {}
     ]
    ],
+   "infrastructure/expected-fail/unhandled-rejection.html": [
+    [
+     "infrastructure/expected-fail/unhandled-rejection.html",
+     {}
+    ]
+   ],
    "infrastructure/server/context.any.js": [
     [
      "infrastructure/server/context.any.html",
@@ -252517,6 +253033,12 @@
      {}
     ]
    ],
+   "intersection-observer/same-origin-grand-child-iframe.sub.html": [
+    [
+     "intersection-observer/same-origin-grand-child-iframe.sub.html",
+     {}
+    ]
+   ],
    "intersection-observer/shadow-content.html": [
     [
      "intersection-observer/shadow-content.html",
@@ -268840,6 +269362,12 @@
      }
     ]
    ],
+   "permissions/permissions-query-feature-policy-attribute.https.sub.html": [
+    [
+     "permissions/permissions-query-feature-policy-attribute.https.sub.html",
+     {}
+    ]
+   ],
    "permissions/test-background-fetch-permission.html": [
     [
      "permissions/test-background-fetch-permission.html",
@@ -269843,6 +270371,12 @@
      {}
     ]
    ],
+   "portals/portals-repeated-activate.html": [
+    [
+     "portals/portals-repeated-activate.html",
+     {}
+    ]
+   ],
    "portals/portals-set-src-after-activate.html": [
     [
      "portals/portals-set-src-after-activate.html",
@@ -284908,6 +285442,14 @@
      }
     ]
    ],
+   "shadow-dom/focus/focus-selector-delegatesFocus.html": [
+    [
+     "shadow-dom/focus/focus-selector-delegatesFocus.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
    "shadow-dom/focus/focus-tabindex-order-shadow-negative.html": [
     [
      "shadow-dom/focus/focus-tabindex-order-shadow-negative.html",
@@ -306855,6 +307397,23 @@
      {}
     ]
    ],
+   "webxr/ar-module/idlharness.https.window.js": [
+    [
+     "webxr/ar-module/idlharness.https.window.html",
+     {
+      "script_metadata": [
+       [
+        "script",
+        "/resources/WebIDLParser.js"
+       ],
+       [
+        "script",
+        "/resources/idlharness.js"
+       ]
+      ]
+     }
+    ]
+   ],
    "webxr/events_input_source_recreation.https.html": [
     [
      "webxr/events_input_source_recreation.https.html",
@@ -306891,6 +307450,23 @@
      {}
     ]
    ],
+   "webxr/gamepads-module/idlharness.https.window.js": [
+    [
+     "webxr/gamepads-module/idlharness.https.window.html",
+     {
+      "script_metadata": [
+       [
+        "script",
+        "/resources/WebIDLParser.js"
+       ],
+       [
+        "script",
+        "/resources/idlharness.js"
+       ]
+      ]
+     }
+    ]
+   ],
    "webxr/getInputPose_handedness.https.html": [
     [
      "webxr/getInputPose_handedness.https.html",
@@ -321931,7 +322507,7 @@
    "testharness"
   ],
   "2dcontext/imagebitmap/createImageBitmap-invalid-args.html": [
-   "004b3ca6bf39eb7613d2621c8a431df5ab52278b",
+   "c64371eaa8c7940a78ff064b5cffac575607d230",
    "testharness"
   ],
   "2dcontext/imagebitmap/createImageBitmap-origin.sub.html": [
@@ -324259,15 +324835,15 @@
    "testharness"
   ],
   "IndexedDB/fire-error-event-exception.html": [
-   "fe0dc182567af2a48b4be82d809b97baf469fb3e",
+   "0a3f12265894f03adfb2b6577e5d35dbf0c89c5d",
    "testharness"
   ],
   "IndexedDB/fire-success-event-exception.html": [
-   "c4e55066bbab9069e744c089f81df0714ad4db19",
+   "ab0ac44eb7c33ba5f62caa6dca49935c8296cf26",
    "testharness"
   ],
   "IndexedDB/fire-upgradeneeded-event-exception.html": [
-   "5db452ebafe68a095f083b65a713ba3e0ad40cf5",
+   "1a8163a58b15606e2f00bc6439238c03267ce83b",
    "testharness"
   ],
   "IndexedDB/get-databases.any.js": [
@@ -325663,7 +326239,7 @@
    "testharness"
   ],
   "IndexedDB/transaction-relaxed-durability.tentative.any.js": [
-   "c6a6f37ba9e0b29dc17fe66e487920acf2c4ecc6",
+   "2ba96ec08edd3e35c85bef4712a94a9a75174624",
    "testharness"
   ],
   "IndexedDB/transaction-requestqueue.htm": [
@@ -337290,6 +337866,14 @@
    "91adbfce2d32ec1f46853b4af60b14c74468a842",
    "reftest"
   ],
+  "css/CSS2/floats/new-fc-beside-float-with-margin-rtl.html": [
+   "5a564f7831c9c19ff7c464c676981c62a53c9a88",
+   "reftest"
+  ],
+  "css/CSS2/floats/new-fc-beside-float-with-margin.html": [
+   "ead8e548be95df87220881a8e66e5f3a47c93f9b",
+   "reftest"
+  ],
   "css/CSS2/floats/new-fc-relayout.html": [
    "97d8b9a2ff1f3be8aeab2c26817e7542511c59cb",
    "reftest"
@@ -337338,8 +337922,8 @@
    "4ac426fe6bee576a9a54c2ed2143c7829e901f23",
    "testharness"
   ],
-  "css/CSS2/floats/zero-width-floats-positioning.html": [
-   "7f8e34daaef68356aa7b9fc4216cf918d93cc6cf",
+  "css/CSS2/floats/zero-width-floats-positioning.tentative.html": [
+   "18f8f6e2046693faf5b46e107a2dd3fa3aca8558",
    "reftest"
   ],
   "css/CSS2/floats/zero-width-floats.html": [
@@ -349779,7 +350363,7 @@
    "testharness"
   ],
   "css/css-animations/parsing/animation-delay-invalid.html": [
-   "a58d2cd11bc572d3a7899fb70b8b04adbd76a713",
+   "52e42a2e2b67a0593f264b57d99b6e9034a835a3",
    "testharness"
   ],
   "css/css-animations/parsing/animation-delay-valid.html": [
@@ -349791,7 +350375,7 @@
    "testharness"
   ],
   "css/css-animations/parsing/animation-direction-invalid.html": [
-   "0b48d97f0a1bb670daec7335049aa486810a2cde",
+   "5c96216d045c665f2005feb2cae642aad5d7f6f6",
    "testharness"
   ],
   "css/css-animations/parsing/animation-direction-valid.html": [
@@ -349803,7 +350387,7 @@
    "testharness"
   ],
   "css/css-animations/parsing/animation-duration-invalid.html": [
-   "5edacd3735e4f3ac0c0724415b3ca0052f10d33b",
+   "bd8cf2adfe98954d43f3e4d3b7f839d6f59b0e96",
    "testharness"
   ],
   "css/css-animations/parsing/animation-duration-valid.html": [
@@ -349815,19 +350399,23 @@
    "testharness"
   ],
   "css/css-animations/parsing/animation-fill-mode-invalid.html": [
-   "dda2221f4746a64778ea4c5a82fa42c35243a342",
+   "2a82f2354639feb9abbba32b7159a0de1f1a18c4",
    "testharness"
   ],
   "css/css-animations/parsing/animation-fill-mode-valid.html": [
    "1f73a821d15119d6a8fc2720d53f6cefdd29fb5d",
    "testharness"
   ],
+  "css/css-animations/parsing/animation-invalid.html": [
+   "c5790a3fafa4cbdb73126c98596506e3ed796310",
+   "testharness"
+  ],
   "css/css-animations/parsing/animation-iteration-count-computed.html": [
    "0ac53aa65184020b65669807c699ef6c55362af2",
    "testharness"
   ],
   "css/css-animations/parsing/animation-iteration-count-invalid.html": [
-   "ff1e8e23a08cf58c08922eb40145e916852c0562",
+   "621340f7c3d87b7edb19a3db94e9dc759014d7c8",
    "testharness"
   ],
   "css/css-animations/parsing/animation-iteration-count-valid.html": [
@@ -349859,25 +350447,33 @@
    "testharness"
   ],
   "css/css-animations/parsing/animation-play-state-invalid.html": [
-   "f47a2f75ddfc35a279037ada8df34077bd1308ab",
+   "91a6f017370a7cf6089d610e2666f64c61a8c98f",
    "testharness"
   ],
   "css/css-animations/parsing/animation-play-state-valid.html": [
    "ce6d053ec2736ec8d5e8420b3d1a1e4f07fd04ed",
    "testharness"
   ],
+  "css/css-animations/parsing/animation-shorthand.html": [
+   "2e3053e7afcc6eaa7cd2b3912b37b80295ea426d",
+   "testharness"
+  ],
   "css/css-animations/parsing/animation-timing-function-computed.html": [
    "99bc12ccaa8f24ae5db06cfd0d78d3bd0c015bef",
    "testharness"
   ],
   "css/css-animations/parsing/animation-timing-function-invalid.html": [
-   "adc1cc10e39d09df78c4398ffca008739d751076",
+   "621145b0e004c583d4a0131eb10d4875fe17da3b",
    "testharness"
   ],
   "css/css-animations/parsing/animation-timing-function-valid.html": [
    "7ab823ea1da1535606ac4aad30fb21f423ba6703",
    "testharness"
   ],
+  "css/css-animations/parsing/animation-valid.html": [
+   "65de3c6fcfed3f69fa798fa19425bdc054e0700b",
+   "testharness"
+  ],
   "css/css-animations/pending-style-changes-001.html": [
    "fb74d7fa7d062d60153d47913df9eb2b0c7267c8",
    "testharness"
@@ -349926,8 +350522,12 @@
    "3e7843b8a07577970279ef9a4e14bfb83c1816f0",
    "testharness"
   ],
+  "css/css-backgrounds/animations/border-image-outset-interpolation-expected.txt": [
+   "6ca6cb7701110980a1adbf8f5e1cde9edda2cba6",
+   "support"
+  ],
   "css/css-backgrounds/animations/border-image-outset-interpolation.html": [
-   "d4726e87d119462a703cc7ac504e8025f3874680",
+   "aebadbbafb236a090aa543ecf82e5661bee7de74",
    "testharness"
   ],
   "css/css-backgrounds/animations/border-image-slice-interpolation.html": [
@@ -352786,10 +353386,6 @@
    "51c67b96ccb52ac09ef6d78e598506317ff784ab",
    "testharness"
   ],
-  "css/css-backgrounds/parsing/background-invalid-expected.txt": [
-   "4e890e2d1a745f42c8feed70f21e1be0d617182f",
-   "support"
-  ],
   "css/css-backgrounds/parsing/background-invalid.html": [
    "76ff18f35d1f7471f165c61d731f8838a8563059",
    "testharness"
@@ -352959,7 +353555,7 @@
    "testharness"
   ],
   "css/css-backgrounds/parsing/border-image-width-computed.html": [
-   "98e5616a22847c0536b25d8a96393aafa9c0a913",
+   "2c36eda8c785337eae8f3f3eefb2bf92e29b82a0",
    "testharness"
   ],
   "css/css-backgrounds/parsing/border-image-width-invalid.html": [
@@ -353726,6 +354322,10 @@
    "77009170938d9634497f73bc21501ced502c7008",
    "testharness"
   ],
+  "css/css-box/parsing/margin-shorthand.html": [
+   "293927983e504a3227335944ab05f966d51cccd6",
+   "testharness"
+  ],
   "css/css-box/parsing/margin-valid.html": [
    "154aa2de7cb16ca0845f8368e731ec5c941108cb",
    "testharness"
@@ -353786,6 +354386,10 @@
    "3e3a560c2f71877494577f9dbc5c2eecfbab8a62",
    "testharness"
   ],
+  "css/css-box/parsing/padding-shorthand.html": [
+   "dc0139dc47a70688cd8667e6069b4ba5654b7b1c",
+   "testharness"
+  ],
   "css/css-box/parsing/padding-valid.html": [
    "0d3d51e86bb015dd5720041cdae671a29a74c77b",
    "testharness"
@@ -354034,6 +354638,14 @@
    "f68b7c046d9d22994dbc78c722b5004f1253027f",
    "reftest"
   ],
+  "css/css-cascade/all-prop-initial-visited-ref.html": [
+   "f596b559b0e26b9c03d47b7dcab966a4d091308b",
+   "support"
+  ],
+  "css/css-cascade/all-prop-initial-visited.html": [
+   "6fb7936652a77dade7d5e72032064b67d2886637",
+   "reftest"
+  ],
   "css/css-cascade/all-prop-initial-xml.html": [
    "a04956a52d1f120583c26a462356ba8e47ac1277",
    "testharness"
@@ -356218,6 +356830,14 @@
    "a78e9f713b2428763ed4244aae1b6269a15d6637",
    "reftest"
   ],
+  "css/css-content/inheritance-expected.txt": [
+   "a75fca4057ea2537d7cfdae56699339451ba0109",
+   "support"
+  ],
+  "css/css-content/inheritance.html": [
+   "a3242556fdcb4d5fea0d4d28fba6067ed02b340c",
+   "testharness"
+  ],
   "css/css-content/pseudo-element-inline-box-ref.html": [
    "8294ae672d15643b1d8eeb8c9914fa93fe4e879a",
    "support"
@@ -359898,6 +360518,10 @@
    "e82c284632dd5b3babbd3979958874013bf3b9aa",
    "testharness"
   ],
+  "css/css-flexbox/parsing/flex-flow-shorthand.html": [
+   "6ae19bdc044dd31b11448e407204accfb0340632",
+   "testharness"
+  ],
   "css/css-flexbox/parsing/flex-flow-valid.html": [
    "01acd435096db60d214a0b07cb24fccdfded9c93",
    "testharness"
@@ -359918,6 +360542,10 @@
    "ae010d7b4b4540f6591c1ad42f1c89753a71afc6",
    "testharness"
   ],
+  "css/css-flexbox/parsing/flex-shorthand.html": [
+   "51e01794154edbe475e57d2ca6fb93de65dea8bd",
+   "testharness"
+  ],
   "css/css-flexbox/parsing/flex-shrink-computed.html": [
    "69a6d8c52b61f162f9c7333f53ed44145e51913f",
    "testharness"
@@ -359975,7 +360603,7 @@
    "reftest"
   ],
   "css/css-flexbox/percentage-heights-003.html": [
-   "9d434cf7cb8ba2023c126391032985d3d3b7c5d9",
+   "c27af532169a349be42379ab9949afec15b47ae2",
    "testharness"
   ],
   "css/css-flexbox/percentage-heights-004-ref.html": [
@@ -370538,6 +371166,10 @@
    "b36fbb2bbc8ce403632769e1a098f9560e910221",
    "reftest"
   ],
+  "css/css-grid/grid-items/grid-item-dynamic-min-contribution-001.html": [
+   "c4ced6b2a12e0f080d6df2fccc8f74270f45683c",
+   "testharness"
+  ],
   "css/css-grid/grid-items/grid-item-min-auto-size-001.html": [
    "f50e9ef312418f4d3b737bd55b4a7e5c75f09230",
    "testharness"
@@ -370646,6 +371278,54 @@
    "e45530b2fd4a380ba62c3b42ba52157cec098a00",
    "testharness"
   ],
+  "css/css-grid/grid-items/grid-items-percentage-margins-003.html": [
+   "03d5d7f2c499b00cda96b8235a11852998900259",
+   "reftest"
+  ],
+  "css/css-grid/grid-items/grid-items-percentage-margins-004.html": [
+   "52e6f3bf1a688af98bd28d68f8d7e0ddde3ebee5",
+   "reftest"
+  ],
+  "css/css-grid/grid-items/grid-items-percentage-margins-005.html": [
+   "9cff92d1aa0ccdf2aa2dd0c89b4bd626778d1214",
+   "reftest"
+  ],
+  "css/css-grid/grid-items/grid-items-percentage-margins-006.html": [
+   "04d30e3edfc9920fb22f645549b00497ba0241fb",
+   "reftest"
+  ],
+  "css/css-grid/grid-items/grid-items-percentage-margins-007.html": [
+   "2906fe0608704a1b8413fa7a24db140667254283",
+   "reftest"
+  ],
+  "css/css-grid/grid-items/grid-items-percentage-margins-008.html": [
+   "7bd2e0fc5f4f24b35ff37c61c0b20c1b2ab61571",
+   "reftest"
+  ],
+  "css/css-grid/grid-items/grid-items-percentage-margins-009.html": [
+   "70a6c231dc91b1b2f866e9cd4463860ce9f58c4f",
+   "reftest"
+  ],
+  "css/css-grid/grid-items/grid-items-percentage-margins-010.html": [
+   "34352f60020ec44e4d5f27344818bdb476de694e",
+   "reftest"
+  ],
+  "css/css-grid/grid-items/grid-items-percentage-margins-011.html": [
+   "36bd208df007332656acbb4b3ffb5aac86675c82",
+   "reftest"
+  ],
+  "css/css-grid/grid-items/grid-items-percentage-margins-012.html": [
+   "9cdc15337a936724b8ce157638544f4f9e35b65c",
+   "reftest"
+  ],
+  "css/css-grid/grid-items/grid-items-percentage-margins-013.html": [
+   "581415b828e6d54056fe94e5145e276e7e428352",
+   "reftest"
+  ],
+  "css/css-grid/grid-items/grid-items-percentage-margins-014.html": [
+   "5766e60339a0d83568c93a7f750976dbb9955e6a",
+   "reftest"
+  ],
   "css/css-grid/grid-items/grid-items-percentage-margins-vertical-lr-001.html": [
    "aa0ff96985878c5f21d7e7a8175b1351e9841656",
    "testharness"
@@ -370670,6 +371350,54 @@
    "3175469fb08361398658ebcfabb553909aa9c080",
    "testharness"
   ],
+  "css/css-grid/grid-items/grid-items-percentage-paddings-003.html": [
+   "d85a6c1abcfac6c2ecf6bfc1251ba41b58fbab89",
+   "reftest"
+  ],
+  "css/css-grid/grid-items/grid-items-percentage-paddings-004.html": [
+   "26302daf2d606637930ea41971f3d6066f782a2b",
+   "reftest"
+  ],
+  "css/css-grid/grid-items/grid-items-percentage-paddings-005.html": [
+   "151b604f9bb7c7defdb5edf558ed207777cc0903",
+   "reftest"
+  ],
+  "css/css-grid/grid-items/grid-items-percentage-paddings-006.html": [
+   "bcbc7ced73a77ebfb1e2aa027383f868bf38fe87",
+   "reftest"
+  ],
+  "css/css-grid/grid-items/grid-items-percentage-paddings-007.html": [
+   "d4cf80c18df05bf06406eccf8aefe7050ed4025f",
+   "reftest"
+  ],
+  "css/css-grid/grid-items/grid-items-percentage-paddings-008.html": [
+   "38f766b5cfffcca21906203c8c3472dd1230b197",
+   "reftest"
+  ],
+  "css/css-grid/grid-items/grid-items-percentage-paddings-009.html": [
+   "eb1d1f47f28c3daefd78e9e98881459f91c2046d",
+   "reftest"
+  ],
+  "css/css-grid/grid-items/grid-items-percentage-paddings-010.html": [
+   "ecd430c68d41698b328341eb9d9e2daba2a7848c",
+   "reftest"
+  ],
+  "css/css-grid/grid-items/grid-items-percentage-paddings-011.html": [
+   "e394ced4e6e52f3379428d3ad854bcab0b3cb38d",
+   "reftest"
+  ],
+  "css/css-grid/grid-items/grid-items-percentage-paddings-012.html": [
+   "07b2d27b58173a84851c4836c85281efa818c2e4",
+   "reftest"
+  ],
+  "css/css-grid/grid-items/grid-items-percentage-paddings-013.html": [
+   "9b6c2bfe0ad261358ff7657752bd3bc3dff0896d",
+   "reftest"
+  ],
+  "css/css-grid/grid-items/grid-items-percentage-paddings-014.html": [
+   "9e67960913a25f0fe1cfe137ceca5d11ebf0b43f",
+   "reftest"
+  ],
   "css/css-grid/grid-items/grid-items-percentage-paddings-vertical-lr-001.html": [
    "6ad624a0a262067eb6e3b0724989ab01ca04f6a1",
    "testharness"
@@ -371290,6 +372018,10 @@
    "b989322775eb7dbf273a3dc3fbb3d1af31f524ba",
    "testharness"
   ],
+  "css/css-grid/parsing/grid-area-shorthand.html": [
+   "9a265502d5c0dfd1b2ebb7ed54b81514216af826",
+   "testharness"
+  ],
   "css/css-grid/parsing/grid-area-valid.html": [
    "8e7d0d43d1cfac44935593892b67fdb40b179791",
    "testharness"
@@ -371299,7 +372031,7 @@
    "testharness"
   ],
   "css/css-grid/parsing/grid-auto-columns-invalid.html": [
-   "40b6059a7e8b564a4aef5393a7be77cbaa1ff4a2",
+   "04e0fadf0df2824a499bede7f2fe80e410a29e1a",
    "testharness"
   ],
   "css/css-grid/parsing/grid-auto-columns-valid.html": [
@@ -371331,7 +372063,7 @@
    "testharness"
   ],
   "css/css-grid/parsing/grid-auto-rows-invalid.html": [
-   "4111e2563365579b3810c701a782df54dce3c61e",
+   "1b61479f3c2f51c23a3be59a7d90b179de1407ca",
    "testharness"
   ],
   "css/css-grid/parsing/grid-auto-rows-valid.html": [
@@ -371355,7 +372087,7 @@
    "testharness"
   ],
   "css/css-grid/parsing/grid-template-columns-valid.html": [
-   "85ac76a999aab5adf628a8e38f626fcae299d12f",
+   "6bf2e7bce63c88d028f5dea1bf3e7be8cab7775c",
    "testharness"
   ],
   "css/css-grid/parsing/grid-template-rows-invalid.html": [
@@ -371363,7 +372095,11 @@
    "testharness"
   ],
   "css/css-grid/parsing/grid-template-rows-valid.html": [
-   "ec8d64f79bacc1d7831e415768c2a76bf05607e0",
+   "2d3a1ed8045c3eef9982cffc3f95415518f560cb",
+   "testharness"
+  ],
+  "css/css-grid/parsing/grid-template-shorthand.html": [
+   "b9165359a7250afab60463878b9beb8592424f58",
    "testharness"
   ],
   "css/css-grid/placement/grid-auto-placement-implicit-tracks-001.html": [
@@ -373270,6 +374006,10 @@
    "ff0c8366bb988fafe72746837a330801ae2fe34b",
    "testharness"
   ],
+  "css/css-lists/parsing/list-style-shorthand.sub.html": [
+   "140df208aab9e8c7811de14bd96b99bad7d89752",
+   "testharness"
+  ],
   "css/css-lists/parsing/list-style-type-computed-expected.txt": [
    "eabf33a193d5bbb194bcaa708f13b2f2e474d216",
    "support"
@@ -373594,6 +374334,10 @@
    "604b801c76040a5058612fd19c75ee66107081ed",
    "testharness"
   ],
+  "css/css-logical/parsing/inset-shorthand.html": [
+   "4557879129e006980d2775658aadece56458ba35",
+   "testharness"
+  ],
   "css/css-logical/parsing/inset-valid.html": [
    "2d8f937f075b0d0fbde677e15266f47af5fec3f8",
    "testharness"
@@ -379735,7 +380479,7 @@
    "testharness"
   ],
   "css/css-scroll-snap/scroll-margin.html": [
-   "c85232edf23876a1ab37d858c4d59940b183e01e",
+   "e6ce4ac49c01ff65823fd83ee6866a6019701f6e",
    "testharness"
   ],
   "css/css-scroll-snap/scroll-padding.html": [
@@ -383078,6 +383822,10 @@
    "3dd2d0c834ec8c7340b093a4c7a1272fb35a8a26",
    "testharness"
   ],
+  "css/css-text-decor/parsing/text-decoration-shorthand.html": [
+   "904313f0528de50541d88b3db89902bdbf721cfe",
+   "testharness"
+  ],
   "css/css-text-decor/parsing/text-decoration-skip-ink-computed.html": [
    "0b4807cec08a818c07a3d3bcaefc2092ecca9c14",
    "testharness"
@@ -395346,6 +396094,10 @@
    "8d0360a8ecf7a37b81acb10917b63abc7c9543cc",
    "testharness"
   ],
+  "css/css-transitions/idlharness-expected.txt": [
+   "3c9dbb02792fda31a8d3d92cda284d39e8876fa4",
+   "support"
+  ],
   "css/css-transitions/idlharness.html": [
    "4cc7ee50eb4915fcf95843f7eeee266abfa7b81a",
    "testharness"
@@ -395379,7 +396131,7 @@
    "testharness"
   ],
   "css/css-transitions/parsing/transition-delay-invalid.html": [
-   "b34d50551ce433ebe672c7fddb4a549582c754db",
+   "4b7a14328601ebf6f38e016d5844744bac1a3839",
    "testharness"
   ],
   "css/css-transitions/parsing/transition-delay-valid.html": [
@@ -395391,35 +396143,51 @@
    "testharness"
   ],
   "css/css-transitions/parsing/transition-duration-invalid.html": [
-   "fd0f341f4071b53561cf8b072bb105d3bd1a4563",
+   "4474089bbb0f89fdfc83a8436c7d5926e046256f",
    "testharness"
   ],
   "css/css-transitions/parsing/transition-duration-valid.html": [
    "311ca086695151747559a0995b61c7fe4c755592",
    "testharness"
   ],
+  "css/css-transitions/parsing/transition-invalid.html": [
+   "64310b13a15e982402e1d8c3b3d6daad5be67676",
+   "testharness"
+  ],
   "css/css-transitions/parsing/transition-property-computed.html": [
    "1e8cfeb22ddfbba2225494e16fdb0b27732a3ed0",
    "testharness"
   ],
   "css/css-transitions/parsing/transition-property-invalid.html": [
-   "903a206eac13688a51ff2ba88552de67efa2e9cb",
+   "715e13d7a249d8762350070c7c47aa8043297b54",
    "testharness"
   ],
   "css/css-transitions/parsing/transition-property-valid.html": [
    "4e3894f5aa94e00aa59406ee1aab92b9226483af",
    "testharness"
   ],
+  "css/css-transitions/parsing/transition-shorthand.html": [
+   "caffb3978cf0162cb8616c6723c6cb93e33750b4",
+   "testharness"
+  ],
   "css/css-transitions/parsing/transition-timing-function-computed.html": [
-   "9834dfdbf0dde78d0d2c1b468c5badddc2460ac9",
+   "fa03b2295b9c2f92ab4e520cc75153d9eaa6e672",
    "testharness"
   ],
   "css/css-transitions/parsing/transition-timing-function-invalid.html": [
-   "00bd2131e0927ba38e633ad7be404b8ec26e51a9",
+   "c69b7e75d3d3ef31df4f6ec927b8fbf2032484d6",
    "testharness"
   ],
+  "css/css-transitions/parsing/transition-timing-function-valid-expected.txt": [
+   "0d8cfd02f6de0911b4d3437540aabb51aa41c606",
+   "support"
+  ],
   "css/css-transitions/parsing/transition-timing-function-valid.html": [
-   "2e2c1827bfbef9d4cc58e32ec88da3c7fd614225",
+   "5402fdac195b2dc2d68553d593e1924f5c3be695",
+   "testharness"
+  ],
+  "css/css-transitions/parsing/transition-valid.html": [
+   "c4651f5f125f40c0ec75f6d58b2641fa78b47cf0",
    "testharness"
   ],
   "css/css-transitions/properties-value-001-expected.txt": [
@@ -395714,36 +396482,36 @@
    "9a74bebfb7a45765cac3693b1461953ea75cef92",
    "testharness"
   ],
-  "css/css-transitions/transition-delay-000.html": [
-   "2b4cedbb52405903e367ea6ca7a39dcca3b167b6",
+  "css/css-transitions/transition-delay-000-manual.html": [
+   "b205085997ced154dd81e5085dbc6a0cfce19045",
    "manual"
   ],
   "css/css-transitions/transition-delay-001.html": [
    "921525ea72d2e1e28d2321c1594085deaf2330f0",
    "testharness"
   ],
-  "css/css-transitions/transition-delay-002.html": [
-   "70e952b308c35affc5f7bdfbc66326df49ba6397",
+  "css/css-transitions/transition-delay-002-manual.html": [
+   "168f94b9c054b481df7ccea0c5e07b8643715c8c",
    "manual"
   ],
-  "css/css-transitions/transition-delay-003.html": [
-   "3062e9a4842dcb5ecfd3b59c26260b412cd3b573",
+  "css/css-transitions/transition-delay-003-manual.html": [
+   "e3680ca2615ab3d490467101c047a42153a46d61",
    "manual"
   ],
   "css/css-transitions/transition-duration-001.html": [
    "b5c095f001efb373934850db67527ace118e10cd",
    "testharness"
   ],
-  "css/css-transitions/transition-duration-002.html": [
-   "e9ba5760c605e28e698411f73f3280cc453b9637",
+  "css/css-transitions/transition-duration-002-manual.html": [
+   "03f514d365d165d777e43f83142e801f4f9833d9",
    "manual"
   ],
-  "css/css-transitions/transition-duration-003.html": [
-   "bb68b5f51c1a5c6dc84de7499599472bc286ad39",
+  "css/css-transitions/transition-duration-003-manual.html": [
+   "cb561008836236752f0ed37ad68159481e71596f",
    "manual"
   ],
-  "css/css-transitions/transition-duration-004.html": [
-   "01c42473319d90130f9aec5df39a28a287aff7ed",
+  "css/css-transitions/transition-duration-004-manual.html": [
+   "b93904bb7667b7c5afa7f9fdcd3dad524e2f9f41",
    "manual"
   ],
   "css/css-transitions/transition-property-001.html": [
@@ -395758,176 +396526,176 @@
    "99196b6d1d4ec86be77930d578602110b6a7deb6",
    "testharness"
   ],
-  "css/css-transitions/transition-property-003.html": [
-   "17668b053e83e102565e341dd337ffc2b4544cf4",
+  "css/css-transitions/transition-property-003-manual.html": [
+   "291204d5752e5fcb9c7b8fb8ef32a95d7d4b1813",
    "manual"
   ],
-  "css/css-transitions/transition-property-004.html": [
-   "6393c6e3d54f59e8ae9cde42eda248d0c891f68d",
+  "css/css-transitions/transition-property-004-manual.html": [
+   "d2e84c99d69003d46c439ce6c623594390701a2a",
    "manual"
   ],
-  "css/css-transitions/transition-property-005.html": [
-   "a10ff4a3c1acd4cf31d18bc510f228ed416085ae",
+  "css/css-transitions/transition-property-005-manual.html": [
+   "e69941001bca8c441cdb66aaf4582d7e3c336afc",
    "manual"
   ],
-  "css/css-transitions/transition-property-006.html": [
-   "e7d8c5e39462d526b4ee60f97046fe14f5e904a1",
+  "css/css-transitions/transition-property-006-manual.html": [
+   "6032a401d0cfea4a717a3c07ebaca841857aef72",
    "manual"
   ],
-  "css/css-transitions/transition-property-007.html": [
-   "0d006fe9b0b1101a03528aa085ceda850deb621c",
+  "css/css-transitions/transition-property-007-manual.html": [
+   "898aea5b2079caa0d66a94b673feb8e42ee69dfc",
    "manual"
   ],
-  "css/css-transitions/transition-property-008.html": [
-   "47ca1eee1053ca272eb72f3b6e5eaaa1a9343807",
+  "css/css-transitions/transition-property-008-manual.html": [
+   "53caa1028a47fafec6b2d07a3aa58e7c709cd2d8",
    "manual"
   ],
-  "css/css-transitions/transition-property-009.html": [
-   "b45948b9dd6040af8dd3f2e7dfdcec1c6002cd58",
+  "css/css-transitions/transition-property-009-manual.html": [
+   "5f272854eb2e3f3ebf1dcd8f5130ef100218ec28",
    "manual"
   ],
-  "css/css-transitions/transition-property-010.html": [
-   "f05f6aa133e2852aa75b7fa43dc3637964ad1741",
+  "css/css-transitions/transition-property-010-manual.html": [
+   "a7e06ef78072f6ea6944e35495e1be70b232c499",
    "manual"
   ],
-  "css/css-transitions/transition-property-011.html": [
-   "7b3716dde8adfc3cab36d38115a83702388808d8",
+  "css/css-transitions/transition-property-011-manual.html": [
+   "3799ad212aebddb60c3f1818129e7a4d71e5bfb7",
    "manual"
   ],
-  "css/css-transitions/transition-property-012.html": [
-   "0e19e52d62abcfd5d4f3852000ce99634a860b3d",
+  "css/css-transitions/transition-property-012-manual.html": [
+   "8587e264119c455f1d7bb8d882c3a290e3248124",
    "manual"
   ],
-  "css/css-transitions/transition-property-013.html": [
-   "9fb075b09d2b0f04556916cbb4afcbf29e0a021b",
+  "css/css-transitions/transition-property-013-manual.html": [
+   "3b13c038161e1a2037f838c8133330425a42e700",
    "manual"
   ],
-  "css/css-transitions/transition-property-014.html": [
-   "91075ff638f32d1b6f958019c7862fdf171f0475",
+  "css/css-transitions/transition-property-014-manual.html": [
+   "d4aca3805b3b983bc1e3363abd8ba5b33ea71ef7",
    "manual"
   ],
-  "css/css-transitions/transition-property-015.html": [
-   "b37d4fc9a7beae894eb63fb98aa3fe9d6dcc039f",
+  "css/css-transitions/transition-property-015-manual.html": [
+   "e5805bc4ba6882394c1b45932ce97eaab71afc43",
    "manual"
   ],
-  "css/css-transitions/transition-property-016.html": [
-   "2670cd7385222e0959553c376193ea94e76ade39",
+  "css/css-transitions/transition-property-016-manual.html": [
+   "d2cc57cd9796d819aa914dcad7ff0525266cb64e",
    "manual"
   ],
-  "css/css-transitions/transition-property-017.html": [
-   "3b94ecde0c51b82d4650834181c25718576fd327",
+  "css/css-transitions/transition-property-017-manual.html": [
+   "f24c51a7383b76c2dd56db5e1d69eb6c3808cc0c",
    "manual"
   ],
-  "css/css-transitions/transition-property-018.html": [
-   "593e3ff71944fde48c84ae99191242a9078ea5ee",
+  "css/css-transitions/transition-property-018-manual.html": [
+   "e0b6bd955b5e2b65b131d21f5ea5a646c00afed0",
    "manual"
   ],
-  "css/css-transitions/transition-property-019.html": [
-   "83f900005469647bd05cf7080e41fd59c1b641ef",
+  "css/css-transitions/transition-property-019-manual.html": [
+   "24751292c2886a761e90ed009543768747ffff29",
    "manual"
   ],
-  "css/css-transitions/transition-property-020.html": [
-   "af0aea41bcd4615825a961778ab499f61a718f8a",
+  "css/css-transitions/transition-property-020-manual.html": [
+   "e4f7b577920f321453e5a25aadc1d814c4e3ac91",
    "manual"
   ],
-  "css/css-transitions/transition-property-021.html": [
-   "f499c9aee43f50bb0a74acfba1fa412976a994ad",
+  "css/css-transitions/transition-property-021-manual.html": [
+   "c0492223bbf6043cd5b93f9290640bceaf53f338",
    "manual"
   ],
-  "css/css-transitions/transition-property-022.html": [
-   "f36954902e3667eb305340075d5952344cc62bbd",
+  "css/css-transitions/transition-property-022-manual.html": [
+   "ece1a32eb09ee3baf7f38ca39da5530774af81c8",
    "manual"
   ],
-  "css/css-transitions/transition-property-023.html": [
-   "81c8cadac422bcbb48b88a053ae0df564a0a0242",
+  "css/css-transitions/transition-property-023-manual.html": [
+   "267be61aa1560646ffcb12693f4783942242a51c",
    "manual"
   ],
-  "css/css-transitions/transition-property-024.html": [
-   "b0e9d41dbc0dd0628adf9894fb6811f559efa45a",
+  "css/css-transitions/transition-property-024-manual.html": [
+   "fad3d7ac239ceb28f26d6ae40a2eff88af7690aa",
    "manual"
   ],
-  "css/css-transitions/transition-property-025.html": [
-   "bfa6f698930d13412d6c19a424aefb2c566c27a7",
+  "css/css-transitions/transition-property-025-manual.html": [
+   "c0f276184894a29f1abd5eb46322f6b0a4a5ffe5",
    "manual"
   ],
-  "css/css-transitions/transition-property-026.html": [
-   "d6f0481bea7ad1b54ba2d44efd62513ec834b221",
+  "css/css-transitions/transition-property-026-manual.html": [
+   "35846e3fb5334cf049f1031e6c542e46105ba5f8",
    "manual"
   ],
-  "css/css-transitions/transition-property-027.html": [
-   "01f50dc475ab5fd3ad0f7094d7efa1db0ad362b9",
+  "css/css-transitions/transition-property-027-manual.html": [
+   "5ad5f5d5bd5187593a421b261758227e464f5204",
    "manual"
   ],
-  "css/css-transitions/transition-property-028.html": [
-   "83d8751109b1e29e76aaa98fedce03f205b68a63",
+  "css/css-transitions/transition-property-028-manual.html": [
+   "be319d2c21204d6ba6bbdb1e6be454782a49203a",
    "manual"
   ],
-  "css/css-transitions/transition-property-029.html": [
-   "fb435c91249d691862b24a63f5f5b9c35166afb8",
+  "css/css-transitions/transition-property-029-manual.html": [
+   "84c55326fe8ab2c5f3b20d07939a15de60ba42d0",
    "manual"
   ],
-  "css/css-transitions/transition-property-030.html": [
-   "286af42e12cc2c8249d1bc1e2ca14f3aedba0293",
+  "css/css-transitions/transition-property-030-manual.html": [
+   "ba75f7ce725f320cf4d478273adfa22e47f5ff6a",
    "manual"
   ],
-  "css/css-transitions/transition-property-031.html": [
-   "d5bf23276f7e594f77f86f9b292fe134a57aabed",
+  "css/css-transitions/transition-property-031-manual.html": [
+   "14cf23c6bdc649f09862f2a573008171177a882f",
    "manual"
   ],
-  "css/css-transitions/transition-property-032.html": [
-   "020a8573c8729efeb49e1bde33d7942c8f89f70f",
+  "css/css-transitions/transition-property-032-manual.html": [
+   "c6596608ed13fd93ce60c1ca5d05f5dabd8e6157",
    "manual"
   ],
-  "css/css-transitions/transition-property-033.html": [
-   "fcb999fa079be9df7569e57af8019d93b8b9905b",
+  "css/css-transitions/transition-property-033-manual.html": [
+   "fd7646c66bc47827794ebd0792b7586216dbe2af",
    "manual"
   ],
-  "css/css-transitions/transition-property-034.html": [
-   "b4da3a9bca07ba24040e1723baa4662c1d83af95",
+  "css/css-transitions/transition-property-034-manual.html": [
+   "07804121c9c862b4bcc2e1babf9c65c17d71e206",
    "manual"
   ],
-  "css/css-transitions/transition-property-035.html": [
-   "27c9ea9e1d8e8721224bd3bbe46405dffbcab90f",
+  "css/css-transitions/transition-property-035-manual.html": [
+   "4a9e9b128fd5402c97bb64fdbaaa1706814c18c5",
    "manual"
   ],
-  "css/css-transitions/transition-property-036.html": [
-   "326e615398c5905e92bdacec50b22effa23b3572",
+  "css/css-transitions/transition-property-036-manual.html": [
+   "746bc409ee0e92d6e0588079dff63e4a0e89a68d",
    "manual"
   ],
-  "css/css-transitions/transition-property-037.html": [
-   "79ce16fb961c9f3bfceda7bf996afb7aef05381f",
+  "css/css-transitions/transition-property-037-manual.html": [
+   "d031caaaa405fcf57b44890ee97159f28d88fc42",
    "manual"
   ],
-  "css/css-transitions/transition-property-038.html": [
-   "5b16e41f578b70217b2ca1b406fb1a9d1f571248",
+  "css/css-transitions/transition-property-038-manual.html": [
+   "2f9302bad7593a24a6617a91d388202afed979ef",
    "manual"
   ],
-  "css/css-transitions/transition-property-039.html": [
-   "0ef6da528cb81c746c799ec2fb84c0c6f0f1d872",
+  "css/css-transitions/transition-property-039-manual.html": [
+   "bf0b209bdad43712bb42fdf41d14328b4d4ac5f8",
    "manual"
   ],
-  "css/css-transitions/transition-property-040.html": [
-   "b333f371f3f974467c745d4cbfa4165077c1aa61",
+  "css/css-transitions/transition-property-040-manual.html": [
+   "83a3cf802b3e00fc717d01de51f8824a15af71ed",
    "manual"
   ],
-  "css/css-transitions/transition-property-041.html": [
-   "b3386a0534f190d15e5251c31e59c05a779dc4af",
+  "css/css-transitions/transition-property-041-manual.html": [
+   "04f8351a0309f5b4e10c610a6c07325944492220",
    "manual"
   ],
-  "css/css-transitions/transition-property-042.html": [
-   "fbb3e2d8b1ad7208b40d669e70b5f41e75601c6a",
+  "css/css-transitions/transition-property-042-manual.html": [
+   "15977497fbb81be0a86f24ce52a7e6359e18bf98",
    "manual"
   ],
-  "css/css-transitions/transition-property-043.html": [
-   "b87dc84a85636d4c1cc32a4a2716b33ecf28b370",
+  "css/css-transitions/transition-property-043-manual.html": [
+   "3b939bcf0ab8d5800ac2e0088da0774f56e28028",
    "manual"
   ],
-  "css/css-transitions/transition-property-044.html": [
-   "f1d584fcf25396db414078066302ce2f7bb979f2",
+  "css/css-transitions/transition-property-044-manual.html": [
+   "d7c2f467492d9e234467956e3409b9665cee9e9d",
    "manual"
   ],
-  "css/css-transitions/transition-property-045.html": [
-   "3fa82c16d1f9e7f01760003c07bdfbc38afa060d",
+  "css/css-transitions/transition-property-045-manual.html": [
+   "912ed4df50ccc545c0a7c77f4cc43c0b75104c4a",
    "manual"
   ],
   "css/css-transitions/transition-reparented.html": [
@@ -395938,56 +396706,28 @@
    "10700abf9bc48d0938fd3f5b77b031ecc0c05e4a",
    "reftest"
   ],
-  "css/css-transitions/transition-timing-function-001.html": [
-   "4c9598f3919b84dc79d7c92c76b74b7f950423aa",
-   "testharness"
-  ],
-  "css/css-transitions/transition-timing-function-002.html": [
-   "527eb9e85ad4dc4944b39e83c1a0d79b8f515ddb",
+  "css/css-transitions/transition-timing-function-002-manual.html": [
+   "abd729bdedeff531c08279f1b4c4a7399b69d0c2",
    "manual"
   ],
-  "css/css-transitions/transition-timing-function-003.html": [
-   "353b94e7eca1e3f837d5c0e0ec02c1c0167b19a3",
+  "css/css-transitions/transition-timing-function-003-manual.html": [
+   "9fee35a972ed2f1790dd6c58140e92248044bfa7",
    "manual"
   ],
-  "css/css-transitions/transition-timing-function-004.html": [
-   "0601b4bd148a113ef0f5e0b5f6b3c33cf40c38b5",
+  "css/css-transitions/transition-timing-function-004-manual.html": [
+   "f57d49aeabb305bfea5281d159382c334f37ac8c",
    "manual"
   ],
-  "css/css-transitions/transition-timing-function-005.html": [
-   "eb46ece6044fe5d204b8dde056e655179732ef90",
+  "css/css-transitions/transition-timing-function-005-manual.html": [
+   "27726cd6d5b3bd4bc9532d64e2062318dd019574",
    "manual"
   ],
-  "css/css-transitions/transition-timing-function-006.html": [
-   "d8640d9304778f2ad41f56a90ba23486e8d59f34",
+  "css/css-transitions/transition-timing-function-006-manual.html": [
+   "d97e6bb07694d5b19dffba48a3890f0c07f15d03",
    "manual"
   ],
-  "css/css-transitions/transition-timing-function-007.html": [
-   "72ffbf6a1302c1858bf7880bfa033793c72b40d1",
-   "manual"
-  ],
-  "css/css-transitions/transition-timing-function-008.html": [
-   "2e20f7ee5f2a9ff9602222635a7723850fbd9e51",
-   "manual"
-  ],
-  "css/css-transitions/transition-timing-function-009.html": [
-   "a3e2f1a6bd2226a24484899c2a1f3126967989dc",
-   "manual"
-  ],
-  "css/css-transitions/transition-timing-function-010.html": [
-   "16af80655189fe64a1be1612910eca3f2aa449d4",
-   "manual"
-  ],
-  "css/css-transitions/transition-timing-function-011.html": [
-   "5d0f5a25b25aae82fc73e8a52a419f92350b5e3c",
-   "manual"
-  ],
-  "css/css-transitions/transition-timing-function-012.html": [
-   "f3bc812217e4a31153187ab33478f461571e089e",
-   "manual"
-  ],
-  "css/css-transitions/transition-timing-function-013.html": [
-   "5d89c45e0245ba4fedcd84905a59e3e8580319a8",
+  "css/css-transitions/transition-timing-function-010-manual.html": [
+   "953d7210b6d725cc668887ff592cc630ced88aec",
    "manual"
   ],
   "css/css-transitions/transitioncancel-001.html": [
@@ -398946,6 +399686,10 @@
    "75fc7e60bd9dc3f249b8340cf342b68fa45b7d68",
    "testharness"
   ],
+  "css/css-ui/parsing/outline-shorthand.html": [
+   "01239e199e651ff53237c19c4a76a500338e8514",
+   "testharness"
+  ],
   "css/css-ui/parsing/outline-style-computed.html": [
    "3824b8d59815b20206a90e428644942ac220c68c",
    "testharness"
@@ -400746,6 +401490,18 @@
    "fee5e92a9312f80b6d36966b721d01269f1ad30b",
    "reftest"
   ],
+  "css/css-values/clamp-length-computed.html": [
+   "67dc19a99f4d687745f27b7548d44e2795981d42",
+   "testharness"
+  ],
+  "css/css-values/clamp-length-invalid.html": [
+   "68c298b7ffc431d58025c0c9c5c2163db3742334",
+   "testharness"
+  ],
+  "css/css-values/clamp-length-serialize.html": [
+   "4719e4c0254902bb1c2234c4cfc1c4003a8df0d4",
+   "testharness"
+  ],
   "css/css-values/ex-calc-expression-001-ref.html": [
    "888a51ea9b6ac04fb065ee5d84a18be8fe765aca",
    "support"
@@ -400842,6 +401598,10 @@
    "73069ecfe1e6d5b198f6e01df48facbe117d6828",
    "reftest"
   ],
+  "css/css-values/min-max-percentage-length-interpolation.html": [
+   "14af1352d1740d32cd52ab069ab1799f87803f5d",
+   "reftest"
+  ],
   "css/css-values/minmax-angle-computed.html": [
    "84e598a8147e123285d54876f942a0df0a5bf57f",
    "testharness"
@@ -410854,6 +411614,14 @@
    "188a65b715291b33d93d8a6af88c2a7f6e25858c",
    "reftest"
   ],
+  "css/mediaqueries/aspect-ratio-serialization-expected.txt": [
+   "551aadd174919857cae83cc3b8e5803b271dda2f",
+   "support"
+  ],
+  "css/mediaqueries/aspect-ratio-serialization.html": [
+   "cce35592885f29eafd2c5c1b94a0da173217fc2a",
+   "testharness"
+  ],
   "css/mediaqueries/device-aspect-ratio-001.html": [
    "60f49b9b3cfedaf8136dcb568570ef71124cba8b",
    "reftest"
@@ -411027,7 +411795,7 @@
    "testharness"
   ],
   "css/motion/animation/offset-interpolation.html": [
-   "04f4d4b3bd78f95939c34aa098b85a7947d4fcbd",
+   "2ee011bd77a975e9b566d24658995693c574f620",
    "testharness"
   ],
   "css/motion/animation/offset-path-interpolation-001.html": [
@@ -411310,8 +412078,12 @@
    "cc2eb500eb88d24055dfe84e0c052546d90e9a29",
    "testharness"
   ],
+  "css/motion/parsing/offset-parsing-valid-expected.txt": [
+   "2a043073fa24db4efb3d4de7d5436a830a7be478",
+   "support"
+  ],
   "css/motion/parsing/offset-parsing-valid.html": [
-   "3fe8a5b20d805ae3d330b8c653593b6b0c0e0d9e",
+   "7f8a0fd34c329178e42908edd27858d577cdbad1",
    "testharness"
   ],
   "css/motion/parsing/offset-path-computed-expected.txt": [
@@ -413459,7 +414231,7 @@
    "support"
   ],
   "css/support/interpolation-testcommon.js": [
-   "e7ee011cdb470ee228a8a32442d6a717ef6ffd0a",
+   "24c47e136c8d98603238a09dbb64bd79cd6751d2",
    "support"
   ],
   "css/support/parsing-testcommon.js": [
@@ -413507,7 +414279,7 @@
    "support"
   ],
   "css/support/shorthand-testcommon.js": [
-   "1fd603c290c14d4672fc8f63f2d964da9867be78",
+   "3298113513fb1e34311a6e7f34dd2d20cfe0c870",
    "support"
   ],
   "css/support/square-purple.png": [
@@ -417327,7 +418099,7 @@
    "reftest"
   ],
   "css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-margin-box-border-radius-008-ref.html": [
-   "f5edbedfb74e763fdcdc1451d538caeda5c023c0",
+   "7cf8fafc933623c8a7912e8912a96d2fb178f8b5",
    "support"
   ],
   "css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-margin-box-border-radius-008.html": [
@@ -420082,6 +420854,10 @@
    "9f6d871417dcb006380f6e59bd0c0a031fd7e78e",
    "testharness"
   ],
+  "dom/nodes/MutationObserver-sanity.html": [
+   "a4f6382b944db4b2734ea54c9990dd4135c52557",
+   "testharness"
+  ],
   "dom/nodes/MutationObserver-takeRecords.html": [
    "6a27ef77ecacf55a7eaaae18cdd007e017e42cd9",
    "testharness"
@@ -437095,7 +437871,7 @@
    "support"
   ],
   "html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window-expected.txt": [
-   "d86c1db7d01d34ca2bc784ea7afafcee08508890",
+   "61e4b6f14a93fb8972cd9794f2323167d0c8bae9",
    "support"
   ],
   "html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js": [
@@ -437810,6 +438586,14 @@
    "f66244ab10ffbfeb5ef64ca7564fdd37794288af",
    "reftest"
   ],
+  "html/rendering/non-replaced-elements/tables/table-column-width-ref.html": [
+   "1eb7c00d21413292ffb47e956cf341338d6e26ff",
+   "support"
+  ],
+  "html/rendering/non-replaced-elements/tables/table-column-width.html": [
+   "6358e14a3926b4f6b97d32832c45c0ef9237f24d",
+   "reftest"
+  ],
   "html/rendering/non-replaced-elements/tables/table-direction-ref.html": [
    "2bbd6c04772fd538426d516d2a2d1b301d05ff3f",
    "support"
@@ -439762,6 +440546,10 @@
    "911aa7b5c96333f78da5ea315e1ca1b8381dcd74",
    "testharness"
   ],
+  "html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-remove-from-document-different-load.html": [
+   "4802665cdda09d7d8763b133aed301d43cdce08d",
+   "testharness"
+  ],
   "html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-remove-from-document-networkState.html": [
    "df0985d6fb435c25dce510f924b1470878c5602f",
    "testharness"
@@ -449742,6 +450530,14 @@
    "4442d513753112fac2e35855268d0b246f01fa09",
    "testharness"
   ],
+  "infrastructure/expected-fail/unhandled-rejection-expected.txt": [
+   "3a828c8d0a58d7faedb6b89ef5e60c57599efad9",
+   "support"
+  ],
+  "infrastructure/expected-fail/unhandled-rejection.html": [
+   "f25f6e088fa06fbcd38b62929309e761b0060988",
+   "testharness"
+  ],
   "infrastructure/metadata/infrastructure/assumptions/allowed-to-play.html.ini": [
    "c9fbabede6d695cd3795e4390b35da0454ffcc34",
    "support"
@@ -449766,6 +450562,10 @@
    "0bcdd374f2521b6534208ab750a1c0d36e7dd7ca",
    "support"
   ],
+  "infrastructure/metadata/infrastructure/expected-fail/unhandled-rejection.html.ini": [
+   "39773dfe714a6b5754bfe73c64294bcb38f2afa3",
+   "support"
+  ],
   "infrastructure/metadata/infrastructure/reftest/reftest_and_fail.html.ini": [
    "81aef049cd122f7332c66f5a087947e512a59d0e",
    "support"
@@ -450395,7 +451195,7 @@
    "support"
   ],
   "interfaces/gamepad.idl": [
-   "b7497c276f1610139ef14c1cc4d0c34c1f2c406b",
+   "27541bf2553520dcf7f2ce52386014c9a4363377",
    "support"
   ],
   "interfaces/generic-sensor.idl": [
@@ -450531,7 +451331,7 @@
    "support"
   ],
   "interfaces/payment-handler.idl": [
-   "b5d79decb06530001cd9d63e6fcba43995d27ba1",
+   "c87c855d439609adee24d2f49fc77879f9c8352b",
    "support"
   ],
   "interfaces/payment-method-basic-card.idl": [
@@ -450742,6 +451542,14 @@
    "81a23a35be6f857e49253d47cb9c64d24677b56d",
    "support"
   ],
+  "interfaces/webxr-ar-module.idl": [
+   "61fcd6a730f7c3846a8639075a0b2c2a3b755e0c",
+   "support"
+  ],
+  "interfaces/webxr-gamepads-module.idl": [
+   "3aa17a7fe0c8020f6101c0fee29107ce7b24cb37",
+   "support"
+  ],
   "interfaces/webxr.idl": [
    "b03aa556bb815127203e79c7b4bbc864d539314b",
    "support"
@@ -450866,6 +451674,10 @@
    "a093b22028c11c3e54db4a6f8fcccaad6a309bfb",
    "testharness"
   ],
+  "intersection-observer/resources/cross-origin-child-iframe.sub.html": [
+   "8e2c36ed56072ad9fd2e82d43b609f5719d78a55",
+   "support"
+  ],
   "intersection-observer/resources/cross-origin-subframe.html": [
    "4305ed1719b68f227192e005c9696fec5fe58f83",
    "support"
@@ -450882,6 +451694,10 @@
    "9d0769ae44a1bb4a6195c006999b0959f706330c",
    "support"
   ],
+  "intersection-observer/resources/same-origin-grand-child-iframe.html": [
+   "25db5a29d8a917916d0b2012f8f790ea9178e681",
+   "support"
+  ],
   "intersection-observer/resources/scaled-target-subframe.html": [
    "8f6f930e00915417fcba592df5520999c427ed91",
    "support"
@@ -450922,6 +451738,10 @@
    "20bd11d4beb1e8bdd623eaad96f11788747f0d15",
    "testharness"
   ],
+  "intersection-observer/same-origin-grand-child-iframe.sub.html": [
+   "57c0347ddc8ec748e3ff025a0ef7f11342f32a1d",
+   "testharness"
+  ],
   "intersection-observer/shadow-content.html": [
    "ce9473cb79258fca90321ee26240612c387ac9b9",
    "testharness"
@@ -450963,7 +451783,7 @@
    "testharness"
   ],
   "intersection-observer/v2/delay-test.html": [
-   "231df32c31df0458a4d5de09da55f0244854e0a6",
+   "e3906ea2c2975cbe678f55e34ead09527bc2bbfc",
    "testharness"
   ],
   "intersection-observer/v2/drop-shadow-filter-vertical-rl.html": [
@@ -451371,7 +452191,7 @@
    "testharness"
   ],
   "lint.whitelist": [
-   "be87d27864059b94b79f74a7f671f119cc40c0f9",
+   "d9ea5c17c7cf66a47199faba54d4793e8236f6cb",
    "support"
   ],
   "loading/lazyload/common.js": [
@@ -452579,7 +453399,7 @@
    "testharness"
   ],
   "mathml/relations/html5-tree/clipboard-event-handlers.tentative.html": [
-   "82fda880887839b72ac8c683d076ea07a8525d80",
+   "9816f5126a030de083ce4a6ca020976d9bb3beeb",
    "testharness"
   ],
   "mathml/relations/html5-tree/color-attributes-1-ref.html": [
@@ -452675,7 +453495,7 @@
    "testharness"
   ],
   "mathml/relations/html5-tree/math-global-event-handlers.tentative.html": [
-   "e96feeaf0960641e4413b7b43b93e46490460ee7",
+   "be9bee9c6c68fc2ec8caf5043242c45711ed0ed1",
    "testharness"
   ],
   "mathml/relations/html5-tree/required-extensions-2-ref.html": [
@@ -464122,6 +464942,10 @@
    "7c09f5d407e890c0ed02df1217d85f2f36d722bc",
    "testharness"
   ],
+  "payment-handler/change-payment-method-manual.https-expected.txt": [
+   "f30628bbf9f8c9b6b12d5f4d39ef73048709dcee",
+   "support"
+  ],
   "payment-handler/change-payment-method-manual.https.html": [
    "56690d2b26ed671f773a16853463126e57735f77",
    "manual"
@@ -464175,7 +464999,7 @@
    "testharness"
   ],
   "payment-handler/payment-request-event-manual.https-expected.txt": [
-   "b76179f0c74a04d903ba1911be97252db6552851",
+   "a00a329711ec8f8de1e7e7aeda6704564483c9d3",
    "support"
   ],
   "payment-handler/payment-request-event-manual.https.html": [
@@ -464191,7 +465015,7 @@
    "testharness"
   ],
   "payment-handler/supports-shipping-contact-delegation-manual.https-expected.txt": [
-   "3a76dbf89699c771bd62376c0307a48373262caf",
+   "149709f312a02ec55d70e564c13ac013e54bb947",
    "support"
   ],
   "payment-handler/supports-shipping-contact-delegation-manual.https.html": [
@@ -464463,7 +465287,7 @@
    "testharness"
   ],
   "payment-request/payment-request-canmakepayment-method.https-expected.txt": [
-   "5b7ee0ea3db4c800b85e24e6f7bce3f300c4fb98",
+   "f12b171c62a6d860027b12ada3d46078786df131",
    "support"
   ],
   "payment-request/payment-request-canmakepayment-method.https.html": [
@@ -464498,10 +465322,6 @@
    "4da11304a21427040f72317e3746feebb251d12e",
    "testharness"
   ],
-  "payment-request/payment-request-hasenrolledinstrument-method.tentative.https-expected.txt": [
-   "ad1d3ce1fbbd63a4ed8f306fb33bca7853b57427",
-   "support"
-  ],
   "payment-request/payment-request-hasenrolledinstrument-method.tentative.https.html": [
    "c1f7b27a22b41fe64a7fb77e73336d3d0daec159",
    "testharness"
@@ -464539,7 +465359,7 @@
    "testharness"
   ],
   "payment-request/payment-request-show-method.https-expected.txt": [
-   "b9ec0aea579037597a4270d3259e70c799dccd27",
+   "694a3c86b6bee483e820849119481fb231e7c9a1",
    "support"
   ],
   "payment-request/payment-request-show-method.https.html": [
@@ -464782,10 +465602,22 @@
    "b055f50f636848ceb7b1750484cc12328a121398",
    "support"
   ],
+  "permissions/feature-policy-permissions-query.html": [
+   "bd152e973e8fd520460a325d47beab8c25f45d31",
+   "support"
+  ],
   "permissions/idlharness.any.js": [
    "ff0a969badace39c3c4466c4528e30c21355e132",
    "testharness"
   ],
+  "permissions/permissions-query-feature-policy-attribute.https.sub-expected.txt": [
+   "b3a521320e8acb70c2f2199d608d4bd3379934e0",
+   "support"
+  ],
+  "permissions/permissions-query-feature-policy-attribute.https.sub.html": [
+   "1d7333d9b5f67a405dc6979d5ddcfda444a04c39",
+   "testharness"
+  ],
   "permissions/test-background-fetch-permission.html": [
    "c824ecf1d2b47630f8ebcef3ed42c8c908c8e9eb",
    "testharness"
@@ -465454,6 +466286,10 @@
    "0eae0ddfd6ef1e9de2251f50914a855f4142b9d5",
    "reftest"
   ],
+  "portals/portals-repeated-activate.html": [
+   "a3843dddb47b55d920b249b01f47199b1202bda6",
+   "testharness"
+  ],
   "portals/portals-set-src-after-activate.html": [
    "8da6b341840162dc7348b95cfed060c075a75135",
    "testharness"
@@ -465542,6 +466378,10 @@
    "26f62839af5ed8ea7a50535f411780bdf7fd6e03",
    "support"
   ],
+  "portals/resources/portal-repeated-activate-window.html": [
+   "e716034eff860fe567bc373f4676d55f97a5a786",
+   "support"
+  ],
   "portals/resources/portals-adopt-predecessor-portal.html": [
    "b7eb3b96779a561cacf11d6c7e9362ca1049be6c",
    "support"
@@ -465562,6 +466402,10 @@
    "92aef00380ae4a6180039ad0b10169c81a190441",
    "support"
   ],
+  "portals/resources/simple-portal-adopts-and-activates-predecessor.html": [
+   "56bfd10f647fb63597dbc5ec902a8c2b90257b18",
+   "support"
+  ],
   "portals/resources/simple-portal-adopts-predecessor.html": [
    "b199bdd93b3a03437ebde7abaef9b14ac61b1f76",
    "support"
@@ -477259,7 +478103,7 @@
    "support"
   ],
   "resources/chromium/contacts_manager_mock.js": [
-   "618968ec18da930ad1d3180adb68f05064bb1807",
+   "ae4c33b073dfd2b156030b2cb6d045e133b57c23",
    "support"
   ],
   "resources/chromium/device.mojom.js": [
@@ -477319,7 +478163,7 @@
    "support"
   ],
   "resources/chromium/mock-imagecapture.js": [
-   "eec414bd032a2dd01f27e18de64df0bde4e4a459",
+   "9d46b57020f36277b8bece93588699cae2a82471",
    "support"
   ],
   "resources/chromium/mojo_bindings.js": [
@@ -477443,7 +478287,7 @@
    "support"
   ],
   "resources/testharness.js": [
-   "15591042aa4cb0fdd75fe3bf56b9bdfb63fd161d",
+   "9ef46ca77646c92044ffc9d515009fafc11ed7d1",
    "support"
   ],
   "resources/testharness.js.headers": [
@@ -479483,7 +480327,7 @@
    "manual"
   ],
   "service-workers/service-worker/fetch-event-within-sw.https.html": [
-   "8a567fd7a93f8552412cfff657789c5375eba971",
+   "f5a60c3060961a2b1674c8959c5d4a0af7b5452a",
    "testharness"
   ],
   "service-workers/service-worker/fetch-event.https-expected.txt": [
@@ -481578,6 +482422,14 @@
    "20456b057e1e724cdac9bc656f3b3d6c7ac2f658",
    "testharness"
   ],
+  "shadow-dom/focus/focus-selector-delegatesFocus-expected.txt": [
+   "8b0d0bfc2ae13879b9b6a1dfb9b27f413c9d4ef3",
+   "support"
+  ],
+  "shadow-dom/focus/focus-selector-delegatesFocus.html": [
+   "386045258e043f7b0849aaa366d34bb645f2f73f",
+   "testharness"
+  ],
   "shadow-dom/focus/focus-tabindex-order-shadow-negative.html": [
    "ab25ea829bd10952ad6e96898fc95a1a1ae25d8f",
    "testharness"
@@ -481607,7 +482459,7 @@
    "testharness"
   ],
   "shadow-dom/focus/resources/shadow-utils.js": [
-   "6ea372afdf180a95d9fda632ebccd00a13df85bf",
+   "8033ce0169f4aa83b54c3567c68c4cc4f5b7a490",
    "support"
   ],
   "shadow-dom/form-control-form-attribute.html": [
@@ -483051,7 +483903,7 @@
    "testharness"
   ],
   "streams/readable-byte-streams/construct-byob-request.any.serviceworker-expected.txt": [
-   "39cb31bdc3c7514005ce8a501d37e9038da682e2",
+   "6e0da30f5ce6d430095664301cc4be4cb9beb850",
    "support"
   ],
   "streams/readable-byte-streams/construct-byob-request.any.sharedworker-expected.txt": [
@@ -483975,7 +484827,7 @@
    "testharness"
   ],
   "svg/animations/scripted/onhover-syncbases.html": [
-   "07726017a02f30958c72496ac1fcb5b3c40531dd",
+   "de757f369af36db7a072ffa4b4216faa56063ecd",
    "testharness"
   ],
   "svg/animations/scripted/paced-value-animation-overwrites-keyTimes.html": [
@@ -486491,7 +487343,7 @@
    "support"
   ],
   "tools/ci/tcdownload.py": [
-   "91c763a7acdd3416d7eff55407bf8f73b840d96a",
+   "46e9005740d39d3a9fcd136f5aeb7effcc3087e6",
    "support"
   ],
   "tools/ci/update_pr_preview.py": [
@@ -486559,7 +487411,7 @@
    "support"
   ],
   "tools/lint/lint.py": [
-   "48a275bcf29df6264258da3885e0e5f83a7ec85a",
+   "7689c359928d6be0f58384dfdc22d8eaa9f0d932",
    "support"
   ],
   "tools/lint/rules.py": [
@@ -490851,7 +491703,7 @@
    "support"
   ],
   "tools/wptrunner/requirements.txt": [
-   "d6c7a4ff3983663d088c64f6608e3fcf7de3bbfe",
+   "3584c93a199716d0b9809dc4180195647887d1a0",
    "support"
   ],
   "tools/wptrunner/requirements_android_webview.txt": [
@@ -491703,7 +492555,7 @@
    "support"
   ],
   "trusted-types/trusted-types-eval-reporting.tentative.https.html": [
-   "309873cb1f8028ecb071ec5db3dfda62337e6b43",
+   "4ec5db1adce7478cc3e97f942a9de68f1263d31d",
    "testharness"
   ],
   "trusted-types/trusted-types-eval-reporting.tentative.https.html.headers": [
@@ -493670,8 +494522,12 @@
    "bbb8ee2a3261fcb98cda7a83056467bc0b20dac6",
    "testharness"
   ],
+  "web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-001-expected.txt": [
+   "5b5ccfe7ac54eabbd45c5851d4ca12b77cdbb229",
+   "support"
+  ],
   "web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-001.html": [
-   "5c9ec84e8db79f73ac1423258a84bf0d18d70a5f",
+   "5bd0ae2b1edbb508d45ac64258332fcaddf5434c",
    "testharness"
   ],
   "web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-002.html": [
@@ -494579,7 +495435,7 @@
    "testharness"
   ],
   "webaudio/the-audio-api/the-audioworklet-interface/audioworklet-addmodule-resolution.https.html": [
-   "e94621296a3114ddbc53f26d74c330d3496dac63",
+   "dc324b22d6539d5383ed53f68ab911f6e96fd0dd",
    "testharness"
   ],
   "webaudio/the-audio-api/the-audioworklet-interface/audioworklet-audioparam-size.https.html": [
@@ -494963,7 +495819,7 @@
    "testharness"
   ],
   "webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSourceToScriptProcessorTest.html": [
-   "3e364eb7b359948402ef8ecdb287a5f55bb80fc3",
+   "b1f18d397d4fbcf3150e76aa478ce1a00a64e217",
    "testharness"
   ],
   "webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/no-cors.https.html": [
@@ -494979,7 +495835,7 @@
    "testharness"
   ],
   "webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/mediastreamaudiosourcenode-routing.html": [
-   "2e04ab6a3f248e69846cadbdc41c5369c406f519",
+   "816eba0b29ae616e09099544e839b85bb0a8bea5",
    "testharness"
   ],
   "webaudio/the-audio-api/the-offlineaudiocontext-interface/ctor-offlineaudiocontext.html": [
@@ -495083,7 +495939,7 @@
    "testharness"
   ],
   "webaudio/the-audio-api/the-waveshapernode-interface/curve-tests.html": [
-   "a2e40777d4285732622fe0776f5e862276bf41c9",
+   "81e64dc12e9c757b613ddd377c39ed313b3cea47",
    "testharness"
   ],
   "webaudio/the-audio-api/the-waveshapernode-interface/silent-inputs.html": [
@@ -502358,6 +503214,10 @@
    "cb7f47252d5746f61f1c9df2d981d47ef35940c5",
    "support"
   ],
+  "webxr/ar-module/idlharness.https.window.js": [
+   "1268f4ea2a5eb228fb49a6f06d8905f8d9480ae7",
+   "testharness"
+  ],
   "webxr/events_input_source_recreation.https.html": [
    "ecb4b022bf09410cae44b4f5a3c71bc5c054181e",
    "testharness"
@@ -502382,6 +503242,10 @@
    "f76847a8769073bb4753702f32dd5c2ccc9d3532",
    "testharness"
   ],
+  "webxr/gamepads-module/idlharness.https.window.js": [
+   "4509c67a847109f2fdaed5be49c87777e1927a12",
+   "testharness"
+  ],
   "webxr/getInputPose_handedness.https.html": [
    "5a310c6dd77274631d0ef9e751c6f195def9c3d3",
    "testharness"
@@ -502575,7 +503439,7 @@
    "testharness"
   ],
   "webxr/xrSession_input_events_end.https.html": [
-   "37e020605a7e88320c42e054f867f611955c5713",
+   "a932aad2fad78ceb2449928773da3ecfe237b8e7",
    "testharness"
   ],
   "webxr/xrSession_prevent_multiple_exclusive.https.html": [
@@ -502650,8 +503514,12 @@
    "1b7d982d596187f1381bee73eac2990900a37f8f",
    "testharness"
   ],
+  "webxr/xrWebGLLayer_constructor.https-expected.txt": [
+   "be0603a78356f77aa03542657046774d805ffde1",
+   "support"
+  ],
   "webxr/xrWebGLLayer_constructor.https.html": [
-   "0584da79c12def757f951ec53c4c048f18c39b8c",
+   "7e57f4286c66ea9f8380791840dada3d82b611fe",
    "testharness"
   ],
   "webxr/xrWebGLLayer_framebuffer_draw.https.html": [
@@ -506579,7 +507447,7 @@
    "testharness"
   ],
   "xhr/xmlhttprequest-sync-default-feature-policy.sub.html": [
-   "5ad5557700d79cb0104a5a5db52afdfa0906533b",
+   "ab5b78b77c66ee5bdca8e7acb5fb61f18d9574c1",
    "testharness"
   ],
   "xhr/xmlhttprequest-sync-not-hang-scriptloader-subframe.html": [
diff --git a/third_party/blink/web_tests/external/wpt/2dcontext/imagebitmap/createImageBitmap-invalid-args.html b/third_party/blink/web_tests/external/wpt/2dcontext/imagebitmap/createImageBitmap-invalid-args.html
index 004b3ca6..c64371e 100644
--- a/third_party/blink/web_tests/external/wpt/2dcontext/imagebitmap/createImageBitmap-invalid-args.html
+++ b/third_party/blink/web_tests/external/wpt/2dcontext/imagebitmap/createImageBitmap-invalid-args.html
@@ -52,7 +52,7 @@
     description: 'createImageBitmap with <sourceType> source and sw set to 0',
     promiseTestFunction:
       (source, t) => {
-        return promise_rejects(t, new RangeError(),
+        return promise_rejects_js(t, RangeError,
             createImageBitmap(source, 0, 0, 0, 10));
       }
   },
@@ -60,7 +60,7 @@
     description: 'createImageBitmap with <sourceType> source and sh set to 0',
     promiseTestFunction:
       (source, t) => {
-        return promise_rejects(t, new RangeError(),
+        return promise_rejects_js(t, RangeError,
             createImageBitmap(source, 0, 0, 10, 0));
       }
   },
@@ -100,88 +100,88 @@
 });
 
 promise_test( t => {
-  return promise_rejects(t, new TypeError(), createImageBitmap(undefined));
+  return promise_rejects_js(t, TypeError, createImageBitmap(undefined));
 }, "createImageBitmap with undefined image source.");
 
 promise_test( t => {
-  return promise_rejects(t, new TypeError(), createImageBitmap(null));
+  return promise_rejects_js(t, TypeError, createImageBitmap(null));
 }, "createImageBitmap with null image source.");
 
 promise_test( t => {
   var context = document.createElement("canvas").getContext("2d");
-  return promise_rejects(t, new TypeError(), createImageBitmap(context));
+  return promise_rejects_js(t, TypeError, createImageBitmap(context));
 }, "createImageBitmap with CanvasRenderingContext2D image source.");
 
 promise_test( t => {
   var context = document.createElement("canvas").getContext("webgl");
-  return promise_rejects(t, new TypeError(), createImageBitmap(context));
+  return promise_rejects_js(t, TypeError, createImageBitmap(context));
 }, "createImageBitmap with WebGLRenderingContext image source.");
 
 promise_test( t => {
   var buffer = new Uint8Array();
-  return promise_rejects(t, new TypeError(), createImageBitmap(buffer));
+  return promise_rejects_js(t, TypeError, createImageBitmap(buffer));
 }, "createImageBitmap with Uint8Array image source.");
 
 promise_test( t => {
   var buffer = new ArrayBuffer(8);
-  return promise_rejects(t, new TypeError(), createImageBitmap(buffer));
+  return promise_rejects_js(t, TypeError, createImageBitmap(buffer));
 }, "createImageBitmap with ArrayBuffer image source.");
 
 promise_test( t => {
-  return promise_rejects(t, "InvalidStateError",
+  return promise_rejects_dom(t, "InvalidStateError",
     createImageBitmap(new Image()));
 }, "createImageBitmap with empty image source.");
 
 promise_test( t => {
-  return promise_rejects(t, "InvalidStateError",
+  return promise_rejects_dom(t, "InvalidStateError",
     createImageBitmap(document.createElement('video')));
 }, "createImageBitmap with empty video source.");
 
 promise_test( t => {
   return makeOversizedCanvas().then(canvas => {
-    return promise_rejects(t, "InvalidStateError",
+    return promise_rejects_dom(t, "InvalidStateError",
         createImageBitmap(canvas));
   });
 }, "createImageBitmap with an oversized canvas source.");
 
 promise_test( t => {
   return makeOversizedOffscreenCanvas().then(offscreenCanvas => {
-    return promise_rejects(t, "InvalidStateError",
+    return promise_rejects_dom(t, "InvalidStateError",
         createImageBitmap(offscreenCanvas));
   });
 }, "createImageBitmap with an invalid OffscreenCanvas source.");
 
 promise_test( t => {
   return makeInvalidBlob().then(blob => {
-    return promise_rejects(t, "InvalidStateError",
+    return promise_rejects_dom(t, "InvalidStateError",
         createImageBitmap(blob));
   });
 }, "createImageBitmap with an undecodable blob source.");
 
 promise_test( t => {
   return makeBrokenImage().then(image => {
-    return promise_rejects(t, "InvalidStateError",
+    return promise_rejects_dom(t, "InvalidStateError",
         createImageBitmap(image));
   });
 }, "createImageBitmap with a broken image source.");
 
 promise_test( t => {
   return makeAvailableButBrokenImage("/images/broken.png").then(image => {
-    return promise_rejects(t, "InvalidStateError",
+    return promise_rejects_dom(t, "InvalidStateError",
         createImageBitmap(image));
   });
 }, "createImageBitmap with an available but undecodable image source.");
 
 promise_test( t => {
   return makeAvailableButBrokenImage("/images/red-zeroheight.svg").then(image => {
-    return promise_rejects(t, "InvalidStateError",
+    return promise_rejects_dom(t, "InvalidStateError",
         createImageBitmap(image));
   });
 }, "createImageBitmap with an available but zero height image source.");
 
 promise_test( t => {
   return makeAvailableButBrokenImage("/images/red-zerowidth.svg").then(image => {
-    return promise_rejects(t, "InvalidStateError",
+    return promise_rejects_dom(t, "InvalidStateError",
         createImageBitmap(image));
   });
 }, "createImageBitmap with an available but zero width image source.");
@@ -189,7 +189,8 @@
 promise_test( t => {
   return makeImageBitmap().then(bitmap => {
     bitmap.close()
-    return promise_rejects(t, "InvalidStateError", createImageBitmap(bitmap));
+    return promise_rejects_dom(t, "InvalidStateError",
+        createImageBitmap(bitmap));
   });
 }, "createImageBitmap with a closed ImageBitmap.");
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/fire-error-event-exception.html b/third_party/blink/web_tests/external/wpt/IndexedDB/fire-error-event-exception.html
index fe0dc18..0a3f122 100644
--- a/third_party/blink/web_tests/external/wpt/IndexedDB/fire-error-event-exception.html
+++ b/third_party/blink/web_tests/external/wpt/IndexedDB/fire-error-event-exception.html
@@ -21,6 +21,9 @@
       const request = store.add(0, 0);
       request.onsuccess = t.unreached_func('request should fail');
       func(t, db, tx, request);
+      tx.addEventListener('abort', t.step_func_done(() => {
+        assert_equals(tx.error.name, 'AbortError');
+      }));
     },
     description);
 }
@@ -31,9 +34,6 @@
   request.onerror = () => {
     throw Error();
   };
-  tx.onabort = t.step_func_done(() => {
-    assert_equals(tx.error.name, 'AbortError');
-  });
 }, 'Exception in error event handler on request');
 
 fire_error_event_test((t, db, tx, request) => {
@@ -41,30 +41,33 @@
     e.preventDefault();
     throw Error();
   };
-  tx.onabort = t.step_func_done(() => {
-    assert_equals(tx.error.name, 'AbortError');
-  });
 }, 'Exception in error event handler on request, with preventDefault');
 
 fire_error_event_test((t, db, tx, request) => {
   request.addEventListener('error', () => {
     throw Error();
   });
-  tx.onabort = t.step_func_done(() => {
-    assert_equals(tx.error.name, 'AbortError');
-  });
 }, 'Exception in error event listener on request');
 
 fire_error_event_test((t, db, tx, request) => {
+  request.addEventListener('error', {
+    get handleEvent() {
+      throw new Error();
+    },
+  });
+}, 'Exception in error event listener ("handleEvent" lookup) on request');
+
+fire_error_event_test((t, db, tx, request) => {
+  request.addEventListener('error', {});
+}, 'Exception in error event listener (non-callable "handleEvent") on request');
+
+fire_error_event_test((t, db, tx, request) => {
   request.addEventListener('error', () => {
     // no-op
   });
   request.addEventListener('error', () => {
     throw Error();
   });
-  tx.onabort = t.step_func_done(() => {
-    assert_equals(tx.error.name, 'AbortError');
-  });
 }, 'Exception in second error event listener on request');
 
 fire_error_event_test((t, db, tx, request) => {
@@ -77,10 +80,9 @@
     assert_true(is_transaction_active(tx, 's'),
                 'Transaction should be active until dispatch completes');
   }));
-  tx.onabort = t.step_func_done(() => {
+  tx.addEventListener('abort', t.step_func(() => {
     assert_true(second_listener_called);
-    assert_equals(tx.error.name, 'AbortError');
-  });
+  }));
 }, 'Exception in first error event listener on request, ' +
    'transaction active in second');
 
@@ -90,9 +92,6 @@
   tx.onerror = () => {
     throw Error();
   };
-  tx.onabort = t.step_func_done(() => {
-    assert_equals(tx.error.name, 'AbortError');
-  });
 }, 'Exception in error event handler on transaction');
 
 fire_error_event_test((t, db, tx, request) => {
@@ -100,18 +99,12 @@
     e.preventDefault();
     throw Error();
   };
-  tx.onabort = t.step_func_done(() => {
-    assert_equals(tx.error.name, 'AbortError');
-  });
 }, 'Exception in error event handler on transaction, with preventDefault');
 
 fire_error_event_test((t, db, tx, request) => {
   tx.addEventListener('error', () => {
     throw Error();
   });
-  tx.onabort = t.step_func_done(() => {
-    assert_equals(tx.error.name, 'AbortError');
-  });
 }, 'Exception in error event listener on transaction');
 
 fire_error_event_test((t, db, tx, request) => {
@@ -121,9 +114,6 @@
   tx.addEventListener('error', () => {
     throw Error();
   });
-  tx.onabort = t.step_func_done(() => {
-    assert_equals(tx.error.name, 'AbortError');
-  });
 }, 'Exception in second error event listener on transaction');
 
 fire_error_event_test((t, db, tx, request) => {
@@ -136,10 +126,9 @@
     assert_true(is_transaction_active(tx, 's'),
                 'Transaction should be active until dispatch completes');
   }));
-  tx.onabort = t.step_func_done(() => {
+  tx.addEventListener('abort', t.step_func(() => {
     assert_true(second_listener_called);
-    assert_equals(tx.error.name, 'AbortError');
-  });
+  }));
 }, 'Exception in first error event listener on transaction, ' +
    'transaction active in second');
 
@@ -149,9 +138,6 @@
   db.onerror = () => {
     throw Error();
   };
-  tx.onabort = t.step_func_done(() => {
-    assert_equals(tx.error.name, 'AbortError');
-  });
 }, 'Exception in error event handler on connection');
 
 fire_error_event_test((t, db, tx, request) => {
@@ -159,18 +145,12 @@
     e.preventDefault()
     throw Error();
   };
-  tx.onabort = t.step_func_done(() => {
-    assert_equals(tx.error.name, 'AbortError');
-  });
 }, 'Exception in error event handler on connection, with preventDefault');
 
 fire_error_event_test((t, db, tx, request) => {
   db.addEventListener('error', () => {
     throw Error();
   });
-  tx.onabort = t.step_func_done(() => {
-    assert_equals(tx.error.name, 'AbortError');
-  });
 }, 'Exception in error event listener on connection');
 
 fire_error_event_test((t, db, tx, request) => {
@@ -180,9 +160,6 @@
   db.addEventListener('error', () => {
     throw Error();
   });
-  tx.onabort = t.step_func_done(() => {
-    assert_equals(tx.error.name, 'AbortError');
-  });
 }, 'Exception in second error event listener on connection');
 
 fire_error_event_test((t, db, tx, request) => {
@@ -195,10 +172,9 @@
     assert_true(is_transaction_active(tx, 's'),
                 'Transaction should be active until dispatch completes');
   }));
-  tx.onabort = t.step_func_done(() => {
+  tx.addEventListener('abort', t.step_func(() => {
     assert_true(second_listener_called);
-    assert_equals(tx.error.name, 'AbortError');
-  });
+  }));
 }, 'Exception in first error event listener on connection, ' +
    'transaction active in second');
 
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/fire-success-event-exception.html b/third_party/blink/web_tests/external/wpt/IndexedDB/fire-success-event-exception.html
index c4e55066..ab0ac44e 100644
--- a/third_party/blink/web_tests/external/wpt/IndexedDB/fire-success-event-exception.html
+++ b/third_party/blink/web_tests/external/wpt/IndexedDB/fire-success-event-exception.html
@@ -19,6 +19,9 @@
       const store = tx.objectStore('s');
       const request = store.get(0);
       func(t, db, tx, request);
+      tx.addEventListener('abort', t.step_func_done(() => {
+        assert_equals(tx.error.name, 'AbortError');
+      }));
     },
     description);
 }
@@ -27,30 +30,35 @@
   request.onsuccess = () => {
     throw Error();
   };
-  tx.onabort = t.step_func_done(() => {
-    assert_equals(tx.error.name, 'AbortError');
-  });
 }, 'Exception in success event handler on request');
 
 fire_success_event_test((t, db, tx, request) => {
   request.addEventListener('success', () => {
     throw Error();
   });
-  tx.onabort = t.step_func_done(() => {
-    assert_equals(tx.error.name, 'AbortError');
-  });
 }, 'Exception in success event listener on request');
 
 fire_success_event_test((t, db, tx, request) => {
+  request.addEventListener('success', {
+    get handleEvent() {
+      throw new Error();
+    },
+  });
+}, 'Exception in success event listener ("handleEvent" lookup) on request');
+
+fire_success_event_test((t, db, tx, request) => {
+  request.addEventListener('success', {
+    handleEvent: null,
+  });
+}, 'Exception in success event listener (non-callable "handleEvent") on request');
+
+fire_success_event_test((t, db, tx, request) => {
   request.addEventListener('success', () => {
     // no-op
   });
   request.addEventListener('success', () => {
     throw Error();
   });
-  tx.onabort = t.step_func_done(() => {
-    assert_equals(tx.error.name, 'AbortError');
-  });
 }, 'Exception in second success event listener on request');
 
 fire_success_event_test((t, db, tx, request) => {
@@ -63,10 +71,9 @@
     assert_true(is_transaction_active(tx, 's'),
                 'Transaction should be active until dispatch completes');
   }));
-  tx.onabort = t.step_func_done(() => {
+  tx.addEventListener('abort', t.step_func(() => {
     assert_true(second_listener_called);
-    assert_equals(tx.error.name, 'AbortError');
-  });
+  }));
 }, 'Exception in first success event listener, tx active in second');
 
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/fire-upgradeneeded-event-exception.html b/third_party/blink/web_tests/external/wpt/IndexedDB/fire-upgradeneeded-event-exception.html
index 5db452e..1a8163a 100644
--- a/third_party/blink/web_tests/external/wpt/IndexedDB/fire-upgradeneeded-event-exception.html
+++ b/third_party/blink/web_tests/external/wpt/IndexedDB/fire-upgradeneeded-event-exception.html
@@ -15,48 +15,55 @@
     del.onerror = t.unreached_func('deleteDatabase should succeed');
     const open = indexedDB.open(dbname, 1);
     open.onsuccess = t.unreached_func('open should fail');
+    let tx;
+    open.addEventListener('upgradeneeded', () => {
+      tx = open.transaction;
+    });
     func(t, open);
+    open.addEventListener('error', t.step_func_done(() => {
+      assert_equals(tx.error.name, 'AbortError');
+    }));
   }, description);
 }
 
 fire_upgradeneeded_event_test((t, open) => {
-  let tx;
   open.onupgradeneeded = () => {
-    tx = open.transaction;
     throw Error();
   };
-  open.onerror = t.step_func_done(() => {
-    assert_equals(tx.error.name, 'AbortError');
-  });
 }, 'Exception in upgradeneeded handler');
 
 fire_upgradeneeded_event_test((t, open) => {
-  let tx;
   open.addEventListener('upgradeneeded', () => {
-    tx = open.transaction;
     throw Error();
   });
-  open.onerror = t.step_func_done(() => {
-    assert_equals(tx.error.name, 'AbortError');
-  });
 }, 'Exception in upgradeneeded listener');
 
 fire_upgradeneeded_event_test((t, open) => {
-  let tx;
+  open.addEventListener('upgradeneeded', {
+    get handleEvent() {
+      throw new Error();
+    },
+  });
+}, 'Exception in upgradeneeded "handleEvent" lookup');
+
+fire_upgradeneeded_event_test((t, open) => {
+  open.addEventListener('upgradeneeded', {
+    get handleEvent() {
+      return 10;
+    },
+  });
+}, 'Exception in upgradeneeded due to non-callable "handleEvent"');
+
+fire_upgradeneeded_event_test((t, open) => {
   open.addEventListener('upgradeneeded', () => {
     // No-op.
   });
   open.addEventListener('upgradeneeded', () => {
-    tx = open.transaction;
     throw Error();
   });
-  open.onerror = t.step_func_done(() => {
-    assert_equals(tx.error.name, 'AbortError');
-  });
 }, 'Exception in second upgradeneeded listener');
 
 fire_upgradeneeded_event_test((t, open) => {
-  let tx;
   let second_listener_called = false;
   open.addEventListener('upgradeneeded', () => {
     open.result.createObjectStore('s');
@@ -64,14 +71,12 @@
   });
   open.addEventListener('upgradeneeded', t.step_func(() => {
     second_listener_called = true;
-    tx = open.transaction;
-    assert_true(is_transaction_active(tx, 's'),
+    assert_true(is_transaction_active(open.transaction, 's'),
                 'Transaction should be active until dispatch completes');
   }));
-  open.onerror = t.step_func_done(() => {
+  open.addEventListener('error', t.step_func(() => {
     assert_true(second_listener_called);
-    assert_equals(tx.error.name, 'AbortError');
-  });
+  }));
 }, 'Exception in first upgradeneeded listener, tx active in second');
 
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-delay-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-delay-invalid.html
index a58d2cd11b..52e42a2 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-delay-invalid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-delay-invalid.html
@@ -14,6 +14,9 @@
 test_invalid_value("animation-delay", "infinite");
 test_invalid_value("animation-delay", "0");
 test_invalid_value("animation-delay", "1s 2s");
+
+test_invalid_value("animation-delay", "initial, -3s");
+test_invalid_value("animation-delay", "-3s, initial");
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-direction-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-direction-invalid.html
index 0b48d97f..5c96216 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-direction-invalid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-direction-invalid.html
@@ -13,6 +13,9 @@
 <script>
 test_invalid_value("animation-direction", "auto");
 test_invalid_value("animation-direction", "normal reverse");
+
+test_invalid_value("animation-direction", "reverse, initial");
+test_invalid_value("animation-direction", "initial, reverse");
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-duration-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-duration-invalid.html
index 5edacd3..bd8cf2a 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-duration-invalid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-duration-invalid.html
@@ -15,6 +15,9 @@
 test_invalid_value("animation-duration", '0');
 test_invalid_value("animation-duration", 'infinite');
 test_invalid_value("animation-duration", '1s 2s');
+
+test_invalid_value("animation-duration", 'initial, 1s');
+test_invalid_value("animation-duration", '1s, initial');
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-fill-mode-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-fill-mode-invalid.html
index dda2221..2a82f235 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-fill-mode-invalid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-fill-mode-invalid.html
@@ -13,6 +13,9 @@
 <script>
 test_invalid_value("animation-fill-mode", "auto");
 test_invalid_value("animation-fill-mode", "forwards backwards");
+
+test_invalid_value("animation-fill-mode", "both, initial");
+test_invalid_value("animation-fill-mode", "initial, both");
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-invalid.html
new file mode 100644
index 0000000..c5790a3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-invalid.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Animations: parsing animation with invalid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-animations/#propdef-animation">
+<meta name="assert" content="animation supports only the grammar '<single-animation> #'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_invalid_value("animation", "1s 2s 3s");
+test_invalid_value("animation", "-1s -2s");
+
+test_invalid_value("animation", "steps(1) steps(2)");
+
+test_invalid_value("animation", "1 2");
+
+test_invalid_value("animation", "reverse alternate anim");
+
+test_invalid_value("animation", "both backwards anim");
+
+test_invalid_value("animation", "paused running anim");
+
+test_invalid_value("animation", "anim1 anim2");
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-iteration-count-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-iteration-count-invalid.html
index ff1e8e2..621340f 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-iteration-count-invalid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-iteration-count-invalid.html
@@ -14,6 +14,9 @@
 test_invalid_value("animation-iteration-count", "auto");
 test_invalid_value("animation-iteration-count", "-2");
 test_invalid_value("animation-iteration-count", "3 4");
+
+test_invalid_value("animation-iteration-count", "initial, 4");
+test_invalid_value("animation-iteration-count", "4, initial");
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-play-state-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-play-state-invalid.html
index f47a2f7..91a6f017 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-play-state-invalid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-play-state-invalid.html
@@ -13,6 +13,9 @@
 <script>
 test_invalid_value("animation-play-state", "auto");
 test_invalid_value("animation-play-state", "paused running");
+
+test_invalid_value("animation-play-state", "paused, initial");
+test_invalid_value("animation-play-state", "initial, paused");
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-shorthand.html b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-shorthand.html
new file mode 100644
index 0000000..2e3053e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-shorthand.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Animations: animation sets longhands</title>
+<link rel="help" href="https://drafts.csswg.org/css-animations/#propdef-animation">
+<meta name="assert" content="animation supports the full grammar '<single-animation> #'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/shorthand-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_shorthand_value('animation', 'anim paused both reverse 4 1s -3s cubic-bezier(0, -2, 1, 3)', {
+  'animation-duration': '1s',
+  'animation-timing-function': 'cubic-bezier(0, -2, 1, 3)',
+  'animation-delay': '-3s',
+  'animation-iteration-count': '4',
+  'animation-direction': 'reverse',
+  'animation-fill-mode': 'both',
+  'animation-play-state': 'paused',
+  'animation-name': 'anim'
+});
+
+test_shorthand_value('animation', 'anim paused both reverse, 4 1s -3s cubic-bezier(0, -2, 1, 3)', {
+  'animation-duration': '0s, 1s',
+  'animation-timing-function': 'ease, cubic-bezier(0, -2, 1, 3)',
+  'animation-delay': '0s, -3s',
+  'animation-iteration-count': '1, 4',
+  'animation-direction': 'reverse, normal',
+  'animation-fill-mode': 'both, none',
+  'animation-play-state': 'paused, running',
+  'animation-name': 'anim, none'
+});
+
+test_shorthand_value('animation', '4 1s -3s cubic-bezier(0, -2, 1, 3), anim paused both reverse', {
+  'animation-duration': '1s, 0s',
+  'animation-timing-function': 'cubic-bezier(0, -2, 1, 3), ease',
+  'animation-delay': '-3s, 0s',
+  'animation-iteration-count': '4, 1',
+  'animation-direction': 'normal, reverse',
+  'animation-fill-mode': 'none, both',
+  'animation-play-state': 'running, paused',
+  'animation-name': 'none, anim'
+});
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-timing-function-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-timing-function-invalid.html
index adc1cc1..621145b 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-timing-function-invalid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-timing-function-invalid.html
@@ -18,6 +18,9 @@
 test_invalid_value("animation-timing-function", "cubic-bezier(1, 2, 3, 4, 5)");
 test_invalid_value("animation-timing-function", "cubic-bezier(-0.1, 0.1, 0.5, 0.9)");
 test_invalid_value("animation-timing-function", "cubic-bezier(0.5, 0.1, 1.1, 0.9)");
+
+test_invalid_value("animation-timing-function", "initial, cubic-bezier(0, -2, 1, 3)");
+test_invalid_value("animation-timing-function", "cubic-bezier(0, -2, 1, 3), initial");
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-valid.html b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-valid.html
new file mode 100644
index 0000000..65de3c6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-valid.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Animations: parsing animation with valid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-animations/#propdef-animation">
+<meta name="assert" content="animation supports the full grammar '<single-animation> #'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+// <single-animation> = <time> || <easing-function> || <time> ||
+// <single-animation-iteration-count> || <single-animation-direction> ||
+// <single-animation-fill-mode> || <single-animation-play-state> ||
+// [ none | <keyframes-name> ]
+test_valid_value("animation", "1s", ["1s", "1s ease 0s 1 normal none running none"]);
+test_valid_value("animation", "cubic-bezier(0, -2, 1, 3)", ["cubic-bezier(0, -2, 1, 3)", "0s cubic-bezier(0, -2, 1, 3) 0s 1 normal none running none"]);
+test_valid_value("animation", "1s -3s", ["1s -3s", "1s ease -3s 1 normal none running none"]);
+test_valid_value("animation", "4", ["4", "0s ease 0s 4 normal none running none"]);
+test_valid_value("animation", "reverse", ["reverse", "0s ease 0s 1 reverse none running none"]);
+test_valid_value("animation", "both", ["both", "0s ease 0s 1 normal both running none"]);
+test_valid_value("animation", "paused", ["paused", "0s ease 0s 1 normal none paused none"]);
+test_valid_value("animation", "none", ["none", "0s ease 0s 1 normal none running none"]);
+test_valid_value("animation", "anim", ["anim", "0s ease 0s 1 normal none running anim"]);
+
+test_valid_value("animation", "anim paused both reverse 4 1s -3s cubic-bezier(0, -2, 1, 3)",
+  "1s cubic-bezier(0, -2, 1, 3) -3s 4 reverse both paused anim");
+
+test_valid_value("animation", "anim paused both reverse, 4 1s -3s cubic-bezier(0, -2, 1, 3)",
+  "0s ease 0s 1 reverse both paused anim, 1s cubic-bezier(0, -2, 1, 3) -3s 4 normal none running none");
+
+// TODO: Add test with a single negative time.
+// TODO: Add test with a single timing-function keyword.
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/animations/border-image-outset-interpolation-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/animations/border-image-outset-interpolation-expected.txt
new file mode 100644
index 0000000..6ca6cb7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/animations/border-image-outset-interpolation-expected.txt
@@ -0,0 +1,172 @@
+This is a testharness.js-based test.
+Found 168 tests; 128 PASS, 40 FAIL, 0 TIMEOUT, 0 NOTRUN.
+PASS CSS Transitions: property <border-image-outset> from neutral to [2px] at (-0.3) should be [0.7px]
+PASS CSS Transitions: property <border-image-outset> from neutral to [2px] at (0) should be [1px]
+PASS CSS Transitions: property <border-image-outset> from neutral to [2px] at (0.3) should be [1.3px]
+PASS CSS Transitions: property <border-image-outset> from neutral to [2px] at (0.6) should be [1.6px]
+PASS CSS Transitions: property <border-image-outset> from neutral to [2px] at (1) should be [2px]
+PASS CSS Transitions: property <border-image-outset> from neutral to [2px] at (1.5) should be [2.5px]
+PASS CSS Transitions with transition: all: property <border-image-outset> from neutral to [2px] at (-0.3) should be [0.7px]
+PASS CSS Transitions with transition: all: property <border-image-outset> from neutral to [2px] at (0) should be [1px]
+PASS CSS Transitions with transition: all: property <border-image-outset> from neutral to [2px] at (0.3) should be [1.3px]
+PASS CSS Transitions with transition: all: property <border-image-outset> from neutral to [2px] at (0.6) should be [1.6px]
+PASS CSS Transitions with transition: all: property <border-image-outset> from neutral to [2px] at (1) should be [2px]
+PASS CSS Transitions with transition: all: property <border-image-outset> from neutral to [2px] at (1.5) should be [2.5px]
+PASS CSS Animations: property <border-image-outset> from neutral to [2px] at (-0.3) should be [0.7px]
+PASS CSS Animations: property <border-image-outset> from neutral to [2px] at (0) should be [1px]
+PASS CSS Animations: property <border-image-outset> from neutral to [2px] at (0.3) should be [1.3px]
+PASS CSS Animations: property <border-image-outset> from neutral to [2px] at (0.6) should be [1.6px]
+PASS CSS Animations: property <border-image-outset> from neutral to [2px] at (1) should be [2px]
+PASS CSS Animations: property <border-image-outset> from neutral to [2px] at (1.5) should be [2.5px]
+PASS Web Animations: property <border-image-outset> from neutral to [2px] at (-0.3) should be [0.7px]
+PASS Web Animations: property <border-image-outset> from neutral to [2px] at (0) should be [1px]
+PASS Web Animations: property <border-image-outset> from neutral to [2px] at (0.3) should be [1.3px]
+PASS Web Animations: property <border-image-outset> from neutral to [2px] at (0.6) should be [1.6px]
+PASS Web Animations: property <border-image-outset> from neutral to [2px] at (1) should be [2px]
+PASS Web Animations: property <border-image-outset> from neutral to [2px] at (1.5) should be [2.5px]
+FAIL CSS Transitions: property <border-image-outset> from [initial] to [2] at (-0.3) should be [0] assert_equals: expected "0 " but got "2 "
+FAIL CSS Transitions: property <border-image-outset> from [initial] to [2] at (0) should be [0] assert_equals: expected "0 " but got "2 "
+FAIL CSS Transitions: property <border-image-outset> from [initial] to [2] at (0.3) should be [0.6] assert_equals: expected "0.6 " but got "2 "
+FAIL CSS Transitions: property <border-image-outset> from [initial] to [2] at (0.6) should be [1.2] assert_equals: expected "1.2 " but got "2 "
+PASS CSS Transitions: property <border-image-outset> from [initial] to [2] at (1) should be [2]
+FAIL CSS Transitions: property <border-image-outset> from [initial] to [2] at (1.5) should be [3] assert_equals: expected "3 " but got "2 "
+FAIL CSS Transitions with transition: all: property <border-image-outset> from [initial] to [2] at (-0.3) should be [0] assert_equals: expected "0 " but got "2 "
+FAIL CSS Transitions with transition: all: property <border-image-outset> from [initial] to [2] at (0) should be [0] assert_equals: expected "0 " but got "2 "
+FAIL CSS Transitions with transition: all: property <border-image-outset> from [initial] to [2] at (0.3) should be [0.6] assert_equals: expected "0.6 " but got "2 "
+FAIL CSS Transitions with transition: all: property <border-image-outset> from [initial] to [2] at (0.6) should be [1.2] assert_equals: expected "1.2 " but got "2 "
+PASS CSS Transitions with transition: all: property <border-image-outset> from [initial] to [2] at (1) should be [2]
+FAIL CSS Transitions with transition: all: property <border-image-outset> from [initial] to [2] at (1.5) should be [3] assert_equals: expected "3 " but got "2 "
+FAIL CSS Animations: property <border-image-outset> from [initial] to [2] at (-0.3) should be [0] assert_equals: expected "0 " but got "0px "
+FAIL CSS Animations: property <border-image-outset> from [initial] to [2] at (0) should be [0] assert_equals: expected "0 " but got "0px "
+FAIL CSS Animations: property <border-image-outset> from [initial] to [2] at (0.3) should be [0.6] assert_equals: expected "0.6 " but got "0px "
+FAIL CSS Animations: property <border-image-outset> from [initial] to [2] at (0.6) should be [1.2] assert_equals: expected "1.2 " but got "2 "
+PASS CSS Animations: property <border-image-outset> from [initial] to [2] at (1) should be [2]
+FAIL CSS Animations: property <border-image-outset> from [initial] to [2] at (1.5) should be [3] assert_equals: expected "3 " but got "2 "
+FAIL Web Animations: property <border-image-outset> from [initial] to [2] at (-0.3) should be [0] assert_equals: expected "0 " but got "0px "
+FAIL Web Animations: property <border-image-outset> from [initial] to [2] at (0) should be [0] assert_equals: expected "0 " but got "0px "
+FAIL Web Animations: property <border-image-outset> from [initial] to [2] at (0.3) should be [0.6] assert_equals: expected "0.6 " but got "0px "
+FAIL Web Animations: property <border-image-outset> from [initial] to [2] at (0.6) should be [1.2] assert_equals: expected "1.2 " but got "2 "
+PASS Web Animations: property <border-image-outset> from [initial] to [2] at (1) should be [2]
+FAIL Web Animations: property <border-image-outset> from [initial] to [2] at (1.5) should be [3] assert_equals: expected "3 " but got "2 "
+PASS CSS Transitions: property <border-image-outset> from [inherit] to [2px] at (-0.3) should be [12.4px]
+PASS CSS Transitions: property <border-image-outset> from [inherit] to [2px] at (0) should be [10px]
+PASS CSS Transitions: property <border-image-outset> from [inherit] to [2px] at (0.3) should be [7.6px]
+PASS CSS Transitions: property <border-image-outset> from [inherit] to [2px] at (0.6) should be [5.2px]
+PASS CSS Transitions: property <border-image-outset> from [inherit] to [2px] at (1) should be [2px]
+PASS CSS Transitions: property <border-image-outset> from [inherit] to [2px] at (1.5) should be [0px]
+PASS CSS Transitions with transition: all: property <border-image-outset> from [inherit] to [2px] at (-0.3) should be [12.4px]
+PASS CSS Transitions with transition: all: property <border-image-outset> from [inherit] to [2px] at (0) should be [10px]
+PASS CSS Transitions with transition: all: property <border-image-outset> from [inherit] to [2px] at (0.3) should be [7.6px]
+PASS CSS Transitions with transition: all: property <border-image-outset> from [inherit] to [2px] at (0.6) should be [5.2px]
+PASS CSS Transitions with transition: all: property <border-image-outset> from [inherit] to [2px] at (1) should be [2px]
+PASS CSS Transitions with transition: all: property <border-image-outset> from [inherit] to [2px] at (1.5) should be [0px]
+PASS CSS Animations: property <border-image-outset> from [inherit] to [2px] at (-0.3) should be [12.4px]
+PASS CSS Animations: property <border-image-outset> from [inherit] to [2px] at (0) should be [10px]
+PASS CSS Animations: property <border-image-outset> from [inherit] to [2px] at (0.3) should be [7.6px]
+PASS CSS Animations: property <border-image-outset> from [inherit] to [2px] at (0.6) should be [5.2px]
+PASS CSS Animations: property <border-image-outset> from [inherit] to [2px] at (1) should be [2px]
+PASS CSS Animations: property <border-image-outset> from [inherit] to [2px] at (1.5) should be [0px]
+PASS Web Animations: property <border-image-outset> from [inherit] to [2px] at (-0.3) should be [12.4px]
+PASS Web Animations: property <border-image-outset> from [inherit] to [2px] at (0) should be [10px]
+PASS Web Animations: property <border-image-outset> from [inherit] to [2px] at (0.3) should be [7.6px]
+PASS Web Animations: property <border-image-outset> from [inherit] to [2px] at (0.6) should be [5.2px]
+PASS Web Animations: property <border-image-outset> from [inherit] to [2px] at (1) should be [2px]
+PASS Web Animations: property <border-image-outset> from [inherit] to [2px] at (1.5) should be [0px]
+FAIL CSS Transitions: property <border-image-outset> from [unset] to [2] at (-0.3) should be [0] assert_equals: expected "0 " but got "2 "
+FAIL CSS Transitions: property <border-image-outset> from [unset] to [2] at (0) should be [0] assert_equals: expected "0 " but got "2 "
+FAIL CSS Transitions: property <border-image-outset> from [unset] to [2] at (0.3) should be [0.6] assert_equals: expected "0.6 " but got "2 "
+FAIL CSS Transitions: property <border-image-outset> from [unset] to [2] at (0.6) should be [1.2] assert_equals: expected "1.2 " but got "2 "
+PASS CSS Transitions: property <border-image-outset> from [unset] to [2] at (1) should be [2]
+FAIL CSS Transitions: property <border-image-outset> from [unset] to [2] at (1.5) should be [3] assert_equals: expected "3 " but got "2 "
+FAIL CSS Transitions with transition: all: property <border-image-outset> from [unset] to [2] at (-0.3) should be [0] assert_equals: expected "0 " but got "2 "
+FAIL CSS Transitions with transition: all: property <border-image-outset> from [unset] to [2] at (0) should be [0] assert_equals: expected "0 " but got "2 "
+FAIL CSS Transitions with transition: all: property <border-image-outset> from [unset] to [2] at (0.3) should be [0.6] assert_equals: expected "0.6 " but got "2 "
+FAIL CSS Transitions with transition: all: property <border-image-outset> from [unset] to [2] at (0.6) should be [1.2] assert_equals: expected "1.2 " but got "2 "
+PASS CSS Transitions with transition: all: property <border-image-outset> from [unset] to [2] at (1) should be [2]
+FAIL CSS Transitions with transition: all: property <border-image-outset> from [unset] to [2] at (1.5) should be [3] assert_equals: expected "3 " but got "2 "
+FAIL CSS Animations: property <border-image-outset> from [unset] to [2] at (-0.3) should be [0] assert_equals: expected "0 " but got "0px "
+FAIL CSS Animations: property <border-image-outset> from [unset] to [2] at (0) should be [0] assert_equals: expected "0 " but got "0px "
+FAIL CSS Animations: property <border-image-outset> from [unset] to [2] at (0.3) should be [0.6] assert_equals: expected "0.6 " but got "0px "
+FAIL CSS Animations: property <border-image-outset> from [unset] to [2] at (0.6) should be [1.2] assert_equals: expected "1.2 " but got "2 "
+PASS CSS Animations: property <border-image-outset> from [unset] to [2] at (1) should be [2]
+FAIL CSS Animations: property <border-image-outset> from [unset] to [2] at (1.5) should be [3] assert_equals: expected "3 " but got "2 "
+FAIL Web Animations: property <border-image-outset> from [unset] to [2] at (-0.3) should be [0] assert_equals: expected "0 " but got "0px "
+FAIL Web Animations: property <border-image-outset> from [unset] to [2] at (0) should be [0] assert_equals: expected "0 " but got "0px "
+FAIL Web Animations: property <border-image-outset> from [unset] to [2] at (0.3) should be [0.6] assert_equals: expected "0.6 " but got "0px "
+FAIL Web Animations: property <border-image-outset> from [unset] to [2] at (0.6) should be [1.2] assert_equals: expected "1.2 " but got "2 "
+PASS Web Animations: property <border-image-outset> from [unset] to [2] at (1) should be [2]
+FAIL Web Animations: property <border-image-outset> from [unset] to [2] at (1.5) should be [3] assert_equals: expected "3 " but got "2 "
+PASS CSS Transitions: property <border-image-outset> from [0px] to [5px] at (-0.3) should be [0px]
+PASS CSS Transitions: property <border-image-outset> from [0px] to [5px] at (0) should be [0px]
+PASS CSS Transitions: property <border-image-outset> from [0px] to [5px] at (0.3) should be [1.5px]
+PASS CSS Transitions: property <border-image-outset> from [0px] to [5px] at (0.6) should be [3px]
+PASS CSS Transitions: property <border-image-outset> from [0px] to [5px] at (1) should be [5px]
+PASS CSS Transitions: property <border-image-outset> from [0px] to [5px] at (1.5) should be [7.5px]
+PASS CSS Transitions with transition: all: property <border-image-outset> from [0px] to [5px] at (-0.3) should be [0px]
+PASS CSS Transitions with transition: all: property <border-image-outset> from [0px] to [5px] at (0) should be [0px]
+PASS CSS Transitions with transition: all: property <border-image-outset> from [0px] to [5px] at (0.3) should be [1.5px]
+PASS CSS Transitions with transition: all: property <border-image-outset> from [0px] to [5px] at (0.6) should be [3px]
+PASS CSS Transitions with transition: all: property <border-image-outset> from [0px] to [5px] at (1) should be [5px]
+PASS CSS Transitions with transition: all: property <border-image-outset> from [0px] to [5px] at (1.5) should be [7.5px]
+PASS CSS Animations: property <border-image-outset> from [0px] to [5px] at (-0.3) should be [0px]
+PASS CSS Animations: property <border-image-outset> from [0px] to [5px] at (0) should be [0px]
+PASS CSS Animations: property <border-image-outset> from [0px] to [5px] at (0.3) should be [1.5px]
+PASS CSS Animations: property <border-image-outset> from [0px] to [5px] at (0.6) should be [3px]
+PASS CSS Animations: property <border-image-outset> from [0px] to [5px] at (1) should be [5px]
+PASS CSS Animations: property <border-image-outset> from [0px] to [5px] at (1.5) should be [7.5px]
+PASS Web Animations: property <border-image-outset> from [0px] to [5px] at (-0.3) should be [0px]
+PASS Web Animations: property <border-image-outset> from [0px] to [5px] at (0) should be [0px]
+PASS Web Animations: property <border-image-outset> from [0px] to [5px] at (0.3) should be [1.5px]
+PASS Web Animations: property <border-image-outset> from [0px] to [5px] at (0.6) should be [3px]
+PASS Web Animations: property <border-image-outset> from [0px] to [5px] at (1) should be [5px]
+PASS Web Animations: property <border-image-outset> from [0px] to [5px] at (1.5) should be [7.5px]
+PASS CSS Transitions: property <border-image-outset> from [0] to [1] at (-0.3) should be [0]
+PASS CSS Transitions: property <border-image-outset> from [0] to [1] at (0) should be [0]
+PASS CSS Transitions: property <border-image-outset> from [0] to [1] at (0.3) should be [0.3]
+PASS CSS Transitions: property <border-image-outset> from [0] to [1] at (0.6) should be [0.6]
+PASS CSS Transitions: property <border-image-outset> from [0] to [1] at (1) should be [1]
+PASS CSS Transitions: property <border-image-outset> from [0] to [1] at (1.5) should be [1.5]
+PASS CSS Transitions with transition: all: property <border-image-outset> from [0] to [1] at (-0.3) should be [0]
+PASS CSS Transitions with transition: all: property <border-image-outset> from [0] to [1] at (0) should be [0]
+PASS CSS Transitions with transition: all: property <border-image-outset> from [0] to [1] at (0.3) should be [0.3]
+PASS CSS Transitions with transition: all: property <border-image-outset> from [0] to [1] at (0.6) should be [0.6]
+PASS CSS Transitions with transition: all: property <border-image-outset> from [0] to [1] at (1) should be [1]
+PASS CSS Transitions with transition: all: property <border-image-outset> from [0] to [1] at (1.5) should be [1.5]
+PASS CSS Animations: property <border-image-outset> from [0] to [1] at (-0.3) should be [0]
+PASS CSS Animations: property <border-image-outset> from [0] to [1] at (0) should be [0]
+PASS CSS Animations: property <border-image-outset> from [0] to [1] at (0.3) should be [0.3]
+PASS CSS Animations: property <border-image-outset> from [0] to [1] at (0.6) should be [0.6]
+PASS CSS Animations: property <border-image-outset> from [0] to [1] at (1) should be [1]
+PASS CSS Animations: property <border-image-outset> from [0] to [1] at (1.5) should be [1.5]
+PASS Web Animations: property <border-image-outset> from [0] to [1] at (-0.3) should be [0]
+PASS Web Animations: property <border-image-outset> from [0] to [1] at (0) should be [0]
+PASS Web Animations: property <border-image-outset> from [0] to [1] at (0.3) should be [0.3]
+PASS Web Animations: property <border-image-outset> from [0] to [1] at (0.6) should be [0.6]
+PASS Web Animations: property <border-image-outset> from [0] to [1] at (1) should be [1]
+PASS Web Animations: property <border-image-outset> from [0] to [1] at (1.5) should be [1.5]
+PASS CSS Transitions: property <border-image-outset> from [1 2 3px 4px] to [101 102 103px 104px] at (-0.3) should be [0 0 0px 0px]
+PASS CSS Transitions: property <border-image-outset> from [1 2 3px 4px] to [101 102 103px 104px] at (0) should be [1 2 3px 4px]
+PASS CSS Transitions: property <border-image-outset> from [1 2 3px 4px] to [101 102 103px 104px] at (0.3) should be [31 32 33px 34px]
+PASS CSS Transitions: property <border-image-outset> from [1 2 3px 4px] to [101 102 103px 104px] at (0.6) should be [61 62 63px 64px]
+PASS CSS Transitions: property <border-image-outset> from [1 2 3px 4px] to [101 102 103px 104px] at (1) should be [101 102 103px 104px]
+PASS CSS Transitions: property <border-image-outset> from [1 2 3px 4px] to [101 102 103px 104px] at (1.5) should be [151 152 153px 154px]
+PASS CSS Transitions with transition: all: property <border-image-outset> from [1 2 3px 4px] to [101 102 103px 104px] at (-0.3) should be [0 0 0px 0px]
+PASS CSS Transitions with transition: all: property <border-image-outset> from [1 2 3px 4px] to [101 102 103px 104px] at (0) should be [1 2 3px 4px]
+PASS CSS Transitions with transition: all: property <border-image-outset> from [1 2 3px 4px] to [101 102 103px 104px] at (0.3) should be [31 32 33px 34px]
+PASS CSS Transitions with transition: all: property <border-image-outset> from [1 2 3px 4px] to [101 102 103px 104px] at (0.6) should be [61 62 63px 64px]
+PASS CSS Transitions with transition: all: property <border-image-outset> from [1 2 3px 4px] to [101 102 103px 104px] at (1) should be [101 102 103px 104px]
+PASS CSS Transitions with transition: all: property <border-image-outset> from [1 2 3px 4px] to [101 102 103px 104px] at (1.5) should be [151 152 153px 154px]
+PASS CSS Animations: property <border-image-outset> from [1 2 3px 4px] to [101 102 103px 104px] at (-0.3) should be [0 0 0px 0px]
+PASS CSS Animations: property <border-image-outset> from [1 2 3px 4px] to [101 102 103px 104px] at (0) should be [1 2 3px 4px]
+PASS CSS Animations: property <border-image-outset> from [1 2 3px 4px] to [101 102 103px 104px] at (0.3) should be [31 32 33px 34px]
+PASS CSS Animations: property <border-image-outset> from [1 2 3px 4px] to [101 102 103px 104px] at (0.6) should be [61 62 63px 64px]
+PASS CSS Animations: property <border-image-outset> from [1 2 3px 4px] to [101 102 103px 104px] at (1) should be [101 102 103px 104px]
+PASS CSS Animations: property <border-image-outset> from [1 2 3px 4px] to [101 102 103px 104px] at (1.5) should be [151 152 153px 154px]
+PASS Web Animations: property <border-image-outset> from [1 2 3px 4px] to [101 102 103px 104px] at (-0.3) should be [0 0 0px 0px]
+PASS Web Animations: property <border-image-outset> from [1 2 3px 4px] to [101 102 103px 104px] at (0) should be [1 2 3px 4px]
+PASS Web Animations: property <border-image-outset> from [1 2 3px 4px] to [101 102 103px 104px] at (0.3) should be [31 32 33px 34px]
+PASS Web Animations: property <border-image-outset> from [1 2 3px 4px] to [101 102 103px 104px] at (0.6) should be [61 62 63px 64px]
+PASS Web Animations: property <border-image-outset> from [1 2 3px 4px] to [101 102 103px 104px] at (1) should be [101 102 103px 104px]
+PASS Web Animations: property <border-image-outset> from [1 2 3px 4px] to [101 102 103px 104px] at (1.5) should be [151 152 153px 154px]
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/animations/border-image-outset-interpolation.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/animations/border-image-outset-interpolation.html
index d4726e8..aebadbb 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/animations/border-image-outset-interpolation.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/animations/border-image-outset-interpolation.html
@@ -48,14 +48,14 @@
 test_interpolation({
   property: 'border-image-outset',
   from: 'initial',
-  to: '2px',
+  to: '2',
 }, [
-  {at: -0.3, expect: '0px'}, // Non-negative
-  {at: 0, expect: '0px'},
-  {at: 0.3, expect: '0.6px'},
-  {at: 0.6, expect: '1.2px'},
-  {at: 1, expect: '2px'},
-  {at: 1.5, expect: '3px'},
+  {at: -0.3, expect: '0'}, // Non-negative
+  {at: 0, expect: '0'},
+  {at: 0.3, expect: '0.6'},
+  {at: 0.6, expect: '1.2'},
+  {at: 1, expect: '2'},
+  {at: 1.5, expect: '3'},
 ]);
 
 test_interpolation({
@@ -74,14 +74,14 @@
 test_interpolation({
   property: 'border-image-outset',
   from: 'unset',
-  to: '2px',
+  to: '2',
 }, [
-  {at: -0.3, expect: '0px'}, // Non-negative
-  {at: 0, expect: '0px'},
-  {at: 0.3, expect: '0.6px'},
-  {at: 0.6, expect: '1.2px'},
-  {at: 1, expect: '2px'},
-  {at: 1.5, expect: '3px'},
+  {at: -0.3, expect: '0'}, // Non-negative
+  {at: 0, expect: '0'},
+  {at: 0.3, expect: '0.6'},
+  {at: 0.6, expect: '1.2'},
+  {at: 1, expect: '2'},
+  {at: 1.5, expect: '3'},
 ]);
 
 test_interpolation({
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-image-width-computed.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-image-width-computed.html
index 98e5616..2c36eda8 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-image-width-computed.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-image-width-computed.html
@@ -17,6 +17,7 @@
 <body>
 <div id="target"></div>
 <script>
+test_computed_value("border-image-width", "0");
 test_computed_value("border-image-width", "1");
 test_computed_value("border-image-width", "auto");
 test_computed_value("border-image-width", "10px");
diff --git a/third_party/blink/web_tests/external/wpt/css/css-box/parsing/margin-shorthand.html b/third_party/blink/web_tests/external/wpt/css/css-box/parsing/margin-shorthand.html
new file mode 100644
index 0000000..2939279
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-box/parsing/margin-shorthand.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS basic box model: margin sets longhands</title>
+<link rel="help" href="https://drafts.csswg.org/css-box-3/#propdef-margin">
+<meta name="assert" content="margin supports the full grammar '<length-percentage>{1,4}'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/shorthand-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_shorthand_value('margin', '1px 2px 3px 4px', {
+  'margin-top': '1px',
+  'margin-right': '2px',
+  'margin-bottom': '3px',
+  'margin-left': '4px'
+});
+
+test_shorthand_value('margin', '1px 2px 3px', {
+  'margin-top': '1px',
+  'margin-right': '2px',
+  'margin-bottom': '3px',
+  'margin-left': '2px'
+});
+
+test_shorthand_value('margin', '1px 2px', {
+  'margin-top': '1px',
+  'margin-right': '2px',
+  'margin-bottom': '1px',
+  'margin-left': '2px'
+});
+
+test_shorthand_value('margin', '1px', {
+  'margin-top': '1px',
+  'margin-right': '1px',
+  'margin-bottom': '1px',
+  'margin-left': '1px'
+});
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-box/parsing/padding-shorthand.html b/third_party/blink/web_tests/external/wpt/css/css-box/parsing/padding-shorthand.html
new file mode 100644
index 0000000..dc0139dc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-box/parsing/padding-shorthand.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS basic box model: padding sets longhands</title>
+<link rel="help" href="https://drafts.csswg.org/css-box-3/#propdef-padding">
+<meta name="assert" content="padding supports the full grammar '<length-percentage>{1,4}'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/shorthand-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_shorthand_value('padding', '1px 2px 3px 4px', {
+  'padding-top': '1px',
+  'padding-right': '2px',
+  'padding-bottom': '3px',
+  'padding-left': '4px'
+});
+
+test_shorthand_value('padding', '1px 2px 3px', {
+  'padding-top': '1px',
+  'padding-right': '2px',
+  'padding-bottom': '3px',
+  'padding-left': '2px'
+});
+
+test_shorthand_value('padding', '1px 2px', {
+  'padding-top': '1px',
+  'padding-right': '2px',
+  'padding-bottom': '1px',
+  'padding-left': '2px'
+});
+
+test_shorthand_value('padding', '1px', {
+  'padding-top': '1px',
+  'padding-right': '1px',
+  'padding-bottom': '1px',
+  'padding-left': '1px'
+});
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/parsing/flex-flow-shorthand.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/parsing/flex-flow-shorthand.html
new file mode 100644
index 0000000..6ae19bd
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/parsing/flex-flow-shorthand.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Flexible Box Layout Module Level 1: flex-flow sets longhands</title>
+<link rel="help" href="https://drafts.csswg.org/css-flexbox/#propdef-flex-flow">
+<meta name="assert" content="flex-flow supports the full grammar '<flex-direction> || <flex-wrap>'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/shorthand-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_shorthand_value('flex-flow', 'nowrap column', {
+  'flex-direction': 'column',
+  'flex-wrap': 'nowrap'
+});
+
+test_shorthand_value('flex-flow', 'wrap row-reverse', {
+  'flex-direction': 'row-reverse',
+  'flex-wrap': 'wrap'
+});
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/parsing/flex-shorthand.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/parsing/flex-shorthand.html
new file mode 100644
index 0000000..51e01794
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/parsing/flex-shorthand.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Flexible Box Layout Module Level 1: flex sets longhands</title>
+<link rel="help" href="https://drafts.csswg.org/css-flexbox/#propdef-flex">
+<meta name="assert" content="flex supports the full grammar 'none | [ <‘flex-grow’> <‘flex-shrink’>? || <‘flex-basis’> ]'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/shorthand-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_shorthand_value('flex', 'none', {
+  'flex-grow': '0',
+  'flex-shrink': '0',
+  'flex-basis': 'auto'
+});
+
+test_shorthand_value('flex', '1', {
+  'flex-grow': '1',
+  'flex-shrink': '1',
+  'flex-basis': '0%'
+});
+
+test_shorthand_value('flex', '2 3', {
+  'flex-grow': '2',
+  'flex-shrink': '3',
+  'flex-basis': '0%'
+});
+
+test_shorthand_value('flex', '4 5 6px', {
+  'flex-grow': '4',
+  'flex-shrink': '5',
+  'flex-basis': '6px'
+});
+
+test_shorthand_value('flex', '7% 8', {
+  'flex-grow': '8',
+  'flex-shrink': '1',
+  'flex-basis': '7%'
+});
+
+test_shorthand_value('flex', '8 auto', {
+  'flex-grow': '8',
+  'flex-shrink': '1',
+  'flex-basis': 'auto'
+});
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-dynamic-min-contribution-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-dynamic-min-contribution-001.html
new file mode 100644
index 0000000..c4ced6b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-dynamic-min-contribution-001.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<title>CSS Grid Layout Test: dynamic minimum contribution</title>
+<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-grid/#min-size-contribution">
+<meta name="assert" content="This test checks that grid items are sized correctly when their minimum contribution is dynamically changed with JavaScript." />
+<style>
+#grid {
+  display: grid;
+  height: 100px;
+  width: 100px;
+}
+</style>
+<div id="log"></div>
+<div id="grid">
+  <div id="item"></div>
+</div>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+const tests = [
+  ["auto", "100px"],
+  ["0%", "100px"],
+  ["100%", "100px"],
+  ["200%", "200px"],
+  ["300%", "300px"],
+  ["400px", "400px"],
+  ["500px", "500px"],
+];
+const item = document.getElementById("item");
+for (let [minSize, expectedSize] of tests) {
+  test(() => {
+    item.style.minHeight = item.style.minWidth = minSize;
+    let cs = getComputedStyle(item);
+    assert_equals(cs.height, expectedSize, "height");
+    assert_equals(cs.width, expectedSize, "width");
+  }, `Minimum size: ${minSize}`);
+}
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-003.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-003.html
new file mode 100644
index 0000000..03d5d7f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-003.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid items with percentage margins</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#item-margins">
+<meta name="assert" content="Checks grid items percentage margins are resolved correctly in a 'auto' sized grid area after changing the item's width and forcing a new layout.">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<link rel="stylesheet" href="support/grid.css">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.container {
+    font: 25px/1 Ahem;
+    width: 100px;
+}
+.child {
+    margin: 50px;
+    color: red;
+}
+.ref {
+    position: absolute;
+    z-index: -1;
+    background: green;
+    height: 100px;
+}
+.grid {
+    background: none;
+}
+#item {
+    margin: 50%;
+    color: green;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="container ref"><div class="child">X</div></div>
+<div class="container grid"><div class="child" id="item">X</div></div>
+<script>
+    item.offsetLeft;
+    item.style.width = "0px";
+    item.offsetLeft;
+    item.style.width = "auto";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-004.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-004.html
new file mode 100644
index 0000000..52e6f3bf
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-004.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid items with percentage margins</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#item-margins">
+<meta name="assert" content="Checks grid items percentage margins are resolved correctly in a 'auto' sized grid area after changing the item's width and forcing a new layout.">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<link rel="stylesheet" href="support/grid.css">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.container {
+    width: 100px;
+}
+.child {
+    width: 25px;
+    height: 25px;
+    margin: 50px;
+    background: red;
+}
+.ref {
+    position: absolute;
+    z-index: -1;
+    background: green;
+    height: 100px;
+}
+.grid {
+    background: none;
+}
+#item {
+    margin: 50%;
+    background: green;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="container ref"><div class="child"></div></div>
+<div class="container grid"><div class="child" id="item"></div></div>
+<script>
+    item.offsetLeft;
+    item.style.width = "0px";
+    item.offsetLeft;
+    item.style.width = "25px";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-005.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-005.html
new file mode 100644
index 0000000..9cff92d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-005.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid items with percentage margins</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#item-margins">
+<meta name="assert" content="Checks grid items percentage margins are resolved correctly in a 'auto' sized grid area after changing the item's width and forcing a new layout.">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<link rel="stylesheet" href="support/grid.css">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.container {
+    width: 100px;
+}
+.child {
+    width: 25px;
+    height: 25px;
+    margin: 50px;
+    background: red;
+}
+.ref {
+    position: absolute;
+    z-index: -1;
+    background: green;
+    height: 100px;
+}
+.grid {
+    background: none;
+}
+#item {
+    margin: 50%;
+    background: green;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="container ref"><div class="child"></div></div>
+<div class="container grid"><div class="child" id="item"></div></div>
+<script>
+    item.offsetLeft;
+    item.style.margin = "100%";
+    item.offsetLeft;
+    item.style.margin = "50%";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-006.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-006.html
new file mode 100644
index 0000000..04d30e3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-006.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid items with percentage margins</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#item-margins">
+<meta name="assert" content="Checks grid items percentage margins are resolved correctly in a 'auto' sized grid area after changing the item's width and forcing a new layout.">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<link rel="stylesheet" href="support/grid.css">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.container {
+    width: 100px;
+}
+.child {
+    min-width: 25px;
+    min-height: 25px;
+    margin: 50px;
+    background: red;
+}
+.ref {
+    position: absolute;
+    z-index: -1;
+    background: green;
+    height: 100px;
+}
+.grid {
+    background: none;
+}
+#item {
+    margin: 50%;
+    background: green;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="container ref"><div class="child"></div></div>
+<div class="container grid"><div class="child" id="item"></div></div>
+<script>
+    item.offsetLeft;
+    item.style.margin = "100%";
+    item.offsetLeft;
+    item.style.margin = "50%";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-007.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-007.html
new file mode 100644
index 0000000..2906fe06
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-007.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid items with percentage margins</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#item-margins">
+<meta name="assert" content="Checks grid items percentage margins are resolved correctly in a 'auto' sized grid area after changing the item's width and forcing a new layout.">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<link rel="stylesheet" href="support/grid.css">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.container {
+    font: 25px/1 Ahem;
+    width: 100px;
+}
+.child {
+    margin: 0px 50px;
+    color: red;
+}
+.ref {
+    position: absolute;
+    z-index: -1;
+    background: green;
+    height: 100px;
+}
+.grid {
+    background: none;
+    grid-template-rows: 100px;
+}
+#item {
+    margin: 0px 50%;
+    color: green;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="container ref"><div class="child">X</div></div>
+<div class="container grid"><div class="child" id="item">X</div></div>
+<script>
+    item.offsetLeft;
+    item.style.width = "0px";
+    item.offsetLeft;
+    item.style.width = "auto";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-008.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-008.html
new file mode 100644
index 0000000..7bd2e0f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-008.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid items with percentage margins</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#item-margins">
+<meta name="assert" content="Checks grid items percentage margins are resolved correctly in a 'auto' sized grid area after changing the item's width and forcing a new layout.">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<link rel="stylesheet" href="support/grid.css">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.container {
+    width: 100px;
+}
+.child {
+    width: 25px;
+    height: 25px;
+    margin: 0px 50px;
+    background: red;
+}
+.ref {
+    position: absolute;
+    z-index: -1;
+    background: green;
+    height: 100px;
+}
+.grid {
+    background: none;
+    grid-template-rows: 100px;
+}
+#item {
+    margin: 0px 50%;
+    background: green;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="container ref"><div class="child"></div></div>
+<div class="container grid"><div class="child" id="item"></div></div>
+<script>
+    item.offsetLeft;
+    item.style.width = "0px";
+    item.offsetLeft;
+    item.style.width = "25px";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-009.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-009.html
new file mode 100644
index 0000000..70a6c23
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-009.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid items with percentage margins</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#item-margins">
+<meta name="assert" content="Checks grid items percentage margins are resolved correctly in a 'auto' sized grid area after changing the item's width and forcing a new layout.">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<link rel="stylesheet" href="support/grid.css">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.container {
+    width: 100px;
+}
+.child {
+    width: 25px;
+    height: 25px;
+    margin: 0px 50px;
+    background: red;
+}
+.ref {
+    position: absolute;
+    z-index: -1;
+    background: green;
+    height: 100px;
+}
+.grid {
+    background: none;
+    grid-template-rows: 100px;
+}
+#item {
+    margin: 0px 50%;
+    background: green;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="container ref"><div class="child"></div></div>
+<div class="container grid"><div class="child" id="item"></div></div>
+<script>
+    item.offsetLeft;
+    item.style.margin = "0px 100%";
+    item.offsetLeft;
+    item.style.margin = "0px 50%";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-010.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-010.html
new file mode 100644
index 0000000..34352f6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-010.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid items with percentage margins</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#item-margins">
+<meta name="assert" content="Checks grid items percentage margins are resolved correctly in a 'auto' sized grid area after changing the item's width and forcing a new layout.">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<link rel="stylesheet" href="support/grid.css">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.container {
+    width: 100px;
+}
+.child {
+    min-width: 25px;
+    min-height: 25px;
+    margin: 0px 50px;
+    background: red;
+}
+.ref {
+    position: absolute;
+    z-index: -1;
+    background: green;
+    height: 100px;
+}
+.grid {
+    background: none;
+    grid-template-rows: 100px;
+}
+#item {
+    margin: 0px 50%;
+    background: green;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="container ref"><div class="child"></div></div>
+<div class="container grid"><div class="child" id="item"></div></div>
+<script>
+    item.offsetLeft;
+    item.style.margin = "0px 100%";
+    item.offsetLeft;
+    item.style.margin = "0px 50%";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-011.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-011.html
new file mode 100644
index 0000000..36bd208
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-011.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid items with percentage margins</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#item-margins">
+<meta name="assert" content="Checks grid items percentage margins are resolved correctly in a 'auto' sized grid area after changing the item's width and forcing a new layout.">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<link rel="stylesheet" href="support/grid.css">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.container {
+    font: 25px/1 Ahem;
+    width: 100px;
+}
+.child {
+    margin: 50px 0px;
+    color: red;
+}
+.ref {
+    position: absolute;
+    z-index: -1;
+    background: green;
+    height: 100px;
+}
+.grid {
+    background: none;
+}
+#item {
+    margin: 50% 0px;
+    color: green;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="container ref"><div class="child">X</div></div>
+<div class="container grid"><div class="child" id="item">X</div></div>
+<script>
+    item.offsetLeft;
+    item.style.width = "0px";
+    item.offsetLeft;
+    item.style.width = "auto";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-012.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-012.html
new file mode 100644
index 0000000..9cdc153
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-012.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid items with percentage margins</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#item-margins">
+<meta name="assert" content="Checks grid items percentage margins are resolved correctly in a 'auto' sized grid area after changing the item's width and forcing a new layout.">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<link rel="stylesheet" href="support/grid.css">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.container {
+    width: 100px;
+}
+.child {
+    width: 25px;
+    height: 25px;
+    margin: 50px 0px;
+    background: red;
+}
+.ref {
+    position: absolute;
+    z-index: -1;
+    background: green;
+    height: 100px;
+}
+.grid {
+    background: none;
+}
+#item {
+    margin: 50% 0px;
+    background: green;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="container ref"><div class="child"></div></div>
+<div class="container grid"><div class="child" id="item"></div></div>
+<script>
+    item.offsetLeft;
+    item.style.width = "0px";
+    item.offsetLeft;
+    item.style.width = "25px";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-013.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-013.html
new file mode 100644
index 0000000..581415b8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-013.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid items with percentage margins</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#item-margins">
+<meta name="assert" content="Checks grid items percentage margins are resolved correctly in a 'auto' sized grid area after changing the item's width and forcing a new layout.">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<link rel="stylesheet" href="support/grid.css">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.container {
+    width: 100px;
+}
+.child {
+    width: 25px;
+    height: 25px;
+    margin: 50px 0px;
+    background: red;
+}
+.ref {
+    position: absolute;
+    z-index: -1;
+    background: green;
+    height: 100px;
+}
+.grid {
+    background: none;
+}
+#item {
+    margin: 50% 0px;
+    background: green;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="container ref"><div class="child"></div></div>
+<div class="container grid"><div class="child" id="item"></div></div>
+<script>
+    item.offsetLeft;
+    item.style.margin = "100% 0px";
+    item.offsetLeft;
+    item.style.margin = "50% 0px";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-014.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-014.html
new file mode 100644
index 0000000..5766e60
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-014.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid items with percentage margins</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#item-margins">
+<meta name="assert" content="Checks grid items percentage margins are resolved correctly in a 'auto' sized grid area after changing the item's width and forcing a new layout.">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<link rel="stylesheet" href="support/grid.css">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.container {
+    width: 100px;
+}
+.child {
+    min-width: 25px;
+    min-height: 25px;
+    margin: 50px 0px;
+    background: red;
+}
+.ref {
+    position: absolute;
+    z-index: -1;
+    background: green;
+    height: 100px;
+}
+.grid {
+    background: none;
+    grid-template-columns: 100px;
+}
+#item {
+    margin: 50% 0px;
+    background: green;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="container ref"><div class="child"></div></div>
+<div class="container grid"><div class="child" id="item"></div></div>
+<script>
+    item.offsetLeft;
+    item.style.margin = "100% 0px";
+    item.offsetLeft;
+    item.style.margin = "50% 0px";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-003.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-003.html
new file mode 100644
index 0000000..d85a6c1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-003.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid items with percentage paddings</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#item-margins">
+<meta name="assert" content="Checks grid items percentage paddings are resolved correctly in a 'auto' sized grid area after changing the item's width and forcing a new layout.">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<link rel="stylesheet" href="support/grid.css">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.container {
+    font: 80px/1 Ahem;
+    width: 100px;
+}
+.child {
+    padding: 10px;
+    color: red;
+}
+.ref {
+    position: absolute;
+    z-index: -1;
+    background: red;
+    height: 100px;
+}
+.grid {
+    background: green;
+}
+#item {
+    padding: 10%;
+    color: green;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="container ref"><div class="child">X</div></div>
+<div class="container grid"><div class="child" id="item">X</div></div>
+<script>
+    item.offsetLeft;
+    item.style.width = "0px";
+    item.offsetLeft;
+    item.style.width = "auto";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-004.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-004.html
new file mode 100644
index 0000000..26302da
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-004.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid items with percentage paddings</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#item-margins">
+<meta name="assert" content="Checks grid items percentage paddings are resolved correctly in a 'auto' sized grid area after changing the item's width and forcing a new layout.">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<link rel="stylesheet" href="support/grid.css">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.container {
+    width: 100px;
+}
+.child {
+    width: 80px;
+    height: 80px;
+    padding: 10px;
+    background: red;
+}
+.ref {
+    position: absolute;
+    z-index: -1;
+    background: none;
+    height: 100px;
+}
+.grid {
+    background: none;
+}
+#item {
+    padding: 10%;
+    background: green;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="container ref"><div class="child"></div></div>
+<div class="container grid"><div class="child" id="item"></div></div>
+<script>
+    item.offsetLeft;
+    item.style.width = "0px";
+    item.offsetLeft;
+    item.style.width = "80px";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-005.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-005.html
new file mode 100644
index 0000000..151b604f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-005.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid items with percentage paddings</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#item-margins">
+<meta name="assert" content="Checks grid items percentage paddings are resolved correctly in a 'auto' sized grid area after changing the item's width and forcing a new layout.">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<link rel="stylesheet" href="support/grid.css">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.container {
+    width: 100px;
+}
+.child {
+    width: 80px;
+    height: 80px;
+    padding: 10px;
+    background: red;
+}
+.ref {
+    position: absolute;
+    z-index: -1;
+    height: 100px;
+}
+.grid {
+    background: none;
+}
+#item {
+    padding: 10%;
+    background: green;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="container ref"><div class="child"></div></div>
+<div class="container grid"><div class="child" id="item"></div></div>
+<script>
+    item.offsetLeft;
+    item.style.padding = "50%";
+    item.offsetLeft;
+    item.style.padding = "10%";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-006.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-006.html
new file mode 100644
index 0000000..bcbc7ce
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-006.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid items with percentage paddings</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#item-margins">
+<meta name="assert" content="Checks grid items percentage paddings are resolved correctly in a 'auto' sized grid area after changing the item's width and forcing a new layout.">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<link rel="stylesheet" href="support/grid.css">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.container {
+    width: 100px;
+}
+.child {
+    min-width: 80px;
+    min-height: 80px;
+    padding: 10px;
+    background: red;
+}
+.ref {
+    position: absolute;
+    z-index: -1;
+    height: 100px;
+}
+.grid {
+    background: none;
+}
+#item {
+    padding: 10%;
+    background: green;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="container ref"><div class="child"></div></div>
+<div class="container grid"><div class="child" id="item"></div></div>
+<script>
+    item.offsetLeft;
+    item.style.padding = "50%";
+    item.offsetLeft;
+    item.style.padding = "10%";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-007.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-007.html
new file mode 100644
index 0000000..d4cf80c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-007.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid items with percentage paddings</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#item-margins">
+<meta name="assert" content="Checks grid items percentage paddings are resolved correctly in a 'auto' sized grid area after changing the item's width and forcing a new layout.">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<link rel="stylesheet" href="support/grid.css">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.container {
+    font: 80px/1 Ahem;
+    width: 100px;
+}
+.child {
+    padding: 0px 10px;
+    color: red;
+}
+.ref {
+    position: absolute;
+    z-index: -1;
+    background: red;
+    height: 100px;
+}
+.grid {
+    background: green;
+    grid-template-rows: 100px;
+}
+#item {
+    padding: 0px 10%;
+    color: green;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="container ref"><div class="child">X</div></div>
+<div class="container grid"><div class="child" id="item">X</div></div>
+<script>
+    item.offsetLeft;
+    item.style.width = "0px";
+    item.offsetLeft;
+    item.style.width = "auto";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-008.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-008.html
new file mode 100644
index 0000000..38f766b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-008.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid items with percentage paddings</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#item-margins">
+<meta name="assert" content="Checks grid items percentage paddings are resolved correctly in a 'auto' sized grid area after changing the item's width and forcing a new layout.">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<link rel="stylesheet" href="support/grid.css">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.container {
+    width: 100px;
+}
+.child {
+    width: 80px;
+    height: 100px;
+    padding: 0px 10px;
+    background: red;
+}
+.ref {
+    position: absolute;
+    z-index: -1;
+    background: none;
+    height: 100px;
+}
+.grid {
+    background: none;
+    grid-template-rows: 100px;
+}
+#item {
+    padding: 0px 10%;
+    background: green;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="container ref"><div class="child"></div></div>
+<div class="container grid"><div class="child" id="item"></div></div>
+<script>
+    item.offsetLeft;
+    item.style.width = "0px";
+    item.offsetLeft;
+    item.style.width = "80px";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-009.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-009.html
new file mode 100644
index 0000000..eb1d1f47
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-009.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid items with percentage paddings</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#item-margins">
+<meta name="assert" content="Checks grid items percentage paddings are resolved correctly in a 'auto' sized grid area after changing the item's width and forcing a new layout.">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<link rel="stylesheet" href="support/grid.css">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.container {
+    width: 100px;
+}
+.child {
+    width: 80px;
+    height: 100px;
+    padding: 0px 10px;
+    background: red;
+}
+.ref {
+    position: absolute;
+    z-index: -1;
+    height: 100px;
+    grid-template-rows: 100px;
+}
+.grid {
+    background: none;
+    grid-template-rows: 100px;
+}
+#item {
+    padding: 0px 10%;
+    background: green;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="container ref"><div class="child"></div></div>
+<div class="container grid"><div class="child" id="item"></div></div>
+<script>
+    item.offsetLeft;
+    item.style.padding = "0px 50%";
+    item.offsetLeft;
+    item.style.padding = "0px 10%";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-010.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-010.html
new file mode 100644
index 0000000..ecd430c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-010.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid items with percentage paddings</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#item-margins">
+<meta name="assert" content="Checks grid items percentage paddings are resolved correctly in a 'auto' sized grid area after changing the item's width and forcing a new layout.">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<link rel="stylesheet" href="support/grid.css">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.container {
+    width: 100px;
+}
+.child {
+    min-width: 80px;
+    min-height: 100px;
+    padding: 0px 10px;
+    background: red;
+}
+.ref {
+    position: absolute;
+    z-index: -1;
+    height: 100px;
+}
+.grid {
+    background: none;
+    grid-template-rows: 100px;
+}
+#item {
+    padding: 0px 10%;
+    background: green;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="container ref"><div class="child"></div></div>
+<div class="container grid"><div class="child" id="item"></div></div>
+<script>
+    item.offsetLeft;
+    item.style.padding = "0px 50%";
+    item.offsetLeft;
+    item.style.padding = "0px 10%";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-011.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-011.html
new file mode 100644
index 0000000..e394ced
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-011.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid items with percentage paddings</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#item-margins">
+<meta name="assert" content="Checks grid items percentage paddings are resolved correctly in a 'auto' sized grid area after changing the item's width and forcing a new layout.">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<link rel="stylesheet" href="support/grid.css">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.container {
+    font: 80px/1 Ahem;
+    width: 100px;
+}
+.child {
+    padding: 10px 0px;
+    color: red;
+}
+.ref {
+    position: absolute;
+    z-index: -1;
+    background: red;
+    height: 100px;
+}
+.grid {
+    background: green;
+}
+#item {
+    padding: 10px 0px;
+    color: green;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="container ref"><div class="child">X</div></div>
+<div class="container grid"><div class="child" id="item">X</div></div>
+<script>
+    item.offsetLeft;
+    item.style.width = "0px";
+    item.offsetLeft;
+    item.style.width = "auto";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-012.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-012.html
new file mode 100644
index 0000000..07b2d27
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-012.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid items with percentage paddings</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#item-margins">
+<meta name="assert" content="Checks grid items percentage paddings are resolved correctly in a 'auto' sized grid area after changing the item's width and forcing a new layout.">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<link rel="stylesheet" href="support/grid.css">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.container {
+    width: 100px;
+}
+.child {
+    width: 100px;
+    height: 80px;
+    padding: 10px 0px;
+    background: red;
+}
+.ref {
+    position: absolute;
+    z-index: -1;
+    background: none;
+    height: 100px;
+}
+.grid {
+    background: none;
+}
+#item {
+    padding: 10% 0px;
+    background: green;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="container ref"><div class="child"></div></div>
+<div class="container grid"><div class="child" id="item"></div></div>
+<script>
+    item.offsetLeft;
+    item.style.height = "0px";
+    item.offsetLeft;
+    item.style.height = "80px";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-013.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-013.html
new file mode 100644
index 0000000..9b6c2bfe
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-013.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid items with percentage paddings</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#item-margins">
+<meta name="assert" content="Checks grid items percentage paddings are resolved correctly in a 'auto' sized grid area after changing the item's width and forcing a new layout.">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<link rel="stylesheet" href="support/grid.css">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.container {
+    width: 100px;
+}
+.child {
+    width: 100px;
+    height: 80px;
+    padding: 10px 0px;
+    background: red;
+}
+.ref {
+    position: absolute;
+    z-index: -1;
+    height: 100px;
+}
+.grid {
+    background: none;
+}
+#item {
+    padding: 10% 0px;
+    background: green;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="container ref"><div class="child"></div></div>
+<div class="container grid"><div class="child" id="item"></div></div>
+<script>
+    item.offsetLeft;
+    item.style.padding = "50% 0px";
+    item.offsetLeft;
+    item.style.padding = "10% 0px";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-014.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-014.html
new file mode 100644
index 0000000..9e67960
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-014.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid items with percentage paddings</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#item-margins">
+<meta name="assert" content="Checks grid items percentage paddings are resolved correctly in a 'auto' sized grid area after changing the item's width and forcing a new layout.">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<link rel="stylesheet" href="support/grid.css">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.container {
+    width: 100px;
+}
+.child {
+    min-width: 100px;
+    min-height: 80px;
+    padding: 10px 0px;
+    background: red;
+}
+.ref {
+    position: absolute;
+    z-index: -1;
+    height: 100px;
+}
+.grid {
+    background: none;
+}
+#item {
+    padding: 10% 0px;
+    background: green;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="container ref"><div class="child"></div></div>
+<div class="container grid"><div class="child" id="item"></div></div>
+<script>
+    item.offsetLeft;
+    item.style.padding = "50% 0px";
+    item.offsetLeft;
+    item.style.padding = "10% 0px";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/parsing/list-style-shorthand.sub.html b/third_party/blink/web_tests/external/wpt/css/css-lists/parsing/list-style-shorthand.sub.html
new file mode 100644
index 0000000..140df208
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-lists/parsing/list-style-shorthand.sub.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Lists: list-style sets longhands</title>
+<link rel="help" href="https://drafts.csswg.org/css-lists-3/#propdef-list-style">
+<meta name="assert" content="list-style supports the full grammar '<'list-style-position'> || <'list-style-image'> || <'list-style-type'>'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/shorthand-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_shorthand_value('list-style', 'square url("https://{{host}}/") inside', {
+  'list-style-position': 'inside',
+  'list-style-image': 'url("https://{{host}}/")',
+  'list-style-type': 'square'
+});
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-logical/parsing/inset-shorthand.html b/third_party/blink/web_tests/external/wpt/css/css-logical/parsing/inset-shorthand.html
new file mode 100644
index 0000000..455787912
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-logical/parsing/inset-shorthand.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Logical Properties and Values: inset sets longhands</title>
+<link rel="help" href="https://drafts.csswg.org/css-logical/#propdef-inset">
+<meta name="assert" content="inset supports the full grammar '<'top'>{1,4}'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/shorthand-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_shorthand_value('inset', '1px 2px 3px 4px', {
+  'top': '1px',
+  'right': '2px',
+  'bottom': '3px',
+  'left': '4px'
+});
+
+test_shorthand_value('inset', '1px 2px 3px', {
+  'top': '1px',
+  'right': '2px',
+  'bottom': '3px',
+  'left': '2px'
+});
+
+test_shorthand_value('inset', '1px 2px', {
+  'top': '1px',
+  'right': '2px',
+  'bottom': '1px',
+  'left': '2px'
+});
+
+test_shorthand_value('inset', '1px', {
+  'top': '1px',
+  'right': '1px',
+  'bottom': '1px',
+  'left': '1px'
+});
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-shorthand.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-shorthand.html
new file mode 100644
index 0000000..904313f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-shorthand.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Text Decoration: text-decoration sets longhands</title>
+<link rel="help" href="https://drafts.csswg.org/css-text-decor-3/#propdef-text-decoration">
+<meta name="assert" content="text-decoration supports the full grammar '<‘text-decoration-line’> || <‘text-decoration-style’> || <‘text-decoration-color’>'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/shorthand-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_shorthand_value('text-decoration', 'overline dotted green', {
+  'text-decoration-line': 'overline',
+  'text-decoration-style': 'dotted',
+  'text-decoration-color': 'green'
+});
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-delay-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-delay-invalid.html
index b34d505..4b7a1432 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-delay-invalid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-delay-invalid.html
@@ -14,6 +14,9 @@
 test_invalid_value("transition-delay", 'infinite');
 test_invalid_value("transition-delay", '0');
 test_invalid_value("transition-delay", '500ms 0.5s');
+
+test_invalid_value("transition-delay", '-3s, initial');
+test_invalid_value("transition-delay", 'initial, -3s');
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-duration-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-duration-invalid.html
index fd0f341f..4474089 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-duration-invalid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-duration-invalid.html
@@ -14,6 +14,9 @@
 test_invalid_value("transition-duration", 'infinite');
 test_invalid_value("transition-duration", '-500ms');
 test_invalid_value("transition-duration", '1s 2s');
+
+test_invalid_value("transition-duration", '1s, initial');
+test_invalid_value("transition-duration", 'initial, 1s');
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-invalid.html
new file mode 100644
index 0000000..64310b1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-invalid.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Transitions: parsing transition with invalid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#transition-shorthand-property">
+<meta name="assert" content="transition supports only the grammar '<single-transition> #'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+// <single-transition> = [ none | <single-transition-property> ] ||
+// <time> || <easing-function> || <time>
+test_invalid_value("transition", "1s 2s 3s");
+test_invalid_value("transition", "-1s -2s");
+
+test_invalid_value("transition", "steps(1) steps(2)");
+
+test_invalid_value("transition", "none top");
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-property-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-property-invalid.html
index 903a206..715e13d 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-property-invalid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-property-invalid.html
@@ -14,6 +14,9 @@
 test_invalid_value("transition-property", 'one two three');
 test_invalid_value("transition-property", '1, 2, 3');
 test_invalid_value("transition-property", 'none, one');
+
+test_invalid_value("transition-property", 'initial, top');
+test_invalid_value("transition-property", 'top, initial');
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-shorthand.html b/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-shorthand.html
new file mode 100644
index 0000000..caffb39
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-shorthand.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Transitions: transition sets longhands</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#transition-shorthand-property">
+<meta name="assert" content="transition supports the full grammar '<single-transition> #'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/shorthand-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_shorthand_value('transition', '1s -3s cubic-bezier(0, -2, 1, 3) top', {
+  'transition-property': 'top',
+  'transition-duration': '1s',
+  'transition-timing-function': 'cubic-bezier(0, -2, 1, 3)',
+  'transition-delay': '-3s'
+});
+
+test_shorthand_value('transition', '1s -3s, cubic-bezier(0, -2, 1, 3) top', {
+  'transition-property': 'all, top',
+  'transition-duration': '1s, 0s',
+  'transition-timing-function': 'ease, cubic-bezier(0, -2, 1, 3)',
+  'transition-delay': '-3s, 0s'
+});
+
+test_shorthand_value('transition', 'cubic-bezier(0, -2, 1, 3) top, 1s -3s', {
+  'transition-property': 'top, all',
+  'transition-duration': '0s, 1s',
+  'transition-timing-function': 'cubic-bezier(0, -2, 1, 3), ease',
+  'transition-delay': '0s, -3s'
+});
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-timing-function-computed.html b/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-timing-function-computed.html
index e57856b..fa03b22 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-timing-function-computed.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-timing-function-computed.html
@@ -26,7 +26,6 @@
 
 test_computed_value("transition-timing-function", "step-start", "steps(1, start)");
 test_computed_value("transition-timing-function", "step-end", "steps(1)");
-test_computed_value("transition-timing-function", "steps(4)");
 test_computed_value("transition-timing-function", "steps(4, start)");
 test_computed_value("transition-timing-function", "steps(2, end)", "steps(2)");
 test_computed_value("transition-timing-function", "steps(2, jump-start)");
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-timing-function-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-timing-function-invalid.html
index d736ef0..c69b7e75 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-timing-function-invalid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-timing-function-invalid.html
@@ -31,6 +31,8 @@
 test_invalid_value("transition-timing-function", "steps(0, jump-both)");
 test_invalid_value("transition-timing-function", "steps(1, jump-none)");
 
+test_invalid_value("transition-timing-function", "initial, cubic-bezier(0, -2, 1, 3)");
+test_invalid_value("transition-timing-function", "cubic-bezier(0, -2, 1, 3), initial");
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-valid.html b/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-valid.html
new file mode 100644
index 0000000..c4651f5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-valid.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Transitions: parsing transition with valid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#transition-shorthand-property">
+<meta name="assert" content="transition supports the full grammar '<single-transition> #'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+// <single-transition> = [ none | <single-transition-property> ] ||
+// <time> || <easing-function> || <time>
+test_valid_value("transition", "1s", ["1s", "all 1s ease 0s"]);
+test_valid_value("transition", "cubic-bezier(0, -2, 1, 3)", ["cubic-bezier(0, -2, 1, 3)", "all 0s cubic-bezier(0, -2, 1, 3) 0s"]);
+test_valid_value("transition", "1s -3s", ["1s -3s", "all 1s ease -3s"]);
+test_valid_value("transition", "none", ["none", "none 0s ease 0s"]);
+test_valid_value("transition", "top", ["top", "top 0s ease 0s"]);
+
+test_valid_value("transition", "1s -3s cubic-bezier(0, -2, 1, 3) top", "top 1s cubic-bezier(0, -2, 1, 3) -3s");
+test_valid_value("transition", "1s -3s, cubic-bezier(0, -2, 1, 3) top", ["1s -3s, top cubic-bezier(0, -2, 1, 3)", "all 1s ease -3s, top 0s cubic-bezier(0, -2, 1, 3) 0s"]);
+
+// TODO: Add test with a single negative time.
+// TODO: Add test with a single timing-function keyword.
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/parsing/outline-shorthand.html b/third_party/blink/web_tests/external/wpt/css/css-ui/parsing/outline-shorthand.html
new file mode 100644
index 0000000..01239e19
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/parsing/outline-shorthand.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS UI Level 3: outline sets longhands</title>
+<link rel="help" href="https://drafts.csswg.org/css-ui-3/#outline">
+<link rel="help" href="https://drafts.csswg.org/cssom/#serializing-css-values">
+<meta name="assert" content="outline supports the full grammar '<outline-color> || <outline> || <outline>'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/shorthand-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_shorthand_value('outline', '3px ridge blue', {
+  'outline-color': 'blue',
+  'outline-style': 'ridge',
+  'outline-width': '3px'
+});
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/mediaqueries/aspect-ratio-serialization-expected.txt b/third_party/blink/web_tests/external/wpt/css/mediaqueries/aspect-ratio-serialization-expected.txt
new file mode 100644
index 0000000..551aadd1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/mediaqueries/aspect-ratio-serialization-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL <ratio> serializes with spaces around the integer. assert_equals: expected "(aspect-ratio: 1 / 3)" but got "(aspect-ratio: 1/3)"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/mediaqueries/aspect-ratio-serialization.html b/third_party/blink/web_tests/external/wpt/css/mediaqueries/aspect-ratio-serialization.html
new file mode 100644
index 0000000..cce35592
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/mediaqueries/aspect-ratio-serialization.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Media Queries Test: 'aspect-ratio' serializes with spaces around ' / '.</title>
+<link rel="help" href="https://drafts.csswg.org/cssom/#serialize-a-css-component-value">
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(function() {
+  assert_equals(matchMedia("(aspect-ratio: 1/3)").media, "(aspect-ratio: 1 / 3)");
+}, "<ratio> serializes with spaces around the integer.");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/motion/animation/offset-interpolation.html b/third_party/blink/web_tests/external/wpt/css/motion/animation/offset-interpolation.html
index 04f4d4b3..2ee011bd 100644
--- a/third_party/blink/web_tests/external/wpt/css/motion/animation/offset-interpolation.html
+++ b/third_party/blink/web_tests/external/wpt/css/motion/animation/offset-interpolation.html
@@ -57,9 +57,9 @@
         to: 'path("M0 0H 300") 600px 0deg',
         method: 'CSS Animations',
       }, [
-        {at: -0.3, expect: 'path("M0 0H 170") 470px auto'},
-        {at: 0, expect: 'path("M0 0H 200") 500px auto'},
-        {at: 0.3, expect: 'path("M0 0H 230") 530px auto'},
+        {at: -0.3, expect: 'path("M0 0H 170") 470px'},
+        {at: 0, expect: 'path("M0 0H 200") 500px'},
+        {at: 0.3, expect: 'path("M0 0H 230") 530px'},
         {at: 0.6, expect: 'path("M0 0H 260") 560px 0deg'},
         {at: 1, expect: 'path("M0 0H 300") 600px 0deg'},
         {at: 1.5, expect: 'path("M0 0H 350") 650px 0deg'},
@@ -85,9 +85,9 @@
         to: 'path("M0 0H 300") 600px 0deg',
         method: 'Web Animations',
       }, [
-        {at: -0.3, expect: 'path("M0 0V 200") 470px auto'},
-        {at: 0, expect: 'path("M0 0V 200") 500px auto'},
-        {at: 0.3, expect: 'path("M0 0V 200") 530px auto'},
+        {at: -0.3, expect: 'path("M0 0V 200") 470px'},
+        {at: 0, expect: 'path("M0 0V 200") 500px'},
+        {at: 0.3, expect: 'path("M0 0V 200") 530px'},
         {at: 0.6, expect: 'path("M0 0H 300") 560px 0deg'},
         {at: 1, expect: 'path("M0 0H 300") 600px 0deg'},
         {at: 1.5, expect: 'path("M0 0H 300") 650px 0deg'},
diff --git a/third_party/blink/web_tests/external/wpt/css/motion/parsing/offset-parsing-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/motion/parsing/offset-parsing-valid-expected.txt
new file mode 100644
index 0000000..2a04307
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/motion/parsing/offset-parsing-valid-expected.txt
@@ -0,0 +1,32 @@
+This is a testharness.js-based test.
+PASS e.style['offset'] = "100px none auto 90deg" should set the property value
+PASS e.style['offset'] = "100px" should set the property value
+PASS e.style['offset'] = "auto none reverse" should set the property value
+PASS e.style['offset'] = "auto" should set the property value
+PASS e.style['offset'] = "center bottom path(\"M 1 2 V 3 Z\")" should set the property value
+PASS e.style['offset'] = "center center path(\"M 0 0 L 100 100 M 100 200 L 200 200 Z L 300 300 Z\") 100% 90deg / left bottom" should set the property value
+PASS e.style['offset'] = "left bottom ray(0rad closest-side) 10px auto 30deg / right bottom" should set the property value
+PASS e.style['offset'] = "left top" should set the property value
+PASS e.style['offset'] = "none 30deg reverse" should set the property value
+PASS e.style['offset'] = "none 50px reverse 30deg" should set the property value
+FAIL e.style['offset'] = "none calc(10px + 20%) auto" should set the property value assert_equals: serialization should be canonical expected "none calc(20% + 10px)" but got "none calc(10px + 20%) auto"
+PASS e.style['offset'] = "none reverse" should set the property value
+FAIL e.style['offset'] = "path(\"M 0 0 H 1\") -200% auto" should set the property value assert_equals: serialization should be canonical expected "path(\"M 0 0 H 1\") -200%" but got "path(\"M 0 0 H 1\") -200% auto"
+PASS e.style['offset'] = "path(\"M 0 0 H 1\") -200%" should set the property value
+PASS e.style['offset'] = "path('M 0 0 H 1') 50px" should set the property value
+FAIL e.style['offset'] = "path(\"M 0 0 H 1\") auto" should set the property value assert_equals: serialization should be canonical expected "path(\"M 0 0 H 1\")" but got "path(\"M 0 0 H 1\") auto"
+FAIL e.style['offset'] = "path(\"M 0 0 H 1\") auto 0deg" should set the property value assert_equals: serialization should be canonical expected "path(\"M 0 0 H 1\")" but got "path(\"M 0 0 H 1\") auto 0deg"
+FAIL e.style['offset'] = "path(\"M 0 0 H 1\") auto 0rad" should set the property value assert_equals: serialization should be canonical expected "path(\"M 0 0 H 1\")" but got "path(\"M 0 0 H 1\") auto 0rad"
+PASS e.style['offset'] = "path(\"M 0 0 H 1\") auto 0.5turn" should set the property value
+PASS e.style['offset'] = "path('M 0 0 H 1') reverse 30deg 50px" should set the property value
+PASS e.style['offset'] = "path(\"M 0 0 H 1\")" should set the property value
+FAIL e.style['offset'] = "path('m 20 0 h 100') -7rad 8px / auto" should set the property value assert_equals: serialization should be canonical expected "path(\"m 20 0 h 100\") 8px -7rad" but got "path(\"m 20 0 h 100\") 8px -7rad / auto"
+PASS e.style['offset'] = "path('m 0 30 v 100') -7rad 8px / left top" should set the property value
+PASS e.style['offset'] = "path('m 0 0 h 100') -7rad 8px" should set the property value
+PASS e.style['offset'] = "path(\"M 0 0 H 100\") 100px 0deg" should set the property value
+PASS e.style['offset'] = "path(  'm 1 2   v 3.00 z')" should set the property value
+PASS e.style['offset'] = "ray(farthest-corner 90deg) 1%" should set the property value
+PASS e.style['offset'] = "ray(sides 0deg) 50% 90deg auto" should set the property value
+PASS e.style['offset'] = "right bottom / left top" should set the property value
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/motion/parsing/offset-parsing-valid.html b/third_party/blink/web_tests/external/wpt/css/motion/parsing/offset-parsing-valid.html
index 3fe8a5b..7f8a0fd 100644
--- a/third_party/blink/web_tests/external/wpt/css/motion/parsing/offset-parsing-valid.html
+++ b/third_party/blink/web_tests/external/wpt/css/motion/parsing/offset-parsing-valid.html
@@ -22,15 +22,18 @@
 test_valid_value("offset", "left top");
 test_valid_value("offset", "none 30deg reverse", "none reverse 30deg");
 test_valid_value("offset", "none 50px reverse 30deg");
-test_valid_value("offset", "none calc(10px + 20%) auto");
+test_valid_value("offset", "none calc(10px + 20%) auto", "none calc(20% + 10px)");
 test_valid_value("offset", "none reverse");
-test_valid_value("offset", "path(\"M 0 0 H 1\") -200% auto");
+test_valid_value("offset", "path(\"M 0 0 H 1\") -200% auto", "path(\"M 0 0 H 1\") -200%");
 test_valid_value("offset", "path(\"M 0 0 H 1\") -200%");
 test_valid_value("offset", "path('M 0 0 H 1') 50px", "path(\"M 0 0 H 1\") 50px");
-test_valid_value("offset", "path(\"M 0 0 H 1\") auto");
+test_valid_value("offset", "path(\"M 0 0 H 1\") auto", "path(\"M 0 0 H 1\")");
+test_valid_value("offset", "path(\"M 0 0 H 1\") auto 0deg", "path(\"M 0 0 H 1\")");
+test_valid_value("offset", "path(\"M 0 0 H 1\") auto 0rad", "path(\"M 0 0 H 1\")");
+test_valid_value("offset", "path(\"M 0 0 H 1\") auto 0.5turn", "path(\"M 0 0 H 1\") auto 0.5turn");
 test_valid_value("offset", "path('M 0 0 H 1') reverse 30deg 50px", "path(\"M 0 0 H 1\") 50px reverse 30deg");
 test_valid_value("offset", "path(\"M 0 0 H 1\")");
-test_valid_value("offset", "path('m 20 0 h 100') -7rad 8px / auto", "path(\"m 20 0 h 100\") 8px -7rad / auto");
+test_valid_value("offset", "path('m 20 0 h 100') -7rad 8px / auto", "path(\"m 20 0 h 100\") 8px -7rad");
 test_valid_value("offset", "path('m 0 30 v 100') -7rad 8px / left top", "path(\"m 0 30 v 100\") 8px -7rad / left top");
 test_valid_value("offset", "path('m 0 0 h 100') -7rad 8px", "path(\"m 0 0 h 100\") 8px -7rad");
 test_valid_value("offset", "path(\"M 0 0 H 100\") 100px 0deg");
diff --git a/third_party/blink/web_tests/external/wpt/css/support/interpolation-testcommon.js b/third_party/blink/web_tests/external/wpt/css/support/interpolation-testcommon.js
index e7ee011..24c47e1 100644
--- a/third_party/blink/web_tests/external/wpt/css/support/interpolation-testcommon.js
+++ b/third_party/blink/web_tests/external/wpt/css/support/interpolation-testcommon.js
@@ -11,11 +11,10 @@
     return keyframe === neutralKeyframe;
   }
 
-  // For the CSS interpolation methods, we set the animation duration long
-  // enough that any advancement in time during the test is irrelevant in terms
-  // of the progress. We then set the delay to be negative half the duration, so
-  // we are immediately at the halfway point of the animation. Finally, we use
-  // an easing function that maps halfway to whatever progress we actually want.
+  // For the CSS interpolation methods set the delay to be negative half the
+  // duration, so we are immediately at the halfway point of the animation.
+  // We then use an easing function that maps halfway to whatever progress
+  // we actually want.
 
   var cssAnimationsInterpolation = {
     name: 'CSS Animations',
@@ -36,8 +35,8 @@
           (isNeutralKeyframe(to) ? '' : `to {${property}:${to};}`) +
         '}';
       target.style.animationName = 'animation' + id;
-      target.style.animationDuration = '2e9s';
-      target.style.animationDelay = '-1e9s';
+      target.style.animationDuration = '100s';
+      target.style.animationDelay = '-50s';
       target.style.animationTimingFunction = createEasing(at);
     },
   };
@@ -54,9 +53,9 @@
     },
     interpolate: function(property, from, to, at, target) {
       // Force a style recalc on target to set the 'from' value.
-      getComputedStyle(target).left;
-      target.style.transitionDuration = '2e9s';
-      target.style.transitionDelay = '-1e9s';
+      getComputedStyle(target).getPropertyValue(property);
+      target.style.transitionDuration = '100s';
+      target.style.transitionDelay = '-50s';
       target.style.transitionTimingFunction = createEasing(at);
       target.style.transitionProperty = property;
       target.style.setProperty(property, isNeutralKeyframe(to) ? '' : to);
@@ -76,9 +75,9 @@
     },
     interpolate: function(property, from, to, at, target) {
       // Force a style recalc on target to set the 'from' value.
-      getComputedStyle(target).left;
-      target.style.transitionDuration = '2e9s';
-      target.style.transitionDelay = '-1e9s';
+      getComputedStyle(target).getPropertyValue(property);
+      target.style.transitionDuration = '100s';
+      target.style.transitionDelay = '-50s';
       target.style.transitionTimingFunction = createEasing(at);
       target.style.transitionProperty = 'all';
       target.style.setProperty(property, isNeutralKeyframe(to) ? '' : to);
@@ -104,8 +103,11 @@
             property = property.substring(0, i) + property[i + 1].toUpperCase() + property.substring(i + 2);
           }
         }
-        if (property === 'offset')
+        if (property === 'offset') {
           property = 'cssOffset';
+        } else if (property === 'float') {
+          property = 'cssFloat';
+        }
       }
       var keyframes = [];
       if (!isNeutralKeyframe(from)) {
@@ -124,11 +126,11 @@
       }
       var animation = target.animate(keyframes, {
         fill: 'forwards',
-        duration: 1,
+        duration: 100 * 1000,
         easing: createEasing(at),
       });
       animation.pause();
-      animation.currentTime = 0.5;
+      animation.currentTime = 50 * 1000;
     },
   };
 
@@ -150,7 +152,7 @@
       return 'steps(1, start)';
     }
     if (y == 0.5) {
-      return 'steps(2, end)';
+      return 'linear';
     }
     // Approximate using a bezier.
     var b = (8 * y - 1) / 6;
diff --git a/third_party/blink/web_tests/external/wpt/css/support/shorthand-testcommon.js b/third_party/blink/web_tests/external/wpt/css/support/shorthand-testcommon.js
index 1fd603c..3298113 100644
--- a/third_party/blink/web_tests/external/wpt/css/support/shorthand-testcommon.js
+++ b/third_party/blink/web_tests/external/wpt/css/support/shorthand-testcommon.js
@@ -3,18 +3,37 @@
 function test_shorthand_value(property, value, longhands) {
     const stringifiedValue = JSON.stringify(value);
 
+    for (let longhand of Object.keys(longhands).sort()) {
+        test(function(){
+            var div = document.getElementById('target') || document.createElement('div');
+            div.style[property] = "";
+            try {
+                div.style[property] = value;
+
+                const readValue = div.style[longhand];
+                assert_equals(readValue, longhands[longhand], longhand + " should be canonical");
+
+                div.style[longhand] = "";
+                div.style[longhand] = readValue;
+                assert_equals(div.style[longhand], readValue, "serialization should round-trip");
+            } finally {
+                div.style[property] = "";
+            }
+        }, "e.style['" + property + "'] = " + stringifiedValue + " should set " + longhand);
+    }
+
     test(function(){
         var div = document.getElementById('target') || document.createElement('div');
         div.style[property] = "";
-        div.style[property] = value;
-
-        for (let longhand of Object.keys(longhands).sort()) {
-            const readValue = div.style[longhand];
-            assert_equals(readValue, longhands[longhand], longhand + " should be canonical");
-
-            div.style[longhand] = "";
-            div.style[longhand] = readValue;
-            assert_equals(div.style[longhand], readValue, "serialization should round-trip");
+        try {
+            const expectedLength = div.style.length;
+            div.style[property] = value;
+            for (let longhand of Object.keys(longhands).sort()) {
+                div.style[longhand] = "";
+            }
+            assert_equals(div.style.length, expectedLength);
+        } finally {
+            div.style[property] = "";
         }
-    }, "e.style['" + property + "'] = " + stringifiedValue + " should set the longhand values");
+    }, "e.style['" + property + "'] = " + stringifiedValue + " should not set unrelated longhands");
 }
diff --git a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-margin-box-border-radius-008-ref.html b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-margin-box-border-radius-008-ref.html
index f5edbed..7cf8faf 100644
--- a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-margin-box-border-radius-008-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-margin-box-border-radius-008-ref.html
@@ -40,7 +40,7 @@
   }
   </style>
 
-  <body class="bfc">
+  <main class="bfc">
     <span class="container">
       <div class="shape"></div>
     </span>
@@ -50,5 +50,5 @@
     <div class="box" style="height: 36px; top: 60px; right: 120px;"></div>
     <div class="box" style="height: 12px; top: 96px; right: 120px;"></div> <!-- Box at corner -->
     <div class="box" style="height: 12px; top: 108px; right: 120px;"></div> <!-- Box at corner -->
-  </body>
+  </main>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/dom/nodes/MutationObserver-sanity.html b/third_party/blink/web_tests/external/wpt/dom/nodes/MutationObserver-sanity.html
new file mode 100644
index 0000000..a4f6382b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/dom/nodes/MutationObserver-sanity.html
@@ -0,0 +1,95 @@
+<!doctype html>
+<meta charset=utf-8>
+<title></title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+  test(() => {
+      var m = new MutationObserver(() => {});
+      assert_throws_js(TypeError, () => {
+          m.observe(document, {});
+      });
+  }, "Should throw if none of childList, attributes, characterData are true");
+
+  test(() => {
+      var m = new MutationObserver(() => {});
+      m.observe(document, { childList: true });
+      m.disconnect();
+  }, "Should not throw if childList is true");
+
+  test(() => {
+      var m = new MutationObserver(() => {});
+      m.observe(document, { attributes: true });
+      m.disconnect();
+  }, "Should not throw if attributes is true");
+
+  test(() => {
+      var m = new MutationObserver(() => {});
+      m.observe(document, { characterData: true });
+      m.disconnect();
+  }, "Should not throw if characterData is true");
+
+  test(() => {
+      var m = new MutationObserver(() => {});
+      m.observe(document, { attributeOldValue: true });
+      m.disconnect();
+  }, "Should not throw if attributeOldValue is true and attributes is omitted");
+
+  test(() => {
+      var m = new MutationObserver(() => {});
+      m.observe(document, { characterDataOldValue: true });
+      m.disconnect();
+  }, "Should not throw if characterDataOldValue is true and characterData is omitted");
+
+  test(() => {
+      var m = new MutationObserver(() => {});
+      m.observe(document, { attributes: ["abc"] });
+      m.disconnect();
+  }, "Should not throw if attributeFilter is present and attributes is omitted");
+
+  test(() => {
+      var m = new MutationObserver(() => {});
+      assert_throws_js(TypeError, () => {
+          m.observe(document, { childList: true, attributeOldValue: true,
+                                attributes: false });
+      });
+  }, "Should throw if attributeOldValue is true and attributes is false");
+
+  test(() => {
+      var m = new MutationObserver(() => {});
+      m.observe(document, { childList: true, attributeOldValue: true,
+                            attributes: true });
+      m.disconnect();
+  }, "Should not throw if attributeOldValue and attributes are both true");
+
+  test(() => {
+      var m = new MutationObserver(() => {});
+      assert_throws_js(TypeError, () => {
+          m.observe(document, { childList: true, attributeFilter: ["abc"],
+                                attributes: false });
+      });
+  }, "Should throw if attributeFilter is present and attributes is false");
+
+  test(() => {
+      var m = new MutationObserver(() => {});
+      m.observe(document, { childList: true, attributeFilter: ["abc"],
+                            attributes: true });
+      m.disconnect();
+  }, "Should not throw if attributeFilter is present and attributes is true");
+
+  test(() => {
+      var m = new MutationObserver(() => {});
+      assert_throws_js(TypeError, () => {
+          m.observe(document, { childList: true, characterDataOldValue: true,
+                                characterData: false });
+      });
+  }, "Should throw if characterDataOldValue is true and characterData is false");
+
+  test(() => {
+      var m = new MutationObserver(() => {});
+      m.observe(document, { childList: true, characterDataOldValue: true,
+                            characterData: true });
+      m.disconnect();
+  }, "Should not throw if characterDataOldValue is true and characterData is true");
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window-expected.txt b/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window-expected.txt
index d86c1db..61e4b6f1 100644
--- a/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window-expected.txt
@@ -7,7 +7,7 @@
 PASS JS-engine-created TypeError (cross-site iframe)
 PASS web API-created TypeError (worker)
 PASS web API-created TypeError (cross-site iframe)
-FAIL web API-created DOMException (worker) assert_equals: expected (string) "Error: Failed to execute 'createElement' on 'Document': The tag name provided ('') is not a valid name.\n    at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:33:14\n    at Test.<anonymous> (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:41:19)\n    at Test.step (http://web-platform.test:8001/resources/testharness.js:1611:25)\n    at async_test (http://web-platform.test:8001/resources/testharness.js:576:22)\n    at stackTests (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:40:3)\n    at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:31:1" but got (undefined) undefined
-FAIL web API-created DOMException (cross-site iframe) assert_equals: expected (string) "Error: Failed to execute 'createElement' on 'Document': The tag name provided ('') is not a valid name.\n    at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:33:14\n    at Test.<anonymous> (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:60:19)\n    at Test.step (http://web-platform.test:8001/resources/testharness.js:1611:25)\n    at async_test (http://web-platform.test:8001/resources/testharness.js:576:22)\n    at stackTests (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:57:3)\n    at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:31:1" but got (undefined) undefined
+FAIL web API-created DOMException (worker) assert_equals: expected (string) "Error: Failed to execute 'createElement' on 'Document': The tag name provided ('') is not a valid name.\n    at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:33:14\n    at Test.<anonymous> (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:41:19)\n    at Test.step (http://web-platform.test:8001/resources/testharness.js:1905:25)\n    at async_test (http://web-platform.test:8001/resources/testharness.js:576:22)\n    at stackTests (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:40:3)\n    at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:31:1" but got (undefined) undefined
+FAIL web API-created DOMException (cross-site iframe) assert_equals: expected (string) "Error: Failed to execute 'createElement' on 'Document': The tag name provided ('') is not a valid name.\n    at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:33:14\n    at Test.<anonymous> (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:60:19)\n    at Test.step (http://web-platform.test:8001/resources/testharness.js:1905:25)\n    at async_test (http://web-platform.test:8001/resources/testharness.js:576:22)\n    at stackTests (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:57:3)\n    at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:31:1" but got (undefined) undefined
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/tables/table-column-width-ref.html b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/tables/table-column-width-ref.html
new file mode 100644
index 0000000..1eb7c00
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/tables/table-column-width-ref.html
@@ -0,0 +1,2 @@
+<!doctype html>
+<div style="border: 1px solid green; width: 0">Text</div>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/tables/table-column-width.html b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/tables/table-column-width.html
new file mode 100644
index 0000000..6358e14
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/tables/table-column-width.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<link rel="match" href="table-column-width-ref.html">
+<table style="display: block">
+  <colgroup style="display: block">
+    <col style="border: 1px solid green; display: block" width="0"></col>
+  </colgroup>
+</table>
+<script>
+  document.querySelector("col").append("Text");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-remove-from-document-different-load.html b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-remove-from-document-different-load.html
new file mode 100644
index 0000000..4802665c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-remove-from-document-different-load.html
@@ -0,0 +1,44 @@
+<!doctype html>
+<title>paused state when removing from a document</title>
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1583052">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/media.js"></script>
+<div id="log"></div>
+<div>
+  <video hidden></video>
+</div>
+<script>
+function afterStableState(func) {
+  var a = new Audio();
+  a.volume = 0;
+  a.addEventListener('volumechange', func);
+}
+
+async_test(function(t) {
+  var v = document.querySelector('video');
+
+  // Much like pause-remove-from-document.html, modulo this call.
+  document.body.appendChild(v);
+
+  v.src = getVideoURI('/media/movie_300');
+  v.play();
+  v.onplaying = t.step_func(function() {
+    assert_false(v.paused, 'paused after playing');
+    v.parentNode.removeChild(v);
+    assert_false(v.paused, 'paused after removing');
+    afterStableState(t.step_func(function() {
+      assert_true(v.paused, 'paused after stable state');
+      v.onpause = t.step_func(function() {
+        assert_true(v.paused, 'paused in pause event');
+        // re-insert and verify that it stays paused
+        document.body.appendChild(v);
+        t.step_timeout(function() {
+          assert_true(v.paused, 'paused after re-inserting');
+          t.done();
+        }, 0);
+      });
+    }));
+  });
+});
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/expected-fail/unhandled-rejection-expected.txt b/third_party/blink/web_tests/external/wpt/infrastructure/expected-fail/unhandled-rejection-expected.txt
new file mode 100644
index 0000000..3a828c8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/infrastructure/expected-fail/unhandled-rejection-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Unhandled rejection Unhandled rejection: error outside any setup or test
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/expected-fail/unhandled-rejection.html b/third_party/blink/web_tests/external/wpt/infrastructure/expected-fail/unhandled-rejection.html
new file mode 100644
index 0000000..f25f6e0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/infrastructure/expected-fail/unhandled-rejection.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Unhandled rejection</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+Promise.reject(new Error("error outside any setup or test"));
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/expected-fail/unhandled-rejection.html.ini b/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/expected-fail/unhandled-rejection.html.ini
new file mode 100644
index 0000000..39773df
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/expected-fail/unhandled-rejection.html.ini
@@ -0,0 +1,4 @@
+[unhandled-rejection.html]
+  [Unhandled rejection]
+    expected: FAIL
+
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/gamepad.idl b/third_party/blink/web_tests/external/wpt/interfaces/gamepad.idl
index b7497c2..27541bf2 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/gamepad.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/gamepad.idl
@@ -38,6 +38,6 @@
   [SameObject] readonly attribute Gamepad gamepad;
 };
 
-dictionary GamepadEventInit: EventInit {
+dictionary GamepadEventInit : EventInit {
   required Gamepad gamepad;
 };
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/payment-handler.idl b/third_party/blink/web_tests/external/wpt/interfaces/payment-handler.idl
index b5d79de..c87c855 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/payment-handler.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/payment-handler.idl
@@ -40,8 +40,9 @@
   attribute EventHandler oncanmakepayment;
 };
 
-[Constructor(DOMString type, CanMakePaymentEventInit eventInitDict), Exposed=ServiceWorker]
+[Exposed=ServiceWorker]
 interface CanMakePaymentEvent : ExtendableEvent {
+  constructor(DOMString type, CanMakePaymentEventInit eventInitDict);
   readonly attribute USVString topOrigin;
   readonly attribute USVString paymentRequestOrigin;
   readonly attribute FrozenArray<PaymentMethodData> methodData;
@@ -65,8 +66,9 @@
   object paymentMethodErrors;
 };
 
-[Constructor(DOMString type, PaymentRequestEventInit eventInitDict), Exposed=ServiceWorker]
+[Exposed=ServiceWorker]
 interface PaymentRequestEvent : ExtendableEvent {
+  constructor(DOMString type, PaymentRequestEventInit eventInitDict);
   readonly attribute USVString topOrigin;
   readonly attribute USVString paymentRequestOrigin;
   readonly attribute DOMString paymentRequestId;
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/webxr-ar-module.idl b/third_party/blink/web_tests/external/wpt/interfaces/webxr-ar-module.idl
new file mode 100644
index 0000000..61fcd6a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/interfaces/webxr-ar-module.idl
@@ -0,0 +1,21 @@
+// GENERATED CONTENT - DO NOT EDIT
+// Content was automatically extracted by Reffy into reffy-reports
+// (https://github.com/tidoust/reffy-reports)
+// Source: WebXR Augmented Reality Module - Level 1 (https://immersive-web.github.io/webxr-ar-module/)
+
+enum XRSessionMode {
+  "inline",
+  "immersive-vr",
+  "immersive-ar"
+};
+
+enum XREnvironmentBlendMode {
+  "opaque",
+  "alpha-blend",
+  "additive"
+};
+
+partial interface XRSession {
+  // Attributes
+  readonly attribute XREnvironmentBlendMode environmentBlendMode;
+};
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/webxr-gamepads-module.idl b/third_party/blink/web_tests/external/wpt/interfaces/webxr-gamepads-module.idl
new file mode 100644
index 0000000..3aa17a7f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/interfaces/webxr-gamepads-module.idl
@@ -0,0 +1,14 @@
+// GENERATED CONTENT - DO NOT EDIT
+// Content was automatically extracted by Reffy into reffy-reports
+// (https://github.com/tidoust/reffy-reports)
+// Source: WebXR Gamepads Module - Level 1 (https://immersive-web.github.io/webxr-gamepads-module/)
+
+partial interface XRInputSource {
+  [SameObject] readonly attribute Gamepad? gamepad;
+};
+
+enum GamepadMappingType {
+  "",            // Defined in the Gamepad API
+  "standard",    // Defined in the Gamepad API
+  "xr-standard",
+};
diff --git a/third_party/blink/web_tests/external/wpt/intersection-observer/resources/cross-origin-child-iframe.sub.html b/third_party/blink/web_tests/external/wpt/intersection-observer/resources/cross-origin-child-iframe.sub.html
new file mode 100644
index 0000000..8e2c36ed
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/intersection-observer/resources/cross-origin-child-iframe.sub.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<script src="/common/get-host-info.sub.js"></script>
+<iframe id="iframe"></iframe>
+<script>
+iframe.src =
+  get_host_info().ORIGIN + "/intersection-observer/resources/same-origin-grand-child-iframe.html";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/intersection-observer/resources/same-origin-grand-child-iframe.html b/third_party/blink/web_tests/external/wpt/intersection-observer/resources/same-origin-grand-child-iframe.html
new file mode 100644
index 0000000..25db5a2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/intersection-observer/resources/same-origin-grand-child-iframe.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<div id="target"></div>
+<script>
+const observer = new IntersectionObserver(records => {
+  window.top.postMessage(records[0].rootBounds, "*");
+}, {});
+observer.observe(target);
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/intersection-observer/same-origin-grand-child-iframe.sub.html b/third_party/blink/web_tests/external/wpt/intersection-observer/same-origin-grand-child-iframe.sub.html
new file mode 100644
index 0000000..57c0347
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/intersection-observer/same-origin-grand-child-iframe.sub.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<meta name="viewport" content="width=device-width,initial-scale=1">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="./resources/intersection-observer-test-utils.js"></script>
+<iframe id="iframe"></iframe>
+<script>
+promise_test(async t => {
+  iframe.src =
+    get_host_info().HTTP_NOTSAMESITE_ORIGIN + "/intersection-observer/resources/cross-origin-child-iframe.sub.html";
+
+  const rootBounds = await new Promise(resolve => {
+    window.addEventListener("message", event => resolve(event.data));
+  }, { once: true } );
+
+  assert_equals(rootBounds.left, 0);
+  assert_equals(rootBounds.top, 0);
+  assert_equals(rootBounds.right, document.documentElement.clientWidth);
+  assert_equals(rootBounds.bottom, document.documentElement.clientHeight);
+}, "rootBounds in a same-origin iframe in the case where there is a cross-origin "
++  "iframe in between the top document and the same origin iframe");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/lint.whitelist b/third_party/blink/web_tests/external/wpt/lint.whitelist
index be87d27..d9ea5c1 100644
--- a/third_party/blink/web_tests/external/wpt/lint.whitelist
+++ b/third_party/blink/web_tests/external/wpt/lint.whitelist
@@ -836,11 +836,6 @@
 AHEM SYSTEM FONT: resource-timing/resources/all_resource_types.htm
 AHEM SYSTEM FONT: resource-timing/resources/iframe-reload-TAO.sub.html
 
-# These tests are imported from mozilla-central and can't be modified in WPT.
-# They do load Ahem as a web font, but they use their own copy which trips the
-# lint rule. Basically false positives.
-AHEM SYSTEM FONT: css/vendor-imports/mozilla/mozilla-central-reftests/*
-
 # TODO: The following should be deleted along with the Ahem web font cleanup
 # PR (https://github.com/web-platform-tests/wpt/pull/18702)
 AHEM SYSTEM FONT: infrastructure/assumptions/ahem-ref.html
diff --git a/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/clipboard-event-handlers.tentative.html b/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/clipboard-event-handlers.tentative.html
index 82fda88..9816f51 100644
--- a/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/clipboard-event-handlers.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/clipboard-event-handlers.tentative.html
@@ -30,6 +30,9 @@
         "math"
     );
     async_test(test => {
+      test.step(function() {
+        assert_true(MathMLElement.prototype.hasOwnProperty(`on${name}`));
+      });
       mathEl[`on${name}`] = test.step_func_done(e => {
         assert_equals(e.currentTarget, mathEl,
                       "The event must be fired at the <math> element");
diff --git a/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/math-global-event-handlers.tentative.html b/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/math-global-event-handlers.tentative.html
index e96feea..be9bee9c6 100644
--- a/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/math-global-event-handlers.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/math-global-event-handlers.tentative.html
@@ -125,6 +125,9 @@
         }, `${name}: dynamic changes on the attribute`);
 
         async_test(t => {
+          t.step(function() {
+            assert_true(MathMLElement.prototype.hasOwnProperty(name));
+          });
           const element = document.createElementNS(
             "http://www.w3.org/1998/Math/MathML",
             "math"
diff --git a/third_party/blink/web_tests/external/wpt/payment-handler/change-payment-method-manual.https-expected.txt b/third_party/blink/web_tests/external/wpt/payment-handler/change-payment-method-manual.https-expected.txt
new file mode 100644
index 0000000..f30628b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/payment-handler/change-payment-method-manual.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Tests for PaymentRequestEvent.changePaymentMethod() Unhandled rejection: Not allowed to install this payment handler
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/payment-handler/payment-request-event-manual.https-expected.txt b/third_party/blink/web_tests/external/wpt/payment-handler/payment-request-event-manual.https-expected.txt
index b76179f..a00a329 100644
--- a/third_party/blink/web_tests/external/wpt/payment-handler/payment-request-event-manual.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/payment-handler/payment-request-event-manual.https-expected.txt
@@ -1,4 +1,4 @@
 This is a testharness.js-based test.
-FAIL Tests for PaymentRequestEvent Not allowed to install this payment handler
+FAIL Tests for PaymentRequestEvent Unhandled rejection: Not allowed to install this payment handler
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/payment-handler/supports-shipping-contact-delegation-manual.https-expected.txt b/third_party/blink/web_tests/external/wpt/payment-handler/supports-shipping-contact-delegation-manual.https-expected.txt
index 3a76dbf..149709f31 100644
--- a/third_party/blink/web_tests/external/wpt/payment-handler/supports-shipping-contact-delegation-manual.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/payment-handler/supports-shipping-contact-delegation-manual.https-expected.txt
@@ -1,4 +1,4 @@
 This is a testharness.js-based test.
-FAIL Tests for Delegation of shipping and contact collection to PH Not allowed to install this payment handler
+FAIL Tests for Delegation of shipping and contact collection to PH Unhandled rejection: Not allowed to install this payment handler
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-canmakepayment-method.https-expected.txt b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-canmakepayment-method.https-expected.txt
index 5b7ee0ea..f12b171 100644
--- a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-canmakepayment-method.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-canmakepayment-method.https-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = No show() or retry() in progress, so nothing to abort
+Harness Error. harness_status.status = 1 , harness_status.message = Unhandled rejection: No show() or retry() in progress, so nothing to abort
 FAIL If payment method identifier are supported, resolve promise with true. promise_test: Unhandled rejection with value: object "UnknownError: Renderer process could not establish or lost IPC connection to the PaymentRequest service in the browser process."
 FAIL If request.[[state]] is "created", then return a promise that resolves to true for known method. assert_equals: if it throws, then it must be a NotAllowedError. expected "NotAllowedError" but got "UnknownError"
 FAIL All methods are unsupported promise_test: Unhandled rejection with value: object "UnknownError: Renderer process could not establish or lost IPC connection to the PaymentRequest service in the browser process."
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-show-method.https-expected.txt b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-show-method.https-expected.txt
index b9ec0ae..694a3c86 100644
--- a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-show-method.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-show-method.https-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Already called show() once
+Harness Error. harness_status.status = 1 , harness_status.message = Unhandled rejection: Already called show() once
 FAIL Calling show() without being triggered by user interaction throws assert_throws: function "function() { throw e }" threw object "UnknownError: Renderer process could not establish or lost IPC connection to the PaymentRequest service in the browser process." that is not a DOMException SecurityError: property "code" is equal to 0, expected 18
 FAIL Throws if the promise [[state]] is not 'created'. promise_test: Unhandled rejection with value: object "InvalidStateError: No show() or retry() in progress, so nothing to abort"
 FAIL If the user agent's "payment request is showing" boolean is true, then return a promise rejected with an "AbortError" DOMException. assert_throws: function "function() { throw e }" threw object "InvalidStateError: Already called show() once" that is not a DOMException AbortError: property "code" is equal to 11, expected 20
diff --git a/third_party/blink/web_tests/external/wpt/permissions/feature-policy-permissions-query.html b/third_party/blink/web_tests/external/wpt/permissions/feature-policy-permissions-query.html
new file mode 100644
index 0000000..bd152e9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/permissions/feature-policy-permissions-query.html
@@ -0,0 +1,11 @@
+<script>
+'use strict';
+
+Promise.resolve().then(() => navigator.permissions.query({name:'geolocation'}))
+  .then(permissionStatus => {
+  window.parent.postMessage({ state: permissionStatus.state }, '*');
+}, error => {
+  window.parent.postMessage({ state: null }, '*');
+});
+</script>
+
diff --git a/third_party/blink/web_tests/external/wpt/permissions/permissions-query-feature-policy-attribute.https.sub-expected.txt b/third_party/blink/web_tests/external/wpt/permissions/permissions-query-feature-policy-attribute.https.sub-expected.txt
new file mode 100644
index 0000000..b3a5213
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/permissions/permissions-query-feature-policy-attribute.https.sub-expected.txt
@@ -0,0 +1,7 @@
+This is a testharness.js-based test.
+FAIL Permissions.state is "prompt" with allow="geolocation" in same-origin iframes. assert_equals: navigator.permissions.query("geolocation") expected "prompt" but got "denied"
+FAIL Permissions.state is "prompt" with allow="geolocation" in cross-origin iframes. assert_equals: navigator.permissions.query("geolocation") expected "prompt" but got "denied"
+FAIL Permission.state is "prompt" in same-origin iframes. assert_equals: navigator.permissions.query("geolocation") expected "prompt" but got "denied"
+PASS Permission.state is "denied" in cross-origin iframes.
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/permissions/permissions-query-feature-policy-attribute.https.sub.html b/third_party/blink/web_tests/external/wpt/permissions/permissions-query-feature-policy-attribute.https.sub.html
new file mode 100644
index 0000000..1d7333d9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/permissions/permissions-query-feature-policy-attribute.https.sub.html
@@ -0,0 +1,75 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Test permissions query againts feature policy allow attribute</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<div id="log"></div>
+
+<script>
+  "use strict";
+
+  function test_permissions_query(
+    feature_description, test, src, expect_state, allow_attribute) {
+    let frame = document.createElement('iframe');
+    frame.src = src;
+
+    if (typeof allow_attribute !== 'undefined') {
+      frame.allow = allow_attribute;
+    }
+
+    window.addEventListener('message', test.step_func(function handler(evt) {
+      if (evt.source === frame.contentWindow) {
+        assert_equals(evt.data.state, expect_state, feature_description);
+        document.body.removeChild(frame);
+        window.removeEventListener('message', handler);
+        test.done();
+      }
+    }));
+
+    document.body.appendChild(frame);
+  }
+
+  const same_origin_src =
+    "/permissions/feature-policy-permissions-query.html";
+  const cross_origin_src =
+    "https://{{domains[www]}}:{{ports[https][0]}}" + same_origin_src;
+
+   async_test(t => {
+    test_permissions_query(
+      'navigator.permissions.query("geolocation")',
+      t,
+      same_origin_src,
+      "prompt",
+      "geolocation"
+    );
+  }, 'Permissions.state is "prompt" with allow="geolocation" in same-origin iframes.');
+
+  async_test(t => {
+    test_permissions_query(
+      'navigator.permissions.query("geolocation")',
+      t,
+      cross_origin_src,
+      "prompt",
+      "geolocation"
+    );
+  }, 'Permissions.state is "prompt" with allow="geolocation" in cross-origin iframes.');
+
+   async_test(t => {
+    test_permissions_query(
+      'navigator.permissions.query("geolocation")',
+      t,
+      same_origin_src,
+      "prompt"
+    );
+  }, 'Permission.state is "prompt" in same-origin iframes.');
+
+  async_test(t => {
+    test_permissions_query(
+      'navigator.permissions.query("geolocation")',
+      t,
+      cross_origin_src,
+      "denied"
+    );
+  }, 'Permission.state is "denied" in cross-origin iframes.');
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/resources/chromium/contacts_manager_mock.js b/third_party/blink/web_tests/external/wpt/resources/chromium/contacts_manager_mock.js
index 618968ec..ae4c33b 100644
--- a/third_party/blink/web_tests/external/wpt/resources/chromium/contacts_manager_mock.js
+++ b/third_party/blink/web_tests/external/wpt/resources/chromium/contacts_manager_mock.js
@@ -10,7 +10,7 @@
       this.bindingSet_ = new mojo.BindingSet(blink.mojom.ContactsManager);
 
       this.interceptor_ = new MojoInterfaceInterceptor(
-        blink.mojom.ContactsManager.name);
+        blink.mojom.ContactsManager.name, "context", true);
       this.interceptor_.oninterfacerequest =
           e => this.bindingSet_.addBinding(this, e.handle);
       this.interceptor_.start();
diff --git a/third_party/blink/web_tests/external/wpt/resources/testharness.js b/third_party/blink/web_tests/external/wpt/resources/testharness.js
index 1559104..9ef46ca 100644
--- a/third_party/blink/web_tests/external/wpt/resources/testharness.js
+++ b/third_party/blink/web_tests/external/wpt/resources/testharness.js
@@ -630,6 +630,27 @@
         });
     }
 
+    function promise_rejects_js(test, expected, promise, description) {
+        return promise.then(test.unreached_func("Should have rejected: " + description)).catch(function(e) {
+            assert_throws_js_impl(expected, function() { throw e },
+                                  description, "promise_reject_js");
+        });
+    }
+
+    function promise_rejects_dom(test, expected, promise, description) {
+        return promise.then(test.unreached_func("Should have rejected: " + description)).catch(function(e) {
+            assert_throws_dom_impl(expected, function() { throw e },
+                                   description, "promise_rejects_dom");
+        });
+    }
+
+    function promise_rejects_exactly(test, expected, promise, description) {
+        return promise.then(test.unreached_func("Should have rejected: " + description)).catch(function(e) {
+            assert_throws_exactly_impl(expected, function() { throw e },
+                                       description, "promise_rejects_exactly");
+        });
+    }
+
     /**
      * This constructor helper allows DOM events to be handled using Promises,
      * which can make it a lot easier to test a very specific series of events,
@@ -811,6 +832,9 @@
     expose(async_test, 'async_test');
     expose(promise_test, 'promise_test');
     expose(promise_rejects, 'promise_rejects');
+    expose(promise_rejects_js, 'promise_rejects_js');
+    expose(promise_rejects_dom, 'promise_rejects_dom');
+    expose(promise_rejects_exactly, 'promise_rejects_exactly');
     expose(generate_tests, 'generate_tests');
     expose(setup, 'setup');
     expose(done, 'done');
@@ -1482,6 +1506,276 @@
     }
     expose(assert_throws, "assert_throws");
 
+    /**
+     * Assert a JS Error with the expected constructor is thrown.
+     *
+     * @param {object} constructor The expected exception constructor.
+     * @param {Function} func Function which should throw.
+     * @param {string} description Error description for the case that the error is not thrown.
+     */
+    function assert_throws_js(constructor, func, description)
+    {
+        assert_throws_js_impl(constructor, func, description,
+                              "assert_throws_js");
+    }
+    expose(assert_throws_js, "assert_throws_js");
+
+    /**
+     * Like assert_throws_js but allows specifying the assertion type
+     * (assert_throws_js or promise_rejects_js, in practice).
+     */
+    function assert_throws_js_impl(constructor, func, description,
+                                   assertion_type)
+    {
+        try {
+            func.call(this);
+            assert(false, assertion_type, description,
+                   "${func} did not throw", {func:func});
+        } catch (e) {
+            if (e instanceof AssertionError) {
+                throw e;
+            }
+
+            // Basic sanity-checks on the thrown exception.
+            assert(typeof e === "object",
+                   assertion_type, description,
+                   "${func} threw ${e} with type ${type}, not an object",
+                   {func:func, e:e, type:typeof e});
+
+            assert(e !== null,
+                   assertion_type, description,
+                   "${func} threw null, not an object",
+                   {func:func});
+
+            // Basic sanity-check on the passed-in constructor
+            assert(typeof constructor == "function",
+                   assertion_type, description,
+                   "${constructor} is not a constructor",
+                   {constructor:constructor});
+            var obj = constructor;
+            while (obj) {
+                if (typeof obj === "function" &&
+                    obj.name === "Error") {
+                    break;
+                }
+                obj = Object.getPrototypeOf(obj);
+            }
+            assert(obj != null,
+                   assertion_type, description,
+                   "${constructor} is not an Error subtype",
+                   {constructor:constructor});
+
+            // And checking that our exception is reasonable
+            assert(e.constructor === constructor &&
+                   e.name === constructor.name,
+                   assertion_type, description,
+                   "${func} threw ${actual} (${actual_name}) expected instance of ${expected} (${expected_name})",
+                   {func:func, actual:e, actual_name:e.name,
+                    expected:constructor,
+                    expected_name:constructor.name});
+        }
+    }
+
+    /**
+     * Assert a DOMException with the expected type is thrown.
+     *
+     * @param {number|string} type The expected exception name or code.  See the
+     *        table of names and codes at
+     *        https://heycam.github.io/webidl/#dfn-error-names-table
+     *        If a number is passed it should be one of the numeric code values
+     *        in that table (e.g. 3, 4, etc).  If a string is passed it can
+     *        either be an exception name (e.g. "HierarchyRequestError",
+     *        "WrongDocumentError") or the name of the corresponding error code
+     *        (e.g. "HIERARCHY_REQUEST_ERR", "WRONG_DOCUMENT_ERR").
+     * @param {Function} func Function which should throw.
+     * @param {string} description Error description for the case that the error is not thrown.
+     */
+    function assert_throws_dom(type, func, description)
+    {
+        assert_throws_dom_impl(type, func, description, "assert_throws_dom")
+    }
+    expose(assert_throws_dom, "assert_throws_dom");
+
+    /**
+     * Like assert_throws_dom but allows specifying the assertion type
+     * (assert_throws_dom or promise_rejects_dom, in practice).
+     */
+    function assert_throws_dom_impl(type, func, description, assertion_type)
+    {
+        try {
+            func.call(this);
+            assert(false, assertion_type, description,
+                   "${func} did not throw", {func:func});
+        } catch (e) {
+            if (e instanceof AssertionError) {
+                throw e;
+            }
+
+            assert(typeof e === "object",
+                   assertion_type, description,
+                   "${func} threw ${e} with type ${type}, not an object",
+                   {func:func, e:e, type:typeof e});
+
+            assert(e !== null,
+                   assertion_type, description,
+                   "${func} threw null, not an object",
+                   {func:func});
+
+            // Sanity-check our type
+            assert(typeof type == "number" ||
+                   typeof type == "string",
+                   assertion_type, description,
+                   "${type} is not a number or string",
+                   {type:type});
+
+            var codename_name_map = {
+                INDEX_SIZE_ERR: 'IndexSizeError',
+                HIERARCHY_REQUEST_ERR: 'HierarchyRequestError',
+                WRONG_DOCUMENT_ERR: 'WrongDocumentError',
+                INVALID_CHARACTER_ERR: 'InvalidCharacterError',
+                NO_MODIFICATION_ALLOWED_ERR: 'NoModificationAllowedError',
+                NOT_FOUND_ERR: 'NotFoundError',
+                NOT_SUPPORTED_ERR: 'NotSupportedError',
+                INUSE_ATTRIBUTE_ERR: 'InUseAttributeError',
+                INVALID_STATE_ERR: 'InvalidStateError',
+                SYNTAX_ERR: 'SyntaxError',
+                INVALID_MODIFICATION_ERR: 'InvalidModificationError',
+                NAMESPACE_ERR: 'NamespaceError',
+                INVALID_ACCESS_ERR: 'InvalidAccessError',
+                TYPE_MISMATCH_ERR: 'TypeMismatchError',
+                SECURITY_ERR: 'SecurityError',
+                NETWORK_ERR: 'NetworkError',
+                ABORT_ERR: 'AbortError',
+                URL_MISMATCH_ERR: 'URLMismatchError',
+                QUOTA_EXCEEDED_ERR: 'QuotaExceededError',
+                TIMEOUT_ERR: 'TimeoutError',
+                INVALID_NODE_TYPE_ERR: 'InvalidNodeTypeError',
+                DATA_CLONE_ERR: 'DataCloneError'
+            };
+
+            var name_code_map = {
+                IndexSizeError: 1,
+                HierarchyRequestError: 3,
+                WrongDocumentError: 4,
+                InvalidCharacterError: 5,
+                NoModificationAllowedError: 7,
+                NotFoundError: 8,
+                NotSupportedError: 9,
+                InUseAttributeError: 10,
+                InvalidStateError: 11,
+                SyntaxError: 12,
+                InvalidModificationError: 13,
+                NamespaceError: 14,
+                InvalidAccessError: 15,
+                TypeMismatchError: 17,
+                SecurityError: 18,
+                NetworkError: 19,
+                AbortError: 20,
+                URLMismatchError: 21,
+                QuotaExceededError: 22,
+                TimeoutError: 23,
+                InvalidNodeTypeError: 24,
+                DataCloneError: 25,
+
+                EncodingError: 0,
+                NotReadableError: 0,
+                UnknownError: 0,
+                ConstraintError: 0,
+                DataError: 0,
+                TransactionInactiveError: 0,
+                ReadOnlyError: 0,
+                VersionError: 0,
+                OperationError: 0,
+                NotAllowedError: 0
+            };
+
+            var code_name_map = {};
+            for (var key in name_code_map) {
+                if (name_code_map[key] > 0) {
+                    code_name_map[name_code_map[key]] = key;
+                }
+            }
+
+            var required_props = {};
+            var name;
+
+            if (typeof type === "number") {
+                if (type === 0) {
+                    throw new AssertionError('Test bug: ambiguous DOMException code 0 passed to assert_throws_dom()');
+                } else if (!(type in code_name_map)) {
+                    throw new AssertionError('Test bug: unrecognized DOMException code "' + type + '" passed to assert_throws_dom()');
+                }
+                name = code_name_map[type];
+                required_props.code = type;
+            } else if (typeof type === "string") {
+                name = type in codename_name_map ? codename_name_map[type] : type;
+                if (!(name in name_code_map)) {
+                    throw new AssertionError('Test bug: unrecognized DOMException code name or name "' + type + '" passed to assert_throws_dom()');
+                }
+
+                required_props.code = name_code_map[name];
+            }
+
+            if (required_props.code === 0 ||
+               ("name" in e &&
+                e.name !== e.name.toUpperCase() &&
+                e.name !== "DOMException")) {
+                // New style exception: also test the name property.
+                required_props.name = name;
+            }
+
+            //We'd like to test that e instanceof the appropriate interface,
+            //but we can't, because we don't know what window it was created
+            //in.  It might be an instanceof the appropriate interface on some
+            //unknown other window.  TODO: Work around this somehow?  Maybe have
+            //the first arg just be a DOMException with the right name instead
+            //of the string-or-code thing we have now?
+
+            for (var prop in required_props) {
+                assert(prop in e && e[prop] == required_props[prop],
+                       assertion_type, description,
+                       "${func} threw ${e} that is not a DOMException " + type + ": property ${prop} is equal to ${actual}, expected ${expected}",
+                       {func:func, e:e, prop:prop, actual:e[prop], expected:required_props[prop]});
+            }
+        }
+    }
+
+    /**
+     * Assert the provided value is thrown.
+     *
+     * @param {value} exception The expected exception.
+     * @param {Function} func Function which should throw.
+     * @param {string} description Error description for the case that the error is not thrown.
+     */
+    function assert_throws_exactly(exception, func, description)
+    {
+        assert_throws_exactly_impl(exception, func, description,
+                                   "assert_throws_exactly");
+    }
+    expose(assert_throws_exactly, "assert_throws_exactly");
+
+    /**
+     * Like assert_throws_exactly but allows specifying the assertion type
+     * (assert_throws_exactly or promise_rejects_exactly, in practice).
+     */
+    function assert_throws_exactly_impl(exception, func, description,
+                                        assertion_type)
+    {
+        try {
+            func.call(this);
+            assert(false, assertion_type, description,
+                   "${func} did not throw", {func:func});
+        } catch (e) {
+            if (e instanceof AssertionError) {
+                throw e;
+            }
+
+            assert(same_value(e, exception), assertion_type, description,
+                   "${func} threw ${e} but we expected it to throw ${exception}",
+                   {func:func, e:e, exception:exception});
+        }
+    }
+
     function assert_unreached(description) {
          assert(false, "assert_unreached", description,
                 "Reached unreachable code");
@@ -3365,38 +3659,42 @@
     var tests = new Tests();
 
     if (global_scope.addEventListener) {
-        var error_handler = function(e) {
+        var error_handler = function(message, stack) {
             if (tests.tests.length === 0 && !tests.allow_uncaught_exception) {
                 tests.set_file_is_test();
             }
 
-            var stack;
-            if (e.error && e.error.stack) {
-                stack = e.error.stack;
-            } else {
-                stack = e.filename + ":" + e.lineno + ":" + e.colno;
-            }
-
             if (tests.file_is_test) {
                 var test = tests.tests[0];
                 if (test.phase >= test.phases.HAS_RESULT) {
                     return;
                 }
-                test.set_status(test.FAIL, e.message, stack);
+                test.set_status(test.FAIL, message, stack);
                 test.phase = test.phases.HAS_RESULT;
-                // The following function invocation is superfluous.
-                // TODO: Remove.
-                test.done();
             } else if (!tests.allow_uncaught_exception) {
                 tests.status.status = tests.status.ERROR;
-                tests.status.message = e.message;
+                tests.status.message = message;
                 tests.status.stack = stack;
             }
             done();
         };
 
-        addEventListener("error", error_handler, false);
-        addEventListener("unhandledrejection", function(e){ error_handler(e.reason); }, false);
+        addEventListener("error", function(e) {
+            var message = e.message;
+            var stack;
+            if (e.error && e.error.stack) {
+                stack = e.error.stack;
+            } else {
+                stack = e.filename + ":" + e.lineno + ":" + e.colno;
+            }
+            error_handler(message, stack);
+        }, false);
+
+        addEventListener("unhandledrejection", function(e) {
+            var message = "Unhandled rejection: " + e.reason.message;
+            // There's no stack for unhandled rejections.
+            error_handler(message);
+        }, false);
     }
 
     test_environment.on_tests_ready();
diff --git a/third_party/blink/web_tests/external/wpt/shadow-dom/focus/focus-selector-delegatesFocus-expected.txt b/third_party/blink/web_tests/external/wpt/shadow-dom/focus/focus-selector-delegatesFocus-expected.txt
new file mode 100644
index 0000000..8b0d0bf
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/shadow-dom/focus/focus-selector-delegatesFocus-expected.txt
@@ -0,0 +1,11 @@
+This is a testharness.js-based test.
+PASS :focus applies to host with delegatesFocus=true when the shadow root's descendant has focus
+FAIL :focus applies to host with delegatesFocus=true when slotted element has focus assert_true: host matches :focus expected true got false
+PASS :focus applies to host with delegatesFocus=true when an element in a nested shadow tree with delegatesFocus=true is focused
+FAIL :focus applies to host with delegatesFocus=true when an element in a nested shadow tree with delegatesFocus=false is focused assert_true: host of nested shadow tree matches focus expected true got false
+FAIL :focus applies to host with delegatesFocus=false when the shadow root's descendant has focus assert_true: host matches :focus expected true got false
+FAIL :focus applies to host with delegatesFocus=false when slotted element has focus assert_true: host matches :focus expected true got false
+FAIL :focus applies to host with delegatesFocus=false when an element in a nested shadow tree with delegatesFocus=true is focused assert_true: topmost host matches focus expected true got false
+FAIL :focus applies to host with delegatesFocus=false when an element in a nested shadow tree with delegatesFocus=false is focused assert_true: host of nested shadow tree matches focus expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/shadow-dom/focus/focus-selector-delegatesFocus.html b/third_party/blink/web_tests/external/wpt/shadow-dom/focus/focus-selector-delegatesFocus.html
new file mode 100644
index 0000000..38604525
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/shadow-dom/focus/focus-selector-delegatesFocus.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8" />
+  <title>CSS Test (Selectors): :focus behavior with shadow hosts & delegatesFocus </title>
+  <link rel="author" title="Rakina Zata Amni" href="rakina@chromium.org" />
+  <link rel="help" href="https://html.spec.whatwg.org/multipage/semantics-other.html#selector-focus" />
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/resources/testdriver.js"></script>
+  <script src="/resources/testdriver-vendor.js"></script>
+  <script src="resources/shadow-utils.js"></script>
+</head>
+
+<body>
+<script>
+function createFocusableDiv() {
+  const div = document.createElement("div");
+  div.innerText = "foo";
+  div.tabIndex = 0;
+  return div;
+}
+
+function createShadowHost(delegatesFocus, container) {
+  const host = document.createElement("div");
+  host.attachShadow({ mode: "open", delegatesFocus: delegatesFocus });
+  container.appendChild(host);
+  return host;
+}
+
+const delegatesFocusValues = [true, false];
+
+for (const delegatesFocus of delegatesFocusValues) {
+  test(() => {
+    resetFocus();
+    const host = createShadowHost(delegatesFocus, document.body);
+    const shadowChild = createFocusableDiv();
+    host.shadowRoot.appendChild(shadowChild);
+
+    shadowChild.focus();
+    assert_true(shadowChild.matches(":focus"), "element in shadow tree matches :focus");
+    assert_true(host.matches(":focus"), "host matches :focus");
+  }, `:focus applies to host with delegatesFocus=${delegatesFocus} when the shadow root's descendant has focus`);
+
+  test(() => {
+    resetFocus();
+    const host = createShadowHost(delegatesFocus, document.body);
+    const slotted = createFocusableDiv();
+    host.shadowRoot.appendChild(document.createElement("slot"));
+    host.appendChild(slotted);
+
+    slotted.focus();
+    assert_true(slotted.matches(":focus"), "slotted element matches :focus");
+    assert_true(host.matches(":focus"), "host matches :focus");
+  }, `:focus applies to host with delegatesFocus=${delegatesFocus} when slotted element has focus`);
+
+  for (const nestedDelegatesFocus of delegatesFocusValues) {
+    test(() => {
+      resetFocus();
+      const host = createShadowHost(delegatesFocus, document.body);
+      const nestedHost = createShadowHost(nestedDelegatesFocus, host.shadowRoot);
+      const nestedShadowChild = createFocusableDiv();
+      nestedHost.shadowRoot.appendChild(nestedShadowChild);
+      nestedShadowChild.focus();
+      assert_true(nestedShadowChild.matches(":focus"), "element in nested shadow tree matches :focus");
+      assert_true(nestedHost.matches(":focus"), "host of nested shadow tree matches focus");
+      assert_true(host.matches(":focus"), "topmost host matches focus");
+}, `:focus applies to host with delegatesFocus=${delegatesFocus} when an element in a nested shadow tree with delegatesFocus=${nestedDelegatesFocus} is focused`);
+  }
+}
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/shadow-dom/focus/resources/shadow-utils.js b/third_party/blink/web_tests/external/wpt/shadow-dom/focus/resources/shadow-utils.js
index 6ea372a..8033ce0 100644
--- a/third_party/blink/web_tests/external/wpt/shadow-dom/focus/resources/shadow-utils.js
+++ b/third_party/blink/web_tests/external/wpt/shadow-dom/focus/resources/shadow-utils.js
@@ -60,8 +60,9 @@
   }
 }
 
-function resetFocus() {
-  document.body.focus();
+function resetFocus(root = document) {
+  if (root.activeElement)
+    root.activeElement.blur();
 }
 
 function navigateFocusForward() {
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/construct-byob-request.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/construct-byob-request.any.serviceworker-expected.txt
index 39cb31b..6e0da30 100644
--- a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/construct-byob-request.any.serviceworker-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/construct-byob-request.any.serviceworker-expected.txt
@@ -1,4 +1,4 @@
 This is a testharness.js-based test.
-FAIL construct-byob-request Failed to register a ServiceWorker for scope ('https://web-platform.test:8444/streams/readable-byte-streams/does/not/exist') with script ('https://web-platform.test:8444/streams/readable-byte-streams/construct-byob-request.any.worker.js'): ServiceWorker script evaluation failed
+FAIL construct-byob-request Unhandled rejection: Failed to register a ServiceWorker for scope ('https://web-platform.test:8444/streams/readable-byte-streams/does/not/exist') with script ('https://web-platform.test:8444/streams/readable-byte-streams/construct-byob-request.any.worker.js'): ServiceWorker script evaluation failed
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/svg/animations/scripted/onhover-syncbases.html b/third_party/blink/web_tests/external/wpt/svg/animations/scripted/onhover-syncbases.html
index 0772601..de757f3 100644
--- a/third_party/blink/web_tests/external/wpt/svg/animations/scripted/onhover-syncbases.html
+++ b/third_party/blink/web_tests/external/wpt/svg/animations/scripted/onhover-syncbases.html
@@ -20,7 +20,7 @@
   let rounds = 5; // How many times the cursor is moved in and out
   let circle = document.querySelector("#circle");
   let delay = 20;
-  let f = t.step_func(function() {
+  function f() {
     assert_equals(window.getComputedStyle(circle, null).fill,
       "rgb(255, 0, 0)")
     if (rounds-- == 0) {
@@ -29,14 +29,14 @@
     }
 
     circle.dispatchEvent(new Event("mouseover"));
-    step_timeout(t.step_func(function() {
+    t.step_timeout(function() {
         assert_equals(window.getComputedStyle(circle, null).fill,
           "rgb(0, 255, 0)")
         circle.dispatchEvent(new Event("mouseout"))
         t.step_timeout(f, delay);
-    }), delay);
-  });
-  step_timeout(f, 0);
+    }, delay);
+  }
+  t.step_timeout(f, 0);
 });
     </script>
   </body>
diff --git a/third_party/blink/web_tests/external/wpt/tools/ci/tcdownload.py b/third_party/blink/web_tests/external/wpt/tools/ci/tcdownload.py
index 91c763a7..46e9005 100644
--- a/third_party/blink/web_tests/external/wpt/tools/ci/tcdownload.py
+++ b/third_party/blink/web_tests/external/wpt/tools/ci/tcdownload.py
@@ -71,7 +71,7 @@
 
     if not taskgroups:
         logger.error("No complete TaskCluster runs found for ref %s" % kwargs["ref"])
-        return
+        return 1
 
     for taskgroup in taskgroups:
         taskgroup_url = "https://queue.taskcluster.net/v1/task-group/%s/list"
diff --git a/third_party/blink/web_tests/external/wpt/tools/lint/lint.py b/third_party/blink/web_tests/external/wpt/tools/lint/lint.py
index 48a275b..7689c35 100644
--- a/third_party/blink/web_tests/external/wpt/tools/lint/lint.py
+++ b/third_party/blink/web_tests/external/wpt/tools/lint/lint.py
@@ -681,7 +681,10 @@
 
 
 ahem_font_re = re.compile(b"font.*:.*ahem", flags=re.IGNORECASE)
-ahem_stylesheet_re = re.compile(b"\/fonts\/ahem\.css", flags=re.IGNORECASE)
+# Ahem can appear either in the global location or in the support
+# directory for legacy Mozilla imports
+ahem_stylesheet_re = re.compile(b"\/fonts\/ahem\.css|support\/ahem.css",
+                                flags=re.IGNORECASE)
 
 
 def check_ahem_system_font(repo_root, path, f):
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/requirements.txt b/third_party/blink/web_tests/external/wpt/tools/wptrunner/requirements.txt
index d6c7a4f..3584c93 100644
--- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/requirements.txt
+++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/requirements.txt
@@ -3,6 +3,6 @@
 mozlog==4.2.0
 mozdebug==0.1.1
 pillow==6.1.0
-urllib3[secure]==1.25.3
+urllib3[secure]==1.25.5
 requests==2.22.0
 six==1.12.0
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-001-expected.txt b/third_party/blink/web_tests/external/wpt/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-001-expected.txt
new file mode 100644
index 0000000..5b5ccfe7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-001-expected.txt
@@ -0,0 +1,74 @@
+This is a testharness.js-based test.
+Found 70 tests; 68 PASS, 2 FAIL, 0 TIMEOUT, 0 NOTRUN.
+PASS non-animatable property 'animation' is not accessed when using a property-indexed keyframe object
+PASS non-animatable property 'animationDelay' is not accessed when using a property-indexed keyframe object
+PASS non-animatable property 'animationDirection' is not accessed when using a property-indexed keyframe object
+PASS non-animatable property 'animationDuration' is not accessed when using a property-indexed keyframe object
+PASS non-animatable property 'animationFillMode' is not accessed when using a property-indexed keyframe object
+PASS non-animatable property 'animationIterationCount' is not accessed when using a property-indexed keyframe object
+PASS non-animatable property 'animationName' is not accessed when using a property-indexed keyframe object
+PASS non-animatable property 'animationPlayState' is not accessed when using a property-indexed keyframe object
+PASS non-animatable property 'animationTimingFunction' is not accessed when using a property-indexed keyframe object
+PASS non-animatable property 'transition' is not accessed when using a property-indexed keyframe object
+PASS non-animatable property 'transitionDelay' is not accessed when using a property-indexed keyframe object
+PASS non-animatable property 'transitionDuration' is not accessed when using a property-indexed keyframe object
+PASS non-animatable property 'transitionProperty' is not accessed when using a property-indexed keyframe object
+PASS non-animatable property 'transitionTimingFunction' is not accessed when using a property-indexed keyframe object
+PASS non-animatable property 'contain' is not accessed when using a property-indexed keyframe object
+PASS non-animatable property 'direction' is not accessed when using a property-indexed keyframe object
+PASS non-animatable property 'display' is not accessed when using a property-indexed keyframe object
+PASS non-animatable property 'textOrientation' is not accessed when using a property-indexed keyframe object
+PASS non-animatable property 'unicodeBidi' is not accessed when using a property-indexed keyframe object
+PASS non-animatable property 'willChange' is not accessed when using a property-indexed keyframe object
+PASS non-animatable property 'writingMode' is not accessed when using a property-indexed keyframe object
+PASS non-animatable property 'unsupportedProperty' is not accessed when using a property-indexed keyframe object
+FAIL non-animatable property 'float' is not accessed when using a property-indexed keyframe object assert_equals: Accessor not called expected 0 but got 1
+PASS non-animatable property 'font-size' is not accessed when using a property-indexed keyframe object
+PASS non-animatable property 'animation' is not accessed when using a keyframe sequence
+PASS non-animatable property 'animationDelay' is not accessed when using a keyframe sequence
+PASS non-animatable property 'animationDirection' is not accessed when using a keyframe sequence
+PASS non-animatable property 'animationDuration' is not accessed when using a keyframe sequence
+PASS non-animatable property 'animationFillMode' is not accessed when using a keyframe sequence
+PASS non-animatable property 'animationIterationCount' is not accessed when using a keyframe sequence
+PASS non-animatable property 'animationName' is not accessed when using a keyframe sequence
+PASS non-animatable property 'animationPlayState' is not accessed when using a keyframe sequence
+PASS non-animatable property 'animationTimingFunction' is not accessed when using a keyframe sequence
+PASS non-animatable property 'transition' is not accessed when using a keyframe sequence
+PASS non-animatable property 'transitionDelay' is not accessed when using a keyframe sequence
+PASS non-animatable property 'transitionDuration' is not accessed when using a keyframe sequence
+PASS non-animatable property 'transitionProperty' is not accessed when using a keyframe sequence
+PASS non-animatable property 'transitionTimingFunction' is not accessed when using a keyframe sequence
+PASS non-animatable property 'contain' is not accessed when using a keyframe sequence
+PASS non-animatable property 'direction' is not accessed when using a keyframe sequence
+PASS non-animatable property 'display' is not accessed when using a keyframe sequence
+PASS non-animatable property 'textOrientation' is not accessed when using a keyframe sequence
+PASS non-animatable property 'unicodeBidi' is not accessed when using a keyframe sequence
+PASS non-animatable property 'willChange' is not accessed when using a keyframe sequence
+PASS non-animatable property 'writingMode' is not accessed when using a keyframe sequence
+PASS non-animatable property 'unsupportedProperty' is not accessed when using a keyframe sequence
+FAIL non-animatable property 'float' is not accessed when using a keyframe sequence assert_equals: Accessor not called expected 0 but got 1
+PASS non-animatable property 'font-size' is not accessed when using a keyframe sequence
+PASS Equivalent property-indexed and sequenced keyframes: two properties with one value
+PASS Equivalent property-indexed and sequenced keyframes: two properties with three values
+PASS Equivalent property-indexed and sequenced keyframes: two properties with different numbers of values
+PASS Equivalent property-indexed and sequenced keyframes: same easing applied to all keyframes
+PASS Equivalent property-indexed and sequenced keyframes: same composite applied to all keyframes
+PASS Keyframes are read from a custom iterator
+PASS 'easing' and 'offset' are ignored on iterable objects
+PASS Keyframes are read from a custom iterator with multiple properties specified
+PASS Keyframes are read from a custom iterator with where an offset is specified
+PASS If a keyframe throws for an animatable property, that exception should be propagated
+PASS Reading from a custom iterator that returns a non-object keyframe should throw
+PASS An undefined keyframe returned from a custom iterator should be treated as a default keyframe
+PASS A null keyframe returned from a custom iterator should be treated as a default keyframe
+PASS A list of values returned from a custom iterator should be ignored
+PASS If a custom iterator throws from next(), the exception should be rethrown
+PASS Accessing a Symbol.iterator property that throws should rethrow
+PASS A non-object returned from the Symbol.iterator property should cause a TypeError to be thrown
+PASS Only enumerable properties on keyframes are read
+PASS Only properties defined directly on keyframes are read
+PASS Only enumerable properties on property-indexed keyframes are read
+PASS Only properties defined directly on property-indexed keyframes are read
+PASS Properties are read in ascending order by Unicode codepoint
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-001.html b/third_party/blink/web_tests/external/wpt/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-001.html
index 5c9ec84e..5bd0ae2 100644
--- a/third_party/blink/web_tests/external/wpt/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-001.html
+++ b/third_party/blink/web_tests/external/wpt/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-001.html
@@ -45,6 +45,8 @@
 
   'unsupportedProperty',
 
+  'float', // We use the string "cssFloat" to represent "float" property, and
+           // so reject "float" in the keyframe-like object.
   'font-size', // Supported property that uses dashes
 ];
 
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-addmodule-resolution.https.html b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-addmodule-resolution.https.html
index e946212..dc324b2 100644
--- a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-addmodule-resolution.https.html
+++ b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-addmodule-resolution.https.html
@@ -12,48 +12,50 @@
     <script id="layout-test-code">
       let audit = Audit.createTaskRunner();
 
-      let sampleRate = 48000;
-      let realtimeContext = new AudioContext();
-      let offlineContext = new OfflineAudioContext(1, sampleRate, sampleRate);
+      setup(() => {
+        let sampleRate = 48000;
+        let realtimeContext = new AudioContext();
+        let offlineContext = new OfflineAudioContext(1, sampleRate, sampleRate);
 
-      let filePath = 'processors/dummy-processor.js';
+        let filePath = 'processors/dummy-processor.js';
 
-      // Test if the browser does not crash upon addModule() call after the
-      // realtime context construction.
-      audit.define(
-          {label: 'module-loading-after-realtime-context-creation'},
-          (task, should) => {
-            let dummyWorkletNode =
-                new AudioWorkletNode(realtimeContext, 'dummy');
-            dummyWorkletNode.connect(realtimeContext.destination);
-            should(dummyWorkletNode instanceof AudioWorkletNode,
-                   '"dummyWorkletNode" is an instance of AudioWorkletNode ' +
-                   'from realtime context')
-                .beTrue();
-            task.done();
+        // Test if the browser does not crash upon addModule() call after the
+        // realtime context construction.
+        audit.define(
+            {label: 'module-loading-after-realtime-context-creation'},
+            (task, should) => {
+              let dummyWorkletNode =
+                  new AudioWorkletNode(realtimeContext, 'dummy');
+              dummyWorkletNode.connect(realtimeContext.destination);
+              should(dummyWorkletNode instanceof AudioWorkletNode,
+                     '"dummyWorkletNode" is an instance of AudioWorkletNode ' +
+                     'from realtime context')
+                  .beTrue();
+              task.done();
+            });
+
+        // Test if the browser does not crash upon addModule() call after the
+        // offline context construction.
+        audit.define(
+            {label: 'module-loading-after-offline-context-creation'},
+            (task, should) => {
+              let dummyWorkletNode =
+                  new AudioWorkletNode(offlineContext, 'dummy');
+              dummyWorkletNode.connect(offlineContext.destination);
+              should(dummyWorkletNode instanceof AudioWorkletNode,
+                     '"dummyWorkletNode" is an instance of AudioWorkletNode ' +
+                     'from offline context')
+                  .beTrue();
+              task.done();
+            });
+
+        Promise.all([
+            realtimeContext.audioWorklet.addModule(filePath),
+            offlineContext.audioWorklet.addModule(filePath)
+          ]).then(() => {
+            audit.run();
           });
-
-      // Test if the browser does not crash upon addModule() call after the
-      // offline context construction.
-      audit.define(
-          {label: 'module-loading-after-offline-context-creation'},
-          (task, should) => {
-            let dummyWorkletNode =
-                new AudioWorkletNode(offlineContext, 'dummy');
-            dummyWorkletNode.connect(offlineContext.destination);
-            should(dummyWorkletNode instanceof AudioWorkletNode,
-                   '"dummyWorkletNode" is an instance of AudioWorkletNode ' +
-                   'from offline context')
-                .beTrue();
-            task.done();
-          });
-
-      Promise.all([
-          realtimeContext.audioWorklet.addModule(filePath),
-          offlineContext.audioWorklet.addModule(filePath)
-        ]).then(() => {
-          audit.run();
-        });
+      });
     </script>
   </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSourceToScriptProcessorTest.html b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSourceToScriptProcessorTest.html
index 3e364eb7..b1f18d39 100644
--- a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSourceToScriptProcessorTest.html
+++ b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSourceToScriptProcessorTest.html
@@ -22,104 +22,106 @@
  <body class="a">
   <div id="log"></div>
   <script>
- var elementSourceTest = async_test("Element Source tests completed");
+ var elementSourceTest = async_test(function(elementSourceTest) {
 
- var src = '/webaudio/resources/sin_440Hz_-6dBFS_1s.wav';
- var BUFFER_SIZE = 2048;
- var context = null;
- var actualBufferArrayC0 = new Float32Array(0);
- var actualBufferArrayC1 = new Float32Array(0);
- var audio = null, source = null, processor = null
+   var src = '/webaudio/resources/sin_440Hz_-6dBFS_1s.wav';
+   var BUFFER_SIZE = 2048;
+   var context = null;
+   var actualBufferArrayC0 = new Float32Array(0);
+   var actualBufferArrayC1 = new Float32Array(0);
+   var audio = null, source = null, processor = null
 
- function loadExpectedBuffer(event) {
-   bufferLoader = new BufferLoader(
-     context,
-     [src],
-     bufferLoadCompleted
-   );
-   bufferLoader.load();
- };
+   function loadExpectedBuffer(event) {
+     bufferLoader = new BufferLoader(
+       context,
+       [src],
+       elementSourceTest.step_func(bufferLoadCompleted)
+     );
+     bufferLoader.load();
+   };
 
- function bufferLoadCompleted(buffer) {
-   runTests(buffer);
- };
+   function bufferLoadCompleted(buffer) {
+     runTests(buffer);
+   };
 
- function concatTypedArray(arr1, arr2) {
-   var result = new Float32Array(arr1.length + arr2.length);
-   result.set(arr1);
-   result.set(arr2, arr1.length);
-   return result;
- }
+   function concatTypedArray(arr1, arr2) {
+     var result = new Float32Array(arr1.length + arr2.length);
+     result.set(arr1);
+     result.set(arr2, arr1.length);
+     return result;
+   }
 
- // Create Audio context.  The reference wav file is sampled at 44.1 kHz so
- // use the same rate for the context to remove extra resampling that might
- // be required.
- context = new AudioContext({sampleRate: 44100});
+   // Create Audio context.  The reference wav file is sampled at 44.1 kHz so
+   // use the same rate for the context to remove extra resampling that might
+   // be required.
+   context = new AudioContext({sampleRate: 44100});
 
- // Create an audio element, and a media element source
- audio = document.createElement('audio');
- audio.src = src;
- source = context.createMediaElementSource(audio);
+   // Create an audio element, and a media element source
+   audio = document.createElement('audio');
+   audio.src = src;
+   source = context.createMediaElementSource(audio);
 
-function processListener (e) {
-  actualBufferArrayC0 = concatTypedArray(actualBufferArrayC0, e.inputBuffer.getChannelData(0));
-  actualBufferArrayC1 = concatTypedArray(actualBufferArrayC1, e.inputBuffer.getChannelData(1));
-}
+   function processListener (e) {
+     actualBufferArrayC0 = concatTypedArray(actualBufferArrayC0, e.inputBuffer.getChannelData(0));
+     actualBufferArrayC1 = concatTypedArray(actualBufferArrayC1, e.inputBuffer.getChannelData(1));
+   }
 
- // Create a processor node to copy the input to the actual buffer
- processor = context.createScriptProcessor(BUFFER_SIZE);
- source.connect(processor);
- processor.connect(context.destination);
- processor.addEventListener('audioprocess', processListener);
+   // Create a processor node to copy the input to the actual buffer
+   processor = context.createScriptProcessor(BUFFER_SIZE);
+   source.connect(processor);
+   processor.connect(context.destination);
+   let audioprocessListener = elementSourceTest.step_func(processListener);
+   processor.addEventListener('audioprocess', audioprocessListener);
 
- // When media playback ended, save the begin to compare with expected buffer
- audio.addEventListener("ended", function(e) {
-   // Setting a timeout since we need audioProcess event to run for all samples
-   window.setTimeout(loadExpectedBuffer, 50);
- });
+   // When media playback ended, save the begin to compare with expected buffer
+   audio.addEventListener("ended", elementSourceTest.step_func(function(e) {
+     // Setting a timeout since we need audioProcess event to run for all samples
+     window.setTimeout(elementSourceTest.step_func(loadExpectedBuffer), 50);
+   }));
 
- audio.play();
+   audio.play();
 
- function runTests(expected) {
-   source.disconnect();
-   processor.disconnect();
+   function runTests(expected) {
+     source.disconnect();
+     processor.disconnect();
 
-   // firefox seems to process events after disconnect
-   processor.removeEventListener('audioprocess', processListener)
+     // firefox seems to process events after disconnect
+     processor.removeEventListener('audioprocess', audioprocessListener)
 
-   // Note: the expected result is from a mono source file.
-   var expectedBuffer = expected[0];
+     // Note: the expected result is from a mono source file.
+     var expectedBuffer = expected[0];
 
-   // Trim the actual elements because we don't have a fine-grained
-   // control over the start and end time of recording the data.
-   var actualTrimmedC0 = trimEmptyElements(actualBufferArrayC0);
-   var actualTrimmedC1 = trimEmptyElements(actualBufferArrayC1);
-   var expectedLength = trimEmptyElements(expectedBuffer.getChannelData(0)).length;
+     // Trim the actual elements because we don't have a fine-grained
+     // control over the start and end time of recording the data.
+     var actualTrimmedC0 = trimEmptyElements(actualBufferArrayC0);
+     var actualTrimmedC1 = trimEmptyElements(actualBufferArrayC1);
+     var expectedLength = trimEmptyElements(expectedBuffer.getChannelData(0)).length;
 
-   // Test that there is some data.
-   test(function() {
-     assert_greater_than(actualTrimmedC0.length, 0,
-                         "processed data array (C0) length greater than 0");
-     assert_greater_than(actualTrimmedC1.length, 0,
-                         "processed data array (C1) length greater than 0");
-   }, "Channel 0 processed some data");
+     // Test that there is some data.
+     test(function() {
+       assert_greater_than(actualTrimmedC0.length, 0,
+                           "processed data array (C0) length greater than 0");
+       assert_greater_than(actualTrimmedC1.length, 0,
+                           "processed data array (C1) length greater than 0");
+     }, "Channel 0 processed some data");
 
-   // Test the actual contents of the 1st and second channel.
-   test(function() {
-     assert_array_approx_equals(
-       actualTrimmedC0,
-       trimEmptyElements(expectedBuffer.getChannelData(0)),
-       1e-4,
-       "comparing expected and rendered buffers (channel 0)");
-     assert_array_approx_equals(
-       actualTrimmedC1,
-       trimEmptyElements(expectedBuffer.getChannelData(0)),
-       1e-4,
-       "comparing expected and rendered buffers (channel 1)");
-   }, "All data processed correctly");
+     // Test the actual contents of the 1st and second channel.
+     test(function() {
+       assert_array_approx_equals(
+         actualTrimmedC0,
+         trimEmptyElements(expectedBuffer.getChannelData(0)),
+         1e-4,
+         "comparing expected and rendered buffers (channel 0)");
+       assert_array_approx_equals(
+         actualTrimmedC1,
+         trimEmptyElements(expectedBuffer.getChannelData(0)),
+         1e-4,
+         "comparing expected and rendered buffers (channel 1)");
+     }, "All data processed correctly");
 
-   elementSourceTest.done();
- };
+     elementSourceTest.done();
+   };
+ }, "Element Source tests completed");
   </script>
  </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/mediastreamaudiosourcenode-routing.html b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/mediastreamaudiosourcenode-routing.html
index 2e04ab6a..816eba0 100644
--- a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/mediastreamaudiosourcenode-routing.html
+++ b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/mediastreamaudiosourcenode-routing.html
@@ -21,105 +21,107 @@
       const t = async_test(
         "MediaStreamAudioSourceNode captures the right track."
       );
-      const ac = new AudioContext();
-      // Test that the right track is captured. Set up a MediaStream that has two
-      // tracks, one with a tone at 100Hz and one with a tone at 1000Hz.
-      const dest0 = ac.createMediaStreamDestination();
-      const dest1 = ac.createMediaStreamDestination();
-      const osc0 = ac.createOscillator();
-      const osc1 = ac.createOscillator();
-      osc0.frequency.value = 100;
-      osc1.frequency.value = 1000;
-      osc0.connect(dest0);
-      osc1.connect(dest1);
-      osc0.start(0);
-      osc1.start(0);
-      const track0 = dest0.stream.getAudioTracks()[0];
-      const track0id = track0.id;
-      const track1 = dest1.stream.getAudioTracks()[0];
-      const track1id = track1.id;
+      t.step(function() {
+          const ac = new AudioContext();
+          // Test that the right track is captured. Set up a MediaStream that has two
+          // tracks, one with a tone at 100Hz and one with a tone at 1000Hz.
+          const dest0 = ac.createMediaStreamDestination();
+          const dest1 = ac.createMediaStreamDestination();
+          const osc0 = ac.createOscillator();
+          const osc1 = ac.createOscillator();
+          osc0.frequency.value = 100;
+          osc1.frequency.value = 1000;
+          osc0.connect(dest0);
+          osc1.connect(dest1);
+          osc0.start(0);
+          osc1.start(0);
+          const track0 = dest0.stream.getAudioTracks()[0];
+          const track0id = track0.id;
+          const track1 = dest1.stream.getAudioTracks()[0];
+          const track1id = track1.id;
 
-      let ids = [track0id, track1id];
-      ids.sort();
-      let targetFrequency;
-      let otherFrequency;
-      if (ids[0] == track0id) {
-        targetFrequency = 100;
-        otherFrequency = 1000;
-      } else {
-        targetFrequency = 1000;
-        otherFrequency = 100;
-      }
+          let ids = [track0id, track1id];
+          ids.sort();
+          let targetFrequency;
+          let otherFrequency;
+          if (ids[0] == track0id) {
+              targetFrequency = 100;
+              otherFrequency = 1000;
+          } else {
+              targetFrequency = 1000;
+              otherFrequency = 100;
+          }
 
-      let twoTrackMediaStream = new MediaStream();
-      twoTrackMediaStream.addTrack(track0);
-      twoTrackMediaStream.addTrack(track1);
+          let twoTrackMediaStream = new MediaStream();
+          twoTrackMediaStream.addTrack(track0);
+          twoTrackMediaStream.addTrack(track1);
 
-      const twoTrackSource = ac.createMediaStreamSource(twoTrackMediaStream);
-      const analyser = ac.createAnalyser();
-      // Don't do smoothing so that the frequency data changes quickly
-      analyser.smoothingTimeConstant = 0;
+          const twoTrackSource = ac.createMediaStreamSource(twoTrackMediaStream);
+          const analyser = ac.createAnalyser();
+          // Don't do smoothing so that the frequency data changes quickly
+          analyser.smoothingTimeConstant = 0;
 
-      twoTrackSource.connect(analyser);
+          twoTrackSource.connect(analyser);
 
-      const indexToCheckForHighEnergy = binIndexForFrequency(
-        targetFrequency,
-        analyser
-      );
-      const indexToCheckForLowEnergy = binIndexForFrequency(
-        otherFrequency,
-        analyser
-      );
-      let frequencyData = new Float32Array(1024);
-      let checkCount = 0;
-      let numberOfRemovals = 0;
-      let stopped = false;
-      function analyse() {
-        analyser.getFloatFrequencyData(frequencyData);
-        // there should be high energy in the right bin, higher than 40dbfs because
-        // it's supposed to be a sine wave at 0dbfs
-        if (frequencyData[indexToCheckForHighEnergy] > -40 && !stopped) {
-          assert_true(true, "Correct track routed to the AudioContext.");
-          checkCount++;
-        }
-        if (stopped && frequencyData[indexToCheckForHighEnergy] < -40) {
-          assert_true(
-            true,
-            `After stopping the track, low energy is found in the
+          const indexToCheckForHighEnergy = binIndexForFrequency(
+              targetFrequency,
+              analyser
+          );
+          const indexToCheckForLowEnergy = binIndexForFrequency(
+              otherFrequency,
+              analyser
+          );
+          let frequencyData = new Float32Array(1024);
+          let checkCount = 0;
+          let numberOfRemovals = 0;
+          let stopped = false;
+          function analyse() {
+              analyser.getFloatFrequencyData(frequencyData);
+              // there should be high energy in the right bin, higher than 40dbfs because
+              // it's supposed to be a sine wave at 0dbfs
+              if (frequencyData[indexToCheckForHighEnergy] > -40 && !stopped) {
+                  assert_true(true, "Correct track routed to the AudioContext.");
+                  checkCount++;
+              }
+              if (stopped && frequencyData[indexToCheckForHighEnergy] < -40) {
+                  assert_true(
+                      true,
+                      `After stopping the track, low energy is found in the
               same bin`
-          );
-          checkCount++;
-        }
-        if (checkCount > 5 && checkCount < 20) {
-          twoTrackMediaStream.getAudioTracks().forEach(track => {
-            if (track.id == ids[0]) {
-              numberOfRemovals++;
-              window.removedTrack = track;
-              twoTrackMediaStream.removeTrack(track);
-            }
-          });
-          assert_true(
-            numberOfRemovals == 1,
-            `The mediastreamtrack can only be
+                  );
+                  checkCount++;
+              }
+              if (checkCount > 5 && checkCount < 20) {
+                  twoTrackMediaStream.getAudioTracks().forEach(track => {
+                      if (track.id == ids[0]) {
+                          numberOfRemovals++;
+                          window.removedTrack = track;
+                          twoTrackMediaStream.removeTrack(track);
+                      }
+                  });
+                  assert_true(
+                      numberOfRemovals == 1,
+                      `The mediastreamtrack can only be
         removed once from the mediastream`
-          );
-        } else if (checkCount >= 20 && checkCount < 30) {
-          window.removedTrack.stop();
-          stopped = true;
-        } else if (checkCount >= 30) {
-          assert_true(
-            numberOfRemovals == 1,
-            `After removing the track from the
+                  );
+              } else if (checkCount >= 20 && checkCount < 30) {
+                  window.removedTrack.stop();
+                  stopped = true;
+              } else if (checkCount >= 30) {
+                  assert_true(
+                      numberOfRemovals == 1,
+                      `After removing the track from the
         mediastream, it's still routed to the graph.`
-          );
-          // After some time, consider that it worked.
-          t.done();
-          return;
-        }
+                  );
+                  // After some time, consider that it worked.
+                  t.done();
+                  return;
+              }
 
-        t.step_timeout(analyse, 100);
-      }
-      t.step_timeout(analyse, 100);
+              t.step_timeout(analyse, 100);
+          }
+          t.step_timeout(analyse, 100);
+      });
     </script>
   </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-waveshapernode-interface/curve-tests.html b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-waveshapernode-interface/curve-tests.html
index a2e40777..81e64dc1 100644
--- a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-waveshapernode-interface/curve-tests.html
+++ b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-waveshapernode-interface/curve-tests.html
@@ -134,35 +134,35 @@
 		*/
 		function executeTest(curveData, inputData, expectedData, testName) {
 			var stTest=async_test("WaveShaperNode - "+testName);
+			stTest.step(function() {
 
-			// Create offline audio context.
-			var ac=new OfflineAudioContext(1, inputData.length, sampleRate);
+				// Create offline audio context.
+				var ac=new OfflineAudioContext(1, inputData.length, sampleRate);
 
-			// Create the WaveShaper and its curve.
-			var waveShaper=ac.createWaveShaper();
-			if(curveData!=null) {
-				var curve=new Float32Array(curveData.length);
-				for(var i=0;i<curveData.length;i++) { curve[i]=curveData[i]; }
-				waveShaper.curve=curve;
-			}
-			waveShaper.connect(ac.destination);
+				// Create the WaveShaper and its curve.
+				var waveShaper=ac.createWaveShaper();
+				if(curveData!=null) {
+					var curve=new Float32Array(curveData.length);
+					for(var i=0;i<curveData.length;i++) { curve[i]=curveData[i]; }
+					waveShaper.curve=curve;
+				}
+				waveShaper.connect(ac.destination);
 
-			// Create buffer containing the input values.
-			var inputBuffer=ac.createBuffer(1, Math.max(inputData.length, 2), sampleRate);
-			var d=inputBuffer.getChannelData(0);
-			for(var i=0;i<inputData.length;i++) { d[i]=inputData[i]; }
+				// Create buffer containing the input values.
+				var inputBuffer=ac.createBuffer(1, Math.max(inputData.length, 2), sampleRate);
+				var d=inputBuffer.getChannelData(0);
+				for(var i=0;i<inputData.length;i++) { d[i]=inputData[i]; }
 
-			// Play the input buffer through the WaveShaper.
-			var src=ac.createBufferSource();
-			src.buffer=inputBuffer;
-			src.connect(waveShaper);
-			src.start();
+				// Play the input buffer through the WaveShaper.
+				var src=ac.createBufferSource();
+				src.buffer=inputBuffer;
+				src.connect(waveShaper);
+				src.start();
 
-			// Test the outputs match the expected values.
-			ac.oncomplete=function(ev) {
-				var d=ev.renderedBuffer.getChannelData(0);
+				// Test the outputs match the expected values.
+				ac.oncomplete=stTest.step_func_done(function(ev) {
+					var d=ev.renderedBuffer.getChannelData(0);
 
-				stTest.step(function() {
 					for(var i=0;i<expectedData.length;i++) {
 						var curveText="null";
 						if(curve!=null) {
@@ -176,10 +176,8 @@
 						assert_approx_equals(d[i], expectedData[i], tolerance, comment);
 					}
 				});
-
-				stTest.done();
-			};
-			ac.startRendering();
+				ac.startRendering();
+			});
 		}
 	</script>
 </body>
diff --git a/third_party/blink/web_tests/external/wpt/webxr/ar-module/idlharness.https.window.js b/third_party/blink/web_tests/external/wpt/webxr/ar-module/idlharness.https.window.js
new file mode 100644
index 0000000..1268f4e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webxr/ar-module/idlharness.https.window.js
@@ -0,0 +1,16 @@
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+
+'use strict';
+
+// https://immersive-web.github.io/webxr-ar-module/
+
+idl_test(
+  ['webxr-ar-module'],
+  ['webxr', 'dom'],
+  async idl_array => {
+    idl_array.add_objects({
+      // TODO: XRSession
+    });
+  }
+);
diff --git a/third_party/blink/web_tests/external/wpt/webxr/gamepads-module/idlharness.https.window.js b/third_party/blink/web_tests/external/wpt/webxr/gamepads-module/idlharness.https.window.js
new file mode 100644
index 0000000..4509c67a8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webxr/gamepads-module/idlharness.https.window.js
@@ -0,0 +1,16 @@
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+
+'use strict';
+
+// https://immersive-web.github.io/webxr-gamepads-module/
+
+idl_test(
+  ['webxr-gamepads-module'],
+  ['webxr', 'dom'],
+  async idl_array => {
+    idl_array.add_objects({
+      // TODO: XRInputSource
+    });
+  }
+);
diff --git a/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_constructor.https-expected.txt b/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_constructor.https-expected.txt
new file mode 100644
index 0000000..be0603a7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_constructor.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Ensure that XRWebGLLayer's constructor throws appropriate errors promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'then' of undefined"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_constructor.https.html b/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_constructor.https.html
index 0584da79..7e57f42 100644
--- a/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_constructor.https.html
+++ b/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_constructor.https.html
@@ -17,8 +17,11 @@
   let gl = webglCanvas.getContext('webgl', glAttributes);
   return navigator.xr.test.simulateDeviceConnection(TRACKED_IMMERSIVE_DEVICE)
     .then(() => {
-      return navigator.xr.requestSession('inline')
-        .then((session) => {
+      let sessionPromise;
+      navigator.xr.test.simulateUserActivation(function() {
+        sessionPromise = navigator.xr.requestSession('inline');
+      });
+      return sessionPromise.then((session) => {
           try {
             let webglLayerIncompatible = new XRWebGLLayer(session, gl);
           } catch (err) {
diff --git a/third_party/blink/web_tests/external/wpt/worklets/animation-worklet-referrer.https-expected.txt b/third_party/blink/web_tests/external/wpt/worklets/animation-worklet-referrer.https-expected.txt
index d605c756..afa46578 100644
--- a/third_party/blink/web_tests/external/wpt/worklets/animation-worklet-referrer.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/worklets/animation-worklet-referrer.https-expected.txt
@@ -7,12 +7,15 @@
 PASS Importing a remote-origin script from a page that has "same-origin" referrer policy should not send referrer.
 PASS Importing a same-origin script from a same-origin worklet script that has "no-referrer" referrer policy should not send referrer.
 PASS Importing a remote-origin script from a same-origin worklet script that has "no-referrer" referrer policy should not send referrer.
+PASS Importing a same-origin script from a remote-origin worklet script that has "no-referrer" referrer policy should not send referrer.
 PASS Importing a remote-origin script from a remote-origin worklet script that has "no-referrer" referrer policy should not send referrer.
 PASS Importing a same-origin script from a same-origin worklet script that has "origin" referrer policy should send referrer.
 PASS Importing a remote-origin script from a same-origin worklet script that has "origin" referrer policy should send referrer.
+PASS Importing a same-origin script from a remote-origin worklet script that has "origin" referrer policy should send referrer.
 PASS Importing a remote-origin script from a remote-origin worklet script that has "origin" referrer policy should send referrer.
 PASS Importing a same-origin script from a same-origin worklet script that has "same-origin" referrer policy should send referrer.
 PASS Importing a remote-origin script from a same-origin worklet script that has "same-origin" referrer policy should not send referrer.
+FAIL Importing a same-origin script from a remote-origin worklet script that has "same-origin" referrer policy should send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
 FAIL Importing a remote-origin script from a remote-origin worklet script that has "same-origin" referrer policy should not send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/worklets/audio-worklet-referrer.https-expected.txt b/third_party/blink/web_tests/external/wpt/worklets/audio-worklet-referrer.https-expected.txt
index d605c756..afa46578 100644
--- a/third_party/blink/web_tests/external/wpt/worklets/audio-worklet-referrer.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/worklets/audio-worklet-referrer.https-expected.txt
@@ -7,12 +7,15 @@
 PASS Importing a remote-origin script from a page that has "same-origin" referrer policy should not send referrer.
 PASS Importing a same-origin script from a same-origin worklet script that has "no-referrer" referrer policy should not send referrer.
 PASS Importing a remote-origin script from a same-origin worklet script that has "no-referrer" referrer policy should not send referrer.
+PASS Importing a same-origin script from a remote-origin worklet script that has "no-referrer" referrer policy should not send referrer.
 PASS Importing a remote-origin script from a remote-origin worklet script that has "no-referrer" referrer policy should not send referrer.
 PASS Importing a same-origin script from a same-origin worklet script that has "origin" referrer policy should send referrer.
 PASS Importing a remote-origin script from a same-origin worklet script that has "origin" referrer policy should send referrer.
+PASS Importing a same-origin script from a remote-origin worklet script that has "origin" referrer policy should send referrer.
 PASS Importing a remote-origin script from a remote-origin worklet script that has "origin" referrer policy should send referrer.
 PASS Importing a same-origin script from a same-origin worklet script that has "same-origin" referrer policy should send referrer.
 PASS Importing a remote-origin script from a same-origin worklet script that has "same-origin" referrer policy should not send referrer.
+FAIL Importing a same-origin script from a remote-origin worklet script that has "same-origin" referrer policy should send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
 FAIL Importing a remote-origin script from a remote-origin worklet script that has "same-origin" referrer policy should not send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/worklets/layout-worklet-referrer.https-expected.txt b/third_party/blink/web_tests/external/wpt/worklets/layout-worklet-referrer.https-expected.txt
index d605c756..afa46578 100644
--- a/third_party/blink/web_tests/external/wpt/worklets/layout-worklet-referrer.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/worklets/layout-worklet-referrer.https-expected.txt
@@ -7,12 +7,15 @@
 PASS Importing a remote-origin script from a page that has "same-origin" referrer policy should not send referrer.
 PASS Importing a same-origin script from a same-origin worklet script that has "no-referrer" referrer policy should not send referrer.
 PASS Importing a remote-origin script from a same-origin worklet script that has "no-referrer" referrer policy should not send referrer.
+PASS Importing a same-origin script from a remote-origin worklet script that has "no-referrer" referrer policy should not send referrer.
 PASS Importing a remote-origin script from a remote-origin worklet script that has "no-referrer" referrer policy should not send referrer.
 PASS Importing a same-origin script from a same-origin worklet script that has "origin" referrer policy should send referrer.
 PASS Importing a remote-origin script from a same-origin worklet script that has "origin" referrer policy should send referrer.
+PASS Importing a same-origin script from a remote-origin worklet script that has "origin" referrer policy should send referrer.
 PASS Importing a remote-origin script from a remote-origin worklet script that has "origin" referrer policy should send referrer.
 PASS Importing a same-origin script from a same-origin worklet script that has "same-origin" referrer policy should send referrer.
 PASS Importing a remote-origin script from a same-origin worklet script that has "same-origin" referrer policy should not send referrer.
+FAIL Importing a same-origin script from a remote-origin worklet script that has "same-origin" referrer policy should send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
 FAIL Importing a remote-origin script from a remote-origin worklet script that has "same-origin" referrer policy should not send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/worklets/paint-worklet-referrer.https-expected.txt b/third_party/blink/web_tests/external/wpt/worklets/paint-worklet-referrer.https-expected.txt
index d605c756..afa46578 100644
--- a/third_party/blink/web_tests/external/wpt/worklets/paint-worklet-referrer.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/worklets/paint-worklet-referrer.https-expected.txt
@@ -7,12 +7,15 @@
 PASS Importing a remote-origin script from a page that has "same-origin" referrer policy should not send referrer.
 PASS Importing a same-origin script from a same-origin worklet script that has "no-referrer" referrer policy should not send referrer.
 PASS Importing a remote-origin script from a same-origin worklet script that has "no-referrer" referrer policy should not send referrer.
+PASS Importing a same-origin script from a remote-origin worklet script that has "no-referrer" referrer policy should not send referrer.
 PASS Importing a remote-origin script from a remote-origin worklet script that has "no-referrer" referrer policy should not send referrer.
 PASS Importing a same-origin script from a same-origin worklet script that has "origin" referrer policy should send referrer.
 PASS Importing a remote-origin script from a same-origin worklet script that has "origin" referrer policy should send referrer.
+PASS Importing a same-origin script from a remote-origin worklet script that has "origin" referrer policy should send referrer.
 PASS Importing a remote-origin script from a remote-origin worklet script that has "origin" referrer policy should send referrer.
 PASS Importing a same-origin script from a same-origin worklet script that has "same-origin" referrer policy should send referrer.
 PASS Importing a remote-origin script from a same-origin worklet script that has "same-origin" referrer policy should not send referrer.
+FAIL Importing a same-origin script from a remote-origin worklet script that has "same-origin" referrer policy should send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
 FAIL Importing a remote-origin script from a remote-origin worklet script that has "same-origin" referrer policy should not send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/worklets/resources/import-same-origin-referrer-checker-worklet-script-from-remote-origin.sub.js b/third_party/blink/web_tests/external/wpt/worklets/resources/import-same-origin-referrer-checker-worklet-script-from-remote-origin.sub.js
new file mode 100644
index 0000000..33af2258
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/worklets/resources/import-same-origin-referrer-checker-worklet-script-from-remote-origin.sub.js
@@ -0,0 +1,2 @@
+// Forward GET parameters to the server.
+import '{{GET[requestor_origin]}}/worklets/resources/referrer-checker.py?referrer_policy={{GET[referrer_policy]}}&expected_referrer={{GET[expected_referrer]}}';
diff --git a/third_party/blink/web_tests/external/wpt/worklets/resources/import-same-origin-referrer-checker-worklet-script-from-remote-origin.sub.js.headers b/third_party/blink/web_tests/external/wpt/worklets/resources/import-same-origin-referrer-checker-worklet-script-from-remote-origin.sub.js.headers
new file mode 100644
index 0000000..cb762ef
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/worklets/resources/import-same-origin-referrer-checker-worklet-script-from-remote-origin.sub.js.headers
@@ -0,0 +1 @@
+Access-Control-Allow-Origin: *
diff --git a/third_party/blink/web_tests/external/wpt/worklets/resources/referrer-tests.js b/third_party/blink/web_tests/external/wpt/worklets/resources/referrer-tests.js
index 01b8e2a..b3c4a048 100644
--- a/third_party/blink/web_tests/external/wpt/worklets/resources/referrer-tests.js
+++ b/third_party/blink/web_tests/external/wpt/worklets/resources/referrer-tests.js
@@ -88,6 +88,7 @@
 
   // Tests for descendant script fetch -----------------------------------------
 
+  // Referrer policy: no-referrer.
   promise_test(() => {
     return runReferrerTest({ workletType: workletType,
                              fetchType: 'descendant',
@@ -111,10 +112,20 @@
                              fetchType: 'descendant',
                              referrerPolicy: 'no-referrer',
                              scriptOrigins: { topLevel: 'remote',
+                                              descendant: 'same' } });
+  }, 'Importing a same-origin script from a remote-origin worklet script ' +
+     'that has "no-referrer" referrer policy should not send referrer.');
+
+  promise_test(() => {
+    return runReferrerTest({ workletType: workletType,
+                             fetchType: 'descendant',
+                             referrerPolicy: 'no-referrer',
+                             scriptOrigins: { topLevel: 'remote',
                                               descendant: 'remote' } });
   }, 'Importing a remote-origin script from a remote-origin worklet script ' +
      'that has "no-referrer" referrer policy should not send referrer.');
 
+  // Referrer policy: origin.
   promise_test(() => {
     return runReferrerTest({ workletType: workletType,
                              fetchType: 'descendant',
@@ -138,10 +149,20 @@
                              fetchType: 'descendant',
                              referrerPolicy: 'origin',
                              scriptOrigins: { topLevel: 'remote',
+                                              descendant: 'same' } });
+  }, 'Importing a same-origin script from a remote-origin worklet script ' +
+     'that has "origin" referrer policy should send referrer.');
+
+  promise_test(() => {
+    return runReferrerTest({ workletType: workletType,
+                             fetchType: 'descendant',
+                             referrerPolicy: 'origin',
+                             scriptOrigins: { topLevel: 'remote',
                                               descendant: 'remote' } });
   }, 'Importing a remote-origin script from a remote-origin worklet script ' +
      'that has "origin" referrer policy should send referrer.');
 
+  // Referrer policy: same-origin.
   promise_test(() => {
     return runReferrerTest({ workletType: workletType,
                              fetchType: 'descendant',
@@ -165,7 +186,18 @@
                              fetchType: 'descendant',
                              referrerPolicy: 'same-origin',
                              scriptOrigins: { topLevel: 'remote',
+                                              descendant: 'same' } });
+  }, 'Importing a same-origin script from a remote-origin worklet script ' +
+     'that has "same-origin" referrer policy should send referrer.');
+
+  promise_test(() => {
+    return runReferrerTest({ workletType: workletType,
+                             fetchType: 'descendant',
+                             referrerPolicy: 'same-origin',
+                             scriptOrigins: { topLevel: 'remote',
                                               descendant: 'remote' } });
   }, 'Importing a remote-origin script from a remote-origin worklet script ' +
      'that has "same-origin" referrer policy should not send referrer.');
+
+  // TODO(domfarolino): Add tests for more referrer policies.
 }
diff --git a/third_party/blink/web_tests/external/wpt/worklets/resources/referrer-window.html b/third_party/blink/web_tests/external/wpt/worklets/resources/referrer-window.html
index 4817f045..934e3dc41 100644
--- a/third_party/blink/web_tests/external/wpt/worklets/resources/referrer-window.html
+++ b/third_party/blink/web_tests/external/wpt/worklets/resources/referrer-window.html
@@ -32,6 +32,14 @@
         location.href);
   }
   if (scriptOrigins.topLevel === 'remote' &&
+      scriptOrigins.descendant === 'same') {
+    url = new URL(
+        get_host_info().HTTPS_REMOTE_ORIGIN +
+        '/worklets/resources/' +
+        'import-same-origin-referrer-checker-worklet-script-from-remote-origin.sub.js');
+    return url;
+  }
+  if (scriptOrigins.topLevel === 'remote' &&
       scriptOrigins.descendant === 'remote') {
     return new URL(
         get_host_info().HTTPS_REMOTE_ORIGIN +
@@ -88,6 +96,7 @@
   }
 
   const params = new URLSearchParams;
+  params.append('requestor_origin', document.location.origin);
   params.append('referrer_policy', referrerPolicy);
   params.append('expected_referrer', expectedReferrer);
 
diff --git a/third_party/blink/web_tests/external/wpt/xhr/xmlhttprequest-sync-default-feature-policy.sub.html b/third_party/blink/web_tests/external/wpt/xhr/xmlhttprequest-sync-default-feature-policy.sub.html
index 5ad55577..ab5b78b 100644
--- a/third_party/blink/web_tests/external/wpt/xhr/xmlhttprequest-sync-default-feature-policy.sub.html
+++ b/third_party/blink/web_tests/external/wpt/xhr/xmlhttprequest-sync-default-feature-policy.sub.html
@@ -9,7 +9,7 @@
   <script>
   'use strict';
   run_all_fp_tests_allow_all(
-      'http://{{domains[www]}}:{{ports[http][0]}}',
+      'http://{{hosts[alt][]}}:{{ports[http][0]}}',
       'sync-xhr',
       'NetworkError',
       () => {
diff --git a/third_party/blink/web_tests/hid/hid_getDevices.html b/third_party/blink/web_tests/hid/hid_getDevices.html
index f5652ec7..5bb3c2a 100644
--- a/third_party/blink/web_tests/hid/hid_getDevices.html
+++ b/third_party/blink/web_tests/hid/hid_getDevices.html
@@ -12,7 +12,7 @@
 
 promise_test(async () => {
   let interceptor =
-      new MojoInterfaceInterceptor(blink.mojom.HidService.name);
+      new MojoInterfaceInterceptor(blink.mojom.HidService.name, "context", true);
   interceptor.oninterfacerequest = e => e.handle.close();
   interceptor.start();
 
diff --git a/third_party/blink/web_tests/hid/hid_requestDevice.html b/third_party/blink/web_tests/hid/hid_requestDevice.html
index 4c01da5..edb92ac 100644
--- a/third_party/blink/web_tests/hid/hid_requestDevice.html
+++ b/third_party/blink/web_tests/hid/hid_requestDevice.html
@@ -20,7 +20,7 @@
 
 promise_test(async (t) => {
   let interceptor =
-      new MojoInterfaceInterceptor(blink.mojom.HidService.name);
+      new MojoInterfaceInterceptor(blink.mojom.HidService.name, "context", true);
   interceptor.oninterfacerequest = e => e.handle.close();
   interceptor.start();
 
diff --git a/third_party/blink/web_tests/hid/resources/hid-test-utils.js b/third_party/blink/web_tests/hid/resources/hid-test-utils.js
index 0fdbd659..b177301 100644
--- a/third_party/blink/web_tests/hid/resources/hid-test-utils.js
+++ b/third_party/blink/web_tests/hid/resources/hid-test-utils.js
@@ -134,7 +134,7 @@
 class FakeHidService {
   constructor() {
     this.interceptor_ =
-        new MojoInterfaceInterceptor(blink.mojom.HidService.name);
+        new MojoInterfaceInterceptor(blink.mojom.HidService.name, "context", true);
     this.interceptor_.oninterfacerequest = e => this.bind(e.handle);
     this.bindingSet_ = new mojo.BindingSet(blink.mojom.HidService);
     this.nextGuidValue_ = 0;
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-breakpoints/use-possible-breakpoints-to-resolve-breakpoint.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-breakpoints/use-possible-breakpoints-to-resolve-breakpoint.js
index 7542fe5..c0740b6 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-breakpoints/use-possible-breakpoints-to-resolve-breakpoint.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-breakpoints/use-possible-breakpoints-to-resolve-breakpoint.js
@@ -54,7 +54,8 @@
     SourcesTestRunner.debuggerPlugin(sourceFrame)._handleGutterClick({
       data: {
         lineNumber: lineNumberClicked,
-        event: {button: 0, shiftKey: shiftKey, consume: () => true}
+        event: {button: 0, shiftKey: shiftKey, consume: () => true},
+        gutterType: SourceFrame.SourcesTextEditor.lineNumbersGutterType
       }
     });
     return promise;
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/payment-handler/change-payment-method-manual.https-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/payment-handler/change-payment-method-manual.https-expected.txt
deleted file mode 100644
index 099831a..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/payment-handler/change-payment-method-manual.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Tests for PaymentRequestEvent.changePaymentMethod() Not allowed to install this payment handler
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-hasenrolledinstrument-method.tentative.https-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/payment-request/payment-request-hasenrolledinstrument-method.tentative.https-expected.txt
similarity index 94%
rename from third_party/blink/web_tests/external/wpt/payment-request/payment-request-hasenrolledinstrument-method.tentative.https-expected.txt
rename to third_party/blink/web_tests/platform/linux/external/wpt/payment-request/payment-request-hasenrolledinstrument-method.tentative.https-expected.txt
index ad1d3ce1..a24f90e2 100644
--- a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-hasenrolledinstrument-method.tentative.https-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/external/wpt/payment-request/payment-request-hasenrolledinstrument-method.tentative.https-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Already called show() once
+Harness Error. harness_status.status = 1 , harness_status.message = Unhandled rejection: Already called show() once
 FAIL hasEnrolledInstrument() resolves to false for unsupported payment methods. promise_test: Unhandled rejection with value: object "UnknownError: Renderer process could not establish or lost IPC connection to the PaymentRequest service in the browser process."
 FAIL If request.[[state]] is "interactive", then return a promise rejected with an "InvalidStateError" DOMException. promise_test: Unhandled rejection with value: object "InvalidStateError: No show() or retry() in progress, so nothing to abort"
 FAIL If request.[[state]] is "closed", then return a promise rejected with an "InvalidStateError" DOMException. promise_test: Unhandled rejection with value: object "InvalidStateError: No show() or retry() in progress, so nothing to abort"
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/payment-handler/change-payment-method-manual.https-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/payment-handler/change-payment-method-manual.https-expected.txt
deleted file mode 100644
index 099831a..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/payment-handler/change-payment-method-manual.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Tests for PaymentRequestEvent.changePaymentMethod() Not allowed to install this payment handler
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/external/wpt/payment-handler/change-payment-method-manual.https-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.11/external/wpt/payment-handler/change-payment-method-manual.https-expected.txt
deleted file mode 100644
index 099831a..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.11/external/wpt/payment-handler/change-payment-method-manual.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Tests for PaymentRequestEvent.changePaymentMethod() Not allowed to install this payment handler
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/payment-handler/change-payment-method-manual.https-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/payment-handler/change-payment-method-manual.https-expected.txt
deleted file mode 100644
index 099831a..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/payment-handler/change-payment-method-manual.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Tests for PaymentRequestEvent.changePaymentMethod() Not allowed to install this payment handler
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/mac-retina/external/wpt/payment-handler/change-payment-method-manual.https-expected.txt b/third_party/blink/web_tests/platform/mac-retina/external/wpt/payment-handler/change-payment-method-manual.https-expected.txt
deleted file mode 100644
index 099831a..0000000
--- a/third_party/blink/web_tests/platform/mac-retina/external/wpt/payment-handler/change-payment-method-manual.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Tests for PaymentRequestEvent.changePaymentMethod() Not allowed to install this payment handler
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/fullscreen/api/element-request-fullscreen-and-move-to-iframe-manual-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/fullscreen/api/element-request-fullscreen-and-move-to-iframe-manual-expected.txt
deleted file mode 100644
index b4e9af13..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/fullscreen/api/element-request-fullscreen-and-move-to-iframe-manual-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = fullscreen error
-PASS Element#requestFullscreen() followed by moving the element into an iframe
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/payment-handler/change-payment-method-manual.https-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/payment-handler/change-payment-method-manual.https-expected.txt
deleted file mode 100644
index 099831a..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/payment-handler/change-payment-method-manual.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Tests for PaymentRequestEvent.changePaymentMethod() Not allowed to install this payment handler
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-hasenrolledinstrument-method.tentative.https-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/payment-request/payment-request-hasenrolledinstrument-method.tentative.https-expected.txt
similarity index 94%
copy from third_party/blink/web_tests/external/wpt/payment-request/payment-request-hasenrolledinstrument-method.tentative.https-expected.txt
copy to third_party/blink/web_tests/platform/mac/external/wpt/payment-request/payment-request-hasenrolledinstrument-method.tentative.https-expected.txt
index ad1d3ce1..a24f90e2 100644
--- a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-hasenrolledinstrument-method.tentative.https-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/external/wpt/payment-request/payment-request-hasenrolledinstrument-method.tentative.https-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Already called show() once
+Harness Error. harness_status.status = 1 , harness_status.message = Unhandled rejection: Already called show() once
 FAIL hasEnrolledInstrument() resolves to false for unsupported payment methods. promise_test: Unhandled rejection with value: object "UnknownError: Renderer process could not establish or lost IPC connection to the PaymentRequest service in the browser process."
 FAIL If request.[[state]] is "interactive", then return a promise rejected with an "InvalidStateError" DOMException. promise_test: Unhandled rejection with value: object "InvalidStateError: No show() or retry() in progress, so nothing to abort"
 FAIL If request.[[state]] is "closed", then return a promise rejected with an "InvalidStateError" DOMException. promise_test: Unhandled rejection with value: object "InvalidStateError: No show() or retry() in progress, so nothing to abort"
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/payment-handler/change-payment-method-manual.https-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/payment-handler/change-payment-method-manual.https-expected.txt
deleted file mode 100644
index 099831a..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/payment-handler/change-payment-method-manual.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Tests for PaymentRequestEvent.changePaymentMethod() Not allowed to install this payment handler
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/payment-request/payment-request-hasenrolledinstrument-method.tentative.https-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/payment-request/payment-request-hasenrolledinstrument-method.tentative.https-expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/external/wpt/payment-request/payment-request-hasenrolledinstrument-method.tentative.https-expected.txt
diff --git a/third_party/blink/web_tests/platform/win7/external/wpt/payment-handler/change-payment-method-manual.https-expected.txt b/third_party/blink/web_tests/platform/win7/external/wpt/payment-handler/change-payment-method-manual.https-expected.txt
deleted file mode 100644
index 099831a..0000000
--- a/third_party/blink/web_tests/platform/win7/external/wpt/payment-handler/change-payment-method-manual.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Tests for PaymentRequestEvent.changePaymentMethod() Not allowed to install this payment handler
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-hasenrolledinstrument-method.tentative.https-expected.txt b/third_party/blink/web_tests/platform/win7/external/wpt/payment-request/payment-request-hasenrolledinstrument-method.tentative.https-expected.txt
similarity index 94%
copy from third_party/blink/web_tests/external/wpt/payment-request/payment-request-hasenrolledinstrument-method.tentative.https-expected.txt
copy to third_party/blink/web_tests/platform/win7/external/wpt/payment-request/payment-request-hasenrolledinstrument-method.tentative.https-expected.txt
index ad1d3ce1..a24f90e2 100644
--- a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-hasenrolledinstrument-method.tentative.https-expected.txt
+++ b/third_party/blink/web_tests/platform/win7/external/wpt/payment-request/payment-request-hasenrolledinstrument-method.tentative.https-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Already called show() once
+Harness Error. harness_status.status = 1 , harness_status.message = Unhandled rejection: Already called show() once
 FAIL hasEnrolledInstrument() resolves to false for unsupported payment methods. promise_test: Unhandled rejection with value: object "UnknownError: Renderer process could not establish or lost IPC connection to the PaymentRequest service in the browser process."
 FAIL If request.[[state]] is "interactive", then return a promise rejected with an "InvalidStateError" DOMException. promise_test: Unhandled rejection with value: object "InvalidStateError: No show() or retry() in progress, so nothing to abort"
 FAIL If request.[[state]] is "closed", then return a promise rejected with an "InvalidStateError" DOMException. promise_test: Unhandled rejection with value: object "InvalidStateError: No show() or retry() in progress, so nothing to abort"
diff --git a/third_party/blink/web_tests/svg/animations/updated-values-after-sandwich-order-change.html b/third_party/blink/web_tests/svg/animations/updated-values-after-sandwich-order-change.html
new file mode 100644
index 0000000..9074009
--- /dev/null
+++ b/third_party/blink/web_tests/svg/animations/updated-values-after-sandwich-order-change.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<title>Updating the 'values' attribute after sandwich order change</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<svg>
+  <rect width="100" height="100">
+    <animate attributeName="opacity" begin="0ms; 40ms; 70ms" dur="10ms" id="first" fill="freeze"/>
+    <animate attributeName="opacity" begin="20ms; 50ms" dur="10ms" from="1" to="1" fill="freeze"/>
+  </rect>
+</svg>
+<script>
+  async_test(t => {
+    let first_animate = document.getElementById("first");
+    window.onload = t.step_func(() => {
+      let svg = first_animate.ownerSVGElement;
+      svg.pauseAnimations();
+      window.requestAnimationFrame(t.step_func_done(() => {
+        svg.unpauseAnimations();
+        first_animate.setAttribute("values", "0; 1");
+      }));
+    });
+  });
+</script>
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCRtpTransceiver.https-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCRtpTransceiver.https-expected.txt
index eec6507..e2a810c 100644
--- a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCRtpTransceiver.https-expected.txt
+++ b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCRtpTransceiver.https-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Cannot read property 'receiver' of undefined
+Harness Error. harness_status.status = 1 , harness_status.message = Unhandled rejection: Cannot read property 'receiver' of undefined
 FAIL checkAddTransceiverNoTrack promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'."
 FAIL checkAddTransceiverWithTrack promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'."
 FAIL checkAddTransceiverWithAddTrack assert_equals: expected "[{currentDirection:null,direction:\"sendrecv\",mid:null,receiver:{track:{kind:\"audio\"}},sender:{track:{}},stopped:false},{currentDirection:null,direction:\"sendrecv\",mid:null,receiver:{track:{kind:\"video\"}},sender:{track:{}},stopped:false}]" but got "[]"
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCSctpTransport-events-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCSctpTransport-events-expected.txt
index 9a5c3c22..2289ca1 100644
--- a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCSctpTransport-events-expected.txt
+++ b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCSctpTransport-events-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Cannot read property 'state' of null
+Harness Error. harness_status.status = 1 , harness_status.message = Unhandled rejection: Cannot read property 'state' of null
 FAIL SctpTransport objects are created at appropriate times assert_not_equals: got disallowed value null
 FAIL SctpTransport reaches connected and closed state promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'state' of null"
 Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCSctpTransport-maxChannels-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCSctpTransport-maxChannels-expected.txt
index 4d62c3a..b413fd3 100644
--- a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCSctpTransport-maxChannels-expected.txt
+++ b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCSctpTransport-maxChannels-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Cannot read property 'state' of null
+Harness Error. harness_status.status = 1 , harness_status.message = Unhandled rejection: Cannot read property 'state' of null
 FAIL An unconnected peerconnection must not have maxChannels set assert_not_equals: RTCSctpTransport must be available got disallowed value null
 FAIL maxChannels gets instantiated after connecting promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'maxChannels' of null"
 Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/lock-grid-with-positioned-child.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/lock-grid-with-positioned-child.html
new file mode 100644
index 0000000..17456cc6
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/lock-grid-with-positioned-child.html
@@ -0,0 +1,41 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Display Locking: lock grid with positioned child</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://github.com/WICG/display-locking">
+<link rel="match" href="pass-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<script src="resources/utils.js"></script>
+
+<style>
+#grid {
+  display: grid;
+}
+#positioned {
+  position: absolute;
+}
+</style>
+
+<div id=log></div>
+<div id=grid>
+  <div id=positioned>lorem ipsum</div>
+</div>
+
+<script>
+function finishTest(status_string) {
+  if (document.getElementById("log").innerHTML === "")
+    document.getElementById("log").innerHTML = status_string;
+  takeScreenshot();
+}
+
+function runTest() {
+  const container = document.getElementById("grid");
+  setInvisible(container).then(() => {
+    finishTest("PASS");
+  });
+}
+
+window.onload = () => requestAnimationFrame(runTest);
+</script>
+</html>
diff --git a/tools/clang/blink_gc_plugin/process-graph.py b/tools/clang/blink_gc_plugin/process-graph.py
index 879f95c..fcbce952 100755
--- a/tools/clang/blink_gc_plugin/process-graph.py
+++ b/tools/clang/blink_gc_plugin/process-graph.py
@@ -3,6 +3,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from __future__ import print_function
 import argparse, os, sys, json, subprocess, pickle, StringIO
 
 parser = argparse.ArgumentParser(
@@ -312,7 +313,7 @@
   sout = out.getvalue()
   if not is_ignored_cycle(sout):
     print("\nFound a potentially leaking cycle starting from a GC root:\n",
-          sout)
+          sout, sep="")
     set_reported_error(True)
 
 def load_graph():
diff --git a/tools/gritsettings/translation_expectations.pyl b/tools/gritsettings/translation_expectations.pyl
index 2e0f459b..7dc85b2 100644
--- a/tools/gritsettings/translation_expectations.pyl
+++ b/tools/gritsettings/translation_expectations.pyl
@@ -39,6 +39,7 @@
       "chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd",
       "chrome/browser/resources/chromeos/select_to_speak/strings/select_to_speak_strings.grd",
       "chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings.grd",
+      "chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings.grd",
       "chrome/browser/ui/android/widget/java/strings/android_ui_widget_strings.grd",
       "chrome/credential_provider/gaiacp/gaia_resources.grd",
       "chromeos/chromeos_strings.grd",
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index a430119..d4ddab1 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -13147,6 +13147,17 @@
   <int value="6" label="Texture array has one element"/>
 </enum>
 
+<enum name="DefaultAppName">
+  <int value="0" label="Calculator"/>
+  <int value="1" label="Text"/>
+  <int value="2" label="Get Help"/>
+  <int value="3" label="Gallery"/>
+  <int value="4" label="Video Player"/>
+  <int value="5" label="Audio Player"/>
+  <int value="6" label="Chrome Canvas"/>
+  <int value="7" label="Camera"/>
+</enum>
+
 <enum name="DefaultBrowserAsyncAttemptResult">
   <obsolete>
     Deprecated 2015/11. Renamed to SetDefaultAttemptResult.
@@ -32751,6 +32762,12 @@
   </int>
 </enum>
 
+<enum name="JavaScriptOnlyValueInPasswordForm">
+  <int value="0" label="Only values from JavaScript, and no user focus"/>
+  <int value="1" label="Only values from JavaScript, and user focus"/>
+  <int value="2" label="User typed or autofilled values"/>
+</enum>
+
 <enum name="JpegColorSpace">
   <int value="0" label="Unknown color space">
     This is the bucket that counts the images that did not fall under any of the
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index b98eef9..1b457dd0 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -5651,6 +5651,18 @@
   </summary>
 </histogram>
 
+<histogram base="true" name="Apps.DefaultAppLaunch" enum="DefaultAppName"
+    expires_after="2020-03-21">
+<!-- Name completed by histogram_suffixes name="DefaultAppLaunchSource" -->
+
+  <owner>dominickn@chromium.org</owner>
+  <owner>nancylingwang@chromium.org</owner>
+  <owner>nigeltao@chromium.org</owner>
+  <summary>
+    Records when a user attempts to launch a particular Chrome OS app.
+  </summary>
+</histogram>
+
 <histogram name="Apps.HomeLauncherTransition.AnimationSmoothness" units="%"
     expires_after="2020-04-01">
 <!-- Name completed by histogram suffixes
@@ -71466,7 +71478,7 @@
   <owner>clamy@chromium.org</owner>
   <owner>nasko@chromium.org</owner>
   <summary>
-    Whether the navigation led to a change of BrowsingInstance or not
+    Whether a main frame navigation led to a change of BrowsingInstance or not.
   </summary>
 </histogram>
 
@@ -71482,7 +71494,7 @@
   <owner>clamy@chromium.org</owner>
   <owner>nasko@chromium.org</owner>
   <summary>
-    Whether the navigation led to a change of SiteInstance or not
+    Whether the navigation led to a change of SiteInstance or not.
   </summary>
 </histogram>
 
@@ -100866,6 +100878,16 @@
   </summary>
 </histogram>
 
+<histogram name="PasswordManager.JavaScriptOnlyValueInSubmittedForm"
+    enum="JavaScriptOnlyValueInPasswordForm" expires_after="M87">
+  <owner>dvadym@chromium.org</owner>
+  <owner>battre@chromium.org</owner>
+  <summary>
+    Records whether a successfully submitted password form has only values that
+    came from JavaScript.
+  </summary>
+</histogram>
+
 <histogram
     name="PasswordManager.KeychainMigration.NumChromeOwnedInaccessiblePasswords"
     units="units">
@@ -106854,6 +106876,28 @@
   </summary>
 </histogram>
 
+<histogram name="PLT.iOS.BrowserInitiatedPageLoadTime" units="ms"
+    expires_after="2020-08-09">
+  <owner>djean@chromium.org</owner>
+  <owner>eugenebut@chromium.org</owner>
+  <summary>
+    Page load time for Browser-initiated navigations. Recorded when
+    CRWWebRequestController::didFinishWithURL completes successfully. iOS
+    specific.
+  </summary>
+</histogram>
+
+<histogram name="PLT.iOS.RendererInitiatedPageLoadTime" units="ms"
+    expires_after="2020-08-09">
+  <owner>djean@chromium.org</owner>
+  <owner>eugenebut@chromium.org</owner>
+  <summary>
+    Page load time for Renderer-initiated navigations. Recorded when
+    CRWWebRequestController::didFinishWithURL completes successfully. iOS
+    specific.
+  </summary>
+</histogram>
+
 <histogram name="PLT.LoadType" enum="LoadType" expires_after="2016-08-02">
   <obsolete>
     Use PageLoad.PaintTiming.NavigationToFirstContentfulPaint.LoadType.*
@@ -132268,7 +132312,7 @@
 </histogram>
 
 <histogram name="Signin.AndroidAccountSigninViewSeedingTime" units="ms"
-    expires_after="M80">
+    expires_after="M85">
   <owner>bsazonov@chromium.org</owner>
   <summary>
     The time it takes to seed accounts before proceeding to the account
@@ -165702,6 +165746,19 @@
   <affected-histogram name="Renderer4.ImageDecodeTaskDurationUs"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="DefaultAppLaunchSource" separator=".">
+  <suffix name="FromAppListGrid" label="From app list grid."/>
+  <suffix name="FromAppListGridContextMenu"
+      label="From app list grid context menu."/>
+  <suffix name="FromAppListQuery" label="From app list query."/>
+  <suffix name="FromAppListQueryContextMenu"
+      label="From app list query context menu."/>
+  <suffix name="FromAppListRecommendation"
+      label="From app list recommendation."/>
+  <suffix name="FromShelf" label="From shelf."/>
+  <affected-histogram name="Apps.DefaultAppLaunch"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="DefaultAppsExperiment" separator="_">
   <suffix name="NoDefaultApps" label="User's without default apps installed"/>
   <suffix name="WithDefaultApps" label="User's with default apps installed"/>
@@ -169330,6 +169387,7 @@
 <histogram_suffixes name="NavigationFrameType" separator=".">
   <suffix name="MainFrame" label="Navigation in the main frame."/>
   <suffix name="Subframe" label="Navigation in a subframe."/>
+  <affected-histogram name="Navigation.IsSameSiteInstance"/>
   <affected-histogram name="Navigation.StartToCommit"/>
   <affected-histogram name="Navigation.StartToCommit.CrossProcess"/>
   <affected-histogram name="Navigation.StartToCommit.SameProcess"/>
diff --git a/tools/perf/benchmarks/system_health_smoke_test.py b/tools/perf/benchmarks/system_health_smoke_test.py
index 21d8839..75cb063 100644
--- a/tools/perf/benchmarks/system_health_smoke_test.py
+++ b/tools/perf/benchmarks/system_health_smoke_test.py
@@ -41,11 +41,14 @@
   # and will later be removed.
   'system_health.memory_mobile/browse:tech:discourse_infinite_scroll',
   'system_health.memory_mobile/browse:social:facebook_infinite_scroll',
+  'system_health.memory_mobile/browse:social:instagram',
+  'system_health.memory_mobile/browse:news:reddit',
   'system_health.memory_mobile/browse:social:tumblr_infinite_scroll',
   'system_health.memory_mobile/browse:tools:maps',
   'system_health.memory_mobile/browse:news:cnn',
   'system_health.memory_mobile/load:media:facebook_photos',
   'system_health.memory_mobile/load:news:cnn',
+  'system_health.memory_mobile/load:news:washingtonpost',
   'system_health.memory_mobile/load:tools:stackoverflow',
   'system_health.memory_desktop/load_accessibility:shopping:amazon',
   'system_health.memory_desktop/browse_accessibility:tech:codesearch',
diff --git a/tools/perf/core/results_processor/histograms_output.py b/tools/perf/core/results_processor/histograms_output.py
new file mode 100644
index 0000000..144537d
--- /dev/null
+++ b/tools/perf/core/results_processor/histograms_output.py
@@ -0,0 +1,68 @@
+# 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.
+
+"""Output formatter for HistogramSet Results Format.
+
+Format specification:
+https://github.com/catapult-project/catapult/blob/master/docs/histogram-set-json-format.md
+"""
+
+import json
+import logging
+import os
+
+from tracing.value.diagnostics import generic_set
+from tracing.value.diagnostics import reserved_infos
+from tracing.value import histogram_set
+
+
+# This file is written by telemetry, it contains output of metric computation.
+# This is a temporary hack to keep things working while we gradually move
+# code from Telemetry to Results Processor.
+HISTOGRAM_DICTS_NAME = 'histogram_dicts.json'
+
+# Output file in HistogramSet format.
+OUTPUT_FILENAME = 'histograms.json'
+
+
+def Process(intermediate_results, options):
+  """Process intermediate results and write output in output_dir."""
+  histogram_dicts = Convert(intermediate_results, options.results_label)
+
+  output_file = os.path.join(options.output_dir, OUTPUT_FILENAME)
+  if not options.reset_results and os.path.isfile(output_file):
+    with open(output_file) as input_stream:
+      try:
+        histogram_dicts += json.load(input_stream)
+      except ValueError:
+        logging.warning(
+            'Found existing histograms json but failed to parse it.')
+
+  with open(output_file, 'w') as output_stream:
+    json.dump(histogram_dicts, output_stream)
+
+
+def Convert(intermediate_results, results_label):
+  """Convert intermediate results to histogram dicts"""
+  histograms = histogram_set.HistogramSet()
+  for result in intermediate_results['testResults']:
+    if HISTOGRAM_DICTS_NAME in result['artifacts']:
+      with open(result['artifacts'][HISTOGRAM_DICTS_NAME]['filePath']) as f:
+        histogram_dicts = json.load(f)
+      histograms.ImportDicts(histogram_dicts)
+
+  diagnostics = intermediate_results['benchmarkRun'].get('diagnostics', {})
+  for name, diag in diagnostics.items():
+    # For now, we only support GenericSet diagnostics that are serialized
+    # as lists of values.
+    assert isinstance(diag, list)
+    histograms.AddSharedDiagnosticToAllHistograms(
+        name, generic_set.GenericSet(diag))
+
+  if results_label is not None:
+    histograms.AddSharedDiagnosticToAllHistograms(
+        reserved_infos.LABELS.name,
+        generic_set.GenericSet([results_label]))
+
+  return histograms.AsDicts()
diff --git a/tools/perf/core/results_processor/histograms_output_unittest.py b/tools/perf/core/results_processor/histograms_output_unittest.py
new file mode 100644
index 0000000..b3ea74d
--- /dev/null
+++ b/tools/perf/core/results_processor/histograms_output_unittest.py
@@ -0,0 +1,114 @@
+# 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.
+
+import unittest
+
+import json
+import os
+import shutil
+import tempfile
+
+from core.results_processor import histograms_output
+from core.results_processor import command_line
+from core.results_processor import testing
+
+from tracing.value import histogram
+from tracing.value import histogram_set
+
+
+class HistogramsOutputTest(unittest.TestCase):
+  def setUp(self):
+    self.output_dir = tempfile.mkdtemp()
+    parser = command_line.ArgumentParser()
+    self.options = parser.parse_args([])
+    self.options.output_dir = self.output_dir
+    command_line.ProcessOptions(self.options)
+
+  def tearDown(self):
+    shutil.rmtree(self.output_dir)
+
+  def testConvertOneStory(self):
+    hist_file = os.path.join(self.output_dir,
+                             histograms_output.HISTOGRAM_DICTS_NAME)
+    with open(hist_file, 'w') as f:
+      json.dump([histogram.Histogram('a', 'unitless').AsDict()], f)
+
+    in_results = testing.IntermediateResults(
+        test_results=[
+            testing.TestResult(
+                'benchmark/story',
+                artifacts={'histogram_dicts.json': testing.Artifact(hist_file)},
+            ),
+        ],
+    )
+
+    histogram_dicts = histograms_output.Convert(in_results, results_label=None)
+    out_histograms = histogram_set.HistogramSet()
+    out_histograms.ImportDicts(histogram_dicts)
+    self.assertEqual(len(out_histograms), 1)
+    self.assertEqual(out_histograms.GetFirstHistogram().name, 'a')
+    self.assertEqual(out_histograms.GetFirstHistogram().unit, 'unitless')
+
+  def testConvertDiagnostics(self):
+    hist_file = os.path.join(self.output_dir,
+                             histograms_output.HISTOGRAM_DICTS_NAME)
+    with open(hist_file, 'w') as f:
+      json.dump([histogram.Histogram('a', 'unitless').AsDict()], f)
+
+    in_results = testing.IntermediateResults(
+        test_results=[],
+        diagnostics={
+            'benchmarks': ['benchmark'],
+            'osNames': ['linux'],
+            'documentationUrls': [['documentation', 'url']],
+        },
+    )
+
+    histogram_dicts = histograms_output.Convert(in_results,
+                                                results_label='label')
+    out_histograms = histogram_set.HistogramSet()
+    out_histograms.ImportDicts(histogram_dicts)
+    diag_values = [list(v) for v in  out_histograms.shared_diagnostics]
+    self.assertEqual(len(diag_values), 4)
+    self.assertIn(['benchmark'], diag_values)
+    self.assertIn(['linux'], diag_values)
+    self.assertIn([['documentation', 'url']], diag_values)
+    self.assertIn(['label'], diag_values)
+
+  def testConvertTwoStories(self):
+    hist_file = os.path.join(self.output_dir,
+                             histograms_output.HISTOGRAM_DICTS_NAME)
+    with open(hist_file, 'w') as f:
+      json.dump([histogram.Histogram('a', 'unitless').AsDict()], f)
+
+    in_results = testing.IntermediateResults(
+        test_results=[
+            testing.TestResult(
+                'benchmark/story1',
+                artifacts={'histogram_dicts.json': testing.Artifact(hist_file)},
+            ),
+            testing.TestResult(
+                'benchmark/story2',
+                artifacts={'histogram_dicts.json': testing.Artifact(hist_file)},
+            ),
+            testing.TestResult(
+                'benchmark/story1',
+                artifacts={'histogram_dicts.json': testing.Artifact(hist_file)},
+            ),
+            testing.TestResult(
+                'benchmark/story2',
+                artifacts={'histogram_dicts.json': testing.Artifact(hist_file)},
+            ),
+        ],
+    )
+
+    histogram_dicts = histograms_output.Convert(in_results,
+                                                results_label='label')
+    out_histograms = histogram_set.HistogramSet()
+    out_histograms.ImportDicts(histogram_dicts)
+    self.assertEqual(len(out_histograms), 4)
+    hist = out_histograms.GetFirstHistogram()
+    self.assertEqual(hist.name, 'a')
+    self.assertEqual(hist.unit, 'unitless')
+    self.assertEqual(list(hist.diagnostics['labels']), ['label'])
diff --git a/tools/perf/core/results_processor/json3_output.py b/tools/perf/core/results_processor/json3_output.py
index 82cdf28..1585156 100644
--- a/tools/perf/core/results_processor/json3_output.py
+++ b/tools/perf/core/results_processor/json3_output.py
@@ -19,10 +19,10 @@
 OUTPUT_FILENAME = 'test-results.json'
 
 
-def Process(intermediate_results, output_dir):
+def Process(intermediate_results, options):
   """Process intermediate results and write output in output_dir."""
-  results = Convert(intermediate_results, output_dir)
-  with open(os.path.join(output_dir, OUTPUT_FILENAME), 'w') as f:
+  results = Convert(intermediate_results, options.output_dir)
+  with open(os.path.join(options.output_dir, OUTPUT_FILENAME), 'w') as f:
     json.dump(results, f, sort_keys=True, indent=4, separators=(',', ': '))
 
 
diff --git a/tools/perf/core/results_processor/processor.py b/tools/perf/core/results_processor/processor.py
index ad13da4..fb60ca2 100644
--- a/tools/perf/core/results_processor/processor.py
+++ b/tools/perf/core/results_processor/processor.py
@@ -13,12 +13,14 @@
 
 from core.results_processor import command_line
 from core.results_processor import json3_output
+from core.results_processor import histograms_output
 
 
 HTML_TRACE_NAME = 'trace.html'
 TELEMETRY_RESULTS = '_telemetry_results.jsonl'
 FORMATTERS = {
     'json-test-results': json3_output,
+    'histograms': histograms_output,
 }
 
 
@@ -48,7 +50,7 @@
       raise NotImplementedError(output_format)
 
     formatter = FORMATTERS[output_format]
-    formatter.Process(intermediate_results, options.output_dir)
+    formatter.Process(intermediate_results, options)
 
 
 def _LoadIntermediateResults(intermediate_file):
diff --git a/tools/perf/core/results_processor/processor_test.py b/tools/perf/core/results_processor/processor_test.py
index de0bcf0..29d70af 100644
--- a/tools/perf/core/results_processor/processor_test.py
+++ b/tools/perf/core/results_processor/processor_test.py
@@ -15,10 +15,16 @@
 import tempfile
 import unittest
 
+import mock
+
 from core.results_processor import json3_output
+from core.results_processor import histograms_output
 from core.results_processor import processor
 from core.results_processor import testing
 
+from tracing.value import histogram
+from tracing.value import histogram_set
+
 
 class ResultsProcessorIntegrationTests(unittest.TestCase):
   def setUp(self):
@@ -96,3 +102,141 @@
     self.assertEqual(len(artifacts), 2)
     self.assertEqual(artifacts['logs'], ['gs://logs.txt'])
     self.assertEqual(artifacts['trace.html'], ['gs://trace.html'])
+
+  # TODO(crbug.com/981349): Remove this mock when histograms format
+  # is enabled in results_processor.
+  @mock.patch('core.results_processor.command_line.SUPPORTED_FORMATS',
+              ['histograms'])
+  def testHistogramsOutput(self):
+    hist_file = os.path.join(self.output_dir,
+                             histograms_output.HISTOGRAM_DICTS_NAME)
+    with open(hist_file, 'w') as f:
+      json.dump([histogram.Histogram('a', 'unitless').AsDict()], f)
+
+    self.SerializeIntermediateResults(
+        test_results=[
+            testing.TestResult(
+                'benchmark/story',
+                artifacts={'histogram_dicts.json': testing.Artifact(hist_file)},
+            ),
+        ],
+        diagnostics={
+            'benchmarks': ['benchmark'],
+            'osNames': ['linux'],
+            'documentationUrls': [['documentation', 'url']],
+        },
+        start_time='2009-02-13T23:31:30.987000Z',
+    )
+
+    processor.main([
+        '--output-format', 'histograms',
+        '--output-dir', self.output_dir,
+        '--intermediate-dir', self.intermediate_dir,
+        '--results-label', 'label',
+    ])
+
+    with open(os.path.join(
+        self.output_dir, histograms_output.OUTPUT_FILENAME)) as f:
+      results = json.load(f)
+
+    out_histograms = histogram_set.HistogramSet()
+    out_histograms.ImportDicts(results)
+    self.assertEqual(len(out_histograms), 1)
+    self.assertEqual(out_histograms.GetFirstHistogram().name, 'a')
+    self.assertEqual(out_histograms.GetFirstHistogram().unit, 'unitless')
+
+    diag_values = [list(v) for v in  out_histograms.shared_diagnostics]
+    self.assertEqual(len(diag_values), 4)
+    self.assertIn(['benchmark'], diag_values)
+    self.assertIn(['linux'], diag_values)
+    self.assertIn([['documentation', 'url']], diag_values)
+    self.assertIn(['label'], diag_values)
+
+  # TODO(crbug.com/981349): Remove this mock when histograms format
+  # is enabled in results_processor.
+  @mock.patch('core.results_processor.command_line.SUPPORTED_FORMATS',
+              ['histograms'])
+  def testHistogramsOutputResetResults(self):
+    hist_file = os.path.join(self.output_dir,
+                             histograms_output.HISTOGRAM_DICTS_NAME)
+    with open(hist_file, 'w') as f:
+      json.dump([histogram.Histogram('a', 'unitless').AsDict()], f)
+
+    self.SerializeIntermediateResults(
+        test_results=[
+            testing.TestResult(
+                'benchmark/story',
+                artifacts={'histogram_dicts.json': testing.Artifact(hist_file)},
+            ),
+        ],
+    )
+
+    processor.main([
+        '--output-format', 'histograms',
+        '--output-dir', self.output_dir,
+        '--intermediate-dir', self.intermediate_dir,
+        '--results-label', 'label1',
+    ])
+
+    processor.main([
+        '--output-format', 'histograms',
+        '--output-dir', self.output_dir,
+        '--intermediate-dir', self.intermediate_dir,
+        '--results-label', 'label2',
+        '--reset-results',
+    ])
+
+    with open(os.path.join(
+        self.output_dir, histograms_output.OUTPUT_FILENAME)) as f:
+      results = json.load(f)
+
+    out_histograms = histogram_set.HistogramSet()
+    out_histograms.ImportDicts(results)
+    self.assertEqual(len(out_histograms), 1)
+    diag_values = [list(v) for v in  out_histograms.shared_diagnostics]
+    self.assertNotIn(['label1'], diag_values)
+    self.assertIn(['label2'], diag_values)
+
+  # TODO(crbug.com/981349): Remove this mock when histograms format
+  # is enabled in results_processor.
+  @mock.patch('core.results_processor.command_line.SUPPORTED_FORMATS',
+              ['histograms'])
+  def testHistogramsOutputAppendResults(self):
+    hist_file = os.path.join(self.output_dir,
+                             histograms_output.HISTOGRAM_DICTS_NAME)
+    with open(hist_file, 'w') as f:
+      json.dump([histogram.Histogram('a', 'unitless').AsDict()], f)
+
+    self.SerializeIntermediateResults(
+        test_results=[
+            testing.TestResult(
+                'benchmark/story',
+                artifacts={'histogram_dicts.json': testing.Artifact(hist_file)},
+            ),
+        ],
+    )
+
+    processor.main([
+        '--output-format', 'histograms',
+        '--output-dir', self.output_dir,
+        '--intermediate-dir', self.intermediate_dir,
+        '--results-label', 'label1',
+    ])
+
+    processor.main([
+        '--output-format', 'histograms',
+        '--output-dir', self.output_dir,
+        '--intermediate-dir', self.intermediate_dir,
+        '--results-label', 'label2',
+    ])
+
+    with open(os.path.join(
+        self.output_dir, histograms_output.OUTPUT_FILENAME)) as f:
+      results = json.load(f)
+
+    out_histograms = histogram_set.HistogramSet()
+    out_histograms.ImportDicts(results)
+    self.assertEqual(len(out_histograms), 2)
+    diag_values = [list(v) for v in  out_histograms.shared_diagnostics]
+    self.assertIn(['label1'], diag_values)
+    self.assertIn(['label2'], diag_values)
diff --git a/tools/perf/core/results_processor/testing.py b/tools/perf/core/results_processor/testing.py
index 275d5cf..21adc520 100644
--- a/tools/perf/core/results_processor/testing.py
+++ b/tools/perf/core/results_processor/testing.py
@@ -11,7 +11,7 @@
 
 
 def IntermediateResults(test_results, start_time='2015-10-21T07:28:00.000Z',
-                        finalized=True, interrupted=False):
+                        finalized=True, interrupted=False, diagnostics=None):
   """Build a dict of 'parsed' intermediate results.
 
   Args:
@@ -28,6 +28,7 @@
           'startTime': start_time,
           'finalized': finalized,
           'interrupted': interrupted,
+          'diagnostics': diagnostics or {},
       },
       'testResults': list(test_results)
   }
diff --git a/tools/perf/page_sets/data/system_health_desktop.json b/tools/perf/page_sets/data/system_health_desktop.json
index 88fc0a77..64aee06 100644
--- a/tools/perf/page_sets/data/system_health_desktop.json
+++ b/tools/perf/page_sets/data/system_health_desktop.json
@@ -113,6 +113,9 @@
         },
         "browse:tools:maps:2019": {
             "DEFAULT": "system_health_desktop_feb332ef0c.wprgo"
+	},
+        "browse:tools:sheets:2019": {
+            "DEFAULT": "system_health_desktop_d7b02362d8.wprgo"
         },
         "browse_accessibility:media:youtube": {
             "DEFAULT": "system_health_desktop_062.wprgo"
@@ -369,4 +372,4 @@
     },
     "description": "Describes the Web Page Replay archives for a story set. Don't edit by hand! Use record_wpr for updating.",
     "platform_specific": true
-}
\ No newline at end of file
+}
diff --git a/tools/perf/page_sets/data/system_health_desktop_d7b02362d8.wprgo.sha1 b/tools/perf/page_sets/data/system_health_desktop_d7b02362d8.wprgo.sha1
new file mode 100644
index 0000000..ff4301e
--- /dev/null
+++ b/tools/perf/page_sets/data/system_health_desktop_d7b02362d8.wprgo.sha1
@@ -0,0 +1 @@
+d7b02362d877b62af94558abea7f3767d2fcd55a
\ No newline at end of file
diff --git a/tools/perf/page_sets/data/system_health_mobile.json b/tools/perf/page_sets/data/system_health_mobile.json
index 6c471ac6..95cecac9 100644
--- a/tools/perf/page_sets/data/system_health_mobile.json
+++ b/tools/perf/page_sets/data/system_health_mobile.json
@@ -63,6 +63,9 @@
         "browse:news:reddit": {
             "DEFAULT": "system_health_mobile_027.wprgo"
         },
+        "browse:news:reddit:2019": {
+            "DEFAULT": "system_health_mobile_1a5563286a.wprgo"
+        },
         "browse:news:toi": {
             "DEFAULT": "system_health_mobile_064.wprgo"
         },
@@ -99,6 +102,9 @@
         "browse:social:instagram": {
             "DEFAULT": "system_health_mobile_060.wprgo"
         },
+        "browse:social:instagram:2019": {
+            "DEFAULT": "system_health_mobile_c38cfb84fc.wprgo"
+        },
         "browse:social:pinterest_infinite_scroll": {
             "DEFAULT": "system_health_mobile_063.wprgo"
         },
@@ -210,6 +216,9 @@
         "load:news:washingtonpost": {
             "DEFAULT": "system_health_mobile_013.wprgo"
         },
+        "load:news:washingtonpost:2019": {
+            "DEFAULT": "system_health_mobile_f2584469fe.wprgo"
+        },
         "load:news:wikipedia": {
             "DEFAULT": "system_health_mobile_002.wprgo"
         },
diff --git a/tools/perf/page_sets/data/system_health_mobile_1a5563286a.wprgo.sha1 b/tools/perf/page_sets/data/system_health_mobile_1a5563286a.wprgo.sha1
new file mode 100644
index 0000000..9a4c651
--- /dev/null
+++ b/tools/perf/page_sets/data/system_health_mobile_1a5563286a.wprgo.sha1
@@ -0,0 +1 @@
+1a5563286a468da721755207026403338f629d23
\ No newline at end of file
diff --git a/tools/perf/page_sets/data/system_health_mobile_c38cfb84fc.wprgo.sha1 b/tools/perf/page_sets/data/system_health_mobile_c38cfb84fc.wprgo.sha1
new file mode 100644
index 0000000..f4fa097
--- /dev/null
+++ b/tools/perf/page_sets/data/system_health_mobile_c38cfb84fc.wprgo.sha1
@@ -0,0 +1 @@
+c38cfb84fcfa54c0540d69f2e4d7f19b46d04ff0
\ No newline at end of file
diff --git a/tools/perf/page_sets/data/system_health_mobile_f2584469fe.wprgo.sha1 b/tools/perf/page_sets/data/system_health_mobile_f2584469fe.wprgo.sha1
new file mode 100644
index 0000000..c21563a6
--- /dev/null
+++ b/tools/perf/page_sets/data/system_health_mobile_f2584469fe.wprgo.sha1
@@ -0,0 +1 @@
+f2584469fe9e114e903bfe67317920fe692a204a
\ No newline at end of file
diff --git a/tools/perf/page_sets/system_health/browsing_stories.py b/tools/perf/page_sets/system_health/browsing_stories.py
index 4657dd4..c44d81a 100644
--- a/tools/perf/page_sets/system_health/browsing_stories.py
+++ b/tools/perf/page_sets/system_health/browsing_stories.py
@@ -161,6 +161,22 @@
     action_runner.NavigateBack()
 
 
+class InstagramMobileStory2019(_ArticleBrowsingStory):
+  NAME = 'browse:social:instagram:2019'
+  URL = 'https://www.instagram.com/badgalriri/'
+  ITEM_SELECTOR = '[class="v1Nh3 kIKUG  _bz0w"] a'
+  ITEMS_TO_VISIT = 8
+
+  SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY
+  TAGS = [story_tags.EMERGING_MARKET, story_tags.YEAR_2019]
+
+  def _WaitForNavigation(self, action_runner):
+    action_runner.WaitForElement(selector='[title="badgalriri"]')
+
+  def _NavigateBack(self, action_runner):
+    action_runner.NavigateBack()
+
+
 class FlipboardDesktopStory2018(_ArticleBrowsingStory):
   NAME = 'browse:news:flipboard:2018'
   URL = 'https://flipboard.com/explore'
@@ -222,6 +238,30 @@
   SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY
   TAGS = [story_tags.YEAR_2016]
 
+class RedditMobileStory2019(_ArticleBrowsingStory):
+  NAME = 'browse:news:reddit:2019'
+  URL = 'https://www.reddit.com/r/news/top/?sort=top&t=week'
+  IS_SINGLE_PAGE_APP = True
+  ITEM_SELECTOR = '.PostHeader__post-title-line'
+  SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY
+  TAGS = [story_tags.YEAR_2019]
+
+  def _DidLoadDocument(self, action_runner):
+    # We encountered ads disguised as articles on the Reddit one so far. The
+    # following code skips that ad.
+    # If we encounter it more often it will make sense to have a more generic
+    # approach, e.g an OFFSET to start iterating from, or an index to skip.
+
+    # Add one to the items to visit since we are going to skip the ad and we
+    # want to still visit the same amount of articles.
+    for i in xrange(self.ITEMS_TO_VISIT + 1):
+      # Skip the ad disguised as an article.
+      if i == 1:
+           continue
+      self._NavigateToItem(action_runner, i)
+      self._ReadNextArticle(action_runner)
+      self._NavigateBack(action_runner)
+      self._ScrollMainPage(action_runner)
 
 class TwitterMobileStory(_ArticleBrowsingStory):
   NAME = 'browse:social:twitter'
@@ -1270,6 +1310,116 @@
 
 
 ##############################################################################
+# Google sheets browsing story.
+##############################################################################
+
+
+class GoogleSheetsDesktopStory(system_health_story.SystemHealthStory):
+  NAME = 'browse:tools:sheets:2019'
+  URL = ('https://docs.google.com/spreadsheets/d/' +
+         '16jfsJs14QrWKhsbxpdJXgoYumxNpnDt08DTK82Puc2A/' +
+         'edit#gid=896027318&range=C:C')
+  SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY
+  TAGS = [story_tags.JAVASCRIPT_HEAVY, story_tags.YEAR_2019]
+
+  # This map translates page-specific event names to event names needed for
+  # the reported_by_page:* metric.
+  EVENTS_REPORTED_BY_PAGE = '''
+    window.__telemetry_reported_page_events = {
+      'ccv':
+          'telemetry:reported_by_page:viewable',
+      'fcoe':
+          'telemetry:reported_by_page:interactive',
+      'first_meaningful_calc_begin':
+          'telemetry:reported_by_page:benchmark_begin',
+      'first_meaningful_calc_end':
+          'telemetry:reported_by_page:benchmark_end'
+    };
+  '''
+
+  # Patch performance.mark to get notified about page events.
+  PERFOMANCE_MARK = '''
+    window.__telemetry_observed_page_events = new Set();
+    (function () {
+      let reported = window.__telemetry_reported_page_events;
+      let observed = window.__telemetry_observed_page_events;
+      let performance_mark = window.performance.mark;
+      window.performance.mark = function (label) {
+        performance_mark.call(window.performance, label);
+        if (reported.hasOwnProperty(label)) {
+          performance_mark.call(
+              window.performance, reported[label]);
+          observed.add(reported[label]);
+        }
+      }
+    })();
+  '''
+
+  # Page event queries.
+  INTERACTIVE_EVENT = '''
+    (window.__telemetry_observed_page_events.has(
+        "telemetry:reported_by_page:interactive"))
+  '''
+  CALC_BEGIN_EVENT = '''
+    (window.__telemetry_observed_page_events.has(
+        "telemetry:reported_by_page:benchmark_begin"))
+  '''
+  CALC_END_EVENT = '''
+    (window.__telemetry_observed_page_events.has(
+        "telemetry:reported_by_page:benchmark_end"))
+  '''
+  CLEAR_EVENTS = 'window.__telemetry_observed_page_events.clear()'
+
+  # Start recalculation of the current column by invoking
+  # trixApp.module$contents$waffle$DesktopRitzApp_DesktopRitzApp$actionRegistry_
+  #   .f_actions__com_google_apps_docs_xplat_controller_ActionRegistryImpl_
+  #   ['trix-fill-right'].fireAction()
+  RECALCULATE_COLUMN = "trixApp.Cb.D['trix-fill-right'].Eb();"
+
+  # Patch the goog$Uri.prototype.setParameterValue to fix the
+  # session parameters that depend on Math.random and Date.now.
+  DETERMINISITIC_SESSION = '''
+    if (window.xk) {
+      window.xk.prototype.wc = function (a, b) {
+          if (a === "rand") { b = "1566829321650"; }
+          if (a === "zx") { b = "9azccr4i1bz5"; }
+          if (a === "ssfi") { b = "0"; }
+          this.C.set(a, b);
+          return this;
+      }
+    }
+  '''
+
+  def __init__(self, story_set, take_memory_measurement):
+    super(GoogleSheetsDesktopStory, self).__init__(story_set,
+        take_memory_measurement)
+    self.script_to_evaluate_on_commit = js_template.Render(
+        '''{{@events_reported_by_page}}
+        {{@performance_mark}}
+        document.addEventListener('readystatechange', event => {
+          if (event.target.readyState === 'interactive') {
+            {{@deterministic_session}}
+          }
+        });''',
+        events_reported_by_page=self.EVENTS_REPORTED_BY_PAGE,
+        performance_mark=self.PERFOMANCE_MARK,
+        deterministic_session=self.DETERMINISITIC_SESSION)
+
+  def _DidLoadDocument(self, action_runner):
+    # 1. Wait until the spreadsheet loads.
+    action_runner.WaitForJavaScriptCondition(self.INTERACTIVE_EVENT)
+    # 2. Idle for 5 seconds for Chrome's timeToInteractive metric.
+    action_runner.Wait(5)
+    # 3. Prepare for observing calcuation events.
+    action_runner.EvaluateJavaScript(self.CLEAR_EVENTS)
+    # 4. Recalculate the column.
+    action_runner.EvaluateJavaScript(self.RECALCULATE_COLUMN)
+    # 5. Wait for calculation completion.
+    action_runner.WaitForJavaScriptCondition(self.CALC_BEGIN_EVENT)
+    action_runner.WaitForJavaScriptCondition(self.CALC_END_EVENT)
+
+
+##############################################################################
 # Browsing stories with infinite scrolling
 ##############################################################################
 
diff --git a/tools/perf/page_sets/system_health/loading_stories.py b/tools/perf/page_sets/system_health/loading_stories.py
index a4a2e2b..fa0e8f7 100644
--- a/tools/perf/page_sets/system_health/loading_stories.py
+++ b/tools/perf/page_sets/system_health/loading_stories.py
@@ -9,6 +9,8 @@
 from page_sets.login_helpers import dropbox_login
 from page_sets.login_helpers import google_login
 
+from telemetry.util import js_template
+
 
 class _LoadingStory(system_health_story.SystemHealthStory):
   """Abstract base class for single-page System Health user stories."""
@@ -241,6 +243,33 @@
     if has_button:
       action_runner.ClickElement(selector=self._CLOSE_BUTTON_SELECTOR)
 
+class LoadWashingtonPostMobileStory2019(_LoadingStory):
+  NAME = 'load:news:washingtonpost:2019'
+  URL = 'https://www.washingtonpost.com/pwa'
+  SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY
+  TAGS = [story_tags.HEALTH_CHECK, story_tags.YEAR_2019]
+  _CONTINUE_FREE_BUTTON_SELECTOR = '.continue-btn.button.free'
+  _ACCEPT_GDPR_SELECTOR = '.agree-ckb'
+  _CONTINUE_TO_SITE_SELECTOR = '.continue-btn.button.accept-consent'
+
+  def _DidLoadDocument(self, action_runner):
+    # Close the popup window. On Nexus 9 (and probably other tables) the popup
+    # window does not have a "Close" button, instead it has only a "Send link
+    # to phone" button. So on tablets we run with the popup window open. The
+    # popup is transparent, so this is mostly an aesthetical issue.
+    has_button = action_runner.EvaluateJavaScript(
+        '!!document.querySelector({{ selector }})',
+        selector=self._CONTINUE_FREE_BUTTON_SELECTOR)
+    if has_button:
+      action_runner.ClickElement(selector=self._CONTINUE_FREE_BUTTON_SELECTOR)
+      action_runner.ScrollPageToElement(selector=self._ACCEPT_GDPR_SELECTOR)
+      action_runner.ClickElement(selector=self._ACCEPT_GDPR_SELECTOR)
+      element_function = js_template.Render(
+        'document.querySelectorAll({{ selector }})[{{ index }}]',
+        selector=self._CONTINUE_TO_SITE_SELECTOR, index=0)
+      action_runner.ClickElement(element_function=element_function)
+
+
 
 class LoadWikipediaStory2018(_LoadingStory):
   NAME = 'load:news:wikipedia:2018'
diff --git a/ui/accessibility/ax_range.h b/ui/accessibility/ax_range.h
index 612516d1..f84ff61 100644
--- a/ui/accessibility/ax_range.h
+++ b/ui/accessibility/ax_range.h
@@ -50,7 +50,7 @@
     focus_.swap(other.focus_);
   }
 
-  virtual ~AXRange() {}
+  virtual ~AXRange() = default;
 
   AXPositionType* anchor() const {
     DCHECK(anchor_);
@@ -62,15 +62,10 @@
     return focus_.get();
   }
 
-  bool IsNull() const {
-    DCHECK(anchor_ && focus_);
-    return anchor_->IsNullPosition() || focus_->IsNullPosition();
-  }
-
   AXRange& operator=(const AXRange& other) = delete;
 
-  AXRange& operator=(const AXRange&& other) {
-    if (this != other) {
+  AXRange& operator=(AXRange&& other) {
+    if (this != &other) {
       anchor_ = AXPositionType::CreateNullPosition();
       focus_ = AXPositionType::CreateNullPosition();
       anchor_.swap(other.anchor_);
@@ -88,7 +83,7 @@
 
   bool operator!=(const AXRange& other) const { return !(*this == other); }
 
-  AXRange GetForwardRange() const {
+  AXRange AsForwardRange() const {
     // When we have a range with an empty text representation, its endpoints
     // would be considered equal as text positions, but they could be located in
     // different anchors of the AXTree. Compare them as tree positions first to
@@ -102,6 +97,8 @@
                : AXRange(anchor_->Clone(), focus_->Clone());
   }
 
+  bool IsCollapsed() const { return !IsNull() && *anchor_ == *focus_; }
+
   // We define a "leaf text range" as an AXRange whose endpoints are leaf text
   // positions located within the same anchor of the AXTree.
   bool IsLeafTextRange() const {
@@ -109,6 +106,11 @@
            anchor_->IsLeafTextPosition() && focus_->IsLeafTextPosition();
   }
 
+  bool IsNull() const {
+    DCHECK(anchor_ && focus_);
+    return anchor_->IsNullPosition() || focus_->IsNullPosition();
+  }
+
   // We can decompose any given AXRange into multiple "leaf text ranges".
   // As an example, consider the following HTML code:
   //
@@ -208,13 +210,13 @@
   };
 
   Iterator begin() const {
-    AXRange forward_range = GetForwardRange();
+    AXRange forward_range = AsForwardRange();
     return Iterator(std::move(forward_range.anchor_),
                     std::move(forward_range.focus_));
   }
 
   Iterator end() const {
-    AXRange forward_range = GetForwardRange();
+    AXRange forward_range = AsForwardRange();
     return Iterator(nullptr, std::move(forward_range.focus_));
   }
 
diff --git a/ui/accessibility/ax_range_unittest.cc b/ui/accessibility/ax_range_unittest.cc
index 2145f4b..2df467ce 100644
--- a/ui/accessibility/ax_range_unittest.cc
+++ b/ui/accessibility/ax_range_unittest.cc
@@ -377,6 +377,100 @@
   EXPECT_EQ(test_positions_1_and_2, test_positions_1_and_3);
 }
 
+TEST_F(AXRangeTest, AsForwardRange) {
+  TestPositionRange null_range(AXNodePosition::CreateNullPosition(),
+                               AXNodePosition::CreateNullPosition());
+  null_range = null_range.AsForwardRange();
+  EXPECT_TRUE(null_range.IsNull());
+
+  TestPositionInstance tree_position = AXNodePosition::CreateTreePosition(
+      tree_->data().tree_id, button_.id, 0 /* child_index */);
+  TestPositionInstance text_position1 = AXNodePosition::CreateTextPosition(
+      tree_->data().tree_id, line_break1_.id, 1 /* text_offset */,
+      ax::mojom::TextAffinity::kDownstream);
+  TestPositionInstance text_position2 = AXNodePosition::CreateTextPosition(
+      tree_->data().tree_id, inline_box2_.id, 0 /* text_offset */,
+      ax::mojom::TextAffinity::kDownstream);
+
+  TestPositionRange tree_to_text_range(text_position1->Clone(),
+                                       tree_position->Clone());
+  tree_to_text_range = tree_to_text_range.AsForwardRange();
+  EXPECT_EQ(*tree_position, *tree_to_text_range.anchor());
+  EXPECT_EQ(*text_position1, *tree_to_text_range.focus());
+
+  TestPositionRange text_to_text_range(text_position2->Clone(),
+                                       text_position1->Clone());
+  text_to_text_range = text_to_text_range.AsForwardRange();
+  EXPECT_EQ(*text_position1, *text_to_text_range.anchor());
+  EXPECT_EQ(*text_position2, *text_to_text_range.focus());
+}
+
+TEST_F(AXRangeTest, IsCollapsed) {
+  TestPositionRange null_range(AXNodePosition::CreateNullPosition(),
+                               AXNodePosition::CreateNullPosition());
+  null_range = null_range.AsForwardRange();
+  EXPECT_FALSE(null_range.IsCollapsed());
+
+  TestPositionInstance tree_position1 = AXNodePosition::CreateTreePosition(
+      tree_->data().tree_id, text_field_.id, 0 /* child_index */);
+  // Since there are no children in inline_box1_, the following is essentially
+  // an "after text" position which should not compare as equivalent to the
+  // above tree position which is a "before text" position inside the text
+  // field.
+  TestPositionInstance tree_position2 = AXNodePosition::CreateTreePosition(
+      tree_->data().tree_id, inline_box1_.id, 0 /* child_index */);
+
+  TestPositionInstance text_position1 = AXNodePosition::CreateTextPosition(
+      tree_->data().tree_id, static_text1_.id, 0 /* text_offset */,
+      ax::mojom::TextAffinity::kDownstream);
+  TestPositionInstance text_position2 = AXNodePosition::CreateTextPosition(
+      tree_->data().tree_id, inline_box1_.id, 0 /* text_offset */,
+      ax::mojom::TextAffinity::kDownstream);
+  TestPositionInstance text_position3 = AXNodePosition::CreateTextPosition(
+      tree_->data().tree_id, inline_box2_.id, 1 /* text_offset */,
+      ax::mojom::TextAffinity::kDownstream);
+
+  TestPositionRange tree_to_null_range(tree_position1->Clone(),
+                                       AXNodePosition::CreateNullPosition());
+  EXPECT_TRUE(tree_to_null_range.IsNull());
+  EXPECT_FALSE(tree_to_null_range.IsCollapsed());
+
+  TestPositionRange null_to_text_range(AXNodePosition::CreateNullPosition(),
+                                       text_position1->Clone());
+  EXPECT_TRUE(null_to_text_range.IsNull());
+  EXPECT_FALSE(null_to_text_range.IsCollapsed());
+
+  TestPositionRange tree_to_tree_range(tree_position2->Clone(),
+                                       tree_position1->Clone());
+  EXPECT_TRUE(tree_to_tree_range.IsCollapsed());
+
+  // A tree and a text position that essentially point to the same text offset
+  // are equivalent, even if they are anchored to a different node.
+  TestPositionRange tree_to_text_range(tree_position1->Clone(),
+                                       text_position1->Clone());
+  EXPECT_TRUE(tree_to_text_range.IsCollapsed());
+
+  // The following positions are not equivalent since tree_position2 is an
+  // "after text" position.
+  tree_to_text_range =
+      TestPositionRange(tree_position2->Clone(), text_position2->Clone());
+  EXPECT_FALSE(tree_to_text_range.IsCollapsed());
+
+  TestPositionRange text_to_text_range(text_position1->Clone(),
+                                       text_position1->Clone());
+  EXPECT_TRUE(text_to_text_range.IsCollapsed());
+
+  // Two text positions that essentially point to the same text offset are
+  // equivalent, even if they are anchored to a different node.
+  text_to_text_range =
+      TestPositionRange(text_position1->Clone(), text_position2->Clone());
+  EXPECT_TRUE(text_to_text_range.IsCollapsed());
+
+  text_to_text_range =
+      TestPositionRange(text_position1->Clone(), text_position3->Clone());
+  EXPECT_FALSE(text_to_text_range.IsCollapsed());
+}
+
 TEST_F(AXRangeTest, BeginAndEndIterators) {
   TestPositionInstance null_position = AXNodePosition::CreateNullPosition();
   TestPositionInstance test_position1 = AXNodePosition::CreateTextPosition(
diff --git a/ui/accessibility/ax_tree_unittest.cc b/ui/accessibility/ax_tree_unittest.cc
index 644722b..1244a46 100644
--- a/ui/accessibility/ax_tree_unittest.cc
+++ b/ui/accessibility/ax_tree_unittest.cc
@@ -674,9 +674,9 @@
   AXTree tree(initial_state);
 
   // Index in parent correct.
-  EXPECT_EQ(tree.GetFromId(2)->GetUnignoredIndexInParent(), (size_t)0);
-  EXPECT_EQ(tree.GetFromId(3)->GetUnignoredIndexInParent(), (size_t)1);
-  EXPECT_EQ(tree.GetFromId(4)->GetUnignoredIndexInParent(), (size_t)2);
+  EXPECT_EQ(0U, tree.GetFromId(2)->GetUnignoredIndexInParent());
+  EXPECT_EQ(1U, tree.GetFromId(3)->GetUnignoredIndexInParent());
+  EXPECT_EQ(2U, tree.GetFromId(4)->GetUnignoredIndexInParent());
 
   // Perform an update where we reorder children to [ 4 3 2 ]
   AXTreeUpdate update;
@@ -694,9 +694,73 @@
   ASSERT_TRUE(tree.Unserialize(update));
 
   // Index in parent should have changed as well.
-  EXPECT_EQ((size_t)0, tree.GetFromId(4)->GetUnignoredIndexInParent());
-  EXPECT_EQ((size_t)1, tree.GetFromId(3)->GetUnignoredIndexInParent());
-  EXPECT_EQ((size_t)2, tree.GetFromId(2)->GetUnignoredIndexInParent());
+  EXPECT_EQ(0U, tree.GetFromId(4)->GetUnignoredIndexInParent());
+  EXPECT_EQ(1U, tree.GetFromId(3)->GetUnignoredIndexInParent());
+  EXPECT_EQ(2U, tree.GetFromId(2)->GetUnignoredIndexInParent());
+}
+
+TEST(AXTreeTest, IndexInParentAfterReorderIgnoredNode) {
+  // This test covers another case where an AXTreeUpdate includes
+  // reordered children.  If one of the reordered nodes is ignored, its
+  // children's unignored index in parent should also be updated.
+
+  // Setup initial tree state.
+  // Tree:
+  //        1
+  //    2   3i  4
+  //       5  6
+  AXTreeUpdate initial_state;
+  initial_state.root_id = 1;
+  initial_state.nodes.resize(6);
+  initial_state.nodes[0].id = 1;
+  initial_state.nodes[0].child_ids.resize(3);
+  initial_state.nodes[0].child_ids[0] = 2;
+  initial_state.nodes[0].child_ids[1] = 3;
+  initial_state.nodes[0].child_ids[2] = 4;
+  initial_state.nodes[1].id = 2;
+  initial_state.nodes[2].id = 3;
+  initial_state.nodes[2].AddState(ax::mojom::State::kIgnored);
+  initial_state.nodes[2].child_ids.resize(2);
+  initial_state.nodes[2].child_ids[0] = 5;
+  initial_state.nodes[2].child_ids[1] = 6;
+  initial_state.nodes[3].id = 4;
+  initial_state.nodes[4].id = 5;
+  initial_state.nodes[5].id = 6;
+  AXTree tree(initial_state);
+
+  // Index in parent correct.
+  EXPECT_EQ(0U, tree.GetFromId(2)->GetUnignoredIndexInParent());
+  EXPECT_EQ(1U, tree.GetFromId(5)->GetUnignoredIndexInParent());
+  EXPECT_EQ(2U, tree.GetFromId(6)->GetUnignoredIndexInParent());
+  EXPECT_EQ(3U, tree.GetFromId(4)->GetUnignoredIndexInParent());
+
+  // Perform an update where we reorder children to [ 3i 2 4 ]. The
+  // unignored index in parent for the children of the ignored node (3) should
+  // be updated.
+  AXTreeUpdate update;
+  update.root_id = 1;
+  update.nodes.resize(6);
+  update.nodes[0].id = 1;
+  update.nodes[0].child_ids.resize(3);
+  update.nodes[0].child_ids[0] = 3;
+  update.nodes[0].child_ids[1] = 2;
+  update.nodes[0].child_ids[2] = 4;
+  update.nodes[1].id = 2;
+  update.nodes[2].id = 3;
+  update.nodes[2].AddState(ax::mojom::State::kIgnored);
+  update.nodes[2].child_ids.resize(2);
+  update.nodes[2].child_ids[0] = 5;
+  update.nodes[2].child_ids[1] = 6;
+  update.nodes[3].id = 4;
+  update.nodes[4].id = 5;
+  update.nodes[5].id = 6;
+
+  ASSERT_TRUE(tree.Unserialize(update));
+
+  EXPECT_EQ(2U, tree.GetFromId(2)->GetUnignoredIndexInParent());
+  EXPECT_EQ(0U, tree.GetFromId(5)->GetUnignoredIndexInParent());
+  EXPECT_EQ(1U, tree.GetFromId(6)->GetUnignoredIndexInParent());
+  EXPECT_EQ(3U, tree.GetFromId(4)->GetUnignoredIndexInParent());
 }
 
 TEST(AXTreeTest, ImplicitAttributeDelete) {
diff --git a/ui/gfx/canvas.cc b/ui/gfx/canvas.cc
index b65334e..955bbba 100644
--- a/ui/gfx/canvas.cc
+++ b/ui/gfx/canvas.cc
@@ -168,10 +168,6 @@
   canvas_->clipPath(path, SkClipOp::kIntersect, do_anti_alias);
 }
 
-bool Canvas::IsClipEmpty() const {
-  return canvas_->isClipEmpty();
-}
-
 bool Canvas::GetClipBounds(Rect* bounds) {
   SkRect out;
   if (canvas_->getLocalClipBounds(&out)) {
diff --git a/ui/gfx/canvas.h b/ui/gfx/canvas.h
index a5273e1..87504bf5 100644
--- a/ui/gfx/canvas.h
+++ b/ui/gfx/canvas.h
@@ -190,9 +190,6 @@
   // should be antialiased.
   void ClipPath(const SkPath& path, bool do_anti_alias);
 
-  // Returns true if the current clip is empty.
-  bool IsClipEmpty() const;
-
   // Returns the bounds of the current clip (in local coordinates) in the
   // |bounds| parameter, and returns true if it is non empty.
   bool GetClipBounds(Rect* bounds);
diff --git a/ui/ozone/platform/drm/gpu/drm_thread.cc b/ui/ozone/platform/drm/gpu/drm_thread.cc
index e941c850..43be05a 100644
--- a/ui/ozone/platform/drm/gpu/drm_thread.cc
+++ b/ui/ozone/platform/drm/gpu/drm_thread.cc
@@ -48,7 +48,7 @@
              GBM_BO_USE_TEXTURING;
       break;
     case gfx::BufferUsage::CAMERA_AND_CPU_READ_WRITE:
-      return GBM_BO_USE_LINEAR | GBM_BO_USE_CAMERA_WRITE | GBM_BO_USE_TEXTURING;
+      return GBM_BO_USE_LINEAR | GBM_BO_USE_CAMERA_WRITE;
     case gfx::BufferUsage::SCANOUT_CPU_READ_WRITE:
       return GBM_BO_USE_LINEAR | GBM_BO_USE_SCANOUT | GBM_BO_USE_TEXTURING;
     case gfx::BufferUsage::SCANOUT_VDA_WRITE:
diff --git a/ui/views/controls/button/label_button.cc b/ui/views/controls/button/label_button.cc
index 8a5c31c..dd05976 100644
--- a/ui/views/controls/button/label_button.cc
+++ b/ui/views/controls/button/label_button.cc
@@ -74,6 +74,16 @@
   SetTextInternal(text);
 }
 
+void LabelButton::ShrinkDownThenClearText() {
+  if (GetText().empty())
+    return;
+  // First, we recalculate preferred size for the new mode (without the label).
+  shrinking_down_label_ = true;
+  PreferredSizeChanged();
+  // Second, we clear the label right away if the button is already small.
+  ClearTextIfShrunkDown();
+}
+
 void LabelButton::SetTextColor(ButtonState for_state, SkColor color) {
   button_state_colors_[for_state] = color;
   if (for_state == STATE_DISABLED)
@@ -178,16 +188,26 @@
   ResetCachedPreferredSize();
 }
 
+void LabelButton::OnBoundsChanged(const gfx::Rect& previous_bounds) {
+  ClearTextIfShrunkDown();
+  Button::OnBoundsChanged(previous_bounds);
+}
+
 gfx::Size LabelButton::CalculatePreferredSize() const {
   // Cache the computed size, as recomputing it is an expensive operation.
   if (!cached_preferred_size_) {
-    const gfx::Size preferred_label_size = label_->GetPreferredSize();
     gfx::Size size = GetUnclampedSizeWithoutLabel();
-    size.Enlarge(preferred_label_size.width(), 0);
 
-    // Increase the height of the label (with insets) if larger.
-    size.set_height(std::max(
-        preferred_label_size.height() + GetInsets().height(), size.height()));
+    // Disregard label in the preferred size if the button is shrinking down to
+    // show no label soon.
+    if (!shrinking_down_label_) {
+      const gfx::Size preferred_label_size = label_->GetPreferredSize();
+      size.Enlarge(preferred_label_size.width(), 0);
+
+      // Increase the height of the label (with insets) if larger.
+      size.set_height(std::max(
+          preferred_label_size.height() + GetInsets().height(), size.height()));
+    }
 
     size.SetToMax(GetMinSize());
 
@@ -475,11 +495,30 @@
 void LabelButton::SetTextInternal(const base::string16& text) {
   SetAccessibleName(text);
   label_->SetText(text);
+
+  // Setting text cancels ShrinkDownThenClearText().
+  if (shrinking_down_label_) {
+    shrinking_down_label_ = false;
+    PreferredSizeChanged();
+  }
+
   // TODO(pkasting): Remove this and forward callback subscriptions to the
   // underlying label property when Label is converted to properties.
   OnPropertyChanged(label_, kPropertyEffectsNone);
 }
 
+void LabelButton::ClearTextIfShrunkDown() {
+  if (!cached_preferred_size_)
+    CalculatePreferredSize();
+  if (shrinking_down_label_ && width() <= cached_preferred_size_->width() &&
+      height() <= cached_preferred_size_->height()) {
+    // Once the button shrinks down to its preferred size (that disregards the
+    // current text), we finish the operation by clearing the text.
+    shrinking_down_label_ = false;
+    SetTextInternal(base::string16());
+  }
+}
+
 void LabelButton::ResetCachedPreferredSize() {
   cached_preferred_size_ = base::nullopt;
 }
diff --git a/ui/views/controls/button/label_button.h b/ui/views/controls/button/label_button.h
index 2162f9e..cac6b57 100644
--- a/ui/views/controls/button/label_button.h
+++ b/ui/views/controls/button/label_button.h
@@ -48,6 +48,15 @@
   base::string16 GetText() const;
   virtual void SetText(const base::string16& text);
 
+  // Makes the button report its preferred size without the label. This lets
+  // AnimatingLayoutManager gradually shrink the button until the text is
+  // invisible, at which point the text gets cleared. Think of this as
+  // transitioning from the current text to SetText("").
+  // Note that the layout manager (or manual SetBounds calls) need to be
+  // configured to eventually hit the the button's preferred size (or smaller)
+  // or the text will never be cleared.
+  void ShrinkDownThenClearText();
+
   // Sets the text color shown for the specified button |for_state| to |color|.
   void SetTextColor(ButtonState for_state, SkColor color);
 
@@ -88,6 +97,7 @@
 
   // Button:
   void SetBorder(std::unique_ptr<Border> border) override;
+  void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
   gfx::Size CalculatePreferredSize() const override;
   int GetHeightForWidth(int w) const override;
   void Layout() override;
@@ -157,6 +167,8 @@
  private:
   void SetTextInternal(const base::string16& text);
 
+  void ClearTextIfShrunkDown();
+
   // Resets |cached_preferred_size_|.
   void ResetCachedPreferredSize();
 
@@ -202,6 +214,11 @@
   // Cache the last computed preferred size.
   mutable base::Optional<gfx::Size> cached_preferred_size_;
 
+  // A flag indicating that this button should not include the label in its
+  // desired size. Furthermore, once the bounds of the button adapt to this
+  // desired size, the text in the label should get cleared.
+  bool shrinking_down_label_ = false;
+
   // Flag indicating default handling of the return key via an accelerator.
   // Whether or not the button appears or behaves as the default button in its
   // current context;
diff --git a/ui/views/controls/button/label_button_unittest.cc b/ui/views/controls/button/label_button_unittest.cc
index 0e8d81e..a4c789c 100644
--- a/ui/views/controls/button/label_button_unittest.cc
+++ b/ui/views/controls/button/label_button_unittest.cc
@@ -172,6 +172,92 @@
             gfx::Size(long_text_width, font_list.GetHeight() * 2));
 }
 
+TEST_F(LabelButtonTest, LabelShrinkDown) {
+  ASSERT_TRUE(button_->GetText().empty());
+
+  const gfx::FontList font_list = button_->label()->font_list();
+  const base::string16 text(ASCIIToUTF16("abcdefghijklm"));
+  const int text_width = gfx::GetStringWidth(text, font_list);
+
+  ASSERT_LT(button_->GetPreferredSize().width(), text_width);
+  button_->SetText(text);
+  EXPECT_GT(button_->GetPreferredSize().width(), text_width);
+  button_->SetSize(button_->GetPreferredSize());
+
+  // When shrinking, the button should report again the size with no label
+  // (while keeping the label).
+  button_->ShrinkDownThenClearText();
+  EXPECT_EQ(button_->GetText(), text);
+  EXPECT_LT(button_->GetPreferredSize().width(), text_width);
+
+  // After the layout manager resizes the button to it's desired size, it's text
+  // should be empty again.
+  button_->SetSize(button_->GetPreferredSize());
+  EXPECT_TRUE(button_->GetText().empty());
+}
+
+TEST_F(LabelButtonTest, LabelShrinksDownOnManualSetBounds) {
+  ASSERT_TRUE(button_->GetText().empty());
+  ASSERT_GT(button_->GetPreferredSize().width(), 1);
+
+  const base::string16 text(ASCIIToUTF16("abcdefghijklm"));
+
+  button_->SetText(text);
+  EXPECT_EQ(button_->GetText(), text);
+  button_->SetSize(button_->GetPreferredSize());
+  button_->SetBoundsRect(gfx::Rect(button_->GetPreferredSize()));
+
+  button_->ShrinkDownThenClearText();
+
+  // Manually setting a smaller size should also clear text.
+  button_->SetBoundsRect(gfx::Rect(1, 1));
+  EXPECT_TRUE(button_->GetText().empty());
+}
+
+TEST_F(LabelButtonTest, LabelShrinksDownCanceledBySettingText) {
+  ASSERT_TRUE(button_->GetText().empty());
+
+  const gfx::FontList font_list = button_->label()->font_list();
+  const base::string16 text(ASCIIToUTF16("abcdefghijklm"));
+  const int text_width = gfx::GetStringWidth(text, font_list);
+
+  ASSERT_LT(button_->GetPreferredSize().width(), text_width);
+  button_->SetText(text);
+  EXPECT_GT(button_->GetPreferredSize().width(), text_width);
+  button_->SetBoundsRect(gfx::Rect(button_->GetPreferredSize()));
+
+  // When shrinking, the button should report again the size with no label
+  // (while keeping the label).
+  button_->ShrinkDownThenClearText();
+  EXPECT_EQ(button_->GetText(), text);
+  gfx::Size shrinking_size = button_->GetPreferredSize();
+  EXPECT_LT(shrinking_size.width(), text_width);
+
+  // When we SetText() again, the shrinking gets canceled.
+  button_->SetText(text);
+  EXPECT_GT(button_->GetPreferredSize().width(), text_width);
+
+  // Even if the layout manager resizes the button to it's size desired for
+  // shrinking, it's text does not get cleared and it still prefers having space
+  // for its label.
+  button_->SetSize(shrinking_size);
+  EXPECT_FALSE(button_->GetText().empty());
+  EXPECT_GT(button_->GetPreferredSize().width(), text_width);
+}
+
+TEST_F(
+    LabelButtonTest,
+    LabelShrinksDownImmediatelyIfAlreadySmallerThanPreferredSizeWithoutLabel) {
+  button_->SetBoundsRect(gfx::Rect(1, 1));
+  button_->SetText(ASCIIToUTF16("abcdefghijklm"));
+
+  // Shrinking the text down when it's already shrunk down (its size is smaller
+  // than preferred without label) should clear the text immediately.
+  EXPECT_FALSE(button_->GetText().empty());
+  button_->ShrinkDownThenClearText();
+  EXPECT_TRUE(button_->GetText().empty());
+}
+
 // Test behavior of View::GetAccessibleNodeData() for buttons when setting a
 // label.
 TEST_F(LabelButtonTest, AccessibleState) {
diff --git a/ui/views/controls/tabbed_pane/tabbed_pane.cc b/ui/views/controls/tabbed_pane/tabbed_pane.cc
index 65da8107..43f77bb 100644
--- a/ui/views/controls/tabbed_pane/tabbed_pane.cc
+++ b/ui/views/controls/tabbed_pane/tabbed_pane.cc
@@ -29,7 +29,9 @@
 #include "ui/views/controls/tabbed_pane/tabbed_pane_listener.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/fill_layout.h"
+#include "ui/views/layout/flex_layout.h"
 #include "ui/views/layout/layout_manager.h"
+#include "ui/views/view_class_properties.h"
 #include "ui/views/widget/widget.h"
 
 namespace views {
@@ -307,6 +309,80 @@
 
 TabStrip::~TabStrip() = default;
 
+void TabStrip::AnimationProgressed(const gfx::Animation* animation) {
+  SchedulePaint();
+}
+
+void TabStrip::AnimationEnded(const gfx::Animation* animation) {
+  if (animation == expand_animation_.get())
+    contract_animation_->Start();
+}
+
+void TabStrip::OnSelectedTabChanged(Tab* from_tab, Tab* to_tab) {
+  DCHECK(!from_tab->selected());
+  DCHECK(to_tab->selected());
+
+  if (GetOrientation() == TabbedPane::Orientation::kHorizontal) {
+    animating_from_ = gfx::Range(from_tab->GetMirroredX(),
+                                 from_tab->GetMirroredX() + from_tab->width());
+    animating_to_ = gfx::Range(to_tab->GetMirroredX(),
+                               to_tab->GetMirroredX() + to_tab->width());
+  } else {
+    animating_from_ = gfx::Range(from_tab->bounds().y(),
+                                 from_tab->bounds().y() + from_tab->height());
+    animating_to_ = gfx::Range(to_tab->bounds().y(),
+                               to_tab->bounds().y() + to_tab->height());
+  }
+
+  contract_animation_->Stop();
+  expand_animation_->Start();
+}
+
+Tab* TabStrip::GetSelectedTab() const {
+  size_t index = GetSelectedTabIndex();
+  return index == kNoSelectedTab ? nullptr : GetTabAtIndex(index);
+}
+
+Tab* TabStrip::GetTabAtDeltaFromSelected(int delta) const {
+  const size_t selected_tab_index = GetSelectedTabIndex();
+  DCHECK_NE(kNoSelectedTab, selected_tab_index);
+  const size_t num_children = children().size();
+  // Clamping |delta| here ensures that even a large negative |delta| will not
+  // cause the addition in the next statement to wrap below 0.
+  delta %= static_cast<int>(num_children);
+  return GetTabAtIndex((selected_tab_index + num_children + delta) %
+                       num_children);
+}
+
+Tab* TabStrip::GetTabAtIndex(size_t index) const {
+  DCHECK_LT(index, children().size());
+  return static_cast<Tab*>(children()[index]);
+}
+
+size_t TabStrip::GetSelectedTabIndex() const {
+  for (size_t i = 0; i < children().size(); ++i)
+    if (GetTabAtIndex(i)->selected())
+      return i;
+  return kNoSelectedTab;
+}
+
+TabbedPane::Orientation TabStrip::GetOrientation() const {
+  return orientation_;
+}
+
+TabbedPane::TabStripStyle TabStrip::GetStyle() const {
+  return style_;
+}
+
+gfx::Size TabStrip::CalculatePreferredSize() const {
+  // Tabstrips don't require any minimum space along their main axis, and can
+  // shrink all the way to zero size.  Only the cross axis thickness matters.
+  const gfx::Size size = GetLayoutManager()->GetPreferredSize(this);
+  return (GetOrientation() == TabbedPane::Orientation::kHorizontal)
+             ? gfx::Size(0, size.height())
+             : gfx::Size(size.width(), 0);
+}
+
 void TabStrip::OnPaintBorder(gfx::Canvas* canvas) {
   // Do not draw border line in kHighlight mode.
   if (GetStyle() == TabbedPane::TabStripStyle::kHighlight)
@@ -394,71 +470,6 @@
                         SK_AlphaOPAQUE));
 }
 
-void TabStrip::AnimationProgressed(const gfx::Animation* animation) {
-  SchedulePaint();
-}
-
-void TabStrip::AnimationEnded(const gfx::Animation* animation) {
-  if (animation == expand_animation_.get())
-    contract_animation_->Start();
-}
-
-void TabStrip::OnSelectedTabChanged(Tab* from_tab, Tab* to_tab) {
-  DCHECK(!from_tab->selected());
-  DCHECK(to_tab->selected());
-
-  if (GetOrientation() == TabbedPane::Orientation::kHorizontal) {
-    animating_from_ = gfx::Range(from_tab->GetMirroredX(),
-                                 from_tab->GetMirroredX() + from_tab->width());
-    animating_to_ = gfx::Range(to_tab->GetMirroredX(),
-                               to_tab->GetMirroredX() + to_tab->width());
-  } else {
-    animating_from_ = gfx::Range(from_tab->bounds().y(),
-                                 from_tab->bounds().y() + from_tab->height());
-    animating_to_ = gfx::Range(to_tab->bounds().y(),
-                               to_tab->bounds().y() + to_tab->height());
-  }
-
-  contract_animation_->Stop();
-  expand_animation_->Start();
-}
-
-Tab* TabStrip::GetSelectedTab() const {
-  size_t index = GetSelectedTabIndex();
-  return index == kNoSelectedTab ? nullptr : GetTabAtIndex(index);
-}
-
-Tab* TabStrip::GetTabAtDeltaFromSelected(int delta) const {
-  const size_t selected_tab_index = GetSelectedTabIndex();
-  DCHECK_NE(kNoSelectedTab, selected_tab_index);
-  const size_t num_children = children().size();
-  // Clamping |delta| here ensures that even a large negative |delta| will not
-  // cause the addition in the next statement to wrap below 0.
-  delta %= static_cast<int>(num_children);
-  return GetTabAtIndex((selected_tab_index + num_children + delta) %
-                       num_children);
-}
-
-Tab* TabStrip::GetTabAtIndex(size_t index) const {
-  DCHECK_LT(index, children().size());
-  return static_cast<Tab*>(children()[index]);
-}
-
-size_t TabStrip::GetSelectedTabIndex() const {
-  for (size_t i = 0; i < children().size(); ++i)
-    if (GetTabAtIndex(i)->selected())
-      return i;
-  return kNoSelectedTab;
-}
-
-TabbedPane::Orientation TabStrip::GetOrientation() const {
-  return orientation_;
-}
-
-TabbedPane::TabStripStyle TabStrip::GetStyle() const {
-  return style_;
-}
-
 DEFINE_ENUM_CONVERTERS(TabbedPane::Orientation,
                        {TabbedPane::Orientation::kHorizontal,
                         base::ASCIIToUTF16("HORIZONTAL")},
@@ -482,8 +493,16 @@
                        TabbedPane::TabStripStyle style) {
   DCHECK(orientation != TabbedPane::Orientation::kHorizontal ||
          style != TabbedPane::TabStripStyle::kHighlight);
+  auto* layout = SetLayoutManager(std::make_unique<views::FlexLayout>());
+  if (orientation == TabbedPane::Orientation::kHorizontal)
+    layout->SetOrientation(views::LayoutOrientation::kVertical);
   tab_strip_ = AddChildView(std::make_unique<TabStrip>(orientation, style));
   contents_ = AddChildView(std::make_unique<View>());
+  contents_->SetProperty(views::kFlexBehaviorKey,
+                         views::FlexSpecification::ForSizeRule(
+                             views::MinimumFlexSizeRule::kScaleToZero,
+                             views::MaximumFlexSizeRule::kUnbounded));
+  contents_->SetLayoutManager(std::make_unique<views::FillLayout>());
 }
 
 TabbedPane::~TabbedPane() = default;
@@ -546,17 +565,6 @@
     SelectTab(tab);
 }
 
-gfx::Size TabbedPane::CalculatePreferredSize() const {
-  gfx::Size size;
-  for (const View* child : contents_->children())
-    size.SetToMax(child->GetPreferredSize());
-  if (GetOrientation() == Orientation::kHorizontal)
-    size.Enlarge(0, tab_strip_->GetPreferredSize().height());
-  else
-    size.Enlarge(tab_strip_->GetPreferredSize().width(), 0);
-  return size;
-}
-
 TabbedPane::Orientation TabbedPane::GetOrientation() const {
   return tab_strip_->GetOrientation();
 }
@@ -584,21 +592,6 @@
   return true;
 }
 
-void TabbedPane::Layout() {
-  const gfx::Size size = tab_strip_->GetPreferredSize();
-  if (GetOrientation() == Orientation::kHorizontal) {
-    tab_strip_->SetBounds(0, 0, width(), size.height());
-    contents_->SetBounds(0, tab_strip_->bounds().bottom(), width(),
-                         std::max(0, height() - size.height()));
-  } else {
-    tab_strip_->SetBounds(0, 0, size.width(), height());
-    contents_->SetBounds(tab_strip_->bounds().width(), 0,
-                         std::max(0, width() - size.width()), height());
-  }
-  for (View* child : contents_->children())
-    child->SetSize(contents_->size());
-}
-
 void TabbedPane::ViewHierarchyChanged(
     const ViewHierarchyChangedDetails& details) {
   if (details.is_add) {
diff --git a/ui/views/controls/tabbed_pane/tabbed_pane.h b/ui/views/controls/tabbed_pane/tabbed_pane.h
index f48d440..5a565691 100644
--- a/ui/views/controls/tabbed_pane/tabbed_pane.h
+++ b/ui/views/controls/tabbed_pane/tabbed_pane.h
@@ -86,9 +86,6 @@
   // Selects |tab| (the tabstrip view, not its content) if it is valid.
   void SelectTab(Tab* tab);
 
-  // Overridden from View:
-  gfx::Size CalculatePreferredSize() const override;
-
   // Gets the orientation of the tab alignment.
   Orientation GetOrientation() const;
 
@@ -125,7 +122,6 @@
   bool MoveSelectionBy(int delta);
 
   // Overridden from View:
-  void Layout() override;
   void ViewHierarchyChanged(
       const ViewHierarchyChangedDetails& details) override;
   bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
@@ -207,10 +203,7 @@
            TabbedPane::TabStripStyle style);
   ~TabStrip() override;
 
-  // Overridden from View:
-  void OnPaintBorder(gfx::Canvas* canvas) override;
-
-  // Overridden from AnimationDelegate:
+  // AnimationDelegate:
   void AnimationProgressed(const gfx::Animation* animation) override;
   void AnimationEnded(const gfx::Animation* animation) override;
 
@@ -228,6 +221,11 @@
 
   TabbedPane::TabStripStyle GetStyle() const;
 
+ protected:
+  // View:
+  gfx::Size CalculatePreferredSize() const override;
+  void OnPaintBorder(gfx::Canvas* canvas) override;
+
  private:
   // The orientation of the tab alignment.
   const TabbedPane::Orientation orientation_;
diff --git a/ui/views/focus/focus_traversal_unittest.cc b/ui/views/focus/focus_traversal_unittest.cc
index 0664155..342532f 100644
--- a/ui/views/focus/focus_traversal_unittest.cc
+++ b/ui/views/focus/focus_traversal_unittest.cc
@@ -489,86 +489,90 @@
   y += 40;
 
   // Left bottom box with style checkboxes.
-  auto contents = std::make_unique<View>();
-  contents->SetBackground(CreateSolidBackground(SK_ColorWHITE));
+  auto tabbed_pane_contents = std::make_unique<View>();
+  tabbed_pane_contents->SetBackground(CreateSolidBackground(SK_ColorWHITE));
   cb = std::make_unique<Checkbox>(ASCIIToUTF16("Bold"));
-  cb_ptr = contents->AddChildView(std::move(cb));
+  cb_ptr = tabbed_pane_contents->AddChildView(std::move(cb));
   cb_ptr->SetBounds(10, 10, 50, 20);
   cb_ptr->SetID(BOLD_CHECKBOX_ID);
 
   cb = std::make_unique<Checkbox>(ASCIIToUTF16("Italic"));
-  cb_ptr = contents->AddChildView(std::move(cb));
+  cb_ptr = tabbed_pane_contents->AddChildView(std::move(cb));
   cb_ptr->SetBounds(70, 10, 50, 20);
   cb_ptr->SetID(ITALIC_CHECKBOX_ID);
 
   cb = std::make_unique<Checkbox>(ASCIIToUTF16("Underlined"));
-  cb_ptr = contents->AddChildView(std::move(cb));
+  cb_ptr = tabbed_pane_contents->AddChildView(std::move(cb));
   cb_ptr->SetBounds(130, 10, 70, 20);
   cb_ptr->SetID(UNDERLINED_CHECKBOX_ID);
 
   auto link = std::make_unique<Link>(ASCIIToUTF16("Help"));
-  auto* link_ptr = contents->AddChildView(std::move(link));
+  auto* link_ptr = tabbed_pane_contents->AddChildView(std::move(link));
   link_ptr->SetBounds(10, 35, 70, 10);
   link_ptr->SetID(STYLE_HELP_LINK_ID);
 
   text_field = std::make_unique<Textfield>();
-  text_field_ptr = contents->AddChildView(std::move(text_field));
+  text_field_ptr = tabbed_pane_contents->AddChildView(std::move(text_field));
   text_field_ptr->SetBounds(10, 50, 100, 20);
   text_field_ptr->SetID(STYLE_TEXT_EDIT_ID);
 
   auto style_tab = std::make_unique<TabbedPane>();
   style_tab_ = GetContentsView()->AddChildView(std::move(style_tab));
   style_tab_->SetBounds(10, y, 210, 100);
-  style_tab_->AddTab(ASCIIToUTF16("Style"), std::move(contents));
+  style_tab_->AddTab(ASCIIToUTF16("Style"), std::move(tabbed_pane_contents));
   style_tab_->GetSelectedTab()->SetID(STYLE_CONTAINER_ID);
   style_tab_->AddTab(ASCIIToUTF16("Other"), std::make_unique<View>());
 
   // Right bottom box with search.
-  contents = std::make_unique<View>();
-  contents->SetBackground(CreateSolidBackground(SK_ColorWHITE));
+  auto border_contents = std::make_unique<View>();
+  border_contents->SetBackground(CreateSolidBackground(SK_ColorWHITE));
   text_field = std::make_unique<Textfield>();
-  text_field_ptr = contents->AddChildView(std::move(text_field));
+  text_field_ptr = border_contents->AddChildView(std::move(text_field));
   text_field_ptr->SetBounds(10, 10, 100, 20);
   text_field_ptr->SetID(SEARCH_TEXTFIELD_ID);
 
   button = MdTextButton::Create(nullptr, ASCIIToUTF16("Search"));
   button->SetBounds(112, 5, 60, 30);
   button->SetID(SEARCH_BUTTON_ID);
-  contents->AddChildView(std::move(button));
+  border_contents->AddChildView(std::move(button));
 
   link = std::make_unique<Link>(ASCIIToUTF16("Help"));
   link->SetHorizontalAlignment(gfx::ALIGN_LEFT);
   link->SetID(HELP_LINK_ID);
-  link_ptr = contents->AddChildView(std::move(link));
+  link_ptr = border_contents->AddChildView(std::move(link));
   link_ptr->SetBounds(175, 10, 30, 20);
 
-  auto search_border_view = std::make_unique<BorderView>(contents.release());
+  auto search_border_view =
+      std::make_unique<BorderView>(border_contents.release());
   search_border_view->SetID(SEARCH_CONTAINER_ID);
-
   search_border_view_ =
       GetContentsView()->AddChildView(std::move(search_border_view));
   search_border_view_->SetBounds(300, y, 240, 50);
 
   y += 60;
 
-  contents = std::make_unique<View>();
-  contents->SetFocusBehavior(View::FocusBehavior::ALWAYS);
-  contents->SetBackground(CreateSolidBackground(SK_ColorBLUE));
-  contents->SetID(THUMBNAIL_CONTAINER_ID);
+  auto view_contents = std::make_unique<View>();
+  view_contents->SetFocusBehavior(View::FocusBehavior::ALWAYS);
+  view_contents->SetBackground(CreateSolidBackground(SK_ColorBLUE));
+  view_contents->SetID(THUMBNAIL_CONTAINER_ID);
   button = MdTextButton::Create(nullptr, ASCIIToUTF16("Star"));
   button->SetBounds(5, 5, 50, 30);
   button->SetID(THUMBNAIL_STAR_ID);
-  contents->AddChildView(std::move(button));
+  view_contents->AddChildView(std::move(button));
   button = MdTextButton::Create(nullptr, ASCIIToUTF16("SuperStar"));
   button->SetBounds(60, 5, 100, 30);
   button->SetID(THUMBNAIL_SUPER_STAR_ID);
-  contents->AddChildView(std::move(button));
+  view_contents->AddChildView(std::move(button));
 
-  auto* contents_ptr = GetContentsView()->AddChildView(std::move(contents));
+  auto* contents_ptr =
+      GetContentsView()->AddChildView(std::move(view_contents));
   contents_ptr->SetBounds(250, y, 200, 50);
   // We can only call RadioButton::SetChecked() on the radio-button is part of
   // the view hierarchy.
   radio_button_to_check->SetChecked(true);
+
+  // Perform any pending layouts.
+  GetWidget()->LayoutRootViewIfNecessary();
 }
 
 TEST_F(FocusTraversalTest, NormalTraversal) {
diff --git a/ui/views/layout/flex_layout.cc b/ui/views/layout/flex_layout.cc
index 11286efc..a8215e3b 100644
--- a/ui/views/layout/flex_layout.cc
+++ b/ui/views/layout/flex_layout.cc
@@ -421,8 +421,7 @@
 
       // Keep track of non-hidden flex controls.
       const bool can_flex =
-          (flex_child.flex.weight() > 0 &&
-           flex_child.preferred_size.main() > 0) ||
+          flex_child.flex.weight() > 0 ||
           flex_child.current_size.main() < flex_child.preferred_size.main();
       if (can_flex)
         (*flex_order_to_index)[flex_child.flex.order()].push_back(view_index);