diff --git a/DEPS b/DEPS
index fa07614..b156b87 100644
--- a/DEPS
+++ b/DEPS
@@ -145,11 +145,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': '5e2c489a335cc52155f983cc065565681e476d1f',
+  'skia_revision': 'f75996469d02b1bfba8b246c526a6d06233ced44',
   # 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': '83ed30595d74cd1ea3f4396984df34e8987669cc',
+  'v8_revision': '4b08436ce71ecb074e9fb7493567cfbb04ccafb0',
   # 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.
@@ -157,7 +157,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': '2251102112312a9762898ce785afce6adc4f5ca3',
+  'angle_revision': 'b3eeb2a403548bc44fc605c051b622081de42410',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -165,7 +165,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '5e97d0125fd968b043ce7e39e7a6409595343234',
+  'pdfium_revision': 'f2095928371177683ee4e1a746f43633a43c303e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -208,7 +208,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '772d5c6161c59cc8a2815d7c096b4818e06c1d17',
+  'catapult_revision': '942e493326d11faffa51617ad07a82831f9408fe',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -276,11 +276,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'shaderc_revision': 'b3b228c60d635b44b0f2035cfb3ac31cf5567120',
+  'shaderc_revision': '90c00916229f6643428c4268010523f9addc460c',
   # 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': '35670f183a730beb8e11aecf75272053560b0ac3',
+  'dawn_revision': '2fb628da46f1af9c0155e08c36d00ac63612c569',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -814,7 +814,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '811aead064fba1e209195aa5830eb00b1c19ad1b',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '14ef7d57c13dd54b9403eb4be300ab4cf5e5cac5',
       'condition': 'checkout_linux',
   },
 
@@ -839,7 +839,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'e765f652958c26fb12f5843b9160b15c7adad347',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '9185e4495d6d17e1ee27313fffdaaf6ca50060ca',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1212,7 +1212,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '5c7d9733468d518942b2cbfe471999c403503c39',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '565082dac7842caf6aed931243439d5cdf679265',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1380,7 +1380,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'abaae129d9a0c6e1e092067e0b105475df43352e',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '01525f9e03384601605ccaa5603481f1de860444',
+    Var('webrtc_git') + '/src.git' + '@' + '7c6f74ab0344e9c6201de711d54026e9990b8e6c',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1421,7 +1421,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@f9fbd0f9b5e93d2a36984ca8e0328e436d8b576d',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@283aa6a07c39b0faf937b73d23376510c2afc487',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/browser/gfx/BUILD.gn b/android_webview/browser/gfx/BUILD.gn
index 3bd4d690..3e4ac5a 100644
--- a/android_webview/browser/gfx/BUILD.gn
+++ b/android_webview/browser/gfx/BUILD.gn
@@ -42,6 +42,10 @@
     "parent_output_surface.h",
     "render_thread_manager.cc",
     "render_thread_manager.h",
+    "root_frame_sink.cc",
+    "root_frame_sink.h",
+    "root_frame_sink_proxy.cc",
+    "root_frame_sink_proxy.h",
     "scoped_app_gl_state_restore.cc",
     "scoped_app_gl_state_restore.h",
     "skia_output_surface_dependency_webview.cc",
diff --git a/android_webview/browser/gfx/browser_view_renderer.cc b/android_webview/browser/gfx/browser_view_renderer.cc
index 20ab24cf..7d2686a 100644
--- a/android_webview/browser/gfx/browser_view_renderer.cc
+++ b/android_webview/browser/gfx/browser_view_renderer.cc
@@ -7,8 +7,11 @@
 #include <memory>
 #include <utility>
 
+#include "android_webview/browser/aw_feature_list.h"
 #include "android_webview/browser/gfx/browser_view_renderer_client.h"
 #include "android_webview/browser/gfx/compositor_frame_consumer.h"
+#include "android_webview/browser/gfx/root_frame_sink.h"
+#include "android_webview/browser/gfx/root_frame_sink_proxy.h"
 #include "base/auto_reset.h"
 #include "base/command_line.h"
 #include "base/logging.h"
@@ -110,7 +113,14 @@
       on_new_picture_enable_(false),
       clear_view_(false),
       offscreen_pre_raster_(false),
-      weak_ptr_factory_(this) {}
+      weak_ptr_factory_(this) {
+  if (base::FeatureList::IsEnabled(features::kVizForWebView)) {
+    root_frame_sink_proxy_ = std::make_unique<RootFrameSinkProxy>(
+        ui_task_runner_,
+        base::BindRepeating(&BrowserViewRenderer::SetNeedsBeginFrames,
+                            base::Unretained(this)));
+  }
+}
 
 BrowserViewRenderer::~BrowserViewRenderer() {
   DCHECK(compositor_map_.empty());
@@ -550,6 +560,8 @@
   // througout its lifetime.
   DCHECK(compositor_map_.count(frame_sink_id) == 0);
   compositor_map_[frame_sink_id] = compositor;
+  if (root_frame_sink_proxy_)
+    root_frame_sink_proxy_->AddChildFrameSinkId(frame_sink_id);
 
   // At this point, the RVHChanged event for the new RVH that contains the
   // |compositor| might have been fired already, in which case just set the
@@ -570,6 +582,8 @@
     copy_requests_.clear();
   }
 
+  if (root_frame_sink_proxy_)
+    root_frame_sink_proxy_->RemoveChildFrameSinkId(frame_sink_id);
   compositor_map_.erase(frame_sink_id);
 }
 
@@ -821,6 +835,10 @@
   PostInvalidate(compositor_);
 }
 
+void BrowserViewRenderer::SetNeedsBeginFrames(bool needs_begin_frames) {
+  NOTIMPLEMENTED();
+}
+
 void BrowserViewRenderer::PostInvalidate(
     content::SynchronousCompositor* compositor) {
   TRACE_EVENT_INSTANT0("android_webview", "BrowserViewRenderer::PostInvalidate",
diff --git a/android_webview/browser/gfx/browser_view_renderer.h b/android_webview/browser/gfx/browser_view_renderer.h
index a63747c..e64f4a3 100644
--- a/android_webview/browser/gfx/browser_view_renderer.h
+++ b/android_webview/browser/gfx/browser_view_renderer.h
@@ -39,6 +39,7 @@
 class BrowserViewRendererClient;
 class ChildFrame;
 class CompositorFrameConsumer;
+class RootFrameSinkProxy;
 
 // Interface for all the WebView-specific content rendering operations.
 // Provides software and hardware rendering and the Capture Picture API.
@@ -181,6 +182,7 @@
       CompositorFrameConsumer* compositor_frame_consumer);
   void ReleaseHardware();
   bool DoUpdateParentDrawData();
+  void SetNeedsBeginFrames(bool needs_begin_frames);
 
   gfx::Vector2d max_scroll_offset() const;
 
@@ -196,6 +198,7 @@
   BrowserViewRendererClient* const client_;
   const scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
   CompositorFrameConsumer* current_compositor_frame_consumer_;
+  std::unique_ptr<RootFrameSinkProxy> root_frame_sink_proxy_;
 
   // The current compositor that's owned by the current RVH.
   content::SynchronousCompositor* compositor_;
diff --git a/android_webview/browser/gfx/root_frame_sink.cc b/android_webview/browser/gfx/root_frame_sink.cc
new file mode 100644
index 0000000..3dcc588
--- /dev/null
+++ b/android_webview/browser/gfx/root_frame_sink.cc
@@ -0,0 +1,98 @@
+// 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 "android_webview/browser/gfx/root_frame_sink.h"
+
+#include "android_webview/browser/gfx/viz_compositor_thread_runner_webview.h"
+#include "base/no_destructor.h"
+#include "base/trace_event/trace_event.h"
+#include "components/viz/common/surfaces/frame_sink_id_allocator.h"
+#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
+#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+
+namespace android_webview {
+
+namespace {
+
+viz::FrameSinkId AllocateParentSinkId() {
+  static base::NoDestructor<viz::FrameSinkIdAllocator> allocator(0u);
+  return allocator->NextFrameSinkId();
+}
+
+}  // namespace
+
+RootFrameSink::RootFrameSink(SetNeedsBeginFrameCallback set_needs_begin_frame)
+    : root_frame_sink_id_(AllocateParentSinkId()),
+      set_needs_begin_frame_(set_needs_begin_frame) {
+  constexpr bool is_root = true;
+  constexpr bool needs_sync_points = true;
+  GetFrameSinkManager()->RegisterFrameSinkId(root_frame_sink_id_,
+                                             false /* report_activationa */);
+  support_ = std::make_unique<viz::CompositorFrameSinkSupport>(
+      this, GetFrameSinkManager(), root_frame_sink_id_, is_root,
+      needs_sync_points);
+  begin_frame_source_ = std::make_unique<viz::ExternalBeginFrameSource>(this);
+  GetFrameSinkManager()->RegisterBeginFrameSource(begin_frame_source_.get(),
+                                                  root_frame_sink_id_);
+}
+
+RootFrameSink::~RootFrameSink() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  GetFrameSinkManager()->UnregisterBeginFrameSource(begin_frame_source_.get());
+  begin_frame_source_.reset();
+  support_.reset();
+  GetFrameSinkManager()->InvalidateFrameSinkId(root_frame_sink_id_);
+}
+
+viz::FrameSinkManagerImpl* RootFrameSink::GetFrameSinkManager() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  // FrameSinkManagerImpl is global and not owned by this class, which is
+  // per-AwContents.
+  return VizCompositorThreadRunnerWebView::GetInstance()->GetFrameSinkManager();
+}
+
+void RootFrameSink::DidReceiveCompositorFrameAck(
+    const std::vector<viz::ReturnedResource>& resources) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  ReclaimResources(resources);
+}
+
+void RootFrameSink::ReclaimResources(
+    const std::vector<viz::ReturnedResource>& resources) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  // Root surface should have no resources to return.
+  CHECK(resources.empty());
+}
+
+void RootFrameSink::OnNeedsBeginFrames(bool needs_begin_frames) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  TRACE_EVENT_INSTANT1("android_webview", "RootFrameSink::OnNeedsBeginFrames",
+                       TRACE_EVENT_SCOPE_THREAD, "needs_begin_frames",
+                       needs_begin_frames);
+  needs_begin_frames_ = needs_begin_frames;
+  set_needs_begin_frame_.Run(needs_begin_frames);
+}
+
+void RootFrameSink::AddChildFrameSinkId(const viz::FrameSinkId& frame_sink_id) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  GetFrameSinkManager()->RegisterFrameSinkHierarchy(root_frame_sink_id_,
+                                                    frame_sink_id);
+}
+
+void RootFrameSink::RemoveChildFrameSinkId(
+    const viz::FrameSinkId& frame_sink_id) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  GetFrameSinkManager()->UnregisterFrameSinkHierarchy(root_frame_sink_id_,
+                                                      frame_sink_id);
+}
+
+bool RootFrameSink::BeginFrame(const viz::BeginFrameArgs& args) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  begin_frame_source_->OnBeginFrame(args);
+  // This is a hack and wrong. Remove this once we have proper frame submission
+  // tracking.
+  return needs_begin_frames_;
+}
+
+}  // namespace android_webview
diff --git a/android_webview/browser/gfx/root_frame_sink.h b/android_webview/browser/gfx/root_frame_sink.h
new file mode 100644
index 0000000..d08af70
--- /dev/null
+++ b/android_webview/browser/gfx/root_frame_sink.h
@@ -0,0 +1,77 @@
+// 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 ANDROID_WEBVIEW_BROWSER_GFX_ROOT_FRAME_SINK_H_
+#define ANDROID_WEBVIEW_BROWSER_GFX_ROOT_FRAME_SINK_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/threading/thread_checker.h"
+#include "components/viz/common/frame_sinks/begin_frame_source.h"
+#include "components/viz/common/frame_timing_details_map.h"
+#include "services/viz/public/mojom/compositing/compositor_frame_sink.mojom.h"
+
+namespace viz {
+class CompositorFrameSinkSupport;
+class FrameSinkManagerImpl;
+class ExternalBeginFrameSource;
+}  // namespace viz
+
+namespace android_webview {
+
+// This class holds per-AwContents classes on the viz thread that do not need
+// access to the GPU. It is single-threaded and refcounted on the viz thread.
+// This needs to be separate from classes for rendering which requires GPU
+// to enable sending begin frames independently from access to GPU.
+class RootFrameSink : public base::RefCounted<RootFrameSink>,
+                      public viz::mojom::CompositorFrameSinkClient,
+                      public viz::ExternalBeginFrameSourceClient {
+ public:
+  using SetNeedsBeginFrameCallback = base::RepeatingCallback<void(bool)>;
+  explicit RootFrameSink(SetNeedsBeginFrameCallback set_needs_begin_frame);
+
+  viz::CompositorFrameSinkSupport* support() const { return support_.get(); }
+  const viz::FrameSinkId& root_frame_sink_id() const {
+    return root_frame_sink_id_;
+  }
+  void AddChildFrameSinkId(const viz::FrameSinkId& frame_sink_id);
+  void RemoveChildFrameSinkId(const viz::FrameSinkId& frame_sink_id);
+  bool BeginFrame(const viz::BeginFrameArgs& args);
+
+  // viz::mojom::CompositorFrameSinkClient implementation.
+  void DidReceiveCompositorFrameAck(
+      const std::vector<viz::ReturnedResource>& resources) override;
+  void OnBeginFrame(const viz::BeginFrameArgs& args,
+                    const viz::FrameTimingDetailsMap& feedbacks) override {}
+  void OnBeginFramePausedChanged(bool paused) override {}
+  void ReclaimResources(
+      const std::vector<viz::ReturnedResource>& resources) override;
+
+  // viz::ExternalBeginFrameSourceClient overrides.
+  void OnNeedsBeginFrames(bool needs_begin_frames) override;
+
+ private:
+  friend class base::RefCounted<RootFrameSink>;
+  ~RootFrameSink() override;
+  viz::FrameSinkManagerImpl* GetFrameSinkManager();
+
+  const viz::FrameSinkId root_frame_sink_id_;
+  std::unique_ptr<viz::CompositorFrameSinkSupport> support_;
+  std::unique_ptr<viz::ExternalBeginFrameSource> begin_frame_source_;
+
+  bool needs_begin_frames_ = false;
+  SetNeedsBeginFrameCallback set_needs_begin_frame_;
+
+  THREAD_CHECKER(thread_checker_);
+
+  DISALLOW_COPY_AND_ASSIGN(RootFrameSink);
+};
+
+using RootFrameSinkGetter = base::OnceCallback<scoped_refptr<RootFrameSink>()>;
+
+}  // namespace android_webview
+
+#endif  // ANDROID_WEBVIEW_BROWSER_GFX_ROOT_FRAME_SINK_H_
diff --git a/android_webview/browser/gfx/root_frame_sink_proxy.cc b/android_webview/browser/gfx/root_frame_sink_proxy.cc
new file mode 100644
index 0000000..2d416b4
--- /dev/null
+++ b/android_webview/browser/gfx/root_frame_sink_proxy.cc
@@ -0,0 +1,123 @@
+// 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 "android_webview/browser/gfx/root_frame_sink_proxy.h"
+
+#include <utility>
+
+#include "android_webview/browser/gfx/root_frame_sink.h"
+#include "android_webview/browser/gfx/viz_compositor_thread_runner_webview.h"
+
+namespace android_webview {
+
+// static
+scoped_refptr<RootFrameSink> RootFrameSinkProxy::GetRootFrameSinkHelper(
+    base::WeakPtr<RootFrameSinkProxy> proxy) {
+  DCHECK(VizCompositorThreadRunnerWebView::GetInstance()
+             ->task_runner()
+             ->BelongsToCurrentThread());
+  if (proxy)
+    return proxy->without_gpu_;
+  return nullptr;
+}
+
+RootFrameSinkProxy::RootFrameSinkProxy(
+    const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner,
+    SetNeedsBeginFrameCallback set_needs_begin_frame_callback)
+    : ui_task_runner_(ui_task_runner),
+      viz_task_runner_(
+          VizCompositorThreadRunnerWebView::GetInstance()->task_runner()),
+      set_needs_begin_frame_callback_(
+          std::move(set_needs_begin_frame_callback)) {
+  DETACH_FROM_THREAD(viz_thread_checker_);
+  viz_task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&RootFrameSinkProxy::InitializeOnViz,
+                                base::Unretained(this)));
+}
+
+void RootFrameSinkProxy::InitializeOnViz() {
+  DCHECK_CALLED_ON_VALID_THREAD(viz_thread_checker_);
+  without_gpu_ = base::MakeRefCounted<RootFrameSink>(
+      base::BindRepeating(&RootFrameSinkProxy::SetNeedsBeginFramesOnViz,
+                          weak_ptr_factory_on_viz_.GetWeakPtr()));
+}
+
+RootFrameSinkProxy::~RootFrameSinkProxy() {
+  DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_);
+  VizCompositorThreadRunnerWebView::GetInstance()->PostTaskAndBlock(
+      FROM_HERE, base::BindOnce(&RootFrameSinkProxy::DestroyOnViz,
+                                base::Unretained(this)));
+}
+
+void RootFrameSinkProxy::DestroyOnViz() {
+  DCHECK_CALLED_ON_VALID_THREAD(viz_thread_checker_);
+  DCHECK(without_gpu_->HasOneRef());
+  without_gpu_.reset();
+  weak_ptr_factory_on_viz_.InvalidateWeakPtrs();
+}
+
+void RootFrameSinkProxy::SetNeedsBeginFramesOnViz(bool needs_begin_frames) {
+  DCHECK_CALLED_ON_VALID_THREAD(viz_thread_checker_);
+  ui_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&RootFrameSinkProxy::SetNeedsBeginFramesOnUI,
+                     weak_ptr_factory_.GetWeakPtr(), needs_begin_frames));
+}
+
+void RootFrameSinkProxy::SetNeedsBeginFramesOnUI(bool needs_begin_frames) {
+  DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_);
+  set_needs_begin_frame_callback_.Run(needs_begin_frames);
+}
+
+void RootFrameSinkProxy::AddChildFrameSinkId(
+    const viz::FrameSinkId& frame_sink_id) {
+  DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_);
+  viz_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&RootFrameSinkProxy::AddChildFrameSinkIdOnViz,
+                     weak_ptr_factory_on_viz_.GetWeakPtr(), frame_sink_id));
+}
+
+void RootFrameSinkProxy::AddChildFrameSinkIdOnViz(
+    const viz::FrameSinkId& frame_sink_id) {
+  DCHECK_CALLED_ON_VALID_THREAD(viz_thread_checker_);
+  without_gpu_->AddChildFrameSinkId(frame_sink_id);
+}
+
+void RootFrameSinkProxy::RemoveChildFrameSinkId(
+    const viz::FrameSinkId& frame_sink_id) {
+  DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_);
+  viz_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&RootFrameSinkProxy::RemoveChildFrameSinkIdOnViz,
+                     weak_ptr_factory_on_viz_.GetWeakPtr(), frame_sink_id));
+}
+
+void RootFrameSinkProxy::RemoveChildFrameSinkIdOnViz(
+    const viz::FrameSinkId& frame_sink_id) {
+  DCHECK_CALLED_ON_VALID_THREAD(viz_thread_checker_);
+  without_gpu_->RemoveChildFrameSinkId(frame_sink_id);
+}
+
+bool RootFrameSinkProxy::BeginFrame(const viz::BeginFrameArgs& args) {
+  DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_);
+  bool invalidate = false;
+  VizCompositorThreadRunnerWebView::GetInstance()->PostTaskAndBlock(
+      FROM_HERE, base::BindOnce(&RootFrameSinkProxy::BeginFrameOnViz,
+                                base::Unretained(this), args, &invalidate));
+  return invalidate;
+}
+
+void RootFrameSinkProxy::BeginFrameOnViz(const viz::BeginFrameArgs& args,
+                                         bool* invalidate) {
+  DCHECK_CALLED_ON_VALID_THREAD(viz_thread_checker_);
+  *invalidate = without_gpu_->BeginFrame(args);
+}
+
+RootFrameSinkGetter RootFrameSinkProxy::GetRootFrameSinkCallback() {
+  return base::BindOnce(&RootFrameSinkProxy::GetRootFrameSinkHelper,
+                        weak_ptr_factory_on_viz_.GetWeakPtr());
+}
+
+}  // namespace android_webview
diff --git a/android_webview/browser/gfx/root_frame_sink_proxy.h b/android_webview/browser/gfx/root_frame_sink_proxy.h
new file mode 100644
index 0000000..215daa0
--- /dev/null
+++ b/android_webview/browser/gfx/root_frame_sink_proxy.h
@@ -0,0 +1,64 @@
+// 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 ANDROID_WEBVIEW_BROWSER_GFX_ROOT_FRAME_SINK_PROXY_H_
+#define ANDROID_WEBVIEW_BROWSER_GFX_ROOT_FRAME_SINK_PROXY_H_
+
+#include "android_webview/browser/gfx/root_frame_sink.h"
+#include "base/macros.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_checker.h"
+
+namespace viz {
+struct BeginFrameArgs;
+}
+
+namespace android_webview {
+
+// Per-AwContents object. Straddles UI and Viz thread. Public methods should be
+// called on the UI thread unless otherwise specified. Mostly used for creating
+// RootFrameSink and routing calls to it.
+class RootFrameSinkProxy {
+ public:
+  using SetNeedsBeginFrameCallback = RootFrameSink::SetNeedsBeginFrameCallback;
+  RootFrameSinkProxy(
+      const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner,
+      SetNeedsBeginFrameCallback set_needs_begin_frame_callback);
+  ~RootFrameSinkProxy();
+
+  void AddChildFrameSinkId(const viz::FrameSinkId& frame_sink_id);
+  void RemoveChildFrameSinkId(const viz::FrameSinkId& frame_sink_id);
+  bool BeginFrame(const viz::BeginFrameArgs& args);
+  // The returned callback can only be called on viz thread.
+  RootFrameSinkGetter GetRootFrameSinkCallback();
+
+ private:
+  static scoped_refptr<RootFrameSink> GetRootFrameSinkHelper(
+      base::WeakPtr<RootFrameSinkProxy> proxy);
+
+  void InitializeOnViz();
+  void DestroyOnViz();
+  void AddChildFrameSinkIdOnViz(const viz::FrameSinkId& frame_sink_id);
+  void RemoveChildFrameSinkIdOnViz(const viz::FrameSinkId& frame_sink_id);
+  void BeginFrameOnViz(const viz::BeginFrameArgs& args, bool* invalidate);
+  void SetNeedsBeginFramesOnViz(bool needs_begin_frames);
+  void SetNeedsBeginFramesOnUI(bool needs_begin_frames);
+
+  const scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
+  const scoped_refptr<base::SingleThreadTaskRunner> viz_task_runner_;
+  SetNeedsBeginFrameCallback set_needs_begin_frame_callback_;
+  scoped_refptr<RootFrameSink> without_gpu_;
+
+  THREAD_CHECKER(ui_thread_checker_);
+  THREAD_CHECKER(viz_thread_checker_);
+
+  base::WeakPtrFactory<RootFrameSinkProxy> weak_ptr_factory_{this};
+  base::WeakPtrFactory<RootFrameSinkProxy> weak_ptr_factory_on_viz_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(RootFrameSinkProxy);
+};
+
+}  // namespace android_webview
+
+#endif  // ANDROID_WEBVIEW_BROWSER_GFX_ROOT_FRAME_SINK_PROXY_H_
diff --git a/android_webview/browser/gfx/viz_compositor_thread_runner_webview.cc b/android_webview/browser/gfx/viz_compositor_thread_runner_webview.cc
index 1d0f347..5965e1d0 100644
--- a/android_webview/browser/gfx/viz_compositor_thread_runner_webview.cc
+++ b/android_webview/browser/gfx/viz_compositor_thread_runner_webview.cc
@@ -7,19 +7,28 @@
 #include <utility>
 
 #include "android_webview/browser/gfx/task_queue_web_view.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/no_destructor.h"
+#include "base/synchronization/waitable_event.h"
 #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
 
 namespace android_webview {
 
 namespace {
+
 void RunAndDone(base::OnceClosure viz_task, base::OnceClosure done_task) {
   std::move(viz_task).Run();
 
   // |done_task| is provided by TaskQueueWebView unblocks the gpu service.
   std::move(done_task).Run();
 }
+
+void RunAndSignal(base::OnceClosure viz_task, base::WaitableEvent* done) {
+  std::move(viz_task).Run();
+  done->Signal();
+}
+
 }  // namespace
 
 // static
@@ -68,6 +77,15 @@
       base::BindOnce(&RunAndDone, std::move(task)));
 }
 
+void VizCompositorThreadRunnerWebView::PostTaskAndBlock(
+    const base::Location& from_here,
+    base::OnceClosure task) {
+  base::WaitableEvent e;
+  task_runner()->PostTask(from_here,
+                          base::BindOnce(&RunAndSignal, std::move(task), &e));
+  e.Wait();
+}
+
 VizCompositorThreadRunnerWebView::~VizCompositorThreadRunnerWebView() = default;
 
 base::SingleThreadTaskRunner* VizCompositorThreadRunnerWebView::task_runner() {
diff --git a/android_webview/browser/gfx/viz_compositor_thread_runner_webview.h b/android_webview/browser/gfx/viz_compositor_thread_runner_webview.h
index bb73240..b9e30549 100644
--- a/android_webview/browser/gfx/viz_compositor_thread_runner_webview.h
+++ b/android_webview/browser/gfx/viz_compositor_thread_runner_webview.h
@@ -12,6 +12,10 @@
 #include "base/threading/thread_checker.h"
 #include "components/viz/service/main/viz_compositor_thread_runner.h"
 
+namespace base {
+class Location;
+}  // namespace base
+
 namespace viz {
 class FrameSinkManagerImpl;
 }  // namespace viz
@@ -35,8 +39,16 @@
   static VizCompositorThreadRunnerWebView* GetInstance();
 
   viz::FrameSinkManagerImpl* GetFrameSinkManager();
+
+  // Must be called from the TaskQueueWebView thread. |task| is allowed to call
+  // TaskQueueWebView::ScheduleTask.
   void ScheduleOnVizAndBlock(base::OnceClosure task);
 
+  // Can be called from any thread, and blocks the caller until the task
+  // finishes executing.
+  void PostTaskAndBlock(const base::Location& from_here,
+                        base::OnceClosure task);
+
   // viz::VizCompositorThreadRunner overrides.
   base::SingleThreadTaskRunner* task_runner() override;
   void CreateFrameSinkManager(
diff --git a/ash/public/cpp/ash_features.cc b/ash/public/cpp/ash_features.cc
index 3b9d9f8..02d006d 100644
--- a/ash/public/cpp/ash_features.cc
+++ b/ash/public/cpp/ash_features.cc
@@ -67,9 +67,6 @@
 const base::Feature kUnlockWithExternalBinary{
     "UnlockWithExternalBinary", base::FEATURE_DISABLED_BY_DEFAULT};
 
-const base::Feature kKioskNextShell{"KioskNextShell",
-                                    base::FEATURE_ENABLED_BY_DEFAULT};
-
 const base::Feature kViewsLogin{"ViewsLogin", base::FEATURE_ENABLED_BY_DEFAULT};
 
 const base::Feature kVirtualDesks{"VirtualDesks",
diff --git a/ash/public/cpp/ash_features.h b/ash/public/cpp/ash_features.h
index 2c1b9391..d4e3451a 100644
--- a/ash/public/cpp/ash_features.h
+++ b/ash/public/cpp/ash_features.h
@@ -85,9 +85,6 @@
 // Enables running an external binary which provides lock screen authentication.
 ASH_PUBLIC_EXPORT extern const base::Feature kUnlockWithExternalBinary;
 
-// Enables the KioskNextShell feature.
-ASH_PUBLIC_EXPORT extern const base::Feature kKioskNextShell;
-
 // Enables views login.
 ASH_PUBLIC_EXPORT extern const base::Feature kViewsLogin;
 
diff --git a/base/process/process_posix.cc b/base/process/process_posix.cc
index 9636d44..589ee72 100644
--- a/base/process/process_posix.cc
+++ b/base/process/process_posix.cc
@@ -10,7 +10,6 @@
 #include <sys/resource.h>
 #include <sys/wait.h>
 
-#include "base/clang_coverage_buildflags.h"
 #include "base/debug/activity_tracker.h"
 #include "base/files/scoped_file.h"
 #include "base/logging.h"
@@ -23,9 +22,6 @@
 #include <sys/event.h>
 #endif
 
-#if BUILDFLAG(CLANG_COVERAGE)
-#include "base/test/clang_coverage.h"
-#endif
 
 namespace {
 
@@ -276,9 +272,6 @@
 
 // static
 void Process::TerminateCurrentProcessImmediately(int exit_code) {
-#if BUILDFLAG(CLANG_COVERAGE)
-  WriteClangCoverageProfile();
-#endif
   _exit(exit_code);
 }
 
diff --git a/build/android/apk_operations.py b/build/android/apk_operations.py
index 7395d2c..f9e509e 100755
--- a/build/android/apk_operations.py
+++ b/build/android/apk_operations.py
@@ -231,7 +231,7 @@
     # NOTE: For now, installation requires running 'bundletool install-apks'.
     # TODO(digit): Add proper support for bundles to devil instead, then use it.
     install_cmd_args = [
-        'install-apks', '--apks=' + bundle_apks,
+        'install-apks', '--apks=' + bundle_apks, '--allow-downgrade',
         '--adb=' + adb_wrapper.AdbWrapper.GetAdbPath(),
         '--device-id=' + device.serial
     ]
diff --git a/build/fuchsia/fidlgen_js/fidl.py b/build/fuchsia/fidlgen_js/fidl.py
index 6f8b99f..d66ba033 100644
--- a/build/fuchsia/fidlgen_js/fidl.py
+++ b/build/fuchsia/fidlgen_js/fidl.py
@@ -293,7 +293,7 @@
 
 
 class InterfaceMethod:
-    def __init__(self, has_request, has_response, maybe_attributes, maybe_request, maybe_request_alignment, maybe_request_size, maybe_response, maybe_response_alignment, maybe_response_size, name, ordinal):
+    def __init__(self, has_request, has_response, maybe_attributes, maybe_request, maybe_request_alignment, maybe_request_size, maybe_response, maybe_response_alignment, maybe_response_size, name, ordinal, generated_ordinal):
         self.has_request = has_request
         self.has_response = has_response
         self.maybe_attributes = maybe_attributes
@@ -305,6 +305,8 @@
         self.maybe_response_size = maybe_response_size
         self.name = name
         self.ordinal = ordinal
+        # TODO(https://crbug.com/991300): Remove once |ordinal| is 64-bit.
+        self.generated_ordinal = generated_ordinal
 
     @staticmethod
     def from_dict(obj):
@@ -320,7 +322,9 @@
         maybe_response_size = from_union([from_int, from_none], obj.get(u"maybe_response_size"))
         name = from_str(obj.get(u"name"))
         ordinal = from_int(obj.get(u"ordinal"))
-        return InterfaceMethod(has_request, has_response, maybe_attributes, maybe_request, maybe_request_alignment, maybe_request_size, maybe_response, maybe_response_alignment, maybe_response_size, name, ordinal)
+        # TODO(https://crbug.com/991300): Remove once |ordinal| is 64-bit.
+        generated_ordinal = from_int(obj.get(u"generated_ordinal"))
+        return InterfaceMethod(has_request, has_response, maybe_attributes, maybe_request, maybe_request_alignment, maybe_request_size, maybe_response, maybe_response_alignment, maybe_response_size, name, ordinal, generated_ordinal)
 
     def to_dict(self):
         result = {}
@@ -335,6 +339,8 @@
         result[u"maybe_response_size"] = from_union([from_int, from_none], self.maybe_response_size)
         result[u"name"] = from_str(self.name)
         result[u"ordinal"] = from_int(self.ordinal)
+        # TODO(https://crbug.com/991300): Remove once |ordinal| is 64-bit.
+        result[u"generated_ordinal"] = from_int(self.generated_ordinal)
         return result
 
 
@@ -546,4 +552,3 @@
 
 def fidl_to_dict(x):
     return to_class(Fidl, x)
-
diff --git a/build/fuchsia/fidlgen_js/gen.py b/build/fuchsia/fidlgen_js/gen.py
index 1425a8ed..0051019 100755
--- a/build/fuchsia/fidlgen_js/gen.py
+++ b/build/fuchsia/fidlgen_js/gen.py
@@ -221,11 +221,6 @@
                             '/' + name + '.' + member.name)
       javascript_name = name + '.' + member.name
       self.resolved_constant_name[fidl_constant_name] = javascript_name
-
-      # https://crbug.com/988195: Also map the legacy unqualified name.
-      legacy_fidl_constant_name = ('.'.join(compound.library) +
-                                   '/' + member.name)
-      self.resolved_constant_name[legacy_fidl_constant_name] = javascript_name
     self.f.write('};\n')
     self.f.write('const _kTT_%(name)s = _kTT_%(type)s;\n\n' % data)
 
@@ -527,10 +522,11 @@
     for method in interface.methods:
       method_name = _CompileIdentifier(method.name)
       self.f.write(
-          'const _k%(name)s_%(method_name)s_Ordinal = %(ordinal)s;\n' % {
+          'const _k%(name)s_%(method_name)s_Ordinal = %(ordinal)sn;\n' % {
               'name': name,
               'method_name': method_name,
-              'ordinal': method.ordinal
+              # TODO(https://crbug.com/991300): Use |ordinal| once it is 64-bit.
+              'ordinal': method.generated_ordinal
           })
 
     self.f.write('\n')
diff --git a/build/fuchsia/fidlgen_js/runtime/fidl.mjs b/build/fuchsia/fidlgen_js/runtime/fidl.mjs
index 9a3cfa2..d7ce381 100644
--- a/build/fuchsia/fidlgen_js/runtime/fidl.mjs
+++ b/build/fuchsia/fidlgen_js/runtime/fidl.mjs
@@ -27,6 +27,14 @@
                  $fidl__kAlignmentMask);
 }
 
+function $fidl__setUint64LE(dataView, offset, value) {
+  var high_bits = Number(BigInt.asUintN(32, value >> 32n))
+  var low_bits = Number(BigInt.asUintN(32, value))
+  dataView.setUint32(offset+0, high_bits, $fidl__kLE);
+  dataView.setUint32(offset+4, low_bits, $fidl__kLE);
+}
+
+
 /**
  * @constructor
  * @param {number} ordinal
@@ -46,7 +54,8 @@
   this.alloc($fidl_kMessageHeaderSize);
   var txid = has_response ? ($fidl__nextTxid++ & $fidl__kUserspaceTxidMask) : 0;
   this.data.setUint32($fidl_kMessageTxidOffset, txid, $fidl__kLE);
-  this.data.setUint32($fidl_kMessageOrdinalOffset, ordinal, $fidl__kLE);
+  $fidl__setUint64LE(
+      this.data, $fidl_kMessageOrdinalOffset, ordinal, $fidl__kLE);
 };
 
 /**
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 12ba1f1c..7bfe3fe 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8905231778037491328
\ No newline at end of file
+8905202830898033264
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 37a5393..246526a5 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-8905235025956967056
\ No newline at end of file
+8905202810180352016
\ No newline at end of file
diff --git a/chrome/VERSION b/chrome/VERSION
index c556447f..a0589add 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=78
 MINOR=0
-BUILD=3882
+BUILD=3883
 PATCH=0
diff --git a/chrome/android/chrome_junit_test_java_sources.gni b/chrome/android/chrome_junit_test_java_sources.gni
index d24cb70..f33325f 100644
--- a/chrome/android/chrome_junit_test_java_sources.gni
+++ b/chrome/android/chrome_junit_test_java_sources.gni
@@ -146,6 +146,7 @@
   "junit/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextTest.java",
   "junit/src/org/chromium/chrome/browser/omnibox/AutocompleteStateUnitTest.java",
   "junit/src/org/chromium/chrome/browser/omnibox/KeyboardHideHelperUnitTest.java",
+  "junit/src/org/chromium/chrome/browser/omnibox/SearchEngineLogoUtilsTest.java",
   "junit/src/org/chromium/chrome/browser/omnibox/SpannableAutocompleteEditTextModelUnitTest.java",
   "junit/src/org/chromium/chrome/browser/omnibox/UrlBarDataTest.java",
   "junit/src/org/chromium/chrome/browser/omnibox/UrlBarMediatorUnitTest.java",
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index 6285582..314373be 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -327,7 +327,9 @@
     <dimen name="omnibox_suggestion_refine_view_modern_end_padding">4dp</dimen>
 
     <!-- Adding search engine logo to the omnibox. -->
-    <dimen name="omnibox_search_engine_logo_favicon_size">24dp</dimen>
+    <!-- Max size which will fit completely in the composed/rounded bg. -->
+    <dimen name="omnibox_search_engine_logo_favicon_size">17dp</dimen>
+    <dimen name="omnibox_search_engine_logo_composed_size">24dp</dimen>
 
     <!-- NTP dimensions -->
     <dimen name="tile_grid_layout_max_width">504dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/feature_engagement/ScreenshotTabObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/feature_engagement/ScreenshotTabObserver.java
index 16035d7..0c63cc15 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/feature_engagement/ScreenshotTabObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/feature_engagement/ScreenshotTabObserver.java
@@ -41,7 +41,7 @@
      * @return ScreenshotTabObserver to use, or null if the tab was null.
      */
     public static ScreenshotTabObserver from(Tab tab) {
-        if (tab == null) return null;
+        if (tab == null || !tab.isInitialized()) return null;
         // Get the current observer from the tab using UserData, if any.  If not, create a new
         // observer and put it into the UserData for the tab.
         ScreenshotTabObserver observer = get(tab);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/SearchEngineLogoUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/SearchEngineLogoUtils.java
index 9040610..1c1ef4c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/SearchEngineLogoUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/SearchEngineLogoUtils.java
@@ -6,10 +6,13 @@
 
 import android.content.res.Resources;
 import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
 import android.support.annotation.Nullable;
 import android.text.TextUtils;
 
 import org.chromium.base.Callback;
+import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.favicon.FaviconHelper;
@@ -17,16 +20,27 @@
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.util.UrlUtilities;
+import org.chromium.chrome.browser.widget.RoundedIconGenerator;
+
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * Collection of shared code for displaying search engine logos.
  */
 public class SearchEngineLogoUtils {
+    private static final String ROUNDED_EDGES_VARIANT = "rounded_edges";
     private static final String DUMMY_URL_QUERY = "replace_me";
+
+    // Cache the logo and return it when the logo url that's cached matches the current logo url.
+    private static Bitmap sCachedComposedBackground;
+    private static String sCachedComposedBackgroundLogoUrl;
     private static FaviconHelper sFaviconHelper;
+    private static RoundedIconGenerator sRoundedIconGenerator;
 
     // Cache these values so they don't need to be recalculated.
     private static int sSearchEngineLogoTargetSizePixels;
+    private static int sSearchEngineLogoComposedSizePixels;
 
     /**
      * Encapsulates complicated boolean check for reuse and readability.
@@ -38,6 +52,13 @@
                 && ChromeFeatureList.isEnabled(ChromeFeatureList.OMNIBOX_SEARCH_ENGINE_LOGO);
     }
 
+    public static boolean shouldRoundedSearchEngineLogo() {
+        return ChromeFeatureList.isInitialized()
+                && ChromeFeatureList.isEnabled(ChromeFeatureList.OMNIBOX_SEARCH_ENGINE_LOGO)
+                && ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean(
+                        ChromeFeatureList.OMNIBOX_SEARCH_ENGINE_LOGO, ROUNDED_EDGES_VARIANT, false);
+    }
+
     /**
      * @return True if the search engine is Google.
      */
@@ -69,18 +90,36 @@
 
     /**
      * @param resources Android resources object, used to read the dimension.
-     * @return The size that the logo should be displayed as.
+     * @return The size that the logo favicon should be.
      */
     public static int getSearchEngineLogoSizePixels(Resources resources) {
         if (sSearchEngineLogoTargetSizePixels == 0) {
-            sSearchEngineLogoTargetSizePixels = resources.getDimensionPixelSize(
-                    R.dimen.omnibox_search_engine_logo_favicon_size);
+            if (shouldRoundedSearchEngineLogo()) {
+                sSearchEngineLogoTargetSizePixels = resources.getDimensionPixelSize(
+                        R.dimen.omnibox_search_engine_logo_favicon_size);
+            } else {
+                sSearchEngineLogoTargetSizePixels =
+                        getSearchEngineLogoComposedSizePixels(resources);
+            }
         }
 
         return sSearchEngineLogoTargetSizePixels;
     }
 
     /**
+     * @param resources Android resources object, used to read the dimension.
+     * @return The total size the logo will be on screen.
+     */
+    public static int getSearchEngineLogoComposedSizePixels(Resources resources) {
+        if (sSearchEngineLogoComposedSizePixels == 0) {
+            sSearchEngineLogoComposedSizePixels = resources.getDimensionPixelSize(
+                    R.dimen.omnibox_search_engine_logo_composed_size);
+        }
+
+        return sSearchEngineLogoComposedSizePixels;
+    }
+
+    /**
      * Get the search engine logo favicon. This can return a null bitmap under certain
      * circumstances, such as: no logo url found, network/cache error, etc.
      *
@@ -93,19 +132,120 @@
         if (sFaviconHelper == null) sFaviconHelper = new FaviconHelper();
 
         String logoUrl = getSearchLogoUrl();
-        if (logoUrl == null) callback.onResult(null);
+        if (logoUrl == null) {
+            callback.onResult(null);
+            return;
+        }
 
+        // Return a cached copy if it's available.
+        if (sCachedComposedBackground != null
+                && sCachedComposedBackgroundLogoUrl.equals(getSearchLogoUrl())) {
+            callback.onResult(sCachedComposedBackground);
+            return;
+        }
+
+        final int logoSizePixels = SearchEngineLogoUtils.getSearchEngineLogoSizePixels(resources);
         boolean willReturn = sFaviconHelper.getLocalFaviconImageForURL(
-                profile, logoUrl, getSearchEngineLogoSizePixels(resources), (image, iconUrl) -> {
+                profile, logoUrl, logoSizePixels, (image, iconUrl) -> {
                     if (image == null) {
                         callback.onResult(image);
                         return;
                     }
 
-                    callback.onResult(Bitmap.createScaledBitmap(image,
-                            SearchEngineLogoUtils.getSearchEngineLogoSizePixels(resources),
-                            SearchEngineLogoUtils.getSearchEngineLogoSizePixels(resources), true));
+                    processReturnedLogo(logoUrl, image, resources, callback);
                 });
         if (!willReturn) callback.onResult(null);
     }
+
+    /**
+     * Process the image returned from a network fetch or cache hit. This method processes the logo
+     * to make it eligible for display. The logo is resized to ensure it will fill the required
+     * size. This is done because the icon returned from native could be a different size. If the
+     * rounded edges variant is active, then a smaller icon is downloaded and drawn on top of a
+     * circle background. This looks better and also has more predictable behavior than rounding the
+     * edges of the full size icon. The circle background is a solid color made up of the result
+     * from a call to getMostCommonEdgeColor(...).
+     * @param logoUrl The url for the given logo.
+     * @param image The logo to process.
+     * @param resources Android resources object used to access dimensions.
+     * @param callback The client callback to receive the processed logo.
+     */
+    private static void processReturnedLogo(
+            String logoUrl, Bitmap image, Resources resources, Callback<Bitmap> callback) {
+        // Scale the logo up to the desired size.
+        int logoSizePixels = SearchEngineLogoUtils.getSearchEngineLogoSizePixels(resources);
+        Bitmap scaledIcon = Bitmap.createScaledBitmap(image,
+                SearchEngineLogoUtils.getSearchEngineLogoSizePixels(resources),
+                SearchEngineLogoUtils.getSearchEngineLogoSizePixels(resources), true);
+
+        Bitmap composedIcon = scaledIcon;
+        if (shouldRoundedSearchEngineLogo()) {
+            int composedSizePixels = getSearchEngineLogoComposedSizePixels(resources);
+            if (sRoundedIconGenerator == null) {
+                sRoundedIconGenerator = new RoundedIconGenerator(composedSizePixels,
+                        composedSizePixels, composedSizePixels, Color.TRANSPARENT, 0);
+            }
+            sRoundedIconGenerator.setBackgroundColor(getMostCommonEdgeColor(image));
+
+            // Generate a rounded background with no text.
+            composedIcon = sRoundedIconGenerator.generateIconForText("");
+            Canvas canvas = new Canvas(composedIcon);
+            // Draw the logo in the middle of the generated background.
+            int dx = (composedSizePixels - logoSizePixels) / 2;
+            canvas.drawBitmap(scaledIcon, dx, dx, null);
+        }
+        // Cache the result icon to reduce future work.
+        sCachedComposedBackground = composedIcon;
+        sCachedComposedBackgroundLogoUrl = logoUrl;
+
+        callback.onResult(sCachedComposedBackground);
+    }
+
+    /**
+     * Samples the edges of given bitmap and returns the most common color.
+     * @param icon Bitmap to be sampled.
+     */
+    @VisibleForTesting
+    static int getMostCommonEdgeColor(Bitmap icon) {
+        Map<Integer, Integer> colorCount = new HashMap<>();
+        for (int i = 0; i < icon.getWidth(); i++) {
+            // top edge
+            int color = icon.getPixel(i, 0);
+            System.out.println("current color: " + color);
+            if (!colorCount.containsKey(color)) colorCount.put(color, 0);
+            colorCount.put(color, colorCount.get(color) + 1);
+
+            // bottom edge
+            color = icon.getPixel(i, icon.getHeight() - 1);
+            if (!colorCount.containsKey(color)) colorCount.put(color, 0);
+            colorCount.put(color, colorCount.get(color) + 1);
+
+            // Measure the lateral edges offset by 1 on each side.
+            if (i > 0 && i < icon.getWidth() - 1) {
+                // left edge
+                color = icon.getPixel(0, i);
+                if (!colorCount.containsKey(color)) colorCount.put(color, 0);
+                colorCount.put(color, colorCount.get(color) + 1);
+
+                // right edge
+                color = icon.getPixel(icon.getWidth() - 1, i);
+                if (!colorCount.containsKey(color)) colorCount.put(color, 0);
+                colorCount.put(color, colorCount.get(color) + 1);
+            }
+        }
+
+        // Find the most common color out of the map.
+        int maxKey = Color.TRANSPARENT;
+        int maxVal = -1;
+        for (int color : colorCount.keySet()) {
+            int count = colorCount.get(color);
+            if (count > maxVal) {
+                maxKey = color;
+                maxVal = count;
+            }
+        }
+        assert maxVal > -1;
+
+        return maxKey;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java
index 32d087771..fd327b4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java
@@ -27,10 +27,8 @@
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.BottomSheetContent;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.StateChangeReason;
 
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.PriorityQueue;
-import java.util.Set;
 
 /**
  * This class is responsible for managing the content shown by the {@link BottomSheet}. Features
@@ -57,15 +55,9 @@
     /** A queue for content that is waiting to be shown in the {@link BottomSheet}. */
     private PriorityQueue<BottomSheetContent> mContentQueue;
 
-    /** A set of contents that have requested to be shown, rather than just preloading. */
-    private Set<BottomSheetContent> mFullShowRequestedSet;
-
     /** Whether the controller is already processing a hide request for the tab. */
     private boolean mIsProcessingHideRequest;
 
-    /** Track whether the sheet was shown for the current tab. */
-    private boolean mWasShownForCurrentTab;
-
     /** Whether the bottom sheet is temporarily suppressed. */
     private boolean mIsSuppressed;
 
@@ -103,7 +95,6 @@
         mSuppressSheetForContextualSearch = suppressSheetForContextualSearch;
         mSnackbarManager = new SnackbarManager(
                 activity, mBottomSheet.findViewById(R.id.bottom_sheet_snackbar_container));
-        mFullShowRequestedSet = new HashSet<>();
 
         // Initialize the queue with a comparator that checks content priority.
         mContentQueue = new PriorityQueue<>(INITIAL_QUEUE_CAPACITY,
@@ -262,8 +253,8 @@
      * the browser (i.e. the tab switcher may be showing).
      */
     private void unsuppressSheet() {
-        if (!mIsSuppressed || mTabProvider.get() == null || !mWasShownForCurrentTab
-                || isOtherUIObscuring() || VrModuleProvider.getDelegate().isInVr()) {
+        if (!mIsSuppressed || mTabProvider.get() == null || isOtherUIObscuring()
+                || VrModuleProvider.getDelegate().isInVr()) {
             return;
         }
         mIsSuppressed = false;
@@ -299,13 +290,11 @@
      *         state, or the browser is in a mode that does not support showing the sheet.
      */
     public boolean requestShowContent(BottomSheetContent content, boolean animate) {
-        // If pre-load failed, do nothing. The content will automatically be queued.
-        mFullShowRequestedSet.add(content);
+        // If load failed, do nothing. The content will automatically be queued.
         if (!loadInternal(content)) return false;
         if (!mBottomSheet.isSheetOpen() && !isOtherUIObscuring()) {
             mBottomSheet.setSheetState(BottomSheet.SheetState.PEEK, animate);
         }
-        mWasShownForCurrentTab = true;
         return true;
     }
 
@@ -345,8 +334,6 @@
      * @param animate Whether the sheet should animate when hiding.
      */
     public void hideContent(BottomSheetContent content, boolean animate) {
-        mFullShowRequestedSet.remove(content);
-
         if (content != mBottomSheet.getCurrentSheetContent()) {
             mContentQueue.remove(content);
             return;
@@ -405,9 +392,7 @@
 
         BottomSheetContent nextContent = mContentQueue.poll();
         mBottomSheet.showContent(nextContent);
-        if (mFullShowRequestedSet.contains(nextContent)) {
-            mBottomSheet.setSheetState(BottomSheet.SheetState.PEEK, true);
-        }
+        mBottomSheet.setSheetState(BottomSheet.SheetState.PEEK, true);
     }
 
     /**
@@ -416,14 +401,10 @@
      */
     private void clearRequestsAndHide() {
         clearRequests(mContentQueue.iterator());
-        clearRequests(mFullShowRequestedSet.iterator());
 
         BottomSheetContent currentContent = mBottomSheet.getCurrentSheetContent();
         if (currentContent != null && !currentContent.hasCustomLifecycle()) {
-            if (mContentQueue.isEmpty() && mFullShowRequestedSet.isEmpty()) {
-                mWasShownForCurrentTab = false;
-                mIsSuppressed = false;
-            }
+            if (mContentQueue.isEmpty()) mIsSuppressed = false;
 
             hideContent(currentContent, /* animate= */ true);
         }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/SearchEngineLogoUtilsTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/SearchEngineLogoUtilsTest.java
new file mode 100644
index 0000000..7be63ce
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/SearchEngineLogoUtilsTest.java
@@ -0,0 +1,76 @@
+// 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.omnibox;
+
+import static org.junit.Assert.assertEquals;
+
+import android.graphics.Bitmap;
+import android.graphics.Color;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+import org.chromium.base.test.BaseRobolectricTestRunner;
+
+/**
+ * Tests for SearchEngineLogoUtils.
+ */
+@RunWith(BaseRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class SearchEngineLogoUtilsTest {
+    @Test
+    public void getMostCommonEdgeColor_allOneColor() {
+        int color = Color.BLUE;
+        Bitmap bitmap = createSolidImage(100, 100, color);
+        assertEquals(color, SearchEngineLogoUtils.getMostCommonEdgeColor(bitmap));
+    }
+
+    @Test
+    public void getMostCommonEdgeColor_outerInnerColor() {
+        int color = Color.BLUE;
+        Bitmap bitmap = createSolidImageWithDifferentInnerColor(100, 100, color, Color.RED);
+        assertEquals(color, SearchEngineLogoUtils.getMostCommonEdgeColor(bitmap));
+    }
+
+    @Test
+    public void getMostCommonEdgeColor_slightlyLargerColor() {
+        int color = Color.BLUE;
+        Bitmap bitmap = createSolidImageWithSlighlyLargerEdgeCoverage(100, 100, color, Color.RED);
+        assertEquals(color, SearchEngineLogoUtils.getMostCommonEdgeColor(bitmap));
+    }
+
+    private static Bitmap createSolidImage(int width, int height, int color) {
+        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+        for (int x = 0; x < bitmap.getWidth(); x++) {
+            for (int y = 0; y < bitmap.getHeight(); y++) {
+                bitmap.setPixel(x, y, color);
+            }
+        }
+        return bitmap;
+    }
+
+    private static Bitmap createSolidImageWithDifferentInnerColor(
+            int width, int height, int outerColor, int innerColor) {
+        Bitmap bitmap = createSolidImage(width, height, outerColor);
+        for (int x = 1; x < bitmap.getWidth() - 1; x++) {
+            for (int y = 1; y < bitmap.getHeight() - 1; y++) {
+                bitmap.setPixel(x, y, innerColor);
+            }
+        }
+        return bitmap;
+    }
+
+    private static Bitmap createSolidImageWithSlighlyLargerEdgeCoverage(
+            int width, int height, int largerColor, int smallerColor) {
+        Bitmap bitmap = createSolidImage(width, height, largerColor);
+        for (int x = 0; x < bitmap.getWidth(); x++) {
+            for (int y = bitmap.getHeight() + 1; y < bitmap.getHeight(); y++) {
+                bitmap.setPixel(x, y, smallerColor);
+            }
+        }
+        return bitmap;
+    }
+}
diff --git a/chrome/app/BUILD.gn b/chrome/app/BUILD.gn
index 9ee7ecc..d24e0e3 100644
--- a/chrome/app/BUILD.gn
+++ b/chrome/app/BUILD.gn
@@ -567,10 +567,6 @@
       "//chromeos/services/secure_channel/public/cpp:manifest",
     ]
   }
-
-  if (!is_android) {
-    deps += [ "//components/mirroring/service:manifest" ]
-  }
 }
 
 source_set("chrome_service_manifests") {
diff --git a/chrome/app/DEPS b/chrome/app/DEPS
index 64cda532..6569f411 100644
--- a/chrome/app/DEPS
+++ b/chrome/app/DEPS
@@ -83,7 +83,6 @@
   "builtin_service_manifests\.cc": [
     "+chromeos/services/network_config",
     "+chromeos/services/secure_channel",
-    "+components/mirroring/service",
     "+components/startup_metric_utils/common",
     "+extensions/buildflags",
     "+mash/public",
diff --git a/chrome/app/builtin_service_manifests.cc b/chrome/app/builtin_service_manifests.cc
index d8ea10c..dd20161 100644
--- a/chrome/app/builtin_service_manifests.cc
+++ b/chrome/app/builtin_service_manifests.cc
@@ -20,16 +20,9 @@
 #include "base/feature_list.h"
 #endif
 
-#if !defined(OS_ANDROID)
-#include "components/mirroring/service/manifest.h"  // nogncheck
-#endif
-
 const std::vector<service_manager::Manifest>&
 GetChromeBuiltinServiceManifests() {
   static base::NoDestructor<std::vector<service_manager::Manifest>> manifests{{
-#if !defined(OS_ANDROID)
-      mirroring::GetManifest(),
-#endif
 #if defined(OS_CHROMEOS)
       ash::GetManifest(),
       chromeos::network_config::GetManifest(),
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 9f89b3b..c4e8686a 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -3315,7 +3315,7 @@
     Do not allow any sites to access serial ports
   </message>
   <message name="IDS_SETTINGS_SITE_SETTINGS_NATIVE_FILE_SYSTEM_WRITE" desc="Label for native file system write permission, which enables sites to save changes to the original files that were selected by the user.">
-    Files on device
+    File editing
   </message>
   <message name="IDS_SETTINGS_SITE_SETTINGS_NATIVE_FILE_SYSTEM_WRITE_ASK" desc="The ask label for native file system write permission in site settings.">
     Ask when a site wants to save your changes directly to files or folders on your device
@@ -5127,10 +5127,10 @@
   <message name="IDS_SETTINGS_SECURITY_KEYS_RESET_ERROR" desc="A failure message reporting to the user that the attempt to reset their security key (which is an external device for user authentication) failed. This is message is shown in uncommon cases when we don't have a more specific message to show the user and have fallen back to displaying a numerical error code reported by the device.">
     Can’t reset this security key. Error <ph name="ERROR_CODE">$1<ex>22</ex></ph>.
   </message>
-  <message name="IDS_SETTINGS_SECURITY_KEYS_RESET_SUCCESS" desc="A mesasge to the user that they have successfully reset (i.e. erased) their security key (which is an external device for user authentication).">
+  <message name="IDS_SETTINGS_SECURITY_KEYS_RESET_SUCCESS" desc="A message to the user that they have successfully reset (i.e. erased) their security key (which is an external device for user authentication).">
     Your security key has been reset
   </message>
-  <message name="IDS_SETTINGS_SECURITY_KEYS_RESET_NOTALLOWED" desc="A mesasge to the user that an attempt to reset (i.e. erase) their security key (an external device for user authentication) failed because the security key refused to be reset. This is usually caused because a reset is only allowed within the first few seconds after being plugged in, so the user has to perform the operation quickly.">
+  <message name="IDS_SETTINGS_SECURITY_KEYS_RESET_NOTALLOWED" desc="A message to the user that an attempt to reset (i.e. erase) their security key (an external device for user authentication) failed because the security key refused to be reset. This is usually caused because a reset is only allowed within the first few seconds after being plugged in, so the user has to perform the operation quickly.">
     Can’t reset this security key. Try resetting the key immediately after inserting it.
   </message>
   <message name="IDS_SETTINGS_SECURITY_KEYS_PIN_TOUCH" desc="An instruction to a user to physically the activation button on their security key (which is an external device for user authentication).">
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 75c6d6a..05f4cff 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -844,6 +844,8 @@
     "net/dns_probe_service.h",
     "net/dns_probe_service_factory.cc",
     "net/dns_probe_service_factory.h",
+    "net/dns_util.cc",
+    "net/dns_util.h",
     "net/file_downloader.cc",
     "net/file_downloader.h",
     "net/net_error_diagnostics_dialog.h",
@@ -1999,7 +2001,6 @@
     "//components/metrics:ui",
     "//components/metrics_services_manager",
     "//components/mirroring/browser",
-    "//components/mirroring/mojom:constants",
     "//components/mirroring/mojom:host",
     "//components/mirroring/mojom:service",
     "//components/mirroring/service:mirroring_service",
@@ -3593,6 +3594,8 @@
       "metrics/perf/heap_collector.h",
       "metrics/perf/metric_collector.cc",
       "metrics/perf/metric_collector.h",
+      "metrics/perf/metric_provider.cc",
+      "metrics/perf/metric_provider.h",
       "metrics/perf/perf_events_collector.cc",
       "metrics/perf/perf_events_collector.h",
       "metrics/perf/perf_output.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index b2e6be39..4176bea 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -25,6 +25,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "cc/base/switches.h"
 #include "chrome/browser/browser_features.h"
@@ -1208,6 +1209,18 @@
      ""},
 };
 
+#if defined(OS_ANDROID)
+const FeatureEntry::FeatureParam
+    kOmniboxSearchEngineLogoRoundedEdgesVariationConstant[] = {
+        {"rounded_edges", "true"}};
+const FeatureEntry::FeatureVariation
+    kOmniboxSearchEngineLogoFeatureVariations[] = {
+        {"(rounded edges)",
+         kOmniboxSearchEngineLogoRoundedEdgesVariationConstant,
+         base::size(kOmniboxSearchEngineLogoRoundedEdgesVariationConstant),
+         nullptr}};
+#endif  // OS_ANDROID
+
 // RECORDING USER METRICS FOR FLAGS:
 // -----------------------------------------------------------------------------
 // The first line of the entry is the internal name.
@@ -2384,13 +2397,13 @@
      flag_descriptions::kKernelnextVMsDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(features::kKernelnextVMs)},
 #endif  // OS_CHROMEOS
-#if !defined(OS_ANDROID) && defined(GOOGLE_CHROME_BUILD)
+#if !defined(OS_ANDROID) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
     {"enable-google-branded-context-menu",
      flag_descriptions::kGoogleBrandedContextMenuName,
      flag_descriptions::kGoogleBrandedContextMenuDescription,
      kOsDesktop | kExpireM77,
      FEATURE_VALUE_TYPE(features::kGoogleBrandedContextMenu)},
-#endif  // !OS_ANDROID && GOOGLE_CHROME_BUILD
+#endif  // !OS_ANDROID && BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #if defined(OS_MACOSX)
     {"enable-immersive-fullscreen-toolbar",
      flag_descriptions::kImmersiveFullscreenName,
@@ -2639,7 +2652,9 @@
     {"omnibox-search-engine-logo",
      flag_descriptions::kOmniboxSearchEngineLogoName,
      flag_descriptions::kOmniboxSearchEngineLogoDescription, kOsAndroid,
-     FEATURE_VALUE_TYPE(omnibox::kOmniboxSearchEngineLogo)},
+     FEATURE_WITH_PARAMS_VALUE_TYPE(omnibox::kOmniboxSearchEngineLogo,
+                                    kOmniboxSearchEngineLogoFeatureVariations,
+                                    "OmniboxSearchEngineLogo")},
 #endif  // defined(OS_ANDROID)
 
     {"omnibox-rich-entity-suggestions",
diff --git a/chrome/browser/active_use_util_unittest.cc b/chrome/browser/active_use_util_unittest.cc
index 48e39c5..24a96e74 100644
--- a/chrome/browser/active_use_util_unittest.cc
+++ b/chrome/browser/active_use_util_unittest.cc
@@ -6,13 +6,14 @@
 
 #include "base/command_line.h"
 #include "base/files/file_path.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/common/chrome_switches.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 TEST(ShouldRecordActiveUse, OrdinaryCommand) {
   base::CommandLine cmd_line(base::FilePath(FILE_PATH_LITERAL("foo.exe")));
-#if !defined(OS_WIN) || defined(GOOGLE_CHROME_BUILD)
+#if !defined(OS_WIN) || BUILDFLAG(GOOGLE_CHROME_BRANDING)
   EXPECT_TRUE(ShouldRecordActiveUse(cmd_line));
 #else
   EXPECT_FALSE(ShouldRecordActiveUse(cmd_line));
@@ -24,7 +25,7 @@
 TEST(ShouldRecordActiveUse, FakeTryChromeAgainCommand) {
   base::CommandLine cmd_line(base::FilePath(FILE_PATH_LITERAL("foo.exe")));
   cmd_line.AppendSwitch(switches::kTryChromeAgain);
-#if !defined(OS_WIN) || defined(GOOGLE_CHROME_BUILD)
+#if !defined(OS_WIN) || BUILDFLAG(GOOGLE_CHROME_BRANDING)
   EXPECT_TRUE(ShouldRecordActiveUse(cmd_line));
 #else
   EXPECT_FALSE(ShouldRecordActiveUse(cmd_line));
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm
index 1427dfb7..77e2c44 100644
--- a/chrome/browser/app_controller_mac.mm
+++ b/chrome/browser/app_controller_mac.mm
@@ -27,6 +27,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
 #include "base/threading/scoped_blocking_call.h"
+#include "build/branding_buildflags.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h"
 #include "chrome/browser/apps/platform_apps/app_window_registry_util.h"
@@ -660,7 +661,7 @@
 // 1) Same spot as other Pref stuff
 // 2) Try and be friendly by keeping this after app launch
 - (void)setUpdateCheckInterval {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   CFStringRef app = CFSTR("com.google.Keystone.Agent");
   CFStringRef checkInterval = CFSTR("checkInterval");
   CFPropertyListRef plist = CFPreferencesCopyAppValue(checkInterval, app);
@@ -1270,7 +1271,7 @@
   menuState_->UpdateCommandEnabled(IDC_MANAGE_EXTENSIONS, true);
   menuState_->UpdateCommandEnabled(IDC_HELP_PAGE_VIA_MENU, true);
   menuState_->UpdateCommandEnabled(IDC_IMPORT_SETTINGS, true);
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   menuState_->UpdateCommandEnabled(IDC_FEEDBACK, true);
 #endif
   menuState_->UpdateCommandEnabled(IDC_TASK_MANAGER, true);
diff --git a/chrome/browser/apps/app_service/arc_apps.cc b/chrome/browser/apps/app_service/arc_apps.cc
index c084ced..190a376 100644
--- a/chrome/browser/apps/app_service/arc_apps.cc
+++ b/chrome/browser/apps/app_service/arc_apps.cc
@@ -317,9 +317,6 @@
     case apps::mojom::LaunchSource::kFromAppListRecommendation:
       uit = arc::UserInteractionType::APP_STARTED_FROM_LAUNCHER_SUGGESTED_APP;
       break;
-    case apps::mojom::LaunchSource::kFromKioskNextHome:
-      uit = arc::UserInteractionType::APP_STARTED_FROM_KIOSK_NEXT_HOME;
-      break;
     case apps::mojom::LaunchSource::kFromParentalControls:
       uit = arc::UserInteractionType::APP_STARTED_FROM_SETTINGS;
       break;
diff --git a/chrome/browser/apps/app_service/built_in_chromeos_apps.cc b/chrome/browser/apps/app_service/built_in_chromeos_apps.cc
index 6eb7ec55..1fe0480d 100644
--- a/chrome/browser/apps/app_service/built_in_chromeos_apps.cc
+++ b/chrome/browser/apps/app_service/built_in_chromeos_apps.cc
@@ -156,7 +156,6 @@
                                  int64_t display_id) {
   switch (launch_source) {
     case apps::mojom::LaunchSource::kUnknown:
-    case apps::mojom::LaunchSource::kFromKioskNextHome:
     case apps::mojom::LaunchSource::kFromParentalControls:
       break;
     case apps::mojom::LaunchSource::kFromAppListGrid:
diff --git a/chrome/browser/apps/app_service/extension_apps.cc b/chrome/browser/apps/app_service/extension_apps.cc
index 5f14956..f991e91 100644
--- a/chrome/browser/apps/app_service/extension_apps.cc
+++ b/chrome/browser/apps/app_service/extension_apps.cc
@@ -169,7 +169,6 @@
 
   switch (launch_source) {
     case apps::mojom::LaunchSource::kUnknown:
-    case apps::mojom::LaunchSource::kFromKioskNextHome:
     case apps::mojom::LaunchSource::kFromParentalControls:
       break;
     case apps::mojom::LaunchSource::kFromAppListGrid:
diff --git a/chrome/browser/apps/app_service/launch_util.cc b/chrome/browser/apps/app_service/launch_util.cc
index 49ac382c..a55ee1e 100644
--- a/chrome/browser/apps/app_service/launch_util.cc
+++ b/chrome/browser/apps/app_service/launch_util.cc
@@ -13,7 +13,6 @@
     apps::mojom::LaunchSource launch_source) {
   switch (launch_source) {
     case apps::mojom::LaunchSource::kUnknown:
-    case apps::mojom::LaunchSource::kFromKioskNextHome:
     case apps::mojom::LaunchSource::kFromParentalControls:
       return ash::LAUNCH_FROM_UNKNOWN;
     case apps::mojom::LaunchSource::kFromAppListGrid:
diff --git a/chrome/browser/apps/platform_apps/api/arc_apps_private/arc_apps_private_apitest.cc b/chrome/browser/apps/platform_apps/api/arc_apps_private/arc_apps_private_apitest.cc
index 028f902..68d235c 100644
--- a/chrome/browser/apps/platform_apps/api/arc_apps_private/arc_apps_private_apitest.cc
+++ b/chrome/browser/apps/platform_apps/api/arc_apps_private/arc_apps_private_apitest.cc
@@ -7,7 +7,6 @@
 #include "base/macros.h"
 #include "base/path_service.h"
 #include "base/test/metrics/histogram_tester.h"
-#include "build/build_config.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/chromeos/login/demo_mode/demo_session.h"
 #include "chrome/browser/extensions/extension_apitest.h"
@@ -102,13 +101,7 @@
   EXPECT_TRUE(app_instance->launch_requests()[0]->IsForApp(launchable_app));
 }
 
-// TODO(crbug/992839) Fix flake on linux-chromeos-rel
-#if defined(OS_LINUX)
-#define MAYBE_OnInstalled DISABLED_OnInstalled
-#else
-#define MAYBE_OnInstalled OnInstalled
-#endif
-IN_PROC_BROWSER_TEST_F(ArcAppsPrivateApiTest, MAYBE_OnInstalled) {
+IN_PROC_BROWSER_TEST_F(ArcAppsPrivateApiTest, OnInstalled) {
   ArcAppListPrefs* prefs = ArcAppListPrefs::Get(browser()->profile());
   ASSERT_TRUE(prefs);
   std::unique_ptr<arc::FakeAppInstance> app_instance = CreateAppInstance(prefs);
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 55afe39..76cab0d 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -44,6 +44,7 @@
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
 #include "base/values.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "cc/base/switches.h"
 #include "chrome/browser/about_flags.h"
@@ -246,9 +247,9 @@
 #include "base/win/win_util.h"
 #include "chrome/browser/chrome_browser_main_win.h"
 #include "chrome/browser/component_updater/sw_reporter_installer_win.h"
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #include "chrome/browser/component_updater/third_party_module_list_component_installer_win.h"
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #include "chrome/browser/downgrade/user_data_downgrade.h"
 #include "chrome/browser/first_run/upgrade_util_win.h"
 #include "chrome/browser/ui/network_profile_bubble.h"
@@ -527,9 +528,9 @@
   // RegisterSwReporterComponent() has support for running only in official
   // builds or tests.
   RegisterSwReporterComponent(cus);
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   RegisterThirdPartyModuleListComponent(cus);
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #endif  // defined(OS_WIN)
 
 #if !defined(OS_ANDROID)
diff --git a/chrome/browser/chrome_browser_main_win.cc b/chrome/browser/chrome_browser_main_win.cc
index dfef8f1..b9a6d9d 100644
--- a/chrome/browser/chrome_browser_main_win.cc
+++ b/chrome/browser/chrome_browser_main_win.cc
@@ -38,6 +38,7 @@
 #include "base/win/registry.h"
 #include "base/win/win_util.h"
 #include "base/win/wrapped_window_proc.h"
+#include "build/branding_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/first_run/first_run.h"
 #include "chrome/browser/memory/memory_pressure_monitor.h"
@@ -94,7 +95,7 @@
 #include "ui/gfx/win/crash_id_helper.h"
 #include "ui/strings/grit/app_locale_settings.h"
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #include "chrome/browser/win/conflicts/third_party_conflicts_manager.h"
 #endif
 
@@ -407,7 +408,7 @@
   DCHECK(module_watcher);
 
   bool third_party_blocking_policy_enabled =
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
       ModuleDatabase::IsThirdPartyBlockingPolicyEnabled();
 #else
       false;
@@ -552,7 +553,7 @@
 void ChromeBrowserMainPartsWin::PostProfileInit() {
   ChromeBrowserMainParts::PostProfileInit();
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // Explicitly disable the third-party modules blocking.
   //
   // Because the blocking code lives in chrome_elf, it is not possible to check
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index dcd81210..c6b4990 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -217,8 +217,6 @@
 #include "components/language/core/browser/pref_names.h"
 #include "components/metrics/call_stack_profile_collector.h"
 #include "components/metrics/client_info.h"
-#include "components/mirroring/mojom/constants.mojom.h"
-#include "components/mirroring/service/features.h"
 #include "components/nacl/common/buildflags.h"
 #include "components/nacl/common/nacl_constants.h"
 #include "components/net_log/chrome_net_log.h"
diff --git a/chrome/browser/chrome_plugin_browsertest.cc b/chrome/browser/chrome_plugin_browsertest.cc
index 0a852cc..7994a69 100644
--- a/chrome/browser/chrome_plugin_browsertest.cc
+++ b/chrome/browser/chrome_plugin_browsertest.cc
@@ -16,6 +16,7 @@
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/plugins/plugin_prefs.h"
 #include "chrome/browser/profiles/profile.h"
@@ -213,7 +214,7 @@
   EnsureFlashProcessCount(1);
 }
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 // Verify that the official builds have the known set of plugins.
 IN_PROC_BROWSER_TEST_F(ChromePluginTest, InstalledPlugins) {
   const char* expected[] = {
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 a1efcd2a..61e6fcee 100644
--- a/chrome/browser/chromeos/backdrop_wallpaper_handlers/backdrop_wallpaper_handlers.cc
+++ b/chrome/browser/chromeos/backdrop_wallpaper_handlers/backdrop_wallpaper_handlers.cc
@@ -161,7 +161,7 @@
             "collections is downloaded from the Backdrop wallpaper service."
           trigger:
             "When ChromeOS Wallpaper Picker extension is open, and "
-            "GOOGLE_CHROME_BUILD is defined."
+            "BUILDFLAG(GOOGLE_CHROME_BUILD) is defined."
           data:
             "The Backdrop protocol buffer messages. No user data is included."
           destination: GOOGLE_OWNED_SERVICE
@@ -231,8 +231,8 @@
             "downloaded from the Backdrop wallpaper service."
           trigger:
             "When ChromeOS Wallpaper Picker extension is open, "
-            "GOOGLE_CHROME_BUILD is defined and user clicks on a particular "
-            "collection."
+            "BUILDFLAG(GOOGLE_CHROME_BUILD) is defined and user clicks on a "
+            "particular collection."
           data:
             "The Backdrop protocol buffer messages. No user data is included."
           destination: GOOGLE_OWNED_SERVICE
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index f666c9977..861b4d07 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -32,6 +32,7 @@
 #include "base/task/post_task.h"
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool/thread_pool.h"
+#include "build/branding_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part_chromeos.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -276,7 +277,7 @@
 // For Chromium builds, don't send it here. Instead, rely on this signal being
 // sent after each successful login.
 bool ShallAttemptTpmOwnership() {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   return StartupUtils::IsEulaAccepted();
 #else
   return false;
@@ -946,7 +947,7 @@
   // ChromeSessionManager because it depends on NetworkPortalDetector.
   InitializeNetworkPortalDetector();
   {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
     bool is_official_build = true;
 #else
     bool is_official_build = false;
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
index aee1cab..33c4ebd 100644
--- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
+++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
@@ -2000,6 +2000,45 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
+// AutotestPrivateGetArcAppWindowInfoFunction
+///////////////////////////////////////////////////////////////////////////////
+
+AutotestPrivateGetArcAppWindowInfoFunction::
+    AutotestPrivateGetArcAppWindowInfoFunction() = default;
+AutotestPrivateGetArcAppWindowInfoFunction::
+    ~AutotestPrivateGetArcAppWindowInfoFunction() = default;
+
+ExtensionFunction::ResponseAction
+AutotestPrivateGetArcAppWindowInfoFunction::Run() {
+  std::unique_ptr<api::autotest_private::GetArcAppWindowInfo::Params> params(
+      api::autotest_private::GetArcAppWindowInfo::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params);
+  DVLOG(1) << "AutotestPrivateGetArcAppWindowInfoFunction "
+           << params->package_name;
+
+  aura::Window* arc_window = GetArcAppWindow(params->package_name);
+  if (!arc_window) {
+    return RespondNow(Error(base::StrCat(
+        {"No ARC app window is found for ", params->package_name})));
+  }
+
+  const gfx::Rect bounds = arc_window->GetBoundsInRootWindow();
+  const bool is_animating = arc_window->layer()->GetAnimator()->is_animating();
+
+  auto bounds_dict = std::make_unique<base::DictionaryValue>();
+  bounds_dict->SetInteger("left", bounds.x());
+  bounds_dict->SetInteger("top", bounds.y());
+  bounds_dict->SetInteger("width", bounds.width());
+  bounds_dict->SetInteger("height", bounds.height());
+
+  auto result = std::make_unique<base::DictionaryValue>();
+  result->SetDictionary("bounds", std::move(bounds_dict));
+  result->SetBoolean("is_animating", is_animating);
+
+  return RespondNow(OneArgument(std::move(result)));
+}
+
+///////////////////////////////////////////////////////////////////////////////
 // AutotestPrivateSetArcAppWindowStateFunction
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h
index f6b7bcc..6376a5a 100644
--- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h
+++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h
@@ -716,6 +716,18 @@
   ResponseAction Run() override;
 };
 
+// Gets various window properties of an ARC window.
+class AutotestPrivateGetArcAppWindowInfoFunction : public ExtensionFunction {
+ public:
+  AutotestPrivateGetArcAppWindowInfoFunction();
+  DECLARE_EXTENSION_FUNCTION("autotestPrivate.getArcAppWindowInfo",
+                             AUTOTESTPRIVATE_GETARCAPPWINDOWINFO)
+
+ private:
+  ~AutotestPrivateGetArcAppWindowInfoFunction() override;
+  ResponseAction Run() override;
+};
+
 template <>
 KeyedService*
 BrowserContextKeyedAPIFactory<AutotestPrivateAPI>::BuildServiceInstanceFor(
diff --git a/chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.cc b/chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.cc
index 1d18c78..a7f615d 100644
--- a/chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.cc
+++ b/chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.cc
@@ -16,6 +16,7 @@
 #include "base/strings/string_util.h"
 #include "base/system/sys_info.h"
 #include "base/task/post_task.h"
+#include "build/branding_buildflags.h"
 #include "chrome/browser/extensions/component_loader.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/profiles/profile.h"
@@ -40,44 +41,53 @@
   const char* id;
   int manifest_resource_id;
 } whitelisted_component_extension[] = {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
     {
         // Official Google XKB Input.
-        extension_ime_util::kXkbExtensionId, IDR_GOOGLE_XKB_MANIFEST,
+        extension_ime_util::kXkbExtensionId,
+        IDR_GOOGLE_XKB_MANIFEST,
     },
 #else
     {
         // Open-sourced ChromeOS xkb extension.
-        extension_ime_util::kXkbExtensionId, IDR_XKB_MANIFEST,
+        extension_ime_util::kXkbExtensionId,
+        IDR_XKB_MANIFEST,
     },
     {
         // Open-sourced ChromeOS Keyboards extension.
-        extension_ime_util::kM17nExtensionId, IDR_M17N_MANIFEST,
+        extension_ime_util::kM17nExtensionId,
+        IDR_M17N_MANIFEST,
     },
     {
         // Open-sourced Pinyin Chinese Input Method.
-        extension_ime_util::kChinesePinyinExtensionId, IDR_PINYIN_MANIFEST,
+        extension_ime_util::kChinesePinyinExtensionId,
+        IDR_PINYIN_MANIFEST,
     },
     {
         // Open-sourced Zhuyin Chinese Input Method.
-        extension_ime_util::kChineseZhuyinExtensionId, IDR_ZHUYIN_MANIFEST,
+        extension_ime_util::kChineseZhuyinExtensionId,
+        IDR_ZHUYIN_MANIFEST,
     },
     {
         // Open-sourced Cangjie Chinese Input Method.
-        extension_ime_util::kChineseCangjieExtensionId, IDR_CANGJIE_MANIFEST,
+        extension_ime_util::kChineseCangjieExtensionId,
+        IDR_CANGJIE_MANIFEST,
     },
     {
         // Open-sourced Japanese Mozc Input.
-        extension_ime_util::kMozcExtensionId, IDR_MOZC_MANIFEST,
+        extension_ime_util::kMozcExtensionId,
+        IDR_MOZC_MANIFEST,
     },
     {
         // Open-sourced Hangul Input.
-        extension_ime_util::kHangulExtensionId, IDR_HANGUL_MANIFEST,
+        extension_ime_util::kHangulExtensionId,
+        IDR_HANGUL_MANIFEST,
     },
 #endif
     {
         // Braille hardware keyboard IME that works together with ChromeVox.
-        extension_ime_util::kBrailleImeExtensionId, IDR_BRAILLE_MANIFEST,
+        extension_ime_util::kBrailleImeExtensionId,
+        IDR_BRAILLE_MANIFEST,
     },
 };
 
diff --git a/chrome/browser/chromeos/kiosk_next_home/kiosk_next.gni b/chrome/browser/chromeos/kiosk_next_home/kiosk_next.gni
deleted file mode 100644
index 3a411a9f..0000000
--- a/chrome/browser/chromeos/kiosk_next_home/kiosk_next.gni
+++ /dev/null
@@ -1,4 +0,0 @@
-declare_args() {
-  # Whether Kiosk Next should be enabled.
-  enable_kiosk_next = is_chromeos
-}
diff --git a/chrome/browser/chromeos/login/eula_browsertest.cc b/chrome/browser/chromeos/login/eula_browsertest.cc
index b85809b..522e113 100644
--- a/chrome/browser/chromeos/login/eula_browsertest.cc
+++ b/chrome/browser/chromeos/login/eula_browsertest.cc
@@ -15,6 +15,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/task/post_task.h"
 #include "base/test/bind_test_util.h"
+#include "build/branding_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/login/test/dialog_window_waiter.h"
 #include "chrome/browser/chromeos/login/test/js_checker.h"
@@ -54,7 +55,7 @@
 
 constexpr char kFakeOnlineEulaPath[] = "/intl/en-US/chrome/eula_text.html";
 constexpr char kFakeOnlineEula[] = "No obligations at all";
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 // See IDS_ABOUT_TERMS_OF_SERVICE for the complete text.
 constexpr char kOfflineEULAWarning[] = "Chrome OS Terms";
 #else
diff --git a/chrome/browser/chromeos/login/hwid_checker.cc b/chrome/browser/chromeos/login/hwid_checker.cc
index ed5eb44..e3fa0a1 100644
--- a/chrome/browser/chromeos/login/hwid_checker.cc
+++ b/chrome/browser/chromeos/login/hwid_checker.cc
@@ -11,6 +11,7 @@
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/system/sys_info.h"
+#include "build/branding_buildflags.h"
 #include "chrome/common/chrome_switches.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/system/statistics_provider.h"
@@ -147,7 +148,7 @@
 }
 
 bool IsMachineHWIDCorrect() {
-#if !defined(GOOGLE_CHROME_BUILD)
+#if !BUILDFLAG(GOOGLE_CHROME_BRANDING)
   return true;
 #endif
   base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
diff --git a/chrome/browser/chromeos/login/hwid_checker_unittest.cc b/chrome/browser/chromeos/login/hwid_checker_unittest.cc
index 3188ea5e..2993f82 100644
--- a/chrome/browser/chromeos/login/hwid_checker_unittest.cc
+++ b/chrome/browser/chromeos/login/hwid_checker_unittest.cc
@@ -3,9 +3,11 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/chromeos/login/hwid_checker.h"
+
 #include "base/system/sys_info.h"
 #include "base/test/scoped_command_line.h"
 #include "base/time/time.h"
+#include "build/branding_buildflags.h"
 #include "chrome/browser/chromeos/scoped_set_running_on_chromeos_for_testing.h"
 #include "chromeos/system/fake_statistics_provider.h"
 #include "content/public/common/content_switches.h"
@@ -134,7 +136,7 @@
       IsHWIDCorrect("SARIEN-MCOO 0-20-1DC-180 B2B-A6J-23P-43A-B2L-A7I"));
 }
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 const char kLsbRelease[] =
     "CHROMEOS_RELEASE_NAME=Chrome OS\n"
     "CHROMEOS_RELEASE_VERSION=1.2.3.4\n";
@@ -264,7 +266,7 @@
   EXPECT_FALSE(IsMachineHWIDCorrect());
 }
 
-#else  // defined(GOOGLE_CHROME_BUILD)
+#else  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
 // Test non-Google Chromium builds.
 TEST(MachineHWIDCheckerTest, NonGoogleBuild) {
@@ -273,5 +275,5 @@
   EXPECT_TRUE(IsMachineHWIDCorrect());
 }
 
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc b/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc
index 6e3e856..7061dc41 100644
--- a/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc
+++ b/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc
@@ -10,6 +10,7 @@
 #include "base/optional.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/values.h"
+#include "build/branding_buildflags.h"
 #include "chrome/browser/chromeos/arc/arc_service_launcher.h"
 #include "chrome/browser/chromeos/arc/arc_session_manager.h"
 #include "chrome/browser/chromeos/extensions/quick_unlock_private/quick_unlock_private_api.h"
@@ -76,7 +77,7 @@
 }
 
 void RunWelcomeScreenChecks() {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   constexpr int kNumberOfVideosPlaying = 1;
 #else
   constexpr int kNumberOfVideosPlaying = 0;
@@ -99,8 +100,7 @@
       ").disabled");
 }
 
-
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 void RunEulaScreenChecks() {
   // Wait for actual EULA to appear.
   test::OobeJS()
@@ -529,7 +529,7 @@
   RunNetworkSelectionScreenChecks();
   test::TapNetworkSelectionNext();
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   test::WaitForEulaScreen();
   RunEulaScreenChecks();
   test::TapEulaAccept();
@@ -545,7 +545,7 @@
   WaitForGaiaSignInScreen(test_setup()->arc_state() != ArcState::kNotAvailable);
   LogInAsRegularUser();
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   test::WaitForSyncConsentScreen();
   test::ExitScreenSyncConsent();
 #endif
@@ -822,7 +822,7 @@
   WaitForGaiaSignInScreen(test_setup()->arc_state() != ArcState::kNotAvailable);
   LogInAsRegularUser();
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   test::WaitForSyncConsentScreen();
   test::ExitScreenSyncConsent();
 #endif
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index 9cec108..9fa973ce 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -8,6 +8,7 @@
 #include <stddef.h>
 #include <stdlib.h>
 #include <sys/types.h>
+
 #include <string>
 #include <utility>
 #include <vector>
@@ -28,6 +29,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "build/branding_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -295,7 +297,7 @@
 bool WizardController::skip_enrollment_prompts_ = false;
 
 // static
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 bool WizardController::is_official_build_ = true;
 #else
 bool WizardController::is_official_build_ = false;
@@ -1120,7 +1122,7 @@
       ProfileManager::GetActiveUserProfile(), enabled);
   if (!enabled)
     return;
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   base::PostTask(FROM_HERE, {base::MayBlock()},
                  base::BindOnce(&breakpad::InitCrashReporter, std::string()));
 #endif
diff --git a/chrome/browser/component_updater/chrome_component_updater_configurator.cc b/chrome/browser/component_updater/chrome_component_updater_configurator.cc
index 8532e5a1b..3765e73 100644
--- a/chrome/browser/component_updater/chrome_component_updater_configurator.cc
+++ b/chrome/browser/component_updater/chrome_component_updater_configurator.cc
@@ -14,6 +14,7 @@
 #include "base/callback.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/version.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/component_updater/component_updater_utils.h"
@@ -256,7 +257,7 @@
 
 update_client::RecoveryCRXElevator ChromeConfigurator::GetRecoveryCRXElevator()
     const {
-#if defined(GOOGLE_CHROME_BUILD) && defined(OS_WIN)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && defined(OS_WIN)
   return base::BindOnce(&RunRecoveryCRXElevated);
 #else
   return {};
diff --git a/chrome/browser/component_updater/pepper_flash_component_installer.cc b/chrome/browser/component_updater/pepper_flash_component_installer.cc
index 9528584..9aafbeb 100644
--- a/chrome/browser/component_updater/pepper_flash_component_installer.cc
+++ b/chrome/browser/component_updater/pepper_flash_component_installer.cc
@@ -26,6 +26,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
 #include "base/version.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/component_updater/component_installer_errors.h"
 #include "chrome/browser/plugins/plugin_prefs.h"
@@ -66,7 +67,7 @@
 
 namespace {
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #if defined(OS_CHROMEOS)
 // CRX hash for Chrome OS. The extension id is:
 // ckjlcfmdbdglblbjglepgnoekdnkoklc.
@@ -152,9 +153,9 @@
   return false;
 }
 #endif  // defined(OS_CHROMEOS)
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
-#if !defined(OS_LINUX) && defined(GOOGLE_CHROME_BUILD)
+#if !defined(OS_LINUX) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
 bool MakePepperFlashPluginInfo(const base::FilePath& flash_path,
                                const base::Version& flash_version,
                                bool out_of_process,
@@ -239,9 +240,9 @@
 void UpdatePathService(const base::FilePath& path) {
   base::PathService::Override(chrome::DIR_PEPPER_FLASH_PLUGIN, path);
 }
-#endif  // !defined(OS_LINUX) && defined(GOOGLE_CHROME_BUILD)
+#endif  // !defined(OS_LINUX) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 class FlashComponentInstallerPolicy : public ComponentInstallerPolicy {
  public:
   FlashComponentInstallerPolicy();
@@ -367,12 +368,12 @@
   mime_types.push_back("application/futuresplash");
   return mime_types;
 }
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
 }  // namespace
 
 void RegisterPepperFlashComponent(ComponentUpdateService* cus) {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // Component updated flash supersedes bundled flash therefore if that one
   // is disabled then this one should never install.
   base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
@@ -387,7 +388,7 @@
   auto installer = base::MakeRefCounted<ComponentInstaller>(
       std::make_unique<FlashComponentInstallerPolicy>());
   installer->Register(cus, base::OnceClosure());
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 }
 
 }  // namespace component_updater
diff --git a/chrome/browser/component_updater/recovery_component_installer.cc b/chrome/browser/component_updater/recovery_component_installer.cc
index 4f141e4..1552b7d 100644
--- a/chrome/browser/component_updater/recovery_component_installer.cc
+++ b/chrome/browser/component_updater/recovery_component_installer.cc
@@ -20,6 +20,7 @@
 #include "base/json/json_file_value_serializer.h"
 #include "base/logging.h"
 #include "base/task/post_task.h"
+#include "build/branding_buildflags.h"
 #include "content/public/browser/browser_task_traits.h"
 #if defined(OS_MACOSX)
 #include "base/mac/authorization_util.h"
@@ -49,7 +50,7 @@
 
 namespace component_updater {
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #if defined(OS_WIN) || defined(OS_MACOSX)
 
 namespace {
@@ -488,11 +489,11 @@
 }
 
 #endif  // defined(OS_WIN) || defined(OS_MACOSX)
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
 void RegisterRecoveryComponent(ComponentUpdateService* cus,
                                PrefService* prefs) {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #if defined(OS_WIN) || defined(OS_MACOSX)
   if (SimulatingElevatedRecovery()) {
     base::PostTask(FROM_HERE, {BrowserThread::UI},
@@ -518,7 +519,7 @@
 void AcceptedElevatedRecoveryInstall(PrefService* prefs) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #if defined(OS_WIN) || defined(OS_MACOSX)
   ElevatedInstallRecoveryComponent(
       prefs->GetFilePath(prefs::kRecoveryComponentUnpackPath));
diff --git a/chrome/browser/component_updater/recovery_improved_component_installer.cc b/chrome/browser/component_updater/recovery_improved_component_installer.cc
index b70fe8f..248dc6d 100644
--- a/chrome/browser/component_updater/recovery_improved_component_installer.cc
+++ b/chrome/browser/component_updater/recovery_improved_component_installer.cc
@@ -11,6 +11,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/process/process.h"
 #include "base/strings/sys_string_conversions.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 
 #if defined(OS_WIN)
@@ -19,7 +20,7 @@
 #include "chrome/install_static/install_util.h"
 #endif
 
-#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
+#if defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #include "chrome/elevation_service/elevation_service_idl.h"
 #endif
 
@@ -34,7 +35,7 @@
     0x97, 0xd7, 0x32, 0x75, 0xcc, 0xd5, 0x7f, 0xec, 0x09, 0x60, 0x6d,
     0x20, 0xc3, 0x81, 0xd7, 0xce, 0x7b, 0x10, 0x15, 0x44, 0xd1};
 
-#if defined(GOOGLE_CHROME_BUILD) && defined(OS_WIN)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && defined(OS_WIN)
 // Instantiates the elevator service, calls its elevator interface, then
 // blocks waiting for the recovery processes to exit. Returns the result
 // of the recovery as a tuple.
@@ -138,7 +139,7 @@
 
 void RegisterRecoveryImprovedComponent(ComponentUpdateService* cus,
                                        PrefService* prefs) {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #if defined(OS_WIN) || defined(OS_MACOSX)
   DVLOG(1) << "Registering RecoveryImproved component.";
 
diff --git a/chrome/browser/component_updater/sw_reporter_installer_win.cc b/chrome/browser/component_updater/sw_reporter_installer_win.cc
index 21ec393..b0cb42e 100644
--- a/chrome/browser/component_updater/sw_reporter_installer_win.cc
+++ b/chrome/browser/component_updater/sw_reporter_installer_win.cc
@@ -36,6 +36,7 @@
 #include "base/time/time.h"
 #include "base/win/registry.h"
 #include "base/win/windows_version.h"
+#include "build/branding_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_win.h"
 #include "chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_win.h"
@@ -81,7 +82,7 @@
 
 // SwReporter is normally only registered in official builds.  However, to
 // enable testing in chromium build bots, test code can set this to true.
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 bool is_sw_reporter_enabled = true;
 #else
 bool is_sw_reporter_enabled = false;
diff --git a/chrome/browser/diagnostics/recon_diagnostics.cc b/chrome/browser/diagnostics/recon_diagnostics.cc
index ba4636b..ace1556 100644
--- a/chrome/browser/diagnostics/recon_diagnostics.cc
+++ b/chrome/browser/diagnostics/recon_diagnostics.cc
@@ -20,6 +20,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/system/sys_info.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/diagnostics/diagnostics_test.h"
 #include "chrome/common/channel_info.h"
@@ -296,9 +297,9 @@
     std::string version_modifier = chrome::GetChannelName();
     if (!version_modifier.empty())
       current_version += " " + version_modifier;
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
     current_version += " GCB";
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
     RecordSuccess(current_version);
     return true;
   }
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc
index 0ec77e7..6af2aa2 100644
--- a/chrome/browser/extensions/api/settings_private/prefs_util.cc
+++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/extensions/api/settings_private/prefs_util.h"
 
 #include "base/feature_list.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/api/settings_private/generated_prefs.h"
@@ -618,12 +619,12 @@
   (*s_whitelist)[proxy_config::prefs::kProxy] =
       settings_api::PrefType::PREF_TYPE_DICTIONARY;
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   (*s_whitelist)[::prefs::kMediaRouterEnableCloudServices] =
       settings_api::PrefType::PREF_TYPE_BOOLEAN;
   (*s_whitelist)[::prefs::kUserFeedbackAllowed] =
       settings_api::PrefType::PREF_TYPE_BOOLEAN;
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
   // Media Remoting settings.
   (*s_whitelist)[::prefs::kMediaRouterMediaRemotingEnabled] =
diff --git a/chrome/browser/extensions/chrome_content_verifier_delegate.cc b/chrome/browser/extensions/chrome_content_verifier_delegate.cc
index 0c007d0..3cf3b28 100644
--- a/chrome/browser/extensions/chrome_content_verifier_delegate.cc
+++ b/chrome/browser/extensions/chrome_content_verifier_delegate.cc
@@ -19,6 +19,7 @@
 #include "base/syslog_logging.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/version.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/install_verifier.h"
@@ -65,7 +66,7 @@
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
 
   Mode experiment_value;
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   experiment_value = ENFORCE_STRICT;
 #else
   experiment_value = NONE;
diff --git a/chrome/browser/extensions/chrome_extensions_interface_registration.cc b/chrome/browser/extensions/chrome_extensions_interface_registration.cc
index 385d9180..2f30fb8e 100644
--- a/chrome/browser/extensions/chrome_extensions_interface_registration.cc
+++ b/chrome/browser/extensions/chrome_extensions_interface_registration.cc
@@ -11,6 +11,7 @@
 #include "base/bind.h"
 #include "base/feature_list.h"
 #include "base/logging.h"
+#include "build/branding_buildflags.h"
 #include "chrome/browser/media/router/media_router_feature.h"       // nogncheck
 #include "chrome/browser/media/router/mojo/media_router_desktop.h"  // nogncheck
 #include "chrome/common/extensions/extension_constants.h"
@@ -46,7 +47,7 @@
 namespace {
 #if defined(OS_CHROMEOS)
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 // Resolves InputEngineManager request in InputMethodManager.
 void BindInputEngineManager(
     chromeos::ime::mojom::InputEngineManagerRequest request,
@@ -54,7 +55,7 @@
   chromeos::input_method::InputMethodManager::Get()->ConnectInputEngineManager(
       std::move(request));
 }
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
 // Translates the renderer-side source ID to video device id.
 void TranslateVideoDeviceId(
@@ -135,12 +136,12 @@
 
 #if defined(OS_CHROMEOS)
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // Registry InputEngineManager for official Google XKB Input only.
   if (extension->id() == chromeos::extension_ime_util::kXkbExtensionId) {
     registry->AddInterface(base::BindRepeating(&BindInputEngineManager));
   }
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
   if (extension->permissions_data()->HasAPIPermission(
           APIPermission::kMediaPerceptionPrivate)) {
diff --git a/chrome/browser/extensions/component_extensions_whitelist/whitelist.cc b/chrome/browser/extensions/component_extensions_whitelist/whitelist.cc
index 8052d08..8e07d2b 100644
--- a/chrome/browser/extensions/component_extensions_whitelist/whitelist.cc
+++ b/chrome/browser/extensions/component_extensions_whitelist/whitelist.cc
@@ -8,6 +8,7 @@
 
 #include "base/logging.h"
 #include "base/stl_util.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/common/buildflags.h"
 #include "chrome/common/extensions/extension_constants.h"
@@ -95,11 +96,11 @@
     case IDR_MOBILE_MANIFEST:
     case IDR_VIDEO_PLAYER_MANIFEST:
     case IDR_WALLPAPERMANAGER_MANIFEST:
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
     case IDR_GENIUS_APP_MANIFEST:
     case IDR_HELP_MANIFEST:
     case IDR_QUICKOFFICE_MANIFEST:
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #endif  // defined(OS_CHROMEOS)
       return true;
   }
diff --git a/chrome/browser/extensions/component_loader.cc b/chrome/browser/extensions/component_loader.cc
index 00620c95e..927eece 100644
--- a/chrome/browser/extensions/component_loader.cc
+++ b/chrome/browser/extensions/component_loader.cc
@@ -17,6 +17,7 @@
 #include "base/path_service.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/extensions/component_extensions_whitelist/whitelist.h"
 #include "chrome/browser/extensions/data_deleter.h"
@@ -64,7 +65,7 @@
 #include "chrome/browser/pdf/pdf_extension_util.h"
 #endif
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #include "chrome/browser/defaults.h"
 #endif
 
@@ -428,12 +429,12 @@
   Add(IDR_MOBILE_MANIFEST,
       base::FilePath(FILE_PATH_LITERAL("/usr/share/chromeos-assets/mobile")));
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   if (browser_defaults::enable_help_app) {
     Add(IDR_HELP_MANIFEST, base::FilePath(FILE_PATH_LITERAL(
                                "/usr/share/chromeos-assets/helpapp")));
   }
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
   // Skip all other extensions that require user session presence.
   if (!skip_session_components) {
@@ -505,7 +506,7 @@
     return;
   }
 
-#if defined(OS_CHROMEOS) && defined(GOOGLE_CHROME_BUILD)
+#if defined(OS_CHROMEOS) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // Since this is a v2 app it has a background page.
   AddWithNameAndDescription(
       IDR_GENIUS_APP_MANIFEST,
@@ -522,9 +523,9 @@
 #endif  // BUILDFLAG(ENABLE_HANGOUT_SERVICES_EXTENSION)
 
     bool install_feedback = enable_background_extensions_during_testing;
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
     install_feedback = true;
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
     if (install_feedback)
       Add(IDR_FEEDBACK_MANIFEST, base::FilePath(FILE_PATH_LITERAL("feedback")));
 
@@ -540,12 +541,12 @@
     AddZipArchiverExtension();
 #endif  // BUILDFLAG(ENABLE_NACL)
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
     std::string id = Add(IDR_QUICKOFFICE_MANIFEST,
                          base::FilePath(FILE_PATH_LITERAL(
                              "/usr/share/chromeos-assets/quickoffice")));
     EnableFileSystemInGuestMode(id);
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
     Add(IDR_ECHO_MANIFEST,
         base::FilePath(FILE_PATH_LITERAL("/usr/share/chromeos-assets/echo")));
@@ -568,12 +569,12 @@
 #endif  // defined(OS_CHROMEOS)
   }
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #if !defined(OS_CHROMEOS)  // http://crbug.com/314799
   AddNetworkSpeechSynthesisExtension();
 #endif
 
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
   Add(IDR_CRYPTOTOKEN_MANIFEST,
       base::FilePath(FILE_PATH_LITERAL("cryptotoken")));
diff --git a/chrome/browser/extensions/component_loader.h b/chrome/browser/extensions/component_loader.h
index 77b0a1e89..de5c2d5 100644
--- a/chrome/browser/extensions/component_loader.h
+++ b/chrome/browser/extensions/component_loader.h
@@ -109,10 +109,6 @@
                                         const std::string& description_string);
 
   void AddChromeOsSpeechSynthesisExtensions();
-
-  // Loads the Kiosk Next extension or adds it to the load list. If this device
-  // doesn't support Kiosk Next, this method is a no-op.
-  void AddKioskNextExtension();
 #endif
 
   void set_ignore_whitelist_for_testing(bool value) {
diff --git a/chrome/browser/extensions/external_component_loader.cc b/chrome/browser/extensions/external_component_loader.cc
index 02ebfb5..6fbaca44 100644
--- a/chrome/browser/extensions/external_component_loader.cc
+++ b/chrome/browser/extensions/external_component_loader.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/extensions/external_component_loader.h"
 
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/component_extensions_whitelist/whitelist.h"
@@ -29,9 +30,9 @@
 
 void ExternalComponentLoader::StartLoading() {
   auto prefs = std::make_unique<base::DictionaryValue>();
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   AddExternalExtension(extension_misc::kInAppPaymentsSupportAppId, prefs.get());
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
 #if defined(OS_CHROMEOS)
   {
diff --git a/chrome/browser/extensions/external_provider_impl_unittest.cc b/chrome/browser/extensions/external_provider_impl_unittest.cc
index 27e1625..5978285 100644
--- a/chrome/browser/extensions/external_provider_impl_unittest.cc
+++ b/chrome/browser/extensions/external_provider_impl_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/path_service.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/scoped_path_override.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -160,7 +161,7 @@
 
 }  // namespace
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 TEST_F(ExternalProviderImplTest, InAppPayments) {
   InitServiceWithExternalProviders();
 
@@ -177,6 +178,6 @@
   EXPECT_TRUE(service_->IsExtensionEnabled(
       extension_misc::kInAppPaymentsSupportAppId));
 }
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/install_verifier.cc b/chrome/browser/extensions/install_verifier.cc
index ff4fa22a..96659327 100644
--- a/chrome/browser/extensions/install_verifier.cc
+++ b/chrome/browser/extensions/install_verifier.cc
@@ -16,6 +16,7 @@
 #include "base/one_shot_event.h"
 #include "base/stl_util.h"
 #include "base/trace_event/trace_event.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/extensions/extension_management.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -71,11 +72,11 @@
     return VerifyStatus::ENFORCE_STRICT;
   }
 
-#if defined(GOOGLE_CHROME_BUILD) && (defined(OS_WIN) || defined(OS_MACOSX))
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && (defined(OS_WIN) || defined(OS_MACOSX))
   VerifyStatus default_status = VerifyStatus::ENFORCE;
 #else
   VerifyStatus default_status = VerifyStatus::NONE;
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
   if (group == "EnforceStrict")
     return VerifyStatus::ENFORCE_STRICT;
diff --git a/chrome/browser/extensions/unpacked_installer.cc b/chrome/browser/extensions/unpacked_installer.cc
index c4ab305..20475a2 100644
--- a/chrome/browser/extensions/unpacked_installer.cc
+++ b/chrome/browser/extensions/unpacked_installer.cc
@@ -14,6 +14,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
+#include "build/branding_buildflags.h"
 #include "chrome/browser/extensions/extension_management.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/load_error_reporter.h"
@@ -126,7 +127,7 @@
   }
 
   if (only_allow_apps && !extension()->is_platform_app()) {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
     // Avoid crashing for users with hijacked shortcuts.
     return true;
 #else
diff --git a/chrome/browser/extensions/updater/chrome_extension_downloader_factory.cc b/chrome/browser/extensions/updater/chrome_extension_downloader_factory.cc
index 1d44065..14e579e 100644
--- a/chrome/browser/extensions/updater/chrome_extension_downloader_factory.cc
+++ b/chrome/browser/extensions/updater/chrome_extension_downloader_factory.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "base/command_line.h"
+#include "build/branding_buildflags.h"
 #include "chrome/browser/extensions/updater/extension_updater_switches.h"
 #include "chrome/browser/google/google_brand.h"
 #include "chrome/browser/profiles/profile.h"
@@ -36,12 +37,12 @@
   std::unique_ptr<ExtensionDownloader> downloader(new ExtensionDownloader(
       delegate, std::move(url_loader_factory), connector,
       required_verifier_format, profile_path));
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   std::string brand;
   google_brand::GetBrand(&brand);
   if (!google_brand::IsOrganic(brand))
     downloader->set_brand_code(brand);
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
   std::string manifest_query_params =
       UpdateQueryParams::Get(UpdateQueryParams::CRX);
   base::CommandLine* command_line =
diff --git a/chrome/browser/extensions/updater/extension_updater_unittest.cc b/chrome/browser/extensions/updater/extension_updater_unittest.cc
index 07d40ff4..440ac5d 100644
--- a/chrome/browser/extensions/updater/extension_updater_unittest.cc
+++ b/chrome/browser/extensions/updater/extension_updater_unittest.cc
@@ -31,6 +31,7 @@
 #include "base/threading/thread.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/version.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/crx_installer.h"
@@ -1914,7 +1915,7 @@
     const std::string brand_string = "brand%3D";
     EXPECT_TRUE(url2_query.find(brand_string) == std::string::npos);
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
     // Make sure the google query has a brand parameter, but only if the
     // brand is non-organic.
     if (expect_brand_code) {
diff --git a/chrome/browser/first_run/first_run_internal_posix.cc b/chrome/browser/first_run/first_run_internal_posix.cc
index ea35151..db313b4 100644
--- a/chrome/browser/first_run/first_run_internal_posix.cc
+++ b/chrome/browser/first_run/first_run_internal_posix.cc
@@ -8,6 +8,7 @@
 #include "base/files/file_util.h"
 #include "base/no_destructor.h"
 #include "base/path_service.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/first_run/first_run.h"
@@ -53,7 +54,7 @@
   if (g_forced_show_dialog_state != ForcedShowDialogState::kNotForced)
     return g_forced_show_dialog_state == ForcedShowDialogState::kForceShown;
 
-#if !defined(GOOGLE_CHROME_BUILD)
+#if !BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // On non-official builds, only --force-first-run-dialog will show the dialog.
   return false;
 #endif
diff --git a/chrome/browser/first_run/upgrade_util_win.cc b/chrome/browser/first_run/upgrade_util_win.cc
index f8fab15..97cd4d1 100644
--- a/chrome/browser/first_run/upgrade_util_win.cc
+++ b/chrome/browser/first_run/upgrade_util_win.cc
@@ -4,7 +4,9 @@
 
 #include "chrome/browser/first_run/upgrade_util.h"
 
+// Must be first.
 #include <windows.h>
+
 #include <objbase.h>
 #include <psapi.h>
 #include <shellapi.h>
@@ -27,6 +29,7 @@
 #include "base/strings/string_util.h"
 #include "base/win/registry.h"
 #include "base/win/windows_version.h"
+#include "build/branding_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/first_run/upgrade_util_win.h"
 #include "chrome/browser/shell_integration.h"
@@ -38,7 +41,7 @@
 #include "components/prefs/pref_service.h"
 #include "ui/base/ui_base_switches.h"
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #include "google_update/google_update_idl.h"
 #endif
 
@@ -52,7 +55,7 @@
 }
 
 bool InvokeGoogleUpdateForRename() {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   Microsoft::WRL::ComPtr<IProcessLauncher> ipl;
   HRESULT hr = ::CoCreateInstance(__uuidof(ProcessLauncherClass), nullptr,
                                   CLSCTX_ALL, IID_PPV_ARGS(&ipl));
@@ -86,9 +89,9 @@
   }
 
   return true;
-#else   // GOOGLE_CHROME_BUILD
+#else   // BUILDFLAG(GOOGLE_CHROME_BRANDING)
   return false;
-#endif  // GOOGLE_CHROME_BUILD
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 }
 
 }  // namespace
diff --git a/chrome/browser/history/top_sites_factory.cc b/chrome/browser/history/top_sites_factory.cc
index 79104306..ad4fccb 100644
--- a/chrome/browser/history/top_sites_factory.cc
+++ b/chrome/browser/history/top_sites_factory.cc
@@ -13,6 +13,7 @@
 #include "base/feature_list.h"
 #include "base/memory/singleton.h"
 #include "base/stl_util.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/engagement/site_engagement_service.h"
 #include "chrome/browser/engagement/site_engagement_service_factory.h"
@@ -56,7 +57,7 @@
 #if !defined(OS_ANDROID)
 // Android does not use prepopulated pages.
 const RawPrepopulatedPage kRawPrepopulatedPages[] = {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
     {
         IDS_NTP_DEFAULT_SEARCH_URL,
         IDS_NTP_DEFAULT_SEARCH_TITLE,
diff --git a/chrome/browser/mac/dock.mm b/chrome/browser/mac/dock.mm
index 85b0f78..82b3866 100644
--- a/chrome/browser/mac/dock.mm
+++ b/chrome/browser/mac/dock.mm
@@ -17,6 +17,7 @@
 #include "base/mac/scoped_cftyperef.h"
 #include "base/mac/scoped_nsautorelease_pool.h"
 #include "base/strings/sys_string_conversions.h"
+#include "build/branding_buildflags.h"
 
 extern "C" {
 
@@ -262,7 +263,7 @@
       }
     }
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
     if (app_index == NSNotFound) {
       // If this is an officially-branded Chrome (including Canary) and an
       // application matching the "other" flavor is already in the Dock, put
@@ -289,28 +290,24 @@
         }
       }
     }
-#endif  // GOOGLE_CHROME_BUILD
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
     if (app_index == NSNotFound) {
       // Put the new application after the last browser application already
       // present in the Dock.
       NSArray* other_browser_app_names =
           [NSArray arrayWithObjects:
-#if defined(GOOGLE_CHROME_BUILD)
-                                    @"Chromium.app",  // Unbranded Google Chrome
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+                       @"Chromium.app",  // Unbranded Google Chrome
 #else
-                                    @"Google Chrome.app",
-                                    @"Google Chrome Canary.app",
+                       @"Google Chrome.app", @"Google Chrome Canary.app",
 #endif
-                                    @"Safari.app",
-                                    @"Firefox.app",
-                                    @"Camino.app",
-                                    @"Opera.app",
-                                    @"OmniWeb.app",
-                                    @"WebKit.app",    // Safari nightly
-                                    @"Aurora.app",    // Firefox dev
-                                    @"Nightly.app",   // Firefox nightly
-                                    nil];
+                       @"Safari.app", @"Firefox.app", @"Camino.app",
+                       @"Opera.app", @"OmniWeb.app",
+                       @"WebKit.app",   // Safari nightly
+                       @"Aurora.app",   // Firefox dev
+                       @"Nightly.app",  // Firefox nightly
+                       nil];
       for (NSUInteger index = 0; index < [persistent_apps count]; ++index) {
         NSString* dock_app_name =
             [[persistent_app_paths objectAtIndex:index] lastPathComponent];
diff --git a/chrome/browser/mac/keystone_glue.mm b/chrome/browser/mac/keystone_glue.mm
index 157ba8fd..c5fdad6 100644
--- a/chrome/browser/mac/keystone_glue.mm
+++ b/chrome/browser/mac/keystone_glue.mm
@@ -42,7 +42,7 @@
 // Constants for the brand file (uses an external file so it can survive
 // updates to Chrome.)
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #define kStableBrandFileName @"Google Chrome Brand.plist"
 #define kCanaryBrandFileName @"Google Chrome Canary Brand.plist"
 #elif BUILDFLAG(CHROMIUM_BRANDING)
@@ -330,7 +330,7 @@
   version_info::Channel channelType = chrome::GetChannelByName(channel);
   if (channelType == version_info::Channel::STABLE) {
     channel = base::SysNSStringToUTF8(ksr::KSRegistrationRemoveExistingTag);
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
     DCHECK(chrome::GetChannelByName(channel) == version_info::Channel::STABLE)
         << "-channel name modification has side effect";
 #endif
diff --git a/chrome/browser/mac/master_prefs.mm b/chrome/browser/mac/master_prefs.mm
index 1ee7c6b..5a9bb4b04 100644
--- a/chrome/browser/mac/master_prefs.mm
+++ b/chrome/browser/mac/master_prefs.mm
@@ -6,13 +6,14 @@
 
 #include "base/files/file_util.h"
 #include "base/mac/foundation_util.h"
+#include "build/branding_buildflags.h"
 #include "chrome/common/channel_info.h"
 #include "chrome/common/chrome_paths_internal.h"
 #include "components/version_info/version_info.h"
 
 namespace {
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 // This should be NSApplicationSupportDirectory, but it has already been
 // released using NSLibraryDirectory.
 const NSSearchPathDirectory kSearchPath = NSLibraryDirectory;
@@ -22,7 +23,7 @@
 const NSSearchPathDirectory kSearchPath = NSApplicationSupportDirectory;
 const char kMasterPreferencesDirectory[] = "Chromium";
 const char kMasterPreferencesFileName[] = "Chromium Master Preferences";
-#endif  // GOOGLE_CHROME_BUILD
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
 }  // namespace
 
@@ -30,12 +31,12 @@
 namespace master_prefs {
 
 base::FilePath MasterPrefsPath() {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // Don't load master preferences for the canary.
   version_info::Channel channel = chrome::GetChannel();
   if (channel == version_info::Channel::CANARY)
     return base::FilePath();
-#endif  // GOOGLE_CHROME_BUILD
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
   // On official builds, try
   //~/Library/Application Support/Google/Chrome/Google Chrome Master Preferences
diff --git a/chrome/browser/media/cast_mirroring_service_host.cc b/chrome/browser/media/cast_mirroring_service_host.cc
index 899c8d3b..2b20146 100644
--- a/chrome/browser/media/cast_mirroring_service_host.cc
+++ b/chrome/browser/media/cast_mirroring_service_host.cc
@@ -13,6 +13,7 @@
 #include "base/optional.h"
 #include "base/single_thread_task_runner.h"
 #include "base/task/post_task.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/media/cast_remoting_connector.h"
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
@@ -20,22 +21,22 @@
 #include "chrome/browser/net/system_network_context_manager.h"
 #include "components/mirroring/browser/single_client_video_capture_host.h"
 #include "components/mirroring/mojom/cast_message_channel.mojom.h"
-#include "components/mirroring/mojom/constants.mojom.h"
 #include "components/mirroring/mojom/session_observer.mojom.h"
 #include "components/mirroring/mojom/session_parameters.mojom.h"
 #include "content/public/browser/audio_loopback_stream_creator.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/desktop_streams_registry.h"
+#include "content/public/browser/gpu_client.h"
 #include "content/public/browser/network_service_instance.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
-#include "content/public/browser/system_connector.h"
+#include "content/public/browser/service_process_host.h"
 #include "content/public/browser/video_capture_device_launcher.h"
 #include "content/public/browser/web_contents.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "services/network/public/mojom/network_service.mojom.h"
-#include "services/service_manager/public/cpp/connector.h"
+#include "services/viz/public/mojom/gpu.mojom.h"
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
 
@@ -166,7 +167,9 @@
 
 CastMirroringServiceHost::CastMirroringServiceHost(
     content::DesktopMediaID source_media_id)
-    : source_media_id_(source_media_id), resource_provider_binding_(this) {
+    : source_media_id_(source_media_id),
+      resource_provider_binding_(this),
+      gpu_client_(nullptr, base::OnTaskRunnerDeleter(nullptr)) {
   // Observe the target WebContents for Tab mirroring.
   if (source_media_id_.type == content::DesktopMediaID::TYPE_WEB_CONTENTS)
     Observe(GetContents(source_media_id_.web_contents_id));
@@ -186,9 +189,14 @@
     return;
   }
 
-  // Connect to the Mirroring Service.
-  content::GetSystemConnector()->BindInterface(mojom::kServiceName,
-                                               &mirroring_service_);
+  // Launch and connect to the Mirroring Service. The process will run until
+  // |mirroring_service_| is reset.
+  content::ServiceProcessHost::Launch(
+      mirroring_service_.BindNewPipeAndPassReceiver(),
+      content::ServiceProcessHost::Options()
+          .WithDisplayName("Mirroring Service")
+          .WithSandboxType(service_manager::SANDBOX_TYPE_UTILITY)
+          .Pass());
   mojom::ResourceProviderPtr provider;
   resource_provider_binding_.Bind(mojo::MakeRequest(&provider));
   mirroring_service_->Start(
@@ -238,6 +246,12 @@
   return gfx::Size(clamped_width, clamped_height);
 }
 
+void CastMirroringServiceHost::BindGpu(
+    mojo::PendingReceiver<viz::mojom::Gpu> receiver) {
+  gpu_client_ = content::CreateGpuClient(std::move(receiver), base::DoNothing(),
+                                         base::ThreadTaskRunnerHandle::Get());
+}
+
 void CastMirroringServiceHost::GetVideoCaptureHost(
     media::mojom::VideoCaptureHostRequest request) {
   base::PostTask(
@@ -305,6 +319,7 @@
 void CastMirroringServiceHost::WebContentsDestroyed() {
   audio_stream_creator_.reset();
   mirroring_service_.reset();
+  gpu_client_.reset();
 }
 
 void CastMirroringServiceHost::ShowCaptureIndicator() {
diff --git a/chrome/browser/media/cast_mirroring_service_host.h b/chrome/browser/media/cast_mirroring_service_host.h
index 981df711..0310cf9 100644
--- a/chrome/browser/media/cast_mirroring_service_host.h
+++ b/chrome/browser/media/cast_mirroring_service_host.h
@@ -10,6 +10,7 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
+#include "base/sequenced_task_runner.h"
 #include "components/mirroring/mojom/mirroring_service.mojom.h"
 #include "components/mirroring/mojom/mirroring_service_host.mojom.h"
 #include "components/mirroring/mojom/resource_provider.mojom.h"
@@ -18,6 +19,7 @@
 #include "content/public/browser/web_contents_observer.h"
 #include "extensions/buildflags/buildflags.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "ui/gfx/geometry/size.h"
 
 // TODO(https://crbug.com/879012): Remove the build flag. OffscreenTab should
@@ -32,6 +34,10 @@
 class WebContents;
 }  // namespace content
 
+namespace viz {
+class GpuClient;
+}
+
 namespace mirroring {
 
 // CastMirroringServiceHost starts/stops a mirroring session through Mirroring
@@ -76,6 +82,7 @@
   static gfx::Size GetClampedResolution(gfx::Size screen_resolution);
 
   // ResourceProvider implementation.
+  void BindGpu(mojo::PendingReceiver<viz::mojom::Gpu> receiver) override;
   void GetVideoCaptureHost(
       media::mojom::VideoCaptureHostRequest request) override;
   void GetNetworkContext(
@@ -113,9 +120,12 @@
   // The binding to this mojom::ResourceProvider implementation.
   mojo::Binding<mojom::ResourceProvider> resource_provider_binding_;
 
-  // The Mojo pointer that will be bound to mojom::MirroringService
-  // implementation.
-  mojom::MirroringServicePtr mirroring_service_;
+  // Connection to the remote mojom::MirroringService implementation.
+  mojo::Remote<mojom::MirroringService> mirroring_service_;
+
+  // The GpuClient associated with the Mirroring Service's GPU connection, if
+  // any.
+  std::unique_ptr<viz::GpuClient, base::OnTaskRunnerDeleter> gpu_client_;
 
   // Used to create an audio loopback stream through the Audio Service.
   std::unique_ptr<content::AudioLoopbackStreamCreator> audio_stream_creator_;
diff --git a/chrome/browser/media/cdm_storage_id_key.cc b/chrome/browser/media/cdm_storage_id_key.cc
index f2c5360..9821175 100644
--- a/chrome/browser/media/cdm_storage_id_key.cc
+++ b/chrome/browser/media/cdm_storage_id_key.cc
@@ -4,13 +4,14 @@
 
 #include "chrome/browser/media/cdm_storage_id_key.h"
 
+#include "build/branding_buildflags.h"
 #include "media/media_buildflags.h"
 
 #if !BUILDFLAG(ENABLE_CDM_STORAGE_ID)
 #error This should only be compiled if "enable_cdm_storage_id" specified.
 #endif
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #include "chrome/browser/internal/google_chrome_cdm_storage_id_key.h"
 #endif
 
diff --git a/chrome/browser/media/router/mojo/media_route_controller.cc b/chrome/browser/media/router/mojo/media_route_controller.cc
index 03fed140..da53ae5 100644
--- a/chrome/browser/media/router/mojo/media_route_controller.cc
+++ b/chrome/browser/media/router/mojo/media_route_controller.cc
@@ -121,11 +121,11 @@
       MediaRouteProviderWakeReason::ROUTE_CONTROLLER_COMMAND);
 }
 
-void MediaRouteController::OnMediaStatusUpdated(const MediaStatus& status) {
+void MediaRouteController::OnMediaStatusUpdated(mojom::MediaStatusPtr status) {
   DCHECK(is_valid_);
-  current_media_status_ = status;
+  current_media_status_ = std::move(status);
   for (Observer& observer : observers_)
-    observer.OnMediaStatusUpdated(status);
+    observer.OnMediaStatusUpdated(*current_media_status_);
 }
 
 void MediaRouteController::Invalidate() {
@@ -158,47 +158,4 @@
   observers_.RemoveObserver(observer);
 }
 
-// static
-MirroringMediaRouteController* MirroringMediaRouteController::From(
-    MediaRouteController* controller) {
-  if (!controller || controller->GetType() != RouteControllerType::kMirroring)
-    return nullptr;
-
-  return static_cast<MirroringMediaRouteController*>(controller);
-}
-
-MirroringMediaRouteController::MirroringMediaRouteController(
-    const MediaRoute::Id& route_id,
-    content::BrowserContext* context,
-    MediaRouter* router)
-    : MediaRouteController(route_id, context, router),
-      prefs_(Profile::FromBrowserContext(context)->GetPrefs()) {
-  DCHECK(prefs_);
-  media_remoting_enabled_ =
-      prefs_->GetBoolean(prefs::kMediaRouterMediaRemotingEnabled);
-}
-
-MirroringMediaRouteController::~MirroringMediaRouteController() {}
-
-RouteControllerType MirroringMediaRouteController::GetType() const {
-  return RouteControllerType::kMirroring;
-}
-
-void MirroringMediaRouteController::OnMediaStatusUpdated(
-    const MediaStatus& status) {
-  // The MRP does not set |mirroring_extra_data|. We set it here before sending
-  // it to observers.
-  latest_status_ = status;
-  latest_status_.mirroring_extra_data.emplace(media_remoting_enabled());
-  MediaRouteController::OnMediaStatusUpdated(latest_status_);
-}
-
-void MirroringMediaRouteController::SetMediaRemotingEnabled(bool enabled) {
-  // This method assumes that |latest_status_| is already set to a valid value.
-  media_remoting_enabled_ = enabled;
-  latest_status_.mirroring_extra_data.emplace(enabled);
-  prefs_->SetBoolean(prefs::kMediaRouterMediaRemotingEnabled, enabled);
-  MediaRouteController::OnMediaStatusUpdated(latest_status_);
-}
-
 }  // namespace media_router
diff --git a/chrome/browser/media/router/mojo/media_route_controller.h b/chrome/browser/media/router/mojo/media_route_controller.h
index 8ce9c8b..c2c984d8 100644
--- a/chrome/browser/media/router/mojo/media_route_controller.h
+++ b/chrome/browser/media/router/mojo/media_route_controller.h
@@ -15,8 +15,6 @@
 #include "chrome/common/media_router/mojom/media_status.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
 
-class PrefService;
-
 namespace content {
 class BrowserContext;
 }
@@ -63,7 +61,7 @@
     // Removes itself as an observer if |controller_| is still valid.
     virtual ~Observer();
 
-    virtual void OnMediaStatusUpdated(const MediaStatus& status) = 0;
+    virtual void OnMediaStatusUpdated(const mojom::MediaStatus& status) = 0;
 
     // Returns a reference to the observed MediaRouteController. The reference
     // should not be stored by any object that does not subclass ::Observer.
@@ -118,7 +116,7 @@
 
   // mojom::MediaStatusObserver:
   // Notifies |observers_| of a status update.
-  void OnMediaStatusUpdated(const MediaStatus& status) override;
+  void OnMediaStatusUpdated(mojom::MediaStatusPtr status) override;
 
   // Notifies |observers_| to dispose their references to the controller. The
   // controller gets destroyed when all the references are disposed.
@@ -130,12 +128,6 @@
 
   MediaRoute::Id route_id() const { return route_id_; }
 
-  // Returns the latest media status that the controller has been notified with.
-  // Returns a nullopt if the controller hasn't been notified yet.
-  const base::Optional<MediaStatus>& current_media_status() const {
-    return current_media_status_;
-  }
-
  protected:
   ~MediaRouteController() override;
 
@@ -194,52 +186,11 @@
   bool is_valid_ = true;
 
   // The latest media status that the controller has been notified with.
-  base::Optional<MediaStatus> current_media_status_;
+  mojom::MediaStatusPtr current_media_status_;
 
   DISALLOW_COPY_AND_ASSIGN(MediaRouteController);
 };
 
-// Controller subclass for Cast streaming mirroring routes. Responsible for:
-// (1) updating the media remoting pref according to user input
-// (2) augmenting the MediaStatus update sent by the MRP with the value from the
-//     media remoting pref.
-class MirroringMediaRouteController : public MediaRouteController {
- public:
-  // Casts |controller| to a MirroringMediaRouteController if its
-  // RouteControllerType is MIRRORING. Returns nullptr otherwise.
-  static MirroringMediaRouteController* From(MediaRouteController* controller);
-
-  MirroringMediaRouteController(const MediaRoute::Id& route_id,
-                                content::BrowserContext* context,
-                                MediaRouter* router);
-
-  // MediaRouteController
-  RouteControllerType GetType() const override;
-  void OnMediaStatusUpdated(const MediaStatus& status) override;
-
-  // Sets the media remoting pref to |enabled| and notifies the observers.
-  // Note that the MRP listens for updates on this pref value and enable/disable
-  // media remoting as needed.
-  void SetMediaRemotingEnabled(bool enabled);
-
-  bool media_remoting_enabled() const { return media_remoting_enabled_; }
-
- protected:
-  ~MirroringMediaRouteController() override;
-
- private:
-  PrefService* const prefs_;
-
-  // This is initialized from |prefs_| in the constructor and updated in
-  // |SetMediaRemotingEnabled()|. This class does not need to listen for pref
-  // changes because this is the only place where the media remoting pref value
-  // can be modified.
-  bool media_remoting_enabled_ = true;
-  MediaStatus latest_status_;
-
-  DISALLOW_COPY_AND_ASSIGN(MirroringMediaRouteController);
-};
-
 }  // namespace media_router
 
 #endif  // CHROME_BROWSER_MEDIA_ROUTER_MOJO_MEDIA_ROUTE_CONTROLLER_H_
diff --git a/chrome/browser/media/router/mojo/media_route_controller_unittest.cc b/chrome/browser/media/router/mojo/media_route_controller_unittest.cc
index ac9eccd0..734ca80a 100644
--- a/chrome/browser/media/router/mojo/media_route_controller_unittest.cc
+++ b/chrome/browser/media/router/mojo/media_route_controller_unittest.cc
@@ -29,6 +29,10 @@
 
 constexpr char kRouteId[] = "routeId";
 
+MATCHER_P(Equals, value, "") {
+  return arg.Equals(value);
+}
+
 }  // namespace
 
 class MediaRouteControllerTest : public ::testing::Test {
@@ -87,16 +91,6 @@
   DISALLOW_COPY_AND_ASSIGN(MediaRouteControllerTest);
 };
 
-class MirroringMediaRouteControllerTest : public MediaRouteControllerTest {
- public:
-  ~MirroringMediaRouteControllerTest() override {}
-
-  scoped_refptr<MediaRouteController> CreateMediaRouteController() override {
-    return base::MakeRefCounted<MirroringMediaRouteController>(
-        kRouteId, &profile_, &router_);
-  }
-};
-
 // Test that when Mojo connections are ready, calls to the Mojo controller go
 // through immediately.
 TEST_F(MediaRouteControllerTest, ForwardControllerCommands) {
@@ -163,22 +157,22 @@
   auto observer1 = CreateObserver();
   auto observer2 = CreateObserver();
 
-  MediaStatus status;
+  mojom::MediaStatus status;
   status.title = "test media status";
 
-  EXPECT_CALL(*observer_, OnMediaStatusUpdated(status));
-  EXPECT_CALL(*observer1, OnMediaStatusUpdated(status));
-  EXPECT_CALL(*observer2, OnMediaStatusUpdated(status));
-  mojo_media_status_observer_->OnMediaStatusUpdated(status);
+  EXPECT_CALL(*observer_, OnMediaStatusUpdated(Equals(status)));
+  EXPECT_CALL(*observer1, OnMediaStatusUpdated(Equals(status)));
+  EXPECT_CALL(*observer2, OnMediaStatusUpdated(Equals(status)));
+  mojo_media_status_observer_->OnMediaStatusUpdated(status.Clone());
   base::RunLoop().RunUntilIdle();
 
   observer1.reset();
   auto observer3 = CreateObserver();
 
-  EXPECT_CALL(*observer_, OnMediaStatusUpdated(status));
-  EXPECT_CALL(*observer2, OnMediaStatusUpdated(status));
-  EXPECT_CALL(*observer3, OnMediaStatusUpdated(status));
-  mojo_media_status_observer_->OnMediaStatusUpdated(status);
+  EXPECT_CALL(*observer_, OnMediaStatusUpdated(Equals(status)));
+  EXPECT_CALL(*observer2, OnMediaStatusUpdated(Equals(status)));
+  EXPECT_CALL(*observer3, OnMediaStatusUpdated(Equals(status)));
+  mojo_media_status_observer_->OnMediaStatusUpdated(status.Clone());
   base::RunLoop().RunUntilIdle();
 }
 
@@ -200,15 +194,4 @@
   EXPECT_TRUE(Mock::VerifyAndClearExpectations(&router_));
 }
 
-TEST_F(MirroringMediaRouteControllerTest, MirroringCommands) {
-  auto controller = GetController();
-  auto* mirroring_controller =
-      MirroringMediaRouteController::From(controller.get());
-
-  mirroring_controller->SetMediaRemotingEnabled(false);
-  EXPECT_FALSE(mirroring_controller->media_remoting_enabled());
-  EXPECT_FALSE(
-      profile_.GetPrefs()->GetBoolean(prefs::kMediaRouterMediaRemotingEnabled));
-}
-
 }  // 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 a7a40ed..0870cace 100644
--- a/chrome/browser/media/router/mojo/media_router_mojo_impl.cc
+++ b/chrome/browser/media/router/mojo/media_router_mojo_impl.cc
@@ -459,11 +459,8 @@
           << __func__ << ": route does not support controller: " << route_id;
       return nullptr;
     case RouteControllerType::kGeneric:
-      route_controller = new MediaRouteController(route_id, context_, this);
-      break;
     case RouteControllerType::kMirroring:
-      route_controller =
-          new MirroringMediaRouteController(route_id, context_, this);
+      route_controller = new MediaRouteController(route_id, context_, this);
       break;
   }
   DCHECK(route_controller);
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 ca20c1a..5b783af 100644
--- a/chrome/browser/media/router/providers/cast/cast_media_controller.cc
+++ b/chrome/browser/media/router/providers/cast/cast_media_controller.cc
@@ -114,12 +114,12 @@
     media_status_.can_set_volume = volume_type->GetString() != "fixed";
     media_status_.can_mute = media_status_.can_set_volume;
   }
-  observer_->OnMediaStatusUpdated(media_status_);
+  observer_->OnMediaStatusUpdated(media_status_.Clone());
 }
 
 void CastMediaController::SetMediaStatus(const base::Value& status_value) {
   UpdateMediaStatus(status_value);
-  observer_->OnMediaStatusUpdated(media_status_);
+  observer_->OnMediaStatusUpdated(media_status_.Clone());
 }
 
 base::Value CastMediaController::CreateMediaRequest(V2MessageType type) {
@@ -175,11 +175,11 @@
   if (player_state && player_state->is_string()) {
     const std::string& state = player_state->GetString();
     if (state == "PLAYING") {
-      media_status_.play_state = MediaStatus::PlayState::PLAYING;
+      media_status_.play_state = mojom::MediaStatus::PlayState::PLAYING;
     } else if (state == "PAUSED") {
-      media_status_.play_state = MediaStatus::PlayState::PAUSED;
+      media_status_.play_state = mojom::MediaStatus::PlayState::PAUSED;
     } else if (state == "BUFFERING") {
-      media_status_.play_state = MediaStatus::PlayState::BUFFERING;
+      media_status_.play_state = mojom::MediaStatus::PlayState::BUFFERING;
     }
   }
 }
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 1e523178..38eea06 100644
--- a/chrome/browser/media/router/providers/cast/cast_media_controller.h
+++ b/chrome/browser/media/router/providers/cast/cast_media_controller.h
@@ -6,7 +6,6 @@
 #define CHROME_BROWSER_MEDIA_ROUTER_PROVIDERS_CAST_CAST_MEDIA_CONTROLLER_H_
 
 #include "base/macros.h"
-#include "chrome/common/media_router/media_status.h"
 #include "chrome/common/media_router/mojom/media_controller.mojom.h"
 #include "chrome/common/media_router/mojom/media_status.mojom.h"
 #include "components/cast_channel/cast_message_util.h"
@@ -52,7 +51,7 @@
 
   const std::string sender_id_;
   ActivityRecord* const activity_;
-  MediaStatus media_status_;
+  mojom::MediaStatus media_status_;
   std::string session_id_;
   int media_session_id_;
 
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 17d92a6..f720b9b7 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
@@ -42,18 +42,18 @@
   EXPECT_EQ(kMediaSessionId, mediaSessionId->GetInt());
 }
 
-Value GetPlayerStateValue(const MediaStatus& status) {
+Value GetPlayerStateValue(const mojom::MediaStatus& status) {
   switch (status.play_state) {
-    case MediaStatus::PlayState::PLAYING:
+    case mojom::MediaStatus::PlayState::PLAYING:
       return Value("PLAYING");
-    case MediaStatus::PlayState::PAUSED:
+    case mojom::MediaStatus::PlayState::PAUSED:
       return Value("PAUSED");
-    case MediaStatus::PlayState::BUFFERING:
+    case mojom::MediaStatus::PlayState::BUFFERING:
       return Value("BUFFERING");
   }
 }
 
-Value GetSupportedMediaCommandsValue(const MediaStatus& status) {
+Value GetSupportedMediaCommandsValue(const mojom::MediaStatus& status) {
   int commands = 0;
   // |can_set_volume| and |can_mute| are not used, because the receiver volume
   // is used instead.
@@ -64,8 +64,8 @@
   return Value(commands);
 }
 
-MediaStatus CreateSampleMediaStatus() {
-  MediaStatus status;
+mojom::MediaStatus CreateSampleMediaStatus() {
+  mojom::MediaStatus status;
   status.title = "media title";
   status.can_play_pause = true;
   status.can_mute = true;
@@ -73,7 +73,7 @@
   status.can_seek = false;
   status.is_muted = false;
   status.volume = 0.7;
-  status.play_state = MediaStatus::PlayState::BUFFERING;
+  status.play_state = mojom::MediaStatus::PlayState::BUFFERING;
   status.duration = base::TimeDelta::FromSeconds(30);
   status.current_time = base::TimeDelta::FromSeconds(12);
   return status;
@@ -134,7 +134,7 @@
     SetMediaStatus(CreateSampleMediaStatus());
   }
 
-  void SetMediaStatus(const MediaStatus& status) {
+  void SetMediaStatus(const mojom::MediaStatus& status) {
     Value status_value(Value::Type::DICTIONARY);
     status_value.SetKey("mediaSessionId", Value(kMediaSessionId));
     status_value.SetKey("media", Value(Value::Type::DICTIONARY));
@@ -239,15 +239,15 @@
 }
 
 TEST_F(CastMediaControllerTest, UpdateMediaStatus) {
-  const MediaStatus expected_status = CreateSampleMediaStatus();
+  const mojom::MediaStatus expected_status = CreateSampleMediaStatus();
 
   EXPECT_CALL(*status_observer_, OnMediaStatusUpdated(_))
-      .WillOnce([&](const MediaStatus& status) {
-        EXPECT_EQ(expected_status.title, status.title);
-        EXPECT_EQ(expected_status.can_play_pause, status.can_play_pause);
-        EXPECT_EQ(expected_status.play_state, status.play_state);
-        EXPECT_EQ(expected_status.duration, status.duration);
-        EXPECT_EQ(expected_status.current_time, status.current_time);
+      .WillOnce([&](mojom::MediaStatusPtr status) {
+        EXPECT_EQ(expected_status.title, status->title);
+        EXPECT_EQ(expected_status.can_play_pause, status->can_play_pause);
+        EXPECT_EQ(expected_status.play_state, status->play_state);
+        EXPECT_EQ(expected_status.duration, status->duration);
+        EXPECT_EQ(expected_status.current_time, status->current_time);
       });
   SetMediaStatus(expected_status);
   VerifyAndClearExpectations();
@@ -260,9 +260,9 @@
   const bool session_muted =
       session->value().FindPath("receiver.volume.muted")->GetBool();
   EXPECT_CALL(*status_observer_, OnMediaStatusUpdated(_))
-      .WillOnce([&](const MediaStatus& status) {
-        EXPECT_FLOAT_EQ(session_volume, status.volume);
-        EXPECT_EQ(session_muted, status.is_muted);
+      .WillOnce([&](mojom::MediaStatusPtr status) {
+        EXPECT_FLOAT_EQ(session_volume, status->volume);
+        EXPECT_EQ(session_muted, status->is_muted);
       });
   controller_->SetSession(*session);
   VerifyAndClearExpectations();
@@ -270,11 +270,11 @@
   // The volume info is set in SetSession() rather than SetMediaStatus(), so the
   // volume info in the latter should be ignored.
   EXPECT_CALL(*status_observer_, OnMediaStatusUpdated(_))
-      .WillOnce([&](const MediaStatus& status) {
-        EXPECT_FLOAT_EQ(session_volume, status.volume);
-        EXPECT_EQ(session_muted, status.is_muted);
+      .WillOnce([&](mojom::MediaStatusPtr status) {
+        EXPECT_FLOAT_EQ(session_volume, status->volume);
+        EXPECT_EQ(session_muted, status->is_muted);
       });
-  MediaStatus updated_status = CreateSampleMediaStatus();
+  mojom::MediaStatus updated_status = CreateSampleMediaStatus();
   updated_status.volume = 0.3;
   updated_status.is_muted = true;
   SetMediaStatus(updated_status);
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 4e83fca..0da6a334 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
@@ -340,7 +340,7 @@
 
   status_.title = title;
   if (media_status_observer_)
-    media_status_observer_->OnMediaStatusUpdated(status_);
+    media_status_observer_->OnMediaStatusUpdated(status_.Clone());
 }
 
 void WiredDisplayMediaRouteProvider::Presentation::SetMojoConnections(
@@ -351,7 +351,7 @@
   media_controller_receiver_ = std::move(media_controller);
 
   media_status_observer_ = std::move(observer);
-  media_status_observer_->OnMediaStatusUpdated(status_);
+  media_status_observer_->OnMediaStatusUpdated(status_.Clone());
   media_status_observer_.set_connection_error_handler(base::BindOnce(
       &WiredDisplayMediaRouteProvider::Presentation::ResetMojoConnections,
       base::Unretained(this)));
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 a322711f0..ba0738c 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
@@ -17,7 +17,6 @@
 #include "chrome/browser/media/router/discovery/media_sink_discovery_metrics.h"
 #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/media_status.h"
 #include "chrome/common/media_router/mojom/media_router.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "ui/display/display.h"
@@ -143,7 +142,7 @@
    private:
     MediaRoute route_;
     std::unique_ptr<WiredDisplayPresentationReceiver> receiver_;
-    MediaStatus status_;
+    mojom::MediaStatus status_;
 
     // |media_controller_request| is retained but not used.
     mojo::PendingReceiver<mojom::MediaController> media_controller_receiver_;
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 062ab7f..c10f8af 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
@@ -383,8 +383,8 @@
       std::move(status_observer_ptr), base::BindOnce([](bool success) {}));
 
   EXPECT_CALL(status_observer, OnMediaStatusUpdated(_))
-      .WillOnce(Invoke([&page_title](const MediaStatus& status) {
-        EXPECT_EQ(status.title, page_title);
+      .WillOnce(Invoke([&page_title](mojom::MediaStatusPtr status) {
+        EXPECT_EQ(status->title, page_title);
       }));
   receiver_creator_.receiver()->RunTitleChangeCallback(page_title);
   base::RunLoop().RunUntilIdle();
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 ccd4fc6cb..7a89e39 100644
--- a/chrome/browser/media/router/test/media_router_mojo_test.cc
+++ b/chrome/browser/media/router/test/media_router_mojo_test.cc
@@ -34,6 +34,10 @@
 const int kTimeoutMillis = 5 * 1000;
 const uint8_t kBinaryMessage[] = {0x01, 0x02, 0x03, 0x04};
 
+MATCHER_P(Equals, value, "") {
+  return arg.Equals(value);
+}
+
 // Creates a media route whose ID is |kRouteId|.
 MediaRoute CreateMediaRoute() {
   MediaRoute route(kRouteId, MediaSource(kSource), kSinkId, kDescription, true,
@@ -403,7 +407,7 @@
 void MediaRouterMojoTest::TestCreateMediaRouteController() {
   MockMediaController media_controller;
   mojom::MediaStatusObserverPtr route_controller_as_observer;
-  MediaStatus media_status;
+  mojom::MediaStatus media_status;
   media_status.title = "test title";
 
   router()->OnRoutesUpdated(MediaRouteProviderId::EXTENSION,
@@ -440,8 +444,8 @@
 
   // The MediaRouteController should be registered with the MediaRouteProvider
   // as a MediaStatusObserver, and should also notify its own observers.
-  EXPECT_CALL(controller_observer, OnMediaStatusUpdated(media_status));
-  route_controller_as_observer->OnMediaStatusUpdated(media_status);
+  EXPECT_CALL(controller_observer, OnMediaStatusUpdated(Equals(media_status)));
+  route_controller_as_observer->OnMediaStatusUpdated(media_status.Clone());
 
   base::RunLoop().RunUntilIdle();
 }
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 b6ac450..4402d48 100644
--- a/chrome/browser/media/router/test/media_router_mojo_test.h
+++ b/chrome/browser/media/router/test/media_router_mojo_test.h
@@ -208,7 +208,7 @@
   explicit MockMediaStatusObserver(mojom::MediaStatusObserverRequest request);
   ~MockMediaStatusObserver() override;
 
-  MOCK_METHOD1(OnMediaStatusUpdated, void(const MediaStatus& status));
+  MOCK_METHOD1(OnMediaStatusUpdated, void(mojom::MediaStatusPtr status));
 
  private:
   mojo::Binding<mojom::MediaStatusObserver> binding_;
@@ -255,7 +255,7 @@
       scoped_refptr<MediaRouteController> controller);
   ~MockMediaRouteControllerObserver() override;
 
-  MOCK_METHOD1(OnMediaStatusUpdated, void(const MediaStatus& status));
+  MOCK_METHOD1(OnMediaStatusUpdated, void(const mojom::MediaStatus& status));
   MOCK_METHOD0(OnControllerInvalidated, void());
 };
 
diff --git a/chrome/browser/metrics/chrome_metrics_service_accessor_unittest.cc b/chrome/browser/metrics/chrome_metrics_service_accessor_unittest.cc
index c90cefd..acf1678 100644
--- a/chrome/browser/metrics/chrome_metrics_service_accessor_unittest.cc
+++ b/chrome/browser/metrics/chrome_metrics_service_accessor_unittest.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
 
 #include "base/macros.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/scoped_testing_local_state.h"
@@ -31,7 +32,7 @@
 };
 
 TEST_F(ChromeMetricsServiceAccessorTest, MetricsReportingEnabled) {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   const char* pref = metrics::prefs::kMetricsReportingEnabled;
   GetLocalState()->SetDefaultPrefValue(pref, base::Value(false));
 
@@ -45,7 +46,8 @@
   EXPECT_FALSE(
       ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled());
 #else
-  // Metrics Reporting is never enabled when GOOGLE_CHROME_BUILD is undefined.
+  // Metrics Reporting is never enabled when GOOGLE_CHROME_BRANDING is
+  // undefined.
   EXPECT_FALSE(
       ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled());
 #endif
diff --git a/chrome/browser/metrics/google_update_metrics_provider_win.cc b/chrome/browser/metrics/google_update_metrics_provider_win.cc
index 626fc160..71e59d90 100644
--- a/chrome/browser/metrics/google_update_metrics_provider_win.cc
+++ b/chrome/browser/metrics/google_update_metrics_provider_win.cc
@@ -11,6 +11,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "build/branding_buildflags.h"
 #include "chrome/install_static/install_details.h"
 #include "third_party/metrics_proto/system_profile.pb.h"
 
@@ -22,11 +23,11 @@
 // the macro to allow checking for successful code compilation on non-official
 // builds.
 bool IsGoogleChromeBuild() {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   return true;
 #else
   return false;
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 }
 
 void ProductDataToProto(const GoogleUpdateSettings::ProductData& product_data,
diff --git a/chrome/browser/metrics/perf/heap_collector.cc b/chrome/browser/metrics/perf/heap_collector.cc
index 57fb462..9b42e48 100644
--- a/chrome/browser/metrics/perf/heap_collector.cc
+++ b/chrome/browser/metrics/perf/heap_collector.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/metrics/perf/heap_collector.h"
 
+#include <inttypes.h>
+
 #include <memory>
 #include <string>
 #include <utility>
@@ -15,6 +17,7 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/metrics/field_trial_params.h"
+#include "base/process/launch.h"
 #include "base/process/process_handle.h"
 #include "base/rand_util.h"
 #include "base/sampling_heap_profiler/sampling_heap_profiler.h"
@@ -25,9 +28,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/system/sys_info.h"
 #include "base/task/post_task.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/metrics/perf/windowed_incognito_observer.h"
 #include "components/services/heap_profiling/public/cpp/settings.h"
 #include "third_party/metrics_proto/sampled_profile.pb.h"
 
@@ -247,22 +248,23 @@
 }
 
 HeapCollector::HeapCollector(HeapCollectionMode mode)
-    : MetricCollector(kHeapCollectorName),
-      sampling_period_bytes_(kHeapSamplingIntervalBytes),
+    : internal::MetricCollector(kHeapCollectorName, CollectionParams()),
       mode_(mode),
       is_enabled_(false),
+      sampling_period_bytes_(kHeapSamplingIntervalBytes),
       weak_factory_(this) {
-  BrowserList::AddObserver(this);
-
   if (mode_ == HeapCollectionMode::kShimLayer) {
     base::SamplingHeapProfiler::Init();
   }
 }
 
+const char* HeapCollector::ToolName() const {
+  return kHeapCollectorName;
+}
+
 HeapCollector::~HeapCollector() {
   // Disable heap sampling when the collector exits.
   DisableSampling();
-  BrowserList::RemoveObserver(this);
 }
 
 void HeapCollector::EnableSampling() {
@@ -297,9 +299,11 @@
   is_enabled_ = false;
 }
 
-void HeapCollector::Init() {
-  if (base::FeatureList::IsEnabled(heap_profiling::kOOPHeapProfilingFeature))
+void HeapCollector::SetUp() {
+  if (base::FeatureList::IsEnabled(heap_profiling::kOOPHeapProfilingFeature)) {
+    sampling_period_bytes_ = kSamplingIntervalBytes.Get();
     SetCollectionParamsFromFeatureParams();
+  }
 
   // For the tcmalloc collector, we set the sampling period every time we enable
   // it. The shim layer sampler has a separate API for starting and stopping, so
@@ -307,53 +311,33 @@
   if (mode_ == HeapCollectionMode::kShimLayer) {
     SetHeapSamplingPeriod(sampling_period_bytes_, mode_);
   }
-
-  // Enable sampling if no incognito session is active.
-  if (!BrowserList::IsIncognitoSessionActive()) {
-    EnableSampling();
-  } else {
-    DisableSampling();
-  }
-
-  MetricCollector::Init();
-}
-
-void HeapCollector::OnBrowserAdded(Browser* browser) {
-  // Pause heap sampling when an incognito session is opened.
-  if (browser->profile()->IsOffTheRecord()) {
-    DisableSampling();
-  }
-}
-
-void HeapCollector::OnBrowserRemoved(Browser* browser) {
-  // Resume heap sampling if no incognito sessions are active.
-  if (!BrowserList::IsIncognitoSessionActive()) {
-    EnableSampling();
-  }
+  EnableSampling();
 }
 
 void HeapCollector::SetCollectionParamsFromFeatureParams() {
-  sampling_period_bytes_ = kSamplingIntervalBytes.Get();
-  collection_params_.periodic_interval =
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  CollectionParams& params = collection_params();
+  params.periodic_interval =
       base::TimeDelta::FromMilliseconds(kPeriodicCollectionIntervalMs.Get());
-  collection_params_.resume_from_suspend.sampling_factor =
+  params.resume_from_suspend.sampling_factor =
       kResumeFromSuspendSamplingFactor.Get();
-  collection_params_.resume_from_suspend.max_collection_delay =
+  params.resume_from_suspend.max_collection_delay =
       base::TimeDelta::FromSeconds(kResumeFromSuspendMaxDelaySec.Get());
-  collection_params_.restore_session.sampling_factor =
-      kRestoreSessionSamplingFactor.Get();
-  collection_params_.restore_session.max_collection_delay =
+  params.restore_session.sampling_factor = kRestoreSessionSamplingFactor.Get();
+  params.restore_session.max_collection_delay =
       base::TimeDelta::FromSeconds(kRestoreSessionMaxDelaySec.Get());
 }
 
-base::WeakPtr<MetricCollector> HeapCollector::GetWeakPtr() {
+base::WeakPtr<internal::MetricCollector> HeapCollector::GetWeakPtr() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return weak_factory_.GetWeakPtr();
 }
 
 bool HeapCollector::ShouldCollect() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // Do not collect further data if we've already collected a substantial amount
   // of data, as indicated by |kCachedHeapDataProtobufSizeThreshold|.
-  if (cached_profile_data_size() >= kCachedHeapDataProtobufSizeThreshold) {
+  if (cached_data_size_ >= kCachedHeapDataProtobufSizeThreshold) {
     AddToUmaHistogram(CollectionAttemptStatus::NOT_READY_TO_COLLECT);
     return false;
   }
@@ -362,18 +346,31 @@
 
 void HeapCollector::CollectProfile(
     std::unique_ptr<SampledProfile> sampled_profile) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   if (mode_ == HeapCollectionMode::kNone)
     return;
 
-  base::Optional<base::FilePath> temp_file = DumpProfileToTempFile();
+  auto incognito_observer = WindowedIncognitoMonitor::CreateObserver();
+  // For privacy reasons, Chrome should only collect heap profiles if there is
+  // no incognito session active (or gets spawned while the profile is saved).
+  if (incognito_observer->IncognitoActive()) {
+    AddToUmaHistogram(CollectionAttemptStatus::INCOGNITO_ACTIVE);
+    return;
+  }
+
+  base::Optional<base::FilePath> temp_file =
+      DumpProfileToTempFile(std::move(incognito_observer));
   if (!temp_file)
     return;
 
-  base::CommandLine quipper = MakeQuipperCommand(temp_file.value());
-  ParseAndSaveProfile(quipper, temp_file.value(), std::move(sampled_profile));
+  auto quipper = MakeQuipperCommand(temp_file.value());
+  ParseAndSaveProfile(std::move(quipper), std::move(temp_file.value()),
+                      std::move(sampled_profile));
 }
 
-base::Optional<base::FilePath> HeapCollector::DumpProfileToTempFile() {
+base::Optional<base::FilePath> HeapCollector::DumpProfileToTempFile(
+    std::unique_ptr<WindowedIncognitoObserver> incognito_observer) {
   base::FilePath temp_path;
   if (!base::CreateTemporaryFile(&temp_path)) {
     AddToUmaHistogram(CollectionAttemptStatus::UNABLE_TO_COLLECT);
@@ -393,21 +390,47 @@
     DeleteFileAsync(temp_path);
     return base::nullopt;
   }
+  if (incognito_observer->IncognitoLaunched()) {
+    AddToUmaHistogram(CollectionAttemptStatus::INCOGNITO_LAUNCHED);
+    DeleteFileAsync(temp_path);
+    return base::nullopt;
+  }
   return base::make_optional<base::FilePath>(temp_path);
 }
 
-base::CommandLine HeapCollector::MakeQuipperCommand(
+// static
+std::unique_ptr<base::CommandLine> HeapCollector::MakeQuipperCommand(
     const base::FilePath& profile_path) {
-  base::CommandLine quipper{base::FilePath(kQuipperLocation)};
-  quipper.AppendSwitchPath(kQuipperHeapProfile, profile_path);
-  quipper.AppendSwitchASCII(kQuipperProcessPid,
-                            std::to_string(base::GetCurrentProcId()));
+  auto quipper =
+      std::make_unique<base::CommandLine>(base::FilePath(kQuipperLocation));
+  quipper->AppendSwitchPath(kQuipperHeapProfile, profile_path);
+  quipper->AppendSwitchASCII(kQuipperProcessPid,
+                             base::NumberToString(base::GetCurrentProcId()));
   return quipper;
 }
 
 void HeapCollector::ParseAndSaveProfile(
-    const base::CommandLine& parser,
-    const base::FilePath& profile_path,
+    std::unique_ptr<base::CommandLine> parser,
+    base::FilePath profile_path,
+    std::unique_ptr<SampledProfile> sampled_profile) {
+  // Parsing processor information may be expensive. Compute asynchronously
+  // in a separate thread.
+  auto task_runner = base::SequencedTaskRunnerHandle::Get();
+  base::PostTask(
+      FROM_HERE,
+      {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
+       base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
+      base::BindOnce(&HeapCollector::ParseProfileOnThreadPool, task_runner,
+                     weak_factory_.GetWeakPtr(), std::move(parser),
+                     std::move(profile_path), std::move(sampled_profile)));
+}
+
+// static
+void HeapCollector::ParseProfileOnThreadPool(
+    scoped_refptr<base::SequencedTaskRunner> task_runner,
+    base::WeakPtr<HeapCollector> heap_collector,
+    std::unique_ptr<base::CommandLine> parser,
+    base::FilePath profile_path,
     std::unique_ptr<SampledProfile> sampled_profile) {
   // We may exit due to parsing errors, so use a FileDeleter to remove the
   // temporary profile data on all paths.
@@ -415,13 +438,16 @@
 
   // Run the parser command on the profile file.
   std::string output;
-  if (!base::GetAppOutput(parser, &output)) {
-    AddToUmaHistogram(CollectionAttemptStatus::ILLEGAL_DATA_RETURNED);
+  if (!base::GetAppOutput(*parser, &output)) {
+    heap_collector->AddToUmaHistogram(
+        CollectionAttemptStatus::ILLEGAL_DATA_RETURNED);
     return;
   }
-
-  SaveSerializedPerfProto(std::move(sampled_profile),
-                          PerfProtoType::PERF_TYPE_DATA, output);
+  task_runner->PostTask(
+      FROM_HERE,
+      base::BindOnce(&HeapCollector::SaveSerializedPerfProto, heap_collector,
+                     std::move(sampled_profile), PerfProtoType::PERF_TYPE_DATA,
+                     std::move(output)));
 }
 
 }  // namespace metrics
diff --git a/chrome/browser/metrics/perf/heap_collector.h b/chrome/browser/metrics/perf/heap_collector.h
index 6494c1e..daf27408 100644
--- a/chrome/browser/metrics/perf/heap_collector.h
+++ b/chrome/browser/metrics/perf/heap_collector.h
@@ -14,10 +14,6 @@
 #include "base/optional.h"
 #include "base/sampling_heap_profiler/sampling_heap_profiler.h"
 #include "chrome/browser/metrics/perf/metric_collector.h"
-#include "chrome/browser/metrics/perf/perf_output.h"
-#include "chrome/browser/ui/browser_list_observer.h"
-
-class Browser;
 
 namespace base {
 class CommandLine;
@@ -37,42 +33,54 @@
   kShimLayer = 2,
 };
 
+class WindowedIncognitoObserver;
+
 // Enables collection of heap profiles using the tcmalloc heap sampling
 // profiler.
-class HeapCollector : public MetricCollector, public BrowserListObserver {
+class HeapCollector : public internal::MetricCollector {
  public:
   explicit HeapCollector(HeapCollectionMode mode);
-  ~HeapCollector() override;
-
-  // MetricCollector:
-  void Init() override;
 
   static HeapCollectionMode CollectionModeFromString(std::string mode);
 
+  // MetricCollector:
+  ~HeapCollector() override;
+  const char* ToolName() const override;
+
  protected:
   // MetricCollector:
-  base::WeakPtr<MetricCollector> GetWeakPtr() override;
+  void SetUp() override;
+  base::WeakPtr<internal::MetricCollector> GetWeakPtr() override;
   bool ShouldCollect() const override;
   void CollectProfile(std::unique_ptr<SampledProfile> sampled_profile) override;
 
-  // BrowserListObserver:
-  void OnBrowserAdded(Browser* browser) override;
-  void OnBrowserRemoved(Browser* browser) override;
-
   // Fetches a heap profile from tcmalloc, dumps it to a temp file, and returns
   // the path.
-  base::Optional<base::FilePath> DumpProfileToTempFile();
+  base::Optional<base::FilePath> DumpProfileToTempFile(
+      std::unique_ptr<WindowedIncognitoObserver> incognito_observer);
 
   // Generates a quipper command to parse the given profile file.
-  base::CommandLine MakeQuipperCommand(const base::FilePath& profile_path);
+  static std::unique_ptr<base::CommandLine> MakeQuipperCommand(
+      const base::FilePath& profile_path);
 
   // Executes the given command line to parse a profile stored at the given
-  // path and saves it in the given sampled profile. The given temporary profile
-  // file is removed after parsing.
-  void ParseAndSaveProfile(const base::CommandLine& parser,
-                           const base::FilePath& profile_path,
+  // path by posting an asynchronous task to the thread pool, since the parsing
+  // may be blocking.
+  void ParseAndSaveProfile(std::unique_ptr<base::CommandLine> parser,
+                           base::FilePath profile_path,
                            std::unique_ptr<SampledProfile> sampled_profile);
 
+  // Executes on the thread pool the given command line to parse a profile
+  // stored at the given path and saves it in the given sampled profile. The
+  // given temporary profile path is removed after parsing. The updated sampled
+  // profile is passed to SaveSerializedPerfProto on the given task runner.
+  static void ParseProfileOnThreadPool(
+      scoped_refptr<base::SequencedTaskRunner> task_runner,
+      base::WeakPtr<HeapCollector> heap_collector,
+      std::unique_ptr<base::CommandLine> parser,
+      base::FilePath profile_path,
+      std::unique_ptr<SampledProfile> sampled_profile);
+
   // Start and stop the collection.
   void EnableSampling();
   void DisableSampling();
@@ -84,15 +92,14 @@
   // trial parameters.
   void SetCollectionParamsFromFeatureParams();
 
+  // Heap collection mode. Thread safe.
+  const HeapCollectionMode mode_;
+
+  bool is_enabled_;
+
   // Heap sampling period.
   size_t sampling_period_bytes_;
 
-  // Heap collection mode.
-  HeapCollectionMode mode_;
-
-  // The collector state.
-  bool is_enabled_;
-
   base::WeakPtrFactory<HeapCollector> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(HeapCollector);
diff --git a/chrome/browser/metrics/perf/heap_collector_unittest.cc b/chrome/browser/metrics/perf/heap_collector_unittest.cc
index 0d78a0c..e506fe20 100644
--- a/chrome/browser/metrics/perf/heap_collector_unittest.cc
+++ b/chrome/browser/metrics/perf/heap_collector_unittest.cc
@@ -18,14 +18,12 @@
 #include "base/sampling_heap_profiler/poisson_allocation_sampler.h"
 #include "base/sampling_heap_profiler/sampling_heap_profiler.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/task/post_task.h"
+#include "base/test/bind_test_util.h"
 #include "base/test/scoped_feature_list.h"
-#include "base/test/test_simple_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/test/base/test_browser_window.h"
-#include "chrome/test/base/testing_profile.h"
+#include "chrome/browser/metrics/perf/windowed_incognito_observer.h"
 #include "components/services/heap_profiling/public/cpp/settings.h"
+#include "content/public/browser/browser_task_traits.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/metrics_proto/sampled_profile.pb.h"
@@ -129,24 +127,54 @@
   return proto;
 }
 
+// Allows testing of HeapCollector behavior when an incognito window is opened.
+class TestIncognitoObserver : public WindowedIncognitoObserver {
+ public:
+  // Factory function to create a TestIncognitoObserver object contained in a
+  // std::unique_ptr<WindowedIncognitoObserver> object. |incognito_launched|
+  // simulates the presence of an open incognito window, or the lack thereof.
+  // Used for passing observers to ParseOutputProtoIfValid().
+  static std::unique_ptr<WindowedIncognitoObserver> CreateWithIncognitoLaunched(
+      bool incognito_launched) {
+    return base::WrapUnique(new TestIncognitoObserver(incognito_launched));
+  }
+
+  bool IncognitoLaunched() const override { return incognito_launched_; }
+
+ private:
+  explicit TestIncognitoObserver(bool incognito_launched)
+      : WindowedIncognitoObserver(nullptr, 0),
+        incognito_launched_(incognito_launched) {}
+
+  bool incognito_launched_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestIncognitoObserver);
+};
+
 // Allows access to some private methods for testing.
 class TestHeapCollector : public HeapCollector {
  public:
   TestHeapCollector() : HeapCollector(HeapCollectionMode::kTcmalloc) {}
   explicit TestHeapCollector(HeapCollectionMode mode) : HeapCollector(mode) {}
 
+  using HeapCollector::AddCachedDataDelta;
   using HeapCollector::collection_params;
-  using HeapCollector::CollectProfile;
   using HeapCollector::DumpProfileToTempFile;
+  using HeapCollector::Init;
   using HeapCollector::IsEnabled;
+  using HeapCollector::IsRunning;
   using HeapCollector::MakeQuipperCommand;
   using HeapCollector::Mode;
   using HeapCollector::ParseAndSaveProfile;
+  using HeapCollector::RecordUserLogin;
+  using HeapCollector::set_profile_done_callback;
 
- private:
   DISALLOW_COPY_AND_ASSIGN(TestHeapCollector);
 };
 
+const base::TimeDelta kPeriodicCollectionInterval =
+    base::TimeDelta::FromHours(1);
+
 #if !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
 size_t HeapSamplingPeriod(const TestHeapCollector& collector) {
   CHECK_EQ(collector.Mode(), HeapCollectionMode::kTcmalloc)
@@ -163,133 +191,84 @@
 
 class HeapCollectorTest : public testing::Test {
  public:
-  HeapCollectorTest() {}
+  HeapCollectorTest()
+      : test_browser_thread_bundle_(
+            base::test::ScopedTaskEnvironment::TimeSource::MOCK_TIME) {}
 
-  // Opens a new browser window, which can be incognito, and returns a unique
-  // handle for it.
-  size_t OpenBrowserWindow(bool incognito) {
-    auto browser_window = std::make_unique<TestBrowserWindow>();
-    Profile* browser_profile =
-        incognito ? profile_->GetOffTheRecordProfile() : profile_.get();
-    Browser::CreateParams params(browser_profile, true);
-    params.type = Browser::TYPE_TABBED;
-    params.window = browser_window.get();
-    auto browser = std::make_unique<Browser>(params);
-
-    size_t handle = next_browser_id++;
-    open_browsers_[handle] =
-        std::make_pair(std::move(browser_window), std::move(browser));
-    return handle;
-  }
-
-  // Closes the browser window with the given handle.
-  void CloseBrowserWindow(size_t handle) {
-    auto it = open_browsers_.find(handle);
-    ASSERT_FALSE(it == open_browsers_.end());
-    open_browsers_.erase(it);
-  }
-
-  void SetUp() override {
-    // Instantiate a testing profile.
-    TestingProfile::Builder profile_builder;
-    profile_ = profile_builder.Build();
+  void SaveProfile(std::unique_ptr<SampledProfile> sampled_profile) {
+    cached_profile_data_.resize(cached_profile_data_.size() + 1);
+    cached_profile_data_.back().Swap(sampled_profile.get());
   }
 
   void MakeHeapCollector(HeapCollectionMode mode) {
     heap_collector_ = std::make_unique<TestHeapCollector>(mode);
+    // Set the periodic collection delay to a well known quantity, so we can
+    // fast forward the time.
+    heap_collector_->collection_params().periodic_interval =
+        kPeriodicCollectionInterval;
+    heap_collector_->set_profile_done_callback(base::BindRepeating(
+        &HeapCollectorTest::SaveProfile, base::Unretained(this)));
+
+    heap_collector_->Init();
     // HeapCollector requires the user to be logged in.
-    heap_collector_->OnUserLoggedIn();
+    heap_collector_->RecordUserLogin(base::TimeTicks::Now());
   }
 
   void TearDown() override {
     heap_collector_.reset();
-    open_browsers_.clear();
-    profile_.reset();
+    cached_profile_data_.clear();
   }
 
  protected:
-  // Needed to pass PrerenderManager's DCHECKs.
   content::TestBrowserThreadBundle test_browser_thread_bundle_;
 
-  // The associated testing browser profile.
-  std::unique_ptr<TestingProfile> profile_;
-
-  // Keep track of the open browsers and accompanying windows.
-  std::unordered_map<
-      size_t,
-      std::pair<std::unique_ptr<TestBrowserWindow>, std::unique_ptr<Browser>>>
-      open_browsers_;
-  static size_t next_browser_id;
+  std::vector<SampledProfile> cached_profile_data_;
 
   std::unique_ptr<TestHeapCollector> heap_collector_;
 
   DISALLOW_COPY_AND_ASSIGN(HeapCollectorTest);
 };
 
-size_t HeapCollectorTest::next_browser_id = 1;
+TEST_F(HeapCollectorTest, CheckTestIncognitoObserver) {
+  EXPECT_FALSE(TestIncognitoObserver::CreateWithIncognitoLaunched(false)
+                   ->IncognitoLaunched());
+  EXPECT_TRUE(TestIncognitoObserver::CreateWithIncognitoLaunched(true)
+                  ->IncognitoLaunched());
+}
 
 #if !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
 TEST_F(HeapCollectorTest, CheckSetup_Tcmalloc) {
   MakeHeapCollector(HeapCollectionMode::kTcmalloc);
-  heap_collector_->Init();
 
   // No profiles are cached on start.
-  std::vector<SampledProfile> stored_profiles;
-  EXPECT_FALSE(heap_collector_->GetSampledProfiles(&stored_profiles));
-  EXPECT_TRUE(stored_profiles.empty());
-
-  // Heap sampling is enabled when no incognito window is open.
-  size_t sampling_period = HeapSamplingPeriod(*heap_collector_);
-  EXPECT_GT(sampling_period, 0u);
-}
-
-TEST_F(HeapCollectorTest, IncognitoWindowDisablesSamplingOnInit_Tcmalloc) {
-  MakeHeapCollector(HeapCollectionMode::kTcmalloc);
-  OpenBrowserWindow(/*incognito=*/true);
-  heap_collector_->Init();
-
-  // Heap sampling is disabled when an incognito session is active.
-  size_t sampling_period = HeapSamplingPeriod(*heap_collector_);
-  EXPECT_EQ(sampling_period, 0u);
-}
-
-TEST_F(HeapCollectorTest, IncognitoWindowPausesSampling_Tcmalloc) {
-  MakeHeapCollector(HeapCollectionMode::kTcmalloc);
-  heap_collector_->Init();
+  EXPECT_TRUE(cached_profile_data_.empty());
 
   // Heap sampling is enabled.
   size_t sampling_period = HeapSamplingPeriod(*heap_collector_);
   EXPECT_GT(sampling_period, 0u);
-
-  // Opening an incognito window disables sampling.
-  auto win1 = OpenBrowserWindow(/*incognito=*/true);
-  sampling_period = HeapSamplingPeriod(*heap_collector_);
-  EXPECT_EQ(sampling_period, 0u);
-
-  // Opening a regular window doesn't resume sampling.
-  OpenBrowserWindow(/*incognito=*/false);
-  // Heap sampling is still disabled.
-  sampling_period = HeapSamplingPeriod(*heap_collector_);
-  EXPECT_EQ(sampling_period, 0u);
-
-  // Open another incognito window and close the first one.
-  auto win3 = OpenBrowserWindow(/*incognito=*/true);
-  CloseBrowserWindow(win1);
-  // Heap sampling is still disabled.
-  sampling_period = HeapSamplingPeriod(*heap_collector_);
-  EXPECT_EQ(sampling_period, 0u);
-
-  // Closing the last incognito window resumes heap sampling.
-  CloseBrowserWindow(win3);
-  // Heap sampling is enabled.
-  sampling_period = HeapSamplingPeriod(*heap_collector_);
-  EXPECT_GT(sampling_period, 0u);
 }
 
-TEST_F(HeapCollectorTest, DumpProfileToTempFile_Tcmalloc) {
+TEST_F(HeapCollectorTest, NoCollectionWhenProfileCacheFull_Tcmalloc) {
   MakeHeapCollector(HeapCollectionMode::kTcmalloc);
+  // Timer is active after login and a periodic collection is scheduled.
+  EXPECT_TRUE(heap_collector_->IsRunning());
+  // Pretend the cache is full.
+  heap_collector_->AddCachedDataDelta(4 * 1024 * 1024);
+
+  // Advance the clock by a periodic collection interval. We shouldn't find a
+  // profile because the cache is full.
+  test_browser_thread_bundle_.FastForwardBy(kPeriodicCollectionInterval);
+
+  EXPECT_TRUE(cached_profile_data_.empty());
+}
+
+TEST_F(HeapCollectorTest, DumpProfileToTempFile_NoIncognito_Tcmalloc) {
+  MakeHeapCollector(HeapCollectionMode::kTcmalloc);
+
+  auto incognito_observer =
+      TestIncognitoObserver::CreateWithIncognitoLaunched(false);
   base::Optional<base::FilePath> got_path =
-      heap_collector_->DumpProfileToTempFile();
+      heap_collector_->DumpProfileToTempFile(std::move(incognito_observer));
   // Check that we got a path.
   ASSERT_TRUE(got_path);
   // Check that the file is readable and not empty.
@@ -302,8 +281,20 @@
   ASSERT_TRUE(base::DeleteFile(got_path.value(), false));
 }
 
+TEST_F(HeapCollectorTest, DumpProfileToTempFile_IncognitoOpened_Tcmalloc) {
+  MakeHeapCollector(HeapCollectionMode::kTcmalloc);
+
+  auto incognito_observer =
+      TestIncognitoObserver::CreateWithIncognitoLaunched(true);
+  base::Optional<base::FilePath> got_path =
+      heap_collector_->DumpProfileToTempFile(std::move(incognito_observer));
+  // Check that we got a path.
+  ASSERT_FALSE(got_path);
+}
+
 TEST_F(HeapCollectorTest, ParseAndSaveProfile_Tcmalloc) {
   MakeHeapCollector(HeapCollectionMode::kTcmalloc);
+
   // Write a sample perf data proto to a temp file.
   const base::FilePath kTempProfile(
       FILE_PATH_LITERAL("/tmp/ParseAndSaveProfile.test"));
@@ -324,20 +315,19 @@
   base::CommandLine::StringVector argv;
   argv.push_back("cat");
   argv.push_back(kTempProfile.value());
-  base::CommandLine cat(argv);
+  auto cat = std::make_unique<base::CommandLine>(argv);
 
   // Run the command.
   auto sampled_profile = std::make_unique<SampledProfile>();
   sampled_profile->set_trigger_event(SampledProfile::PERIODIC_COLLECTION);
-  heap_collector_->ParseAndSaveProfile(cat, kTempProfile,
+  heap_collector_->ParseAndSaveProfile(std::move(cat), kTempProfile,
                                        std::move(sampled_profile));
+  test_browser_thread_bundle_.RunUntilIdle();
 
   // Check that the profile was cached.
-  std::vector<SampledProfile> stored_profiles;
-  EXPECT_TRUE(heap_collector_->GetSampledProfiles(&stored_profiles));
-  ASSERT_EQ(1U, stored_profiles.size());
+  ASSERT_EQ(1U, cached_profile_data_.size());
 
-  const SampledProfile& profile = stored_profiles[0];
+  const SampledProfile& profile = cached_profile_data_[0];
   EXPECT_EQ(SampledProfile::PERIODIC_COLLECTION, profile.trigger_event());
   EXPECT_TRUE(profile.has_ms_after_boot());
   EXPECT_TRUE(profile.has_ms_after_login());
@@ -346,8 +336,6 @@
   EXPECT_EQ(serialized_proto, profile.perf_data().SerializeAsString());
 
   // Check that the temp profile file is removed after pending tasks complete.
-  heap_collector_->Deactivate();
-  test_browser_thread_bundle_.RunUntilIdle();
   temp =
       base::File(kTempProfile, base::File::FLAG_OPEN | base::File::FLAG_READ);
   ASSERT_FALSE(temp.IsValid());
@@ -356,55 +344,35 @@
 
 TEST_F(HeapCollectorTest, CheckSetup_ShimLayer) {
   MakeHeapCollector(HeapCollectionMode::kShimLayer);
-  heap_collector_->Init();
 
   // No profiles are cached on start.
-  std::vector<SampledProfile> stored_profiles;
-  EXPECT_FALSE(heap_collector_->GetSampledProfiles(&stored_profiles));
-  EXPECT_TRUE(stored_profiles.empty());
-
-  EXPECT_TRUE(heap_collector_->IsEnabled());
-}
-
-TEST_F(HeapCollectorTest, IncognitoWindowDisablesSamplingOnInit_ShimLayer) {
-  MakeHeapCollector(HeapCollectionMode::kShimLayer);
-  OpenBrowserWindow(/*incognito=*/true);
-  heap_collector_->Init();
-
-  // Heap sampling is disabled when an incognito session is active.
-  EXPECT_FALSE(heap_collector_->IsEnabled());
-}
-
-TEST_F(HeapCollectorTest, IncognitoWindowPausesSampling_ShimLayer) {
-  MakeHeapCollector(HeapCollectionMode::kShimLayer);
-  heap_collector_->Init();
+  EXPECT_TRUE(cached_profile_data_.empty());
 
   // Heap sampling is enabled.
   EXPECT_TRUE(heap_collector_->IsEnabled());
-
-  // Opening an incognito window disables sampling and doesn't crash the test.
-  auto win1 = OpenBrowserWindow(/*incognito=*/true);
-  EXPECT_FALSE(heap_collector_->IsEnabled());
-
-  // Open also a regular window. Sampling still disabled.
-  OpenBrowserWindow(/*incognito=*/false);
-  EXPECT_FALSE(heap_collector_->IsEnabled());
-
-  // Open another incognito window and close the first one.
-  auto win3 = OpenBrowserWindow(/*incognito=*/true);
-  CloseBrowserWindow(win1);
-  EXPECT_FALSE(heap_collector_->IsEnabled());
-
-  // Closing the last incognito window resumes heap sampling, without
-  // crashing the test.
-  CloseBrowserWindow(win3);
-  EXPECT_TRUE(heap_collector_->IsEnabled());
 }
 
-TEST_F(HeapCollectorTest, DumpProfileToTempFile_ShimLayer) {
+TEST_F(HeapCollectorTest, NoCollectionWhenProfileCacheFull_ShimLayer) {
   MakeHeapCollector(HeapCollectionMode::kShimLayer);
+  // Timer is active after login and a periodic collection is scheduled.
+  EXPECT_TRUE(heap_collector_->IsRunning());
+  // Pretend the cache is full.
+  heap_collector_->AddCachedDataDelta(4 * 1024 * 1024);
+
+  // Advance the clock by a periodic collection interval. We shouldn't find a
+  // profile because the cache is full.
+  test_browser_thread_bundle_.FastForwardBy(kPeriodicCollectionInterval);
+
+  EXPECT_TRUE(cached_profile_data_.empty());
+}
+
+TEST_F(HeapCollectorTest, DumpProfileToTempFile_NoIncognito_ShimLayer) {
+  MakeHeapCollector(HeapCollectionMode::kShimLayer);
+
+  auto incognito_observer =
+      TestIncognitoObserver::CreateWithIncognitoLaunched(false);
   base::Optional<base::FilePath> got_path =
-      heap_collector_->DumpProfileToTempFile();
+      heap_collector_->DumpProfileToTempFile(std::move(incognito_observer));
   // Check that we got a path.
   ASSERT_TRUE(got_path);
   // Check that the file is readable and not empty.
@@ -417,25 +385,39 @@
   ASSERT_TRUE(base::DeleteFile(got_path.value(), false));
 }
 
+TEST_F(HeapCollectorTest, DumpProfileToTempFile_IncognitoOpened_ShimLayer) {
+  MakeHeapCollector(HeapCollectionMode::kShimLayer);
+
+  auto incognito_observer =
+      TestIncognitoObserver::CreateWithIncognitoLaunched(true);
+  base::Optional<base::FilePath> got_path =
+      heap_collector_->DumpProfileToTempFile(std::move(incognito_observer));
+  // Check that we got a path.
+  ASSERT_FALSE(got_path);
+}
+
 TEST_F(HeapCollectorTest, MakeQuipperCommand) {
   const base::FilePath kTempProfile(
       FILE_PATH_LITERAL("/tmp/MakeQuipperCommand.test"));
-  base::CommandLine got = heap_collector_->MakeQuipperCommand(kTempProfile);
+  std::unique_ptr<base::CommandLine> got =
+      TestHeapCollector::MakeQuipperCommand(kTempProfile);
+  ASSERT_TRUE(got);
 
   // Check that we got the correct two switch names.
-  ASSERT_EQ(got.GetSwitches().size(), 2u);
-  EXPECT_TRUE(got.HasSwitch("input_heap_profile"));
-  EXPECT_TRUE(got.HasSwitch("pid"));
+  ASSERT_EQ(got->GetSwitches().size(), 2u);
+  EXPECT_TRUE(got->HasSwitch("input_heap_profile"));
+  EXPECT_TRUE(got->HasSwitch("pid"));
 
   // Check that we got the correct program name and switch values.
-  EXPECT_EQ(got.GetProgram().value(), "/usr/bin/quipper");
-  EXPECT_EQ(got.GetSwitchValuePath("input_heap_profile"), kTempProfile);
-  EXPECT_EQ(got.GetSwitchValueASCII("pid"),
+  EXPECT_EQ(got->GetProgram().value(), "/usr/bin/quipper");
+  EXPECT_EQ(got->GetSwitchValuePath("input_heap_profile"), kTempProfile);
+  EXPECT_EQ(got->GetSwitchValueASCII("pid"),
             base::NumberToString(base::GetCurrentProcId()));
 }
 
 TEST_F(HeapCollectorTest, ParseAndSaveProfile_ShimLayer) {
   MakeHeapCollector(HeapCollectionMode::kShimLayer);
+
   // Write a sample perf data proto to a temp file.
   const base::FilePath kTempProfile(
       FILE_PATH_LITERAL("/tmp/ParseAndSaveProfile.test"));
@@ -456,20 +438,19 @@
   base::CommandLine::StringVector argv;
   argv.push_back("cat");
   argv.push_back(kTempProfile.value());
-  base::CommandLine cat(argv);
+  auto cat = std::make_unique<base::CommandLine>(argv);
 
   // Run the command.
   auto sampled_profile = std::make_unique<SampledProfile>();
   sampled_profile->set_trigger_event(SampledProfile::PERIODIC_COLLECTION);
-  heap_collector_->ParseAndSaveProfile(cat, kTempProfile,
+  heap_collector_->ParseAndSaveProfile(std::move(cat), kTempProfile,
                                        std::move(sampled_profile));
+  test_browser_thread_bundle_.RunUntilIdle();
 
   // Check that the profile was cached.
-  std::vector<SampledProfile> stored_profiles;
-  EXPECT_TRUE(heap_collector_->GetSampledProfiles(&stored_profiles));
-  ASSERT_EQ(1U, stored_profiles.size());
+  ASSERT_EQ(1U, cached_profile_data_.size());
 
-  const SampledProfile& profile = stored_profiles[0];
+  const SampledProfile& profile = cached_profile_data_[0];
   EXPECT_EQ(SampledProfile::PERIODIC_COLLECTION, profile.trigger_event());
   EXPECT_TRUE(profile.has_ms_after_boot());
   EXPECT_TRUE(profile.has_ms_after_login());
@@ -478,8 +459,6 @@
   EXPECT_EQ(serialized_proto, profile.perf_data().SerializeAsString());
 
   // Check that the temp profile file is removed after pending tasks complete.
-  heap_collector_->Deactivate();
-  test_browser_thread_bundle_.RunUntilIdle();
   temp =
       base::File(kTempProfile, base::File::FLAG_OPEN | base::File::FLAG_READ);
   ASSERT_FALSE(temp.IsValid());
@@ -487,13 +466,10 @@
 
 class HeapCollectorCollectionParamsTest : public testing::Test {
  public:
-  HeapCollectorCollectionParamsTest()
-      : task_runner_(base::MakeRefCounted<base::TestSimpleTaskRunner>()),
-        task_runner_handle_(task_runner_) {}
+  HeapCollectorCollectionParamsTest() = default;
 
- private:
-  scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
-  base::ThreadTaskRunnerHandle task_runner_handle_;
+ protected:
+  content::TestBrowserThreadBundle test_browser_thread_bundle_;
 
   DISALLOW_COPY_AND_ASSIGN(HeapCollectorCollectionParamsTest);
 };
@@ -512,11 +488,12 @@
   scoped_feature_list.InitAndEnableFeatureWithParameters(
       heap_profiling::kOOPHeapProfilingFeature, params);
 
-  TestHeapCollector heap_collector(HeapCollectionMode::kTcmalloc);
-  const auto& parsed_params = heap_collector.collection_params();
+  auto heap_collector =
+      std::make_unique<TestHeapCollector>(HeapCollectionMode::kTcmalloc);
+  const auto& parsed_params = heap_collector->collection_params();
 
   // Not initialized yet:
-  size_t sampling_period = HeapSamplingPeriod(heap_collector);
+  size_t sampling_period = HeapSamplingPeriod(*heap_collector);
   EXPECT_NE(800000u, sampling_period);
   EXPECT_NE(base::TimeDelta::FromHours(1), parsed_params.periodic_interval);
   EXPECT_NE(1, parsed_params.resume_from_suspend.sampling_factor);
@@ -526,9 +503,9 @@
   EXPECT_NE(base::TimeDelta::FromSeconds(20),
             parsed_params.restore_session.max_collection_delay);
 
-  heap_collector.Init();
+  heap_collector->Init();
 
-  sampling_period = HeapSamplingPeriod(heap_collector);
+  sampling_period = HeapSamplingPeriod(*heap_collector);
   EXPECT_EQ(800000u, sampling_period);
   EXPECT_EQ(base::TimeDelta::FromHours(1), parsed_params.periodic_interval);
   EXPECT_EQ(1, parsed_params.resume_from_suspend.sampling_factor);
@@ -553,8 +530,9 @@
   scoped_feature_list.InitAndEnableFeatureWithParameters(
       heap_profiling::kOOPHeapProfilingFeature, params);
 
-  TestHeapCollector heap_collector(HeapCollectionMode::kShimLayer);
-  const auto& parsed_params = heap_collector.collection_params();
+  auto heap_collector =
+      std::make_unique<TestHeapCollector>(HeapCollectionMode::kShimLayer);
+  const auto& parsed_params = heap_collector->collection_params();
 
   // Not initialized yet:
   EXPECT_NE(base::TimeDelta::FromHours(1), parsed_params.periodic_interval);
@@ -565,7 +543,7 @@
   EXPECT_NE(base::TimeDelta::FromSeconds(20),
             parsed_params.restore_session.max_collection_delay);
 
-  heap_collector.Init();
+  heap_collector->Init();
 
   EXPECT_EQ(base::TimeDelta::FromHours(1), parsed_params.periodic_interval);
   EXPECT_EQ(1, parsed_params.resume_from_suspend.sampling_factor);
diff --git a/chrome/browser/metrics/perf/metric_collector.cc b/chrome/browser/metrics/perf/metric_collector.cc
index 66fa361..0c257db 100644
--- a/chrome/browser/metrics/perf/metric_collector.cc
+++ b/chrome/browser/metrics/perf/metric_collector.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/metrics/perf/metric_collector.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/rand_util.h"
@@ -12,20 +14,14 @@
 
 namespace metrics {
 
+namespace internal {
+
 namespace {
 
 // Name prefix of the histogram that represents the success and various failure
 // modes for a collector.
 const char kCollectionOutcomeHistogramPrefix[] = "ChromeOS.CWP.Collect";
 
-// Name prefix of the histogram that counts the number of reports uploaded by a
-// collector.
-const char kUploadCountHistogramPrefix[] = "ChromeOS.CWP.Upload";
-
-// An upper bound on the count of reports expected to be uploaded by an UMA
-// callback.
-const int kMaxValueUploadReports = 10;
-
 // This is used to space out session restore collections in the face of several
 // notifications in a short period of time. There should be no less than this
 // much time between collections.
@@ -75,51 +71,45 @@
 
 }  // namespace
 
-MetricCollector::MetricCollector(const std::string& name)
-    : MetricCollector(name, CollectionParams()) {}
-
 MetricCollector::MetricCollector(const std::string& name,
                                  const CollectionParams& collection_params)
-    : collection_params_(collection_params) {
-  collect_uma_histogram_ =
-      std::string(kCollectionOutcomeHistogramPrefix) + name;
-  upload_uma_histogram_ = std::string(kUploadCountHistogramPrefix) + name;
+    : collection_params_(collection_params),
+      collect_uma_histogram_(std::string(kCollectionOutcomeHistogramPrefix) +
+                             name) {
+  // Allow rebinding |sequence_checker_| to the sequence the collector runs on.
+  DETACH_FROM_SEQUENCE(sequence_checker_);
 }
 
-MetricCollector::~MetricCollector() {
+MetricCollector::~MetricCollector() = default;
+
+void MetricCollector::Init() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  SetUp();
 }
 
-void MetricCollector::AddToUmaHistogram(CollectionAttemptStatus outcome) const {
-  base::UmaHistogramEnumeration(collect_uma_histogram_, outcome,
-                                CollectionAttemptStatus::NUM_OUTCOMES);
+void MetricCollector::AddCachedDataDelta(size_t delta) {
+  cached_data_size_ += delta;
 }
 
-bool MetricCollector::GetSampledProfiles(
-    std::vector<SampledProfile>* sampled_profiles) {
+void MetricCollector::ResetCachedDataSize() {
+  cached_data_size_ = 0;
+}
+
+void MetricCollector::RecordUserLogin(base::TimeTicks login_time) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  if (!ShouldUpload() || cached_profile_data_.empty()) {
-    base::UmaHistogramExactLinear(upload_uma_histogram_, 0,
-                                  kMaxValueUploadReports);
-    return false;
-  }
 
-  base::UmaHistogramExactLinear(upload_uma_histogram_,
-                                cached_profile_data_.size(),
-                                kMaxValueUploadReports);
-  sampled_profiles->insert(
-      sampled_profiles->end(),
-      std::make_move_iterator(cached_profile_data_.begin()),
-      std::make_move_iterator(cached_profile_data_.end()));
-  cached_profile_data_.clear();
-  return true;
+  login_time_ = login_time;
+  next_profiling_interval_start_ = login_time;
+  ScheduleIntervalCollection();
+}
+void MetricCollector::StopTimer() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  timer_.AbandonAndStop();
 }
 
-bool MetricCollector::ShouldUpload() const {
-  return true;
-}
-
-void MetricCollector::SuspendDone(base::TimeDelta sleep_duration) {
+void MetricCollector::ScheduleSuspendDoneCollection(
+    base::TimeDelta sleep_duration) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // Collect a profile only 1/|sampling_factor| of the time, to avoid
   // collecting too much data. (0 means disable the trigger)
   const auto& resume_params = collection_params_.resume_from_suspend;
@@ -139,22 +129,10 @@
                               GetWeakPtr(), sleep_duration, collection_delay));
 }
 
-void MetricCollector::CollectPerfDataAfterResume(
-    base::TimeDelta sleep_duration,
-    base::TimeDelta time_after_resume) {
-  // Fill out a SampledProfile protobuf that will contain the collected data.
-  auto sampled_profile = std::make_unique<SampledProfile>();
-  sampled_profile->set_trigger_event(SampledProfile::RESUME_FROM_SUSPEND);
-  sampled_profile->set_suspend_duration_ms(sleep_duration.InMilliseconds());
-  sampled_profile->set_ms_after_resume(time_after_resume.InMilliseconds());
-
-  CollectIfNecessary(std::move(sampled_profile));
-}
-
-void MetricCollector::OnSessionRestoreDone(int num_tabs_restored) {
-  // Collect a profile only 1/|sampling_factor| of the time, to
-  // avoid collecting too much data and potentially causing UI latency.
-  // (0 means disable the trigger)
+void MetricCollector::ScheduleSessionRestoreCollection(int num_tabs_restored) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  // Collect a profile only 1/|sampling_factor| of the time, to avoid
+  // collecting too much data. (0 means disable the trigger)
   const auto& restore_params = collection_params_.restore_session;
   if (restore_params.sampling_factor == 0 ||
       base::RandGenerator(restore_params.sampling_factor) != 0) {
@@ -185,6 +163,24 @@
                      GetWeakPtr(), collection_delay, num_tabs_restored));
 }
 
+void MetricCollector::AddToUmaHistogram(CollectionAttemptStatus outcome) const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  base::UmaHistogramEnumeration(collect_uma_histogram_, outcome,
+                                CollectionAttemptStatus::NUM_OUTCOMES);
+}
+
+void MetricCollector::CollectPerfDataAfterResume(
+    base::TimeDelta sleep_duration,
+    base::TimeDelta time_after_resume) {
+  // Fill out a SampledProfile protobuf that will contain the collected data.
+  auto sampled_profile = std::make_unique<SampledProfile>();
+  sampled_profile->set_trigger_event(SampledProfile::RESUME_FROM_SUSPEND);
+  sampled_profile->set_suspend_duration_ms(sleep_duration.InMilliseconds());
+  sampled_profile->set_ms_after_resume(time_after_resume.InMilliseconds());
+
+  CollectIfNecessary(std::move(sampled_profile));
+}
+
 void MetricCollector::CollectPerfDataAfterSessionRestore(
     base::TimeDelta time_after_restore,
     int num_tabs_restored) {
@@ -250,6 +246,7 @@
   // whether or not the current collection was interval-triggered. If it had
   // been another type of trigger event, the interval timer would have been
   // halted, so it makes sense to reschedule a new interval collection.
+  timer_.Stop();
   ScheduleIntervalCollection();
 }
 
@@ -257,24 +254,11 @@
   return true;
 }
 
-void MetricCollector::OnUserLoggedIn() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  const base::TimeTicks now = base::TimeTicks::Now();
-  login_time_ = now;
-  next_profiling_interval_start_ = now;
-  ScheduleIntervalCollection();
-}
-
-void MetricCollector::Deactivate() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  // Stop the timer, but leave |cached_profile_data_| intact.
-  timer_.Stop();
-}
-
 void MetricCollector::SaveSerializedPerfProto(
     std::unique_ptr<SampledProfile> sampled_profile,
     PerfProtoType type,
-    const std::string& serialized_proto) {
+    std::string serialized_proto) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (serialized_proto.empty()) {
     AddToUmaHistogram(CollectionAttemptStatus::ILLEGAL_DATA_RETURNED);
     return;
@@ -310,18 +294,11 @@
   sampled_profile->set_ms_after_login(
       (base::TimeTicks::Now() - login_time_).InMilliseconds());
 
-  // Add the collected data to the container of collected SampledProfiles.
-  cached_profile_data_.resize(cached_profile_data_.size() + 1);
-  cached_profile_data_.back().Swap(sampled_profile.get());
+  // Run |profile_done_callback_| on success.
   AddToUmaHistogram(CollectionAttemptStatus::SUCCESS);
+  profile_done_callback_.Run(std::move(sampled_profile));
 }
 
-size_t MetricCollector::cached_profile_data_size() const {
-  size_t data_size = 0;
-  for (size_t i = 0; i < cached_profile_data_.size(); ++i) {
-    data_size += cached_profile_data_[i].ByteSize();
-  }
-  return data_size;
-}
+}  // namespace internal
 
 }  // namespace metrics
diff --git a/chrome/browser/metrics/perf/metric_collector.h b/chrome/browser/metrics/perf/metric_collector.h
index 953e4087..9e862de 100644
--- a/chrome/browser/metrics/perf/metric_collector.h
+++ b/chrome/browser/metrics/perf/metric_collector.h
@@ -7,8 +7,8 @@
 
 #include <stdint.h>
 
+#include <memory>
 #include <string>
-#include <vector>
 
 #include "base/macros.h"
 #include "base/sequence_checker.h"
@@ -20,36 +20,55 @@
 
 class SampledProfile;
 
-// Provides a common interface for metric collectors with custom trigger
-// definitions.
+namespace internal {
+
+// MetricCollector implements the basic collector functionality, including the
+// scheduling and synchronization logic between the various trigger events, and
+// the profile post-processing logic. Except for the constructor that can be
+// invoked from a different thread, all its methods run on the same sequence,
+// which is enforced by a sequence checker. A collector is managed by a
+// MetricProvider, including the sequence on which it runs.
 class MetricCollector {
  public:
-  explicit MetricCollector(const std::string& name);
-  explicit MetricCollector(const std::string& name,
-                           const CollectionParams& collection_params);
+  using ProfileDoneCallback =
+      base::RepeatingCallback<void(std::unique_ptr<SampledProfile>)>;
+
+  // It may be invoked on a difference sequence than the member functions.
+  MetricCollector(const std::string& name,
+                  const CollectionParams& collection_params);
+
   virtual ~MetricCollector();
 
-  // Collector specific initialization.
-  virtual void Init() {}
+  virtual const char* ToolName() const = 0;
 
-  // Appends collected perf data protobufs to |sampled_profiles|. Clears all the
-  // stored profile data. Returns true if it wrote to |sampled_profiles|.
-  bool GetSampledProfiles(std::vector<SampledProfile>* sampled_profiles);
+  void Init();
+
+  // These methods are used to update the cached_data_size_ field via PostTask
+  // from the provider.
+  void AddCachedDataDelta(size_t delta);
+  void ResetCachedDataSize();
 
   // Turns on profile collection. Resets the timer that's used to schedule
   // collections.
-  void OnUserLoggedIn();
+  void RecordUserLogin(base::TimeTicks login_time);
 
-  // Turns off profile collection. Does not delete any data that was already
-  // collected and stored in |cached_profile_data_|.
-  void Deactivate();
+  // Deactivates the timer and turns off profile collection. Does not delete any
+  // profile data that was already collected.
+  void StopTimer();
 
-  // Called when a suspend finishes. This is a successful suspend followed by
-  // a resume.
-  void SuspendDone(base::TimeDelta sleep_duration);
+  // Schedules a collection after a resume from suspend event. A collection is
+  // scheduled with the probablity given by the sampling factor stored in
+  // |collection_params_|.
+  void ScheduleSuspendDoneCollection(base::TimeDelta sleep_duration);
 
-  // Called when a session restore has finished.
-  void OnSessionRestoreDone(int num_tabs_restored);
+  // Schedules a collection after a session restore event. A collection is
+  // scheduled with the probablity given by the sampling factor stored in
+  // |collection_params_|.
+  void ScheduleSessionRestoreCollection(int num_tabs_restored);
+
+  void set_profile_done_callback(ProfileDoneCallback cb) {
+    profile_done_callback_ = std::move(cb);
+  }
 
  protected:
   // Perf proto type.
@@ -78,14 +97,16 @@
   // Returns a WeakPtr to this instance.
   virtual base::WeakPtr<MetricCollector> GetWeakPtr() = 0;
 
+  // Collector specific initialization.
+  virtual void SetUp() {}
+
   // Saves the given outcome to the uma histogram associated with the collector.
   void AddToUmaHistogram(CollectionAttemptStatus outcome) const;
 
-  const CollectionParams& collection_params() const {
-    return collection_params_;
-  }
-
-  const base::OneShotTimer& timer() const { return timer_; }
+  // Returns whether the underlying timer is running or not.
+  bool IsRunning() { return timer_.IsRunning(); }
+  // Returns the current timer delay. Useful for debugging.
+  base::TimeDelta CurrentTimerDelay() { return timer_.GetCurrentDelay(); }
 
   base::TimeTicks login_time() const { return login_time_; }
 
@@ -102,7 +123,7 @@
                                           int num_tabs_restored);
 
   // Selects a random time in the upcoming profiling interval that begins at
-  // |next_profiling_interval_start_|. Schedules |timer_| to invoke
+  // |next_profiling_interval_start|. Schedules |timer| to invoke
   // DoPeriodicCollection() when that time comes.
   void ScheduleIntervalCollection();
 
@@ -121,32 +142,36 @@
   virtual void CollectProfile(
       std::unique_ptr<SampledProfile> sampled_profile) = 0;
 
-  // Returns if a collector should upload any profiles at this time. A collector
-  // implementation can override this logic.
-  virtual bool ShouldUpload() const;
-
   // Parses the given serialized perf proto of the given type (data or stat).
   // If valid, it adds it to the given sampled_profile and stores it in the
   // local profile data cache.
   void SaveSerializedPerfProto(std::unique_ptr<SampledProfile> sampled_profile,
                                PerfProtoType type,
-                               const std::string& serialized_proto);
+                               std::string serialized_proto);
 
-  // Returns the size of the cached profile data.
-  size_t cached_profile_data_size() const;
+  // Returns a const reference to the collection_params.
+  const CollectionParams& collection_params() const {
+    return collection_params_;
+  }
 
-  // Parameters controlling how profiles are collected.
-  CollectionParams collection_params_;
+  // Returns a mutable reference to the collection_params, so that collectors
+  // and tests can update the params.
+  CollectionParams& collection_params() { return collection_params_; }
 
+  // The size of cached profile data.
+  size_t cached_data_size_ = 0;
+
+  // Checks that some methods are called on the collector sequence.
   SEQUENCE_CHECKER(sequence_checker_);
 
  private:
+  // Parameters controlling how profiles are collected. Initialized at
+  // collector creation time. Then accessed only on the collector sequence.
+  CollectionParams collection_params_;
+
   // For scheduling collection of profile data.
   base::OneShotTimer timer_;
 
-  // Vector of SampledProfile protobufs containing perf profiles.
-  std::vector<SampledProfile> cached_profile_data_;
-
   // Record of the last login time.
   base::TimeTicks login_time_;
 
@@ -156,15 +181,18 @@
   // Tracks the last time a session restore was collected.
   base::TimeTicks last_session_restore_collection_time_;
 
-  // Name of the histogram that represents the success and various failure modes
-  // of collection attempts.
-  std::string collect_uma_histogram_;
-  // Name of the histogram that counts the number of uploaded reports.
-  std::string upload_uma_histogram_;
+  // Name of the histogram that represents the success and various failure
+  // modes of collection attempts.
+  const std::string collect_uma_histogram_;
+
+  // A callback to be Run on each successfully collected profile.
+  ProfileDoneCallback profile_done_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(MetricCollector);
 };
 
+}  // namespace internal
+
 }  // namespace metrics
 
 #endif  // CHROME_BROWSER_METRICS_PERF_METRIC_COLLECTOR_H_
diff --git a/chrome/browser/metrics/perf/metric_collector_unittest.cc b/chrome/browser/metrics/perf/metric_collector_unittest.cc
index 5120fb9c..8a1c673 100644
--- a/chrome/browser/metrics/perf/metric_collector_unittest.cc
+++ b/chrome/browser/metrics/perf/metric_collector_unittest.cc
@@ -12,8 +12,11 @@
 #include <vector>
 
 #include "base/macros.h"
-#include "base/test/test_simple_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/task/post_task.h"
+#include "base/test/bind_test_util.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/metrics_proto/sampled_profile.pb.h"
 #include "third_party/protobuf/src/google/protobuf/io/coded_stream.h"
@@ -22,6 +25,8 @@
 
 namespace metrics {
 
+namespace internal {
+
 namespace {
 
 // Returns an example PerfDataProto. The contents don't have to make sense. They
@@ -102,6 +107,11 @@
       : MetricCollector("UMA.CWP.TestData", collection_params),
         weak_factory_(this) {}
 
+  const char* ToolName() const override { return "test"; }
+  base::WeakPtr<MetricCollector> GetWeakPtr() override {
+    return weak_factory_.GetWeakPtr();
+  }
+
   void CollectProfile(
       std::unique_ptr<SampledProfile> sampled_profile) override {
     PerfDataProto perf_data_proto = GetExamplePerfDataProto();
@@ -110,56 +120,78 @@
                             perf_data_proto.SerializeAsString());
   }
 
-  base::WeakPtr<MetricCollector> GetWeakPtr() override {
-    return weak_factory_.GetWeakPtr();
-  }
-
   using MetricCollector::collection_params;
+  using MetricCollector::CurrentTimerDelay;
+  using MetricCollector::Init;
+  using MetricCollector::IsRunning;
   using MetricCollector::login_time;
   using MetricCollector::PerfProtoType;
+  using MetricCollector::RecordUserLogin;
   using MetricCollector::SaveSerializedPerfProto;
   using MetricCollector::ScheduleIntervalCollection;
-  using MetricCollector::timer;
+  using MetricCollector::ScheduleSessionRestoreCollection;
+  using MetricCollector::ScheduleSuspendDoneCollection;
+  using MetricCollector::set_profile_done_callback;
+  using MetricCollector::StopTimer;
 
  private:
-  std::vector<SampledProfile> stored_profiles_;
-
   base::WeakPtrFactory<TestMetricCollector> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(TestMetricCollector);
 };
 
+const base::TimeDelta kPeriodicCollectionInterval =
+    base::TimeDelta::FromHours(1);
+const base::TimeDelta kMaxCollectionDelay = base::TimeDelta::FromSeconds(1);
+
 }  // namespace
 
 class MetricCollectorTest : public testing::Test {
  public:
   MetricCollectorTest()
-      : task_runner_(base::MakeRefCounted<base::TestSimpleTaskRunner>()),
-        task_runner_handle_(task_runner_),
+      : test_browser_thread_bundle_(
+            base::test::ScopedTaskEnvironment::TimeSource::MOCK_TIME),
         perf_data_proto_(GetExamplePerfDataProto()),
         perf_stat_proto_(GetExamplePerfStatProto()) {}
 
+  void SaveProfile(std::unique_ptr<SampledProfile> sampled_profile) {
+    cached_profile_data_.resize(cached_profile_data_.size() + 1);
+    cached_profile_data_.back().Swap(sampled_profile.get());
+  }
+
   void SetUp() override {
     CollectionParams test_params;
     // Set the sampling factors for the triggers to 1, so we always trigger
-    // collection.
+    // collection, and set the collection delays to well known quantities, so
+    // we can fast forward the time.
     test_params.resume_from_suspend.sampling_factor = 1;
+    test_params.resume_from_suspend.max_collection_delay = kMaxCollectionDelay;
     test_params.restore_session.sampling_factor = 1;
+    test_params.restore_session.max_collection_delay = kMaxCollectionDelay;
+    test_params.periodic_interval = kPeriodicCollectionInterval;
 
     metric_collector_ = std::make_unique<TestMetricCollector>(test_params);
+    metric_collector_->set_profile_done_callback(base::BindRepeating(
+        &MetricCollectorTest::SaveProfile, base::Unretained(this)));
     metric_collector_->Init();
-
     // MetricCollector requires the user to be logged in.
-    metric_collector_->OnUserLoggedIn();
+    metric_collector_->RecordUserLogin(base::TimeTicks::Now());
   }
 
-  void TearDown() override { metric_collector_.reset(); }
+  void TearDown() override {
+    metric_collector_.reset();
+    cached_profile_data_.clear();
+  }
 
  protected:
-  std::unique_ptr<TestMetricCollector> metric_collector_;
+  // test_browser_thread_bundle_ must be the first member (or at least before
+  // any member that cares about tasks) to be initialized first and destroyed
+  // last.
+  content::TestBrowserThreadBundle test_browser_thread_bundle_;
 
-  scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
-  base::ThreadTaskRunnerHandle task_runner_handle_;
+  std::vector<SampledProfile> cached_profile_data_;
+
+  std::unique_ptr<TestMetricCollector> metric_collector_;
 
   // Store sample perf data/stat protobufs for testing.
   PerfDataProto perf_data_proto_;
@@ -173,18 +205,7 @@
   EXPECT_GT(perf_stat_proto_.ByteSize(), 0);
 
   // Timer is active after user logs in.
-  EXPECT_TRUE(metric_collector_->timer().IsRunning());
-  EXPECT_FALSE(metric_collector_->login_time().is_null());
-
-  // There are no cached profiles at start.
-  std::vector<SampledProfile> stored_profiles;
-  EXPECT_FALSE(metric_collector_->GetSampledProfiles(&stored_profiles));
-  EXPECT_TRUE(stored_profiles.empty());
-}
-
-TEST_F(MetricCollectorTest, EnabledOnLogin) {
-  metric_collector_->OnUserLoggedIn();
-  EXPECT_TRUE(metric_collector_->timer().IsRunning());
+  EXPECT_TRUE(metric_collector_->IsRunning());
   EXPECT_FALSE(metric_collector_->login_time().is_null());
 }
 
@@ -195,9 +216,9 @@
   metric_collector_->SaveSerializedPerfProto(
       std::move(sampled_profile),
       TestMetricCollector::PerfProtoType::PERF_TYPE_DATA, std::string());
+  test_browser_thread_bundle_.RunUntilIdle();
 
-  std::vector<SampledProfile> stored_profiles;
-  EXPECT_FALSE(metric_collector_->GetSampledProfiles(&stored_profiles));
+  EXPECT_TRUE(cached_profile_data_.empty());
 }
 
 TEST_F(MetricCollectorTest, PerfDataProto) {
@@ -208,12 +229,10 @@
       std::move(sampled_profile),
       TestMetricCollector::PerfProtoType::PERF_TYPE_DATA,
       perf_data_proto_.SerializeAsString());
+  test_browser_thread_bundle_.RunUntilIdle();
+  ASSERT_EQ(1U, cached_profile_data_.size());
 
-  std::vector<SampledProfile> stored_profiles;
-  EXPECT_TRUE(metric_collector_->GetSampledProfiles(&stored_profiles));
-  ASSERT_EQ(1U, stored_profiles.size());
-
-  const SampledProfile& profile = stored_profiles[0];
+  const SampledProfile& profile = cached_profile_data_[0];
   EXPECT_EQ(SampledProfile::PERIODIC_COLLECTION, profile.trigger_event());
   EXPECT_TRUE(profile.has_ms_after_boot());
   EXPECT_TRUE(profile.has_ms_after_login());
@@ -276,15 +295,15 @@
   auto sampled_profile = std::make_unique<SampledProfile>();
   sampled_profile->set_trigger_event(SampledProfile::PERIODIC_COLLECTION);
 
+  // Perf data protos are saved from the collector task runner.
   metric_collector_->SaveSerializedPerfProto(
       std::move(sampled_profile),
       TestMetricCollector::PerfProtoType::PERF_TYPE_DATA, perf_data_string);
+  test_browser_thread_bundle_.RunUntilIdle();
 
-  std::vector<SampledProfile> stored_profiles;
-  EXPECT_TRUE(metric_collector_->GetSampledProfiles(&stored_profiles));
-  ASSERT_EQ(1U, stored_profiles.size());
+  ASSERT_EQ(1U, cached_profile_data_.size());
 
-  const SampledProfile& profile = stored_profiles[0];
+  const SampledProfile& profile = cached_profile_data_[0];
   EXPECT_EQ(SampledProfile::PERIODIC_COLLECTION, profile.trigger_event());
   EXPECT_TRUE(profile.has_perf_data());
 
@@ -331,16 +350,16 @@
   auto sampled_profile = std::make_unique<SampledProfile>();
   sampled_profile->set_trigger_event(SampledProfile::PERIODIC_COLLECTION);
 
+  // Perf data protos are saved from the collector task runner.
   metric_collector_->SaveSerializedPerfProto(
       std::move(sampled_profile),
       TestMetricCollector::PerfProtoType::PERF_TYPE_STAT,
       perf_stat_proto_.SerializeAsString());
+  test_browser_thread_bundle_.RunUntilIdle();
 
-  std::vector<SampledProfile> stored_profiles;
-  EXPECT_TRUE(metric_collector_->GetSampledProfiles(&stored_profiles));
-  ASSERT_EQ(1U, stored_profiles.size());
+  ASSERT_EQ(1U, cached_profile_data_.size());
 
-  const SampledProfile& profile = stored_profiles[0];
+  const SampledProfile& profile = cached_profile_data_[0];
   EXPECT_EQ(SampledProfile::PERIODIC_COLLECTION, profile.trigger_event());
   EXPECT_TRUE(profile.has_ms_after_boot());
   EXPECT_TRUE(profile.has_ms_after_login());
@@ -356,10 +375,12 @@
   auto sampled_profile = std::make_unique<SampledProfile>();
   sampled_profile->set_trigger_event(SampledProfile::PERIODIC_COLLECTION);
 
+  // Perf data protos are saved from the collector task runner.
   metric_collector_->SaveSerializedPerfProto(
       std::move(sampled_profile),
       TestMetricCollector::PerfProtoType::PERF_TYPE_DATA,
       perf_data_proto_.SerializeAsString());
+  test_browser_thread_bundle_.RunUntilIdle();
 
   sampled_profile = std::make_unique<SampledProfile>();
   sampled_profile->set_trigger_event(SampledProfile::RESTORE_SESSION);
@@ -368,6 +389,7 @@
       std::move(sampled_profile),
       TestMetricCollector::PerfProtoType::PERF_TYPE_STAT,
       perf_stat_proto_.SerializeAsString());
+  test_browser_thread_bundle_.RunUntilIdle();
 
   sampled_profile = std::make_unique<SampledProfile>();
   sampled_profile->set_trigger_event(SampledProfile::RESUME_FROM_SUSPEND);
@@ -377,6 +399,7 @@
       std::move(sampled_profile),
       TestMetricCollector::PerfProtoType::PERF_TYPE_DATA,
       perf_data_proto_.SerializeAsString());
+  test_browser_thread_bundle_.RunUntilIdle();
 
   sampled_profile = std::make_unique<SampledProfile>();
   sampled_profile->set_trigger_event(SampledProfile::PERIODIC_COLLECTION);
@@ -384,13 +407,12 @@
       std::move(sampled_profile),
       TestMetricCollector::PerfProtoType::PERF_TYPE_STAT,
       perf_stat_proto_.SerializeAsString());
+  test_browser_thread_bundle_.RunUntilIdle();
 
-  std::vector<SampledProfile> stored_profiles;
-  EXPECT_TRUE(metric_collector_->GetSampledProfiles(&stored_profiles));
-  ASSERT_EQ(4U, stored_profiles.size());
+  ASSERT_EQ(4U, cached_profile_data_.size());
 
   {
-    const SampledProfile& profile = stored_profiles[0];
+    const SampledProfile& profile = cached_profile_data_[0];
     EXPECT_EQ(SampledProfile::PERIODIC_COLLECTION, profile.trigger_event());
     EXPECT_TRUE(profile.has_ms_after_boot());
     EXPECT_TRUE(profile.has_ms_after_login());
@@ -401,7 +423,7 @@
   }
 
   {
-    const SampledProfile& profile = stored_profiles[1];
+    const SampledProfile& profile = cached_profile_data_[1];
     EXPECT_EQ(SampledProfile::RESTORE_SESSION, profile.trigger_event());
     EXPECT_TRUE(profile.has_ms_after_boot());
     EXPECT_TRUE(profile.has_ms_after_login());
@@ -413,7 +435,7 @@
   }
 
   {
-    const SampledProfile& profile = stored_profiles[2];
+    const SampledProfile& profile = cached_profile_data_[2];
     EXPECT_EQ(SampledProfile::RESUME_FROM_SUSPEND, profile.trigger_event());
     EXPECT_TRUE(profile.has_ms_after_boot());
     EXPECT_TRUE(profile.has_ms_after_login());
@@ -426,7 +448,7 @@
   }
 
   {
-    const SampledProfile& profile = stored_profiles[3];
+    const SampledProfile& profile = cached_profile_data_[3];
     EXPECT_EQ(SampledProfile::PERIODIC_COLLECTION, profile.trigger_event());
     EXPECT_TRUE(profile.has_ms_after_boot());
     EXPECT_TRUE(profile.has_ms_after_login());
@@ -437,128 +459,132 @@
   }
 }
 
-TEST_F(MetricCollectorTest, Deactivate) {
+TEST_F(MetricCollectorTest, StopTimer) {
   auto sampled_profile = std::make_unique<SampledProfile>();
   sampled_profile->set_trigger_event(SampledProfile::PERIODIC_COLLECTION);
 
   metric_collector_->CollectProfile(std::move(sampled_profile));
+  test_browser_thread_bundle_.RunUntilIdle();
 
-  metric_collector_->OnUserLoggedIn();
-  EXPECT_TRUE(metric_collector_->timer().IsRunning());
+  EXPECT_TRUE(metric_collector_->IsRunning());
   EXPECT_FALSE(metric_collector_->login_time().is_null());
 
-  // Timer is stopped by Deactivate(), but login time and cached profiles stay.
-  metric_collector_->Deactivate();
-  EXPECT_FALSE(metric_collector_->timer().IsRunning());
+  // Timer is stopped by StopTimer(), but login time and cached profiles stay.
+  metric_collector_->StopTimer();
+  EXPECT_FALSE(metric_collector_->IsRunning());
   EXPECT_FALSE(metric_collector_->login_time().is_null());
 
-  std::vector<SampledProfile> stored_profiles;
-  EXPECT_TRUE(metric_collector_->GetSampledProfiles(&stored_profiles));
+  EXPECT_FALSE(cached_profile_data_.empty());
 }
 
-TEST_F(MetricCollectorTest, SuspendDone) {
+TEST_F(MetricCollectorTest, ScheduleSuspendDoneCollection) {
   const auto kSuspendDuration = base::TimeDelta::FromMinutes(3);
 
-  metric_collector_->SuspendDone(kSuspendDuration);
+  metric_collector_->ScheduleSuspendDoneCollection(kSuspendDuration);
 
-  // Timer is active after the SuspendDone call.
-  EXPECT_TRUE(metric_collector_->timer().IsRunning());
+  // The timer should be running at this point.
+  EXPECT_TRUE(metric_collector_->IsRunning());
 
-  // Run all pending tasks. This will run all the tasks already queued, but not
-  // any new tasks created while executing the existing pending tasks. This is
-  // important, because our collectors always queue a new periodic collection
-  // task after each collection, regardless of trigger. Thus, RunUntilIdle
-  // would never terminate.
-  task_runner_->RunPendingTasks();
+  // Fast forward the time by the max collection delay.
+  test_browser_thread_bundle_.FastForwardBy(kMaxCollectionDelay);
 
-  std::vector<SampledProfile> stored_profiles;
-  EXPECT_TRUE(metric_collector_->GetSampledProfiles(&stored_profiles));
-  ASSERT_EQ(1U, stored_profiles.size());
+  // Check that the SuspendDone trigger produced one profile.
+  ASSERT_EQ(1U, cached_profile_data_.size());
 
-  // Timer is rearmed for periodic collection after each collection.
-  EXPECT_TRUE(metric_collector_->timer().IsRunning());
-
-  const SampledProfile& profile = stored_profiles[0];
+  const SampledProfile& profile = cached_profile_data_[0];
   EXPECT_EQ(SampledProfile::RESUME_FROM_SUSPEND, profile.trigger_event());
   EXPECT_EQ(kSuspendDuration.InMilliseconds(), profile.suspend_duration_ms());
   EXPECT_TRUE(profile.has_ms_after_resume());
   EXPECT_TRUE(profile.has_ms_after_login());
   EXPECT_TRUE(profile.has_ms_after_boot());
 
-  // Run all new pending tasks. This will run a periodic collection that was
-  // scheduled by the previous collection event.
-  task_runner_->RunPendingTasks();
+  // A profile collection rearms the timer for a new perodic collection.
+  // Check that the timer is running.
+  EXPECT_TRUE(metric_collector_->IsRunning());
+  cached_profile_data_.clear();
 
-  stored_profiles.clear();
-  EXPECT_TRUE(metric_collector_->GetSampledProfiles(&stored_profiles));
-  ASSERT_EQ(1U, stored_profiles.size());
-  const SampledProfile& profile2 = stored_profiles[0];
+  // Currently, any collection from another trigger event pushes the periodic
+  // collection interval forward by kPeriodicCollectionInterval. Since we had
+  // a SuspendDone collection, we should not see any new profiles during the
+  // next periodic collection interval, but see one in the following interval.
+  test_browser_thread_bundle_.FastForwardBy(kPeriodicCollectionInterval -
+                                            kMaxCollectionDelay);
+  EXPECT_TRUE(cached_profile_data_.empty());
+
+  test_browser_thread_bundle_.FastForwardBy(kPeriodicCollectionInterval);
+
+  ASSERT_EQ(1U, cached_profile_data_.size());
+  const SampledProfile& profile2 = cached_profile_data_[0];
   EXPECT_EQ(SampledProfile::PERIODIC_COLLECTION, profile2.trigger_event());
 }
 
-TEST_F(MetricCollectorTest, OnSessionRestoreDone) {
+TEST_F(MetricCollectorTest, ScheduleSessionRestoreCollection) {
   const int kRestoredTabs = 7;
 
-  metric_collector_->OnSessionRestoreDone(kRestoredTabs);
+  metric_collector_->ScheduleSessionRestoreCollection(kRestoredTabs);
 
-  // Timer is active after the OnSessionRestoreDone call.
-  EXPECT_TRUE(metric_collector_->timer().IsRunning());
+  // The timer should be running at this point.
+  EXPECT_TRUE(metric_collector_->IsRunning());
 
-  // Run all pending tasks.
-  task_runner_->RunPendingTasks();
+  // Fast forward the time by the max collection delay.
+  test_browser_thread_bundle_.FastForwardBy(kMaxCollectionDelay);
 
-  std::vector<SampledProfile> stored_profiles;
-  EXPECT_TRUE(metric_collector_->GetSampledProfiles(&stored_profiles));
-  ASSERT_EQ(1U, stored_profiles.size());
+  ASSERT_EQ(1U, cached_profile_data_.size());
 
-  // Timer is rearmed for periodic collection after each collection.
-  EXPECT_TRUE(metric_collector_->timer().IsRunning());
-
-  const SampledProfile& profile = stored_profiles[0];
+  const SampledProfile& profile = cached_profile_data_[0];
   EXPECT_EQ(SampledProfile::RESTORE_SESSION, profile.trigger_event());
   EXPECT_EQ(kRestoredTabs, profile.num_tabs_restored());
   EXPECT_FALSE(profile.has_ms_after_resume());
   EXPECT_TRUE(profile.has_ms_after_login());
   EXPECT_TRUE(profile.has_ms_after_boot());
 
-  // A second SessionRestoreDone call is throttled.
-  metric_collector_->OnSessionRestoreDone(1);
-  // Run all new pending tasks. This will run a periodic collection, but not a
-  // second session restore.
-  task_runner_->RunPendingTasks();
+  // Timer is rearmed for periodic collection after each collection.
+  // Check that the timer is running.
+  EXPECT_TRUE(metric_collector_->IsRunning());
+  cached_profile_data_.clear();
 
-  stored_profiles.clear();
-  EXPECT_TRUE(metric_collector_->GetSampledProfiles(&stored_profiles));
-  ASSERT_EQ(1U, stored_profiles.size());
-  const SampledProfile& profile2 = stored_profiles[0];
+  // A second SessionRestoreDone call is throttled.
+  metric_collector_->ScheduleSessionRestoreCollection(1);
+
+  // Fast forward the time by the max collection delay.
+  test_browser_thread_bundle_.FastForwardBy(kMaxCollectionDelay);
+  // This should find no new session restore profiles.
+  EXPECT_TRUE(cached_profile_data_.empty());
+
+  // Currently, any collection from another trigger event pushes the periodic
+  // collection interval forward by kPeriodicCollectionInterval. Since we had
+  // a SessionRestore collection, we should not see any new profiles during the
+  // current periodic collection interval, but see one in the next interval.
+  test_browser_thread_bundle_.FastForwardBy(kPeriodicCollectionInterval -
+                                            kMaxCollectionDelay * 2);
+  EXPECT_TRUE(cached_profile_data_.empty());
+
+  // Advance clock another collection interval. We should find a profile.
+  test_browser_thread_bundle_.FastForwardBy(kPeriodicCollectionInterval);
+  ASSERT_EQ(1U, cached_profile_data_.size());
+  const SampledProfile& profile2 = cached_profile_data_[0];
   EXPECT_EQ(SampledProfile::PERIODIC_COLLECTION, profile2.trigger_event());
 
-  // Rerun any new pending tasks. This run should include a new periodic
-  // collection, but no session restore.
-  task_runner_->RunPendingTasks();
-
-  stored_profiles.clear();
-  EXPECT_TRUE(metric_collector_->GetSampledProfiles(&stored_profiles));
-  ASSERT_EQ(1U, stored_profiles.size());
-  const SampledProfile& profile3 = stored_profiles[0];
+  // Advance the clock another periodic collection interval. This run should
+  // include a new periodic collection, but no session restore.
+  cached_profile_data_.clear();
+  test_browser_thread_bundle_.FastForwardBy(kPeriodicCollectionInterval);
+  ASSERT_EQ(1U, cached_profile_data_.size());
+  const SampledProfile& profile3 = cached_profile_data_[0];
   EXPECT_EQ(SampledProfile::PERIODIC_COLLECTION, profile3.trigger_event());
 }
 
 TEST_F(MetricCollectorTest, ScheduleIntervalCollection) {
   // Timer is active after login and a periodic collection is scheduled.
-  EXPECT_TRUE(metric_collector_->timer().IsRunning());
+  EXPECT_TRUE(metric_collector_->IsRunning());
 
-  // Run all pending tasks.
-  task_runner_->RunPendingTasks();
+  // Advance the clock by a periodic collection interval. We must have a
+  // periodic collection profile.
+  test_browser_thread_bundle_.FastForwardBy(kPeriodicCollectionInterval);
 
-  std::vector<SampledProfile> stored_profiles;
-  EXPECT_TRUE(metric_collector_->GetSampledProfiles(&stored_profiles));
-  ASSERT_EQ(1U, stored_profiles.size());
+  ASSERT_EQ(1U, cached_profile_data_.size());
 
-  // Timer is rearmed after each collection.
-  EXPECT_TRUE(metric_collector_->timer().IsRunning());
-
-  const SampledProfile& profile = stored_profiles[0];
+  const SampledProfile& profile = cached_profile_data_[0];
   EXPECT_EQ(SampledProfile::PERIODIC_COLLECTION, profile.trigger_event());
   EXPECT_FALSE(profile.has_suspend_duration_ms());
   EXPECT_FALSE(profile.has_ms_after_resume());
@@ -569,6 +595,9 @@
   EXPECT_FALSE(profile.has_perf_stat());
   EXPECT_EQ(perf_data_proto_.SerializeAsString(),
             profile.perf_data().SerializeAsString());
+
+  // Make sure timer is rearmed after each collection.
+  EXPECT_TRUE(metric_collector_->IsRunning());
 }
 
 // Setting the sampling factors to zero should disable the triggers.
@@ -581,19 +610,24 @@
 
   metric_collector_ = std::make_unique<TestMetricCollector>(test_params);
   metric_collector_->Init();
+  metric_collector_->RecordUserLogin(base::TimeTicks::Now());
 
   // Cancel the background collection.
-  metric_collector_->Deactivate();
-  EXPECT_FALSE(metric_collector_->timer().IsRunning())
+  metric_collector_->StopTimer();
+
+  EXPECT_FALSE(metric_collector_->IsRunning())
       << "Sanity: timer should not be running.";
 
-  // Calling SuspendDone or OnSessionRestoreDone should not start the timer
-  // that triggers collection.
-  metric_collector_->SuspendDone(base::TimeDelta::FromMinutes(10));
-  EXPECT_FALSE(metric_collector_->timer().IsRunning());
+  // Calling ScheduleSuspendDoneCollection or ScheduleSessionRestoreCollection
+  // should not start the timer that triggers collection.
+  metric_collector_->ScheduleSuspendDoneCollection(
+      base::TimeDelta::FromMinutes(10));
+  EXPECT_FALSE(metric_collector_->IsRunning());
 
-  metric_collector_->OnSessionRestoreDone(100);
-  EXPECT_FALSE(metric_collector_->timer().IsRunning());
+  metric_collector_->ScheduleSessionRestoreCollection(100);
+  EXPECT_FALSE(metric_collector_->IsRunning());
 }
 
+}  // namespace internal
+
 }  // namespace metrics
diff --git a/chrome/browser/metrics/perf/metric_provider.cc b/chrome/browser/metrics/perf/metric_provider.cc
new file mode 100644
index 0000000..70605a0
--- /dev/null
+++ b/chrome/browser/metrics/perf/metric_provider.cc
@@ -0,0 +1,147 @@
+// 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/metrics/perf/metric_provider.h"
+
+#include "base/bind.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "third_party/metrics_proto/sampled_profile.pb.h"
+
+namespace metrics {
+
+namespace {
+
+// Name prefix of the histogram that counts the number of reports uploaded by a
+// metric provider.
+const char kUploadCountHistogramPrefix[] = "ChromeOS.CWP.Upload";
+
+// An upper bound on the count of reports expected to be uploaded by an UMA
+// callback.
+const int kMaxValueUploadReports = 10;
+
+}  // namespace
+
+using MetricCollector = internal::MetricCollector;
+
+MetricProvider::MetricProvider(std::unique_ptr<MetricCollector> collector)
+    : upload_uma_histogram_(std::string(kUploadCountHistogramPrefix) +
+                            collector->ToolName()),
+      // Run the collector at a higher priority to enable fast triggering of
+      // profile collections. In particular, we want fast triggering when
+      // jankiness is detected, but even random based periodic collection
+      // benefits from a higher priority, to avoid biasing the collection to
+      // times when the system is not busy. The work performed on the dedicated
+      // sequence is short and infrequent. Expensive parsing operations are
+      // executed asynchronously on the thread pool.
+      collector_task_runner_(
+          base::CreateSequencedTaskRunner({base::TaskPriority::USER_VISIBLE})),
+      metric_collector_(std::move(collector)),
+      weak_factory_(this) {
+  metric_collector_->set_profile_done_callback(base::BindRepeating(
+      &MetricProvider::OnProfileDone, weak_factory_.GetWeakPtr()));
+}
+
+MetricProvider::~MetricProvider() {
+  // Destroy the metric_collector_ on the collector sequence.
+  collector_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce([](std::unique_ptr<MetricCollector> collector_) {},
+                     std::move(metric_collector_)));
+}
+
+void MetricProvider::Init() {
+  // It is safe to use base::Unretained to post tasks to the metric_collector_
+  // on the collector sequence, since we control its lifetime. Any tasks
+  // posted to it are bound to run before we destroy it on the collector
+  // sequence.
+  collector_task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&MetricCollector::Init,
+                                base::Unretained(metric_collector_.get())));
+}
+
+bool MetricProvider::GetSampledProfiles(
+    std::vector<SampledProfile>* sampled_profiles) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  if (cached_profile_data_.empty()) {
+    base::UmaHistogramExactLinear(upload_uma_histogram_, 0,
+                                  kMaxValueUploadReports);
+    return false;
+  }
+
+  base::UmaHistogramExactLinear(upload_uma_histogram_,
+                                cached_profile_data_.size(),
+                                kMaxValueUploadReports);
+  sampled_profiles->insert(
+      sampled_profiles->end(),
+      std::make_move_iterator(cached_profile_data_.begin()),
+      std::make_move_iterator(cached_profile_data_.end()));
+  collector_task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&MetricCollector::ResetCachedDataSize,
+                                base::Unretained(metric_collector_.get())));
+  cached_profile_data_.clear();
+  return true;
+}
+
+void MetricProvider::OnUserLoggedIn() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  const base::TimeTicks now = base::TimeTicks::Now();
+  collector_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&MetricCollector::RecordUserLogin,
+                     base::Unretained(metric_collector_.get()), now));
+}
+
+void MetricProvider::Deactivate() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  // Notifies the collector to turn off the timer. Does not delete any data that
+  // was already collected and stored in |cached_profile_data|.
+  collector_task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&MetricCollector::StopTimer,
+                                base::Unretained(metric_collector_.get())));
+}
+
+void MetricProvider::SuspendDone(base::TimeDelta sleep_duration) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  collector_task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&MetricCollector::ScheduleSuspendDoneCollection,
+                                base::Unretained(metric_collector_.get()),
+                                sleep_duration));
+}
+
+void MetricProvider::OnSessionRestoreDone(int num_tabs_restored) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  collector_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&MetricCollector::ScheduleSessionRestoreCollection,
+                     base::Unretained(metric_collector_.get()),
+                     num_tabs_restored));
+}
+
+// static
+void MetricProvider::OnProfileDone(
+    base::WeakPtr<MetricProvider> provider,
+    std::unique_ptr<SampledProfile> sampled_profile) {
+  base::PostTask(FROM_HERE, base::TaskTraits(content::BrowserThread::UI),
+                 base::BindOnce(&MetricProvider::AddProfileToCache, provider,
+                                std::move(sampled_profile)));
+}
+
+void MetricProvider::AddProfileToCache(
+    std::unique_ptr<SampledProfile> sampled_profile) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  collector_task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&MetricCollector::AddCachedDataDelta,
+                                base::Unretained(metric_collector_.get()),
+                                sampled_profile->ByteSize()));
+  cached_profile_data_.resize(cached_profile_data_.size() + 1);
+  cached_profile_data_.back().Swap(sampled_profile.get());
+}
+
+}  // namespace metrics
diff --git a/chrome/browser/metrics/perf/metric_provider.h b/chrome/browser/metrics/perf/metric_provider.h
new file mode 100644
index 0000000..64ef76d3
--- /dev/null
+++ b/chrome/browser/metrics/perf/metric_provider.h
@@ -0,0 +1,86 @@
+// 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_METRICS_PERF_METRIC_PROVIDER_H_
+#define CHROME_BROWSER_METRICS_PERF_METRIC_PROVIDER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/metrics/perf/metric_collector.h"
+
+namespace base {
+class TimeDelta;
+}  // namespace base
+
+namespace metrics {
+
+class SampledProfile;
+
+// MetricProvider manages a metric collector implementation and provides a
+// common interface for metric collectors with custom trigger definitions.
+// The provider runs its collector on a dedicated sequence. Trigger events
+// received on the UI or other threads, are passed to the managed collector
+// on its dedicated sequence, via PostTask messages.
+class MetricProvider {
+ public:
+  explicit MetricProvider(std::unique_ptr<internal::MetricCollector> collector);
+
+  ~MetricProvider();
+
+  void Init();
+
+  // Appends collected perf data protobufs to |sampled_profiles|. Clears all the
+  // stored profile data. Returns true if it wrote to |sampled_profiles|.
+  bool GetSampledProfiles(std::vector<SampledProfile>* sampled_profiles);
+
+  // Called on a user log in event.
+  void OnUserLoggedIn();
+
+  // Turns off profile collection. Called also on a user logout event.
+  void Deactivate();
+
+  // Called when a suspend finishes. This is a successful suspend followed by
+  // a resume.
+  void SuspendDone(base::TimeDelta sleep_duration);
+
+  // Called when a session restore has finished.
+  void OnSessionRestoreDone(int num_tabs_restored);
+
+ private:
+  // Callback invoked by the collector on every successful profile capture. It
+  // may be invoked on any sequence.
+  static void OnProfileDone(base::WeakPtr<MetricProvider> provider,
+                            std::unique_ptr<SampledProfile> sampled_profile);
+
+  // Saves a profile to the local cache.
+  void AddProfileToCache(std::unique_ptr<SampledProfile> sampled_profile);
+
+  // Vector of SampledProfile protobufs containing perf profiles.
+  std::vector<SampledProfile> cached_profile_data_;
+
+  // Name of the histogram that counts the number of uploaded reports.
+  const std::string upload_uma_histogram_;
+
+  // Use a dedicated sequence for the collector. Thread safe. Initialized at
+  // construction time, then immutable.
+  const scoped_refptr<base::SequencedTaskRunner> collector_task_runner_;
+
+  // The metric collector implementation. It is destroyed on the collector
+  // sequence after all non-delayed tasks posted by the provider to the sequence
+  // have executed.
+  std::unique_ptr<internal::MetricCollector> metric_collector_;
+
+  base::WeakPtrFactory<MetricProvider> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(MetricProvider);
+};
+
+}  // namespace metrics
+
+#endif  // CHROME_BROWSER_METRICS_PERF_METRIC_PROVIDER_H_
diff --git a/chrome/browser/metrics/perf/metric_provider_unittest.cc b/chrome/browser/metrics/perf/metric_provider_unittest.cc
new file mode 100644
index 0000000..7139496d
--- /dev/null
+++ b/chrome/browser/metrics/perf/metric_provider_unittest.cc
@@ -0,0 +1,217 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/metrics/perf/metric_provider.h"
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/test/bind_test_util.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/metrics_proto/sampled_profile.pb.h"
+
+namespace metrics {
+
+namespace {
+
+// Returns an example PerfDataProto. The contents don't have to make sense. They
+// just need to constitute a semantically valid protobuf.
+// |proto| is an output parameter that will contain the created protobuf.
+PerfDataProto GetExamplePerfDataProto() {
+  PerfDataProto proto;
+  proto.set_timestamp_sec(1435604013);  // Time since epoch in seconds.
+
+  PerfDataProto_PerfFileAttr* file_attr = proto.add_file_attrs();
+  file_attr->add_ids(61);
+  file_attr->add_ids(62);
+  file_attr->add_ids(63);
+
+  PerfDataProto_PerfEventAttr* attr = file_attr->mutable_attr();
+  attr->set_type(1);
+  attr->set_size(2);
+  attr->set_config(3);
+  attr->set_sample_period(4);
+  attr->set_sample_freq(5);
+
+  PerfDataProto_PerfEventStats* stats = proto.mutable_stats();
+  stats->set_num_events_read(100);
+  stats->set_num_sample_events(200);
+  stats->set_num_mmap_events(300);
+  stats->set_num_fork_events(400);
+  stats->set_num_exit_events(500);
+
+  return proto;
+}
+
+// Allows access to some private methods for testing.
+class TestMetricCollector : public internal::MetricCollector {
+ public:
+  TestMetricCollector() : TestMetricCollector(CollectionParams()) {}
+  explicit TestMetricCollector(const CollectionParams& collection_params)
+      : internal::MetricCollector("UMA.CWP.TestData", collection_params),
+        weak_factory_(this) {}
+
+  const char* ToolName() const override { return "test"; }
+  base::WeakPtr<internal::MetricCollector> GetWeakPtr() override {
+    return weak_factory_.GetWeakPtr();
+  }
+
+  void CollectProfile(
+      std::unique_ptr<SampledProfile> sampled_profile) override {
+    PerfDataProto perf_data_proto = GetExamplePerfDataProto();
+    SaveSerializedPerfProto(std::move(sampled_profile),
+                            PerfProtoType::PERF_TYPE_DATA,
+                            perf_data_proto.SerializeAsString());
+  }
+
+ private:
+  base::WeakPtrFactory<TestMetricCollector> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestMetricCollector);
+};
+
+const base::TimeDelta kPeriodicCollectionInterval =
+    base::TimeDelta::FromHours(1);
+const base::TimeDelta kMaxCollectionDelay = base::TimeDelta::FromSeconds(1);
+
+}  // namespace
+
+class MetricProviderTest : public testing::Test {
+ public:
+  MetricProviderTest()
+      : test_browser_thread_bundle_(
+            base::test::ScopedTaskEnvironment::TimeSource::MOCK_TIME) {}
+
+  void SetUp() override {
+    CollectionParams test_params;
+    // Set the sampling factors for the triggers to 1, so we always trigger
+    // collection, and set the collection delays to well known quantities, so
+    // we can fast forward the time.
+    test_params.resume_from_suspend.sampling_factor = 1;
+    test_params.resume_from_suspend.max_collection_delay = kMaxCollectionDelay;
+    test_params.restore_session.sampling_factor = 1;
+    test_params.restore_session.max_collection_delay = kMaxCollectionDelay;
+    test_params.periodic_interval = kPeriodicCollectionInterval;
+
+    metric_provider_ = std::make_unique<MetricProvider>(
+        std::make_unique<TestMetricCollector>(test_params));
+    metric_provider_->Init();
+    test_browser_thread_bundle_.RunUntilIdle();
+  }
+
+  void TearDown() override { metric_provider_.reset(); }
+
+ protected:
+  // test_browser_thread_bundle_ must be the first member (or at least before
+  // any member that cares about tasks) to be initialized first and destroyed
+  // last.
+  content::TestBrowserThreadBundle test_browser_thread_bundle_;
+
+  std::unique_ptr<MetricProvider> metric_provider_;
+
+  DISALLOW_COPY_AND_ASSIGN(MetricProviderTest);
+};
+
+TEST_F(MetricProviderTest, CheckSetup) {
+  // There are no cached profiles at start.
+  std::vector<SampledProfile> stored_profiles;
+  EXPECT_FALSE(metric_provider_->GetSampledProfiles(&stored_profiles));
+  EXPECT_TRUE(stored_profiles.empty());
+}
+
+TEST_F(MetricProviderTest, DisabledBeforeLogin) {
+  test_browser_thread_bundle_.FastForwardBy(kPeriodicCollectionInterval);
+
+  // There are no cached profiles after a profiling interval.
+  std::vector<SampledProfile> stored_profiles;
+  EXPECT_FALSE(metric_provider_->GetSampledProfiles(&stored_profiles));
+  EXPECT_TRUE(stored_profiles.empty());
+}
+
+TEST_F(MetricProviderTest, EnabledOnLogin) {
+  metric_provider_->OnUserLoggedIn();
+  test_browser_thread_bundle_.FastForwardBy(kPeriodicCollectionInterval);
+
+  // We should find a cached PERIODIC_COLLECTION profile after a profiling
+  // interval.
+  std::vector<SampledProfile> stored_profiles;
+  EXPECT_TRUE(metric_provider_->GetSampledProfiles(&stored_profiles));
+  EXPECT_EQ(stored_profiles.size(), 1u);
+
+  const SampledProfile& profile = stored_profiles[0];
+  EXPECT_EQ(SampledProfile::PERIODIC_COLLECTION, profile.trigger_event());
+  EXPECT_FALSE(profile.has_suspend_duration_ms());
+  EXPECT_FALSE(profile.has_ms_after_resume());
+  EXPECT_TRUE(profile.has_ms_after_login());
+  EXPECT_TRUE(profile.has_ms_after_boot());
+}
+
+TEST_F(MetricProviderTest, DisabledOnDeactivate) {
+  metric_provider_->OnUserLoggedIn();
+  test_browser_thread_bundle_.RunUntilIdle();
+
+  metric_provider_->Deactivate();
+  test_browser_thread_bundle_.FastForwardBy(kPeriodicCollectionInterval);
+
+  // There are no cached profiles after a profiling interval.
+  std::vector<SampledProfile> stored_profiles;
+  EXPECT_FALSE(metric_provider_->GetSampledProfiles(&stored_profiles));
+  EXPECT_TRUE(stored_profiles.empty());
+}
+
+TEST_F(MetricProviderTest, SuspendDone) {
+  metric_provider_->OnUserLoggedIn();
+  test_browser_thread_bundle_.RunUntilIdle();
+
+  const auto kSuspendDuration = base::TimeDelta::FromMinutes(3);
+
+  metric_provider_->SuspendDone(kSuspendDuration);
+
+  // Fast forward the time by the max collection delay.
+  test_browser_thread_bundle_.FastForwardBy(kMaxCollectionDelay);
+
+  // Check that the SuspendDone trigger produced one profile.
+  std::vector<SampledProfile> stored_profiles;
+  EXPECT_TRUE(metric_provider_->GetSampledProfiles(&stored_profiles));
+  ASSERT_EQ(1U, stored_profiles.size());
+
+  const SampledProfile& profile = stored_profiles[0];
+  EXPECT_EQ(SampledProfile::RESUME_FROM_SUSPEND, profile.trigger_event());
+  EXPECT_EQ(kSuspendDuration.InMilliseconds(), profile.suspend_duration_ms());
+  EXPECT_TRUE(profile.has_ms_after_resume());
+  EXPECT_TRUE(profile.has_ms_after_login());
+  EXPECT_TRUE(profile.has_ms_after_boot());
+}
+
+TEST_F(MetricProviderTest, OnSessionRestoreDone) {
+  metric_provider_->OnUserLoggedIn();
+  test_browser_thread_bundle_.RunUntilIdle();
+
+  const int kRestoredTabs = 7;
+
+  metric_provider_->OnSessionRestoreDone(kRestoredTabs);
+
+  // Fast forward the time by the max collection delay.
+  test_browser_thread_bundle_.FastForwardBy(kMaxCollectionDelay);
+
+  std::vector<SampledProfile> stored_profiles;
+  EXPECT_TRUE(metric_provider_->GetSampledProfiles(&stored_profiles));
+  ASSERT_EQ(1U, stored_profiles.size());
+
+  const SampledProfile& profile = stored_profiles[0];
+  EXPECT_EQ(SampledProfile::RESTORE_SESSION, profile.trigger_event());
+  EXPECT_EQ(kRestoredTabs, profile.num_tabs_restored());
+  EXPECT_FALSE(profile.has_ms_after_resume());
+  EXPECT_TRUE(profile.has_ms_after_login());
+  EXPECT_TRUE(profile.has_ms_after_boot());
+}
+
+}  // namespace metrics
diff --git a/chrome/browser/metrics/perf/perf_events_collector.cc b/chrome/browser/metrics/perf/perf_events_collector.cc
index 7e458a6..f995823c 100644
--- a/chrome/browser/metrics/perf/perf_events_collector.cc
+++ b/chrome/browser/metrics/perf/perf_events_collector.cc
@@ -4,6 +4,9 @@
 
 #include "chrome/browser/metrics/perf/perf_events_collector.h"
 
+#include <algorithm>
+#include <utility>
+
 #include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/metrics/histogram_functions.h"
@@ -245,37 +248,32 @@
 }  // namespace internal
 
 PerfCollector::PerfCollector()
-    : MetricCollector(kPerfCollectorName),
-      windowed_incognito_monitor_(std::make_unique<WindowedIncognitoMonitor>()),
-      weak_factory_(this) {
-  // Parsing processor information may be expensive. Compute asynchronously
-  // in a separate thread.
-  DCHECK(base::SequencedTaskRunnerHandle::IsSet());
-  ui_task_runner_ = base::SequencedTaskRunnerHandle::Get();
+    : internal::MetricCollector(kPerfCollectorName, CollectionParams()),
+      weak_factory_(this) {}
+
+PerfCollector::~PerfCollector() = default;
+
+void PerfCollector::SetUp() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  auto task_runner = base::SequencedTaskRunnerHandle::Get();
   base::PostTask(
       FROM_HERE,
       {base::ThreadPool(), base::MayBlock(), base::TaskPriority::BEST_EFFORT,
        base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
-      base::BindOnce(&PerfCollector::ParseCPUFrequencies, ui_task_runner_,
+      base::BindOnce(&PerfCollector::ParseCPUFrequencies, task_runner,
                      weak_factory_.GetWeakPtr()));
-}
 
-PerfCollector::~PerfCollector() {
-  // Destroy WindowedIncognitoMonitor on the UI thread.
-  ui_task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce([](std::unique_ptr<WindowedIncognitoMonitor> ref) {},
-                     std::move(windowed_incognito_monitor_)));
-}
-
-void PerfCollector::Init() {
   CHECK(command_selector_.SetOdds(
       internal::GetDefaultCommandsForCpu(GetCPUIdentity())));
   std::map<std::string, std::string> params;
-  if (variations::GetVariationParams(kCWPFieldTrialName, &params))
+  if (variations::GetVariationParams(kCWPFieldTrialName, &params)) {
     SetCollectionParamsFromVariationParams(params);
+  }
+}
 
-  MetricCollector::Init();
+const char* PerfCollector::ToolName() const {
+  return kPerfCollectorName;
 }
 
 namespace internal {
@@ -333,27 +331,28 @@
 
 void PerfCollector::SetCollectionParamsFromVariationParams(
     const std::map<std::string, std::string>& params) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   int64_t value;
+  CollectionParams& collector_params = collection_params();
   if (GetInt64Param(params, "ProfileCollectionDurationSec", &value)) {
-    collection_params_.collection_duration =
-        base::TimeDelta::FromSeconds(value);
+    collector_params.collection_duration = base::TimeDelta::FromSeconds(value);
   }
   if (GetInt64Param(params, "PeriodicProfilingIntervalMs", &value)) {
-    collection_params_.periodic_interval =
+    collector_params.periodic_interval =
         base::TimeDelta::FromMilliseconds(value);
   }
   if (GetInt64Param(params, "ResumeFromSuspend::SamplingFactor", &value)) {
-    collection_params_.resume_from_suspend.sampling_factor = value;
+    collector_params.resume_from_suspend.sampling_factor = value;
   }
   if (GetInt64Param(params, "ResumeFromSuspend::MaxDelaySec", &value)) {
-    collection_params_.resume_from_suspend.max_collection_delay =
+    collector_params.resume_from_suspend.max_collection_delay =
         base::TimeDelta::FromSeconds(value);
   }
   if (GetInt64Param(params, "RestoreSession::SamplingFactor", &value)) {
-    collection_params_.restore_session.sampling_factor = value;
+    collector_params.restore_session.sampling_factor = value;
   }
   if (GetInt64Param(params, "RestoreSession::MaxDelaySec", &value)) {
-    collection_params_.restore_session.max_collection_delay =
+    collector_params.restore_session.max_collection_delay =
         base::TimeDelta::FromSeconds(value);
   }
 
@@ -388,7 +387,7 @@
   command_selector_.SetOdds(commands);
 }
 
-MetricCollector::PerfProtoType PerfCollector::GetPerfProtoType(
+internal::MetricCollector::PerfProtoType PerfCollector::GetPerfProtoType(
     const std::vector<std::string>& args) {
   if (args.size() > 1 && args[0] == "perf") {
     if (args[1] == "record" || args[1] == "mem")
@@ -408,12 +407,12 @@
     std::string perf_stdout) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  // We are done using |perf_output_call_| and may destroy it.
+  // We are done using |perf_output_call| and may destroy it.
   perf_output_call_ = nullptr;
 
   ParseOutputProtoIfValid(std::move(incognito_observer),
                           std::move(sampled_profile), type, has_cycles,
-                          perf_stdout);
+                          std::move(perf_stdout));
 }
 
 void PerfCollector::ParseOutputProtoIfValid(
@@ -421,7 +420,7 @@
     std::unique_ptr<SampledProfile> sampled_profile,
     PerfProtoType type,
     bool has_cycles,
-    const std::string& perf_stdout) {
+    std::string perf_stdout) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // Check whether an incognito window had been opened during profile
@@ -443,15 +442,17 @@
       base::BindOnce(&OnCollectProcessTypes, sampled_profile.get()),
       base::BindOnce(&PerfCollector::SaveSerializedPerfProto,
                      weak_factory_.GetWeakPtr(), std::move(sampled_profile),
-                     type, perf_stdout));
+                     type, std::move(perf_stdout)));
   DCHECK(posted);
 }
 
-base::WeakPtr<MetricCollector> PerfCollector::GetWeakPtr() {
+base::WeakPtr<internal::MetricCollector> PerfCollector::GetWeakPtr() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return weak_factory_.GetWeakPtr();
 }
 
 bool PerfCollector::ShouldCollect() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // Only allow one active collection.
   if (perf_output_call_) {
     AddToUmaHistogram(CollectionAttemptStatus::ALREADY_COLLECTING);
@@ -460,7 +461,7 @@
 
   // Do not collect further data if we've already collected a substantial amount
   // of data, as indicated by |kCachedPerfDataProtobufSizeThreshold|.
-  if (cached_profile_data_size() >= kCachedPerfDataProtobufSizeThreshold) {
+  if (cached_data_size_ >= kCachedPerfDataProtobufSizeThreshold) {
     AddToUmaHistogram(CollectionAttemptStatus::NOT_READY_TO_COLLECT);
     return false;
   }
@@ -486,7 +487,9 @@
 
 void PerfCollector::CollectProfile(
     std::unique_ptr<SampledProfile> sampled_profile) {
-  auto incognito_observer = windowed_incognito_monitor_->CreateObserver();
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  auto incognito_observer = WindowedIncognitoMonitor::CreateObserver();
   // For privacy reasons, Chrome should only collect perf data if there is no
   // incognito session active (or gets spawned during the collection).
   if (incognito_observer->IncognitoActive()) {
@@ -501,7 +504,7 @@
   bool has_cycles = internal::CommandSamplesCPUCycles(command);
 
   perf_output_call_ = std::make_unique<PerfOutputCall>(
-      collection_params_.collection_duration, command,
+      collection_params().collection_duration, command,
       base::BindOnce(&PerfCollector::OnPerfOutputComplete,
                      weak_factory_.GetWeakPtr(), std::move(incognito_observer),
                      std::move(sampled_profile), type, has_cycles));
diff --git a/chrome/browser/metrics/perf/perf_events_collector.h b/chrome/browser/metrics/perf/perf_events_collector.h
index 658f11e..2f1e31b5 100644
--- a/chrome/browser/metrics/perf/perf_events_collector.h
+++ b/chrome/browser/metrics/perf/perf_events_collector.h
@@ -6,6 +6,9 @@
 #define CHROME_BROWSER_METRICS_PERF_PERF_EVENTS_COLLECTOR_H_
 
 #include <map>
+#include <memory>
+#include <string>
+#include <vector>
 
 #include "chrome/browser/metrics/perf/metric_collector.h"
 #include "chrome/browser/metrics/perf/random_selector.h"
@@ -18,18 +21,18 @@
 
 struct CPUIdentity;
 class PerfOutputCall;
-class WindowedIncognitoMonitor;
 class WindowedIncognitoObserver;
 
 // Enables collection of perf events profile data. perf aka "perf events" is a
 // performance profiling infrastructure built into the linux kernel. For more
 // information, see: https://perf.wiki.kernel.org/index.php/Main_Page.
-class PerfCollector : public MetricCollector {
+class PerfCollector : public internal::MetricCollector {
  public:
   PerfCollector();
-  ~PerfCollector() override;
 
-  void Init() override;
+  // MetricCollector:
+  ~PerfCollector() override;
+  const char* ToolName() const override;
 
  protected:
   // Returns the perf proto type associated with the given vector of perf
@@ -53,10 +56,11 @@
       std::unique_ptr<SampledProfile> sampled_profile,
       PerfProtoType type,
       bool has_cycles,
-      const std::string& perf_stdout);
+      std::string perf_stdout);
 
   // MetricCollector:
-  base::WeakPtr<MetricCollector> GetWeakPtr() override;
+  void SetUp() override;
+  base::WeakPtr<internal::MetricCollector> GetWeakPtr() override;
   bool ShouldCollect() const override;
   void CollectProfile(std::unique_ptr<SampledProfile> sampled_profile) override;
 
@@ -67,9 +71,13 @@
   static void ParseCPUFrequencies(
       scoped_refptr<base::SequencedTaskRunner> task_runner,
       base::WeakPtr<PerfCollector> perf_collector);
-  // Executes on the same sequence as the processing of perf data.
+  // Saves the given frequencies to |max_frequencies_mhz_|.
   void SaveCPUFrequencies(const std::vector<uint32_t>& frequencies);
 
+  const std::vector<uint32_t>& max_frequencies_mhz() const {
+    return max_frequencies_mhz_;
+  }
+
   // Enumeration representing success and various failure modes for parsing CPU
   // frequencies. These values are persisted to logs. Entries should not be
   // renumbered and numeric values should never be reused.
@@ -82,16 +90,9 @@
     kMaxValue = kAllZeroCPUFrequencies,
   };
 
-  // Vector of max frequencies associated with each logical CPU. Computed
-  // asynchronously at start, but initialized using the same sequence as the
-  // perf data processing code.
-  std::vector<uint32_t> max_frequencies_mhz_;
-
-  std::unique_ptr<WindowedIncognitoMonitor> windowed_incognito_monitor_;
-
  private:
   // Change the values in |collection_params_| and the commands in
-  // |command_selector_| for any keys that are present in |params|.
+  // |command_selector| for any keys that are present in |params|.
   void SetCollectionParamsFromVariationParams(
       const std::map<std::string, std::string>& params);
 
@@ -101,8 +102,9 @@
   // An active call to perf/quipper, if set.
   std::unique_ptr<PerfOutputCall> perf_output_call_;
 
-  // For destroying |windowed_incognito_monitor_| on the UI thread.
-  scoped_refptr<base::SequencedTaskRunner> ui_task_runner_;
+  // Vector of max frequencies associated with each logical CPU. Computed
+  // asynchronously at start.
+  std::vector<uint32_t> max_frequencies_mhz_;
 
   base::WeakPtrFactory<PerfCollector> weak_factory_;
 
diff --git a/chrome/browser/metrics/perf/perf_events_collector_unittest.cc b/chrome/browser/metrics/perf/perf_events_collector_unittest.cc
index 3cb5e712..88489b9 100644
--- a/chrome/browser/metrics/perf/perf_events_collector_unittest.cc
+++ b/chrome/browser/metrics/perf/perf_events_collector_unittest.cc
@@ -12,16 +12,15 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/metrics/field_trial.h"
-#include "base/task/thread_pool/thread_pool.h"
-#include "base/test/scoped_task_environment.h"
-#include "base/test/test_simple_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/task/post_task.h"
+#include "base/test/bind_test_util.h"
 #include "chrome/browser/metrics/perf/cpu_identity.h"
 #include "chrome/browser/metrics/perf/windowed_incognito_observer.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/login/login_state/login_state.h"
 #include "components/variations/variations_associated_data.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/metrics_proto/sampled_profile.pb.h"
 
@@ -119,12 +118,10 @@
     return base::WrapUnique(new TestIncognitoObserver(incognito_launched));
   }
 
-  ~TestIncognitoObserver() override = default;
-
   bool IncognitoLaunched() const override { return incognito_launched_; }
 
  private:
-  TestIncognitoObserver(bool incognito_launched)
+  explicit TestIncognitoObserver(bool incognito_launched)
       : WindowedIncognitoObserver(nullptr, 0),
         incognito_launched_(incognito_launched) {}
 
@@ -136,70 +133,100 @@
 // Allows access to some private methods for testing.
 class TestPerfCollector : public PerfCollector {
  public:
-  TestPerfCollector() {}
+  TestPerfCollector() = default;
 
-  using MetricCollector::PerfProtoType;
+  void CollectProfile(
+      std::unique_ptr<SampledProfile> sampled_profile) override {
+    PerfDataProto perf_data_proto = GetExamplePerfDataProto();
+    SaveSerializedPerfProto(std::move(sampled_profile),
+                            PerfProtoType::PERF_TYPE_DATA,
+                            perf_data_proto.SerializeAsString());
+  }
+
+  using PerfCollector::AddCachedDataDelta;
   using PerfCollector::collection_params;
   using PerfCollector::command_selector;
-  using PerfCollector::max_frequencies_mhz_;
+  using PerfCollector::Init;
+  using PerfCollector::IsRunning;
+  using PerfCollector::max_frequencies_mhz;
   using PerfCollector::ParseOutputProtoIfValid;
+  using PerfCollector::PerfProtoType;
+  using PerfCollector::RecordUserLogin;
+  using PerfCollector::set_profile_done_callback;
 
- private:
   DISALLOW_COPY_AND_ASSIGN(TestPerfCollector);
 };
 
+const base::TimeDelta kPeriodicCollectionInterval =
+    base::TimeDelta::FromHours(1);
+
 }  // namespace
 
 class PerfCollectorTest : public testing::Test {
  public:
   PerfCollectorTest()
-      : scoped_task_environment_(
-            std::make_unique<base::test::ScopedTaskEnvironment>()),
-        task_runner_(base::MakeRefCounted<base::TestSimpleTaskRunner>()) {}
+      : test_browser_thread_bundle_(
+            base::test::ScopedTaskEnvironment::TimeSource::MOCK_TIME) {}
+
+  void SaveProfile(std::unique_ptr<SampledProfile> sampled_profile) {
+    cached_profile_data_.resize(cached_profile_data_.size() + 1);
+    cached_profile_data_.back().Swap(sampled_profile.get());
+  }
 
   void SetUp() override {
-    // PerfCollector requires chromeos::LoginState and
-    // chromeos::DBusThreadManagerto be initialized.
-    chromeos::LoginState::Initialize();
-    chromeos::DBusThreadManager::Initialize();
-
     perf_collector_ = std::make_unique<TestPerfCollector>();
-    perf_collector_->Init();
+    // Set the periodic collection delay to a well known quantity, so we can
+    // fast forward the time.
+    perf_collector_->collection_params().periodic_interval =
+        kPeriodicCollectionInterval;
+    perf_collector_->set_profile_done_callback(base::BindRepeating(
+        &PerfCollectorTest::SaveProfile, base::Unretained(this)));
 
+    perf_collector_->Init();
     // PerfCollector requires the user to be logged in.
-    perf_collector_->OnUserLoggedIn();
+    perf_collector_->RecordUserLogin(base::TimeTicks::Now());
   }
 
   void TearDown() override {
     perf_collector_.reset();
-    chromeos::DBusThreadManager::Shutdown();
-    chromeos::LoginState::Shutdown();
+    cached_profile_data_.clear();
   }
 
  protected:
+  // test_browser_thread_bundle_ must be the first member (or at least before
+  // any member that cares about tasks) to be initialized first and destroyed
+  // last.
+  content::TestBrowserThreadBundle test_browser_thread_bundle_;
+
+  std::vector<SampledProfile> cached_profile_data_;
+
   std::unique_ptr<TestPerfCollector> perf_collector_;
 
-  // scoped_task_environment_ must be the first member (or at least before any
-  // member that cares about tasks) to be initialized first and destroyed last.
-  std::unique_ptr<base::test::ScopedTaskEnvironment> scoped_task_environment_;
-
-  scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
-
   DISALLOW_COPY_AND_ASSIGN(PerfCollectorTest);
 };
 
 TEST_F(PerfCollectorTest, CheckSetup) {
-  std::vector<SampledProfile> stored_profiles;
-  EXPECT_FALSE(perf_collector_->GetSampledProfiles(&stored_profiles));
-  EXPECT_TRUE(stored_profiles.empty());
+  // No profiles saved at start.
+  EXPECT_TRUE(cached_profile_data_.empty());
 
   EXPECT_FALSE(TestIncognitoObserver::CreateWithIncognitoLaunched(false)
                    ->IncognitoLaunched());
   EXPECT_TRUE(TestIncognitoObserver::CreateWithIncognitoLaunched(true)
                   ->IncognitoLaunched());
-  base::ThreadPoolInstance::Get()->FlushForTesting();
-  scoped_task_environment_->RunUntilIdle();
-  EXPECT_GT(perf_collector_->max_frequencies_mhz_.size(), 0u);
+  test_browser_thread_bundle_.RunUntilIdle();
+  EXPECT_GT(perf_collector_->max_frequencies_mhz().size(), 0u);
+}
+
+TEST_F(PerfCollectorTest, NoCollectionWhenProfileCacheFull) {
+  // Timer is active after login and a periodic collection is scheduled.
+  EXPECT_TRUE(perf_collector_->IsRunning());
+  // Pretend the cache is full.
+  perf_collector_->AddCachedDataDelta(4 * 1024 * 1024);
+
+  // Advance the clock by a periodic collection interval. We shouldn't find a
+  // profile because the cache is full.
+  test_browser_thread_bundle_.FastForwardBy(kPeriodicCollectionInterval);
+  EXPECT_TRUE(cached_profile_data_.empty());
 }
 
 // Simulate opening and closing of incognito window in between calls to
@@ -209,30 +236,27 @@
   PerfStatProto perf_stat_proto = GetExamplePerfStatProto();
   EXPECT_GT(perf_data_proto.ByteSize(), 0);
   EXPECT_GT(perf_stat_proto.ByteSize(), 0);
-  base::ThreadPoolInstance::Get()->FlushForTesting();
-  scoped_task_environment_->RunUntilIdle();
+  test_browser_thread_bundle_.RunUntilIdle();
 
   auto sampled_profile = std::make_unique<SampledProfile>();
   sampled_profile->set_trigger_event(SampledProfile::PERIODIC_COLLECTION);
 
+  auto incognito_observer =
+      TestIncognitoObserver::CreateWithIncognitoLaunched(false);
   perf_collector_->ParseOutputProtoIfValid(
-      TestIncognitoObserver::CreateWithIncognitoLaunched(false),
-      std::move(sampled_profile),
+      std::move(incognito_observer), std::move(sampled_profile),
       TestPerfCollector::PerfProtoType::PERF_TYPE_DATA, true,
       perf_data_proto.SerializeAsString());
 
-  // Run the (Thread|Sequenced)TaskRunnerHandle queue until both the
-  // (Thread|Sequenced)TaskRunnerHandle queue and the TaskSchedule queue are
-  // empty as the above ParseOutputProtoIfValid call posts a task to
-  // asynchronously collect process and thread types and the profile cache will
-  // be updated only after this collection completes.
-  scoped_task_environment_->RunUntilIdle();
+  // Run the TestBrowserThreadBundle queue until it's empty as the above
+  // ParseOutputProtoIfValid call posts a task to asynchronously collect process
+  // and thread types and the profile cache will be updated asynchronously via
+  // another PostTask request after this collection completes.
+  test_browser_thread_bundle_.RunUntilIdle();
 
-  std::vector<SampledProfile> stored_profiles1;
-  EXPECT_TRUE(perf_collector_->GetSampledProfiles(&stored_profiles1));
-  ASSERT_EQ(1U, stored_profiles1.size());
+  ASSERT_EQ(1U, cached_profile_data_.size());
 
-  const SampledProfile& profile1 = stored_profiles1[0];
+  const SampledProfile& profile1 = cached_profile_data_[0];
   EXPECT_EQ(SampledProfile::PERIODIC_COLLECTION, profile1.trigger_event());
   EXPECT_TRUE(profile1.has_ms_after_login());
   ASSERT_TRUE(profile1.has_perf_data());
@@ -240,23 +264,22 @@
   EXPECT_EQ(SerializeMessageToVector(perf_data_proto),
             SerializeMessageToVector(profile1.perf_data()));
   EXPECT_GT(profile1.cpu_max_frequency_mhz_size(), 0);
+  cached_profile_data_.clear();
 
   sampled_profile = std::make_unique<SampledProfile>();
   sampled_profile->set_trigger_event(SampledProfile::RESTORE_SESSION);
   sampled_profile->set_ms_after_restore(3000);
+  incognito_observer =
+      TestIncognitoObserver::CreateWithIncognitoLaunched(false);
   perf_collector_->ParseOutputProtoIfValid(
-      TestIncognitoObserver::CreateWithIncognitoLaunched(false),
-      std::move(sampled_profile),
+      std::move(incognito_observer), std::move(sampled_profile),
       TestPerfCollector::PerfProtoType::PERF_TYPE_STAT, false,
       perf_stat_proto.SerializeAsString());
+  test_browser_thread_bundle_.RunUntilIdle();
 
-  scoped_task_environment_->RunUntilIdle();
+  ASSERT_EQ(1U, cached_profile_data_.size());
 
-  std::vector<SampledProfile> stored_profiles2;
-  EXPECT_TRUE(perf_collector_->GetSampledProfiles(&stored_profiles2));
-  ASSERT_EQ(1U, stored_profiles2.size());
-
-  const SampledProfile& profile2 = stored_profiles2[0];
+  const SampledProfile& profile2 = cached_profile_data_[0];
   EXPECT_EQ(SampledProfile::RESTORE_SESSION, profile2.trigger_event());
   EXPECT_TRUE(profile2.has_ms_after_login());
   EXPECT_EQ(3000, profile2.ms_after_restore());
@@ -265,52 +288,48 @@
   EXPECT_EQ(SerializeMessageToVector(perf_stat_proto),
             SerializeMessageToVector(profile2.perf_stat()));
   EXPECT_EQ(profile2.cpu_max_frequency_mhz_size(), 0);
+  cached_profile_data_.clear();
 
   sampled_profile = std::make_unique<SampledProfile>();
   sampled_profile->set_trigger_event(SampledProfile::RESUME_FROM_SUSPEND);
   // An incognito window opens.
+  incognito_observer = TestIncognitoObserver::CreateWithIncognitoLaunched(true);
   perf_collector_->ParseOutputProtoIfValid(
-      TestIncognitoObserver::CreateWithIncognitoLaunched(true),
-      std::move(sampled_profile),
+      std::move(incognito_observer), std::move(sampled_profile),
       TestPerfCollector::PerfProtoType::PERF_TYPE_DATA, true,
       perf_data_proto.SerializeAsString());
+  test_browser_thread_bundle_.RunUntilIdle();
 
-  scoped_task_environment_->RunUntilIdle();
-
-  std::vector<SampledProfile> stored_profiles_empty;
-  EXPECT_FALSE(perf_collector_->GetSampledProfiles(&stored_profiles_empty));
+  EXPECT_TRUE(cached_profile_data_.empty());
 
   sampled_profile = std::make_unique<SampledProfile>();
   sampled_profile->set_trigger_event(SampledProfile::PERIODIC_COLLECTION);
   // Incognito window is still open.
+  incognito_observer = TestIncognitoObserver::CreateWithIncognitoLaunched(true);
   perf_collector_->ParseOutputProtoIfValid(
-      TestIncognitoObserver::CreateWithIncognitoLaunched(true),
-      std::move(sampled_profile),
+      std::move(incognito_observer), std::move(sampled_profile),
       TestPerfCollector::PerfProtoType::PERF_TYPE_STAT, false,
       perf_stat_proto.SerializeAsString());
+  test_browser_thread_bundle_.RunUntilIdle();
 
-  scoped_task_environment_->RunUntilIdle();
-
-  EXPECT_FALSE(perf_collector_->GetSampledProfiles(&stored_profiles_empty));
+  EXPECT_TRUE(cached_profile_data_.empty());
 
   sampled_profile = std::make_unique<SampledProfile>();
   sampled_profile->set_trigger_event(SampledProfile::RESUME_FROM_SUSPEND);
   sampled_profile->set_suspend_duration_ms(60000);
   sampled_profile->set_ms_after_resume(1500);
   // Incognito window closes.
+  incognito_observer =
+      TestIncognitoObserver::CreateWithIncognitoLaunched(false);
   perf_collector_->ParseOutputProtoIfValid(
-      TestIncognitoObserver::CreateWithIncognitoLaunched(false),
-      std::move(sampled_profile),
+      std::move(incognito_observer), std::move(sampled_profile),
       TestPerfCollector::PerfProtoType::PERF_TYPE_DATA, true,
       perf_data_proto.SerializeAsString());
+  test_browser_thread_bundle_.RunUntilIdle();
 
-  scoped_task_environment_->RunUntilIdle();
+  ASSERT_EQ(1U, cached_profile_data_.size());
 
-  std::vector<SampledProfile> stored_profiles3;
-  EXPECT_TRUE(perf_collector_->GetSampledProfiles(&stored_profiles3));
-  ASSERT_EQ(1U, stored_profiles3.size());
-
-  const SampledProfile& profile3 = stored_profiles3[0];
+  const SampledProfile& profile3 = cached_profile_data_[0];
   EXPECT_EQ(SampledProfile::RESUME_FROM_SUSPEND, profile3.trigger_event());
   EXPECT_TRUE(profile3.has_ms_after_login());
   EXPECT_EQ(60000, profile3.suspend_duration_ms());
@@ -629,28 +648,12 @@
  public:
   PerfCollectorCollectionParamsTest() : field_trial_list_(nullptr) {}
 
-  void SetUp() override {
-    // PerfCollector requires chromeos::LoginState and
-    // chromeos::DBusThreadManagerto be initialized.
-    chromeos::LoginState::Initialize();
-    chromeos::DBusThreadManager::Initialize();
-
-    // PerfCollector requires the user to be logged in.
-    chromeos::LoginState::Get()->SetLoggedInState(
-        chromeos::LoginState::LOGGED_IN_ACTIVE,
-        chromeos::LoginState::LOGGED_IN_USER_REGULAR);
-  }
-
   void TearDown() override {
-    chromeos::DBusThreadManager::Shutdown();
-    chromeos::LoginState::Shutdown();
     variations::testing::ClearAllVariationParams();
   }
 
- private:
-  // scoped_task_environment_ must be the first member (or at least before any
-  // member that cares about tasks) to be initialized first and destroyed last.
-  base::test::ScopedTaskEnvironment scoped_task_environment_;
+ protected:
+  content::TestBrowserThreadBundle test_browser_thread_bundle_;
 
   base::FieldTrialList field_trial_list_;
 
@@ -658,11 +661,11 @@
 };
 
 TEST_F(PerfCollectorCollectionParamsTest, Commands_InitializedAfterVariations) {
-  TestPerfCollector perf_provider;
-  EXPECT_TRUE(perf_provider.command_selector().odds().empty());
+  auto perf_collector = std::make_unique<TestPerfCollector>();
+  EXPECT_TRUE(perf_collector->command_selector().odds().empty());
   // Init would be called after VariationsService is initialized.
-  perf_provider.Init();
-  EXPECT_FALSE(perf_provider.command_selector().odds().empty());
+  perf_collector->Init();
+  EXPECT_FALSE(perf_collector->command_selector().odds().empty());
 }
 
 TEST_F(PerfCollectorCollectionParamsTest, Commands_EmptyExperiment) {
@@ -674,10 +677,10 @@
   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
       "ChromeOSWideProfilingCollection", "group_name"));
 
-  TestPerfCollector perf_provider;
-  EXPECT_TRUE(perf_provider.command_selector().odds().empty());
-  perf_provider.Init();
-  EXPECT_EQ(default_cmds, perf_provider.command_selector().odds());
+  auto perf_collector = std::make_unique<TestPerfCollector>();
+  EXPECT_TRUE(perf_collector->command_selector().odds().empty());
+  perf_collector->Init();
+  EXPECT_EQ(default_cmds, perf_collector->command_selector().odds());
 }
 
 TEST_F(PerfCollectorCollectionParamsTest, Commands_InvalidValues) {
@@ -700,10 +703,10 @@
   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
       "ChromeOSWideProfilingCollection", "group_name"));
 
-  TestPerfCollector perf_provider;
-  EXPECT_TRUE(perf_provider.command_selector().odds().empty());
-  perf_provider.Init();
-  EXPECT_EQ(default_cmds, perf_provider.command_selector().odds());
+  auto perf_collector = std::make_unique<TestPerfCollector>();
+  EXPECT_TRUE(perf_collector->command_selector().odds().empty());
+  perf_collector->Init();
+  EXPECT_EQ(default_cmds, perf_collector->command_selector().odds());
 }
 
 TEST_F(PerfCollectorCollectionParamsTest, Commands_Override) {
@@ -726,16 +729,16 @@
   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
       "ChromeOSWideProfilingCollection", "group_name"));
 
-  TestPerfCollector perf_provider;
-  EXPECT_TRUE(perf_provider.command_selector().odds().empty());
-  perf_provider.Init();
+  auto perf_collector = std::make_unique<TestPerfCollector>();
+  EXPECT_TRUE(perf_collector->command_selector().odds().empty());
+  perf_collector->Init();
 
   std::vector<WeightAndValue> expected_cmds;
   expected_cmds.push_back(WeightAndValue(50.0, "perf record foo"));
   expected_cmds.push_back(WeightAndValue(25.0, "perf record bar"));
   expected_cmds.push_back(WeightAndValue(25.0, "perf record baz"));
 
-  EXPECT_EQ(expected_cmds, perf_provider.command_selector().odds());
+  EXPECT_EQ(expected_cmds, perf_collector->command_selector().odds());
 }
 
 TEST_F(PerfCollectorCollectionParamsTest, Parameters_Override) {
@@ -751,8 +754,8 @@
   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
       "ChromeOSWideProfilingCollection", "group_name"));
 
-  TestPerfCollector perf_provider;
-  const auto& parsed_params = perf_provider.collection_params();
+  auto perf_collector = std::make_unique<TestPerfCollector>();
+  const auto& parsed_params = perf_collector->collection_params();
 
   // Not initialized yet:
   EXPECT_NE(base::TimeDelta::FromSeconds(15),
@@ -765,7 +768,7 @@
   EXPECT_NE(base::TimeDelta::FromSeconds(20),
             parsed_params.restore_session.max_collection_delay);
 
-  perf_provider.Init();
+  perf_collector->Init();
 
   EXPECT_EQ(base::TimeDelta::FromSeconds(15),
             parsed_params.collection_duration);
diff --git a/chrome/browser/metrics/perf/profile_provider_chromeos.cc b/chrome/browser/metrics/perf/profile_provider_chromeos.cc
index 266758a6..9be6db3 100644
--- a/chrome/browser/metrics/perf/profile_provider_chromeos.cc
+++ b/chrome/browser/metrics/perf/profile_provider_chromeos.cc
@@ -7,11 +7,11 @@
 #include "base/allocator/buildflags.h"
 #include "base/bind.h"
 #include "base/metrics/field_trial_params.h"
-#include "base/rand_util.h"
 #include "base/sampling_heap_profiler/sampling_heap_profiler.h"
 #include "chrome/browser/metrics/perf/heap_collector.h"
-#include "chrome/browser/metrics/perf/metric_collector.h"
+#include "chrome/browser/metrics/perf/metric_provider.h"
 #include "chrome/browser/metrics/perf/perf_events_collector.h"
+#include "chrome/browser/metrics/perf/windowed_incognito_observer.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "components/services/heap_profiling/public/cpp/settings.h"
 #include "third_party/metrics_proto/sampled_profile.pb.h"
@@ -29,8 +29,11 @@
 }  // namespace
 
 ProfileProvider::ProfileProvider() : weak_factory_(this) {
+  // Initialize the WindowedIncognitoMonitor on the UI thread.
+  WindowedIncognitoMonitor::Init();
   // Register a perf events collector.
-  collectors_.push_back(std::make_unique<PerfCollector>());
+  collectors_.push_back(
+      std::make_unique<MetricProvider>(std::make_unique<PerfCollector>()));
 }
 
 ProfileProvider::~ProfileProvider() {
@@ -46,7 +49,8 @@
             heap_profiling::kOOPHeapProfilingFeature,
             heap_profiling::kOOPHeapProfilingFeatureMode));
     if (mode != HeapCollectionMode::kNone) {
-      collectors_.push_back(std::make_unique<HeapCollector>(mode));
+      collectors_.push_back(std::make_unique<MetricProvider>(
+          std::make_unique<HeapCollector>(mode)));
     }
   }
 #endif
diff --git a/chrome/browser/metrics/perf/profile_provider_chromeos.h b/chrome/browser/metrics/perf/profile_provider_chromeos.h
index 66183ec2..6552c414 100644
--- a/chrome/browser/metrics/perf/profile_provider_chromeos.h
+++ b/chrome/browser/metrics/perf/profile_provider_chromeos.h
@@ -7,6 +7,7 @@
 
 #include <vector>
 
+#include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "chrome/browser/sessions/session_restore.h"
 #include "chromeos/dbus/power/power_manager_client.h"
@@ -14,7 +15,7 @@
 
 namespace metrics {
 
-class MetricCollector;
+class MetricProvider;
 class SampledProfile;
 
 // Provides access to ChromeOS profile data using different metric collectors.
@@ -47,7 +48,7 @@
   void OnSessionRestoreDone(int num_tabs_restored);
 
   // Vector of registered metric collectors.
-  std::vector<std::unique_ptr<MetricCollector>> collectors_;
+  std::vector<std::unique_ptr<MetricProvider>> collectors_;
 
  private:
   // Points to the on-session-restored callback that was registered with
diff --git a/chrome/browser/metrics/perf/profile_provider_chromeos_unittest.cc b/chrome/browser/metrics/perf/profile_provider_chromeos_unittest.cc
index 342edd4..77ed3b47 100644
--- a/chrome/browser/metrics/perf/profile_provider_chromeos_unittest.cc
+++ b/chrome/browser/metrics/perf/profile_provider_chromeos_unittest.cc
@@ -13,14 +13,16 @@
 
 #include "base/allocator/buildflags.h"
 #include "base/macros.h"
-#include "base/run_loop.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/time/time.h"
 #include "chrome/browser/metrics/perf/heap_collector.h"
 #include "chrome/browser/metrics/perf/metric_collector.h"
+#include "chrome/browser/metrics/perf/metric_provider.h"
+#include "chrome/browser/metrics/perf/windowed_incognito_observer.h"
 #include "chromeos/login/login_state/login_state.h"
 #include "components/services/heap_profiling/public/cpp/settings.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/metrics_proto/sampled_profile.pb.h"
 
@@ -59,23 +61,28 @@
 
 // Custome metric collectors to register with the profile provider for testing.
 template <int TSTAMP>
-class TestMetricCollector : public MetricCollector {
+class TestMetricCollector : public internal::MetricCollector {
  public:
   TestMetricCollector() : TestMetricCollector(CollectionParams()) {}
   explicit TestMetricCollector(const CollectionParams& collection_params)
-      : MetricCollector("UMA.CWP.TestData", collection_params),
+      : internal::MetricCollector("UMA.CWP.TestData", collection_params),
         weak_factory_(this) {}
 
+  const char* ToolName() const override { return "test"; }
+  base::WeakPtr<internal::MetricCollector> GetWeakPtr() override {
+    return weak_factory_.GetWeakPtr();
+  }
+
   void CollectProfile(
       std::unique_ptr<SampledProfile> sampled_profile) override {
     PerfDataProto perf_data_proto = GetExamplePerfDataProto(TSTAMP);
-    SaveSerializedPerfProto(std::move(sampled_profile),
-                            PerfProtoType::PERF_TYPE_DATA,
-                            perf_data_proto.SerializeAsString());
-  }
-
-  base::WeakPtr<MetricCollector> GetWeakPtr() override {
-    return weak_factory_.GetWeakPtr();
+    // Create an incognito observer to test initialization on the UI thread.
+    auto observer = WindowedIncognitoMonitor::CreateObserver();
+    if (!observer->IncognitoActive()) {
+      SaveSerializedPerfProto(std::move(sampled_profile),
+                              PerfProtoType::PERF_TYPE_DATA,
+                              perf_data_proto.SerializeAsString());
+    }
   }
 
  private:
@@ -103,10 +110,10 @@
     test_params.periodic_interval = kPeriodicCollectionInterval;
 
     collectors_.clear();
-    collectors_.push_back(
-        std::make_unique<TestMetricCollector<100>>(test_params));
-    collectors_.push_back(
-        std::make_unique<TestMetricCollector<200>>(test_params));
+    collectors_.push_back(std::make_unique<MetricProvider>(
+        std::make_unique<TestMetricCollector<100>>(test_params)));
+    collectors_.push_back(std::make_unique<MetricProvider>(
+        std::make_unique<TestMetricCollector<200>>(test_params)));
   }
 
   using ProfileProvider::collectors_;
@@ -140,7 +147,7 @@
 class ProfileProviderTest : public testing::Test {
  public:
   ProfileProviderTest()
-      : scoped_task_environment_(
+      : test_browser_thread_bundle_(
             base::test::ScopedTaskEnvironment::TimeSource::MOCK_TIME) {}
 
   void SetUp() override {
@@ -150,7 +157,6 @@
     chromeos::LoginState::Initialize();
 
     profile_provider_ = std::make_unique<TestProfileProvider>();
-    base::RunLoop().RunUntilIdle();
     profile_provider_->Init();
   }
 
@@ -161,7 +167,10 @@
   }
 
  protected:
-  base::test::ScopedTaskEnvironment scoped_task_environment_;
+  // test_browser_thread_bundle_ must be the first member (or at least before
+  // any member that cares about tasks) to be initialized first and destroyed
+  // last.
+  content::TestBrowserThreadBundle test_browser_thread_bundle_;
 
   std::unique_ptr<TestProfileProvider> profile_provider_;
 
@@ -179,7 +188,7 @@
 
 TEST_F(ProfileProviderTest, UserLoginLogout) {
   // No user is logged in, so no collection is scheduled to run.
-  scoped_task_environment_.FastForwardBy(kPeriodicCollectionInterval);
+  test_browser_thread_bundle_.FastForwardBy(kPeriodicCollectionInterval);
 
   std::vector<SampledProfile> stored_profiles;
   EXPECT_FALSE(profile_provider_->GetSampledProfiles(&stored_profiles));
@@ -193,7 +202,7 @@
 
   // Run all pending tasks. SetLoggedInState has activated timers for periodic
   // collection causing timer based pending tasks.
-  scoped_task_environment_.FastForwardBy(kPeriodicCollectionInterval);
+  test_browser_thread_bundle_.FastForwardBy(kPeriodicCollectionInterval);
   // We should find two profiles, one for each collector.
   EXPECT_TRUE(profile_provider_->GetSampledProfiles(&stored_profiles));
   ExpectTwoStoredPerfProfiles<SampledProfile::PERIODIC_COLLECTION>(
@@ -205,7 +214,7 @@
       chromeos::LoginState::LOGGED_IN_NONE,
       chromeos::LoginState::LOGGED_IN_USER_NONE);
   // Run all pending tasks.
-  scoped_task_environment_.FastForwardBy(kPeriodicCollectionInterval);
+  test_browser_thread_bundle_.FastForwardBy(kPeriodicCollectionInterval);
   // We should find no new profiles.
   stored_profiles.clear();
   EXPECT_FALSE(profile_provider_->GetSampledProfiles(&stored_profiles));
@@ -216,7 +225,7 @@
   // No user is logged in, so no collection is done on resume from suspend.
   profile_provider_->SuspendDone(base::TimeDelta::FromMinutes(10));
   // Run all pending tasks.
-  scoped_task_environment_.FastForwardBy(kMaxCollectionDelay);
+  test_browser_thread_bundle_.FastForwardBy(kMaxCollectionDelay);
 
   std::vector<SampledProfile> stored_profiles;
   EXPECT_FALSE(profile_provider_->GetSampledProfiles(&stored_profiles));
@@ -236,7 +245,7 @@
   // Trigger a canceled suspend (zero sleep duration).
   profile_provider_->SuspendDone(base::TimeDelta::FromSeconds(0));
   // Run all pending tasks.
-  scoped_task_environment_.FastForwardBy(kMaxCollectionDelay);
+  test_browser_thread_bundle_.FastForwardBy(kMaxCollectionDelay);
 
   // We should find no profiles.
   std::vector<SampledProfile> stored_profiles;
@@ -245,8 +254,8 @@
 }
 
 TEST_F(ProfileProviderTest, SuspendDone) {
-  // Set user state as logged in. This activates periodic collection, but we can
-  // deactivate it for each collector.
+  // Set user state as logged in. This activates periodic collection, but other
+  // triggers like SUSPEND_DONE take precedence.
   chromeos::LoginState::Get()->SetLoggedInState(
       chromeos::LoginState::LOGGED_IN_ACTIVE,
       chromeos::LoginState::LOGGED_IN_USER_REGULAR);
@@ -254,7 +263,7 @@
   // Trigger a resume from suspend.
   profile_provider_->SuspendDone(base::TimeDelta::FromMinutes(10));
   // Run all pending tasks.
-  scoped_task_environment_.FastForwardBy(kMaxCollectionDelay);
+  test_browser_thread_bundle_.FastForwardBy(kMaxCollectionDelay);
 
   // We should find two profiles, one for each collector.
   std::vector<SampledProfile> stored_profiles;
@@ -267,7 +276,7 @@
   // No user is logged in, so no collection is done on session restore.
   profile_provider_->OnSessionRestoreDone(10);
   // Run all pending tasks.
-  scoped_task_environment_.FastForwardBy(kMaxCollectionDelay);
+  test_browser_thread_bundle_.FastForwardBy(kMaxCollectionDelay);
 
   std::vector<SampledProfile> stored_profiles;
   EXPECT_FALSE(profile_provider_->GetSampledProfiles(&stored_profiles));
@@ -287,7 +296,7 @@
   // Trigger a session restore.
   profile_provider_->OnSessionRestoreDone(10);
   // Run all pending tasks.
-  scoped_task_environment_.FastForwardBy(kMaxCollectionDelay);
+  test_browser_thread_bundle_.FastForwardBy(kMaxCollectionDelay);
 
   // We should find two profiles, one for each collector.
   std::vector<SampledProfile> stored_profiles;
@@ -326,7 +335,7 @@
   }
 
  private:
-  base::test::ScopedTaskEnvironment scoped_task_environment_;
+  content::TestBrowserThreadBundle test_browser_thread_bundle_;
 
   DISALLOW_COPY_AND_ASSIGN(ProfileProviderFeatureParamsTest);
 };
diff --git a/chrome/browser/metrics/perf/windowed_incognito_observer.cc b/chrome/browser/metrics/perf/windowed_incognito_observer.cc
index 8c11dfe..55cb2cfb 100644
--- a/chrome/browser/metrics/perf/windowed_incognito_observer.cc
+++ b/chrome/browser/metrics/perf/windowed_incognito_observer.cc
@@ -4,19 +4,14 @@
 
 #include "chrome/browser/metrics/perf/windowed_incognito_observer.h"
 
+#include "base/macros.h"
+#include "base/no_destructor.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
 
 namespace metrics {
 
-std::unique_ptr<WindowedIncognitoObserver>
-WindowedIncognitoMonitor::CreateObserver() {
-  base::AutoLock lock(lock_);
-  return std::make_unique<WindowedIncognitoObserver>(
-      this, num_incognito_window_opened_);
-}
-
 WindowedIncognitoObserver::WindowedIncognitoObserver(
     WindowedIncognitoMonitor* monitor,
     uint64_t num_incognito_window_opened)
@@ -32,21 +27,62 @@
   return windowed_incognito_monitor_->IncognitoActive();
 }
 
+// static
+void WindowedIncognitoMonitor::Init() {
+  ignore_result(WindowedIncognitoMonitor::Get());
+}
+
+// static
+std::unique_ptr<WindowedIncognitoObserver>
+WindowedIncognitoMonitor::CreateObserver() {
+  WindowedIncognitoMonitor* instance = WindowedIncognitoMonitor::Get();
+  return instance->CreateIncognitoObserver();
+}
+
+// static
+WindowedIncognitoMonitor* WindowedIncognitoMonitor::Get() {
+  static base::NoDestructor<WindowedIncognitoMonitor> instance;
+  return instance.get();
+}
+
 WindowedIncognitoMonitor::WindowedIncognitoMonitor()
     : num_active_incognito_windows_(0), num_incognito_window_opened_(0) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  RegisterInstance();
+}
+
+WindowedIncognitoMonitor::~WindowedIncognitoMonitor() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  UnregisterInstance();
+}
+
+void WindowedIncognitoMonitor::RegisterInstance() {
+  // |running_sessions_| is only accessed on the UI thread in RegisterInstance
+  // and UnregisterInstance. Therefore, we don't need to explicitly synchronize
+  // access to it.
+  if (running_sessions_++)
+    return;
   BrowserList::AddObserver(this);
 
-  // No need to acquire |lock_| because no observer has been created yet.
-  // Iterate over the BrowserList to get the current value of
-  // |num_active_incognito_windows_|.
   for (auto* window : *BrowserList::GetInstance())
     if (window->profile()->IsOffTheRecord())
       num_active_incognito_windows_++;
 }
 
-WindowedIncognitoMonitor::~WindowedIncognitoMonitor() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  BrowserList::RemoveObserver(this);
+void WindowedIncognitoMonitor::UnregisterInstance() {
+  // |running_sessions_| is only accessed on the UI thread in RegisterInstance
+  // and UnregisterInstance. Therefore, we don't need to explicitly synchronize
+  // access to it.
+  DCHECK_GT(running_sessions_, 0);
+  if (!--running_sessions_)
+    BrowserList::RemoveObserver(this);
+}
+
+std::unique_ptr<WindowedIncognitoObserver>
+WindowedIncognitoMonitor::CreateIncognitoObserver() {
+  base::AutoLock lock(lock_);
+  return std::make_unique<WindowedIncognitoObserver>(
+      this, num_incognito_window_opened_);
 }
 
 bool WindowedIncognitoMonitor::IncognitoActive() const {
@@ -65,10 +101,10 @@
 void WindowedIncognitoMonitor::OnBrowserAdded(Browser* browser) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  base::AutoLock lock(lock_);
   if (!browser->profile()->IsOffTheRecord())
     return;
 
+  base::AutoLock lock(lock_);
   num_active_incognito_windows_++;
   num_incognito_window_opened_++;
 }
@@ -76,10 +112,10 @@
 void WindowedIncognitoMonitor::OnBrowserRemoved(Browser* browser) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  base::AutoLock lock(lock_);
   if (!browser->profile()->IsOffTheRecord())
     return;
 
+  base::AutoLock lock(lock_);
   DCHECK(num_active_incognito_windows_ > 0);
   num_active_incognito_windows_--;
 }
diff --git a/chrome/browser/metrics/perf/windowed_incognito_observer.h b/chrome/browser/metrics/perf/windowed_incognito_observer.h
index 9e69e2a..4dbcd10f 100644
--- a/chrome/browser/metrics/perf/windowed_incognito_observer.h
+++ b/chrome/browser/metrics/perf/windowed_incognito_observer.h
@@ -12,6 +12,11 @@
 
 class Browser;
 
+namespace base {
+template <class T>
+class NoDestructor;
+}  // namespace base
+
 namespace metrics {
 
 class WindowedIncognitoMonitor;
@@ -22,21 +27,17 @@
 //
 // Example:
 //
-// // Create an WindowedIncognitoMonitor on the UI thread:
-// auto windowed_incognito_monitor =
-//     std:::make_unique<WindowedIncognitoMonitor>();
+// // Initialize the WindowedIncognitoMonitor on the UI thread:
+// WindowedIncognitoMonitor::Init();
 //
 // // Use an observer from any sequence:
-// auto observer = windowed_incognito_monitor->CreateObserver();
+// auto observer = WindowedIncognitoMonitor::CreateObserver();
 // bool active = observer->IncognitoActive();
 // // |active| will be true if there is any active incognito window.
 //
 // // An incognito window is opened.
 // bool launched = observer->IncognitoLaunched();
 // EXPECT_TRUE(launched);
-//
-// // Destroy the monitor on the UI thread:
-// windowed_incognito_monitor.reset();
 class WindowedIncognitoObserver {
  public:
   explicit WindowedIncognitoObserver(WindowedIncognitoMonitor* monitor,
@@ -64,14 +65,24 @@
 // for creating and serving WindowedIncognitoObserver are thread-safe.
 class WindowedIncognitoMonitor : public BrowserListObserver {
  public:
-  WindowedIncognitoMonitor();
-  ~WindowedIncognitoMonitor() override;
+  // Must be called on the UI thread before any observers are created.
+  static void Init();
 
   // Returns an instance of WindowedIncognitoObserver that represents the
   // request for monitoring any incognito window launches from now on.
-  std::unique_ptr<WindowedIncognitoObserver> CreateObserver();
+  static std::unique_ptr<WindowedIncognitoObserver> CreateObserver();
 
  protected:
+  static WindowedIncognitoMonitor* Get();
+
+  friend class base::NoDestructor<WindowedIncognitoMonitor>;
+  WindowedIncognitoMonitor();
+  ~WindowedIncognitoMonitor() override;
+
+  void RegisterInstance();
+  void UnregisterInstance();
+  std::unique_ptr<WindowedIncognitoObserver> CreateIncognitoObserver();
+
   // Making IncognitoActive() and IncognitoLaunched() only accessible from
   // WindowedIncognitoObserver;
   friend class WindowedIncognitoObserver;
@@ -97,6 +108,11 @@
   }
 
  private:
+  // Number of initialization attempts.
+  int running_sessions_ = 0;
+
+  // Protects access to |num_active_incognito_windows_| and
+  // |num_incognito_window_opened_|.
   mutable base::Lock lock_;
 
   // The number of active incognito window(s).
diff --git a/chrome/browser/net/dns_util.cc b/chrome/browser/net/dns_util.cc
new file mode 100644
index 0000000..71a5f24d
--- /dev/null
+++ b/chrome/browser/net/dns_util.cc
@@ -0,0 +1,37 @@
+// 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/net/dns_util.h"
+
+#include "net/third_party/uri_template/uri_template.h"
+#include "url/gurl.h"
+
+bool IsValidDoHTemplate(const std::string& server_template,
+                        std::string* server_method) {
+  std::string url_string;
+  std::string test_query = "this_is_a_test_query";
+  std::unordered_map<std::string, std::string> template_params(
+      {{"dns", test_query}});
+  std::set<std::string> vars_found;
+  bool valid_template = uri_template::Expand(server_template, template_params,
+                                             &url_string, &vars_found);
+  if (!valid_template) {
+    // The URI template is malformed.
+    return false;
+  }
+  GURL url(url_string);
+  if (!url.is_valid() || !url.SchemeIs("https")) {
+    // The expanded template must be a valid HTTPS URL.
+    return false;
+  }
+  if (url.host().find(test_query) != std::string::npos) {
+    // The dns variable may not be part of the hostname.
+    return false;
+  }
+  // If the template contains a dns variable, use GET, otherwise use POST.
+  DCHECK(server_method);
+  *server_method =
+      (vars_found.find("dns") == vars_found.end()) ? "POST" : "GET";
+  return true;
+}
diff --git a/chrome/browser/net/dns_util.h b/chrome/browser/net/dns_util.h
new file mode 100644
index 0000000..e628c584
--- /dev/null
+++ b/chrome/browser/net/dns_util.h
@@ -0,0 +1,17 @@
+// 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_NET_DNS_UTIL_H_
+#define CHROME_BROWSER_NET_DNS_UTIL_H_
+
+#include <string>
+
+// Returns true if the URI template is acceptable for sending requests. If so,
+// the |server_method| is set to "GET" if the template contains a "dns" variable
+// and to "POST" otherwise. Any "dns" variable may not be part of the hostname,
+// and the expanded template must parse to a valid HTTPS URL.
+bool IsValidDoHTemplate(const std::string& server_template,
+                        std::string* server_method);
+
+#endif  // CHROME_BROWSER_NET_DNS_UTIL_H_
diff --git a/chrome/browser/net/dns_util_unittest.cc b/chrome/browser/net/dns_util_unittest.cc
new file mode 100644
index 0000000..5a014b19
--- /dev/null
+++ b/chrome/browser/net/dns_util_unittest.cc
@@ -0,0 +1,48 @@
+// 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/net/dns_util.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(NetDnsUtilTest, IsValidDoHTemplate) {
+  std::string server_method;
+  EXPECT_TRUE(IsValidDoHTemplate(
+      "https://dnsserver.example.net/dns-query{?dns}", &server_method));
+  EXPECT_EQ("GET", server_method);
+
+  EXPECT_TRUE(IsValidDoHTemplate(
+      "https://dnsserver.example.net/dns-query{?dns,extra}", &server_method));
+  EXPECT_EQ("GET", server_method);
+
+  EXPECT_TRUE(IsValidDoHTemplate(
+      "https://dnsserver.example.net/dns-query{?query}", &server_method));
+  EXPECT_EQ("POST", server_method);
+
+  EXPECT_TRUE(IsValidDoHTemplate("https://dnsserver.example.net/dns-query",
+                                 &server_method));
+  EXPECT_EQ("POST", server_method);
+
+  EXPECT_TRUE(IsValidDoHTemplate("https://query:{dns}@dnsserver.example.net",
+                                 &server_method));
+  EXPECT_EQ("GET", server_method);
+
+  EXPECT_TRUE(IsValidDoHTemplate("https://dnsserver.example.net{/dns}",
+                                 &server_method));
+  EXPECT_EQ("GET", server_method);
+
+  // Invalid template format
+  EXPECT_FALSE(IsValidDoHTemplate(
+      "https://dnsserver.example.net/dns-query{{?dns}}", &server_method));
+  // Must be HTTPS
+  EXPECT_FALSE(IsValidDoHTemplate("http://dnsserver.example.net/dns-query",
+                                  &server_method));
+  EXPECT_FALSE(IsValidDoHTemplate(
+      "http://dnsserver.example.net/dns-query{?dns}", &server_method));
+  // Template must expand to a valid URL
+  EXPECT_FALSE(IsValidDoHTemplate("https://{?dns}", &server_method));
+  // The hostname must not contain the dns variable
+  EXPECT_FALSE(
+      IsValidDoHTemplate("https://{dns}.dnsserver.net", &server_method));
+}
diff --git a/chrome/browser/net/profile_network_context_service.cc b/chrome/browser/net/profile_network_context_service.cc
index cf29bab..1db9dee3 100644
--- a/chrome/browser/net/profile_network_context_service.cc
+++ b/chrome/browser/net/profile_network_context_service.cc
@@ -109,11 +109,7 @@
 
   if (chromeos::ProfileHelper::Get()->IsSigninProfile(profile) ||
       chromeos::ProfileHelper::Get()->IsLockScreenAppProfile(profile)) {
-    // No need to override the feature-set setting through policy for sign-in
-    // and lock screen app profiles, as no custom trust anchors can be active
-    // there.
-    return base::FeatureList::IsEnabled(
-        net::features::kCertVerifierBuiltinFeature);
+    return true;
   }
 
   // TODO(https://crbug.com/982936): Instead of evaluating the primary profile
diff --git a/chrome/browser/net/profile_network_context_service_browsertest.cc b/chrome/browser/net/profile_network_context_service_browsertest.cc
index bcc5359..badcdb6 100644
--- a/chrome/browser/net/profile_network_context_service_browsertest.cc
+++ b/chrome/browser/net/profile_network_context_service_browsertest.cc
@@ -320,25 +320,26 @@
       ProfileNetworkContextServiceCertVerifierBuiltinDisabledBrowsertest);
 };
 
-// If the built-in cert verifier is disabled, it should be disabled everywhere.
+// If the built-in cert verifier feature is disabled, it should be disabled in
+// user profiles but enabled in the sign-in profile.
 IN_PROC_BROWSER_TEST_F(
     ProfileNetworkContextServiceCertVerifierBuiltinDisabledBrowsertest,
     TurnedOffByFeature) {
   SkipToLoginScreen();
-  EXPECT_FALSE(IsSigninProfileUsingBuiltinCertVerifier());
+  EXPECT_TRUE(IsSigninProfileUsingBuiltinCertVerifier());
 
   LogIn(kAccountId, kAccountPassword, kEmptyServices);
 
   EXPECT_FALSE(IsActiveProfileUsingBuiltinCertVerifier());
 }
 
-// If the built-in cert verifier is disabled, but policy force-enables it for a
-// profile, it should be enabled in the profile.
+// If the built-in cert verifier feature is disabled, but policy force-enables
+// it for a profile, it should be enabled in the profile.
 IN_PROC_BROWSER_TEST_F(
     ProfileNetworkContextServiceCertVerifierBuiltinDisabledBrowsertest,
     TurnedOffByFeatureOverrideByPolicy) {
   SkipToLoginScreen();
-  EXPECT_FALSE(IsSigninProfileUsingBuiltinCertVerifier());
+  EXPECT_TRUE(IsSigninProfileUsingBuiltinCertVerifier());
 
   SetPolicyValue(policy::key::kBuiltinCertificateVerifierEnabled,
                  base::Value(true));
diff --git a/chrome/browser/net/system_network_context_manager.cc b/chrome/browser/net/system_network_context_manager.cc
index 41f1a05..77db734 100644
--- a/chrome/browser/net/system_network_context_manager.cc
+++ b/chrome/browser/net/system_network_context_manager.cc
@@ -23,6 +23,7 @@
 #include "chrome/browser/chrome_content_browser_client.h"
 #include "chrome/browser/component_updater/crl_set_component_installer.h"
 #include "chrome/browser/net/chrome_mojo_proxy_resolver_factory.h"
+#include "chrome/browser/net/dns_util.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "chrome/browser/ssl/ssl_config_service_manager.h"
 #include "chrome/common/channel_info.h"
@@ -51,7 +52,6 @@
 #include "content/public/common/service_names.mojom.h"
 #include "content/public/common/user_agent.h"
 #include "mojo/public/cpp/bindings/associated_interface_ptr.h"
-#include "net/dns/public/util.h"
 #include "net/net_buildflags.h"
 #include "net/third_party/uri_template/uri_template.h"
 #include "services/network/network_service.h"
@@ -93,28 +93,23 @@
   *insecure_stub_resolver_enabled =
       local_state->GetBoolean(prefs::kBuiltInDnsClientEnabled);
 
-  const auto& doh_server_list =
-      local_state->GetList(prefs::kDnsOverHttpsServers)->GetList();
-  const auto& doh_server_method_list =
-      local_state->GetList(prefs::kDnsOverHttpsServerMethods)->GetList();
+  std::string doh_mode = local_state->GetString(prefs::kDnsOverHttpsMode);
+  if (doh_mode == "secure")
+    *secure_dns_mode = net::DnsConfig::SecureDnsMode::SECURE;
+  else if (doh_mode == "automatic")
+    *secure_dns_mode = net::DnsConfig::SecureDnsMode::AUTOMATIC;
+  else
+    *secure_dns_mode = net::DnsConfig::SecureDnsMode::OFF;
 
-  // The two lists may have mismatched lengths during a pref change. Just skip
-  // the DOH server list updates then, as the configuration may be incorrect.
-  //
-  // TODO(mmenke): May need to improve safety here when / if DNS over HTTPS is
-  // exposed via settings, as it's possible for the old and new lengths to be
-  // the same, but the servers not to match. Either a PostTask or merging the
-  // prefs would work around that.
-  if (doh_server_list.size() == doh_server_method_list.size()) {
-    for (size_t i = 0; i < doh_server_list.size(); ++i) {
-      if (!doh_server_list[i].is_string() ||
-          !doh_server_method_list[i].is_string()) {
-        continue;
-      }
-
-      if (!net::dns_util::IsValidDoHTemplate(
-              doh_server_list[i].GetString(),
-              doh_server_method_list[i].GetString())) {
+  std::string doh_templates =
+      local_state->GetString(prefs::kDnsOverHttpsTemplates);
+  std::string server_method;
+  if (!doh_templates.empty() &&
+      *secure_dns_mode != net::DnsConfig::SecureDnsMode::OFF) {
+    for (const std::string& server_template :
+         SplitString(doh_templates, " ", base::TRIM_WHITESPACE,
+                     base::SPLIT_WANT_NONEMPTY)) {
+      if (!IsValidDoHTemplate(server_template, &server_method)) {
         continue;
       }
 
@@ -125,18 +120,11 @@
 
       network::mojom::DnsOverHttpsServerPtr dns_over_https_server =
           network::mojom::DnsOverHttpsServer::New();
-      dns_over_https_server->server_template = doh_server_list[i].GetString();
-      dns_over_https_server->use_post =
-          (doh_server_method_list[i].GetString() == "POST");
+      dns_over_https_server->server_template = server_template;
+      dns_over_https_server->use_post = (server_method == "POST");
       (*dns_over_https_servers)->emplace_back(std::move(dns_over_https_server));
     }
   }
-
-  // TODO(crbug.com/985589): Read secure dns mode from prefs.
-  if (dns_over_https_servers->has_value())
-    *secure_dns_mode = net::DnsConfig::SecureDnsMode::AUTOMATIC;
-  else
-    *secure_dns_mode = net::DnsConfig::SecureDnsMode::OFF;
 }
 
 void OnStubResolverConfigChanged(PrefService* local_state,
@@ -384,31 +372,28 @@
   // features before registering change callbacks for these preferences.
   local_state_->SetDefaultPrefValue(prefs::kBuiltInDnsClientEnabled,
                                     base::Value(ShouldEnableAsyncDns()));
-  base::ListValue default_doh_servers;
-  base::ListValue default_doh_server_methods;
+  std::string default_doh_mode = "off";
+  std::string default_doh_templates = "";
   if (base::FeatureList::IsEnabled(features::kDnsOverHttps)) {
-    std::string server(variations::GetVariationParamValueByFeature(
-        features::kDnsOverHttps, "server"));
-    std::string method(variations::GetVariationParamValueByFeature(
-        features::kDnsOverHttps, "method"));
-    if (!server.empty()) {
-      default_doh_servers.AppendString(server);
-      default_doh_server_methods.AppendString(method);
+    if (features::kDnsOverHttpsFallbackParam.Get()) {
+      default_doh_mode = "automatic";
+    } else {
+      default_doh_mode = "secure";
     }
+    default_doh_templates = features::kDnsOverHttpsTemplatesParam.Get();
   }
-  local_state_->SetDefaultPrefValue(prefs::kDnsOverHttpsServers,
-                                    std::move(default_doh_servers));
-  local_state_->SetDefaultPrefValue(prefs::kDnsOverHttpsServerMethods,
-                                    std::move(default_doh_server_methods));
+  local_state_->SetDefaultPrefValue(prefs::kDnsOverHttpsMode,
+                                    base::Value(default_doh_mode));
+  local_state_->SetDefaultPrefValue(prefs::kDnsOverHttpsTemplates,
+                                    base::Value(default_doh_templates));
 
   PrefChangeRegistrar::NamedChangeCallback dns_pref_callback =
       base::BindRepeating(&OnStubResolverConfigChanged,
                           base::Unretained(local_state_));
   pref_change_registrar_.Add(prefs::kBuiltInDnsClientEnabled,
                              dns_pref_callback);
-  pref_change_registrar_.Add(prefs::kDnsOverHttpsServers, dns_pref_callback);
-  pref_change_registrar_.Add(prefs::kDnsOverHttpsServerMethods,
-                             dns_pref_callback);
+  pref_change_registrar_.Add(prefs::kDnsOverHttpsMode, dns_pref_callback);
+  pref_change_registrar_.Add(prefs::kDnsOverHttpsTemplates, dns_pref_callback);
 
   PrefChangeRegistrar::NamedChangeCallback auth_pref_callback =
       base::BindRepeating(&OnAuthPrefsChanged, base::Unretained(local_state_));
@@ -456,8 +441,8 @@
   // captured). Thus, the preference defaults are updated in the constructor
   // for SystemNetworkContextManager, at which point the feature list is ready.
   registry->RegisterBooleanPref(prefs::kBuiltInDnsClientEnabled, false);
-  registry->RegisterListPref(prefs::kDnsOverHttpsServers);
-  registry->RegisterListPref(prefs::kDnsOverHttpsServerMethods);
+  registry->RegisterStringPref(prefs::kDnsOverHttpsMode, std::string());
+  registry->RegisterStringPref(prefs::kDnsOverHttpsTemplates, std::string());
 
   // Static auth params
   registry->RegisterStringPref(prefs::kAuthSchemes,
diff --git a/chrome/browser/net/system_network_context_manager_browsertest.cc b/chrome/browser/net/system_network_context_manager_browsertest.cc
index 8f6fae3..a6c2446 100644
--- a/chrome/browser/net/system_network_context_manager_browsertest.cc
+++ b/chrome/browser/net/system_network_context_manager_browsertest.cc
@@ -50,11 +50,10 @@
       insecure_stub_resolver_enabled, secure_dns_mode, dns_over_https_servers);
 }
 
-// Checks the values returned by GetStubResolverConfigForTesting() match
+// Checks that the values returned by GetStubResolverConfigForTesting() match
 // |async_dns_feature_enabled| (With empty DNS over HTTPS prefs). Then sets
-// various DNS over HTTPS servers, and makes sure the settings are respected.
-// TODO(crbug.com/985589): Check that the SecureDnsMode is read correctly from
-// the prefs once it is stored there.
+// various DoH modes and DoH template strings and makes sure the settings are
+// respected.
 void RunStubResolverConfigTests(bool async_dns_feature_enabled) {
   // Check initial state.
   bool insecure_stub_resolver_enabled = !async_dns_feature_enabled;
@@ -67,149 +66,91 @@
   EXPECT_EQ(net::DnsConfig::SecureDnsMode::OFF, secure_dns_mode);
   EXPECT_FALSE(dns_over_https_servers.has_value());
 
-  // Check state after setting various DNS over HTTPS preferences.
-
-  // The POST template is only valid for POSTs, though the GET template is
-  // technically valid for both POSTs and GETs.
-  const char kGoodPostTemplate[] = "https://foo.test/";
-  const char kGoodGetTemplate[] = "https://bar.test/dns-query{?dns}";
-  const char kBadTemplate[] = "dns-query{?dns}";
-
-  const char kPost[] = "POST";
-  // The code actually looks for POST and not-POST, but may as well use "GET"
-  // for not-POST.
-  const char kGet[] = "GET";
+  std::string good_post_template = "https://foo.test/";
+  std::string good_get_template = "https://bar.test/dns-query{?dns}";
+  std::string bad_template = "dns-query{?dns}";
+  std::string good_then_bad_template = good_get_template + " " + bad_template;
+  std::string bad_then_good_template = bad_template + " " + good_get_template;
+  std::string multiple_good_templates =
+      "  " + good_get_template + "   " + good_post_template + "  ";
 
   PrefService* local_state = g_browser_process->local_state();
-  base::Value servers(base::Value::Type::LIST);
-  base::Value methods(base::Value::Type::LIST);
-
-  // Test cases with server and method length mismatches. This shouldn't happen
-  // at steady state, but can happen during pref changes.
-
-  servers.GetList().push_back(base::Value(kGoodGetTemplate));
-  local_state->Set(prefs::kDnsOverHttpsServers, servers);
-  local_state->Set(prefs::kDnsOverHttpsServerMethods, methods);
+  local_state->SetString(prefs::kDnsOverHttpsMode, "secure");
+  local_state->SetString(prefs::kDnsOverHttpsTemplates, bad_template);
   GetStubResolverConfig(&insecure_stub_resolver_enabled, &secure_dns_mode,
                         &dns_over_https_servers);
   EXPECT_EQ(async_dns_feature_enabled, insecure_stub_resolver_enabled);
-  EXPECT_EQ(net::DnsConfig::SecureDnsMode::OFF, secure_dns_mode);
+  EXPECT_EQ(net::DnsConfig::SecureDnsMode::SECURE, secure_dns_mode);
   EXPECT_FALSE(dns_over_https_servers.has_value());
-  servers.GetList().clear();
-  methods.GetList().clear();
 
-  methods.GetList().push_back(base::Value(kPost));
-  local_state->Set(prefs::kDnsOverHttpsServers, servers);
-  local_state->Set(prefs::kDnsOverHttpsServerMethods, methods);
+  local_state->SetString(prefs::kDnsOverHttpsTemplates, good_post_template);
   GetStubResolverConfig(&insecure_stub_resolver_enabled, &secure_dns_mode,
                         &dns_over_https_servers);
   EXPECT_EQ(async_dns_feature_enabled, insecure_stub_resolver_enabled);
-  EXPECT_EQ(net::DnsConfig::SecureDnsMode::OFF, secure_dns_mode);
-  EXPECT_FALSE(dns_over_https_servers.has_value());
-  servers.GetList().clear();
-  methods.GetList().clear();
-
-  // Test case with incorrect server type.
-  servers.GetList().push_back(base::Value(15));
-  methods.GetList().push_back(base::Value(kPost));
-  local_state->Set(prefs::kDnsOverHttpsServers, servers);
-  local_state->Set(prefs::kDnsOverHttpsServerMethods, methods);
-  GetStubResolverConfig(&insecure_stub_resolver_enabled, &secure_dns_mode,
-                        &dns_over_https_servers);
-  EXPECT_EQ(async_dns_feature_enabled, insecure_stub_resolver_enabled);
-  EXPECT_EQ(net::DnsConfig::SecureDnsMode::OFF, secure_dns_mode);
-  EXPECT_FALSE(dns_over_https_servers.has_value());
-  servers.GetList().clear();
-  methods.GetList().clear();
-
-  // Test case with incorrect method type.
-  servers.GetList().push_back(base::Value(kGoodGetTemplate));
-  methods.GetList().push_back(base::Value(3.14));
-  local_state->Set(prefs::kDnsOverHttpsServers, servers);
-  local_state->Set(prefs::kDnsOverHttpsServerMethods, methods);
-  GetStubResolverConfig(&insecure_stub_resolver_enabled, &secure_dns_mode,
-                        &dns_over_https_servers);
-  EXPECT_EQ(async_dns_feature_enabled, insecure_stub_resolver_enabled);
-  EXPECT_EQ(net::DnsConfig::SecureDnsMode::OFF, secure_dns_mode);
-  EXPECT_FALSE(dns_over_https_servers.has_value());
-  servers.GetList().clear();
-  methods.GetList().clear();
-
-  // Test case with one bad template.
-  servers.GetList().push_back(base::Value(kBadTemplate));
-  methods.GetList().push_back(base::Value(kPost));
-  local_state->Set(prefs::kDnsOverHttpsServers, servers);
-  local_state->Set(prefs::kDnsOverHttpsServerMethods, methods);
-  GetStubResolverConfig(&insecure_stub_resolver_enabled, &secure_dns_mode,
-                        &dns_over_https_servers);
-  EXPECT_EQ(async_dns_feature_enabled, insecure_stub_resolver_enabled);
-  EXPECT_EQ(net::DnsConfig::SecureDnsMode::OFF, secure_dns_mode);
-  EXPECT_FALSE(dns_over_https_servers.has_value());
-  servers.GetList().clear();
-  methods.GetList().clear();
-
-  // Test case with one good template.
-  servers.GetList().push_back(base::Value(kGoodPostTemplate));
-  methods.GetList().push_back(base::Value(kPost));
-  local_state->Set(prefs::kDnsOverHttpsServers, servers);
-  local_state->Set(prefs::kDnsOverHttpsServerMethods, methods);
-  GetStubResolverConfig(&insecure_stub_resolver_enabled, &secure_dns_mode,
-                        &dns_over_https_servers);
-  EXPECT_EQ(async_dns_feature_enabled, insecure_stub_resolver_enabled);
-  EXPECT_EQ(net::DnsConfig::SecureDnsMode::AUTOMATIC, secure_dns_mode);
+  EXPECT_EQ(net::DnsConfig::SecureDnsMode::SECURE, secure_dns_mode);
   ASSERT_TRUE(dns_over_https_servers.has_value());
   ASSERT_EQ(1u, dns_over_https_servers->size());
-  EXPECT_EQ(kGoodPostTemplate, dns_over_https_servers->at(0)->server_template);
+  EXPECT_EQ(good_post_template, dns_over_https_servers->at(0)->server_template);
   EXPECT_EQ(true, dns_over_https_servers->at(0)->use_post);
-  servers.GetList().clear();
-  methods.GetList().clear();
 
-  // Test case with one good template, one bad one.
-  servers.GetList().push_back(base::Value(kGoodGetTemplate));
-  methods.GetList().push_back(base::Value(kGet));
-  servers.GetList().push_back(base::Value(kBadTemplate));
-  methods.GetList().push_back(base::Value(kPost));
-  local_state->Set(prefs::kDnsOverHttpsServers, servers);
-  local_state->Set(prefs::kDnsOverHttpsServerMethods, methods);
+  local_state->SetString(prefs::kDnsOverHttpsMode, "automatic");
+  local_state->SetString(prefs::kDnsOverHttpsTemplates, bad_template);
+  GetStubResolverConfig(&insecure_stub_resolver_enabled, &secure_dns_mode,
+                        &dns_over_https_servers);
+  EXPECT_EQ(async_dns_feature_enabled, insecure_stub_resolver_enabled);
+  EXPECT_EQ(net::DnsConfig::SecureDnsMode::AUTOMATIC, secure_dns_mode);
+  EXPECT_FALSE(dns_over_https_servers.has_value());
+
+  local_state->SetString(prefs::kDnsOverHttpsTemplates, good_then_bad_template);
   GetStubResolverConfig(&insecure_stub_resolver_enabled, &secure_dns_mode,
                         &dns_over_https_servers);
   EXPECT_EQ(async_dns_feature_enabled, insecure_stub_resolver_enabled);
   EXPECT_EQ(net::DnsConfig::SecureDnsMode::AUTOMATIC, secure_dns_mode);
   ASSERT_TRUE(dns_over_https_servers.has_value());
   ASSERT_EQ(1u, dns_over_https_servers->size());
-  EXPECT_EQ(kGoodGetTemplate, dns_over_https_servers->at(0)->server_template);
-  EXPECT_EQ(false, dns_over_https_servers->at(0)->use_post);
-  servers.GetList().clear();
-  methods.GetList().clear();
+  EXPECT_EQ(good_get_template, dns_over_https_servers->at(0)->server_template);
+  EXPECT_FALSE(dns_over_https_servers->at(0)->use_post);
 
-  // Test case with two good templates.
-  servers.GetList().push_back(base::Value(kGoodPostTemplate));
-  methods.GetList().push_back(base::Value(kPost));
-  servers.GetList().push_back(base::Value(kGoodGetTemplate));
-  methods.GetList().push_back(base::Value(kGet));
-  local_state->Set(prefs::kDnsOverHttpsServers, servers);
-  local_state->Set(prefs::kDnsOverHttpsServerMethods, methods);
+  local_state->SetString(prefs::kDnsOverHttpsTemplates, bad_then_good_template);
+  GetStubResolverConfig(&insecure_stub_resolver_enabled, &secure_dns_mode,
+                        &dns_over_https_servers);
+  EXPECT_EQ(async_dns_feature_enabled, insecure_stub_resolver_enabled);
+  EXPECT_EQ(net::DnsConfig::SecureDnsMode::AUTOMATIC, secure_dns_mode);
+  ASSERT_TRUE(dns_over_https_servers.has_value());
+  ASSERT_EQ(1u, dns_over_https_servers->size());
+  EXPECT_EQ(good_get_template, dns_over_https_servers->at(0)->server_template);
+  EXPECT_FALSE(dns_over_https_servers->at(0)->use_post);
+
+  local_state->SetString(prefs::kDnsOverHttpsTemplates,
+                         multiple_good_templates);
   GetStubResolverConfig(&insecure_stub_resolver_enabled, &secure_dns_mode,
                         &dns_over_https_servers);
   EXPECT_EQ(async_dns_feature_enabled, insecure_stub_resolver_enabled);
   EXPECT_EQ(net::DnsConfig::SecureDnsMode::AUTOMATIC, secure_dns_mode);
   ASSERT_TRUE(dns_over_https_servers.has_value());
   ASSERT_EQ(2u, dns_over_https_servers->size());
-  EXPECT_EQ(kGoodPostTemplate, dns_over_https_servers->at(0)->server_template);
-  EXPECT_EQ(true, dns_over_https_servers->at(0)->use_post);
-  EXPECT_EQ(kGoodGetTemplate, dns_over_https_servers->at(1)->server_template);
-  EXPECT_EQ(false, dns_over_https_servers->at(1)->use_post);
-  servers.GetList().clear();
-  methods.GetList().clear();
+  EXPECT_EQ(good_get_template, dns_over_https_servers->at(0)->server_template);
+  EXPECT_FALSE(dns_over_https_servers->at(0)->use_post);
+  EXPECT_EQ(good_post_template, dns_over_https_servers->at(1)->server_template);
+  EXPECT_TRUE(dns_over_https_servers->at(1)->use_post);
 
-  // Test case with policy BuiltInDnsClientEnabled enabled.
-  local_state->Set(prefs::kDnsOverHttpsServers, servers);
-  local_state->Set(prefs::kDnsOverHttpsServerMethods, methods);
+  local_state->SetString(prefs::kDnsOverHttpsMode, "off");
+  local_state->SetString(prefs::kDnsOverHttpsTemplates, good_get_template);
   GetStubResolverConfig(&insecure_stub_resolver_enabled, &secure_dns_mode,
                         &dns_over_https_servers);
   EXPECT_EQ(async_dns_feature_enabled, insecure_stub_resolver_enabled);
   EXPECT_EQ(net::DnsConfig::SecureDnsMode::OFF, secure_dns_mode);
   EXPECT_FALSE(dns_over_https_servers.has_value());
+
+  local_state->SetString(prefs::kDnsOverHttpsMode, "no_match");
+  GetStubResolverConfig(&insecure_stub_resolver_enabled, &secure_dns_mode,
+                        &dns_over_https_servers);
+  EXPECT_EQ(async_dns_feature_enabled, insecure_stub_resolver_enabled);
+  EXPECT_EQ(net::DnsConfig::SecureDnsMode::OFF, secure_dns_mode);
+  EXPECT_FALSE(dns_over_https_servers.has_value());
+
+  // Test case with policy BuiltInDnsClientEnabled enabled. The DoH fields
+  // should be unaffected.
   local_state->Set(prefs::kBuiltInDnsClientEnabled,
                    base::Value(!async_dns_feature_enabled));
   GetStubResolverConfig(&insecure_stub_resolver_enabled, &secure_dns_mode,
diff --git a/chrome/browser/net/trial_comparison_cert_verifier_controller.cc b/chrome/browser/net/trial_comparison_cert_verifier_controller.cc
index e01a2bf..548eb5a 100644
--- a/chrome/browser/net/trial_comparison_cert_verifier_controller.cc
+++ b/chrome/browser/net/trial_comparison_cert_verifier_controller.cc
@@ -12,6 +12,7 @@
 #include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_macros.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/profiles/profile_manager.h"
@@ -57,7 +58,7 @@
 bool TrialComparisonCertVerifierController::MaybeAllowedForProfile(
     Profile* profile) {
   bool is_official_build = g_is_fake_official_build_for_cert_verifier_testing;
-#if defined(OFFICIAL_BUILD) && defined(GOOGLE_CHROME_BUILD)
+#if defined(OFFICIAL_BUILD) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
   is_official_build = true;
 #endif
 
diff --git a/chrome/browser/net/trial_comparison_cert_verifier_controller_unittest.cc b/chrome/browser/net/trial_comparison_cert_verifier_controller_unittest.cc
index a1983c6..d64e19b 100644
--- a/chrome/browser/net/trial_comparison_cert_verifier_controller_unittest.cc
+++ b/chrome/browser/net/trial_comparison_cert_verifier_controller_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/run_loop.h"
 #include "base/task/post_task.h"
 #include "base/test/scoped_feature_list.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/safe_browsing/certificate_reporting_service_factory.h"
 #include "chrome/browser/safe_browsing/certificate_reporting_service_test_utils.h"
@@ -272,13 +273,13 @@
   CreateController();
 
   EXPECT_FALSE(trial_controller().IsAllowed());
-#if defined(OFFICIAL_BUILD) && defined(GOOGLE_CHROME_BUILD)
+#if defined(OFFICIAL_BUILD) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // In a real official build, expect the trial config to be updated.
   EXPECT_CALL(mock_config_client(), OnTrialConfigUpdated(true)).Times(1);
 #endif
   safe_browsing::SetExtendedReportingPref(pref_service(), true);
 
-#if defined(OFFICIAL_BUILD) && defined(GOOGLE_CHROME_BUILD)
+#if defined(OFFICIAL_BUILD) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // In a real official build, expect the trial to be allowed now.  (Don't
   // need to test sending reports here, since that'll be tested by
   // OfficialBuildTrialEnabled.)
diff --git a/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc b/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc
index fbab482..f4631552d 100644
--- a/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc
+++ b/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc
@@ -22,6 +22,7 @@
 #include "components/optimization_guide/hints_fetcher.h"
 #include "components/optimization_guide/hints_processing_util.h"
 #include "components/optimization_guide/optimization_filter.h"
+#include "components/optimization_guide/optimization_guide_constants.h"
 #include "components/optimization_guide/optimization_guide_features.h"
 #include "components/optimization_guide/optimization_guide_prefs.h"
 #include "components/optimization_guide/optimization_guide_service.h"
@@ -477,7 +478,8 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   // Record the result of loading a hint. This is used as a signal for testing.
-  LOCAL_HISTOGRAM_BOOLEAN("OptimizationGuide.LoadedHint.Result", loaded_hint);
+  LOCAL_HISTOGRAM_BOOLEAN(optimization_guide::kLoadedHintLocalHistogramString,
+                          loaded_hint);
 
   // Run the callback now that the hint is loaded. This is used as a signal by
   // tests.
diff --git a/chrome/browser/page_load_metrics/page_load_tracker.cc b/chrome/browser/page_load_metrics/page_load_tracker.cc
index cb6d40d..fefd7c5 100644
--- a/chrome/browser/page_load_metrics/page_load_tracker.cc
+++ b/chrome/browser/page_load_metrics/page_load_tracker.cc
@@ -81,10 +81,13 @@
   if (transition & ui::PAGE_TRANSITION_CLIENT_REDIRECT) {
     return END_CLIENT_REDIRECT;
   }
-  if (ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_RELOAD))
-    return END_RELOAD;
+  // Check for forward/back navigations first since there are forward/back
+  // navigations that haved PAGE_TRANSITION_RELOAD but are not user reloads
+  // (pull-to-refresh or preview opt-out).
   if (transition & ui::PAGE_TRANSITION_FORWARD_BACK)
     return END_FORWARD_BACK;
+  if (ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_RELOAD))
+    return END_RELOAD;
   if (ui::PageTransitionIsNewNavigation(transition))
     return END_NEW_NAVIGATION;
   NOTREACHED()
diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc
index 4a4720d..363ab363 100644
--- a/chrome/browser/pdf/pdf_extension_test.cc
+++ b/chrome/browser/pdf/pdf_extension_test.cc
@@ -24,6 +24,7 @@
 #include "base/test/test_timeouts.h"
 #include "base/thread_annotations.h"
 #include "base/threading/thread_restrictions.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/extensions/component_loader.h"
@@ -427,7 +428,7 @@
 #define MAYBE_Load Load
 #endif
 IN_PROC_BROWSER_TEST_P(PDFExtensionLoadTest, MAYBE_Load) {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // Load private PDFs.
   LoadAllPdfsTest("pdf_private", GetParam());
 #endif
@@ -1137,7 +1138,7 @@
   EXPECT_EQ(ax::mojom::Role::kRegion, region->data().role);
 }
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 // Test a particular PDF encountered in the wild that triggered a crash
 // when accessibility is enabled.  (http://crbug.com/668724)
 IN_PROC_BROWSER_TEST_F(PDFExtensionTest, PdfAccessibilityTextRunCrash) {
@@ -2337,16 +2338,16 @@
     // the expectation file contains a skip marker.
     // This is used to skip certain tests on certain platforms.
     content::DumpAccessibilityTestHelper test_helper(formatter.get());
-    base::Optional<base::FilePath> expected_file_path =
+    base::FilePath expected_file_path =
         test_helper.GetExpectationFilePath(test_file_path);
-    if (!expected_file_path) {
+    if (expected_file_path.empty()) {
       LOG(INFO) << "No expectation file present, ignoring test on this "
                    "platform.";
       return;
     }
 
     base::Optional<std::vector<std::string>> expected_lines =
-        test_helper.LoadExpectationFile(*expected_file_path);
+        test_helper.LoadExpectationFile(expected_file_path);
     if (!expected_lines) {
       LOG(INFO) << "Skipping this test on this platform.";
       return;
@@ -2378,7 +2379,7 @@
 
     // Validate the dump against the expectation file.
     EXPECT_TRUE(test_helper.ValidateAgainstExpectation(
-        test_file_path, *expected_file_path, actual_lines, *expected_lines));
+        test_file_path, expected_file_path, actual_lines, *expected_lines));
   }
 
   void AddDefaultFilters(std::vector<PropertyFilter>* property_filters) {
diff --git a/chrome/browser/plugins/plugin_info_host_impl.cc b/chrome/browser/plugins/plugin_info_host_impl.cc
index 4c90434..865ca928 100644
--- a/chrome/browser/plugins/plugin_info_host_impl.cc
+++ b/chrome/browser/plugins/plugin_info_host_impl.cc
@@ -16,6 +16,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
 #include "base/task_runner_util.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
@@ -327,11 +328,11 @@
   std::vector<std::string> mime_types;
   PluginService::GetInstance()->GetPluginInfoArray(
       url, mime_type, allow_wildcard, &matching_plugins, &mime_types);
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   base::EraseIf(matching_plugins, [&](const WebPluginInfo& info) {
     return info.path.value() == ChromeContentClient::kNotPresent;
   });
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
   if (matching_plugins.empty()) {
     *status = chrome::mojom::PluginStatus::kNotFound;
     return false;
diff --git a/chrome/browser/policy/browser_dm_token_storage_win.cc b/chrome/browser/policy/browser_dm_token_storage_win.cc
index 5f74cf3..497fa7e 100644
--- a/chrome/browser/policy/browser_dm_token_storage_win.cc
+++ b/chrome/browser/policy/browser_dm_token_storage_win.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/policy/browser_dm_token_storage_win.h"
 
+// Must be first.
 #include <windows.h>
 
 #include <comutil.h>
@@ -30,18 +31,19 @@
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/win/registry.h"
 #include "base/win/scoped_bstr.h"
+#include "build/branding_buildflags.h"
 #include "chrome/install_static/install_util.h"
 #include "chrome/installer/util/install_util.h"
 #include "chrome/installer/util/util_constants.h"
 #include "content/public/browser/browser_thread.h"
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #include "google_update/google_update_idl.h"
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
 namespace policy {
 namespace {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 // Explicitly allow DMTokenStorage impersonate the client since some COM code
 // elsewhere in the browser process may have previously used
 // CoInitializeSecurity to set the impersonation level to something other than
@@ -53,10 +55,10 @@
       COLE_DEFAULT_PRINCIPAL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
       RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_DYNAMIC_CLOAKING);
 }
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
 bool StoreDMTokenInRegistry(const std::string& token) {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   if (token.empty())
     return false;
 
@@ -122,7 +124,7 @@
   return true;
 #else
   return false;
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 }
 }  // namespace
 
diff --git a/chrome/browser/policy/chrome_browser_policy_connector.cc b/chrome/browser/policy/chrome_browser_policy_connector.cc
index 68b637c8..d02f19bf 100644
--- a/chrome/browser/policy/chrome_browser_policy_connector.cc
+++ b/chrome/browser/policy/chrome_browser_policy_connector.cc
@@ -13,6 +13,7 @@
 #include "base/command_line.h"
 #include "base/path_service.h"
 #include "base/task/post_task.h"
+#include "build/branding_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/policy/configuration_policy_handler_list_factory.h"
 #include "chrome/browser/policy/device_management_service_configuration.h"
@@ -177,7 +178,7 @@
   return std::make_unique<AsyncPolicyProvider>(GetSchemaRegistry(),
                                                std::move(loader));
 #elif defined(OS_MACOSX)
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // Explicitly watch the "com.google.Chrome" bundle ID, no matter what this
   // app's bundle ID actually is. All channels of Chrome should obey the same
   // policies.
diff --git a/chrome/browser/policy/cloud/machine_level_user_cloud_policy_browsertest.cc b/chrome/browser/policy/cloud/machine_level_user_cloud_policy_browsertest.cc
index 4a082b6c..61e20761 100644
--- a/chrome/browser/policy/cloud/machine_level_user_cloud_policy_browsertest.cc
+++ b/chrome/browser/policy/cloud/machine_level_user_cloud_policy_browsertest.cc
@@ -18,6 +18,7 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_browser_main.h"
@@ -449,7 +450,7 @@
     histogram_tester_.ExpectTotalCount(kEnrollmentResultMetrics, 0);
   }
 
-#if !defined(GOOGLE_CHROME_BUILD)
+#if !BUILDFLAG(GOOGLE_CHROME_BRANDING)
   void SetUpDefaultCommandLine(base::CommandLine* command_line) override {
     InProcessBrowserTest::SetUpDefaultCommandLine(command_line);
     command_line->AppendSwitch(::switches::kEnableMachineLevelUserCloudPolicy);
@@ -557,7 +558,7 @@
                                     test_server_->GetServiceURL().spec());
   }
 
-#if !defined(GOOGLE_CHROME_BUILD)
+#if !BUILDFLAG(GOOGLE_CHROME_BRANDING)
   void SetUpDefaultCommandLine(base::CommandLine* command_line) override {
     InProcessBrowserTest::SetUpDefaultCommandLine(command_line);
     command_line->AppendSwitch(::switches::kEnableMachineLevelUserCloudPolicy);
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index c7d3af3..3c2c5f0 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -14,6 +14,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/stl_util.h"
 #include "base/values.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/net/disk_cache_dir_policy_handler.h"
 #include "chrome/browser/policy/browsing_history_policy_handler.h"
@@ -956,7 +957,7 @@
     prefs::kAbusiveExperienceInterventionEnforce,
     base::Value::Type::BOOLEAN },
 
-#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
+#if defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
   { key::kThirdPartyBlockingEnabled,
     prefs::kThirdPartyBlockingEnabled,
     base::Value::Type::BOOLEAN },
diff --git a/chrome/browser/policy/machine_level_user_cloud_policy_controller.cc b/chrome/browser/policy/machine_level_user_cloud_policy_controller.cc
index 2d87f9d..ee73196 100644
--- a/chrome/browser/policy/machine_level_user_cloud_policy_controller.cc
+++ b/chrome/browser/policy/machine_level_user_cloud_policy_controller.cc
@@ -14,6 +14,7 @@
 #include "base/path_service.h"
 #include "base/task/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
@@ -38,7 +39,7 @@
 #include "chrome/install_static/install_util.h"
 #endif
 
-#if !defined(GOOGLE_CHROME_BUILD)
+#if !BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #include "chrome/common/chrome_switches.h"
 #endif
 
@@ -60,7 +61,7 @@
 // However, it can be enabled on Chromium by command line switch for test and
 // development purpose.
 bool IsMachineLevelUserCloudPolicyEnabled() {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   return true;
 #else
   return base::CommandLine::ForCurrentProcess()->HasSwitch(
diff --git a/chrome/browser/policy/policy_path_parser_mac.mm b/chrome/browser/policy/policy_path_parser_mac.mm
index c2812482..632c39f7 100644
--- a/chrome/browser/policy/policy_path_parser_mac.mm
+++ b/chrome/browser/policy/policy_path_parser_mac.mm
@@ -18,6 +18,7 @@
 #include "base/mac/scoped_cftyperef.h"
 #include "base/macros.h"
 #include "base/strings/sys_string_conversions.h"
+#include "build/branding_buildflags.h"
 #include "components/policy/policy_constants.h"
 
 namespace policy {
@@ -101,7 +102,7 @@
 void CheckUserDataDirPolicy(base::FilePath* user_data_dir) {
   // Since the configuration management infrastructure is not initialized when
   // this code runs, read the policy preference directly.
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // Explicitly access the "com.google.Chrome" bundle ID, no matter what this
   // app's bundle ID actually is. All channels of Chrome should obey the same
   // policies.
diff --git a/chrome/browser/policy/policy_prefs_browsertest.cc b/chrome/browser/policy/policy_prefs_browsertest.cc
index dc129a1..83bffc4 100644
--- a/chrome/browser/policy/policy_prefs_browsertest.cc
+++ b/chrome/browser/policy/policy_prefs_browsertest.cc
@@ -26,6 +26,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/values.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
@@ -191,7 +192,7 @@
   void AddSupportedOs(const std::string& os) { supported_os_.push_back(os); }
 
   bool IsSupported() const {
-#if !defined(GOOGLE_CHROME_BUILD)
+#if !BUILDFLAG(GOOGLE_CHROME_BRANDING)
     if (is_official_only())
       return false;
 #endif
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index a162849..6972248 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -7,6 +7,7 @@
 #include <string>
 
 #include "base/trace_event/trace_event.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/about_flags.h"
 #include "chrome/browser/accessibility/accessibility_labels_service.h"
@@ -336,11 +337,11 @@
 
 #if defined(OS_WIN)
 #include "chrome/browser/component_updater/sw_reporter_installer_win.h"
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #include "chrome/browser/win/conflicts/incompatible_applications_updater.h"
 #include "chrome/browser/win/conflicts/module_database.h"
 #include "chrome/browser/win/conflicts/third_party_conflicts_manager.h"
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #include "chrome/browser/safe_browsing/chrome_cleaner/settings_resetter_win.h"
 #include "chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_prefs_manager.h"
 #endif
@@ -697,11 +698,11 @@
 
 #if defined(OS_WIN)
   component_updater::RegisterPrefsForSwReporter(registry);
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   IncompatibleApplicationsUpdater::RegisterLocalStatePrefs(registry);
   ModuleDatabase::RegisterLocalStatePrefs(registry);
   ThirdPartyConflictsManager::RegisterLocalStatePrefs(registry);
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
   registry->RegisterBooleanPref(kHasSeenWin10PromoPage, false);  // DEPRECATED
   registry->RegisterStringPref(kLastWelcomedOSVersion, std::string());
diff --git a/chrome/browser/prefs/chrome_pref_service_factory.cc b/chrome/browser/prefs/chrome_pref_service_factory.cc
index 5e83325..d382d47 100644
--- a/chrome/browser/prefs/chrome_pref_service_factory.cc
+++ b/chrome/browser/prefs/chrome_pref_service_factory.cc
@@ -19,6 +19,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/policy/chrome_browser_policy_connector.h"
@@ -178,7 +179,7 @@
 #endif  // defined(OS_WIN)
     {29, prefs::kMediaStorageIdSalt, EnforcementLevel::ENFORCE_ON_LOAD,
      PrefTrackingStrategy::ATOMIC, ValueType::IMPERSONAL},
-#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
+#if defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
     {30, prefs::kModuleBlacklistCacheMD5Digest,
      EnforcementLevel::ENFORCE_ON_LOAD, PrefTrackingStrategy::ATOMIC,
      ValueType::IMPERSONAL},
@@ -321,7 +322,7 @@
 #endif
   std::string seed;
   CHECK(ui::ResourceBundle::HasSharedInstance());
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   seed = ui::ResourceBundle::GetSharedInstance()
              .GetRawDataResource(IDR_PREF_HASH_SEED_BIN)
              .as_string();
diff --git a/chrome/browser/previews/defer_all_script_browsertest.cc b/chrome/browser/previews/defer_all_script_browsertest.cc
index 73e015c..ad9a2478 100644
--- a/chrome/browser/previews/defer_all_script_browsertest.cc
+++ b/chrome/browser/previews/defer_all_script_browsertest.cc
@@ -24,6 +24,7 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
 #include "components/optimization_guide/hints_component_info.h"
+#include "components/optimization_guide/optimization_guide_constants.h"
 #include "components/optimization_guide/optimization_guide_features.h"
 #include "components/optimization_guide/optimization_guide_service.h"
 #include "components/optimization_guide/proto/hints.pb.h"
@@ -31,7 +32,6 @@
 #include "components/previews/content/previews_hints.h"
 #include "components/previews/content/previews_optimization_guide.h"
 #include "components/previews/content/previews_ui_service.h"
-#include "components/previews/core/previews_constants.h"
 #include "components/previews/core/previews_features.h"
 #include "components/previews/core/previews_switches.h"
 #include "components/ukm/test_ukm_recorder.h"
@@ -146,8 +146,7 @@
     ui_test_utils::NavigateToURL(browser(), url);
 
     RetryForHistogramUntilCountReached(
-        &histogram_tester,
-        previews::kPreviewsOptimizationGuideOnLoadedHintResultHistogramString,
+        &histogram_tester, optimization_guide::kLoadedHintLocalHistogramString,
         1);
   }
 
diff --git a/chrome/browser/previews/defer_all_script_priority_browsertest.cc b/chrome/browser/previews/defer_all_script_priority_browsertest.cc
index 2839401..e9b36e65 100644
--- a/chrome/browser/previews/defer_all_script_priority_browsertest.cc
+++ b/chrome/browser/previews/defer_all_script_priority_browsertest.cc
@@ -24,6 +24,7 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
 #include "components/optimization_guide/hints_component_info.h"
+#include "components/optimization_guide/optimization_guide_constants.h"
 #include "components/optimization_guide/optimization_guide_features.h"
 #include "components/optimization_guide/optimization_guide_service.h"
 #include "components/optimization_guide/proto/hints.pb.h"
@@ -31,7 +32,6 @@
 #include "components/previews/content/previews_hints.h"
 #include "components/previews/content/previews_optimization_guide.h"
 #include "components/previews/content/previews_ui_service.h"
-#include "components/previews/core/previews_constants.h"
 #include "components/previews/core/previews_features.h"
 #include "components/previews/core/previews_switches.h"
 #include "content/public/test/browser_test.h"
@@ -225,8 +225,7 @@
     ui_test_utils::NavigateToURL(browser(), url);
 
     RetryForHistogramUntilCountReached(
-        &histogram_tester,
-        previews::kPreviewsOptimizationGuideOnLoadedHintResultHistogramString,
+        &histogram_tester, optimization_guide::kLoadedHintLocalHistogramString,
         1);
   }
 
diff --git a/chrome/browser/previews/hints_fetcher_browsertest.cc b/chrome/browser/previews/hints_fetcher_browsertest.cc
index 24f6308d8..d067da7 100644
--- a/chrome/browser/previews/hints_fetcher_browsertest.cc
+++ b/chrome/browser/previews/hints_fetcher_browsertest.cc
@@ -25,6 +25,7 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
 #include "components/optimization_guide/hints_component_info.h"
+#include "components/optimization_guide/optimization_guide_constants.h"
 #include "components/optimization_guide/optimization_guide_features.h"
 #include "components/optimization_guide/optimization_guide_prefs.h"
 #include "components/optimization_guide/optimization_guide_service.h"
@@ -35,7 +36,6 @@
 #include "components/previews/content/previews_optimization_guide.h"
 #include "components/previews/content/previews_ui_service.h"
 #include "components/previews/core/previews_black_list.h"
-#include "components/previews/core/previews_constants.h"
 #include "components/previews/core/previews_features.h"
 #include "components/previews/core/previews_switches.h"
 #include "content/public/browser/browser_task_traits.h"
@@ -217,8 +217,7 @@
     ui_test_utils::NavigateToURL(browser(), url);
 
     RetryForHistogramUntilCountReached(
-        &histogram_tester,
-        previews::kPreviewsOptimizationGuideOnLoadedHintResultHistogramString,
+        &histogram_tester, optimization_guide::kLoadedHintLocalHistogramString,
         1);
   }
 
diff --git a/chrome/browser/previews/previews_browsertest.cc b/chrome/browser/previews/previews_browsertest.cc
index 018e882..1d65189 100644
--- a/chrome/browser/previews/previews_browsertest.cc
+++ b/chrome/browser/previews/previews_browsertest.cc
@@ -23,6 +23,7 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
 #include "components/optimization_guide/hints_component_info.h"
+#include "components/optimization_guide/optimization_guide_constants.h"
 #include "components/optimization_guide/optimization_guide_features.h"
 #include "components/optimization_guide/optimization_guide_service.h"
 #include "components/optimization_guide/proto/hints.pb.h"
@@ -30,7 +31,6 @@
 #include "components/previews/content/previews_decider_impl.h"
 #include "components/previews/content/previews_optimization_guide.h"
 #include "components/previews/content/previews_ui_service.h"
-#include "components/previews/core/previews_constants.h"
 #include "components/previews/core/previews_features.h"
 #include "components/previews/core/previews_switches.h"
 #include "content/public/browser/browser_task_traits.h"
@@ -276,8 +276,7 @@
     ui_test_utils::NavigateToURL(browser(), hint_setup_url);
 
     RetryForHistogramUntilCountReached(
-        &histogram_tester,
-        previews::kPreviewsOptimizationGuideOnLoadedHintResultHistogramString,
+        &histogram_tester, optimization_guide::kLoadedHintLocalHistogramString,
         1);
   }
 
diff --git a/chrome/browser/previews/previews_lite_page_browsertest.cc b/chrome/browser/previews/previews_lite_page_browsertest.cc
index d43571e81..bcc07385 100644
--- a/chrome/browser/previews/previews_lite_page_browsertest.cc
+++ b/chrome/browser/previews/previews_lite_page_browsertest.cc
@@ -68,7 +68,6 @@
 #include "components/previews/content/previews_optimization_guide.h"
 #include "components/previews/content/previews_ui_service.h"
 #include "components/previews/content/previews_user_data.h"
-#include "components/previews/core/previews_constants.h"
 #include "components/previews/core/previews_experiments.h"
 #include "components/previews/core/previews_features.h"
 #include "components/previews/core/previews_lite_page_redirect.h"
diff --git a/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc b/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc
index d5e97dc..ba65cd0 100644
--- a/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc
+++ b/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc
@@ -26,6 +26,7 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
 #include "components/optimization_guide/hints_component_info.h"
+#include "components/optimization_guide/optimization_guide_constants.h"
 #include "components/optimization_guide/optimization_guide_features.h"
 #include "components/optimization_guide/optimization_guide_service.h"
 #include "components/optimization_guide/proto/hints.pb.h"
@@ -35,7 +36,6 @@
 #include "components/previews/content/previews_optimization_guide.h"
 #include "components/previews/content/previews_ui_service.h"
 #include "components/previews/core/previews_black_list.h"
-#include "components/previews/core/previews_constants.h"
 #include "components/previews/core/previews_features.h"
 #include "components/previews/core/previews_switches.h"
 #include "components/ukm/test_ukm_recorder.h"
@@ -215,8 +215,7 @@
     ui_test_utils::NavigateToURL(browser(), url);
 
     RetryForHistogramUntilCountReached(
-        &histogram_tester,
-        previews::kPreviewsOptimizationGuideOnLoadedHintResultHistogramString,
+        &histogram_tester, optimization_guide::kLoadedHintLocalHistogramString,
         1);
   }
 
diff --git a/chrome/browser/printing/print_preview_dialog_controller.cc b/chrome/browser/printing/print_preview_dialog_controller.cc
index d2a3be7..d8d50b43 100644
--- a/chrome/browser/printing/print_preview_dialog_controller.cc
+++ b/chrome/browser/printing/print_preview_dialog_controller.cc
@@ -14,6 +14,7 @@
 #include "base/macros.h"
 #include "base/path_service.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
@@ -42,7 +43,7 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/web_dialogs/web_dialog_delegate.h"
 
-#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
+#if defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #include "chrome/browser/win/conflicts/module_database.h"
 #endif
 
@@ -241,7 +242,7 @@
 
 // static
 void PrintPreviewDialogController::PrintPreview(WebContents* initiator) {
-#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
+#if defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
   ModuleDatabase::GetInstance()->DisableThirdPartyBlocking();
 #endif
 
diff --git a/chrome/browser/printing/printing_message_filter.cc b/chrome/browser/printing/printing_message_filter.cc
index 355324f..40762a3 100644
--- a/chrome/browser/printing/printing_message_filter.cc
+++ b/chrome/browser/printing/printing_message_filter.cc
@@ -11,6 +11,7 @@
 #include "base/bind.h"
 #include "base/memory/singleton.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/printing/print_job_manager.h"
@@ -31,7 +32,7 @@
 #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
 #endif
 
-#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
+#if defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #include "chrome/browser/win/conflicts/module_database.h"
 #endif
 
@@ -184,7 +185,7 @@
 void PrintingMessageFilter::OnScriptedPrint(
     const PrintHostMsg_ScriptedPrint_Params& params,
     IPC::Message* reply_msg) {
-#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
+#if defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
   ModuleDatabase::GetInstance()->DisableThirdPartyBlocking();
 #endif
 
diff --git a/chrome/browser/profile_resetter/triggered_profile_resetter_win.cc b/chrome/browser/profile_resetter/triggered_profile_resetter_win.cc
index e3f4155..a0239b4 100644
--- a/chrome/browser/profile_resetter/triggered_profile_resetter_win.cc
+++ b/chrome/browser/profile_resetter/triggered_profile_resetter_win.cc
@@ -2,19 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/profile_resetter/triggered_profile_resetter.h"
-
 #include <stdint.h>
 
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/win/registry.h"
 #include "build/branding_buildflags.h"
+#include "chrome/browser/profile_resetter/triggered_profile_resetter.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
 #include "components/prefs/pref_service.h"
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #define PRODUCT_NAME L"Google\\Chrome"
 #elif BUILDFLAG(CHROMIUM_BRANDING)
 #define PRODUCT_NAME L"Chromium"
diff --git a/chrome/browser/resource_coordinator/local_site_characteristics_data_store.cc b/chrome/browser/resource_coordinator/local_site_characteristics_data_store.cc
index 423cc90..fd0b5dac 100644
--- a/chrome/browser/resource_coordinator/local_site_characteristics_data_store.cc
+++ b/chrome/browser/resource_coordinator/local_site_characteristics_data_store.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/resource_coordinator/tab_manager_features.h"
 #include "components/history/core/browser/history_service.h"
 #include "components/history/core/browser/url_row.h"
+#include "url/gurl.h"
 
 namespace resource_coordinator {
 
@@ -24,9 +25,9 @@
     "Site Characteristics Database";
 
 size_t CountOriginsInURLRows(const history::URLRows& rows) {
-  std::set<url::Origin> origins;
+  std::set<GURL> origins;
   for (auto& row : rows)
-    origins.insert(url::Origin::Create(row.url()));
+    origins.insert(row.url().GetOrigin());
   return origins.size();
 }
 
@@ -164,8 +165,11 @@
   } else {
     std::vector<url::Origin> origins_to_remove;
 
-    DCHECK_EQ(deletion_info.deleted_urls_origin_map().size(),
-              CountOriginsInURLRows(deletion_info.deleted_rows()));
+    // CHECK_EQ instead of DCHECK_EQ to determine if
+    // https://crbug.com/966059 still happens in production.
+    // TODO(sebmarchand): Remove once https://crbug.com/966059 is fixed.
+    CHECK_EQ(deletion_info.deleted_urls_origin_map().size(),
+             CountOriginsInURLRows(deletion_info.deleted_rows()));
     for (const auto& it : deletion_info.deleted_urls_origin_map()) {
       const url::Origin origin = url::Origin::Create(it.first);
       const int remaining_visits_in_history = it.second.first;
diff --git a/chrome/browser/resources/chromeos/switch_access/menu_manager.js b/chrome/browser/resources/chromeos/switch_access/menu_manager.js
index cce66f4..94cd0a0 100644
--- a/chrome/browser/resources/chromeos/switch_access/menu_manager.js
+++ b/chrome/browser/resources/chromeos/switch_access/menu_manager.js
@@ -79,7 +79,9 @@
      */
     this.menuPanel_;
 
-    this.init_();
+    if (window.switchAccess.improvedTextInputEnabled()) {
+      this.init_();
+    }
   }
 
   /**
@@ -123,9 +125,12 @@
       chrome.accessibilityPrivate.setSwitchAccessMenuState(
           true, navNode.location, actions.length);
       this.menuOriginNode_ = navNode;
-      this.menuOriginNode_.addEventListener(
-          chrome.automation.EventType.TEXT_SELECTION_CHANGED,
-          this.onSelectionChanged_.bind(this), false /** Don't use capture. */);
+      if (window.switchAccess.improvedTextInputEnabled()) {
+        this.menuOriginNode_.addEventListener(
+            chrome.automation.EventType.TEXT_SELECTION_CHANGED,
+            this.onSelectionChanged_.bind(this),
+            false /** Don't use capture. */);
+      }
     } else {
       console.log('Unable to show Switch Access menu.');
     }
@@ -191,9 +196,11 @@
     if (this.node_)
       this.node_ = null;
 
-    this.menuOriginNode_.removeEventListener(
-        chrome.automation.EventType.TEXT_SELECTION_CHANGED,
-        this.onSelectionChanged_.bind(this), false /** Don't use capture. */);
+    if (window.switchAccess.improvedTextInputEnabled()) {
+      this.menuOriginNode_.removeEventListener(
+          chrome.automation.EventType.TEXT_SELECTION_CHANGED,
+          this.onSelectionChanged_.bind(this), false /** Don't use capture. */);
+    }
     chrome.accessibilityPrivate.setSwitchAccessMenuState(
         false /** Hide the menu. */, SAConstants.EMPTY_LOCATION, 0);
   }
diff --git a/chrome/browser/resources/chromeos/switch_access/menu_panel.html b/chrome/browser/resources/chromeos/switch_access/menu_panel.html
index 0b9ee33..d47c7bd 100644
--- a/chrome/browser/resources/chromeos/switch_access/menu_panel.html
+++ b/chrome/browser/resources/chromeos/switch_access/menu_panel.html
@@ -85,6 +85,7 @@
     <button class="action" id="moveUpOneLineOfText">
       <img src="icons/moveUpOneLineOfText.svg">
       <p class="i18n" msgid="move_up_one_line_of_text"></p>
+    </button>
     <button class="action" id="selectStart">
       <img src="icons/textSelectionStart.svg">
       <p class="i18n" msgid="selection_start"></p>
diff --git a/chrome/browser/resources/chromeos/switch_access/switch_access.js b/chrome/browser/resources/chromeos/switch_access/switch_access.js
index e73b5da2..989cef2 100644
--- a/chrome/browser/resources/chromeos/switch_access/switch_access.js
+++ b/chrome/browser/resources/chromeos/switch_access/switch_access.js
@@ -62,6 +62,11 @@
    * @private
    */
   init_() {
+    chrome.commandLinePrivate.hasSwitch(
+        'enable-experimental-accessibility-switch-access-text', (result) => {
+          this.enableImprovedTextInput_ = result;
+        });
+
     this.commands_ = new Commands(this);
     this.autoScanManager_ = new AutoScanManager(this);
     const onPrefsReady =
@@ -75,11 +80,6 @@
       if (this.navReadyCallback_)
         this.navReadyCallback_();
     }.bind(this));
-
-    chrome.commandLinePrivate.hasSwitch(
-        'enable-experimental-accessibility-switch-access-text', (result) => {
-          this.enableImprovedTextInput_ = result;
-        });
   }
 
   /**
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_reboot_dialog_controller_impl_browsertest_win.cc b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_reboot_dialog_controller_impl_browsertest_win.cc
index bfee018..821d119 100644
--- a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_reboot_dialog_controller_impl_browsertest_win.cc
+++ b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_reboot_dialog_controller_impl_browsertest_win.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "base/run_loop.h"
+#include "build/branding_buildflags.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_navigation_util_win.h"
 #include "chrome/browser/safe_browsing/chrome_cleaner/mock_chrome_cleaner_controller_win.h"
@@ -45,7 +46,7 @@
 
 // The reboot flow requires loading chrome://settings/cleanup, which only
 // exists on the Google-branded browser.
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
 class ChromeCleanerRebootFlowTest : public InProcessBrowserTest {
  public:
@@ -190,7 +191,7 @@
   EnsureCompletedExecution();
 }
 
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
 class ChromeCleanerRebootDialogResponseTest : public InProcessBrowserTest {
  public:
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/mock_chrome_cleaner_process_win.cc b/chrome/browser/safe_browsing/chrome_cleaner/mock_chrome_cleaner_process_win.cc
index 976bc4e1..bc983297 100644
--- a/chrome/browser/safe_browsing/chrome_cleaner/mock_chrome_cleaner_process_win.cc
+++ b/chrome/browser/safe_browsing/chrome_cleaner/mock_chrome_cleaner_process_win.cc
@@ -27,6 +27,7 @@
 #include "base/values.h"
 #include "base/win/scoped_handle.h"
 #include "base/win/win_util.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/grit/generated_resources.h"
@@ -543,7 +544,7 @@
           kInstalledExtensionId1, kInstalledExtensionId2, kUnknownExtensionId,
       });
 // Scanner results only fetches extension names on Windows Chrome build.
-#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
+#if defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
       expected_extension_names_ = base::Optional<std::vector<base::string16>>({
           kInstalledExtensionName1, kInstalledExtensionName2,
           l10n_util::GetStringFUTF16(
diff --git a/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.cc b/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.cc
index c222b1c0b..58ec6efb 100644
--- a/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.cc
@@ -22,6 +22,7 @@
 #include "base/task/post_task.h"
 #include "base/task/task_traits.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
@@ -49,7 +50,7 @@
 
 const base::Feature kIncidentReportingEnableUpload {
   "IncidentReportingEnableUpload",
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
       base::FEATURE_ENABLED_BY_DEFAULT
 #else
       base::FEATURE_DISABLED_BY_DEFAULT
diff --git a/chrome/browser/safe_browsing/incident_reporting/platform_state_store_win_unittest.cc b/chrome/browser/safe_browsing/incident_reporting/platform_state_store_win_unittest.cc
index 8bf892d..e7d29413 100644
--- a/chrome/browser/safe_browsing/incident_reporting/platform_state_store_win_unittest.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/platform_state_store_win_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/test_reg_util_win.h"
 #include "base/win/registry.h"
+#include "build/branding_buildflags.h"
 #include "chrome/browser/prefs/browser_prefs.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
@@ -109,7 +110,7 @@
 
 // static
 const char PlatformStateStoreWinTest::kProfileName_[] = "test_profile";
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 const base::char16 PlatformStateStoreWinTest::kStoreKeyName_[] =
     L"Software\\Google\\Chrome\\IncidentsSent";
 #else
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.cc b/chrome/browser/safe_browsing/safe_browsing_service.cc
index f2a346df..cbac4e7 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service.cc
@@ -22,6 +22,7 @@
 #include "base/threading/thread.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/trace_event/trace_event.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -252,7 +253,7 @@
 #if defined(OS_WIN)
   client_name = install_static::GetSafeBrowsingName();
 #else
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   client_name = "googlechrome";
 #else
   client_name = "chromium";
diff --git a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
index 9375b03..072a00a8 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
@@ -38,6 +38,7 @@
 #include "base/task/post_task.h"
 #include "base/test/thread_test_helper.h"
 #include "base/time/time.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/bookmarks/startup_task_runner_service_factory.h"
 #include "chrome/browser/browser_process.h"
@@ -123,10 +124,10 @@
 
 namespace {
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 const char kBlacklistResource[] = "/blacklisted/script.js";
 const char kMaliciousResource[] = "/malware/script.js";
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 const char kEmptyPage[] = "/empty.html";
 const char kMalwareFile[] = "/downloads/dangerous/dangerous.exe";
 const char kMalwarePage[] = "/safe_browsing/malware.html";
@@ -1226,9 +1227,9 @@
   EXPECT_EQ(SB_THREAT_TYPE_URL_BINARY_MALWARE, client->GetThreatType());
 }
 
-#if defined(GOOGLE_CHROME_BUILD)
-// This test is only enabled when GOOGLE_CHROME_BUILD is true because the store
-// that this test uses is only populated on GOOGLE_CHROME_BUILD builds.
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+// This test is only enabled when GOOGLE_CHROME_BRANDING is true because the
+// store that this test uses is only populated on GOOGLE_CHROME_BRANDING builds.
 IN_PROC_BROWSER_TEST_F(V4SafeBrowsingServiceTest, CheckResourceUrl) {
   GURL blacklist_url = embedded_test_server()->GetURL(kBlacklistResource);
   GURL malware_url = embedded_test_server()->GetURL(kMaliciousResource);
@@ -1259,7 +1260,7 @@
   client->CheckResourceUrl(embedded_test_server()->GetURL(kEmptyPage));
   EXPECT_EQ(SB_THREAT_TYPE_SAFE, client->GetThreatType());
 }
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 ///////////////////////////////////////////////////////////////////////////////
 // END: These tests use SafeBrowsingService::Client to directly interact with
 // SafeBrowsingService.
diff --git a/chrome/browser/safe_browsing/settings_reset_prompt/default_settings_fetcher.cc b/chrome/browser/safe_browsing/settings_reset_prompt/default_settings_fetcher.cc
index 73ea003..a7fb6ebb 100644
--- a/chrome/browser/safe_browsing/settings_reset_prompt/default_settings_fetcher.cc
+++ b/chrome/browser/safe_browsing/settings_reset_prompt/default_settings_fetcher.cc
@@ -11,6 +11,7 @@
 #include "base/bind_helpers.h"
 #include "base/logging.h"
 #include "base/task/post_task.h"
+#include "build/branding_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/google/google_brand.h"
 #include "chrome/browser/net/system_network_context_manager.h"
@@ -25,9 +26,9 @@
 
 namespace {
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 constexpr char kOmahaUrl[] = "https://tools.google.com/service/update2";
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
 }  // namespace
 
@@ -61,7 +62,7 @@
 void DefaultSettingsFetcher::Start() {
   DCHECK(!config_fetcher_);
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   std::string brandcode;
   if (google_brand::GetBrand(&brandcode) && !brandcode.empty()) {
     config_fetcher_.reset(new BrandcodeConfigFetcher(
@@ -72,7 +73,7 @@
         GURL(kOmahaUrl), brandcode));
     return;
   }
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
   // For non Google Chrome builds and cases with an empty |brandcode|, we create
   // a default-constructed |BrandcodedDefaultSettings| object and post the
diff --git a/chrome/browser/shell_integration_linux.cc b/chrome/browser/shell_integration_linux.cc
index 707f2a9a..6b085929 100644
--- a/chrome/browser/shell_integration_linux.cc
+++ b/chrome/browser/shell_integration_linux.cc
@@ -36,6 +36,7 @@
 #include "base/threading/scoped_blocking_call.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_restrictions.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/shell_integration.h"
 #include "chrome/common/buildflags.h"
@@ -250,7 +251,7 @@
 
 // TODO(loyso): shell_integraion_linux.cc won't compile with app_list disabled?
 #if BUILDFLAG(ENABLE_APP_LIST)
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 const char kAppListDesktopName[] = "chrome-app-list";
 #else  // BUILDFLAG(CHROMIUM_BRANDING)
 const char kAppListDesktopName[] = "chromium-app-list";
@@ -416,7 +417,7 @@
 }
 
 std::string GetDesktopName(base::Environment* env) {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   version_info::Channel product_channel(chrome::GetChannel());
   switch (product_channel) {
     case version_info::Channel::DEV:
@@ -438,7 +439,7 @@
 }
 
 std::string GetIconName() {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   return "google-chrome";
 #else  // BUILDFLAG(CHROMIUM_BRANDING)
   return "chromium-browser";
diff --git a/chrome/browser/shell_integration_linux_unittest.cc b/chrome/browser/shell_integration_linux_unittest.cc
index 7ae9576e..035ecd6 100644
--- a/chrome/browser/shell_integration_linux_unittest.cc
+++ b/chrome/browser/shell_integration_linux_unittest.cc
@@ -21,6 +21,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_path_override.h"
+#include "build/branding_buildflags.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "chrome/common/chrome_constants.h"
 #include "content/public/test/test_browser_thread_bundle.h"
@@ -332,125 +333,99 @@
     bool nodisplay;
     const char* const expected_output;
   } test_cases[] = {
-    // Real-world case.
-    { "http://gmail.com",
-      "GMail",
-      "chrome-http__gmail.com",
-      "",
-      false,
+      // Real-world case.
+      {"http://gmail.com", "GMail", "chrome-http__gmail.com", "", false,
 
-      "#!/usr/bin/env xdg-open\n"
-      "[Desktop Entry]\n"
-      "Version=1.0\n"
-      "Terminal=false\n"
-      "Type=Application\n"
-      "Name=GMail\n"
-      "Exec=/opt/google/chrome/google-chrome --app=http://gmail.com/\n"
-      "Icon=chrome-http__gmail.com\n"
-      "StartupWMClass=gmail.com\n"
-    },
+       "#!/usr/bin/env xdg-open\n"
+       "[Desktop Entry]\n"
+       "Version=1.0\n"
+       "Terminal=false\n"
+       "Type=Application\n"
+       "Name=GMail\n"
+       "Exec=/opt/google/chrome/google-chrome --app=http://gmail.com/\n"
+       "Icon=chrome-http__gmail.com\n"
+       "StartupWMClass=gmail.com\n"},
 
-    // Make sure that empty icons are replaced by the chrome icon.
-    { "http://gmail.com",
-      "GMail",
-      "",
-      "",
-      false,
+      // Make sure that empty icons are replaced by the chrome icon.
+      {"http://gmail.com", "GMail", "", "", false,
 
-      "#!/usr/bin/env xdg-open\n"
-      "[Desktop Entry]\n"
-      "Version=1.0\n"
-      "Terminal=false\n"
-      "Type=Application\n"
-      "Name=GMail\n"
-      "Exec=/opt/google/chrome/google-chrome --app=http://gmail.com/\n"
-#if defined(GOOGLE_CHROME_BUILD)
-      "Icon=google-chrome\n"
+       "#!/usr/bin/env xdg-open\n"
+       "[Desktop Entry]\n"
+       "Version=1.0\n"
+       "Terminal=false\n"
+       "Type=Application\n"
+       "Name=GMail\n"
+       "Exec=/opt/google/chrome/google-chrome --app=http://gmail.com/\n"
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+       "Icon=google-chrome\n"
 #else
-      "Icon=chromium-browser\n"
+       "Icon=chromium-browser\n"
 #endif
-      "StartupWMClass=gmail.com\n"
-    },
+       "StartupWMClass=gmail.com\n"},
 
-    // Test adding categories and NoDisplay=true.
-    { "http://gmail.com",
-      "GMail",
-      "chrome-http__gmail.com",
-      "Graphics;Education;",
-      true,
+      // Test adding categories and NoDisplay=true.
+      {"http://gmail.com", "GMail", "chrome-http__gmail.com",
+       "Graphics;Education;", true,
 
-      "#!/usr/bin/env xdg-open\n"
-      "[Desktop Entry]\n"
-      "Version=1.0\n"
-      "Terminal=false\n"
-      "Type=Application\n"
-      "Name=GMail\n"
-      "Exec=/opt/google/chrome/google-chrome --app=http://gmail.com/\n"
-      "Icon=chrome-http__gmail.com\n"
-      "Categories=Graphics;Education;\n"
-      "NoDisplay=true\n"
-      "StartupWMClass=gmail.com\n"
-    },
+       "#!/usr/bin/env xdg-open\n"
+       "[Desktop Entry]\n"
+       "Version=1.0\n"
+       "Terminal=false\n"
+       "Type=Application\n"
+       "Name=GMail\n"
+       "Exec=/opt/google/chrome/google-chrome --app=http://gmail.com/\n"
+       "Icon=chrome-http__gmail.com\n"
+       "Categories=Graphics;Education;\n"
+       "NoDisplay=true\n"
+       "StartupWMClass=gmail.com\n"},
 
-    // Now we're starting to be more evil...
-    { "http://evil.com/evil --join-the-b0tnet",
-      "Ownz0red\nExec=rm -rf /",
-      "chrome-http__evil.com_evil",
-      "",
-      false,
+      // Now we're starting to be more evil...
+      {"http://evil.com/evil --join-the-b0tnet", "Ownz0red\nExec=rm -rf /",
+       "chrome-http__evil.com_evil", "", false,
 
-      "#!/usr/bin/env xdg-open\n"
-      "[Desktop Entry]\n"
-      "Version=1.0\n"
-      "Terminal=false\n"
-      "Type=Application\n"
-      "Name=http://evil.com/evil%20--join-the-b0tnet\n"
-      "Exec=/opt/google/chrome/google-chrome "
-      "--app=http://evil.com/evil%20--join-the-b0tnet\n"
-      "Icon=chrome-http__evil.com_evil\n"
-      "StartupWMClass=evil.com__evil%20--join-the-b0tnet\n"
-    },
-    { "http://evil.com/evil; rm -rf /; \"; rm -rf $HOME >ownz0red",
-      "Innocent Title",
-      "chrome-http__evil.com_evil",
-      "",
-      false,
+       "#!/usr/bin/env xdg-open\n"
+       "[Desktop Entry]\n"
+       "Version=1.0\n"
+       "Terminal=false\n"
+       "Type=Application\n"
+       "Name=http://evil.com/evil%20--join-the-b0tnet\n"
+       "Exec=/opt/google/chrome/google-chrome "
+       "--app=http://evil.com/evil%20--join-the-b0tnet\n"
+       "Icon=chrome-http__evil.com_evil\n"
+       "StartupWMClass=evil.com__evil%20--join-the-b0tnet\n"},
+      {"http://evil.com/evil; rm -rf /; \"; rm -rf $HOME >ownz0red",
+       "Innocent Title", "chrome-http__evil.com_evil", "", false,
 
-      "#!/usr/bin/env xdg-open\n"
-      "[Desktop Entry]\n"
-      "Version=1.0\n"
-      "Terminal=false\n"
-      "Type=Application\n"
-      "Name=Innocent Title\n"
-      "Exec=/opt/google/chrome/google-chrome "
-      "\"--app=http://evil.com/evil;%20rm%20-rf%20/;%20%22;%20rm%20"
-      // Note: $ is escaped as \$ within an arg to Exec, and then
-      // the \ is escaped as \\ as all strings in a Desktop file should
-      // be; finally, \\ becomes \\\\ when represented in a C++ string!
-      "-rf%20\\\\$HOME%20%3Eownz0red\"\n"
-      "Icon=chrome-http__evil.com_evil\n"
-      "StartupWMClass=evil.com__evil;%20rm%20-rf%20_;%20%22;%20"
-      "rm%20-rf%20$HOME%20%3Eownz0red\n"
-    },
-    { "http://evil.com/evil | cat `echo ownz0red` >/dev/null",
-      "Innocent Title",
-      "chrome-http__evil.com_evil",
-      "",
-      false,
+       "#!/usr/bin/env xdg-open\n"
+       "[Desktop Entry]\n"
+       "Version=1.0\n"
+       "Terminal=false\n"
+       "Type=Application\n"
+       "Name=Innocent Title\n"
+       "Exec=/opt/google/chrome/google-chrome "
+       "\"--app=http://evil.com/evil;%20rm%20-rf%20/;%20%22;%20rm%20"
+       // Note: $ is escaped as \$ within an arg to Exec, and then
+       // the \ is escaped as \\ as all strings in a Desktop file should
+       // be; finally, \\ becomes \\\\ when represented in a C++ string!
+       "-rf%20\\\\$HOME%20%3Eownz0red\"\n"
+       "Icon=chrome-http__evil.com_evil\n"
+       "StartupWMClass=evil.com__evil;%20rm%20-rf%20_;%20%22;%20"
+       "rm%20-rf%20$HOME%20%3Eownz0red\n"},
+      {"http://evil.com/evil | cat `echo ownz0red` >/dev/null",
+       "Innocent Title", "chrome-http__evil.com_evil", "", false,
 
-      "#!/usr/bin/env xdg-open\n"
-      "[Desktop Entry]\n"
-      "Version=1.0\n"
-      "Terminal=false\n"
-      "Type=Application\n"
-      "Name=Innocent Title\n"
-      "Exec=/opt/google/chrome/google-chrome "
-      "--app=http://evil.com/evil%20%7C%20cat%20%60echo%20ownz0red"
-      "%60%20%3E/dev/null\n"
-      "Icon=chrome-http__evil.com_evil\n"
-      "StartupWMClass=evil.com__evil%20%7C%20cat%20%60echo%20ownz0red"
-      "%60%20%3E_dev_null\n"
-    },
+       "#!/usr/bin/env xdg-open\n"
+       "[Desktop Entry]\n"
+       "Version=1.0\n"
+       "Terminal=false\n"
+       "Type=Application\n"
+       "Name=Innocent Title\n"
+       "Exec=/opt/google/chrome/google-chrome "
+       "--app=http://evil.com/evil%20%7C%20cat%20%60echo%20ownz0red"
+       "%60%20%3E/dev/null\n"
+       "Icon=chrome-http__evil.com_evil\n"
+       "StartupWMClass=evil.com__evil%20%7C%20cat%20%60echo%20ownz0red"
+       "%60%20%3E_dev_null\n"},
   };
 
   for (size_t i = 0; i < base::size(test_cases); i++) {
@@ -501,31 +476,28 @@
     const char* const icon_name;
     const char* const expected_output;
   } test_cases[] = {
-    // Real-world case.
-    { "Chrome Apps",
-      "chrome-apps",
+      // Real-world case.
+      {"Chrome Apps", "chrome-apps",
 
-      "[Desktop Entry]\n"
-      "Version=1.0\n"
-      "Type=Directory\n"
-      "Name=Chrome Apps\n"
-      "Icon=chrome-apps\n"
-    },
+       "[Desktop Entry]\n"
+       "Version=1.0\n"
+       "Type=Directory\n"
+       "Name=Chrome Apps\n"
+       "Icon=chrome-apps\n"},
 
-    // Make sure that empty icons are replaced by the chrome icon.
-    { "Chrome Apps",
-      "",
+      // Make sure that empty icons are replaced by the chrome icon.
+      {"Chrome Apps", "",
 
-      "[Desktop Entry]\n"
-      "Version=1.0\n"
-      "Type=Directory\n"
-      "Name=Chrome Apps\n"
-#if defined(GOOGLE_CHROME_BUILD)
-      "Icon=google-chrome\n"
+       "[Desktop Entry]\n"
+       "Version=1.0\n"
+       "Type=Directory\n"
+       "Name=Chrome Apps\n"
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+       "Icon=google-chrome\n"
 #else
-      "Icon=chromium-browser\n"
+       "Icon=chromium-browser\n"
 #endif
-    },
+      },
   };
 
   for (size_t i = 0; i < base::size(test_cases); i++) {
diff --git a/chrome/browser/ssl/cert_report_helper.cc b/chrome/browser/ssl/cert_report_helper.cc
index b3b52302..ce88dce 100644
--- a/chrome/browser/ssl/cert_report_helper.cc
+++ b/chrome/browser/ssl/cert_report_helper.cc
@@ -12,6 +12,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
@@ -202,7 +203,7 @@
   DCHECK(ShouldShowCertificateReporterCheckbox());
 
   bool is_official_build = g_is_fake_official_build_for_cert_report_testing;
-#if defined(OFFICIAL_BUILD) && defined(GOOGLE_CHROME_BUILD)
+#if defined(OFFICIAL_BUILD) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
   is_official_build = true;
 #endif
 
diff --git a/chrome/browser/subresource_filter/subresource_filter_browsertest.cc b/chrome/browser/subresource_filter/subresource_filter_browsertest.cc
index 42f80407..e13250d 100644
--- a/chrome/browser/subresource_filter/subresource_filter_browsertest.cc
+++ b/chrome/browser/subresource_filter/subresource_filter_browsertest.cc
@@ -22,6 +22,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
+#include "build/branding_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/metrics/subprocess_metrics_provider.h"
 #include "chrome/browser/safe_browsing/test_safe_browsing_database_helper.h"
@@ -223,7 +224,7 @@
                        SubresourceFilterListNeedsBranding) {
   bool has_list = database_helper()->HasListSynced(
       safe_browsing::GetUrlSubresourceFilterId());
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   EXPECT_TRUE(has_list);
 #else
   EXPECT_FALSE(has_list);
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 2c53465..d9de7126 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -26,10 +26,6 @@
 import("//ui/base/ui_features.gni")
 import("//ui/views/features.gni")
 
-if (is_chromeos) {
-  import("//chrome/browser/chromeos/kiosk_next_home/kiosk_next.gni")
-}
-
 # Use a static library here because many test binaries depend on this but don't
 # require many files from it. This makes linking more efficient.
 jumbo_split_static_library("ui") {
@@ -1957,10 +1953,6 @@
     if (use_cras) {
       defines += [ "USE_CRAS" ]
     }
-
-    if (enable_kiosk_next) {
-      defines += [ "KIOSK_NEXT" ]
-    }
   }
 
   if (is_win || is_mac || is_desktop_linux || is_chromeos) {
diff --git a/chrome/browser/ui/app_list/app_list_client_impl_browsertest.cc b/chrome/browser/ui/app_list/app_list_client_impl_browsertest.cc
index 27e923c..cdab02b 100644
--- a/chrome/browser/ui/app_list/app_list_client_impl_browsertest.cc
+++ b/chrome/browser/ui/app_list/app_list_client_impl_browsertest.cc
@@ -17,6 +17,7 @@
 #include "base/test/bind_test_util.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/apps/app_service/app_launch_params.h"
 #include "chrome/browser/apps/launch_service/launch_service.h"
@@ -261,11 +262,11 @@
 
   // Any app that opens a window to dismiss app list is good enough for this
   // test.
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   const std::string app_title = "chrome";
 #else
   const std::string app_title = "chromium";
-#endif  // !defined(GOOGLE_CHROME_BUILD)
+#endif  // !BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
   const std::string app_result_id =
       "chrome-extension://mgndgikekgjfcpckkfioiadnlibdjbkf/";
diff --git a/chrome/browser/ui/app_list/search/logging/search_ranking_event_logger_unittest.cc b/chrome/browser/ui/app_list/search/logging/search_ranking_event_logger_unittest.cc
index ecacc78..ff1c6e4 100644
--- a/chrome/browser/ui/app_list/search/logging/search_ranking_event_logger_unittest.cc
+++ b/chrome/browser/ui/app_list/search/logging/search_ranking_event_logger_unittest.cc
@@ -8,11 +8,13 @@
 #include <memory>
 #include <utility>
 
+#include "ash/public/cpp/app_list/app_list_features.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/scoped_mock_clock_override.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/time/time.h"
@@ -142,6 +144,10 @@
         base::BindRepeating(&BuildHistoryService));
     profile_ = profile_builder.Build();
 
+    scoped_feature_list_.InitWithFeaturesAndParameters(
+        {}, {app_list_features::kEnableQueryBasedMixedTypesRanker,
+             app_list_features::kEnableAppRanker});
+
     search_controller_ = std::make_unique<SearchControllerFake>(profile_.get());
 
     logger_ = std::make_unique<SearchRankingEventLogger>(
@@ -214,6 +220,7 @@
   content::TestBrowserThreadBundle thread_bundle_;
   base::ScopedMockClockOverride time_;
   base::ScopedTempDir history_dir_;
+  base::test::ScopedFeatureList scoped_feature_list_;
 
   ukm::TestAutoSetUkmRecorder recorder_;
 
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.cc b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.cc
index c8c34a64..1e646e47 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.cc
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.cc
@@ -229,9 +229,21 @@
         config, chromeos::ProfileHelper::IsEphemeralUserProfile(profile_));
   }
 
-  app_ranker_ = std::make_unique<AppSearchResultRanker>(
-      profile_->GetPath(),
-      chromeos::ProfileHelper::IsEphemeralUserProfile(profile_));
+  if (app_list_features::IsAppRankerEnabled() &&
+      GetFieldTrialParamByFeatureAsBool(app_list_features::kEnableAppRanker,
+                                        "use_recurrence_ranker", true)) {
+    RecurrenceRankerConfigProto config;
+    config.set_min_seconds_between_saves(240u);
+    config.set_condition_limit(1u);
+    config.set_condition_decay(0.5f);
+    config.set_target_limit(200);
+    config.set_target_decay(0.8f);
+    config.mutable_predictor()->mutable_default_predictor();
+
+    app_ranker_ = std::make_unique<RecurrenceRanker>(
+        "AppRanker", profile_->GetPath().AppendASCII("app_ranker.pb"), config,
+        chromeos::ProfileHelper::IsEphemeralUserProfile(profile_));
+  }
 }
 
 void SearchResultRanker::FetchRankings(const base::string16& query) {
@@ -321,8 +333,8 @@
           NormalizeId(app_launch_data.id, app_launch_data.ranking_item_type),
           app_launch_data.query);
     }
-  } else if (model == Model::APPS) {
-    app_ranker_->Train(NormalizeAppId(app_launch_data.id));
+  } else if (model == Model::APPS && app_ranker_) {
+    app_ranker_->Record(NormalizeAppId(app_launch_data.id));
   }
 }
 
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.h b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.h
index bfd6cb3..5eaaf7ca 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.h
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.h
@@ -22,7 +22,6 @@
 #include "chrome/browser/ui/app_list/search/mixer.h"
 #include "chrome/browser/ui/app_list/search/search_result_ranker/app_launch_data.h"
 #include "chrome/browser/ui/app_list/search/search_result_ranker/app_launch_event_logger.h"
-#include "chrome/browser/ui/app_list/search/search_result_ranker/app_search_result_ranker.h"
 #include "chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker_util.h"
 #include "components/history/core/browser/history_service.h"
 #include "components/history/core/browser/history_service_observer.h"
@@ -123,6 +122,10 @@
   // Ranks files and previous queries for launcher zero-state.
   std::unique_ptr<RecurrenceRanker> zero_state_mixed_types_ranker_;
 
+  // Ranks apps.
+  std::unique_ptr<RecurrenceRanker> app_ranker_;
+  std::map<std::string, float> app_ranks_;
+
   // Converts JSON config strings to RecurrenceRankerConfigProtos.
   JsonConfigConverter config_converter_;
 
@@ -135,13 +138,6 @@
   ScopedObserver<history::HistoryService, history::HistoryServiceObserver>
       history_service_observer_;
 
-  // TODO(931149): Move the AppSearchResultRanker instance and associated logic
-  // to here.
-
-  // Ranks apps and arc app shortcuts on-device.
-  std::unique_ptr<AppSearchResultRanker> app_ranker_;
-  base::flat_map<std::string, float> app_ranks_;
-
   Profile* profile_;
 
   base::WeakPtrFactory<SearchResultRanker> weak_factory_;
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker_unittest.cc b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker_unittest.cc
index b15f1a1c..b5132c45 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker_unittest.cc
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker_unittest.cc
@@ -107,13 +107,20 @@
 
   std::unique_ptr<SearchResultRanker> MakeRanker(
       bool query_based_mixed_types_enabled,
+      bool app_ranker_enabled,
       const std::map<std::string, std::string>& params = {}) {
     if (query_based_mixed_types_enabled) {
-      scoped_feature_list_.InitAndEnableFeatureWithParameters(
-          app_list_features::kEnableQueryBasedMixedTypesRanker, params);
+      scoped_feature_list_.InitWithFeaturesAndParameters(
+          {{app_list_features::kEnableQueryBasedMixedTypesRanker, params}},
+          {app_list_features::kEnableAppRanker});
+    } else if (app_ranker_enabled) {
+      scoped_feature_list_.InitWithFeaturesAndParameters(
+          {{app_list_features::kEnableAppRanker, params}},
+          {app_list_features::kEnableQueryBasedMixedTypesRanker});
     } else {
-      scoped_feature_list_.InitAndDisableFeature(
-          app_list_features::kEnableQueryBasedMixedTypesRanker);
+      scoped_feature_list_.InitWithFeaturesAndParameters(
+          {}, {app_list_features::kEnableQueryBasedMixedTypesRanker,
+               app_list_features::kEnableAppRanker});
     }
 
     auto ranker = std::make_unique<SearchResultRanker>(
@@ -156,7 +163,7 @@
 };
 
 TEST_F(SearchResultRankerTest, MixedTypesRankersAreDisabledWithFlag) {
-  auto ranker = MakeRanker(false);
+  auto ranker = MakeRanker(false, false);
   ranker->InitializeRankers();
   Wait();
 
@@ -183,7 +190,8 @@
 
 TEST_F(SearchResultRankerTest, CategoryModelImprovesScores) {
   auto ranker = MakeRanker(
-      true, {{"use_category_model", "true"}, {"boost_coefficient", "1.0"}});
+      true, false,
+      {{"use_category_model", "true"}, {"boost_coefficient", "1.0"}});
   ranker->InitializeRankers();
   Wait();
 
@@ -208,7 +216,20 @@
 }
 
 TEST_F(SearchResultRankerTest, AppModelImprovesScores) {
-  auto ranker = MakeRanker(false);
+  const std::string json = R"({
+      "min_seconds_between_saves": 250,
+      "target_limit": 100,
+      "target_decay": 0.5,
+      "condition_limit": 50,
+      "condition_decay": 0.7,
+      "predictor": {
+        "predictor_type": "frecency",
+        "decay_coeff": 0.8
+      }
+    })";
+
+  auto ranker = MakeRanker(
+      false, true, {{"use_recurrence_ranker", "true"}, {"config", json}});
   ranker->InitializeRankers();
   Wait();
 
@@ -245,7 +266,7 @@
   // model.  With the |config| parameter, the ranker uses the default predictor
   // for the RecurrenceRanker.
   base::RunLoop run_loop;
-  auto ranker = MakeRanker(true, {{"boost_coefficient", "1.0"}});
+  auto ranker = MakeRanker(true, false, {{"boost_coefficient", "1.0"}});
   ranker->set_json_config_parsed_for_testing(run_loop.QuitClosure());
   ranker->InitializeRankers();
   run_loop.Run();
@@ -291,7 +312,7 @@
   const std::string& url_4 = "some.domain.com";
 
   base::RunLoop run_loop;
-  auto ranker = MakeRanker(true, {{"boost_coefficient", "1.0"}});
+  auto ranker = MakeRanker(true, false, {{"boost_coefficient", "1.0"}});
   ranker->set_json_config_parsed_for_testing(run_loop.QuitClosure());
   ranker->InitializeRankers();
   run_loop.Run();
@@ -344,7 +365,7 @@
 
   base::RunLoop run_loop;
   auto ranker =
-      MakeRanker(true, {{"boost_coefficient", "1.0"}, {"config", json}});
+      MakeRanker(true, false, {{"boost_coefficient", "1.0"}, {"config", json}});
   ranker->set_json_config_parsed_for_testing(run_loop.QuitClosure());
   ranker->InitializeRankers();
   run_loop.Run();
@@ -372,7 +393,7 @@
 
   base::RunLoop run_loop;
   auto ranker =
-      MakeRanker(true, {{"boost_coefficient", "1.0"}, {"config", json}});
+      MakeRanker(true, false, {{"boost_coefficient", "1.0"}, {"config", json}});
   ranker->set_json_config_parsed_for_testing(run_loop.QuitClosure());
   ranker->InitializeRankers();
   run_loop.Run();
diff --git a/chrome/browser/ui/ash/keyboard_shortcut_viewer_metadata_unittest.cc b/chrome/browser/ui/ash/keyboard_shortcut_viewer_metadata_unittest.cc
index d45fe27..8f30b7f 100644
--- a/chrome/browser/ui/ash/keyboard_shortcut_viewer_metadata_unittest.cc
+++ b/chrome/browser/ui/ash/keyboard_shortcut_viewer_metadata_unittest.cc
@@ -2,19 +2,21 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "ash/components/shortcut_viewer/keyboard_shortcut_viewer_metadata.h"
+
 #include <set>
 #include <string>
 #include <tuple>
 #include <vector>
 
 #include "ash/components/shortcut_viewer/keyboard_shortcut_item.h"
-#include "ash/components/shortcut_viewer/keyboard_shortcut_viewer_metadata.h"
 #include "ash/components/strings/grit/ash_components_strings.h"
 #include "ash/public/cpp/accelerators.h"
 #include "base/hash/md5.h"
 #include "base/macros.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "build/branding_buildflags.h"
 #include "chrome/browser/ui/views/accelerator_table.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -24,7 +26,7 @@
 constexpr int kAshAcceleratorsTotalNum = 109;
 // The hash of Ash accelerators.
 constexpr char kAshAcceleratorsHash[] = "8b62c1607085b5ca6a65ef43b97deac0";
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 // Internal builds add an extra accelerator for the Feedback app.
 // The total number of Chrome accelerators (available on Chrome OS).
 constexpr int kChromeAcceleratorsTotalNum = 92;
@@ -35,7 +37,7 @@
 constexpr int kChromeAcceleratorsTotalNum = 92;
 // The hash of Chrome accelerators (available on Chrome OS).
 constexpr char kChromeAcceleratorsHash[] = "7c45362e298cf77aae142dec7154adcf";
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
 const char* BooleanToString(bool value) {
   return value ? "true" : "false";
diff --git a/chrome/browser/ui/autofill/autofill_popup_layout_model.cc b/chrome/browser/ui/autofill/autofill_popup_layout_model.cc
index f77a73e..015205cf 100644
--- a/chrome/browser/ui/autofill/autofill_popup_layout_model.cc
+++ b/chrome/browser/ui/autofill/autofill_popup_layout_model.cc
@@ -9,6 +9,7 @@
 #include "base/macros.h"
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/android/android_theme_resources.h"
 #include "chrome/browser/ui/autofill/autofill_popup_view.h"
@@ -78,13 +79,13 @@
      kResourceNotFoundId},
     {"settings", IDR_ANDROID_AUTOFILL_SETTINGS, kResourceNotFoundId},
     {"create", IDR_ANDROID_AUTOFILL_CREATE, kResourceNotFoundId},
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
     {"googlePay", IDR_ANDROID_AUTOFILL_GOOGLE_PAY, kResourceNotFoundId},
-#endif  // GOOGLE_CHROME_BUILD
-#elif defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
+#elif BUILDFLAG(GOOGLE_CHROME_BRANDING)
     {"googlePay", IDR_AUTOFILL_GOOGLE_PAY, kResourceNotFoundId},
     {"googlePayDark", IDR_AUTOFILL_GOOGLE_PAY_DARK, kResourceNotFoundId},
-#endif  // GOOGLE_CHROME_BUILD
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 };
 
 int GetRowHeightFromId(int identifier) {
@@ -233,7 +234,7 @@
     return gfx::CreateVectorIcon(kGlobeIcon, kIconSize, gfx::kChromeIconGrey);
   }
   if (icon_str == "google") {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
     return gfx::CreateVectorIcon(kGoogleGLogoIcon, kIconSize,
                                  gfx::kPlaceholderColor);
 #else
@@ -241,7 +242,7 @@
 #endif
   }
 
-#if !defined(GOOGLE_CHROME_BUILD)
+#if !BUILDFLAG(GOOGLE_CHROME_BRANDING)
   if (icon_str == "googlePay" || icon_str == "googlePayDark") {
     return gfx::ImageSkia();
   }
@@ -283,7 +284,7 @@
 
 int AutofillPopupLayoutModel::GetIconResourceID(
     const std::string& resource_name) const {
-#if !defined(GOOGLE_CHROME_BUILD)
+#if !BUILDFLAG(GOOGLE_CHROME_BRANDING)
   if (resource_name == "googlePay" || resource_name == "googlePayDark") {
     return 0;
   }
diff --git a/chrome/browser/ui/cocoa/main_menu_builder.mm b/chrome/browser/ui/cocoa/main_menu_builder.mm
index cf931785..90d57644 100644
--- a/chrome/browser/ui/cocoa/main_menu_builder.mm
+++ b/chrome/browser/ui/cocoa/main_menu_builder.mm
@@ -4,6 +4,7 @@
 
 #import "chrome/browser/ui/cocoa/main_menu_builder.h"
 
+#include "build/branding_buildflags.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/ui/cocoa/accelerators_cocoa.h"
 #include "chrome/browser/ui/cocoa/history_menu_bridge.h"
@@ -423,7 +424,7 @@
   base::scoped_nsobject<NSMenuItem> item =
       Item(IDS_HELP_MENU_MAC)
           .submenu({
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
             Item(IDS_FEEDBACK_MAC).command_id(IDC_FEEDBACK),
 #endif
                 Item(IDS_HELP_MAC)
diff --git a/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar.mm b/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar.mm
index 936f484e..cc59406 100644
--- a/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar.mm
+++ b/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar.mm
@@ -11,6 +11,7 @@
 #import "base/mac/scoped_nsobject.h"
 #import "base/mac/sdk_forward_declarations.h"
 #include "base/strings/sys_string_conversions.h"
+#include "build/branding_buildflags.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -494,7 +495,7 @@
                                             defaultProvider->short_name());
 
   NSImage* image = nil;
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   if (isGoogle) {
     image = NSImageFromImageSkiaWithColorSpace(
         gfx::CreateVectorIcon(kGoogleGLogoIcon, kTouchBarIconSize,
diff --git a/chrome/browser/ui/profile_error_dialog.cc b/chrome/browser/ui/profile_error_dialog.cc
index 018f43d..8bcbd16 100644
--- a/chrome/browser/ui/profile_error_dialog.cc
+++ b/chrome/browser/ui/profile_error_dialog.cc
@@ -69,7 +69,7 @@
   chrome::ShowWarningMessageBox(
       nullptr, l10n_util::GetStringUTF16(IDS_PROFILE_ERROR_DIALOG_TITLE),
       l10n_util::GetStringUTF16(message_id));
-#endif  // BUILDFLAGdefined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
 #endif  // !defined(OS_ANDROID)
 }
diff --git a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
index 240f837..0c012dee 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
@@ -17,6 +17,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/threading/thread_restrictions.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -909,7 +910,7 @@
   static_cast<ProfileImpl*>(profile_urls)->last_session_exit_type_ =
       Profile::EXIT_CRASHED;
 
-#if !defined(OS_MACOSX) && !defined(GOOGLE_CHROME_BUILD)
+#if !defined(OS_MACOSX) && !BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // Use HistogramTester to make sure a bubble is shown when it's not on
   // platform Mac OS X and it's not official Chrome build.
   //
@@ -920,7 +921,7 @@
   // the file thread before the bubble is shown. It is difficult to make sure
   // that the histogram check runs after all threads have finished their tasks.
   base::HistogramTester histogram_tester;
-#endif  // !defined(OS_MACOSX) && !defined(GOOGLE_CHROME_BUILD)
+#endif  // !defined(OS_MACOSX) && !BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
   base::CommandLine dummy(base::CommandLine::NO_PROGRAM);
   dummy.AppendSwitchASCII(switches::kTestType, "browser");
@@ -970,11 +971,11 @@
   EXPECT_TRUE(search::IsInstantNTP(tab_strip->GetWebContentsAt(0)));
   EnsureRestoreUIWasShown(tab_strip->GetWebContentsAt(0));
 
-#if !defined(OS_MACOSX) && !defined(GOOGLE_CHROME_BUILD)
+#if !defined(OS_MACOSX) && !BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // Each profile should have one session restore bubble shown, so we should
   // observe count 3 in bucket 0 (which represents bubble shown).
   histogram_tester.ExpectBucketCount("SessionCrashed.Bubble", 0, 3);
-#endif  // !defined(OS_MACOSX) && !defined(GOOGLE_CHROME_BUILD)
+#endif  // !defined(OS_MACOSX) && !BUILDFLAG(GOOGLE_CHROME_BRANDING)
 }
 
 IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorTest,
@@ -1048,14 +1049,14 @@
 }
 
 void StartupBrowserCreatorFirstRunTest::SetUpInProcessBrowserTestFixture() {
-#if defined(OS_LINUX) && defined(GOOGLE_CHROME_BUILD)
+#if defined(OS_LINUX) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // Set a policy that prevents the first-run dialog from being shown.
   policy_map_.Set(policy::key::kMetricsReportingEnabled,
                   policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
                   policy::POLICY_SOURCE_CLOUD,
                   std::make_unique<base::Value>(false), nullptr);
   provider_.UpdateChromePolicy(policy_map_);
-#endif  // defined(OS_LINUX) && defined(GOOGLE_CHROME_BUILD)
+#endif  // defined(OS_LINUX) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
   EXPECT_CALL(provider_, IsInitializationComplete(_))
       .WillRepeatedly(Return(true));
@@ -1091,7 +1092,7 @@
             tab_strip->GetWebContentsAt(1)->GetURL().ExtractFileName());
 }
 
-#if defined(GOOGLE_CHROME_BUILD) && defined(OS_MACOSX)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && defined(OS_MACOSX)
 // http://crbug.com/314819
 #define MAYBE_RestoreOnStartupURLsPolicySpecified \
     DISABLED_RestoreOnStartupURLsPolicySpecified
@@ -1148,7 +1149,7 @@
             tab_strip->GetWebContentsAt(0)->GetURL().ExtractFileName());
 }
 
-#if defined(GOOGLE_CHROME_BUILD) && defined(OS_MACOSX)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && defined(OS_MACOSX)
 // http://crbug.com/314819
 #define MAYBE_FirstRunTabsWithRestoreSession \
     DISABLED_FirstRunTabsWithRestoreSession
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
index b841031..aa81ec45 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -22,6 +22,7 @@
 #include "base/strings/string_util.h"
 #include "base/task/post_task.h"
 #include "base/values.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/apps/apps_launch.h"
 #include "chrome/browser/apps/launch_service/launch_service.h"
@@ -80,9 +81,9 @@
 #endif
 
 #if defined(OS_WIN)
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #include "chrome/browser/win/conflicts/incompatible_applications_updater.h"
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #include "chrome/browser/notifications/notification_platform_bridge_win.h"
 #include "chrome/browser/shell_integration_win.h"
 #include "chrome/browser/ui/startup/credential_provider_signin_dialog_win.h"
@@ -592,7 +593,7 @@
   const bool is_incognito_or_guest = profile_->IsOffTheRecord();
   bool is_post_crash_launch = HasPendingUncleanExit(profile_);
   bool has_incompatible_applications = false;
-#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
+#if defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
   if (is_post_crash_launch) {
     // Check if there are any incompatible applications cached from the last
     // Chrome run.
diff --git a/chrome/browser/ui/sync/profile_signin_confirmation_helper_browsertest.cc b/chrome/browser/ui/sync/profile_signin_confirmation_helper_browsertest.cc
index 53b590fd..e332acc9 100644
--- a/chrome/browser/ui/sync/profile_signin_confirmation_helper_browsertest.cc
+++ b/chrome/browser/ui/sync/profile_signin_confirmation_helper_browsertest.cc
@@ -8,6 +8,7 @@
 #include "base/command_line.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/first_run/first_run.h"
 #include "chrome/browser/ui/browser.h"
@@ -30,7 +31,8 @@
 };
 
 // http://crbug.com/321302
-#if defined(GOOGLE_CHROME_BUILD) && (defined(OS_MACOSX) || defined(OS_LINUX))
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && \
+    (defined(OS_MACOSX) || defined(OS_LINUX))
 #define MAYBE_HasNotBeenShutdown DISABLED_HasNotBeenShutdown
 #else
 #define MAYBE_HasNotBeenShutdown HasNotBeenShutdown
@@ -44,7 +46,8 @@
 }
 
 // http://crbug.com/321302
-#if defined(GOOGLE_CHROME_BUILD) && (defined(OS_MACOSX) || defined(OS_LINUX))
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && \
+    (defined(OS_MACOSX) || defined(OS_LINUX))
 #define MAYBE_HasNoSyncedExtensions DISABLED_HasNoSyncedExtensions
 #else
 #define MAYBE_HasNoSyncedExtensions HasNoSyncedExtensions
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc
index 63eba3b..57699df 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -1889,18 +1889,16 @@
 void TabStripModel::MoveAndSetGroup(int index,
                                     int new_index,
                                     base::Optional<TabGroupId> new_group) {
+  // Ungroup tab before moving, so that if this is the last tab in the group
+  // observers can delete that group.
   base::Optional<TabGroupId> old_group = UngroupTab(index);
-
-  // TODO(crbug.com/940677): Ideally the delta of type kGroupChanged below would
-  // be batched with the move deltas resulting from MoveWebContentsAt, but that
-  // is not possible right now.
-  if (index != new_index)
-    MoveWebContentsAtImpl(index, new_index, false);
-  contents_data_[new_index]->set_group(new_group);
+  contents_data_[index]->set_group(new_group);
   if (new_group.has_value())
     group_data_.at(new_group.value()).TabAdded();
+  NotifyGroupChange(index, old_group, new_group);
 
-  NotifyGroupChange(new_index, old_group, new_group);
+  if (index != new_index)
+    MoveWebContentsAtImpl(index, new_index, false);
 }
 
 void TabStripModel::NotifyGroupChange(int index,
diff --git a/chrome/browser/ui/toolbar/app_menu_icon_controller_unittest.cc b/chrome/browser/ui/toolbar/app_menu_icon_controller_unittest.cc
index 1adea7bc..e2d47c8f0 100644
--- a/chrome/browser/ui/toolbar/app_menu_icon_controller_unittest.cc
+++ b/chrome/browser/ui/toolbar/app_menu_icon_controller_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/time/default_clock.h"
 #include "base/time/default_tick_clock.h"
 #include "base/time/time.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/defaults.h"
 #include "chrome/browser/upgrade_detector/upgrade_detector.h"
@@ -93,7 +94,7 @@
 
   // Returns true if the test is apparently running as an unstable channel.
   bool IsUnstableChannel() {
-#if !defined(GOOGLE_CHROME_BUILD)
+#if !BUILDFLAG(GOOGLE_CHROME_BRANDING)
     // Dev and canary channels are specific to Google Chrome branding.
     return false;
 #elif defined(OS_WIN)
diff --git a/chrome/browser/ui/ui_features.cc b/chrome/browser/ui/ui_features.cc
index 440dee7..be27ca2 100644
--- a/chrome/browser/ui/ui_features.cc
+++ b/chrome/browser/ui/ui_features.cc
@@ -45,7 +45,7 @@
 // Enables popup cards containing tab information when hovering over a tab.
 // https://crbug.com/910739
 const base::Feature kTabHoverCards{"TabHoverCards",
-                                   base::FEATURE_DISABLED_BY_DEFAULT};
+                                   base::FEATURE_ENABLED_BY_DEFAULT};
 // Parameter name used for tab hover cards user study.
 // TODO(corising): Removed this after tab hover cards user study.
 const char kTabHoverCardsFeatureParameterName[] = "setting";
diff --git a/chrome/browser/ui/views/accelerator_table.cc b/chrome/browser/ui/views/accelerator_table.cc
index 53f1e63..da8b6740 100644
--- a/chrome/browser/ui/views/accelerator_table.cc
+++ b/chrome/browser/ui/views/accelerator_table.cc
@@ -157,7 +157,7 @@
 
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING) && !defined(OS_MACOSX)
     {ui::VKEY_I, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, IDC_FEEDBACK},
-#endif  // GOOGLE_CHROME_BUILD && !OS_MACOSX
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING) && !OS_MACOSX
     {ui::VKEY_N, ui::EF_SHIFT_DOWN | ui::EF_PLATFORM_ACCELERATOR,
      IDC_NEW_INCOGNITO_WINDOW},
     {ui::VKEY_T, ui::EF_PLATFORM_ACCELERATOR, IDC_NEW_TAB},
diff --git a/chrome/browser/ui/views/accelerator_table_unittest.cc b/chrome/browser/ui/views/accelerator_table_unittest.cc
index 7862e6d..8427440 100644
--- a/chrome/browser/ui/views/accelerator_table_unittest.cc
+++ b/chrome/browser/ui/views/accelerator_table_unittest.cc
@@ -2,12 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/browser/ui/views/accelerator_table.h"
+
 #include <stddef.h>
 
 #include <set>
 
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
-#include "chrome/browser/ui/views/accelerator_table.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/events/event_constants.h"
 
@@ -71,7 +73,7 @@
     // See http://crbug.com/737307 for details.
     if (ash_entry.action == ash::NEW_WINDOW ||
         ash_entry.action == ash::NEW_INCOGNITO_WINDOW ||
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
         ash_entry.action == ash::OPEN_FEEDBACK_PAGE ||
 #endif
         ash_entry.action == ash::RESTORE_TAB ||
diff --git a/chrome/browser/ui/views/autofill/payments/local_card_migration_bubble_views.cc b/chrome/browser/ui/views/autofill/payments/local_card_migration_bubble_views.cc
index 0caf3db7..373efd6 100644
--- a/chrome/browser/ui/views/autofill/payments/local_card_migration_bubble_views.cc
+++ b/chrome/browser/ui/views/autofill/payments/local_card_migration_bubble_views.cc
@@ -5,10 +5,12 @@
 #include "chrome/browser/ui/views/autofill/payments/local_card_migration_bubble_views.h"
 
 #include <stddef.h>
+
 #include <memory>
 #include <utility>
 
 #include "base/strings/utf_string_conversions.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/ui/browser_dialogs.h"
@@ -35,7 +37,7 @@
 namespace autofill {
 
 namespace {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 const int kMigrationBubbleGooglePayLogoWidth = 40;
 #endif
 const int kMigrationBubbleGooglePayLogoHeight = 16;
@@ -105,7 +107,7 @@
       views::BoxLayout::Orientation::kVertical, gfx::Insets(),
       ChromeLayoutProvider::Get()->GetDistanceMetric(
           DISTANCE_RELATED_CONTROL_VERTICAL_SMALL)));
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // kGooglePayLogoIcon is square, and CreateTiledImage() will clip it whereas
   // setting the icon size would rescale it incorrectly.
   gfx::ImageSkia image = gfx::ImageSkiaOperations::CreateTiledImage(
diff --git a/chrome/browser/ui/views/autofill/payments/local_card_migration_dialog_view.cc b/chrome/browser/ui/views/autofill/payments/local_card_migration_dialog_view.cc
index 7f6abcb..60c44be 100644
--- a/chrome/browser/ui/views/autofill/payments/local_card_migration_dialog_view.cc
+++ b/chrome/browser/ui/views/autofill/payments/local_card_migration_dialog_view.cc
@@ -12,6 +12,7 @@
 #include "base/location.h"
 #include "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/branding_buildflags.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/ui/autofill/payments/local_card_migration_dialog_factory.h"
 #include "chrome/browser/ui/autofill/payments/local_card_migration_dialog_state.h"
@@ -76,7 +77,7 @@
   auto title = std::make_unique<views::Label>(
       l10n_util::GetPluralStringFUTF16(message_id, card_list_size));
   constexpr int kMigrationDialogTitleFontSize = 8;
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   constexpr int kMigrationDialogTitleMarginTop = 0;
 #else
   constexpr int kMigrationDialogTitleMarginTop = 12;
@@ -478,7 +479,7 @@
       views::BoxLayout::Orientation::kVertical, gfx::Insets(),
       kMigrationDialogMainContainerChildSpacing));
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   auto* image = new views::ImageView();
   constexpr int kImageBorderBottom = 8;
   image->SetBorder(views::CreateEmptyBorder(0, 0, kImageBorderBottom, 0));
@@ -490,7 +491,7 @@
   image->SetAccessibleName(
       l10n_util::GetStringUTF16(IDS_AUTOFILL_GOOGLE_PAY_LOGO_ACCESSIBLE_NAME));
   AddChildView(image);
-#endif  // GOOGLE_CHROME_BUILD
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
   LocalCardMigrationDialogState view_state = controller_->GetViewState();
   AddChildView(CreateTitle(view_state, this, controller_->GetCardList().size())
diff --git a/chrome/browser/ui/views/autofill/payments/local_card_migration_error_dialog_view.cc b/chrome/browser/ui/views/autofill/payments/local_card_migration_error_dialog_view.cc
index 98c0581..34328e7 100644
--- a/chrome/browser/ui/views/autofill/payments/local_card_migration_error_dialog_view.cc
+++ b/chrome/browser/ui/views/autofill/payments/local_card_migration_error_dialog_view.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/views/autofill/payments/local_card_migration_error_dialog_view.h"
 
 #include "base/macros.h"
+#include "build/branding_buildflags.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/ui/autofill/payments/local_card_migration_dialog_factory.h"
 #include "chrome/browser/ui/autofill/payments/payments_ui_constants.h"
@@ -101,7 +102,7 @@
       views::BoxLayout::Orientation::kVertical, gfx::Insets(),
       kMigrationDialogMainContainerChildSpacing));
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   auto* image = new views::ImageView();
   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
   image->SetImage(
@@ -111,7 +112,7 @@
   image->SetAccessibleName(
       l10n_util::GetStringUTF16(IDS_AUTOFILL_GOOGLE_PAY_LOGO_ACCESSIBLE_NAME));
   AddChildView(image);
-#endif  // GOOGLE_CHROME_BUILD
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
   auto* error_view = new views::View();
   auto* horizontal_layout =
diff --git a/chrome/browser/ui/views/autofill/payments/payments_view_util.cc b/chrome/browser/ui/views/autofill/payments/payments_view_util.cc
index da389036..4f8634b5 100644
--- a/chrome/browser/ui/views/autofill/payments/payments_view_util.cc
+++ b/chrome/browser/ui/views/autofill/payments/payments_view_util.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/views/autofill/payments/payments_view_util.h"
 
+#include "build/branding_buildflags.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
 #include "chrome/browser/ui/views/chrome_typography.h"
@@ -31,7 +32,7 @@
 namespace {
 
 // Dimensions of the Google Pay logo.
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 constexpr int kGooglePayLogoWidth = 40;
 #endif
 constexpr int kGooglePayLogoHeight = 16;
@@ -61,7 +62,7 @@
   layout->StartRow(views::GridLayout::kFixedSize, 0);
 
   auto icon_view = std::make_unique<views::ImageView>();
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // kGooglePayLogoIcon is square, and CreateTiledImage() will clip it whereas
   // setting the icon size would rescale it incorrectly.
   gfx::ImageSkia image = gfx::ImageSkiaOperations::CreateTiledImage(
diff --git a/chrome/browser/ui/views/chrome_views_delegate_linux.cc b/chrome/browser/ui/views/chrome_views_delegate_linux.cc
index 3a3712e..13723310c 100644
--- a/chrome/browser/ui/views/chrome_views_delegate_linux.cc
+++ b/chrome/browser/ui/views/chrome_views_delegate_linux.cc
@@ -6,6 +6,7 @@
 
 #include "base/environment.h"
 #include "base/nix/xdg_util.h"
+#include "build/branding_buildflags.h"
 #include "chrome/browser/ui/views/native_widget_factory.h"
 #include "chrome/common/channel_info.h"
 #include "chrome/grit/chrome_unscaled_resources.h"
@@ -23,7 +24,7 @@
 }
 
 int GetWindowIconResourceId() {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   switch (chrome::GetChannel()) {
     case version_info::Channel::DEV:
       return IDR_PRODUCT_LOGO_128_DEV;
diff --git a/chrome/browser/ui/views/frame/global_menu_bar_x11.cc b/chrome/browser/ui/views/frame/global_menu_bar_x11.cc
index 69736824..0ef67fa8 100644
--- a/chrome/browser/ui/views/frame/global_menu_bar_x11.cc
+++ b/chrome/browser/ui/views/frame/global_menu_bar_x11.cc
@@ -20,6 +20,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/branding_buildflags.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/history/top_sites_factory.h"
@@ -148,7 +149,7 @@
     {kMenuEnd}};
 
 constexpr GlobalMenuBarCommand kHelpMenu[] = {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
     {IDC_FEEDBACK, IDS_FEEDBACK},
 #endif
     {IDC_HELP_PAGE_VIA_MENU, IDS_HELP_PAGE},
diff --git a/chrome/browser/ui/views/media_router/cast_dialog_sink_button.cc b/chrome/browser/ui/views/media_router/cast_dialog_sink_button.cc
index a7c92b5..e609a64 100644
--- a/chrome/browser/ui/views/media_router/cast_dialog_sink_button.cc
+++ b/chrome/browser/ui/views/media_router/cast_dialog_sink_button.cc
@@ -8,6 +8,7 @@
 
 #include "base/debug/stack_trace.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/branding_buildflags.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
 #include "chrome/browser/ui/views/chrome_typography.h"
@@ -27,7 +28,7 @@
 #include "ui/views/layout/layout_provider.h"
 #include "ui/views/vector_icons.h"
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #include "chrome/browser/ui/media_router/internal/vector_icons/vector_icons.h"
 #endif
 
@@ -52,14 +53,14 @@
       break;
 // Use proprietary icons only in Chrome builds. The default TV icon is used
 // instead for these sink types in Chromium builds.
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
     case SinkIconType::MEETING:
       vector_icon = &vector_icons::kMeetIcon;
       break;
     case SinkIconType::HANGOUT:
       vector_icon = &vector_icons::kHangoutIcon;
       break;
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
     case SinkIconType::CAST:
     case SinkIconType::GENERIC:
     default:
diff --git a/chrome/browser/ui/views/policy/enterprise_startup_dialog_view.cc b/chrome/browser/ui/views/policy/enterprise_startup_dialog_view.cc
index 8b64e8d..fbee04e 100644
--- a/chrome/browser/ui/views/policy/enterprise_startup_dialog_view.cc
+++ b/chrome/browser/ui/views/policy/enterprise_startup_dialog_view.cc
@@ -10,6 +10,7 @@
 #include "base/i18n/message_formatter.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
@@ -44,7 +45,7 @@
 constexpr int kLineHeight = 22;    // The height of text line.
 constexpr int kFontSizeDelta = 3;  // The font size of text.
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 constexpr int kLogoHeight = 20;  // The height of Chrome enterprise logo.
 #endif
 
@@ -173,7 +174,7 @@
 }
 
 std::unique_ptr<views::View> EnterpriseStartupDialogView::CreateExtraView() {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // Show Google Chrome Enterprise logo only for official build.
   auto logo_image = std::make_unique<views::ImageView>();
   logo_image->SetImage(ui::ResourceBundle::GetSharedInstance()
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc b/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
index 47f213e..3a0249c3 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
+++ b/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
@@ -14,6 +14,7 @@
 #include "base/test/metrics/user_action_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/threading/thread_restrictions.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -523,7 +524,7 @@
 // below the threshold.
 // TODO(https://crbug.com/862573): Re-enable when no longer failing when
 // is_chrome_branded is true.
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #define MAYBE_IncrementDiceSigninPromoShowCounter \
   DISABLED_IncrementDiceSigninPromoShowCounter
 #else
@@ -543,7 +544,7 @@
 // ensures that the profile chooser is shown correctly above this threshold.
 // TODO(https://crbug.com/862573): Re-enable when no longer failing when
 // is_chrome_branded is true.
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #define MAYBE_DiceSigninPromoWithoutIllustration \
   DISABLED_DiceSigninPromoWithoutIllustration
 #else
diff --git a/chrome/browser/ui/views/session_crashed_bubble_view.cc b/chrome/browser/ui/views/session_crashed_bubble_view.cc
index 472b7561..9a669962 100644
--- a/chrome/browser/ui/views/session_crashed_bubble_view.cc
+++ b/chrome/browser/ui/views/session_crashed_bubble_view.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/views/session_crashed_bubble_view.h"
 
 #include <stddef.h>
+
 #include <string>
 #include <utility>
 #include <vector>
@@ -14,6 +15,7 @@
 #include "base/macros.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/task_runner_util.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/metrics/metrics_reporting_state.h"
 #include "chrome/browser/prefs/session_startup_pref.h"
@@ -68,7 +70,7 @@
 }
 
 bool DoesSupportConsentCheck() {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   return true;
 #else
   return false;
diff --git a/chrome/browser/ui/views/tabs/tab_strip_browsertest.cc b/chrome/browser/ui/views/tabs/tab_strip_browsertest.cc
new file mode 100644
index 0000000..e0d82e6
--- /dev/null
+++ b/chrome/browser/ui/views/tabs/tab_strip_browsertest.cc
@@ -0,0 +1,55 @@
+// 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/ui/views/tabs/tab_strip.h"
+
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_tabstrip.h"
+#include "chrome/browser/ui/tabs/tab_group_id.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "url/gurl.h"
+
+// Integration tests for interactions between TabStripModel and TabStrip.
+class TabStripBrowsertest : public InProcessBrowserTest {
+ public:
+  TabStripModel* tab_strip_model() { return browser()->tab_strip_model(); }
+
+  TabStrip* tab_strip() {
+    return BrowserView::GetBrowserViewForBrowser(browser())->tabstrip();
+  }
+
+  void AppendTab() { chrome::AddTabAt(browser(), GURL(), -1, true); }
+
+  TabGroupId AddTabToNewGroup(int tab_index) {
+    tab_strip_model()->AddToNewGroup({tab_index});
+    return tab_strip_model()->GetTabGroupForTab(tab_index).value();
+  }
+};
+
+// Regression test for crbug.com/983961.
+IN_PROC_BROWSER_TEST_F(TabStripBrowsertest, MoveTabAndDeleteGroup) {
+  AppendTab();
+  AppendTab();
+
+  TabGroupId group = AddTabToNewGroup(0);
+  AddTabToNewGroup(2);
+
+  Tab* tab0 = tab_strip()->tab_at(0);
+  Tab* tab1 = tab_strip()->tab_at(1);
+  Tab* tab2 = tab_strip()->tab_at(2);
+
+  tab_strip_model()->AddToExistingGroup({2}, group);
+
+  EXPECT_EQ(tab0, tab_strip()->tab_at(0));
+  EXPECT_EQ(tab2, tab_strip()->tab_at(1));
+  EXPECT_EQ(tab1, tab_strip()->tab_at(2));
+
+  EXPECT_EQ(group, tab_strip_model()->GetTabGroupForTab(1));
+
+  std::vector<TabGroupId> groups = tab_strip_model()->ListTabGroups();
+  EXPECT_EQ(groups.size(), 1U);
+  EXPECT_EQ(groups[0], group);
+}
diff --git a/chrome/browser/ui/views/tabs/tab_unittest.cc b/chrome/browser/ui/views/tabs/tab_unittest.cc
index 64a2214..ec758a0 100644
--- a/chrome/browser/ui/views/tabs/tab_unittest.cc
+++ b/chrome/browser/ui/views/tabs/tab_unittest.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/ui/tabs/tab_group_id.h"
 #include "chrome/browser/ui/tabs/tab_group_visual_data.h"
 #include "chrome/browser/ui/tabs/tab_utils.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/tabs/alert_indicator.h"
 #include "chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h"
 #include "chrome/browser/ui/views/tabs/tab_close_button.h"
@@ -487,6 +488,10 @@
 // Regression test for http://crbug.com/420313: Confirms that any child Views of
 // Tab do not attempt to provide their own tooltip behavior/text.
 TEST_F(TabTest, TooltipProvidedByTab) {
+  // This test isn't relevant when tab hover cards are enabled since tab
+  // tooltips are then disabled.
+  if (base::FeatureList::IsEnabled(features::kTabHoverCards))
+    return;
   Widget widget;
   InitWidget(&widget);
 
@@ -501,9 +506,9 @@
   data.favicon = gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
 
   data.title = base::UTF8ToUTF16(
-      "This is a really long tab title that would case views::Label to provide "
-      "its own tooltip; but Tab should disable that feature so it can provide "
-      "the tooltip instead.");
+      "This is a really long tab title that would cause views::Label to "
+      "provide its own tooltip; but Tab should disable that feature so it can "
+      "provide the tooltip instead.");
 
   // Test both with and without an indicator showing since the tab tooltip text
   // should include a description of the alert state when the indicator is
diff --git a/chrome/browser/ui/webui/chromeos/account_manager_welcome_ui.cc b/chrome/browser/ui/webui/chromeos/account_manager_welcome_ui.cc
index 67d228a..50129289 100644
--- a/chrome/browser/ui/webui/chromeos/account_manager_welcome_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/account_manager_welcome_ui.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/strings/utf_string_conversions.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"
@@ -44,7 +45,7 @@
                                IDR_ACCOUNT_MANAGER_SHARED_CSS);
   html_source->AddResourcePath("account_manager_welcome.js",
                                IDR_ACCOUNT_MANAGER_WELCOME_JS);
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   html_source->AddResourcePath("account_manager_welcome_1x.png",
                                IDR_ACCOUNT_MANAGER_WELCOME_1X_PNG);
   html_source->AddResourcePath("account_manager_welcome_2x.png",
diff --git a/chrome/browser/ui/webui/chromeos/account_migration_welcome_ui.cc b/chrome/browser/ui/webui/chromeos/account_migration_welcome_ui.cc
index 78f33804..0c2d281 100644
--- a/chrome/browser/ui/webui/chromeos/account_migration_welcome_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/account_migration_welcome_ui.cc
@@ -10,6 +10,7 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/branding_buildflags.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.h"
 #include "chrome/common/url_constants.h"
@@ -99,7 +100,7 @@
                                IDR_ACCOUNT_MIGRATION_BROWSER_PROXY_HTML);
   html_source->AddResourcePath("account_migration_browser_proxy.js",
                                IDR_ACCOUNT_MIGRATION_BROWSER_PROXY_JS);
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   html_source->AddResourcePath("account_manager_welcome_1x.png",
                                IDR_ACCOUNT_MANAGER_WELCOME_1X_PNG);
   html_source->AddResourcePath("account_manager_welcome_2x.png",
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
index b780e5a..4057c00 100644
--- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
@@ -20,6 +20,7 @@
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
+#include "build/branding_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen_view.h"
@@ -135,7 +136,7 @@
 constexpr char kRecommendAppListViewJSPath[] = "recommend_app_list_view.js";
 constexpr char kStringsJSPath[] = "strings.js";
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 constexpr char kLogo24PX1XSvgPath[] = "logo_24px-1x.svg";
 constexpr char kLogo24PX2XSvgPath[] = "logo_24px-2x.svg";
 constexpr char kSyncConsentIcons[] = "sync-consent-icons.html";
@@ -147,7 +148,7 @@
   source->AddResourcePath(kArcAssistantLogoPath, IDR_ASSISTANT_LOGO_PNG);
   source->AddResourcePath(kArcSupervisionIconPath, IDR_SUPERVISION_ICON_PNG);
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   source->AddResourcePath(kLogo24PX1XSvgPath, IDR_PRODUCT_LOGO_24PX_1X);
   source->AddResourcePath(kLogo24PX2XSvgPath, IDR_PRODUCT_LOGO_24PX_2X);
 #endif
@@ -157,7 +158,7 @@
 }
 
 void AddSyncConsentResources(content::WebUIDataSource* source) {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   source->AddResourcePath(kSyncConsentIcons,
                           IDR_PRODUCT_CHROMEOS_SYNC_CONSENT_SCREEN_ICONS);
   // No #else section here as Sync Settings screen is Chrome-specific.
@@ -552,7 +553,7 @@
   const std::string& app_locale = g_browser_process->GetApplicationLocale();
   webui::SetLoadTimeDataDefaults(app_locale, localized_strings);
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   localized_strings->SetString("buildType", "chrome");
 #else
   localized_strings->SetString("buildType", "chromium");
diff --git a/chrome/browser/ui/webui/settings/about_handler.cc b/chrome/browser/ui/webui/settings/about_handler.cc
index 7fb463a..d4961df 100644
--- a/chrome/browser/ui/webui/settings/about_handler.cc
+++ b/chrome/browser/ui/webui/settings/about_handler.cc
@@ -25,6 +25,7 @@
 #include "base/task/post_task.h"
 #include "base/time/time.h"
 #include "base/values.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_content_browser_client.h"
@@ -325,7 +326,7 @@
   html_source->AddString("aboutObsoleteSystemURL",
                          ObsoleteSystem::GetLinkURL());
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   base::string16 tos = l10n_util::GetStringFUTF16(
       IDS_ABOUT_TERMS_OF_SERVICE, base::UTF8ToUTF16(chrome::kChromeUITermsURL));
   html_source->AddString("aboutProductTos", tos);
@@ -334,7 +335,7 @@
 #if defined(OS_CHROMEOS)
   std::string safetyInfoLink = GetSafetyInfoLink();
   html_source->AddBoolean("shouldShowSafetyInfo", !safetyInfoLink.empty());
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   html_source->AddString(
       "aboutProductSafety",
       l10n_util::GetStringUTF16(IDS_ABOUT_SAFETY_INFORMATION));
diff --git a/chrome/browser/ui/webui/settings/chrome_cleanup_handler_win.cc b/chrome/browser/ui/webui/settings/chrome_cleanup_handler_win.cc
index d7a9cd51..37f8b05 100644
--- a/chrome/browser/ui/webui/settings/chrome_cleanup_handler_win.cc
+++ b/chrome/browser/ui/webui/settings/chrome_cleanup_handler_win.cc
@@ -18,6 +18,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/lock.h"
 #include "base/values.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -119,7 +120,7 @@
     Profile* profile,
     const std::set<base::string16>& extension_ids,
     std::set<base::string16>* extension_names) {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   extensions::ExtensionRegistry* extension_registry =
       extensions::ExtensionRegistry::Get(profile);
   for (const base::string16& extension_id : extension_ids) {
@@ -303,16 +304,16 @@
 
 void ChromeCleanupHandler::HandleGetMoreItemsPluralString(
     const base::ListValue* args) {
-#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
+#if defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
   GetPluralString(IDS_SETTINGS_RESET_CLEANUP_DETAILS_MORE, args);
-#endif  // defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
+#endif  // defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
 }
 
 void ChromeCleanupHandler::HandleGetItemsToRemovePluralString(
     const base::ListValue* args) {
-#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
+#if defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
   GetPluralString(IDS_SETTINGS_RESET_CLEANUP_DETAILS_ITEMS_TO_BE_REMOVED, args);
-#endif  // defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
+#endif  // defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
 }
 
 void ChromeCleanupHandler::GetPluralString(int id,
diff --git a/chrome/browser/ui/webui/settings/chrome_cleanup_handler_win_unittest.cc b/chrome/browser/ui/webui/settings/chrome_cleanup_handler_win_unittest.cc
index a9fb0bb..d54baa6a 100644
--- a/chrome/browser/ui/webui/settings/chrome_cleanup_handler_win_unittest.cc
+++ b/chrome/browser/ui/webui/settings/chrome_cleanup_handler_win_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/webui/settings/chrome_cleanup_handler_win.h"
 
+#include "build/branding_buildflags.h"
 #include "chrome/browser/safe_browsing/chrome_cleaner/mock_chrome_cleaner_process_win.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/testing_browser_process.h"
@@ -35,7 +36,7 @@
   };
 
   std::set<base::string16> expected_names = {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
     // Extension names are only available in Google-branded builds.
     MockChromeCleanerProcess::kInstalledExtensionName1,
     MockChromeCleanerProcess::kInstalledExtensionName2,
diff --git a/chrome/browser/ui/webui/settings/metrics_reporting_handler_unittest.cc b/chrome/browser/ui/webui/settings/metrics_reporting_handler_unittest.cc
index d5adb28..b26e2be 100644
--- a/chrome/browser/ui/webui/settings/metrics_reporting_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/metrics_reporting_handler_unittest.cc
@@ -2,7 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#if defined(GOOGLE_CHROME_BUILD) && !defined(OS_CHROMEOS)
+#include "build/branding_buildflags.h"
+
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && !defined(OS_CHROMEOS)
 
 #include "chrome/browser/ui/webui/settings/metrics_reporting_handler.h"
 
@@ -124,4 +126,4 @@
 
 }  // namespace settings
 
-#endif  // defined(GOOGLE_CHROME_BUILD) && !defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING) && !defined(OS_CHROMEOS)
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
index 184059f..2443519 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -13,6 +13,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/win/windows_version.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "build/buildflag.h"
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
@@ -103,12 +104,12 @@
 #include "chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.h"
 #include "device/fido/win/webauthn_api.h"
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #include "base/metrics/field_trial_params.h"
 #include "base/strings/strcat.h"
 #include "chrome/grit/chrome_unscaled_resources.h"
 #include "ui/base/resource/resource_bundle.h"
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #endif  // defined(OS_WIN)
 
 #if defined(USE_NSS_CERTS)
@@ -414,7 +415,7 @@
   static constexpr LocalizedString kLocalizedStrings[] = {
     {"aboutProductLogoAlt", IDS_SHORT_PRODUCT_LOGO_ALT_TEXT},
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
     {"aboutReportAnIssue", IDS_SETTINGS_ABOUT_PAGE_REPORT_AN_ISSUE},
 #endif
 
@@ -1108,7 +1109,7 @@
                           base::size(kLocalizedStrings));
 }
 
-#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
+#if defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
 void AddChromeCleanupStrings(content::WebUIDataSource* html_source) {
   const wchar_t kUnwantedSoftwareProtectionWhitePaperUrl[] =
       L"https://www.google.ca/chrome/browser/privacy/"
@@ -1237,11 +1238,11 @@
   html_source->AddString("incompatibleApplicationsSubpageLearnHow",
                          learn_how_text);
 }
-#endif  // defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
+#endif  // defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
 void AddResetStrings(content::WebUIDataSource* html_source) {
   static constexpr LocalizedString kLocalizedStrings[] = {
-#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
+#if defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
     {"resetPageTitle", IDS_SETTINGS_RESET_AND_CLEANUP},
 #else
     {"resetPageTitle", IDS_SETTINGS_RESET},
@@ -1264,7 +1265,7 @@
     {"resetAutomatedDialogTitle", IDS_SETTINGS_RESET_AUTOMATED_DIALOG_TITLE},
     {"resetProfileBannerButton", IDS_SETTINGS_RESET_BANNER_RESET_BUTTON_TEXT},
     {"resetProfileBannerDescription", IDS_SETTINGS_RESET_BANNER_TEXT},
-#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
+#if defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
     {"resetCleanupComputerTrigger",
      IDS_SETTINGS_RESET_CLEAN_UP_COMPUTER_TRIGGER},
 #endif
@@ -3276,10 +3277,10 @@
   AddAutofillStrings(html_source, profile);
   AddAppearanceStrings(html_source, profile);
 
-#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
+#if defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
   AddChromeCleanupStrings(html_source);
   AddIncompatibleApplicationsStrings(html_source);
-#endif  // defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
+#endif  // defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
   AddChangePasswordStrings(html_source);
   AddClearBrowsingDataStrings(html_source, profile);
diff --git a/chrome/browser/ui/webui/welcome/google_apps_handler.cc b/chrome/browser/ui/webui/welcome/google_apps_handler.cc
index 1a8f2ed..4cedf809 100644
--- a/chrome/browser/ui/webui/welcome/google_apps_handler.cc
+++ b/chrome/browser/ui/webui/welcome/google_apps_handler.cc
@@ -8,6 +8,7 @@
 #include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/stl_util.h"
+#include "build/branding_buildflags.h"
 #include "chrome/browser/favicon/favicon_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/welcome/bookmark_item.h"
@@ -45,7 +46,7 @@
 constexpr const int kGoogleAppIconSize = 48;  // Pixels.
 
 GoogleAppsHandler::GoogleAppsHandler() {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // Do not translate icon name as it is not human visible and needs to
   // match CSS.
 
@@ -86,7 +87,7 @@
       {static_cast<int>(GoogleApps::kTranslate),
        l10n_util::GetStringUTF8(IDS_WELCOME_GOOGLE_APPS_TRANSLATE), "translate",
        "https://translate.google.com", IDS_WELCOME_TRANSLATE});
-#endif  // defined(GOOGLE_CHROME_BUILD)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 }
 
 GoogleAppsHandler::~GoogleAppsHandler() {}
diff --git a/chrome/browser/web_applications/components/web_app_data_retriever.h b/chrome/browser/web_applications/components/web_app_data_retriever.h
index d972055d..188715f 100644
--- a/chrome/browser/web_applications/components/web_app_data_retriever.h
+++ b/chrome/browser/web_applications/components/web_app_data_retriever.h
@@ -33,8 +33,8 @@
 
 class WebAppIconDownloader;
 
-// Class used by BookmarkAppInstallationTask to retrieve the necessary
-// information to install an app. Should only be called from the UI thread.
+// Class used by WebAppInstallTask to retrieve the necessary information to
+// install an app. Should only be called from the UI thread.
 class WebAppDataRetriever : content::WebContentsObserver {
  public:
   // Returns nullptr for WebApplicationInfo if error.
diff --git a/chrome/browser/web_applications/proto/web_app.proto b/chrome/browser/web_applications/proto/web_app.proto
index eaacc420..53c5b4a2 100644
--- a/chrome/browser/web_applications/proto/web_app.proto
+++ b/chrome/browser/web_applications/proto/web_app.proto
@@ -16,6 +16,12 @@
   required int32 size_in_px = 2;
 }
 
+// TODO(loyso): Move this enum to components/sync/protocol/sync_enums.proto.
+enum LaunchContainerProto {
+  TAB = 1;
+  WINDOW = 2;
+}
+
 // WebApp class data.
 // This should be a superset for WebAppSpecifics in
 // components/sync/protocol/web_app_specifics.proto
@@ -24,11 +30,12 @@
   required string app_id = 1;
   required string launch_url = 2;
   required string name = 3;
-  optional uint32 theme_color = 4;
+  required LaunchContainerProto launch_container = 4;
+  optional uint32 theme_color = 5;
 
   // Local data members, not to be synced:
-  optional string description = 5;
-  optional string scope = 6;
+  optional string description = 6;
+  optional string scope = 7;
   // List of icon infos.
-  repeated WebAppIconInfoProto icons = 7;
+  repeated WebAppIconInfoProto icons = 8;
 }
diff --git a/chrome/browser/web_applications/web_app.cc b/chrome/browser/web_applications/web_app.cc
index 69f83bbc..f97432a0 100644
--- a/chrome/browser/web_applications/web_app.cc
+++ b/chrome/browser/web_applications/web_app.cc
@@ -5,6 +5,7 @@
 #include <ios>
 #include <ostream>
 
+#include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/web_app.h"
 
 #include "base/logging.h"
@@ -12,7 +13,8 @@
 
 namespace web_app {
 
-WebApp::WebApp(const AppId& app_id) : app_id_(app_id) {}
+WebApp::WebApp(const AppId& app_id)
+    : app_id_(app_id), launch_container_(LaunchContainer::kDefault) {}
 
 WebApp::~WebApp() = default;
 
@@ -38,6 +40,11 @@
   theme_color_ = theme_color;
 }
 
+void WebApp::SetLaunchContainer(LaunchContainer launch_container) {
+  DCHECK_NE(LaunchContainer::kDefault, launch_container);
+  launch_container_ = launch_container;
+}
+
 void WebApp::SetIcons(Icons icons) {
   icons_ = std::move(icons);
 }
diff --git a/chrome/browser/web_applications/web_app.h b/chrome/browser/web_applications/web_app.h
index 005fe8c..c12c0182 100644
--- a/chrome/browser/web_applications/web_app.h
+++ b/chrome/browser/web_applications/web_app.h
@@ -17,6 +17,8 @@
 
 namespace web_app {
 
+enum class LaunchContainer;
+
 class WebApp {
  public:
   explicit WebApp(const AppId& app_id);
@@ -29,6 +31,7 @@
   const GURL& launch_url() const { return launch_url_; }
   const GURL& scope() const { return scope_; }
   const base::Optional<SkColor>& theme_color() const { return theme_color_; }
+  const LaunchContainer& launch_container() const { return launch_container_; }
 
   struct IconInfo {
     GURL url;
@@ -42,6 +45,7 @@
   void SetLaunchUrl(const GURL& launch_url);
   void SetScope(const GURL& scope);
   void SetThemeColor(base::Optional<SkColor> theme_color);
+  void SetLaunchContainer(LaunchContainer launch_container);
   void SetIcons(Icons icons);
 
  private:
@@ -54,6 +58,7 @@
   // is within the scope.
   GURL scope_;
   base::Optional<SkColor> theme_color_;
+  LaunchContainer launch_container_;
   Icons icons_;
 
   DISALLOW_COPY_AND_ASSIGN(WebApp);
diff --git a/chrome/browser/web_applications/web_app_database.cc b/chrome/browser/web_applications/web_app_database.cc
index 69fcc470..8d0cd13a 100644
--- a/chrome/browser/web_applications/web_app_database.cc
+++ b/chrome/browser/web_applications/web_app_database.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/proto/web_app.pb.h"
 #include "chrome/browser/web_applications/web_app.h"
 #include "chrome/browser/web_applications/web_app_database_factory.h"
@@ -72,6 +73,12 @@
 
   proto->set_name(web_app.name());
 
+  DCHECK_NE(LaunchContainer::kDefault, web_app.launch_container());
+  proto->set_launch_container(web_app.launch_container() ==
+                                      LaunchContainer::kWindow
+                                  ? LaunchContainerProto::WINDOW
+                                  : LaunchContainerProto::TAB);
+
   // Optional fields:
   proto->set_description(web_app.description());
   if (!web_app.scope().is_empty())
@@ -107,6 +114,15 @@
   }
   web_app->SetName(proto.name());
 
+  if (!proto.has_launch_container()) {
+    DLOG(ERROR) << "WebApp proto parse error: no launch_container field";
+    return nullptr;
+  }
+  web_app->SetLaunchContainer(proto.launch_container() ==
+                                      LaunchContainerProto::WINDOW
+                                  ? LaunchContainer::kWindow
+                                  : LaunchContainer::kTab);
+
   // Optional fields:
   if (proto.has_description())
     web_app->SetDescription(proto.description());
diff --git a/chrome/browser/web_applications/web_app_database_unittest.cc b/chrome/browser/web_applications/web_app_database_unittest.cc
index f40bb786..6d6386e 100644
--- a/chrome/browser/web_applications/web_app_database_unittest.cc
+++ b/chrome/browser/web_applications/web_app_database_unittest.cc
@@ -32,10 +32,11 @@
 bool operator==(const WebApp& web_app, const WebApp& web_app2) {
   return std::tie(web_app.app_id(), web_app.name(), web_app.launch_url(),
                   web_app.description(), web_app.scope(), web_app.theme_color(),
-                  web_app.icons()) ==
+                  web_app.icons(), web_app.launch_container()) ==
          std::tie(web_app2.app_id(), web_app2.name(), web_app2.launch_url(),
                   web_app2.description(), web_app2.scope(),
-                  web_app2.theme_color(), web_app2.icons());
+                  web_app2.theme_color(), web_app2.icons(),
+                  web_app2.launch_container());
 }
 
 bool operator!=(const WebApp& web_app, const WebApp& web_app2) {
@@ -94,6 +95,8 @@
     app->SetLaunchUrl(GURL(launch_url));
     app->SetScope(GURL(scope));
     app->SetThemeColor(theme_color);
+    app->SetLaunchContainer((suffix & 1) ? LaunchContainer::kTab
+                                         : LaunchContainer::kWindow);
 
     const std::string icon_url =
         base_url + "/icon" + base::NumberToString(suffix);
@@ -207,11 +210,13 @@
   const auto launch_url = GURL("https://example.com/");
   const AppId app_id = GenerateAppIdFromURL(GURL(launch_url));
   const std::string name = "Name";
+  const auto launch_container = LaunchContainer::kTab;
 
   auto app = std::make_unique<WebApp>(app_id);
   // Required fields:
   app->SetLaunchUrl(launch_url);
   app->SetName(name);
+  app->SetLaunchContainer(launch_container);
   // Let optional fields be empty:
   EXPECT_TRUE(app->description().empty());
   EXPECT_TRUE(app->scope().is_empty());
@@ -228,6 +233,7 @@
   EXPECT_EQ(app_id, app_copy->app_id());
   EXPECT_EQ(launch_url, app_copy->launch_url());
   EXPECT_EQ(name, app_copy->name());
+  EXPECT_EQ(launch_container, app_copy->launch_container());
   // No optional fields.
   EXPECT_TRUE(app_copy->description().empty());
   EXPECT_TRUE(app_copy->scope().is_empty());
diff --git a/chrome/browser/web_applications/web_app_install_finalizer.cc b/chrome/browser/web_applications/web_app_install_finalizer.cc
index f088d32..dcbb116 100644
--- a/chrome/browser/web_applications/web_app_install_finalizer.cc
+++ b/chrome/browser/web_applications/web_app_install_finalizer.cc
@@ -71,6 +71,10 @@
   web_app->SetLaunchUrl(web_app_info.app_url);
   web_app->SetScope(web_app_info.scope);
   web_app->SetThemeColor(web_app_info.theme_color);
+  web_app->SetLaunchContainer(web_app_info.open_as_window
+                                  ? LaunchContainer::kWindow
+                                  : LaunchContainer::kTab);
+
   SetIcons(web_app_info, web_app.get());
 
   icon_manager_->WriteData(
diff --git a/chrome/browser/web_applications/web_app_install_task_unittest.cc b/chrome/browser/web_applications/web_app_install_task_unittest.cc
index ae53e60..2ea1a553e 100644
--- a/chrome/browser/web_applications/web_app_install_task_unittest.cc
+++ b/chrome/browser/web_applications/web_app_install_task_unittest.cc
@@ -169,7 +169,8 @@
                              const std::string name,
                              const std::string description,
                              const GURL& scope,
-                             base::Optional<SkColor> theme_color) {
+                             base::Optional<SkColor> theme_color,
+                             bool open_as_window) {
     auto web_app_info = std::make_unique<WebApplicationInfo>();
 
     web_app_info->app_url = url;
@@ -177,7 +178,7 @@
     web_app_info->description = base::UTF8ToUTF16(description);
     web_app_info->scope = scope;
     web_app_info->theme_color = theme_color;
-    web_app_info->open_as_window = true;
+    web_app_info->open_as_window = open_as_window;
 
     data_retriever_->SetRendererWebApplicationInfo(std::move(web_app_info));
   }
@@ -185,7 +186,8 @@
   void CreateRendererAppInfo(const GURL& url,
                              const std::string name,
                              const std::string description) {
-    CreateRendererAppInfo(url, name, description, GURL(), base::nullopt);
+    CreateRendererAppInfo(url, name, description, GURL(), base::nullopt,
+                          /*open_as_window*/ true);
   }
 
   static base::NullableString16 ToNullableUTF16(const std::string& str) {
@@ -323,7 +325,8 @@
   const AppId app_id = GenerateAppIdFromURL(url);
 
   CreateDefaultDataToRetrieve(url, scope);
-  CreateRendererAppInfo(url, name, description, /*scope*/ GURL{}, theme_color);
+  CreateRendererAppInfo(url, name, description, /*scope*/ GURL{}, theme_color,
+                        /*open_as_window*/ true);
 
   base::RunLoop run_loop;
   bool callback_called = false;
@@ -442,9 +445,9 @@
 
 TEST_F(WebAppInstallTaskTest, InstallableCheck) {
   const std::string renderer_description = "RendererDescription";
-  CreateRendererAppInfo(GURL("https://renderer.com/path"), "RendererName",
-                        renderer_description,
-                        GURL("https://renderer.com/scope"), 0x00);
+  CreateRendererAppInfo(
+      GURL("https://renderer.com/path"), "RendererName", renderer_description,
+      GURL("https://renderer.com/scope"), 0x00, /*open_as_window*/ true);
 
   const GURL manifest_start_url = GURL("https://example.com/start");
   const AppId app_id = GenerateAppIdFromURL(manifest_start_url);
@@ -1026,7 +1029,8 @@
   const GURL scope("https://example.com/scope");
   const base::Optional<SkColor> theme_color = 0xAABBCCDD;
 
-  CreateRendererAppInfo(url, name, description, /*scope*/ GURL{}, theme_color);
+  CreateRendererAppInfo(url, name, description, /*scope*/ GURL{}, theme_color,
+                        /*open_as_window*/ true);
   {
     auto manifest = std::make_unique<blink::Manifest>();
     manifest->start_url = url;
@@ -1086,40 +1090,36 @@
 }
 
 TEST_F(WebAppInstallTaskTest, InstallWebAppWithParams_LaunchContainer) {
-  SetInstallFinalizerForTesting();
   {
     CreateDataToRetrieve(GURL("https://example.com/"),
                          /*open_as_window*/ false);
 
     InstallManager::InstallParams params;
     params.launch_container = LaunchContainer::kDefault;
-    InstallWebAppWithParams(params);
+    auto app_id = InstallWebAppWithParams(params);
 
-    std::unique_ptr<WebApplicationInfo> web_app_info =
-        test_install_finalizer().web_app_info();
-    EXPECT_FALSE(web_app_info->open_as_window);
+    EXPECT_EQ(LaunchContainer::kTab,
+              registrar_->GetAppById(app_id)->launch_container());
   }
   {
     CreateDataToRetrieve(GURL("https://example.org/"), /*open_as_window*/ true);
 
     InstallManager::InstallParams params;
     params.launch_container = LaunchContainer::kDefault;
-    InstallWebAppWithParams(params);
+    auto app_id = InstallWebAppWithParams(params);
 
-    std::unique_ptr<WebApplicationInfo> web_app_info =
-        test_install_finalizer().web_app_info();
-    EXPECT_TRUE(web_app_info->open_as_window);
+    EXPECT_EQ(LaunchContainer::kWindow,
+              registrar_->GetAppById(app_id)->launch_container());
   }
   {
     CreateDataToRetrieve(GURL("https://example.au/"), /*open_as_window*/ true);
 
     InstallManager::InstallParams params;
     params.launch_container = LaunchContainer::kTab;
-    InstallWebAppWithParams(params);
+    auto app_id = InstallWebAppWithParams(params);
 
-    std::unique_ptr<WebApplicationInfo> web_app_info =
-        test_install_finalizer().web_app_info();
-    EXPECT_FALSE(web_app_info->open_as_window);
+    EXPECT_EQ(LaunchContainer::kTab,
+              registrar_->GetAppById(app_id)->launch_container());
   }
   {
     CreateDataToRetrieve(GURL("https://example.app/"),
@@ -1127,11 +1127,10 @@
 
     InstallManager::InstallParams params;
     params.launch_container = LaunchContainer::kWindow;
-    InstallWebAppWithParams(params);
+    auto app_id = InstallWebAppWithParams(params);
 
-    std::unique_ptr<WebApplicationInfo> web_app_info =
-        test_install_finalizer().web_app_info();
-    EXPECT_TRUE(web_app_info->open_as_window);
+    EXPECT_EQ(LaunchContainer::kWindow,
+              registrar_->GetAppById(app_id)->launch_container());
   }
 }
 
diff --git a/chrome/browser/web_applications/web_app_registrar.cc b/chrome/browser/web_applications/web_app_registrar.cc
index 1e48be7..5204da5 100644
--- a/chrome/browser/web_applications/web_app_registrar.cc
+++ b/chrome/browser/web_applications/web_app_registrar.cc
@@ -11,6 +11,7 @@
 #include "base/callback.h"
 #include "base/logging.h"
 #include "chrome/browser/web_applications/abstract_web_app_database.h"
+#include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/web_app.h"
 
 namespace web_app {
@@ -144,8 +145,8 @@
 
 LaunchContainer WebAppRegistrar::GetAppLaunchContainer(
     const AppId& app_id) const {
-  // TODO(loyso): Implement it.
-  return LaunchContainer::kTab;
+  WebApp* web_app = GetAppById(app_id);
+  return web_app ? web_app->launch_container() : LaunchContainer::kDefault;
 }
 
 base::flat_set<AppId> WebAppRegistrar::GetAppIdsForTesting() const {
diff --git a/chrome/browser/web_applications/web_app_registrar_unittest.cc b/chrome/browser/web_applications/web_app_registrar_unittest.cc
index 13ef2a0e..499bde67 100644
--- a/chrome/browser/web_applications/web_app_registrar_unittest.cc
+++ b/chrome/browser/web_applications/web_app_registrar_unittest.cc
@@ -188,7 +188,7 @@
   EXPECT_TRUE(registrar->is_empty());
 }
 
-TEST(WebAppRegistrar, GetAppDetails) {
+TEST(WebAppRegistrar, GetAppDataFields) {
   auto database = std::make_unique<TestWebAppDatabase>();
   auto registrar = std::make_unique<WebAppRegistrar>(nullptr, database.get());
 
@@ -197,21 +197,32 @@
   const std::string name = "Name";
   const std::string description = "Description";
   const base::Optional<SkColor> theme_color = 0xAABBCCDD;
+  const auto launch_container = LaunchContainer::kWindow;
 
   EXPECT_EQ(std::string(), registrar->GetAppShortName(app_id));
   EXPECT_EQ(GURL(), registrar->GetAppLaunchURL(app_id));
 
   auto web_app = std::make_unique<WebApp>(app_id);
+  WebApp* web_app_ptr = web_app.get();
+
   web_app->SetName(name);
   web_app->SetDescription(description);
   web_app->SetThemeColor(theme_color);
   web_app->SetLaunchUrl(launch_url);
+  web_app->SetLaunchContainer(launch_container);
+
   registrar->RegisterApp(std::move(web_app));
 
   EXPECT_EQ(name, registrar->GetAppShortName(app_id));
   EXPECT_EQ(description, registrar->GetAppDescription(app_id));
   EXPECT_EQ(theme_color, registrar->GetAppThemeColor(app_id));
   EXPECT_EQ(launch_url, registrar->GetAppLaunchURL(app_id));
+  EXPECT_EQ(launch_container, registrar->GetAppLaunchContainer(app_id));
+
+  EXPECT_EQ(LaunchContainer::kDefault,
+            registrar->GetAppLaunchContainer("unknown"));
+  web_app_ptr->SetLaunchContainer(LaunchContainer::kTab);
+  EXPECT_EQ(LaunchContainer::kTab, registrar->GetAppLaunchContainer(app_id));
 }
 
 }  // namespace web_app
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 0ca0ae3..18c3913 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -7,7 +7,6 @@
 #include <vector>
 
 #include "base/command_line.h"
-#include "base/metrics/field_trial_params.h"
 #include "base/no_destructor.h"
 #include "base/strings/string_split.h"
 #include "build/build_config.h"
@@ -259,6 +258,22 @@
     "DisallowUnsafeHttpDownloads", base::FEATURE_DISABLED_BY_DEFAULT};
 const char kDisallowUnsafeHttpDownloadsParamName[] = "MimeTypeList";
 
+// Enable DNS over HTTPS (DoH).
+const base::Feature kDnsOverHttps{"DnsOverHttps",
+                                  base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Set whether fallback to insecure DNS is allowed by default. This setting may
+// be overridden for individual transactions.
+const base::FeatureParam<bool> kDnsOverHttpsFallbackParam{&kDnsOverHttps,
+                                                          "Fallback", true};
+
+// Supply one or more space-separated DoH server URI templates to use when this
+// feature is enabled. If no templates are specified, then a hardcoded mapping
+// will be used to construct a list of DoH templates associated with the IP
+// addresses of insecure resolvers in the discovered configuration.
+const base::FeatureParam<std::string> kDnsOverHttpsTemplatesParam{
+    &kDnsOverHttps, "Templates", ""};
+
 #if defined(OS_ANDROID)
 // Enable changing default downloads storage location on Android.
 const base::Feature kDownloadsLocationChange{"DownloadsLocationChange",
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 658e230..0a45fb2 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -10,6 +10,7 @@
 
 #include "base/component_export.h"
 #include "base/feature_list.h"
+#include "base/metrics/field_trial_params.h"
 #include "build/build_config.h"
 #include "build/buildflag.h"
 #include "chrome/common/buildflags.h"
@@ -153,6 +154,13 @@
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const char kDisallowUnsafeHttpDownloadsParamName[];
 
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kDnsOverHttps;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::FeatureParam<bool> kDnsOverHttpsFallbackParam;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::FeatureParam<std::string> kDnsOverHttpsTemplatesParam;
+
 #if defined(OS_ANDROID)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kDownloadsLocationChange;
diff --git a/chrome/common/extensions/api/autotest_private.idl b/chrome/common/extensions/api/autotest_private.idl
index 18990c0d..64339e6 100644
--- a/chrome/common/extensions/api/autotest_private.idl
+++ b/chrome/common/extensions/api/autotest_private.idl
@@ -207,6 +207,19 @@
   };
   callback GetArcPackageCallback = void (ArcPackageDict package);
 
+  dictionary Bounds {
+    double left;
+    double top;
+    double width;
+    double height;
+  };
+
+  dictionary ArcAppWindowInfo {
+    Bounds bounds;
+    boolean isAnimating;
+  };
+  callback GetArcAppWindowInfoCallback = void (ArcAppWindowInfo info);
+
   callback LaunchArcAppCallback = void (boolean appLaunched);
 
   callback TakeScreenshotCallback = void (DOMString base64Png);
@@ -476,5 +489,11 @@
     // |packageName|: the package name of the ARC app window.
     // |callback| is invoked with the window state.
     static void getArcAppWindowState(DOMString packageName, WindowStateCallback callback);
+
+    // Get various information on an ARC window.
+    // |packageName|: the package name of the ARC app window.
+    // |callback|: called when the operation has completed.
+    static void getArcAppWindowInfo(DOMString packageName,
+                                    GetArcAppWindowInfoCallback callback);
   };
 };
diff --git a/chrome/common/extensions/extension_constants.cc b/chrome/common/extensions/extension_constants.cc
index 0f1a64f..53d88ca2 100644
--- a/chrome/common/extensions/extension_constants.cc
+++ b/chrome/common/extensions/extension_constants.cc
@@ -84,7 +84,6 @@
     kZipArchiverExtensionId,
     kChromeCameraAppId,
     kChromeCameraAppDevId,
-    kKioskNextHomeAppId,
 #endif        // defined(OS_CHROMEOS)
     nullptr,  // Null-terminated array.
 };
@@ -119,7 +118,6 @@
 const char kChromeCameraAppId[] = "hfhhnacclhffhdffklopdkcgdhifgngh";
 const char kChromeCameraAppDevId[] = "flgnmkgjffmkephdokeeliiopbjaafpm";
 const char kChromeCameraAppPath[] = "chromeos/camera";
-const char kKioskNextHomeAppId[] = "nbaolgedfgoedkjbfmpediclncanmpbc";
 
 #endif  // defined(CHROME_OS)
 
diff --git a/chrome/common/extensions/extension_constants.h b/chrome/common/extensions/extension_constants.h
index bfbb9d2..75717b3 100644
--- a/chrome/common/extensions/extension_constants.h
+++ b/chrome/common/extensions/extension_constants.h
@@ -243,8 +243,6 @@
 extern const char kChromeCameraAppDevId[];
 // Path to preinstalled Chrome camera app.
 extern const char kChromeCameraAppPath[];
-// The app ID of the Kiosk Next Home app.
-extern const char kKioskNextHomeAppId[];
 #endif
 
 // What causes an extension to be installed? Used in histograms, so don't
diff --git a/chrome/common/media_router/BUILD.gn b/chrome/common/media_router/BUILD.gn
index 7a70515..2f253237 100644
--- a/chrome/common/media_router/BUILD.gn
+++ b/chrome/common/media_router/BUILD.gn
@@ -27,8 +27,6 @@
     "media_sink.h",
     "media_source.cc",
     "media_source.h",
-    "media_status.cc",
-    "media_status.h",
     "route_request_result.cc",
     "route_request_result.h",
   ]
diff --git a/chrome/common/media_router/media_status.cc b/chrome/common/media_router/media_status.cc
deleted file mode 100644
index 2b20f826..0000000
--- a/chrome/common/media_router/media_status.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/common/media_router/media_status.h"
-
-namespace media_router {
-
-MirroringMediaStatusExtraData::MirroringMediaStatusExtraData(
-    bool media_remoting_enabled)
-    : media_remoting_enabled(media_remoting_enabled) {}
-MirroringMediaStatusExtraData::~MirroringMediaStatusExtraData() = default;
-
-MediaStatus::MediaStatus() = default;
-
-MediaStatus::MediaStatus(const MediaStatus& other) = default;
-
-MediaStatus::~MediaStatus() = default;
-
-MediaStatus& MediaStatus::operator=(const MediaStatus& other) = default;
-
-bool MediaStatus::operator==(const MediaStatus& other) const {
-  return title == other.title &&
-         can_play_pause == other.can_play_pause && can_mute == other.can_mute &&
-         can_set_volume == other.can_set_volume && can_seek == other.can_seek &&
-         play_state == other.play_state && is_muted == other.is_muted &&
-         volume == other.volume && duration == other.duration &&
-         current_time == other.current_time;
-}
-
-}  // namespace media_router
diff --git a/chrome/common/media_router/media_status.h b/chrome/common/media_router/media_status.h
deleted file mode 100644
index 53e2516..0000000
--- a/chrome/common/media_router/media_status.h
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_COMMON_MEDIA_ROUTER_MEDIA_STATUS_H_
-#define CHROME_COMMON_MEDIA_ROUTER_MEDIA_STATUS_H_
-
-#include <string>
-
-#include "base/optional.h"
-#include "base/time/time.h"
-
-namespace media_router {
-
-struct MirroringMediaStatusExtraData {
-  explicit MirroringMediaStatusExtraData(bool media_remoting_enabled);
-  ~MirroringMediaStatusExtraData();
-
-  // Whether media remoting is enabled for mirroring session associated with the
-  // MediaRoute.
-  bool media_remoting_enabled;
-};
-
-// Represents the current state of a media content.
-struct MediaStatus {
- public:
-  enum class PlayState { PLAYING, PAUSED, BUFFERING };
-
-  MediaStatus();
-  MediaStatus(const MediaStatus& other);
-  ~MediaStatus();
-
-  MediaStatus& operator=(const MediaStatus& other);
-  bool operator==(const MediaStatus& other) const;
-
-  // The main title of the media. For example, in a MediaStatus representing
-  // a YouTube Cast session, this could be the title of the video.
-  std::string title;
-
-  // If this is true, the media can be played and paused.
-  bool can_play_pause = false;
-
-  // If this is true, the media can be muted and unmuted.
-  bool can_mute = false;
-
-  // If this is true, the media's volume can be changed.
-  bool can_set_volume = false;
-
-  // If this is true, the media's current playback position can be changed.
-  bool can_seek = false;
-
-  PlayState play_state = PlayState::PLAYING;
-
-  bool is_muted = false;
-
-  // Current volume of the media, with 1 being the highest and 0 being the
-  // lowest/no sound. When |is_muted| is true, there should be no sound
-  // regardless of |volume|.
-  float volume = 0;
-
-  // The length of the media. A value of zero indicates that this is a media
-  // with no set duration (e.g. a live stream).
-  base::TimeDelta duration;
-
-  // Current playback position. Must be less than or equal to |duration|.
-  base::TimeDelta current_time;
-
-  // Only set for mirroring routes.
-  base::Optional<MirroringMediaStatusExtraData> mirroring_extra_data;
-};
-
-}  // namespace media_router
-
-#endif  // CHROME_COMMON_MEDIA_ROUTER_MEDIA_STATUS_H_
diff --git a/chrome/common/media_router/mojom/media_router.mojom b/chrome/common/media_router/mojom/media_router.mojom
index 8a772b64..c2ea00f 100644
--- a/chrome/common/media_router/mojom/media_router.mojom
+++ b/chrome/common/media_router/mojom/media_router.mojom
@@ -87,6 +87,7 @@
   int32 cast_channel_id;
 };
 
+// TODO(crbug.com/993437): Replace the use of this enum with a boolean field.
 enum RouteControllerType {
   kNone,
   kGeneric,
diff --git a/chrome/common/media_router/mojom/media_status.typemap b/chrome/common/media_router/mojom/media_status.typemap
deleted file mode 100644
index c718e72..0000000
--- a/chrome/common/media_router/mojom/media_status.typemap
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-mojom = "//chrome/common/media_router/mojom/media_status.mojom"
-public_headers = [ "//chrome/common/media_router/media_status.h" ]
-traits_headers =
-    [ "//chrome/common/media_router/mojom/media_status_mojom_traits.h" ]
-sources = [
-  "//chrome/common/media_router/mojom/media_status_mojom_traits.cc",
-]
-type_mappings = [ "media_router.mojom.MediaStatus=media_router::MediaStatus" ]
diff --git a/chrome/common/media_router/mojom/media_status_mojom_traits.cc b/chrome/common/media_router/mojom/media_status_mojom_traits.cc
deleted file mode 100644
index 29ba90b..0000000
--- a/chrome/common/media_router/mojom/media_status_mojom_traits.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/common/media_router/mojom/media_status_mojom_traits.h"
-
-#include "base/strings/string_util.h"
-#include "mojo/public/cpp/base/time_mojom_traits.h"
-
-namespace mojo {
-
-// static
-bool StructTraits<media_router::mojom::MediaStatusDataView,
-                  media_router::MediaStatus>::
-    Read(media_router::mojom::MediaStatusDataView data,
-         media_router::MediaStatus* out) {
-  if (!data.ReadTitle(&out->title) || !base::IsStringUTF8(out->title))
-    return false;
-
-  out->can_play_pause = data.can_play_pause();
-  out->can_mute = data.can_mute();
-  out->can_set_volume = data.can_set_volume();
-  out->can_seek = data.can_seek();
-
-  if (!data.ReadPlayState(&out->play_state))
-    return false;
-
-  out->is_muted = data.is_muted();
-  out->volume = data.volume();
-
-  if (!data.ReadDuration(&out->duration))
-    return false;
-
-  if (!data.ReadCurrentTime(&out->current_time))
-    return false;
-
-  return true;
-}
-
-}  // namespace mojo
diff --git a/chrome/common/media_router/mojom/media_status_mojom_traits.h b/chrome/common/media_router/mojom/media_status_mojom_traits.h
deleted file mode 100644
index e755f44..0000000
--- a/chrome/common/media_router/mojom/media_status_mojom_traits.h
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_COMMON_MEDIA_ROUTER_MOJOM_MEDIA_STATUS_MOJOM_TRAITS_H_
-#define CHROME_COMMON_MEDIA_ROUTER_MOJOM_MEDIA_STATUS_MOJOM_TRAITS_H_
-
-#include <string>
-
-#include "chrome/common/media_router/media_status.h"
-#include "chrome/common/media_router/mojom/media_status.mojom.h"
-
-namespace mojo {
-
-template <>
-struct EnumTraits<media_router::mojom::MediaStatus::PlayState,
-                  media_router::MediaStatus::PlayState> {
-  static media_router::mojom::MediaStatus::PlayState ToMojom(
-      media_router::MediaStatus::PlayState play_state) {
-    switch (play_state) {
-      case media_router::MediaStatus::PlayState::PLAYING:
-        return media_router::mojom::MediaStatus::PlayState::PLAYING;
-      case media_router::MediaStatus::PlayState::PAUSED:
-        return media_router::mojom::MediaStatus::PlayState::PAUSED;
-      case media_router::MediaStatus::PlayState::BUFFERING:
-        return media_router::mojom::MediaStatus::PlayState::BUFFERING;
-    }
-    NOTREACHED() << "Unknown play state " << static_cast<int>(play_state);
-    return media_router::mojom::MediaStatus::PlayState::PLAYING;
-  }
-
-  static bool FromMojom(media_router::mojom::MediaStatus::PlayState input,
-                        media_router::MediaStatus::PlayState* output) {
-    switch (input) {
-      case media_router::mojom::MediaStatus::PlayState::PLAYING:
-        *output = media_router::MediaStatus::PlayState::PLAYING;
-        return true;
-      case media_router::mojom::MediaStatus::PlayState::PAUSED:
-        *output = media_router::MediaStatus::PlayState::PAUSED;
-        return true;
-      case media_router::mojom::MediaStatus::PlayState::BUFFERING:
-        *output = media_router::MediaStatus::PlayState::BUFFERING;
-        return true;
-    }
-    NOTREACHED() << "Unknown play state " << static_cast<int>(input);
-    return false;
-  }
-};
-
-template <>
-struct StructTraits<media_router::mojom::MediaStatusDataView,
-                    media_router::MediaStatus> {
-  static bool Read(media_router::mojom::MediaStatusDataView data,
-                   media_router::MediaStatus* out);
-
-  static const std::string& title(const media_router::MediaStatus& status) {
-    return status.title;
-  }
-
-  static bool can_play_pause(const media_router::MediaStatus& status) {
-    return status.can_play_pause;
-  }
-
-  static bool can_mute(const media_router::MediaStatus& status) {
-    return status.can_mute;
-  }
-
-  static bool can_set_volume(const media_router::MediaStatus& status) {
-    return status.can_set_volume;
-  }
-
-  static bool can_seek(const media_router::MediaStatus& status) {
-    return status.can_seek;
-  }
-
-  static media_router::MediaStatus::PlayState play_state(
-      const media_router::MediaStatus& status) {
-    return status.play_state;
-  }
-
-  static bool is_muted(const media_router::MediaStatus& status) {
-    return status.is_muted;
-  }
-
-  static float volume(const media_router::MediaStatus& status) {
-    return status.volume;
-  }
-
-  static base::TimeDelta duration(const media_router::MediaStatus& status) {
-    return status.duration;
-  }
-
-  static base::TimeDelta current_time(const media_router::MediaStatus& status) {
-    return status.current_time;
-  }
-};
-
-}  // namespace mojo
-
-#endif  // CHROME_COMMON_MEDIA_ROUTER_MOJOM_MEDIA_STATUS_MOJOM_TRAITS_H_
diff --git a/chrome/common/media_router/mojom/typemaps.gni b/chrome/common/media_router/mojom/typemaps.gni
index a151a2a..6d3dab2 100644
--- a/chrome/common/media_router/mojom/typemaps.gni
+++ b/chrome/common/media_router/mojom/typemaps.gni
@@ -2,7 +2,4 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-typemaps = [
-  "//chrome/common/media_router/mojom/media_router.typemap",
-  "//chrome/common/media_router/mojom/media_status.typemap",
-]
+typemaps = [ "//chrome/common/media_router/mojom/media_router.typemap" ]
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index a79cd7d..78f23467 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -1830,11 +1830,14 @@
 // Boolean that specifies whether the built-in asynchronous DNS client is used.
 const char kBuiltInDnsClientEnabled[] = "async_dns.enabled";
 
-// String containing list of DNS over HTTPS servers to be used.
-const char kDnsOverHttpsServers[] = "dns_over_https.servers";
-// String contianing list of methods (GET or POST) to use with DNS over HTTPS
-// servers, in the same order of the above pref.
-const char kDnsOverHttpsServerMethods[] = "dns_over_https.methods";
+// String specifying the secure DNS mode to use. Any string other than
+// "secure" or "automatic" will be mapped to the default "off" mode.
+const char kDnsOverHttpsMode[] = "dns_over_https.mode";
+// String containing a space-separated list of DNS over HTTPS templates to use
+// in secure mode or automatic mode. If no templates are specified in automatic
+// mode, we will attempt discovery of DoH servers associated with the configured
+// insecure resolvers.
+const char kDnsOverHttpsTemplates[] = "dns_over_https.templates";
 
 // A pref holding the value of the policy used to explicitly allow or deny
 // access to audio capture devices.  When enabled or not set, the user is
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 9eb061f..b2df798 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -725,8 +725,8 @@
 extern const char kH2ClientCertCoalescingHosts[];
 
 extern const char kBuiltInDnsClientEnabled[];
-extern const char kDnsOverHttpsServers[];
-extern const char kDnsOverHttpsServerMethods[];
+extern const char kDnsOverHttpsMode[];
+extern const char kDnsOverHttpsTemplates[];
 
 extern const char kRegisteredProtocolHandlers[];
 extern const char kIgnoredProtocolHandlers[];
diff --git a/chrome/services/app_service/public/mojom/types.mojom b/chrome/services/app_service/public/mojom/types.mojom
index 97e0192..e292ea6 100644
--- a/chrome/services/app_service/public/mojom/types.mojom
+++ b/chrome/services/app_service/public/mojom/types.mojom
@@ -155,7 +155,6 @@
   kFromAppListQuery,             // Query-dependent results (larger icons).
   kFromAppListQueryContextMenu,  // Query-dependent results; context menu.
   kFromAppListRecommendation,    // Query-less recommendations (smaller icons).
-  kFromKioskNextHome,            // Kiosk Next Home app.
   kFromParentalControls,         // Parental Controls Settings Section.
 };
 
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 4030cb5fe..a5d3e07 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -45,10 +45,6 @@
   include_js_tests = !(is_asan || is_msan || is_tsan)
 }
 
-if (is_chromeos) {
-  import("//chrome/browser/chromeos/kiosk_next_home/kiosk_next.gni")
-}
-
 # This target exists to reference other test executables to bring these files
 # into the build.
 group("test") {
@@ -1094,6 +1090,7 @@
       "../browser/ui/passwords/google_password_manager_navigation_throttle_browsertest.cc",
       "../browser/ui/tabs/pinned_tab_service_browsertest.cc",
       "../browser/ui/views/tabs/tab_hover_card_bubble_view_browsertest.cc",
+      "../browser/ui/views/tabs/tab_strip_browsertest.cc",
       "../browser/wake_lock/wake_lock_browsertest.cc",
 
       # If this list is used on Android in the future, these browser / speech/*
@@ -2939,6 +2936,7 @@
     "../browser/net/chrome_network_delegate_unittest.cc",
     "../browser/net/dns_probe_runner_unittest.cc",
     "../browser/net/dns_probe_service_factory_unittest.cc",
+    "../browser/net/dns_util_unittest.cc",
     "../browser/net/file_downloader_unittest.cc",
     "../browser/net/net_error_tab_helper_unittest.cc",
     "../browser/net/probe_message_unittest.cc",
@@ -4009,6 +4007,7 @@
       "../browser/google/google_brand_code_map_chromeos_unittest.cc",
       "../browser/media/webrtc/desktop_media_list_ash_unittest.cc",
       "../browser/metrics/perf/metric_collector_unittest.cc",
+      "../browser/metrics/perf/metric_provider_unittest.cc",
       "../browser/metrics/perf/perf_events_collector_unittest.cc",
       "../browser/metrics/perf/process_type_collector_unittest.cc",
       "../browser/metrics/perf/profile_provider_chromeos_unittest.cc",
diff --git a/chrome/test/base/ui_test_utils.cc b/chrome/test/base/ui_test_utils.cc
index 78fcb8fe1..6e8effa 100644
--- a/chrome/test/base/ui_test_utils.cc
+++ b/chrome/test/base/ui_test_utils.cc
@@ -288,16 +288,14 @@
   for (auto* browser : *BrowserList::GetInstance())
     initial_browsers.insert(browser);
 
-  content::WindowedNotificationObserver tab_added_observer(
-      chrome::NOTIFICATION_TAB_ADDED,
-      content::NotificationService::AllSources());
+  AllBrowserTabAddedWaiter tab_added_waiter;
 
   browser->OpenURL(OpenURLParams(
       url, Referrer(), disposition, ui::PAGE_TRANSITION_TYPED, false));
   if (browser_test_flags & BROWSER_TEST_WAIT_FOR_BROWSER)
     browser = WaitForBrowserNotInSet(initial_browsers);
   if (browser_test_flags & BROWSER_TEST_WAIT_FOR_TAB)
-    tab_added_observer.Wait();
+    tab_added_waiter.Wait();
   if (!(browser_test_flags & BROWSER_TEST_WAIT_FOR_NAVIGATION)) {
     // Some other flag caused the wait prior to this.
     return nullptr;
@@ -654,6 +652,9 @@
     TabStripModel* tab_strip_model,
     const TabStripModelChange& change,
     const TabStripSelectionChange& selection) {
+  if (web_contents_)
+    return;
+
   if (change.type() != TabStripModelChange::kInserted)
     return;
 
diff --git a/chrome/test/chromedriver/session_commands.cc b/chrome/test/chromedriver/session_commands.cc
index ca9302be..c92171c 100644
--- a/chrome/test/chromedriver/session_commands.cc
+++ b/chrome/test/chromedriver/session_commands.cc
@@ -384,8 +384,14 @@
       !platform_name_value->is_none()) {
     if (platform_name_value->is_string()) {
       std::string requested_platform_name = platform_name_value->GetString();
+      std::string requested_first_token =
+        requested_platform_name.substr(0, requested_platform_name.find(' '));
+
       std::string actual_platform_name =
-          base::ToLowerASCII(base::SysInfo::OperatingSystemName());
+        base::ToLowerASCII(base::SysInfo::OperatingSystemName());
+      std::string actual_first_token =
+        actual_platform_name.substr(0, actual_platform_name.find(' '));
+
       bool is_android = capabilities->FindPath(
                             "goog:chromeOptions.androidPackage") != nullptr;
       bool is_remote = capabilities->FindPath(
@@ -398,11 +404,10 @@
         // If any of the above cases pass, we return true.
       } else if (is_android && requested_platform_name != "android") {
         return false;
-      } else if (requested_platform_name == "mac" ||
-                 requested_platform_name == "windows" ||
-                 requested_platform_name == "linux") {
-        if (!base::StartsWith(actual_platform_name, requested_platform_name,
-                              base::CompareCase::SENSITIVE))
+      } else if (requested_first_token == "mac" ||
+                 requested_first_token == "windows" ||
+                 requested_first_token == "linux") {
+        if (actual_first_token != requested_first_token)
           return false;
       } else if (requested_platform_name != actual_platform_name) {
         return false;
diff --git a/chrome/updater/win/test/BUILD.gn b/chrome/updater/win/test/BUILD.gn
index d1d2c72d..e290745a 100644
--- a/chrome/updater/win/test/BUILD.gn
+++ b/chrome/updater/win/test/BUILD.gn
@@ -22,6 +22,11 @@
     "test_initializer.cc",
     "test_initializer.h",
   ]
+
+  deps = [
+    "//base",
+    "//chrome/updater:common",
+  ]
 }
 
 source_set("test_executables") {
diff --git a/chrome/utility/BUILD.gn b/chrome/utility/BUILD.gn
index a5582085..8259d87 100644
--- a/chrome/utility/BUILD.gn
+++ b/chrome/utility/BUILD.gn
@@ -32,7 +32,6 @@
     "//chrome:strings",
     "//chrome/common",
     "//chrome/common:mojo_bindings",
-    "//components/mirroring/mojom:constants",
     "//components/mirroring/service:mirroring_service",
     "//components/safe_browsing:buildflags",
     "//components/search_engines",
diff --git a/chrome/utility/chrome_content_utility_client.cc b/chrome/utility/chrome_content_utility_client.cc
index 144d083..c08ea48 100644
--- a/chrome/utility/chrome_content_utility_client.cc
+++ b/chrome/utility/chrome_content_utility_client.cc
@@ -17,9 +17,6 @@
 #include "base/time/time.h"
 #include "chrome/common/buildflags.h"
 #include "chrome/utility/services.h"
-#include "components/mirroring/mojom/constants.mojom.h"
-#include "components/mirroring/service/features.h"
-#include "components/mirroring/service/mirroring_service.h"
 #include "components/safe_browsing/buildflags.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
@@ -135,15 +132,6 @@
 ChromeContentUtilityClient::MaybeCreateMainThreadService(
     const std::string& service_name,
     service_manager::mojom::ServiceRequest request) {
-#if !defined(OS_ANDROID)
-  if (base::FeatureList::IsEnabled(mirroring::features::kMirroringService) &&
-      base::FeatureList::IsEnabled(features::kAudioServiceAudioStreams) &&
-      service_name == mirroring::mojom::kServiceName) {
-    return std::make_unique<mirroring::MirroringService>(
-        std::move(request), content::ChildThread::Get()->GetIOTaskRunner());
-  }
-#endif
-
 #if defined(OS_CHROMEOS)
 #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
   if (service_name == chromeos::assistant::mojom::kAudioDecoderServiceName) {
diff --git a/chrome/utility/services.cc b/chrome/utility/services.cc
index 356d7ed6..71a1b35a 100644
--- a/chrome/utility/services.cc
+++ b/chrome/utility/services.cc
@@ -15,6 +15,7 @@
 #include "components/services/patch/public/mojom/file_patcher.mojom.h"
 #include "components/services/unzip/public/mojom/unzipper.mojom.h"
 #include "components/services/unzip/unzipper_impl.h"
+#include "content/public/common/content_features.h"
 #include "content/public/utility/utility_thread.h"
 #include "device/vr/buildflags/buildflags.h"
 #include "extensions/buildflags/buildflags.h"
@@ -32,6 +33,8 @@
 #if !defined(OS_ANDROID)
 #include "chrome/common/importer/profile_import.mojom.h"
 #include "chrome/utility/importer/profile_import_impl.h"
+#include "components/mirroring/service/features.h"
+#include "components/mirroring/service/mirroring_service.h"
 #include "services/proxy_resolver/proxy_resolver_factory_impl.h"  // nogncheck
 #include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h"
 #endif  // !defined(OS_ANDROID)
@@ -110,6 +113,14 @@
     mojo::PendingReceiver<chrome::mojom::ProfileImport> receiver) {
   return std::make_unique<ProfileImportImpl>(std::move(receiver));
 }
+
+auto RunMirroringService(
+    mojo::PendingReceiver<mirroring::mojom::MirroringService> receiver) {
+  DCHECK(base::FeatureList::IsEnabled(mirroring::features::kMirroringService));
+  DCHECK(base::FeatureList::IsEnabled(features::kAudioServiceAudioStreams));
+  return std::make_unique<mirroring::MirroringService>(
+      std::move(receiver), content::UtilityThread::Get()->GetIOTaskRunner());
+}
 #endif  // !defined(OS_ANDROID)
 
 #if BUILDFLAG(ENABLE_PRINTING) && defined(OS_CHROMEOS)
@@ -195,6 +206,7 @@
 
 #if !defined(OS_ANDROID)
     RunProfileImporter,
+    RunMirroringService,
 #endif
 
 #if defined(OS_WIN)
diff --git a/chromecast/media/cma/backend/android/java/src/org/chromium/chromecast/cma/backend/android/AudioSinkAudioTrackImpl.java b/chromecast/media/cma/backend/android/java/src/org/chromium/chromecast/cma/backend/android/AudioSinkAudioTrackImpl.java
index a704a199..b4d01d8 100644
--- a/chromecast/media/cma/backend/android/java/src/org/chromium/chromecast/cma/backend/android/AudioSinkAudioTrackImpl.java
+++ b/chromecast/media/cma/backend/android/java/src/org/chromium/chromecast/cma/backend/android/AudioSinkAudioTrackImpl.java
@@ -135,7 +135,7 @@
     private static final long MAX_TIME_IGNORING_TSTAMPS_NSECS = SEC_IN_NSEC;
 
     // Additional padding for minimum buffer time, determined experimentally.
-    private static final long MIN_BUFFERED_TIME_PADDING_USEC = ANDROID_AUDIO_PERIOD_SIZE_USEC;
+    private static final long MIN_BUFFERED_TIME_PADDING_USEC = 120000;
 
     private static AudioManager sAudioManager;
 
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn
index 67439dd..8b62a934 100644
--- a/chromeos/BUILD.gn
+++ b/chromeos/BUILD.gn
@@ -237,12 +237,9 @@
   # Tast test sources live in the Chromium OS repository.
   # To diagnose tast failures or disable tests, see go/tast-failures
   tast_test("chrome_all_tast_tests") {
-    # To disable a specific test, add it the following list.
-    tast_disabled_tests = [
-      "security.SELinuxFilesARC",  # crbug.com/968155
-      "ui.MashLogin",
-      "ui.SingleProcessMashLogin",
-    ]
+    # To disable a specific test, add it the following list and cite a bug.
+    # crbug.com/968155
+    tast_disabled_tests = [ "security.SELinuxFilesARC" ]
   }
 
   group("cros_chrome_deploy") {
diff --git a/chromeos/constants/chromeos_features.cc b/chromeos/constants/chromeos_features.cc
index 5fe3b6c7..00a1cc9 100644
--- a/chromeos/constants/chromeos_features.cc
+++ b/chromeos/constants/chromeos_features.cc
@@ -164,7 +164,7 @@
 // Enables or disables showing the battery level in the System Tray and Settings
 // UI for supported Bluetooth Devices.
 const base::Feature kShowBluetoothDeviceBattery{
-    "ShowBluetoothDeviceBattery", base::FEATURE_DISABLED_BY_DEFAULT};
+    "ShowBluetoothDeviceBattery", base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Shows the Play Store icon in Demo Mode.
 const base::Feature kShowPlayInDemoMode{"ShowPlayInDemoMode",
diff --git a/components/download/internal/common/download_file_impl.cc b/components/download/internal/common/download_file_impl.cc
index 3091b11..ce58672 100644
--- a/components/download/internal/common/download_file_impl.cc
+++ b/components/download/internal/common/download_file_impl.cc
@@ -555,6 +555,8 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   is_paused_ = true;
   record_stream_bandwidth_ = false;
+  for (auto& stream : source_streams_)
+    stream.second->ClearDataReadyCallback();
 }
 
 void DownloadFileImpl::Resume() {
@@ -565,7 +567,7 @@
   for (auto& stream : source_streams_) {
     SourceStream* source_stream = stream.second.get();
     if (!source_stream->is_finished()) {
-      StreamActive(source_stream, MOJO_RESULT_OK);
+      ActivateStream(source_stream);
     }
   }
 }
@@ -722,15 +724,19 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   source_stream->Initialize();
-  source_stream->RegisterDataReadyCallback(
-      base::Bind(&DownloadFileImpl::StreamActive, weak_factory_.GetWeakPtr(),
-                 source_stream));
   // Truncate |source_stream|'s length if necessary.
   for (const auto& received_slice : received_slices_) {
     source_stream->TruncateLengthWithWrittenDataBlock(
         received_slice.offset, received_slice.received_bytes);
   }
   num_active_streams_++;
+  ActivateStream(source_stream);
+}
+
+void DownloadFileImpl::ActivateStream(SourceStream* source_stream) {
+  source_stream->RegisterDataReadyCallback(
+      base::Bind(&DownloadFileImpl::StreamActive, weak_factory_.GetWeakPtr(),
+                 source_stream));
   StreamActive(source_stream, MOJO_RESULT_OK);
 }
 
diff --git a/components/download/public/common/download_file_impl.h b/components/download/public/common/download_file_impl.h
index 4f6c60c..59ef5d5 100644
--- a/components/download/public/common/download_file_impl.h
+++ b/components/download/public/common/download_file_impl.h
@@ -277,6 +277,9 @@
   // Register callback and start to read data from the stream.
   void RegisterAndActivateStream(SourceStream* source_stream);
 
+  // Helper method to activate a stream and start reading from it.
+  void ActivateStream(SourceStream* source_stream);
+
   // Called when a stream completes.
   void OnStreamCompleted(SourceStream* source_stream);
 
diff --git a/components/gcm_driver/web_push_sender.cc b/components/gcm_driver/web_push_sender.cc
index 30b28608..aea3125 100644
--- a/components/gcm_driver/web_push_sender.cc
+++ b/components/gcm_driver/web_push_sender.cc
@@ -15,7 +15,6 @@
 #include "components/gcm_driver/crypto/json_web_token_util.h"
 #include "components/gcm_driver/crypto/p256_key_util.h"
 #include "components/gcm_driver/web_push_metrics.h"
-#include "net/base/load_flags.h"
 #include "net/http/http_request_headers.h"
 #include "net/http/http_status_code.h"
 #include "services/network/public/cpp/cors/cors.h"
@@ -102,8 +101,7 @@
   std::string server_url =
       base::StringPrintf(kFCMServerUrlFormat, fcm_token.c_str());
   resource_request->url = GURL(server_url);
-  resource_request->load_flags =
-      net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES;
+  resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
   resource_request->method = "POST";
   resource_request->headers.SetHeader(net::HttpRequestHeaders::kAuthorization,
                                       auth_header);
diff --git a/components/keyed_service/content/browser_context_keyed_service_factory.cc b/components/keyed_service/content/browser_context_keyed_service_factory.cc
index 19046586..5a91f1ddfd 100644
--- a/components/keyed_service/content/browser_context_keyed_service_factory.cc
+++ b/components/keyed_service/content/browser_context_keyed_service_factory.cc
@@ -60,9 +60,6 @@
 content::BrowserContext*
 BrowserContextKeyedServiceFactory::GetBrowserContextToUse(
     content::BrowserContext* context) const {
-  // TODO(crbug.com/701326): This DCHECK should be moved to GetContextToUse().
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
   // Safe default for Incognito mode: no service.
   if (context->IsOffTheRecord())
     return nullptr;
@@ -103,6 +100,7 @@
 }
 
 void* BrowserContextKeyedServiceFactory::GetContextToUse(void* context) const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   AssertContextWasntDestroyed(context);
   return GetBrowserContextToUse(static_cast<content::BrowserContext*>(context));
 }
diff --git a/components/keyed_service/content/refcounted_browser_context_keyed_service_factory.cc b/components/keyed_service/content/refcounted_browser_context_keyed_service_factory.cc
index 3158079..65f7ed1 100644
--- a/components/keyed_service/content/refcounted_browser_context_keyed_service_factory.cc
+++ b/components/keyed_service/content/refcounted_browser_context_keyed_service_factory.cc
@@ -61,9 +61,6 @@
 content::BrowserContext*
 RefcountedBrowserContextKeyedServiceFactory::GetBrowserContextToUse(
     content::BrowserContext* context) const {
-  // TODO(crbug.com/701326): This DCHECK should be moved to GetContextToUse().
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
   // Safe default for Incognito mode: no service.
   if (context->IsOffTheRecord())
     return nullptr;
@@ -105,6 +102,7 @@
 
 void* RefcountedBrowserContextKeyedServiceFactory::GetContextToUse(
     void* context) const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   AssertContextWasntDestroyed(context);
   return GetBrowserContextToUse(static_cast<content::BrowserContext*>(context));
 }
diff --git a/components/keyed_service/core/keyed_service_base_factory.cc b/components/keyed_service/core/keyed_service_base_factory.cc
index d27b2093..e09bd566 100644
--- a/components/keyed_service/core/keyed_service_base_factory.cc
+++ b/components/keyed_service/core/keyed_service_base_factory.cc
@@ -1,3 +1,4 @@
+
 // Copyright 2014 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
@@ -34,9 +35,7 @@
 }
 
 void KeyedServiceBaseFactory::AssertContextWasntDestroyed(void* context) const {
-  // TODO(crbug.com/701326): We should DCHECK(CalledOnValidThread()) here, but
-  // currently some code doesn't do service getting on the main thread.
-  // This needs to be fixed and DCHECK should be restored here.
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   dependency_manager_->AssertContextWasntDestroyed(context);
 }
 
diff --git a/components/keyed_service/ios/browser_state_keyed_service_factory.cc b/components/keyed_service/ios/browser_state_keyed_service_factory.cc
index 533a3a2..a4106db4 100644
--- a/components/keyed_service/ios/browser_state_keyed_service_factory.cc
+++ b/components/keyed_service/ios/browser_state_keyed_service_factory.cc
@@ -54,9 +54,6 @@
 
 web::BrowserState* BrowserStateKeyedServiceFactory::GetBrowserStateToUse(
     web::BrowserState* context) const {
-  // TODO(crbug.com/701326): This DCHECK should be moved to GetContextToUse().
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
   // Safe default for Incognito mode: no service.
   if (context->IsOffTheRecord())
     return nullptr;
@@ -92,6 +89,7 @@
 }
 
 void* BrowserStateKeyedServiceFactory::GetContextToUse(void* context) const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   AssertContextWasntDestroyed(context);
   return GetBrowserStateToUse(static_cast<web::BrowserState*>(context));
 }
diff --git a/components/keyed_service/ios/refcounted_browser_state_keyed_service_factory.cc b/components/keyed_service/ios/refcounted_browser_state_keyed_service_factory.cc
index bf18ad5f..1262f65 100644
--- a/components/keyed_service/ios/refcounted_browser_state_keyed_service_factory.cc
+++ b/components/keyed_service/ios/refcounted_browser_state_keyed_service_factory.cc
@@ -60,9 +60,6 @@
 web::BrowserState*
 RefcountedBrowserStateKeyedServiceFactory::GetBrowserStateToUse(
     web::BrowserState* context) const {
-  // TODO(crbug.com/701326): This DCHECK should be moved to GetContextToUse().
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
   // Safe default for Incognito mode: no service.
   if (context->IsOffTheRecord())
     return nullptr;
@@ -103,6 +100,7 @@
 
 void* RefcountedBrowserStateKeyedServiceFactory::GetContextToUse(
     void* context) const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   AssertContextWasntDestroyed(context);
   return GetBrowserStateToUse(static_cast<web::BrowserState*>(context));
 }
diff --git a/components/leveldb_proto/BUILD.gn b/components/leveldb_proto/BUILD.gn
index fb521c3..6dae43b 100644
--- a/components/leveldb_proto/BUILD.gn
+++ b/components/leveldb_proto/BUILD.gn
@@ -10,7 +10,7 @@
   ]
 }
 
-static_library("leveldb_proto") {
+component("leveldb_proto") {
   sources = [
     "internal/leveldb_database.cc",
     "internal/leveldb_database.h",
@@ -41,6 +41,7 @@
     "public/shared_proto_database_client_list.cc",
     "public/shared_proto_database_client_list.h",
   ]
+  defines = [ "IS_LEVELDB_PROTO_IMPL" ]
   deps = [
     ":proto",
   ]
@@ -76,6 +77,7 @@
     "internal/unique_proto_database_unittest.cc",
   ]
   deps = [
+    ":proto",
     ":test_support",
     "//testing/gmock",
     "//testing/gtest",
diff --git a/components/leveldb_proto/internal/leveldb_database.h b/components/leveldb_proto/internal/leveldb_database.h
index 049f255..4aff9b2 100644
--- a/components/leveldb_proto/internal/leveldb_database.h
+++ b/components/leveldb_proto/internal/leveldb_database.h
@@ -10,6 +10,7 @@
 #include <string>
 #include <vector>
 
+#include "base/component_export.h"
 #include "base/strings/string_split.h"
 #include "components/leveldb_proto/public/proto_database.h"
 #include "third_party/leveldatabase/env_chromium.h"
@@ -29,7 +30,7 @@
 // Interacts with the LevelDB third party module.
 // Once constructed, function calls and destruction should all occur on the
 // same thread (not necessarily the same as the constructor).
-class LevelDB {
+class COMPONENT_EXPORT(LEVELDB_PROTO) LevelDB {
  public:
   // Constructor. Does *not* open a leveldb - only initialize this class.
   // |client_name| is the name of the "client" that owns this instance. Used
diff --git a/components/leveldb_proto/internal/leveldb_proto_feature_list.h b/components/leveldb_proto/internal/leveldb_proto_feature_list.h
index f87217de..a471165 100644
--- a/components/leveldb_proto/internal/leveldb_proto_feature_list.h
+++ b/components/leveldb_proto/internal/leveldb_proto_feature_list.h
@@ -5,11 +5,13 @@
 #ifndef COMPONENTS_LEVELDB_PROTO_INTERNAL_LEVELDB_PROTO_FEATURE_LIST_H_
 #define COMPONENTS_LEVELDB_PROTO_INTERNAL_LEVELDB_PROTO_FEATURE_LIST_H_
 
+#include "base/component_export.h"
 #include "base/feature_list.h"
 
 namespace leveldb_proto {
 
-extern const base::Feature kProtoDBSharedMigration;
+extern const COMPONENT_EXPORT(LEVELDB_PROTO) base::Feature
+    kProtoDBSharedMigration;
 
 }  // namespace leveldb_proto
 
diff --git a/components/leveldb_proto/internal/proto_database_impl.h b/components/leveldb_proto/internal/proto_database_impl.h
index d80bd8c..2125bef8 100644
--- a/components/leveldb_proto/internal/proto_database_impl.h
+++ b/components/leveldb_proto/internal/proto_database_impl.h
@@ -41,21 +41,21 @@
 
 // Update transactions happen on background task runner and callback runs on the
 // client task runner.
-void RunUpdateCallback(
+void COMPONENT_EXPORT(LEVELDB_PROTO) RunUpdateCallback(
     scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
     Callbacks::UpdateCallback callback,
     bool success);
 
 // Load transactions happen on background task runner. The loaded keys need to
 // be given to clients on client task runner.
-void RunLoadKeysCallback(
+void COMPONENT_EXPORT(LEVELDB_PROTO) RunLoadKeysCallback(
     scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
     Callbacks::LoadKeysCallback callback,
     bool success,
     std::unique_ptr<KeyVector> keys);
 
 // Helper to run destroy callback on the client task runner.
-void RunDestroyCallback(
+void COMPONENT_EXPORT(LEVELDB_PROTO) RunDestroyCallback(
     scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
     Callbacks::DestroyCallback callback,
     bool success);
diff --git a/components/leveldb_proto/internal/proto_database_selector.h b/components/leveldb_proto/internal/proto_database_selector.h
index 48cab0c4..73ee4a4 100644
--- a/components/leveldb_proto/internal/proto_database_selector.h
+++ b/components/leveldb_proto/internal/proto_database_selector.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include <string>
 
+#include "base/component_export.h"
 #include "base/containers/queue.h"
 #include "base/files/file_path.h"
 #include "base/sequenced_task_runner.h"
@@ -25,7 +26,7 @@
 // A wrapper around unique and shared database client. Handles initialization of
 // underlying database as unique or shared as requested.
 // TODO: Discuss the init flow/migration path for unique/shared DB here.
-class ProtoDatabaseSelector
+class COMPONENT_EXPORT(LEVELDB_PROTO) ProtoDatabaseSelector
     : public base::RefCountedThreadSafe<ProtoDatabaseSelector> {
  public:
   ProtoDatabaseSelector(
diff --git a/components/leveldb_proto/internal/proto_leveldb_wrapper.h b/components/leveldb_proto/internal/proto_leveldb_wrapper.h
index 7f4dfc4e..0ed2d84 100644
--- a/components/leveldb_proto/internal/proto_leveldb_wrapper.h
+++ b/components/leveldb_proto/internal/proto_leveldb_wrapper.h
@@ -12,6 +12,7 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/component_export.h"
 #include "base/memory/ptr_util.h"
 #include "base/sequenced_task_runner.h"
 #include "base/strings/string_util.h"
@@ -38,7 +39,7 @@
 // When the ProtoDatabase instance is deleted, in-progress asynchronous
 // operations will be completed and the corresponding callbacks will be called.
 // Construction/calls/destruction should all happen on the same thread.
-class ProtoLevelDBWrapper {
+class COMPONENT_EXPORT(LEVELDB_PROTO) ProtoLevelDBWrapper {
  public:
   // Used to destroy database when initialization fails.
   static void Destroy(
diff --git a/components/leveldb_proto/internal/shared_proto_database.cc b/components/leveldb_proto/internal/shared_proto_database.cc
index dff092f..cd65ddfb 100644
--- a/components/leveldb_proto/internal/shared_proto_database.cc
+++ b/components/leveldb_proto/internal/shared_proto_database.cc
@@ -413,7 +413,8 @@
     Callbacks::UpdateCallback obsolete_cleared_callback = base::DoNothing();
     base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
-        base::BindOnce(&DestroyObsoleteSharedProtoDatabaseClients,
+        base::BindOnce(&SharedProtoDatabaseClient::
+                           DestroyObsoleteSharedProtoDatabaseClients,
                        std::move(db_wrapper),
                        std::move(obsolete_cleared_callback)),
         kDelayToClearObsoleteDatabase);
diff --git a/components/leveldb_proto/internal/shared_proto_database.h b/components/leveldb_proto/internal/shared_proto_database.h
index f2e1509..025af89 100644
--- a/components/leveldb_proto/internal/shared_proto_database.h
+++ b/components/leveldb_proto/internal/shared_proto_database.h
@@ -10,6 +10,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/component_export.h"
 #include "base/containers/queue.h"
 #include "base/memory/ref_counted.h"
 #include "base/sequence_checker.h"
@@ -22,7 +23,7 @@
 // Controls a single LevelDB database to be used by many clients, and provides
 // a way to get SharedProtoDatabaseClients that allow shared access to the
 // underlying single database.
-class SharedProtoDatabase
+class COMPONENT_EXPORT(LEVELDB_PROTO) SharedProtoDatabase
     : public base::RefCountedThreadSafe<SharedProtoDatabase> {
  public:
   using SharedClientInitCallback =
diff --git a/components/leveldb_proto/internal/shared_proto_database_client.cc b/components/leveldb_proto/internal/shared_proto_database_client.cc
index cee0dcc47..631194c 100644
--- a/components/leveldb_proto/internal/shared_proto_database_client.cc
+++ b/components/leveldb_proto/internal/shared_proto_database_client.cc
@@ -42,35 +42,43 @@
 
 }  // namespace
 
-std::string StripPrefix(const std::string& key, const std::string& prefix) {
+// static
+std::string SharedProtoDatabaseClient::StripPrefix(const std::string& key,
+                                                   const std::string& prefix) {
   return base::StartsWith(key, prefix, base::CompareCase::SENSITIVE)
              ? key.substr(prefix.length())
              : key;
 }
 
-std::unique_ptr<KeyVector> PrefixStrings(std::unique_ptr<KeyVector> strings,
-                                         const std::string& prefix) {
+// static
+std::unique_ptr<KeyVector> SharedProtoDatabaseClient::PrefixStrings(
+    std::unique_ptr<KeyVector> strings,
+    const std::string& prefix) {
   for (auto& str : *strings)
     str.assign(base::StrCat({prefix, str}));
   return strings;
 }
 
-bool KeyFilterStripPrefix(const KeyFilter& key_filter,
-                          const std::string& prefix,
-                          const std::string& key) {
+// static
+bool SharedProtoDatabaseClient::KeyFilterStripPrefix(
+    const KeyFilter& key_filter,
+    const std::string& prefix,
+    const std::string& key) {
   if (key_filter.is_null())
     return true;
   return key_filter.Run(StripPrefix(key, prefix));
 }
 
-void GetSharedDatabaseInitStatusAsync(
+// static
+void SharedProtoDatabaseClient::GetSharedDatabaseInitStatusAsync(
     const std::string& client_db_id,
     const scoped_refptr<SharedProtoDatabase>& shared_db,
     Callbacks::InitStatusCallback callback) {
   shared_db->GetDatabaseInitStatusAsync(client_db_id, std::move(callback));
 }
 
-void UpdateClientMetadataAsync(
+// static
+void SharedProtoDatabaseClient::UpdateClientMetadataAsync(
     const scoped_refptr<SharedProtoDatabase>& shared_db,
     const std::string& client_db_id,
     SharedDBMetadataProto::MigrationStatus migration_status,
@@ -79,7 +87,8 @@
                                        std::move(callback));
 }
 
-void DestroyObsoleteSharedProtoDatabaseClients(
+// static
+void SharedProtoDatabaseClient::DestroyObsoleteSharedProtoDatabaseClients(
     std::unique_ptr<ProtoLevelDBWrapper> db_wrapper,
     Callbacks::UpdateCallback callback) {
   ProtoLevelDBWrapper* db_wrapper_ptr = db_wrapper.get();
@@ -107,7 +116,9 @@
   }
 }
 
-void SetObsoleteClientListForTesting(const ProtoDbType* list) {
+// static
+void SharedProtoDatabaseClient::SetObsoleteClientListForTesting(
+    const ProtoDbType* list) {
   g_obsolete_client_list_for_testing = list;
 }
 
diff --git a/components/leveldb_proto/internal/shared_proto_database_client.h b/components/leveldb_proto/internal/shared_proto_database_client.h
index 2bbc1f7..e1c3960f 100644
--- a/components/leveldb_proto/internal/shared_proto_database_client.h
+++ b/components/leveldb_proto/internal/shared_proto_database_client.h
@@ -9,6 +9,7 @@
 #include <string>
 
 #include "base/bind.h"
+#include "base/component_export.h"
 #include "base/sequence_checker.h"
 #include "components/leveldb_proto/internal/leveldb_database.h"
 #include "components/leveldb_proto/internal/proto/shared_db_metadata.pb.h"
@@ -25,45 +26,48 @@
     base::OnceCallback<void(Enums::InitStatus,
                             SharedDBMetadataProto::MigrationStatus)>;
 
-std::string StripPrefix(const std::string& key, const std::string& prefix);
-
-std::unique_ptr<KeyVector> PrefixStrings(std::unique_ptr<KeyVector> strings,
-                                         const std::string& prefix);
-
-bool KeyFilterStripPrefix(const KeyFilter& key_filter,
-                          const std::string& prefix,
-                          const std::string& key);
-
-void GetSharedDatabaseInitStatusAsync(
-    const std::string& client_db_id,
-    const scoped_refptr<SharedProtoDatabase>& db,
-    Callbacks::InitStatusCallback callback);
-
-void UpdateClientMetadataAsync(
-    const scoped_refptr<SharedProtoDatabase>& db,
-    const std::string& client_db_id,
-    SharedDBMetadataProto::MigrationStatus migration_status,
-    ClientCorruptCallback callback);
-
-// Destroys all the data from obsolete clients, for the given |db_wrapper|
-// instance. |callback| is called once all the obsolete clients data are
-// removed, with failure status if one or more of the update fails.
-void DestroyObsoleteSharedProtoDatabaseClients(
-    std::unique_ptr<ProtoLevelDBWrapper> db_wrapper,
-    Callbacks::UpdateCallback callback);
-
-// Sets list of client names that are obsolete and will be cleared by next call
-// to DestroyObsoleteSharedProtoDatabaseClients(). |list| is list of dbs
-// with a |LAST| to mark the end of list.
-void SetObsoleteClientListForTesting(const ProtoDbType* list);
-
 // An implementation of ProtoDatabase<T> that uses a shared LevelDB and task
 // runner.
 // Should be created, destroyed, and used on the same sequenced task runner.
-class SharedProtoDatabaseClient : public UniqueProtoDatabase {
+class COMPONENT_EXPORT(LEVELDB_PROTO) SharedProtoDatabaseClient
+    : public UniqueProtoDatabase {
  public:
   static std::string PrefixForDatabase(ProtoDbType db_type);
 
+  static std::string StripPrefix(const std::string& key,
+                                 const std::string& prefix);
+
+  static std::unique_ptr<KeyVector> PrefixStrings(
+      std::unique_ptr<KeyVector> strings,
+      const std::string& prefix);
+
+  static bool KeyFilterStripPrefix(const KeyFilter& key_filter,
+                                   const std::string& prefix,
+                                   const std::string& key);
+
+  static void GetSharedDatabaseInitStatusAsync(
+      const std::string& client_db_id,
+      const scoped_refptr<SharedProtoDatabase>& db,
+      Callbacks::InitStatusCallback callback);
+
+  static void UpdateClientMetadataAsync(
+      const scoped_refptr<SharedProtoDatabase>& db,
+      const std::string& client_db_id,
+      SharedDBMetadataProto::MigrationStatus migration_status,
+      ClientCorruptCallback callback);
+
+  // Destroys all the data from obsolete clients, for the given |db_wrapper|
+  // instance. |callback| is called once all the obsolete clients data are
+  // removed, with failure status if one or more of the update fails.
+  static void DestroyObsoleteSharedProtoDatabaseClients(
+      std::unique_ptr<ProtoLevelDBWrapper> db_wrapper,
+      Callbacks::UpdateCallback callback);
+
+  // Sets list of client names that are obsolete and will be cleared by next
+  // call to DestroyObsoleteSharedProtoDatabaseClients(). |list| is list of dbs
+  // with a |LAST| to mark the end of list.
+  static void SetObsoleteClientListForTesting(const ProtoDbType* list);
+
   ~SharedProtoDatabaseClient() override;
 
   void Init(const std::string& client_uma_name,
diff --git a/components/leveldb_proto/internal/shared_proto_database_client_unittest.cc b/components/leveldb_proto/internal/shared_proto_database_client_unittest.cc
index e64ba45..d89e912 100644
--- a/components/leveldb_proto/internal/shared_proto_database_client_unittest.cc
+++ b/components/leveldb_proto/internal/shared_proto_database_client_unittest.cc
@@ -254,7 +254,7 @@
   // Sets the obsolete client list to given list, runs clean up tasks and waits
   // for them to complete.
   void DestroyObsoleteClientsAndWait(const ProtoDbType* client_list) {
-    SetObsoleteClientListForTesting(client_list);
+    SharedProtoDatabaseClient::SetObsoleteClientListForTesting(client_list);
     base::RunLoop wait_loop;
     Callbacks::UpdateCallback wait_callback = base::BindOnce(
         [](base::OnceClosure closure, bool success) {
@@ -263,12 +263,12 @@
         },
         wait_loop.QuitClosure());
 
-    DestroyObsoleteSharedProtoDatabaseClients(
+    SharedProtoDatabaseClient::DestroyObsoleteSharedProtoDatabaseClients(
         std::make_unique<ProtoLevelDBWrapper>(
             db_->database_task_runner_for_testing(), GetLevelDB()),
         std::move(wait_callback));
     wait_loop.Run();
-    SetObsoleteClientListForTesting(nullptr);
+    SharedProtoDatabaseClient::SetObsoleteClientListForTesting(nullptr);
   }
 
   void UpdateMetadataAsync(
@@ -282,8 +282,9 @@
         },
         wait_loop.QuitClosure());
     client->set_migration_status(migration_status);
-    UpdateClientMetadataAsync(client->parent_db_, client->prefix_,
-                              migration_status, std::move(wait_callback));
+    SharedProtoDatabaseClient::UpdateClientMetadataAsync(
+        client->parent_db_, client->prefix_, migration_status,
+        std::move(wait_callback));
     wait_loop.Run();
   }
 
diff --git a/components/leveldb_proto/internal/shared_proto_database_provider.h b/components/leveldb_proto/internal/shared_proto_database_provider.h
index 62b61884..a5e9eba 100644
--- a/components/leveldb_proto/internal/shared_proto_database_provider.h
+++ b/components/leveldb_proto/internal/shared_proto_database_provider.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_LEVELDB_PROTO_INTERNAL_SHARED_PROTO_DATABASE_PROVIDER_H_
 #define COMPONENTS_LEVELDB_PROTO_INTERNAL_SHARED_PROTO_DATABASE_PROVIDER_H_
 
+#include "base/component_export.h"
 #include "base/memory/weak_ptr.h"
 #include "base/sequenced_task_runner.h"
 
@@ -17,7 +18,7 @@
 // provider to be used in the wrapper. |client_task_runner| is the
 // SequencedTaskRunner provided by the main provider so its WeakPtrs are
 // always checked on the right sequence.
-class SharedProtoDatabaseProvider {
+class COMPONENT_EXPORT(LEVELDB_PROTO) SharedProtoDatabaseProvider {
  public:
   using GetSharedDBInstanceCallback =
       base::OnceCallback<void(scoped_refptr<SharedProtoDatabase>)>;
diff --git a/components/leveldb_proto/internal/unique_proto_database.h b/components/leveldb_proto/internal/unique_proto_database.h
index 8b113361..c093069 100644
--- a/components/leveldb_proto/internal/unique_proto_database.h
+++ b/components/leveldb_proto/internal/unique_proto_database.h
@@ -9,6 +9,7 @@
 #include <string>
 
 #include "base/bind.h"
+#include "base/component_export.h"
 #include "base/sequence_checker.h"
 #include "components/leveldb_proto/internal/proto_leveldb_wrapper.h"
 #include "components/leveldb_proto/public/proto_database.h"
@@ -17,7 +18,7 @@
 
 // An implementation of ProtoDatabase<std::string> that manages the lifecycle of
 // a unique LevelDB instance.
-class UniqueProtoDatabase {
+class COMPONENT_EXPORT(LEVELDB_PROTO) UniqueProtoDatabase {
  public:
   explicit UniqueProtoDatabase(
       const scoped_refptr<base::SequencedTaskRunner>& task_runner);
diff --git a/components/leveldb_proto/public/proto_database.h b/components/leveldb_proto/public/proto_database.h
index e2fcba1..65994524 100644
--- a/components/leveldb_proto/public/proto_database.h
+++ b/components/leveldb_proto/public/proto_database.h
@@ -8,6 +8,7 @@
 #include <map>
 #include <vector>
 
+#include "base/component_export.h"
 #include "base/files/file_path.h"
 #include "base/sequenced_task_runner.h"
 #include "base/threading/thread_checker.h"
@@ -216,7 +217,7 @@
 // Return a new instance of Options, but with two additions:
 // 1) create_if_missing = true
 // 2) max_open_files = 0
-leveldb_env::Options CreateSimpleOptions();
+leveldb_env::Options COMPONENT_EXPORT(LEVELDB_PROTO) CreateSimpleOptions();
 
 }  // namespace leveldb_proto
 
diff --git a/components/leveldb_proto/public/proto_database_provider.h b/components/leveldb_proto/public/proto_database_provider.h
index b7a3718..a33452cd5 100644
--- a/components/leveldb_proto/public/proto_database_provider.h
+++ b/components/leveldb_proto/public/proto_database_provider.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "base/component_export.h"
 #include "base/files/file_path.h"
 #include "base/sequenced_task_runner.h"
 #include "components/keyed_service/core/keyed_service.h"
@@ -21,7 +22,7 @@
 
 // Class that provides instances of ProtoDatabase tied to the current
 // profile directory.
-class ProtoDatabaseProvider {
+class COMPONENT_EXPORT(LEVELDB_PROTO) ProtoDatabaseProvider {
  public:
   using GetSharedDBInstanceCallback =
       base::OnceCallback<void(scoped_refptr<SharedProtoDatabase>)>;
diff --git a/components/leveldb_proto/public/shared_proto_database_client_list.h b/components/leveldb_proto/public/shared_proto_database_client_list.h
index e46ecef..7a799b8 100644
--- a/components/leveldb_proto/public/shared_proto_database_client_list.h
+++ b/components/leveldb_proto/public/shared_proto_database_client_list.h
@@ -9,6 +9,8 @@
 
 #include <string>
 
+#include "base/component_export.h"
+
 namespace leveldb_proto {
 
 const char* const kFeatureEngagementName = "FeatureEngagement";
@@ -57,7 +59,7 @@
     ProtoDbType::LAST,  // Marks the end of list.
 };
 
-class SharedProtoDatabaseClientList {
+class COMPONENT_EXPORT(LEVELDB_PROTO) SharedProtoDatabaseClientList {
  public:
   // Determines if the given |db_type| should use a unique or shared DB.
   static bool ShouldUseSharedDB(ProtoDbType db_type);
diff --git a/components/mirroring/mojom/BUILD.gn b/components/mirroring/mojom/BUILD.gn
index 466db8c..b62d28b0 100644
--- a/components/mirroring/mojom/BUILD.gn
+++ b/components/mirroring/mojom/BUILD.gn
@@ -4,12 +4,6 @@
 
 import("//mojo/public/tools/bindings/mojom.gni")
 
-mojom("constants") {
-  sources = [
-    "constants.mojom",
-  ]
-}
-
 mojom("common") {
   sources = [
     "cast_message_channel.mojom",
@@ -45,6 +39,7 @@
     "//media/mojo/mojom",
     "//media/mojo/mojom:remoting",
     "//services/network/public/mojom",
+    "//services/viz/public/mojom",
     "//ui/gfx/geometry/mojom",
   ]
 }
diff --git a/components/mirroring/mojom/constants.mojom b/components/mirroring/mojom/constants.mojom
deleted file mode 100644
index ace762e..0000000
--- a/components/mirroring/mojom/constants.mojom
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module mirroring.mojom;
-
-const string kServiceName = "mirroring";
diff --git a/components/mirroring/mojom/resource_provider.mojom b/components/mirroring/mojom/resource_provider.mojom
index eac2fe7..18a54867 100644
--- a/components/mirroring/mojom/resource_provider.mojom
+++ b/components/mirroring/mojom/resource_provider.mojom
@@ -10,6 +10,7 @@
 import "media/mojo/mojom/audio_data_pipe.mojom";
 import "media/mojo/mojom/audio_input_stream.mojom";
 import "media/mojo/mojom/audio_parameters.mojom";
+import "services/viz/public/mojom/gpu.mojom";
 
 // This interface is used by ResourceProvider to notify that an audio input
 // stream is created as requested. The lifetime of the stream is limited by the
@@ -25,6 +26,8 @@
 // This interface is used by the Mirroring Service to ask the browser to provide
 // resources.
 interface ResourceProvider {
+  // Acquires an interface to the GPU process.
+  BindGpu(pending_receiver<viz.mojom.Gpu> receiver);
   GetVideoCaptureHost(media.mojom.VideoCaptureHost& request);
   GetNetworkContext(network.mojom.NetworkContext& request);
   CreateAudioStream(AudioStreamCreatorClient client,
diff --git a/components/mirroring/service/BUILD.gn b/components/mirroring/service/BUILD.gn
index 6c02d8cf..62b48a82a 100644
--- a/components/mirroring/service/BUILD.gn
+++ b/components/mirroring/service/BUILD.gn
@@ -63,7 +63,6 @@
     "//net",
     "//services/network/public/cpp",
     "//services/network/public/mojom",
-    "//services/service_manager/public/cpp:cpp",
     "//services/viz/public/cpp/gpu",
     "//ui/base",
     "//ui/gfx",
@@ -114,17 +113,3 @@
     "//testing/gtest",
   ]
 }
-
-source_set("manifest") {
-  sources = [
-    "manifest.cc",
-    "manifest.h",
-  ]
-
-  deps = [
-    "//base",
-    "//components/mirroring/mojom:constants",
-    "//components/mirroring/mojom:service",
-    "//services/service_manager/public/cpp",
-  ]
-}
diff --git a/components/mirroring/service/DEPS b/components/mirroring/service/DEPS
index a50f12e..07a4900 100644
--- a/components/mirroring/service/DEPS
+++ b/components/mirroring/service/DEPS
@@ -9,7 +9,6 @@
   "+net",
   "+services/network/public",
   "+services/network/test",
-  "+services/service_manager",
   "+services/viz/public",
   "+ui/base",
 ]
diff --git a/components/mirroring/service/manifest.cc b/components/mirroring/service/manifest.cc
deleted file mode 100644
index 4218df7..0000000
--- a/components/mirroring/service/manifest.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/mirroring/service/manifest.h"
-
-#include "base/no_destructor.h"
-#include "components/mirroring/mojom/constants.mojom.h"
-#include "components/mirroring/mojom/mirroring_service.mojom.h"
-#include "services/service_manager/public/cpp/manifest_builder.h"
-
-namespace mirroring {
-
-const service_manager::Manifest& GetManifest() {
-  static base::NoDestructor<service_manager::Manifest> manifest{
-      service_manager::ManifestBuilder()
-          .WithServiceName(mojom::kServiceName)
-          .WithDisplayName("Mirroring Service")
-          .WithOptions(
-              service_manager::ManifestOptionsBuilder()
-                  .WithExecutionMode(service_manager::Manifest::ExecutionMode::
-                                         kOutOfProcessBuiltin)
-                  .WithSandboxType("utility")
-                  .Build())
-          .ExposeCapability("mirroring",
-                            service_manager::Manifest::InterfaceList<
-                                mojom::MirroringService>())
-          .RequireCapability("content_system", "gpu_client")
-          .RequireCapability("ui", "gpu_client")
-
-          .Build()};
-  return *manifest;
-}
-
-}  // namespace mirroring
diff --git a/components/mirroring/service/manifest.h b/components/mirroring/service/manifest.h
deleted file mode 100644
index 26022af..0000000
--- a/components/mirroring/service/manifest.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_MIRRORING_SERVICE_MANIFEST_H_
-#define COMPONENTS_MIRRORING_SERVICE_MANIFEST_H_
-
-#include "services/service_manager/public/cpp/manifest.h"
-
-namespace mirroring {
-
-const service_manager::Manifest& GetManifest();
-
-}  // namespace mirroring
-
-#endif  // COMPONENTS_MIRRORING_SERVICE_MANIFEST_H_
diff --git a/components/mirroring/service/mirroring_service.cc b/components/mirroring/service/mirroring_service.cc
index 168c3fe..110a723 100644
--- a/components/mirroring/service/mirroring_service.cc
+++ b/components/mirroring/service/mirroring_service.cc
@@ -12,41 +12,12 @@
 namespace mirroring {
 
 MirroringService::MirroringService(
-    service_manager::mojom::ServiceRequest request,
+    mojo::PendingReceiver<mojom::MirroringService> receiver,
     scoped_refptr<base::SingleThreadTaskRunner> io_task_runner)
-    : service_binding_(this, std::move(request)),
-      service_keepalive_(&service_binding_, base::TimeDelta()),
-      io_task_runner_(std::move(io_task_runner)) {
-  registry_.AddInterface<mojom::MirroringService>(
-      base::BindRepeating(&MirroringService::Create, base::Unretained(this)));
-}
+    : receiver_(this, std::move(receiver)),
+      io_task_runner_(std::move(io_task_runner)) {}
 
-MirroringService::~MirroringService() {
-  session_.reset();
-  registry_.RemoveInterface<mojom::MirroringService>();
-}
-
-void MirroringService::OnBindInterface(
-    const service_manager::BindSourceInfo& source_info,
-    const std::string& interface_name,
-    mojo::ScopedMessagePipeHandle interface_pipe) {
-  registry_.BindInterface(interface_name, std::move(interface_pipe));
-}
-
-bool MirroringService::OnServiceManagerConnectionLost() {
-  bindings_.CloseAllBindings();
-  return true;
-}
-
-void MirroringService::Create(mojom::MirroringServiceRequest request) {
-  bindings_.AddBinding(this, std::move(request));
-  bindings_.set_connection_error_handler(base::BindRepeating(
-      [](MirroringService* service) {
-        service->session_.reset();
-        service->bindings_.CloseAllBindings();
-      },
-      this));
-}
+MirroringService::~MirroringService() = default;
 
 void MirroringService::Start(mojom::SessionParametersPtr params,
                              const gfx::Size& max_resolution,
@@ -55,15 +26,10 @@
                              mojom::CastMessageChannelPtr outbound_channel,
                              mojom::CastMessageChannelRequest inbound_channel) {
   session_.reset();  // Stops the current session if active.
-  std::unique_ptr<viz::Gpu> gpu;
-  if (params->type != mojom::SessionType::AUDIO_ONLY) {
-    gpu = viz::Gpu::Create(service_binding_.GetConnector(), "content_system",
-                           io_task_runner_);
-  }
   session_ = std::make_unique<Session>(
       std::move(params), max_resolution, std::move(observer),
       std::move(resource_provider), std::move(outbound_channel),
-      std::move(inbound_channel), std::move(gpu));
+      std::move(inbound_channel), io_task_runner_);
 }
 
 }  // namespace mirroring
diff --git a/components/mirroring/service/mirroring_service.h b/components/mirroring/service/mirroring_service.h
index aa39f12..6a59bcf 100644
--- a/components/mirroring/service/mirroring_service.h
+++ b/components/mirroring/service/mirroring_service.h
@@ -8,35 +8,21 @@
 #include "base/component_export.h"
 #include "base/macros.h"
 #include "components/mirroring/mojom/mirroring_service.mojom.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-#include "services/service_manager/public/cpp/binder_registry.h"
-#include "services/service_manager/public/cpp/service.h"
-#include "services/service_manager/public/cpp/service_binding.h"
-#include "services/service_manager/public/cpp/service_keepalive.h"
-#include "services/service_manager/public/mojom/service.mojom.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 
 namespace mirroring {
 
 class Session;
 
 class COMPONENT_EXPORT(MIRRORING_SERVICE) MirroringService final
-    : public service_manager::Service,
-      public mojom::MirroringService {
+    : public mojom::MirroringService {
  public:
-  MirroringService(service_manager::mojom::ServiceRequest request,
+  MirroringService(mojo::PendingReceiver<mojom::MirroringService> receiver,
                    scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
   ~MirroringService() override;
 
  private:
-  // service_manager::Service implementation.
-  void OnBindInterface(const service_manager::BindSourceInfo& source_info,
-                       const std::string& interface_name,
-                       mojo::ScopedMessagePipeHandle interface_pipe) override;
-  bool OnServiceManagerConnectionLost() override;
-
-  // Handles the request to connect to this service.
-  void Create(mojom::MirroringServiceRequest request);
-
   // mojom::MirroringService implementation.
   void Start(mojom::SessionParametersPtr params,
              const gfx::Size& max_resolution,
@@ -45,12 +31,8 @@
              mojom::CastMessageChannelPtr outbound_channel,
              mojom::CastMessageChannelRequest inbound_channel) override;
 
-  service_manager::ServiceBinding service_binding_;
-  service_manager::ServiceKeepalive service_keepalive_;
-
+  mojo::Receiver<mojom::MirroringService> receiver_;
   const scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
-  service_manager::BinderRegistry registry_;
-  mojo::BindingSet<mojom::MirroringService> bindings_;
   std::unique_ptr<Session> session_;  // Current mirroring session.
 
   DISALLOW_COPY_AND_ASSIGN(MirroringService);
diff --git a/components/mirroring/service/session.cc b/components/mirroring/service/session.cc
index 38aaf93..5bbdfc6 100644
--- a/components/mirroring/service/session.cc
+++ b/components/mirroring/service/session.cc
@@ -379,7 +379,7 @@
                  mojom::ResourceProviderPtr resource_provider,
                  mojom::CastMessageChannelPtr outbound_channel,
                  mojom::CastMessageChannelRequest inbound_channel,
-                 std::unique_ptr<viz::Gpu> gpu)
+                 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner)
     : session_params_(*session_params),
       state_(MIRRORING),
       observer_(std::move(observer)),
@@ -388,13 +388,19 @@
                           std::move(inbound_channel),
                           base::BindRepeating(&Session::OnResponseParsingError,
                                               base::Unretained(this))),
-      gpu_(std::move(gpu)),
       gpu_channel_host_(nullptr) {
   DCHECK(resource_provider_);
   mirror_settings_.SetResolutionContraints(max_resolution.width(),
                                            max_resolution.height());
   resource_provider_->GetNetworkContext(mojo::MakeRequest(&network_context_));
 
+  if (session_params->type != mojom::SessionType::AUDIO_ONLY &&
+      io_task_runner) {
+    mojo::PendingRemote<viz::mojom::Gpu> remote_gpu;
+    resource_provider_->BindGpu(remote_gpu.InitWithNewPipeAndPassReceiver());
+    gpu_ = viz::Gpu::Create(std::move(remote_gpu), io_task_runner);
+  }
+
   network::mojom::URLLoaderFactoryParamsPtr params =
       network::mojom::URLLoaderFactoryParams::New();
   params->process_id = network::mojom::kBrowserProcessId;
diff --git a/components/mirroring/service/session.h b/components/mirroring/service/session.h
index 1f259fb..b6a6a55 100644
--- a/components/mirroring/service/session.h
+++ b/components/mirroring/service/session.h
@@ -63,7 +63,7 @@
           mojom::ResourceProviderPtr resource_provider,
           mojom::CastMessageChannelPtr outbound_channel,
           mojom::CastMessageChannelRequest inbound_channel,
-          std::unique_ptr<viz::Gpu> gpu);
+          scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
 
   ~Session() override;
 
diff --git a/components/mirroring/service/session_unittest.cc b/components/mirroring/service/session_unittest.cc
index b170fea8..a256406d 100644
--- a/components/mirroring/service/session_unittest.cc
+++ b/components/mirroring/service/session_unittest.cc
@@ -112,6 +112,7 @@
   }
 
   // mojom::ResourceProvider implemenation.
+  void BindGpu(mojo::PendingReceiver<viz::mojom::Gpu> receiver) override {}
   void GetVideoCaptureHost(
       media::mojom::VideoCaptureHostRequest request) override {
     video_host_ = std::make_unique<FakeVideoCaptureHost>(std::move(request));
diff --git a/components/network_session_configurator/browser/network_session_configurator.cc b/components/network_session_configurator/browser/network_session_configurator.cc
index 7470e85..b7e28cce 100644
--- a/components/network_session_configurator/browser/network_session_configurator.cc
+++ b/components/network_session_configurator/browser/network_session_configurator.cc
@@ -26,6 +26,7 @@
 #include "net/base/host_mapping_rules.h"
 #include "net/http/http_stream_factory.h"
 #include "net/quic/quic_utils_chromium.h"
+#include "net/spdy/spdy_session.h"
 #include "net/spdy/spdy_session_pool.h"
 #include "net/third_party/quiche/src/quic/core/quic_packets.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
@@ -107,6 +108,19 @@
   return websocket_value == "true";
 }
 
+int ConfigureSpdySessionMaxQueuedCappedFrames(
+    const base::CommandLine& /*command_line*/,
+    const VariationParameters& http2_trial_params) {
+  int value;
+  if (base::StringToInt(
+          GetVariationParam(http2_trial_params,
+                            "spdy_session_max_queued_capped_frames"),
+          &value)) {
+    return value;
+  }
+  return net::kSpdySessionMaxQueuedCappedFrames;
+}
+
 void ConfigureHttp2Params(const base::CommandLine& command_line,
                           base::StringPiece http2_trial_group,
                           const VariationParameters& http2_trial_params,
@@ -147,6 +161,10 @@
 
   params->enable_websocket_over_http2 =
       ConfigureWebsocketOverHttp2(command_line, http2_trial_params);
+
+  params->spdy_session_max_queued_capped_frames =
+      ConfigureSpdySessionMaxQueuedCappedFrames(command_line,
+                                                http2_trial_params);
 }
 
 bool ShouldEnableQuic(base::StringPiece quic_trial_group,
diff --git a/components/network_session_configurator/common/network_features.cc b/components/network_session_configurator/common/network_features.cc
index c4dd7346..a7145d2 100644
--- a/components/network_session_configurator/common/network_features.cc
+++ b/components/network_session_configurator/common/network_features.cc
@@ -8,7 +8,4 @@
 
 namespace features {
 
-const base::Feature kDnsOverHttps{"dns-over-https",
-                                  base::FEATURE_DISABLED_BY_DEFAULT};
-
 }  // namespace features
diff --git a/components/network_session_configurator/common/network_features.h b/components/network_session_configurator/common/network_features.h
index 4108b1a6..7532695 100644
--- a/components/network_session_configurator/common/network_features.h
+++ b/components/network_session_configurator/common/network_features.h
@@ -10,10 +10,6 @@
 
 namespace features {
 
-// Enabled DNS over HTTPS
-// (https://tools.ietf.org/id/draft-ietf-doh-dns-over-https-12.txt).
-NETWORK_SESSION_CONFIGURATOR_EXPORT extern const base::Feature kDnsOverHttps;
-
 }  // namespace features
 
 #endif  // COMPONENTS_NETWORK_SESSION_CONFIGURATOR_COMMON_NETWORK_FEATURES_H_
diff --git a/components/optimization_guide/optimization_guide_constants.cc b/components/optimization_guide/optimization_guide_constants.cc
index f54c785..573d741f6 100644
--- a/components/optimization_guide/optimization_guide_constants.cc
+++ b/components/optimization_guide/optimization_guide_constants.cc
@@ -14,4 +14,7 @@
 const char kOptimizationGuideServiceDefaultURL[] =
     "https://optimizationguide-pa.googleapis.com/v1:GetHints";
 
+const char kLoadedHintLocalHistogramString[] =
+    "OptimizationGuide.LoadedHint.Result";
+
 }  // namespace optimization_guide
diff --git a/components/optimization_guide/optimization_guide_constants.h b/components/optimization_guide/optimization_guide_constants.h
index 7639f450..cd81f88a 100644
--- a/components/optimization_guide/optimization_guide_constants.h
+++ b/components/optimization_guide/optimization_guide_constants.h
@@ -17,6 +17,10 @@
 // The remote Optimization Guide Service production server to fetch hints from.
 extern const char kOptimizationGuideServiceDefaultURL[];
 
+// The local histogram used to record that the component hints are stored in
+// the cache and are ready for use.
+extern const char kLoadedHintLocalHistogramString[];
+
 }  // namespace optimization_guide
 
 #endif  // COMPONENTS_OPTIMIZATION_GUIDE_OPTIMIZATION_GUIDE_CONSTANTS_H_
diff --git a/components/page_info_strings.grdp b/components/page_info_strings.grdp
index 5d531d7..65ccdec 100644
--- a/components/page_info_strings.grdp
+++ b/components/page_info_strings.grdp
@@ -274,7 +274,7 @@
       Serial ports
     </message>
     <message name="IDS_PAGE_INFO_TYPE_NATIVE_FILE_SYSTEM_WRITE" desc="The label used for the native file system write permission controls in the Page Info popup. The write permission determines whether sites are allowed to save to the original file that was selected by the user through the Native File System API.">
-      Files on device
+      File editing
     </message>
     <message name="IDS_PAGE_INFO_TYPE_BLUETOOTH_SCANNING" desc="The label used for the Bluetooth scanning controls in the Page Info popup.">
       Bluetooth scanning
diff --git a/components/policy/content/policy_blacklist_service.cc b/components/policy/content/policy_blacklist_service.cc
index 0aab90c..2d80667 100644
--- a/components/policy/content/policy_blacklist_service.cc
+++ b/components/policy/content/policy_blacklist_service.cc
@@ -120,7 +120,5 @@
 
 content::BrowserContext* PolicyBlacklistFactory::GetBrowserContextToUse(
     content::BrowserContext* context) const {
-  // TODO(crbug.com/701326): This DCHECK should be moved to GetContextToUse().
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return context;
 }
diff --git a/components/policy/tools/generate_policy_source.py b/components/policy/tools/generate_policy_source.py
index 604c2fd..d519ee4a 100755
--- a/components/policy/tools/generate_policy_source.py
+++ b/components/policy/tools/generate_policy_source.py
@@ -5,11 +5,12 @@
 '''python %prog [options]
 
 Pass at least:
---chrome-version-file <path to src/chrome/VERSION>
+--chrome-version-file <path to src/chrome/VERSION> or --all-chrome-versions
 --target-platform <which platform the target code will be generated for and can
   be one of (win, mac, linux, chromeos, fuchsia)>
 --policy_templates <path to the policy_templates.json input file>.'''
 
+
 from __future__ import with_statement
 from collections import namedtuple
 from collections import OrderedDict
@@ -103,10 +104,12 @@
       if version_min == '':
         raise RuntimeError('supported_on must define a start version: "%s"' % p)
 
-      # Skip if the current Chromium version does not support the policy.
-      if (int(version_min) > chrome_major_version or
-          version_max != '' and int(version_max) < chrome_major_version):
-        continue
+      # Skip if filtering by Chromium version and the current Chromium version
+      # does not support the policy.
+      if chrome_major_version:
+        if (int(version_min) > chrome_major_version or
+            version_max != '' and int(version_max) < chrome_major_version):
+          continue
 
       if platform.startswith('chrome.'):
         platform_sub = platform[7:]
@@ -195,15 +198,15 @@
 
 
 def ParseVersionFile(version_path):
-  major_version = None
+  chrome_major_version = None
   for line in open(version_path, 'r').readlines():
     key, val = line.rstrip('\r\n').split('=', 1)
     if key == 'MAJOR':
-      major_version = val
+      chrome_major_version = val
       break
-  if major_version is None:
+  if chrome_major_version is None:
     raise RuntimeError('VERSION file does not contain major version.')
-  return int(major_version)
+  return int(chrome_major_version)
 
 
 def main():
@@ -277,6 +280,12 @@
       help='path to src/chrome/VERSION',
       metavar='FILE')
   parser.add_option(
+      '--all-chrome-versions',
+      action='store_true',
+      dest='all_chrome_versions',
+      default=False,
+      help='do not restrict generated policies by chrome version')
+  parser.add_option(
       '--target-platform',
       dest='target_platform',
       help='the platform the generated code should run on - can be one of'
@@ -289,12 +298,25 @@
       metavar='FILE')
   (opts, args) = parser.parse_args()
 
-  if (not opts.chrome_version_file or not opts.target_platform or
-      not opts.policy_templates_file):
-    print('Please specify at least:\n'
-          '--chrome-version-file=<path to src/chrome/VERSION>\n'
-          '--target-platform=<platform>\n'
-          '--policy-templates-file=<path to policy_templates.json')
+  has_arg_error = False
+
+  if not opts.target_platform:
+    print('Error: Missing --target-platform=<platform>')
+    has_arg_error = True
+
+  if not opts.policy_templates_file:
+    print('Error: Missing'
+          ' --policy-templates-file=<path to policy_templates.json>')
+    has_arg_error = True
+
+  if not opts.chrome_version_file and not opts.all_chrome_versions:
+    print('Error: Missing'
+          ' --chrome-version-file=<path to src/chrome/VERSION>\n'
+          ' or --all-chrome-versions')
+    has_arg_error = True
+
+  if has_arg_error:
+    print('')
     parser.print_help()
     return 2
 
@@ -307,11 +329,15 @@
   if target_platform == 'chromeos':
     target_platform = 'chrome_os'
 
-  major_version = ParseVersionFile(version_path)
+  if opts.all_chrome_versions:
+    chrome_major_version = None
+  else:
+    chrome_major_version = ParseVersionFile(version_path)
+
   template_file_contents = _LoadJSONFile(template_file_name)
   risk_tags = RiskTags(template_file_contents)
   policy_details = [
-      PolicyDetails(policy, major_version, target_platform,
+      PolicyDetails(policy, chrome_major_version, target_platform,
                     risk_tags.GetValidTags())
       for policy in template_file_contents['policy_definitions']
       if policy['type'] != 'group'
diff --git a/components/previews/content/previews_optimization_guide.cc b/components/previews/content/previews_optimization_guide.cc
index 3702ecb..e1cc20d 100644
--- a/components/previews/content/previews_optimization_guide.cc
+++ b/components/previews/content/previews_optimization_guide.cc
@@ -18,6 +18,7 @@
 #include "components/optimization_guide/hints_component_info.h"
 #include "components/optimization_guide/hints_component_util.h"
 #include "components/optimization_guide/hints_fetcher.h"
+#include "components/optimization_guide/optimization_guide_constants.h"
 #include "components/optimization_guide/optimization_guide_features.h"
 #include "components/optimization_guide/optimization_guide_prefs.h"
 #include "components/optimization_guide/optimization_guide_service.h"
@@ -27,7 +28,6 @@
 #include "components/prefs/pref_service.h"
 #include "components/previews/content/previews_hints.h"
 #include "components/previews/content/previews_user_data.h"
-#include "components/previews/core/previews_constants.h"
 #include "components/previews/core/previews_switches.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "url/gurl.h"
@@ -154,8 +154,8 @@
 
   // Record that the hint finished loading. This is used as a signal during
   // tests.
-  LOCAL_HISTOGRAM_BOOLEAN(
-      kPreviewsOptimizationGuideOnLoadedHintResultHistogramString, loaded_hint);
+  LOCAL_HISTOGRAM_BOOLEAN(optimization_guide::kLoadedHintLocalHistogramString,
+                          loaded_hint);
 
   // Run the callback now that the hint is loaded. This is used as a signal by
   // tests.
diff --git a/components/previews/core/BUILD.gn b/components/previews/core/BUILD.gn
index 886262a..2692866 100644
--- a/components/previews/core/BUILD.gn
+++ b/components/previews/core/BUILD.gn
@@ -6,8 +6,6 @@
   sources = [
     "previews_black_list.cc",
     "previews_black_list.h",
-    "previews_constants.cc",
-    "previews_constants.h",
     "previews_decider.h",
     "previews_experiments.cc",
     "previews_experiments.h",
diff --git a/components/previews/core/previews_constants.cc b/components/previews/core/previews_constants.cc
deleted file mode 100644
index 68263516..0000000
--- a/components/previews/core/previews_constants.cc
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/previews/core/previews_constants.h"
-
-namespace previews {
-
-const char kPreviewsOptimizationGuideOnLoadedHintResultHistogramString[] =
-    "PreviewsOptimizationGuide.OnLoadedHint.Result";
-
-}  // namespace previews
diff --git a/components/previews/core/previews_constants.h b/components/previews/core/previews_constants.h
deleted file mode 100644
index 7c90a47..0000000
--- a/components/previews/core/previews_constants.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_PREVIEWS_CORE_PREVIEWS_CONSTANTS_H_
-#define COMPONENTS_PREVIEWS_CORE_PREVIEWS_CONSTANTS_H_
-
-namespace previews {
-
-// The local histogram used by PreviewsOptimizationGuide to record that a hint
-// finished loading.
-extern const char kPreviewsOptimizationGuideOnLoadedHintResultHistogramString[];
-
-}  // namespace previews
-
-#endif  // COMPONENTS_PREVIEWS_CORE_PREVIEWS_CONSTANTS_H_
diff --git a/components/previews/core/previews_experiments.cc b/components/previews/core/previews_experiments.cc
index e671e81..53daa46 100644
--- a/components/previews/core/previews_experiments.cc
+++ b/components/previews/core/previews_experiments.cc
@@ -13,7 +13,6 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
-#include "components/previews/core/previews_constants.h"
 #include "components/previews/core/previews_features.h"
 #include "components/previews/core/previews_switches.h"
 #include "net/base/url_util.h"
diff --git a/components/previews/core/previews_experiments_unittest.cc b/components/previews/core/previews_experiments_unittest.cc
index 01c3f9b..32efbca2 100644
--- a/components/previews/core/previews_experiments_unittest.cc
+++ b/components/previews/core/previews_experiments_unittest.cc
@@ -15,7 +15,6 @@
 #include "base/strings/string_util.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
-#include "components/previews/core/previews_constants.h"
 #include "components/previews/core/previews_features.h"
 #include "components/variations/variations_associated_data.h"
 
diff --git a/components/viz/common/resources/resource_format_utils.cc b/components/viz/common/resources/resource_format_utils.cc
index 1c0767d..dbc9987 100644
--- a/components/viz/common/resources/resource_format_utils.cc
+++ b/components/viz/common/resources/resource_format_utils.cc
@@ -450,9 +450,11 @@
       return VK_FORMAT_R8_UNORM;
     case LUMINANCE_8:
       return VK_FORMAT_R8_UNORM;
-    case LUMINANCE_F16:
     case YVU_420:
+      return VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
     case YUV_420_BIPLANAR:
+      return VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
+    case LUMINANCE_F16:
     case UYVY_422:
     case ETC1:
     case P010:
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl.cc b/components/viz/service/display_embedder/skia_output_surface_impl.cc
index 81011e91..156152e 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl.cc
@@ -649,7 +649,10 @@
     if (!ycbcr_info)
       return GrBackendFormat::MakeVk(ToVkFormat(resource_format));
 
-    GrVkYcbcrConversionInfo fYcbcrConversionInfo(
+    VkFormat format = ycbcr_info->external_format ? VK_FORMAT_UNDEFINED
+                                                  : ToVkFormat(resource_format);
+    GrVkYcbcrConversionInfo gr_ycbcr_info(
+        format, ycbcr_info->external_format,
         static_cast<VkSamplerYcbcrModelConversion>(
             ycbcr_info->suggested_ycbcr_model),
         static_cast<VkSamplerYcbcrRange>(ycbcr_info->suggested_ycbcr_range),
@@ -657,9 +660,8 @@
         static_cast<VkChromaLocation>(ycbcr_info->suggested_ychroma_offset),
         VK_FILTER_LINEAR,  // VkFilter
         0,                 // VkBool32 forceExplicitReconstruction,
-        ycbcr_info->external_format,
         static_cast<VkFormatFeatureFlags>(ycbcr_info->format_features));
-    return GrBackendFormat::MakeVk(fYcbcrConversionInfo);
+    return GrBackendFormat::MakeVk(gr_ycbcr_info);
 #else
     NOTREACHED();
     return GrBackendFormat();
diff --git a/components/viz/service/hit_test/hit_test_manager.cc b/components/viz/service/hit_test/hit_test_manager.cc
index c46e6b8..2f8178c 100644
--- a/components/viz/service/hit_test/hit_test_manager.cc
+++ b/components/viz/service/hit_test/hit_test_manager.cc
@@ -14,6 +14,16 @@
 // TODO(gklassen): Review and select appropriate sizes based on
 // telemetry / UMA.
 constexpr uint32_t kMaxRegionsPerSurface = 1024;
+
+// Whenever a hit test region is marked as kHitTestAsk there must be a reason
+// for async hit test and vice versa.
+bool FlagsAndAsyncReasonsMatch(uint32_t flags,
+                               uint32_t async_hit_test_reasons) {
+  if (flags & kHitTestAsk)
+    return async_hit_test_reasons != kNotAsyncHitTest;
+  return async_hit_test_reasons == kNotAsyncHitTest;
+}
+
 }  // namespace
 
 HitTestManager::HitTestAsyncQueriedDebugRegion::
@@ -156,6 +166,11 @@
     HitTestRegionList* hit_test_region_list) {
   if (hit_test_region_list->regions.size() > kMaxRegionsPerSurface)
     return false;
+  if (!FlagsAndAsyncReasonsMatch(
+          hit_test_region_list->flags,
+          hit_test_region_list->async_hit_test_reasons)) {
+    return false;
+  }
   for (auto& region : hit_test_region_list->regions) {
     // TODO(gklassen): Ensure that |region->frame_sink_id| is a child of
     // |frame_sink_id|.
@@ -163,15 +178,8 @@
       region.frame_sink_id = FrameSinkId(surface_id.frame_sink_id().client_id(),
                                          region.frame_sink_id.sink_id());
     }
-
-    // Whenever a hit test region is marked as kHitTestAsk there must be a
-    // reason for async hit test and vice versa.
-    if (region.flags & kHitTestAsk) {
-      if (region.async_hit_test_reasons == kNotAsyncHitTest)
-        return false;
-    } else if (region.async_hit_test_reasons != kNotAsyncHitTest) {
+    if (!FlagsAndAsyncReasonsMatch(region.flags, region.async_hit_test_reasons))
       return false;
-    }
   }
   return true;
 }
diff --git a/content/browser/accessibility/accessibility_tree_formatter_blink.cc b/content/browser/accessibility/accessibility_tree_formatter_blink.cc
index ec7637d..c6bcc681 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_blink.cc
+++ b/content/browser/accessibility/accessibility_tree_formatter_blink.cc
@@ -338,14 +338,16 @@
   }
 
   //  Check for relevant rich text selection info in AXTreeData
-  int anchor_id = node.manager()->GetTreeData().sel_anchor_object_id;
+  ui::AXTree::Selection unignored_selection =
+      node.manager()->ax_tree()->GetUnignoredSelection();
+  int anchor_id = unignored_selection.anchor_object_id;
   if (id == anchor_id) {
-    int anchor_offset = node.manager()->GetTreeData().sel_anchor_offset;
+    int anchor_offset = unignored_selection.anchor_offset;
     dict->SetInteger("TreeData.textSelStartOffset", anchor_offset);
   }
-  int focus_id = node.manager()->GetTreeData().sel_focus_object_id;
+  int focus_id = unignored_selection.focus_object_id;
   if (id == focus_id) {
-    int focus_offset = node.manager()->GetTreeData().sel_focus_offset;
+    int focus_offset = unignored_selection.focus_offset;
     dict->SetInteger("TreeData.textSelEndOffset", focus_offset);
   }
 
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index b47d226..1b2340b1 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -1028,7 +1028,9 @@
 }
 
 bool BrowserAccessibility::HasVisibleCaretOrSelection() const {
-  int32_t focus_id = manager()->GetTreeData().sel_focus_object_id;
+  ui::AXTree::Selection unignored_selection =
+      manager()->ax_tree()->GetUnignoredSelection();
+  int32_t focus_id = unignored_selection.focus_object_id;
   BrowserAccessibility* focus_object = manager()->GetFromID(focus_id);
   if (!focus_object)
     return false;
@@ -1041,9 +1043,9 @@
 
   // The selection will be visible in non-editable content only if it is not
   // collapsed into a caret.
-  return (focus_id != manager()->GetTreeData().sel_anchor_object_id ||
-          manager()->GetTreeData().sel_focus_offset !=
-              manager()->GetTreeData().sel_anchor_offset) &&
+  return (focus_id != unignored_selection.anchor_object_id ||
+          unignored_selection.focus_offset !=
+              unignored_selection.anchor_offset) &&
          focus_object->IsDescendantOf(this);
 }
 
@@ -1424,6 +1426,14 @@
     return *empty_data;
 }
 
+const ui::AXTree::Selection BrowserAccessibility::GetUnignoredSelection()
+    const {
+  if (manager())
+    return manager()->ax_tree()->GetUnignoredSelection();
+  return ui::AXTree::Selection{-1, -1, -1,
+                               ax::mojom::TextAffinity::kDownstream};
+}
+
 ui::AXNodePosition::AXPositionInstance
 BrowserAccessibility::CreateTextPositionAt(
     int offset,
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h
index 182f378..407b99f7 100644
--- a/content/browser/accessibility/browser_accessibility.h
+++ b/content/browser/accessibility/browser_accessibility.h
@@ -433,6 +433,7 @@
   base::string16 GetAuthorUniqueId() const override;
   const ui::AXNodeData& GetData() const override;
   const ui::AXTreeData& GetTreeData() const override;
+  const ui::AXTree::Selection GetUnignoredSelection() const override;
   ui::AXNodePosition::AXPositionInstance CreateTextPositionAt(
       int offset,
       ax::mojom::TextAffinity affinity =
diff --git a/content/browser/accessibility/browser_accessibility_android.cc b/content/browser/accessibility/browser_accessibility_android.cc
index e10eea9b..b828f57 100644
--- a/content/browser/accessibility/browser_accessibility_android.cc
+++ b/content/browser/accessibility/browser_accessibility_android.cc
@@ -1329,16 +1329,16 @@
       GetIntAttribute(ax::mojom::IntAttribute::kTextSelStart, &sel_start)) {
     return sel_start;
   }
-
-  int32_t anchor_id = manager()->GetTreeData().sel_anchor_object_id;
+  ui::AXTree::Selection unignored_selection =
+      manager()->ax_tree()->GetUnignoredSelection();
+  int32_t anchor_id = unignored_selection.anchor_object_id;
   BrowserAccessibility* anchor_object = manager()->GetFromID(anchor_id);
   if (!anchor_object) {
     return 0;
   }
 
   auto position = anchor_object->CreatePositionAt(
-      manager()->GetTreeData().sel_anchor_offset,
-      manager()->GetTreeData().sel_anchor_affinity);
+      unignored_selection.anchor_offset, unignored_selection.anchor_affinity);
   while (position->GetAnchor() && position->GetAnchor() != this)
     position = position->CreateParentPosition();
 
@@ -1352,14 +1352,15 @@
     return sel_end;
   }
 
-  int32_t focus_id = manager()->GetTreeData().sel_focus_object_id;
+  ui::AXTree::Selection unignored_selection =
+      manager()->ax_tree()->GetUnignoredSelection();
+  int32_t focus_id = unignored_selection.focus_object_id;
   BrowserAccessibility* focus_object = manager()->GetFromID(focus_id);
   if (!focus_object)
     return 0;
 
   auto position = focus_object->CreatePositionAt(
-      manager()->GetTreeData().sel_focus_offset,
-      manager()->GetTreeData().sel_focus_affinity);
+      unignored_selection.focus_offset, unignored_selection.focus_affinity);
   while (position->GetAnchor() && position->GetAnchor() != this)
     position = position->CreateParentPosition();
 
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
index 241f5a41..61ec74b 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -2115,12 +2115,14 @@
   if (!manager)
     return nil;
 
-  int32_t anchorId = manager->GetTreeData().sel_anchor_object_id;
+  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 = manager->GetTreeData().sel_focus_object_id;
+  int32_t focusId = unignored_selection.focus_object_id;
   const BrowserAccessibility* focusObject = manager->GetFromID(focusId);
   if (!focusObject)
     return nil;
@@ -2128,15 +2130,13 @@
   // |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 = manager->GetTreeData().sel_anchor_offset;
-  int focusOffset = manager->GetTreeData().sel_focus_offset;
+  int anchorOffset = unignored_selection.anchor_offset;
+  int focusOffset = unignored_selection.focus_offset;
   if (anchorOffset < 0 || focusOffset < 0)
     return nil;
 
-  ax::mojom::TextAffinity anchorAffinity =
-      manager->GetTreeData().sel_anchor_affinity;
-  ax::mojom::TextAffinity focusAffinity =
-      manager->GetTreeData().sel_focus_affinity;
+  ax::mojom::TextAffinity anchorAffinity = unignored_selection.anchor_affinity;
+  ax::mojom::TextAffinity focusAffinity = unignored_selection.focus_affinity;
 
   return CreateTextMarkerRange(
       CreateAXPlatformRange(*anchorObject, anchorOffset, anchorAffinity,
diff --git a/content/browser/accessibility/browser_accessibility_manager_android.cc b/content/browser/accessibility/browser_accessibility_manager_android.cc
index dab8e24a..0c6d33c 100644
--- a/content/browser/accessibility/browser_accessibility_manager_android.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_android.cc
@@ -181,7 +181,7 @@
       break;
     }
     case ui::AXEventGenerator::Event::DOCUMENT_SELECTION_CHANGED: {
-      int32_t focus_id = GetTreeData().sel_focus_object_id;
+      int32_t focus_id = ax_tree()->GetUnignoredSelection().focus_object_id;
       BrowserAccessibility* focus_object = GetFromID(focus_id);
       if (focus_object) {
         BrowserAccessibilityAndroid* android_focus_object =
diff --git a/content/browser/accessibility/browser_accessibility_manager_auralinux.cc b/content/browser/accessibility/browser_accessibility_manager_auralinux.cc
index 78cdfdf..8e75489 100644
--- a/content/browser/accessibility/browser_accessibility_manager_auralinux.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_auralinux.cc
@@ -133,7 +133,7 @@
 
   switch (event_type) {
     case ui::AXEventGenerator::Event::DOCUMENT_SELECTION_CHANGED: {
-      int32_t focus_id = GetTreeData().sel_focus_object_id;
+      int32_t focus_id = ax_tree()->GetUnignoredSelection().focus_object_id;
       BrowserAccessibility* focus_object = GetFromID(focus_id);
       if (focus_object)
         FireEvent(focus_object, ax::mojom::Event::kTextSelectionChanged);
diff --git a/content/browser/accessibility/browser_accessibility_manager_mac.mm b/content/browser/accessibility/browser_accessibility_manager_mac.mm
index 790b79d..851da83 100644
--- a/content/browser/accessibility/browser_accessibility_manager_mac.mm
+++ b/content/browser/accessibility/browser_accessibility_manager_mac.mm
@@ -484,7 +484,7 @@
                 forKey:NSAccessibilityTextSelectionGranularity];
   [user_info setObject:@YES forKey:NSAccessibilityTextSelectionChangedFocus];
 
-  int32_t focus_id = GetTreeData().sel_focus_object_id;
+  int32_t focus_id = ax_tree()->GetUnignoredSelection().focus_object_id;
   BrowserAccessibility* focus_object = GetFromID(focus_id);
   if (focus_object) {
     focus_object = focus_object->GetClosestPlatformObject();
diff --git a/content/browser/accessibility/browser_accessibility_manager_win.cc b/content/browser/accessibility/browser_accessibility_manager_win.cc
index 5847fc6..1a10aa9 100644
--- a/content/browser/accessibility/browser_accessibility_manager_win.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_win.cc
@@ -209,7 +209,7 @@
       break;
     case ui::AXEventGenerator::Event::DOCUMENT_SELECTION_CHANGED: {
       // Fire the event on the object where the focus of the selection is.
-      int32_t focus_id = GetTreeData().sel_focus_object_id;
+      int32_t focus_id = ax_tree()->GetUnignoredSelection().focus_object_id;
       BrowserAccessibility* focus_object = GetFromID(focus_id);
       if (focus_object && focus_object->HasVisibleCaretOrSelection())
         FireWinAccessibilityEvent(IA2_EVENT_TEXT_CARET_MOVED, focus_object);
diff --git a/content/browser/accessibility/dump_accessibility_browsertest_base.cc b/content/browser/accessibility/dump_accessibility_browsertest_base.cc
index d8b79ae..b5a37e9e 100644
--- a/content/browser/accessibility/dump_accessibility_browsertest_base.cc
+++ b/content/browser/accessibility/dump_accessibility_browsertest_base.cc
@@ -225,16 +225,15 @@
   // We have to check for this in advance in order to avoid waiting on a
   // WAIT-FOR directive in the source file that's looking for something not
   // supported on the current platform.
-  base::Optional<base::FilePath> expected_file =
-      test_helper.GetExpectationFilePath(file_path);
-  if (!expected_file) {
+  base::FilePath expected_file = test_helper.GetExpectationFilePath(file_path);
+  if (expected_file.empty()) {
     LOG(INFO) << "No expectation file present, ignoring test on this "
                  "platform.";
     return;
   }
 
   base::Optional<std::vector<std::string>> expected_lines =
-      test_helper.LoadExpectationFile(*expected_file);
+      test_helper.LoadExpectationFile(expected_file);
   if (!expected_lines) {
     LOG(INFO) << "Skipping this test on this platform.";
     return;
@@ -377,7 +376,7 @@
 
   // Validate against the expectation file.
   bool matches_expectation = test_helper.ValidateAgainstExpectation(
-      file_path, *expected_file, actual_lines, *expected_lines);
+      file_path, expected_file, actual_lines, *expected_lines);
   EXPECT_TRUE(matches_expectation);
   if (!matches_expectation)
     OnDiffFailed();
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
index c0ff529..d01404c 100644
--- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -2024,6 +2024,21 @@
 }
 
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest,
+                       AccessibilityIgnoredSelectionNoUnignored) {
+  RunHtmlTest(FILE_PATH_LITERAL("ignored-selection-no-unignored.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest,
+                       AccessibilityIgnoredSelectionBetweenText) {
+  RunHtmlTest(FILE_PATH_LITERAL("ignored-selection-between-text.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest,
+                       AccessibilityIgnoredSelection) {
+  RunHtmlTest(FILE_PATH_LITERAL("ignored-selection.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest,
                        AccessibilityLabelWithSelectedOption) {
   RunHtmlTest(FILE_PATH_LITERAL("label-with-selected-option.html"));
 }
diff --git a/content/browser/broadcast_channel/broadcast_channel_provider.cc b/content/browser/broadcast_channel/broadcast_channel_provider.cc
index 8a8f6c69..34a5df131 100644
--- a/content/browser/broadcast_channel/broadcast_channel_provider.cc
+++ b/content/browser/broadcast_channel/broadcast_channel_provider.cc
@@ -7,9 +7,8 @@
 #include "base/bind.h"
 #include "base/stl_util.h"
 #include "content/browser/child_process_security_policy_impl.h"
-#include "mojo/public/cpp/bindings/associated_binding.h"
-#include "mojo/public/cpp/bindings/interface_ptr_set.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/public/cpp/bindings/associated_receiver.h"
+#include "mojo/public/cpp/bindings/associated_remote.h"
 
 namespace content {
 
@@ -19,11 +18,14 @@
 class BroadcastChannelProvider::Connection
     : public blink::mojom::BroadcastChannelClient {
  public:
-  Connection(const url::Origin& origin,
-             const std::string& name,
-             blink::mojom::BroadcastChannelClientAssociatedPtrInfo client,
-             blink::mojom::BroadcastChannelClientAssociatedRequest connection,
-             BroadcastChannelProvider* service);
+  Connection(
+      const url::Origin& origin,
+      const std::string& name,
+      mojo::PendingAssociatedRemote<blink::mojom::BroadcastChannelClient>
+          client,
+      mojo::PendingAssociatedReceiver<blink::mojom::BroadcastChannelClient>
+          connection,
+      BroadcastChannelProvider* service);
 
   void OnMessage(blink::CloneableMessage message) override;
   void MessageToClient(const blink::CloneableMessage& message) const {
@@ -33,13 +35,13 @@
   const std::string& name() const { return name_; }
 
   void set_connection_error_handler(const base::Closure& error_handler) {
-    binding_.set_connection_error_handler(error_handler);
-    client_.set_connection_error_handler(error_handler);
+    receiver_.set_disconnect_handler(error_handler);
+    client_.set_disconnect_handler(error_handler);
   }
 
  private:
-  mojo::AssociatedBinding<blink::mojom::BroadcastChannelClient> binding_;
-  blink::mojom::BroadcastChannelClientAssociatedPtr client_;
+  mojo::AssociatedReceiver<blink::mojom::BroadcastChannelClient> receiver_;
+  mojo::AssociatedRemote<blink::mojom::BroadcastChannelClient> client_;
 
   BroadcastChannelProvider* service_;
   url::Origin origin_;
@@ -49,15 +51,15 @@
 BroadcastChannelProvider::Connection::Connection(
     const url::Origin& origin,
     const std::string& name,
-    blink::mojom::BroadcastChannelClientAssociatedPtrInfo client,
-    blink::mojom::BroadcastChannelClientAssociatedRequest connection,
+    mojo::PendingAssociatedRemote<blink::mojom::BroadcastChannelClient> client,
+    mojo::PendingAssociatedReceiver<blink::mojom::BroadcastChannelClient>
+        connection,
     BroadcastChannelProvider* service)
-    : binding_(this, std::move(connection)),
+    : receiver_(this, std::move(connection)),
+      client_(std::move(client)),
       service_(service),
       origin_(origin),
-      name_(name) {
-  client_.Bind(std::move(client));
-}
+      name_(name) {}
 
 void BroadcastChannelProvider::Connection::OnMessage(
     blink::CloneableMessage message) {
@@ -66,18 +68,19 @@
 
 BroadcastChannelProvider::BroadcastChannelProvider() {}
 
-mojo::BindingId BroadcastChannelProvider::Connect(
+mojo::ReceiverId BroadcastChannelProvider::Connect(
     RenderProcessHostId render_process_host_id,
-    blink::mojom::BroadcastChannelProviderRequest request) {
-  return bindings_.AddBinding(this, std::move(request), render_process_host_id);
+    mojo::PendingReceiver<blink::mojom::BroadcastChannelProvider> receiver) {
+  return receivers_.Add(this, std::move(receiver), render_process_host_id);
 }
 
 void BroadcastChannelProvider::ConnectToChannel(
     const url::Origin& origin,
     const std::string& name,
-    blink::mojom::BroadcastChannelClientAssociatedPtrInfo client,
-    blink::mojom::BroadcastChannelClientAssociatedRequest connection) {
-  RenderProcessHostId process_id = bindings_.dispatch_context();
+    mojo::PendingAssociatedRemote<blink::mojom::BroadcastChannelClient> client,
+    mojo::PendingAssociatedReceiver<blink::mojom::BroadcastChannelClient>
+        connection) {
+  RenderProcessHostId process_id = receivers_.current_context();
   auto* policy = ChildProcessSecurityPolicyImpl::GetInstance();
 
   // TODO(943887): Replace HasSecurityState() call with something that can
diff --git a/content/browser/broadcast_channel/broadcast_channel_provider.h b/content/browser/broadcast_channel/broadcast_channel_provider.h
index fe43bf9..aabe47a 100644
--- a/content/browser/broadcast_channel/broadcast_channel_provider.h
+++ b/content/browser/broadcast_channel/broadcast_channel_provider.h
@@ -9,7 +9,7 @@
 
 #include "base/memory/ref_counted.h"
 #include "content/common/content_export.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
 #include "third_party/blink/public/mojom/broadcastchannel/broadcast_channel.mojom.h"
 #include "url/origin.h"
 
@@ -22,18 +22,19 @@
   BroadcastChannelProvider();
 
   using RenderProcessHostId = int;
-  mojo::BindingId Connect(
+  mojo::ReceiverId Connect(
       RenderProcessHostId render_process_host_id,
-      blink::mojom::BroadcastChannelProviderRequest request);
+      mojo::PendingReceiver<blink::mojom::BroadcastChannelProvider> receiver);
 
   void ConnectToChannel(
       const url::Origin& origin,
       const std::string& name,
-      blink::mojom::BroadcastChannelClientAssociatedPtrInfo client,
-      blink::mojom::BroadcastChannelClientAssociatedRequest connection)
-      override;
+      mojo::PendingAssociatedRemote<blink::mojom::BroadcastChannelClient>
+          client,
+      mojo::PendingAssociatedReceiver<blink::mojom::BroadcastChannelClient>
+          connection) override;
 
-  auto& bindings_for_testing() { return bindings_; }
+  auto& receivers_for_testing() { return receivers_; }
 
  private:
   friend class base::RefCountedThreadSafe<BroadcastChannelProvider>;
@@ -45,8 +46,8 @@
   void ReceivedMessageOnConnection(Connection*,
                                    const blink::CloneableMessage& message);
 
-  mojo::BindingSet<blink::mojom::BroadcastChannelProvider, RenderProcessHostId>
-      bindings_;
+  mojo::ReceiverSet<blink::mojom::BroadcastChannelProvider, RenderProcessHostId>
+      receivers_;
   std::map<url::Origin, std::multimap<std::string, std::unique_ptr<Connection>>>
       connections_;
 };
diff --git a/content/browser/idle/idle_manager.cc b/content/browser/idle/idle_manager.cc
index beb0c7a..9e6c34e0 100644
--- a/content/browser/idle/idle_manager.cc
+++ b/content/browser/idle/idle_manager.cc
@@ -80,9 +80,10 @@
   bindings_.AddBinding(this, std::move(request));
 }
 
-void IdleManager::AddMonitor(base::TimeDelta threshold,
-                             blink::mojom::IdleMonitorPtr monitor_ptr,
-                             AddMonitorCallback callback) {
+void IdleManager::AddMonitor(
+    base::TimeDelta threshold,
+    mojo::PendingRemote<blink::mojom::IdleMonitor> monitor_remote,
+    AddMonitorCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (threshold < kMinimumThreshold) {
     bindings_.ReportBadMessage("Minimum threshold is 60 seconds.");
@@ -90,7 +91,7 @@
   }
 
   auto monitor = std::make_unique<IdleMonitor>(
-      std::move(monitor_ptr), CheckIdleState(threshold), threshold);
+      std::move(monitor_remote), CheckIdleState(threshold), threshold);
 
   // This unretained reference is safe because IdleManager owns all IdleMonitor
   // instances.
diff --git a/content/browser/idle/idle_manager.h b/content/browser/idle/idle_manager.h
index 35b2545d..8bd0630 100644
--- a/content/browser/idle/idle_manager.h
+++ b/content/browser/idle/idle_manager.h
@@ -16,6 +16,7 @@
 #include "base/timer/timer.h"
 #include "content/browser/idle/idle_monitor.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "third_party/blink/public/mojom/idle/idle_manager.mojom.h"
 #include "ui/base/idle/idle.h"
 #include "url/origin.h"
@@ -54,7 +55,7 @@
 
   // blink.mojom.IdleManager:
   void AddMonitor(base::TimeDelta threshold,
-                  blink::mojom::IdleMonitorPtr monitor_ptr,
+                  mojo::PendingRemote<blink::mojom::IdleMonitor> monitor_remote,
                   AddMonitorCallback callback) override;
 
   // Testing helpers.
diff --git a/content/browser/idle/idle_manager_unittest.cc b/content/browser/idle/idle_manager_unittest.cc
index 772bb2f..7213578 100644
--- a/content/browser/idle/idle_manager_unittest.cc
+++ b/content/browser/idle/idle_manager_unittest.cc
@@ -21,6 +21,7 @@
 #include "content/public/test/test_service_manager_context.h"
 #include "content/test/test_render_frame_host.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/test_support/test_utils.h"
 #include "services/service_manager/public/cpp/bind_source_info.h"
 #include "services/service_manager/public/cpp/connector.h"
@@ -76,16 +77,15 @@
   auto impl = std::make_unique<IdleManager>();
   auto* mock = new NiceMock<MockIdleTimeProvider>();
   impl->SetIdleTimeProviderForTest(base::WrapUnique(mock));
-  blink::mojom::IdleManagerPtr service_ptr;
-  impl->CreateService(mojo::MakeRequest(&service_ptr));
+  mojo::Remote<blink::mojom::IdleManager> service_remote;
+  impl->CreateService(service_remote.BindNewPipeAndPassReceiver());
 
-  blink::mojom::IdleMonitorPtr monitor_ptr;
-  blink::mojom::IdleMonitorRequest monitor_request =
-      mojo::MakeRequest(&monitor_ptr);
+  MockIdleMonitor monitor;
+  mojo::Receiver<blink::mojom::IdleMonitor> monitor_receiver(&monitor);
 
   base::RunLoop loop;
 
-  service_ptr.set_connection_error_handler(base::BindLambdaForTesting([&]() {
+  service_remote.set_disconnect_handler(base::BindLambdaForTesting([&]() {
     ADD_FAILURE() << "Unexpected connection error";
 
     loop.Quit();
@@ -97,8 +97,8 @@
   EXPECT_CALL(*mock, CheckIdleStateIsLocked())
       .WillRepeatedly(testing::Return(false));
 
-  service_ptr->AddMonitor(
-      kThreshold, std::move(monitor_ptr),
+  service_remote->AddMonitor(
+      kThreshold, monitor_receiver.BindNewPipeAndPassRemote(),
       base::BindOnce(
           [](base::OnceClosure callback, blink::mojom::IdleStatePtr state) {
             // The initial state of the status of the user is to be active.
@@ -112,18 +112,15 @@
 }
 
 TEST_F(IdleManagerTest, Idle) {
-  blink::mojom::IdleManagerPtr service_ptr;
+  mojo::Remote<blink::mojom::IdleManager> service_remote;
 
   auto impl = std::make_unique<IdleManager>();
   auto* mock = new NiceMock<MockIdleTimeProvider>();
   impl->SetIdleTimeProviderForTest(base::WrapUnique(mock));
-  impl->CreateService(mojo::MakeRequest(&service_ptr));
+  impl->CreateService(service_remote.BindNewPipeAndPassReceiver());
 
-  blink::mojom::IdleMonitorPtr monitor_ptr;
-  auto monitor_request = mojo::MakeRequest(&monitor_ptr);
   MockIdleMonitor monitor;
-  mojo::Binding<blink::mojom::IdleMonitor> monitor_binding(
-      &monitor, std::move(monitor_request));
+  mojo::Receiver<blink::mojom::IdleMonitor> monitor_receiver(&monitor);
 
   {
     base::RunLoop loop;
@@ -131,8 +128,8 @@
     EXPECT_CALL(*mock, CalculateIdleTime())
         .WillRepeatedly(testing::Return(base::TimeDelta::FromSeconds(0)));
 
-    service_ptr->AddMonitor(
-        kThreshold, std::move(monitor_ptr),
+    service_remote->AddMonitor(
+        kThreshold, monitor_receiver.BindNewPipeAndPassRemote(),
         base::BindLambdaForTesting([&](blink::mojom::IdleStatePtr state) {
           EXPECT_EQ(blink::mojom::UserIdleState::kActive, state->user);
           loop.Quit();
@@ -175,18 +172,15 @@
 }
 
 TEST_F(IdleManagerTest, UnlockingScreen) {
-  blink::mojom::IdleManagerPtr service_ptr;
+  mojo::Remote<blink::mojom::IdleManager> service_remote;
 
   auto impl = std::make_unique<IdleManager>();
   auto* mock = new NiceMock<MockIdleTimeProvider>();
   impl->SetIdleTimeProviderForTest(base::WrapUnique(mock));
-  impl->CreateService(mojo::MakeRequest(&service_ptr));
+  impl->CreateService(service_remote.BindNewPipeAndPassReceiver());
 
-  blink::mojom::IdleMonitorPtr monitor_ptr;
-  auto monitor_request = mojo::MakeRequest(&monitor_ptr);
   MockIdleMonitor monitor;
-  mojo::Binding<blink::mojom::IdleMonitor> monitor_binding(
-      &monitor, std::move(monitor_request));
+  mojo::Receiver<blink::mojom::IdleMonitor> monitor_receiver(&monitor);
 
   {
     base::RunLoop loop;
@@ -195,8 +189,8 @@
     EXPECT_CALL(*mock, CheckIdleStateIsLocked())
         .WillRepeatedly(testing::Return(true));
 
-    service_ptr->AddMonitor(
-        kThreshold, std::move(monitor_ptr),
+    service_remote->AddMonitor(
+        kThreshold, monitor_receiver.BindNewPipeAndPassRemote(),
         base::BindLambdaForTesting([&](blink::mojom::IdleStatePtr state) {
           EXPECT_EQ(blink::mojom::ScreenIdleState::kLocked, state->screen);
           loop.Quit();
@@ -224,18 +218,15 @@
 }
 
 TEST_F(IdleManagerTest, LockingScreen) {
-  blink::mojom::IdleManagerPtr service_ptr;
+  mojo::Remote<blink::mojom::IdleManager> service_remote;
 
   auto impl = std::make_unique<IdleManager>();
   auto* mock = new NiceMock<MockIdleTimeProvider>();
   impl->SetIdleTimeProviderForTest(base::WrapUnique(mock));
-  impl->CreateService(mojo::MakeRequest(&service_ptr));
+  impl->CreateService(service_remote.BindNewPipeAndPassReceiver());
 
-  blink::mojom::IdleMonitorPtr monitor_ptr;
-  auto monitor_request = mojo::MakeRequest(&monitor_ptr);
   MockIdleMonitor monitor;
-  mojo::Binding<blink::mojom::IdleMonitor> monitor_binding(
-      &monitor, std::move(monitor_request));
+  mojo::Receiver<blink::mojom::IdleMonitor> monitor_receiver(&monitor);
 
   {
     base::RunLoop loop;
@@ -244,8 +235,8 @@
     EXPECT_CALL(*mock, CheckIdleStateIsLocked())
         .WillRepeatedly(testing::Return(false));
 
-    service_ptr->AddMonitor(
-        kThreshold, std::move(monitor_ptr),
+    service_remote->AddMonitor(
+        kThreshold, monitor_receiver.BindNewPipeAndPassRemote(),
         base::BindLambdaForTesting([&](blink::mojom::IdleStatePtr state) {
           EXPECT_EQ(blink::mojom::ScreenIdleState::kUnlocked, state->screen);
           loop.Quit();
@@ -273,18 +264,15 @@
 }
 
 TEST_F(IdleManagerTest, LockingScreenThenIdle) {
-  blink::mojom::IdleManagerPtr service_ptr;
+  mojo::Remote<blink::mojom::IdleManager> service_remote;
 
   auto impl = std::make_unique<IdleManager>();
   auto* mock = new NiceMock<MockIdleTimeProvider>();
   impl->SetIdleTimeProviderForTest(base::WrapUnique(mock));
-  impl->CreateService(mojo::MakeRequest(&service_ptr));
+  impl->CreateService(service_remote.BindNewPipeAndPassReceiver());
 
-  blink::mojom::IdleMonitorPtr monitor_ptr;
-  auto monitor_request = mojo::MakeRequest(&monitor_ptr);
   MockIdleMonitor monitor;
-  mojo::Binding<blink::mojom::IdleMonitor> monitor_binding(
-      &monitor, std::move(monitor_request));
+  mojo::Receiver<blink::mojom::IdleMonitor> monitor_receiver(&monitor);
 
   {
     base::RunLoop loop;
@@ -293,8 +281,8 @@
     EXPECT_CALL(*mock, CheckIdleStateIsLocked())
         .WillRepeatedly(testing::Return(false));
 
-    service_ptr->AddMonitor(
-        kThreshold, std::move(monitor_ptr),
+    service_remote->AddMonitor(
+        kThreshold, monitor_receiver.BindNewPipeAndPassRemote(),
         base::BindLambdaForTesting([&](blink::mojom::IdleStatePtr state) {
           EXPECT_EQ(blink::mojom::UserIdleState::kActive, state->user);
           EXPECT_EQ(blink::mojom::ScreenIdleState::kUnlocked, state->screen);
@@ -345,18 +333,15 @@
 }
 
 TEST_F(IdleManagerTest, LockingScreenAfterIdle) {
-  blink::mojom::IdleManagerPtr service_ptr;
+  mojo::Remote<blink::mojom::IdleManager> service_remote;
 
   auto impl = std::make_unique<IdleManager>();
   auto* mock = new NiceMock<MockIdleTimeProvider>();
   impl->SetIdleTimeProviderForTest(base::WrapUnique(mock));
-  impl->CreateService(mojo::MakeRequest(&service_ptr));
+  impl->CreateService(service_remote.BindNewPipeAndPassReceiver());
 
-  blink::mojom::IdleMonitorPtr monitor_ptr;
-  auto monitor_request = mojo::MakeRequest(&monitor_ptr);
   MockIdleMonitor monitor;
-  mojo::Binding<blink::mojom::IdleMonitor> monitor_binding(
-      &monitor, std::move(monitor_request));
+  mojo::Receiver<blink::mojom::IdleMonitor> monitor_receiver(&monitor);
 
   {
     base::RunLoop loop;
@@ -367,8 +352,8 @@
     EXPECT_CALL(*mock, CheckIdleStateIsLocked())
         .WillRepeatedly(testing::Return(false));
 
-    service_ptr->AddMonitor(
-        kThreshold, std::move(monitor_ptr),
+    service_remote->AddMonitor(
+        kThreshold, monitor_receiver.BindNewPipeAndPassRemote(),
         base::BindLambdaForTesting([&](blink::mojom::IdleStatePtr state) {
           EXPECT_EQ(blink::mojom::UserIdleState::kActive, state->user);
           EXPECT_EQ(blink::mojom::ScreenIdleState::kUnlocked, state->screen);
@@ -427,21 +412,17 @@
   auto* mock = new NiceMock<MockIdleTimeProvider>();
   impl->SetIdleTimeProviderForTest(base::WrapUnique(mock));
 
-  blink::mojom::IdleManagerPtr service_ptr;
-  impl->CreateService(mojo::MakeRequest(&service_ptr));
+  mojo::Remote<blink::mojom::IdleManager> service_remote;
+  impl->CreateService(service_remote.BindNewPipeAndPassReceiver());
 
-  blink::mojom::IdleMonitorPtr monitor_ptr;
-  blink::mojom::IdleMonitorRequest monitor_request =
-      mojo::MakeRequest(&monitor_ptr);
-  MockIdleMonitor monitor_impl;
-  mojo::Binding<blink::mojom::IdleMonitor> monitor_binding(
-      &monitor_impl, std::move(monitor_request));
+  MockIdleMonitor monitor;
+  mojo::Receiver<blink::mojom::IdleMonitor> monitor_receiver(&monitor);
 
   {
     base::RunLoop loop;
 
-    service_ptr->AddMonitor(
-        kThreshold, std::move(monitor_ptr),
+    service_remote->AddMonitor(
+        kThreshold, monitor_receiver.BindNewPipeAndPassRemote(),
         base::BindLambdaForTesting(
             [&](blink::mojom::IdleStatePtr state) { loop.Quit(); }));
 
@@ -454,7 +435,7 @@
     base::RunLoop loop;
 
     // Simulates the renderer disconnecting.
-    monitor_binding.Close();
+    monitor_receiver.reset();
 
     // Wait for the IdleManager to observe the pipe close.
     loop.RunUntilIdle();
@@ -467,12 +448,11 @@
   auto impl = std::make_unique<IdleManager>();
   auto* mock = new NiceMock<MockIdleTimeProvider>();
   impl->SetIdleTimeProviderForTest(base::WrapUnique(mock));
-  blink::mojom::IdleManagerPtr service_ptr;
-  impl->CreateService(mojo::MakeRequest(&service_ptr));
+  mojo::Remote<blink::mojom::IdleManager> service_remote;
+  impl->CreateService(service_remote.BindNewPipeAndPassReceiver());
 
-  blink::mojom::IdleMonitorPtr monitor_ptr;
-  blink::mojom::IdleMonitorRequest monitor_request =
-      mojo::MakeRequest(&monitor_ptr);
+  MockIdleMonitor monitor;
+  mojo::Receiver<blink::mojom::IdleMonitor> monitor_receiver(&monitor);
 
   base::RunLoop loop;
 
@@ -482,8 +462,9 @@
   EXPECT_CALL(*mock, CheckIdleStateIsLocked())
       .WillRepeatedly(testing::Return(false));
 
-  service_ptr->AddMonitor(
-      base::TimeDelta::FromSeconds(90), std::move(monitor_ptr),
+  service_remote->AddMonitor(
+      base::TimeDelta::FromSeconds(90),
+      monitor_receiver.BindNewPipeAndPassRemote(),
       base::BindLambdaForTesting([&](blink::mojom::IdleStatePtr state) {
         EXPECT_EQ(blink::mojom::UserIdleState::kIdle, state->user);
         loop.Quit();
@@ -497,19 +478,19 @@
   auto impl = std::make_unique<IdleManager>();
   auto* mock = new NiceMock<MockIdleTimeProvider>();
   impl->SetIdleTimeProviderForTest(base::WrapUnique(mock));
-  blink::mojom::IdleManagerPtr service_ptr;
-  impl->CreateService(mojo::MakeRequest(&service_ptr));
+  mojo::Remote<blink::mojom::IdleManager> service_remote;
+  impl->CreateService(service_remote.BindNewPipeAndPassReceiver());
 
-  blink::mojom::IdleMonitorPtr monitor_ptr;
-  blink::mojom::IdleMonitorRequest monitor_request =
-      mojo::MakeRequest(&monitor_ptr);
+  MockIdleMonitor monitor;
+  mojo::Receiver<blink::mojom::IdleMonitor> monitor_receiver(&monitor);
 
   // Should not start initial state of the system.
   EXPECT_CALL(*mock, CalculateIdleTime()).Times(0);
   EXPECT_CALL(*mock, CheckIdleStateIsLocked()).Times(0);
 
-  service_ptr->AddMonitor(base::TimeDelta::FromSeconds(50),
-                          std::move(monitor_ptr), base::NullCallback());
+  service_remote->AddMonitor(base::TimeDelta::FromSeconds(50),
+                             monitor_receiver.BindNewPipeAndPassRemote(),
+                             base::NullCallback());
   EXPECT_EQ("Minimum threshold is 60 seconds.",
             bad_message_observer.WaitForBadMessage());
 }
diff --git a/content/browser/idle/idle_monitor.cc b/content/browser/idle/idle_monitor.cc
index ea332b9..d40db28 100644
--- a/content/browser/idle/idle_monitor.cc
+++ b/content/browser/idle/idle_monitor.cc
@@ -15,7 +15,7 @@
 
 namespace content {
 
-IdleMonitor::IdleMonitor(blink::mojom::IdleMonitorPtr monitor,
+IdleMonitor::IdleMonitor(mojo::PendingRemote<blink::mojom::IdleMonitor> monitor,
                          blink::mojom::IdleStatePtr last_state,
                          base::TimeDelta threshold)
     : client_(std::move(monitor)),
diff --git a/content/browser/idle/idle_monitor.h b/content/browser/idle/idle_monitor.h
index 08f53ff..2f85e1d 100644
--- a/content/browser/idle/idle_monitor.h
+++ b/content/browser/idle/idle_monitor.h
@@ -17,6 +17,7 @@
 #include "content/common/content_export.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "mojo/public/cpp/bindings/connection_error_callback.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "third_party/blink/public/mojom/idle/idle_manager.mojom.h"
 #include "ui/base/idle/idle.h"
 #include "url/origin.h"
@@ -25,7 +26,7 @@
 
 class CONTENT_EXPORT IdleMonitor : public base::LinkNode<IdleMonitor> {
  public:
-  IdleMonitor(blink::mojom::IdleMonitorPtr monitor,
+  IdleMonitor(mojo::PendingRemote<blink::mojom::IdleMonitor> monitor,
               blink::mojom::IdleStatePtr last_state,
               base::TimeDelta threshold);
   ~IdleMonitor();
diff --git a/content/browser/isolated_origin_browsertest.cc b/content/browser/isolated_origin_browsertest.cc
index eb5c5f4c..9402ec3 100644
--- a/content/browser/isolated_origin_browsertest.cc
+++ b/content/browser/isolated_origin_browsertest.cc
@@ -31,7 +31,6 @@
 #include "content/public/test/test_utils.h"
 #include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test_utils_internal.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "services/network/public/cpp/features.h"
@@ -2453,7 +2452,7 @@
  public:
   BroadcastChannelProviderInterceptor(
       RenderProcessHostImpl* rph,
-      blink::mojom::BroadcastChannelProviderRequest request,
+      mojo::PendingReceiver<blink::mojom::BroadcastChannelProvider> receiver,
       const url::Origin& origin_to_inject)
       : origin_to_inject_(origin_to_inject) {
     StoragePartitionImpl* storage_partition =
@@ -2462,13 +2461,13 @@
     // Bind the real BroadcastChannelProvider implementation.
     mojo::BindingId binding_id =
         storage_partition->GetBroadcastChannelProvider()->Connect(
-            rph->GetID(), std::move(request));
+            rph->GetID(), std::move(receiver));
 
     // Now replace it with this object and keep a pointer to the real
     // implementation.
     original_broadcast_channel_provider_ =
         storage_partition->GetBroadcastChannelProvider()
-            ->bindings_for_testing()
+            ->receivers_for_testing()
             .SwapImplForTesting(binding_id, this);
 
     // Register the |this| as a RenderProcessHostObserver, so it can be
@@ -2496,9 +2495,10 @@
   void ConnectToChannel(
       const url::Origin& origin,
       const std::string& name,
-      blink::mojom::BroadcastChannelClientAssociatedPtrInfo client,
-      blink::mojom::BroadcastChannelClientAssociatedRequest connection)
-      override {
+      mojo::PendingAssociatedRemote<blink::mojom::BroadcastChannelClient>
+          client,
+      mojo::PendingAssociatedReceiver<blink::mojom::BroadcastChannelClient>
+          connection) override {
     GetForwardingInterface()->ConnectToChannel(
         origin_to_inject_, name, std::move(client), std::move(connection));
   }
@@ -2516,10 +2516,10 @@
 void CreateTestBroadcastChannelProvider(
     const url::Origin& origin_to_inject,
     RenderProcessHostImpl* rph,
-    blink::mojom::BroadcastChannelProviderRequest request) {
+    mojo::PendingReceiver<blink::mojom::BroadcastChannelProvider> receiver) {
   // This object will register as RenderProcessHostObserver, so it will
   // clean itself automatically on process exit.
-  new BroadcastChannelProviderInterceptor(rph, std::move(request),
+  new BroadcastChannelProviderInterceptor(rph, std::move(receiver),
                                           origin_to_inject);
 }
 
@@ -2528,7 +2528,7 @@
 IN_PROC_BROWSER_TEST_F(IsolatedOriginTest, BroadcastChannelOriginEnforcement) {
   auto mismatched_origin = url::Origin::Create(GURL("http://abc.foo.com"));
   EXPECT_FALSE(IsIsolatedOrigin(mismatched_origin));
-  RenderProcessHostImpl::SetBroadcastChannelProviderRequestHandlerForTesting(
+  RenderProcessHostImpl::SetBroadcastChannelProviderReceiverHandlerForTesting(
       base::BindRepeating(&CreateTestBroadcastChannelProvider,
                           mismatched_origin));
 
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index c91eb3b8..191754d84 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -188,10 +188,8 @@
 #include "media/base/media_switches.h"
 #include "media/media_buildflags.h"
 #include "media/webrtc/webrtc_switches.h"
-#include "mojo/public/cpp/bindings/associated_interface_ptr.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
 #include "mojo/public/cpp/system/platform_handle.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "ppapi/buildflags/buildflags.h"
@@ -1115,10 +1113,10 @@
   return *instance;
 }
 
-RenderProcessHostImpl::BroadcastChannelProviderRequestHandler&
-GetBroadcastChannelProviderRequestHandler() {
+RenderProcessHostImpl::BroadcastChannelProviderReceiverHandler&
+GetBroadcastChannelProviderReceiverHandler() {
   static base::NoDestructor<
-      RenderProcessHostImpl::BroadcastChannelProviderRequestHandler>
+      RenderProcessHostImpl::BroadcastChannelProviderReceiverHandler>
       instance;
   return *instance;
 }
@@ -1591,9 +1589,10 @@
   GetStoragePartitionServiceRequestHandler() = handler;
 }
 
-void RenderProcessHostImpl::SetBroadcastChannelProviderRequestHandlerForTesting(
-    BroadcastChannelProviderRequestHandler handler) {
-  GetBroadcastChannelProviderRequestHandler() = handler;
+void RenderProcessHostImpl::
+    SetBroadcastChannelProviderReceiverHandlerForTesting(
+        BroadcastChannelProviderReceiverHandler handler) {
+  GetBroadcastChannelProviderReceiverHandler() = handler;
 }
 
 RenderProcessHostImpl::~RenderProcessHostImpl() {
@@ -2275,8 +2274,11 @@
 
 void RenderProcessHostImpl::CreateBroadcastChannelProvider(
     blink::mojom::BroadcastChannelProviderRequest request) {
-  if (!GetBroadcastChannelProviderRequestHandler().is_null()) {
-    GetBroadcastChannelProviderRequestHandler().Run(this, std::move(request));
+  // |request| is converted into
+  // mojo::PendingReceiver<blink::mojom::BroadcastChannelProvider> while
+  // RenderProcessHostImpl uses service_manager::BinderRegistry.
+  if (!GetBroadcastChannelProviderReceiverHandler().is_null()) {
+    GetBroadcastChannelProviderReceiverHandler().Run(this, std::move(request));
     return;
   }
 
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index f3b83d9..9821099 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -53,7 +53,6 @@
 #include "mojo/public/cpp/bindings/associated_binding.h"
 #include "mojo/public/cpp/bindings/associated_binding_set.h"
 #include "mojo/public/cpp/bindings/generic_pending_receiver.h"
-#include "mojo/public/cpp/bindings/interface_ptr.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "mojo/public/cpp/system/invitation.h"
 #include "net/base/network_isolation_key.h"
@@ -389,13 +388,13 @@
       StoragePartitionServiceRequestHandler handler);
 
   // Allows external code to supply a callback which handles a
-  // BroadcastChannelProviderRequest. Used for supplying test versions of the
-  // service.
-  using BroadcastChannelProviderRequestHandler = base::RepeatingCallback<void(
+  // mojo::PendingReceiver<blink::mojom::BroadcastChannelProvider>. Used for
+  // supplying test versions of the service.
+  using BroadcastChannelProviderReceiverHandler = base::RepeatingCallback<void(
       RenderProcessHostImpl* rph,
-      blink::mojom::BroadcastChannelProviderRequest request)>;
-  static void SetBroadcastChannelProviderRequestHandlerForTesting(
-      BroadcastChannelProviderRequestHandler handler);
+      mojo::PendingReceiver<blink::mojom::BroadcastChannelProvider> receiver)>;
+  static void SetBroadcastChannelProviderReceiverHandlerForTesting(
+      BroadcastChannelProviderReceiverHandler handler);
 
   RenderFrameMessageFilter* render_frame_message_filter_for_testing() const {
     return render_frame_message_filter_.get();
diff --git a/content/browser/service_manager/common_browser_interfaces.cc b/content/browser/service_manager/common_browser_interfaces.cc
index 9fe6be0d..10fe96c5 100644
--- a/content/browser/service_manager/common_browser_interfaces.cc
+++ b/content/browser/service_manager/common_browser_interfaces.cc
@@ -4,21 +4,16 @@
 
 #include "content/browser/service_manager/common_browser_interfaces.h"
 
-#include <map>
 #include <memory>
 #include <utility>
 
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/command_line.h"
-#include "base/memory/ref_counted.h"
 #include "base/task/post_task.h"
 #include "base/task_runner.h"
 #include "build/build_config.h"
 #include "components/discardable_memory/service/discardable_shared_memory_manager.h"
-#include "components/viz/host/gpu_client.h"
-#include "content/browser/gpu/browser_gpu_client_delegate.h"
-#include "content/common/child_process_host_impl.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/connection_filter.h"
@@ -26,7 +21,6 @@
 #include "content/public/common/service_names.mojom.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
-#include "services/viz/public/mojom/gpu.mojom.h"
 
 #if defined(OS_WIN)
 #include "content/browser/renderer_host/dwrite_font_proxy_impl_win.h"
@@ -54,8 +48,6 @@
         base::BindRepeating(&SandboxSupportMacImpl::BindRequest,
                             base::Owned(new SandboxSupportMacImpl)));
 #endif
-    registry_.AddInterface(base::BindRepeating(
-        &ConnectionFilterImpl::BindGpuRequest, base::Unretained(this)));
 
     auto* discardable_shared_memory_manager =
         discardable_memory::DiscardableSharedMemoryManager::Get();
@@ -79,50 +71,12 @@
                        const std::string& interface_name,
                        mojo::ScopedMessagePipeHandle* interface_pipe,
                        service_manager::Connector* connector) override {
-    // Ignore viz::mojom::Gpu interface request from Renderer process.
-    // The request will be handled in RenderProcessHostImpl.
-    if (source_info.identity.name() == mojom::kRendererServiceName &&
-        interface_name == viz::mojom::Gpu::Name_)
-      return;
-
     registry_.TryBindInterface(interface_name, interface_pipe, source_info);
   }
 
-  void BindGpuRequest(viz::mojom::GpuRequest request,
-                      const service_manager::BindSourceInfo& source_info) {
-    DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
-    // Only allow one connection per service to avoid possible race condition.
-    // So Reset the current connection if there is one.
-    gpu_clients_.erase(source_info.identity);
-
-    const int gpu_client_id =
-        ChildProcessHostImpl::GenerateChildProcessUniqueId();
-    const uint64_t gpu_client_tracing_id =
-        ChildProcessHostImpl::ChildProcessUniqueIdToTracingProcessId(
-            gpu_client_id);
-    auto gpu_client = std::make_unique<viz::GpuClient>(
-        std::make_unique<BrowserGpuClientDelegate>(), gpu_client_id,
-        gpu_client_tracing_id,
-        base::CreateSingleThreadTaskRunner({BrowserThread::IO}));
-    gpu_client->SetConnectionErrorHandler(
-        base::BindOnce(&ConnectionFilterImpl::OnGpuConnectionClosed,
-                       base::Unretained(this), source_info.identity));
-    gpu_client->Add(std::move(request));
-    gpu_clients_.emplace(source_info.identity, std::move(gpu_client));
-  }
-
-  void OnGpuConnectionClosed(const service_manager::Identity& service_identity,
-                             viz::GpuClient* client) {
-    DCHECK_CURRENTLY_ON(BrowserThread::IO);
-    gpu_clients_.erase(service_identity);
-  }
-
   service_manager::BinderRegistryWithArgs<
       const service_manager::BindSourceInfo&>
       registry_;
-  std::map<service_manager::Identity, std::unique_ptr<viz::GpuClient>>
-      gpu_clients_;
 
   DISALLOW_COPY_AND_ASSIGN(ConnectionFilterImpl);
 };
diff --git a/content/child/blink_platform_impl.cc b/content/child/blink_platform_impl.cc
index a9f8282e..18204bb4 100644
--- a/content/child/blink_platform_impl.cc
+++ b/content/child/blink_platform_impl.cc
@@ -427,19 +427,6 @@
      false},
     {"generatePasswordHover", IDR_PASSWORD_GENERATION_ICON_HOVER,
      ui::SCALE_FACTOR_100P, false},
-    // Not limited to Android since it's used for mobile layouts in inspector.
-    {"android.css", IDR_UASTYLE_THEME_CHROMIUM_ANDROID_CSS,
-     ui::SCALE_FACTOR_NONE, true},
-    // Not limited to Android since it's used for mobile layouts in inspector.
-    {"fullscreenAndroid.css", IDR_UASTYLE_FULLSCREEN_ANDROID_CSS,
-     ui::SCALE_FACTOR_NONE, true},
-    // Not limited to Linux since it's used for mobile layouts in inspector.
-    {"linux.css", IDR_UASTYLE_THEME_CHROMIUM_LINUX_CSS, ui::SCALE_FACTOR_NONE,
-     true},
-#if defined(ENABLE_TOUCHLESS_UASTYLE_THEME)
-    {"touchless.css", IDR_UASTYLE_THEME_TOUCHLESS_CSS, ui::SCALE_FACTOR_NONE,
-     true},
-#endif
     {"DocumentXMLTreeViewer.css", IDR_DOCUMENTXMLTREEVIEWER_CSS,
      ui::SCALE_FACTOR_NONE, true},
     {"DocumentXMLTreeViewer.js", IDR_DOCUMENTXMLTREEVIEWER_JS,
diff --git a/content/public/test/dump_accessibility_test_helper.cc b/content/public/test/dump_accessibility_test_helper.cc
index 20154c9..0f77504 100644
--- a/content/public/test/dump_accessibility_test_helper.cc
+++ b/content/public/test/dump_accessibility_test_helper.cc
@@ -26,8 +26,7 @@
     AccessibilityTreeFormatter* formatter)
     : formatter_(formatter) {}
 
-base::Optional<base::FilePath>
-DumpAccessibilityTestHelper::GetExpectationFilePath(
+base::FilePath DumpAccessibilityTestHelper::GetExpectationFilePath(
     const base::FilePath& test_file_path) {
   base::ScopedAllowBlockingForTesting allow_blocking;
   base::FilePath expected_file_path;
@@ -56,7 +55,7 @@
             << " (it can be empty) and then run this test "
             << "with the switch: --"
             << switches::kGenerateAccessibilityTestExpectations;
-  return base::nullopt;
+  return base::FilePath();
 }
 
 base::Optional<std::vector<std::string>>
diff --git a/content/public/test/dump_accessibility_test_helper.h b/content/public/test/dump_accessibility_test_helper.h
index 4db5710c..12e6310 100644
--- a/content/public/test/dump_accessibility_test_helper.h
+++ b/content/public/test/dump_accessibility_test_helper.h
@@ -18,17 +18,17 @@
 // A helper class for writing accessibility tree dump tests.
 class DumpAccessibilityTestHelper {
  public:
-  DumpAccessibilityTestHelper(AccessibilityTreeFormatter* formatter);
+  explicit DumpAccessibilityTestHelper(AccessibilityTreeFormatter* formatter);
   ~DumpAccessibilityTestHelper() = default;
 
   // Returns a path to an expectation file for the current platform. If no
   // suitable expectation file can be found, logs an error message and returns
-  // nullopt.
-  base::Optional<base::FilePath> GetExpectationFilePath(
-      const base::FilePath& test_file_path);
+  // an empty path.
+  base::FilePath GetExpectationFilePath(const base::FilePath& test_file_path);
 
-  // Loads the given expectation file. Returns nullopt if the file contains a
-  // skip marker.
+  // Loads the given expectation file and returns the contents. An expectation
+  // file may be empty, in which case an empty vector is returned.
+  // Returns nullopt if the file contains a skip marker.
   static base::Optional<std::vector<std::string>> LoadExpectationFile(
       const base::FilePath& expected_file);
 
diff --git a/content/renderer/media/android/stream_texture_factory.cc b/content/renderer/media/android/stream_texture_factory.cc
index fb59771b..7743193 100644
--- a/content/renderer/media/android/stream_texture_factory.cc
+++ b/content/renderer/media/android/stream_texture_factory.cc
@@ -77,12 +77,9 @@
     const gfx::Size& size,
     gpu::Mailbox* mailbox,
     gpu::SyncToken* unverified_sync_token) {
-  // TODO(vikassoni): Remove CHECK after debugging.
-  CHECK(host_);
   *mailbox = host_->CreateSharedImage(size);
-  if (!mailbox)
+  if (mailbox->IsZero())
     return;
-  CHECK(host_);
   *unverified_sync_token = host_->GenUnverifiedSyncToken();
 }
 
diff --git a/content/renderer/media/android/stream_texture_factory.h b/content/renderer/media/android/stream_texture_factory.h
index e65bf4e11..88e6e62 100644
--- a/content/renderer/media/android/stream_texture_factory.h
+++ b/content/renderer/media/android/stream_texture_factory.h
@@ -31,7 +31,7 @@
 
 // The proxy class for the gpu thread to notify the compositor thread
 // when a new video frame is available.
-class StreamTextureProxy : public StreamTextureHost::Listener {
+class CONTENT_EXPORT StreamTextureProxy : public StreamTextureHost::Listener {
  public:
   ~StreamTextureProxy() override;
 
@@ -68,6 +68,7 @@
   };
  private:
   friend class StreamTextureFactory;
+  friend class StreamTextureProxyTest;
   explicit StreamTextureProxy(std::unique_ptr<StreamTextureHost> host);
 
   void BindOnThread();
diff --git a/content/renderer/media/android/stream_texture_proxy_unittest.cc b/content/renderer/media/android/stream_texture_proxy_unittest.cc
new file mode 100644
index 0000000..b6cb3b4
--- /dev/null
+++ b/content/renderer/media/android/stream_texture_proxy_unittest.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 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 "base/memory/ptr_util.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "content/renderer/media/android/stream_texture_factory.h"
+#include "content/renderer/stream_texture_host_android.h"
+#include "gpu/command_buffer/common/mailbox.h"
+#include "gpu/command_buffer/common/sync_token.h"
+#include "gpu/ipc/client/gpu_channel_host.h"
+#include "gpu/ipc/common/gpu_messages.h"
+#include "gpu/ipc/common/surface_handle.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+// GpuChannelHost is expected to be created on the IO thread, and posts tasks to
+// setup its IPC listener, so it must be created after the thread task runner
+// handle is set.
+class TestGpuChannelHost : public gpu::GpuChannelHost {
+ public:
+  TestGpuChannelHost()
+      : gpu::GpuChannelHost(
+            0 /* channel_id */,
+            gpu::GPUInfo(),
+            gpu::GpuFeatureInfo(),
+            mojo::ScopedMessagePipeHandle(
+                mojo::MessagePipeHandle(mojo::kInvalidHandleValue))) {}
+
+ protected:
+  ~TestGpuChannelHost() override {}
+};
+
+class StreamTextureProxyTest : public testing::Test {
+ public:
+  StreamTextureProxyTest()
+      : task_runner_(base::MakeRefCounted<base::TestSimpleTaskRunner>()),
+        thread_task_runner_handle_override_(
+            base::ThreadTaskRunnerHandle::OverrideForTesting(task_runner_)),
+        channel_(base::MakeRefCounted<TestGpuChannelHost>()) {}
+
+  ~StreamTextureProxyTest() override { channel_ = nullptr; }
+
+  std::unique_ptr<StreamTextureProxy> CreateProxyWithNullGpuChannelHost() {
+    // Create the StreamTextureHost with a valid |channel_|. Note that route_id
+    // does not matter here for the test we are writing.
+    auto host = std::make_unique<StreamTextureHost>(channel_, 1 /* route_id */);
+
+    // Force the StreamTextureHost's |channel_| to be null by calling
+    // OnChannelError.
+    host->OnChannelError();
+    auto proxy = base::WrapUnique(new StreamTextureProxy(std::move(host)));
+    return proxy;
+  }
+
+ protected:
+  scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
+  base::ScopedClosureRunner thread_task_runner_handle_override_;
+  scoped_refptr<TestGpuChannelHost> channel_;
+};
+
+// This test is to make sure CreateSharedImage() do not crash even if
+// StreamTextureHost's |channel_| is null.
+TEST_F(StreamTextureProxyTest,
+       CreateSharedImageDoesNotCrashWithNullGpuChannelHost) {
+  auto proxy = CreateProxyWithNullGpuChannelHost();
+  gpu::Mailbox mailbox;
+  gpu::SyncToken texture_mailbox_sync_token;
+
+  // This method should not crash even if the StreamTextureHost's |channel_| is
+  // null.
+  proxy->CreateSharedImage(gfx::Size(1, 1), &mailbox,
+                           &texture_mailbox_sync_token);
+}
+
+}  // namespace content
diff --git a/content/renderer/stream_texture_host_android.cc b/content/renderer/stream_texture_host_android.cc
index d0b4ab1d..940c1096 100644
--- a/content/renderer/stream_texture_host_android.cc
+++ b/content/renderer/stream_texture_host_android.cc
@@ -85,8 +85,10 @@
 }
 
 gpu::SyncToken StreamTextureHost::GenUnverifiedSyncToken() {
-  // TODO(vikassoni): Remove CHECK after debugging.
-  CHECK(channel_);
+  // |channel_| can be set to null via OnChannelError() which means
+  // StreamTextureHost could still be alive when |channel_| is gone.
+  if (!channel_)
+    return gpu::SyncToken();
 
   return gpu::SyncToken(gpu::CommandBufferNamespace::GPU_IO,
                         gpu::CommandBufferIdFromChannelAndRoute(
diff --git a/content/renderer/stream_texture_host_android.h b/content/renderer/stream_texture_host_android.h
index 62f8f7b0..3ead2228d 100644
--- a/content/renderer/stream_texture_host_android.h
+++ b/content/renderer/stream_texture_host_android.h
@@ -9,6 +9,7 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "content/common/content_export.h"
 #include "ipc/ipc_listener.h"
 #include "ipc/ipc_message.h"
 
@@ -30,7 +31,7 @@
 
 // Class for handling all the IPC messages between the GPU process and
 // StreamTextureProxy.
-class StreamTextureHost : public IPC::Listener {
+class CONTENT_EXPORT StreamTextureHost : public IPC::Listener {
  public:
   explicit StreamTextureHost(scoped_refptr<gpu::GpuChannelHost> channel,
                              int32_t route_id);
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 3e7c6a4..2dd042c 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -2248,6 +2248,7 @@
       "../browser/renderer_host/render_widget_host_view_android_unittest.cc",
       "../browser/sms/sms_provider_android_unittest.cc",
       "../renderer/java/gin_java_bridge_value_converter_unittest.cc",
+      "../renderer/media/android/stream_texture_proxy_unittest.cc",
       "../renderer/media/android/stream_texture_wrapper_impl_unittest.cc",
     ]
     sources -= [ "../browser/tracing/tracing_ui_unittest.cc" ]
diff --git a/content/test/data/accessibility/html/ignored-selection-between-text-expected-android.txt b/content/test/data/accessibility/html/ignored-selection-between-text-expected-android.txt
new file mode 100644
index 0000000..c48d6622
--- /dev/null
+++ b/content/test/data/accessibility/html/ignored-selection-between-text-expected-android.txt
@@ -0,0 +1,5 @@
+android.webkit.WebView focusable focused scrollable
+++android.view.View name='before selection'
+++android.view.View name='this text is not ignored'
+++android.view.View name='after selection'
+++android.view.View name='Done'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/ignored-selection-between-text-expected-auralinux.txt b/content/test/data/accessibility/html/ignored-selection-between-text-expected-auralinux.txt
new file mode 100644
index 0000000..58f9e0d
--- /dev/null
+++ b/content/test/data/accessibility/html/ignored-selection-between-text-expected-auralinux.txt
@@ -0,0 +1,8 @@
+[document web]
+++[section]
+++++[text] name='before selection'
+++[section]
+++++[text] name='this text is not ignored'
+++[section]
+++++[text] name='after selection'
+++[text] name='Done'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/ignored-selection-between-text-expected-blink.txt b/content/test/data/accessibility/html/ignored-selection-between-text-expected-blink.txt
new file mode 100644
index 0000000..a886a363
--- /dev/null
+++ b/content/test/data/accessibility/html/ignored-selection-between-text-expected-blink.txt
@@ -0,0 +1,16 @@
+rootWebArea
+++genericContainer ignored
+++++genericContainer ignored
+++++++genericContainer
+++++++++staticText name='before selection' TreeData.textSelStartOffset=16
+++++++++++inlineTextBox name='before selection'
+++++++genericContainer ignored invisible
+++++++genericContainer
+++++++++staticText name='this text is not ignored'
+++++++++++inlineTextBox name='this text is not ignored'
+++++++genericContainer ignored invisible
+++++++genericContainer
+++++++++staticText name='after selection' TreeData.textSelEndOffset=0
+++++++++++inlineTextBox name='after selection'
+++++staticText name='Done'
+++++++inlineTextBox name='Done'
diff --git a/content/test/data/accessibility/html/ignored-selection-between-text-expected-mac.txt b/content/test/data/accessibility/html/ignored-selection-between-text-expected-mac.txt
new file mode 100644
index 0000000..b01f366
--- /dev/null
+++ b/content/test/data/accessibility/html/ignored-selection-between-text-expected-mac.txt
@@ -0,0 +1,8 @@
+AXWebArea
+++AXGroup
+++++AXStaticText AXValue='before selection'
+++AXGroup
+++++AXStaticText AXValue='this text is not ignored'
+++AXGroup
+++++AXStaticText AXValue='after selection'
+++AXStaticText AXValue='Done'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/ignored-selection-between-text-expected-uia-win.txt b/content/test/data/accessibility/html/ignored-selection-between-text-expected-uia-win.txt
new file mode 100644
index 0000000..609bfb9
--- /dev/null
+++ b/content/test/data/accessibility/html/ignored-selection-between-text-expected-uia-win.txt
@@ -0,0 +1,8 @@
+document
+++group
+++++description Name='before selection'
+++group
+++++description Name='this text is not ignored'
+++group
+++++description Name='after selection'
+++description Name='Done'
diff --git a/content/test/data/accessibility/html/ignored-selection-between-text-expected-win.txt b/content/test/data/accessibility/html/ignored-selection-between-text-expected-win.txt
new file mode 100644
index 0000000..1d2a902
--- /dev/null
+++ b/content/test/data/accessibility/html/ignored-selection-between-text-expected-win.txt
@@ -0,0 +1,8 @@
+ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE caret_offset=2 n_selections=1 selection_start=0 selection_end=2
+++IA2_ROLE_SECTION n_selections=0
+++++ROLE_SYSTEM_STATICTEXT name='before selection' n_selections=0
+++IA2_ROLE_SECTION n_selections=1 selection_start=0 selection_end=24
+++++ROLE_SYSTEM_STATICTEXT name='this text is not ignored' n_selections=1 selection_start=0 selection_end=24
+++IA2_ROLE_SECTION caret_offset=0 n_selections=0
+++++ROLE_SYSTEM_STATICTEXT name='after selection' caret_offset=0 n_selections=0
+++ROLE_SYSTEM_STATICTEXT name='Done' n_selections=0
diff --git a/content/test/data/accessibility/html/ignored-selection-between-text.html b/content/test/data/accessibility/html/ignored-selection-between-text.html
new file mode 100644
index 0000000..83a33c1
--- /dev/null
+++ b/content/test/data/accessibility/html/ignored-selection-between-text.html
@@ -0,0 +1,37 @@
+<!--
+@WIN-ALLOW:caret_offset*
+@WIN-ALLOW:n_selections*
+@WIN-ALLOW:selection_start*
+@WIN-ALLOW:selection_end*
+@BLINK-ALLOW:editable*
+@BLINK-ALLOW:richlyEditable*
+@BLINK-ALLOW:*textSel*
+@BLINK-ALLOW:id*
+@AURALINUX-ALLOW:editable
+@AURALINUX-ALLOW:multi-line
+@WAIT-FOR:Done
+-->
+
+<body>
+  <div>
+    <div> before selection</div>
+    <div id='hidden-before' aria-hidden="true">
+      Some ignored text
+    </div>
+    <div>this text is not ignored</div>
+    <div id='hidden-after' aria-hidden="true">this text is ignored</div>
+    <div> after selection</div>
+  </div>
+</body>
+
+<script>
+  var selection = window.getSelection();
+  var selectionRange = document.createRange();
+  var hidden_before = document.getElementById('hidden-before')
+  var hidden_after = document.getElementById('hidden-after')
+  selectionRange.setStart(hidden_before.firstChild, 20);
+  selectionRange.setEnd(hidden_after.firstChild, 8);
+  selection.removeAllRanges();
+  selection.addRange(selectionRange);
+  document.body.appendChild(document.createTextNode("Done"));
+</script>
diff --git a/content/test/data/accessibility/html/ignored-selection-expected-android.txt b/content/test/data/accessibility/html/ignored-selection-expected-android.txt
new file mode 100644
index 0000000..30e79e4
--- /dev/null
+++ b/content/test/data/accessibility/html/ignored-selection-expected-android.txt
@@ -0,0 +1,4 @@
+android.webkit.WebView focusable focused scrollable
+++android.view.View name='this text is not ignored'
+++android.view.View name='after selection'
+++android.view.View name='Done'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/ignored-selection-expected-auralinux.txt b/content/test/data/accessibility/html/ignored-selection-expected-auralinux.txt
new file mode 100644
index 0000000..351725f
--- /dev/null
+++ b/content/test/data/accessibility/html/ignored-selection-expected-auralinux.txt
@@ -0,0 +1,5 @@
+[document web]
+++[text] name='this text is not ignored'
+++[section]
+++++[text] name='after selection'
+++[text] name='Done'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/ignored-selection-expected-blink.txt b/content/test/data/accessibility/html/ignored-selection-expected-blink.txt
new file mode 100644
index 0000000..6f76456
--- /dev/null
+++ b/content/test/data/accessibility/html/ignored-selection-expected-blink.txt
@@ -0,0 +1,11 @@
+rootWebArea
+++genericContainer ignored
+++++paragraph ignored invisible
+++++staticText name='this text is not ignored' TreeData.textSelStartOffset=0
+++++++inlineTextBox name='this text is not ignored'
+++++genericContainer ignored invisible
+++++genericContainer
+++++++staticText name='after selection' TreeData.textSelEndOffset=0
+++++++++inlineTextBox name='after selection'
+++++staticText name='Done'
+++++++inlineTextBox name='Done'
diff --git a/content/test/data/accessibility/html/ignored-selection-expected-mac.txt b/content/test/data/accessibility/html/ignored-selection-expected-mac.txt
new file mode 100644
index 0000000..18b4fcf
--- /dev/null
+++ b/content/test/data/accessibility/html/ignored-selection-expected-mac.txt
@@ -0,0 +1,5 @@
+AXWebArea
+++AXStaticText AXValue='this text is not ignored'
+++AXGroup
+++++AXStaticText AXValue='after selection'
+++AXStaticText AXValue='Done'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/ignored-selection-expected-uia-win.txt b/content/test/data/accessibility/html/ignored-selection-expected-uia-win.txt
new file mode 100644
index 0000000..3ea770ed
--- /dev/null
+++ b/content/test/data/accessibility/html/ignored-selection-expected-uia-win.txt
@@ -0,0 +1,5 @@
+document
+++description Name='this text is not ignored'
+++group
+++++description Name='after selection'
+++description Name='Done'
diff --git a/content/test/data/accessibility/html/ignored-selection-expected-win.txt b/content/test/data/accessibility/html/ignored-selection-expected-win.txt
new file mode 100644
index 0000000..64b3bfad
--- /dev/null
+++ b/content/test/data/accessibility/html/ignored-selection-expected-win.txt
@@ -0,0 +1,5 @@
+ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE caret_offset=24 n_selections=1 selection_start=0 selection_end=24
+++ROLE_SYSTEM_STATICTEXT name='this text is not ignored' n_selections=1 selection_start=0 selection_end=24
+++IA2_ROLE_SECTION caret_offset=0 n_selections=0
+++++ROLE_SYSTEM_STATICTEXT name='after selection' caret_offset=0 n_selections=0
+++ROLE_SYSTEM_STATICTEXT name='Done' n_selections=0
diff --git a/content/test/data/accessibility/html/ignored-selection-no-unignored-expected-android.txt b/content/test/data/accessibility/html/ignored-selection-no-unignored-expected-android.txt
new file mode 100644
index 0000000..4029c895
--- /dev/null
+++ b/content/test/data/accessibility/html/ignored-selection-no-unignored-expected-android.txt
@@ -0,0 +1,2 @@
+android.webkit.WebView focusable focused scrollable
+++android.view.View name='Done'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/ignored-selection-no-unignored-expected-auralinux.txt b/content/test/data/accessibility/html/ignored-selection-no-unignored-expected-auralinux.txt
new file mode 100644
index 0000000..67d89a3
--- /dev/null
+++ b/content/test/data/accessibility/html/ignored-selection-no-unignored-expected-auralinux.txt
@@ -0,0 +1,2 @@
+[document web]
+++[text] name='Done'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/ignored-selection-no-unignored-expected-blink.txt b/content/test/data/accessibility/html/ignored-selection-no-unignored-expected-blink.txt
new file mode 100644
index 0000000..02daa5eb
--- /dev/null
+++ b/content/test/data/accessibility/html/ignored-selection-no-unignored-expected-blink.txt
@@ -0,0 +1,7 @@
+rootWebArea
+++genericContainer ignored
+++++genericContainer ignored
+++++++genericContainer ignored invisible
+++++++genericContainer ignored invisible
+++++staticText name='Done' TreeData.textSelEndOffset=0
+++++++inlineTextBox name='Done'
diff --git a/content/test/data/accessibility/html/ignored-selection-no-unignored-expected-mac.txt b/content/test/data/accessibility/html/ignored-selection-no-unignored-expected-mac.txt
new file mode 100644
index 0000000..a7977fa0
--- /dev/null
+++ b/content/test/data/accessibility/html/ignored-selection-no-unignored-expected-mac.txt
@@ -0,0 +1,3 @@
+AXWebArea
+++AXStaticText AXValue='Done'
+<-- End-of-file -->
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/ignored-selection-no-unignored-expected-uia-win.txt b/content/test/data/accessibility/html/ignored-selection-no-unignored-expected-uia-win.txt
new file mode 100644
index 0000000..a322991
--- /dev/null
+++ b/content/test/data/accessibility/html/ignored-selection-no-unignored-expected-uia-win.txt
@@ -0,0 +1,2 @@
+document
+++description Name='Done'
diff --git a/content/test/data/accessibility/html/ignored-selection-no-unignored-expected-win.txt b/content/test/data/accessibility/html/ignored-selection-no-unignored-expected-win.txt
new file mode 100644
index 0000000..6d476009
--- /dev/null
+++ b/content/test/data/accessibility/html/ignored-selection-no-unignored-expected-win.txt
@@ -0,0 +1,2 @@
+ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE caret_offset=0 n_selections=0
+++ROLE_SYSTEM_STATICTEXT name='Done' caret_offset=0 n_selections=0
diff --git a/content/test/data/accessibility/html/ignored-selection-no-unignored.html b/content/test/data/accessibility/html/ignored-selection-no-unignored.html
new file mode 100644
index 0000000..34a10d40
--- /dev/null
+++ b/content/test/data/accessibility/html/ignored-selection-no-unignored.html
@@ -0,0 +1,32 @@
+<!--
+@WIN-ALLOW:caret_offset*
+@WIN-ALLOW:n_selections*
+@WIN-ALLOW:selection_start*
+@WIN-ALLOW:selection_end*
+@BLINK-ALLOW:editable*
+@BLINK-ALLOW:richlyEditable*
+@BLINK-ALLOW:*textSel*
+@BLINK-ALLOW:id*
+@AURALINUX-ALLOW:editable
+@AURALINUX-ALLOW:multi-line
+@WAIT-FOR:Done
+-->
+
+<body>
+  <div>
+    <div id='hidden-before' aria-hidden="true">Some ignored text</div>
+    <div id='hidden-after' aria-hidden="true">this text is also ignored</div>
+  </div>
+</body>
+
+<script>
+  var selection = window.getSelection();
+  var selectionRange = document.createRange();
+  var hidden_before = document.getElementById('hidden-before')
+  var hidden_after = document.getElementById('hidden-after')
+  selectionRange.setStart(hidden_before.firstChild, 10);
+  selectionRange.setEnd(hidden_after.firstChild, 8);
+  selection.removeAllRanges();
+  selection.addRange(selectionRange);
+  document.body.appendChild(document.createTextNode("Done"));
+</script>
diff --git a/content/test/data/accessibility/html/ignored-selection.html b/content/test/data/accessibility/html/ignored-selection.html
new file mode 100644
index 0000000..7c4490de
--- /dev/null
+++ b/content/test/data/accessibility/html/ignored-selection.html
@@ -0,0 +1,32 @@
+<!--
+@WIN-ALLOW:caret_offset*
+@WIN-ALLOW:n_selections*
+@WIN-ALLOW:selection_start*
+@WIN-ALLOW:selection_end*
+@BLINK-ALLOW:editable*
+@BLINK-ALLOW:richlyEditable*
+@BLINK-ALLOW:*textSel*
+@BLINK-ALLOW:id*
+@AURALINUX-ALLOW:editable
+@AURALINUX-ALLOW:multi-line
+@WAIT-FOR:Done
+-->
+
+<body>
+  <p aria-hidden="true" id='hidden-before'></p>
+  this text is not ignored
+  <div id='hidden-after' aria-hidden="true">this text is ignored</div>
+  <div> after selection</div>
+</body>
+
+<script>
+  var selection = window.getSelection();
+  var selectionRange = document.createRange();
+  var hidden_before = document.getElementById('hidden-before')
+  var hidden_after = document.getElementById('hidden-after')
+  selectionRange.setStartAfter(hidden_before);
+  selectionRange.setEnd(hidden_after.firstChild, 8);
+  selection.removeAllRanges();
+  selection.addRange(selectionRange);
+  document.body.appendChild(document.createTextNode("Done"));
+</script>
diff --git a/device/fido/fido_device.cc b/device/fido/fido_device.cc
index 1016d43..f6ab3c2 100644
--- a/device/fido/fido_device.cc
+++ b/device/fido/fido_device.cc
@@ -18,6 +18,10 @@
 FidoDevice::FidoDevice() = default;
 FidoDevice::~FidoDevice() = default;
 
+void FidoDevice::TryWink(base::OnceClosure callback) {
+  std::move(callback).Run();
+}
+
 base::string16 FidoDevice::GetDisplayName() const {
   const auto id = GetId();
   return base::string16(id.begin(), id.end());
diff --git a/device/fido/fido_device.h b/device/fido/fido_device.h
index e828410..9d61442 100644
--- a/device/fido/fido_device.h
+++ b/device/fido/fido_device.h
@@ -66,6 +66,11 @@
   // call (i.e. hairpin) |callback|.
   virtual CancelToken DeviceTransact(std::vector<uint8_t> command,
                                      DeviceCallback callback) = 0;
+  // Attempt to make the device "wink", i.e. grab the attention of the user
+  // usually by flashing a light. |callback| is run after a successful wink or
+  // if the device does not support winking, in which case it may run
+  // immediately.
+  virtual void TryWink(base::OnceClosure callback);
   // Cancel attempts to cancel an enqueued request. If the request is currently
   // active it will be aborted if possible, which is expected to cause it to
   // complete with |kCtap2ErrKeepAliveCancel|. If the request is still enqueued
diff --git a/device/fido/get_assertion_task_unittest.cc b/device/fido/get_assertion_task_unittest.cc
index 7314a1d..422eb77 100644
--- a/device/fido/get_assertion_task_unittest.cc
+++ b/device/fido/get_assertion_task_unittest.cc
@@ -74,6 +74,7 @@
 
 TEST_F(FidoGetAssertionTaskTest, TestU2fSignSuccess) {
   auto device = MockFidoDevice::MakeU2f();
+  device->ExpectWinkedAtLeastOnce();
   device->ExpectRequestAndRespondWith(
       test_data::kU2fSignCommandApdu,
       test_data::kApduEncodedNoErrorSignResponse);
@@ -166,6 +167,7 @@
                                          test_data::kClientDataJson);
 
   auto device = MockFidoDevice::MakeU2f();
+  device->ExpectWinkedAtLeastOnce();
   device->ExpectRequestAndRespondWith(
       test_data::kU2fFakeRegisterCommand,
       test_data::kApduEncodedNoErrorSignResponse);
@@ -236,11 +238,13 @@
                                       error);
   // After falling back to U2F the request will use the alternative app_param,
   // which will be rejected.
+  device->ExpectWinkedAtLeastOnce();
   device->ExpectRequestAndRespondWith(
       test_data::kU2fSignCommandApduWithAlternativeApplicationParameter,
       test_data::kU2fWrongDataApduResponse);
   // After the rejection, the U2F sign request with the primary application
   // parameter should be tried.
+  device->ExpectWinkedAtLeastOnce();
   device->ExpectRequestAndRespondWith(
       test_data::kU2fSignCommandApdu,
       test_data::kApduEncodedNoErrorSignResponse);
diff --git a/device/fido/hid/fido_hid_device.cc b/device/fido/hid/fido_hid_device.cc
index f28e03c..1825154c 100644
--- a/device/fido/hid/fido_hid_device.cc
+++ b/device/fido/hid/fido_hid_device.cc
@@ -22,6 +22,7 @@
 
 // U2F devices only provide a single report so specify a report ID of 0 here.
 static constexpr uint8_t kReportId = 0x00;
+static constexpr uint8_t kWinkCapability = 0x01;
 
 FidoHidDevice::FidoHidDevice(device::mojom::HidDeviceInfoPtr device_info,
                              device::mojom::HidManager* hid_manager)
@@ -42,8 +43,11 @@
     std::vector<uint8_t> command,
     DeviceCallback callback) {
   const CancelToken token = next_cancel_token_++;
-  pending_transactions_.emplace_back(std::move(command), std::move(callback),
-                                     token);
+  const auto command_type = supported_protocol() == ProtocolVersion::kCtap2
+                                ? FidoHidDeviceCommand::kCbor
+                                : FidoHidDeviceCommand::kMsg;
+  pending_transactions_.emplace_back(command_type, std::move(command),
+                                     std::move(callback), token);
   Transition();
   return token;
 }
@@ -110,18 +114,28 @@
                              weak_factory_.GetWeakPtr()));
       break;
     case State::kReady: {
+      DCHECK(!pending_transactions_.empty());
+
+      // Only try to wink if device claims support.
+      if (pending_transactions_.front().command_type ==
+              FidoHidDeviceCommand::kWink &&
+          !(capabilities_ & kWinkCapability)) {
+        DeviceCallback pending_cb =
+            std::move(pending_transactions_.front().callback);
+        pending_transactions_.pop_front();
+        std::move(pending_cb).Run(base::nullopt);
+        break;
+      }
+
       state_ = State::kBusy;
       busy_state_ = BusyState::kWriting;
-      DCHECK(!pending_transactions_.empty());
       ArmTimeout();
 
       // Write message to the device.
       current_token_ = pending_transactions_.front().token;
-      const auto command_type = supported_protocol() == ProtocolVersion::kCtap2
-                                    ? FidoHidDeviceCommand::kCbor
-                                    : FidoHidDeviceCommand::kMsg;
       auto maybe_message(FidoHidMessage::Create(
-          channel_id_, command_type, output_report_size_,
+          channel_id_, pending_transactions_.front().command_type,
+          output_report_size_,
           std::move(pending_transactions_.front().command)));
       DCHECK(maybe_message);
       WriteMessage(std::move(*maybe_message));
@@ -146,10 +160,12 @@
 }
 
 FidoHidDevice::PendingTransaction::PendingTransaction(
+    FidoHidDeviceCommand command_type,
     std::vector<uint8_t> in_command,
     DeviceCallback in_callback,
     CancelToken in_token)
-    : command(std::move(in_command)),
+    : command_type(command_type),
+      command(std::move(in_command)),
       callback(std::move(in_callback)),
       token(in_token) {}
 
@@ -205,7 +221,7 @@
 
 // ParseInitReply parses a potential reply to a U2FHID_INIT message. If the
 // reply matches the given nonce then the assigned channel ID is returned.
-static base::Optional<uint32_t> ParseInitReply(
+base::Optional<uint32_t> FidoHidDevice::ParseInitReply(
     const std::vector<uint8_t>& nonce,
     const std::vector<uint8_t>& buf) {
   auto message = FidoHidMessage::CreateFromSerializedData(buf);
@@ -232,6 +248,8 @@
     return base::nullopt;
   }
 
+  capabilities_ = payload[16];
+
   return static_cast<uint32_t>(payload[8]) << 24 |
          static_cast<uint32_t>(payload[9]) << 16 |
          static_cast<uint32_t>(payload[10]) << 8 |
@@ -408,7 +426,8 @@
 
   const auto cmd = message.cmd();
   auto response = message.GetMessagePayload();
-  if (cmd != FidoHidDeviceCommand::kMsg && cmd != FidoHidDeviceCommand::kCbor) {
+  if (cmd != FidoHidDeviceCommand::kMsg && cmd != FidoHidDeviceCommand::kCbor &&
+      cmd != FidoHidDeviceCommand::kWink) {
     if (cmd != FidoHidDeviceCommand::kError || response.size() != 1) {
       FIDO_LOG(ERROR) << "Unknown HID message received: "
                       << static_cast<int>(cmd) << " "
@@ -458,6 +477,19 @@
   }
 }
 
+void FidoHidDevice::TryWink(base::OnceClosure callback) {
+  const CancelToken token = next_cancel_token_++;
+  pending_transactions_.emplace_back(
+      FidoHidDeviceCommand::kWink, std::vector<uint8_t>(),
+      base::BindOnce(
+          [](base::OnceClosure cb, base::Optional<std::vector<uint8_t>> data) {
+            std::move(cb).Run();
+          },
+          std::move(callback)),
+      token);
+  Transition();
+}
+
 void FidoHidDevice::ArmTimeout() {
   DCHECK(timeout_callback_.IsCancelled());
   timeout_callback_.Reset(
diff --git a/device/fido/hid/fido_hid_device.h b/device/fido/hid/fido_hid_device.h
index 72e7c14..8c4bc8c5 100644
--- a/device/fido/hid/fido_hid_device.h
+++ b/device/fido/hid/fido_hid_device.h
@@ -38,6 +38,7 @@
   // FidoDevice:
   CancelToken DeviceTransact(std::vector<uint8_t> command,
                              DeviceCallback callback) final;
+  void TryWink(base::OnceClosure callback) final;
   void Cancel(CancelToken token) final;
   std::string GetId() const final;
   FidoTransportProtocol DeviceTransport() const final;
@@ -75,11 +76,13 @@
   };
 
   struct COMPONENT_EXPORT(DEVICE_FIDO) PendingTransaction {
-    PendingTransaction(std::vector<uint8_t> command,
+    PendingTransaction(FidoHidDeviceCommand command_type,
+                       std::vector<uint8_t> command,
                        DeviceCallback callback,
                        CancelToken token);
     ~PendingTransaction();
 
+    FidoHidDeviceCommand command_type;
     std::vector<uint8_t> command;
     DeviceCallback callback;
     CancelToken token;
@@ -94,6 +97,8 @@
   // Ask device to allocate a unique channel id for this connection.
   void OnAllocateChannel(std::vector<uint8_t> nonce,
                          base::Optional<FidoHidMessage> message);
+  base::Optional<uint32_t> ParseInitReply(const std::vector<uint8_t>& nonce,
+                                          const std::vector<uint8_t>& buf);
   void OnPotentialInitReply(std::vector<uint8_t> nonce,
                             bool success,
                             uint8_t report_id,
@@ -117,6 +122,8 @@
 
   base::WeakPtr<FidoDevice> GetWeakPtr() override;
 
+  uint8_t capabilities_ = 0;
+
   // |output_report_size_| is the size of the packets that will be sent to the
   // device. (For HID devices, these are called reports.)
   const uint8_t output_report_size_;
diff --git a/device/fido/hid/fido_hid_device_unittest.cc b/device/fido/hid/fido_hid_device_unittest.cc
index 300a8a5..f0369f9 100644
--- a/device/fido/hid/fido_hid_device_unittest.cc
+++ b/device/fido/hid/fido_hid_device_unittest.cc
@@ -39,6 +39,9 @@
     0x5f, 0x44, 0x41, 0x54, 0x41, 0x90, 0x00,
 };
 
+// HID_WINK(0x08), followed by payload length(0).
+constexpr uint8_t kU2fWinkResponseMessage[] = {0x08, 0x00};
+
 // APDU encoded success response with data "MOCK_DATA" followed by a SW_NO_ERROR
 // APDU response code(9000).
 constexpr uint8_t kU2fMockResponseData[] = {0x4d, 0x4f, 0x43, 0x4b, 0x5f, 0x44,
@@ -70,10 +73,12 @@
 // Returns HID_INIT request to send to device with mock connection.
 std::vector<uint8_t> CreateMockInitResponse(
     base::span<const uint8_t> nonce,
-    base::span<const uint8_t> channel_id) {
+    base::span<const uint8_t> channel_id,
+    base::span<const uint8_t> payload = base::span<const uint8_t>()) {
   auto init_response = fido_parsing_utils::Materialize(kInitResponsePrefix);
   fido_parsing_utils::Append(&init_response, nonce);
   fido_parsing_utils::Append(&init_response, channel_id);
+  fido_parsing_utils::Append(&init_response, payload);
   init_response.resize(64);
   return init_response;
 }
@@ -222,10 +227,12 @@
 
   // Add pending transactions manually and ensure they are processed.
   TestDeviceCallbackReceiver receiver_1;
-  device->pending_transactions_.emplace_back(GetMockDeviceRequest(),
+  device->pending_transactions_.emplace_back(FidoHidDeviceCommand::kMsg,
+                                             GetMockDeviceRequest(),
                                              receiver_1.callback(), 0);
   TestDeviceCallbackReceiver receiver_2;
-  device->pending_transactions_.emplace_back(GetMockDeviceRequest(),
+  device->pending_transactions_.emplace_back(FidoHidDeviceCommand::kMsg,
+                                             GetMockDeviceRequest(),
                                              receiver_2.callback(), 0);
   TestDeviceCallbackReceiver receiver_3;
   device->DeviceTransact(GetMockDeviceRequest(), receiver_3.callback());
@@ -726,4 +733,104 @@
   EXPECT_TRUE(get_info_callback.was_called());
 }
 
+// Test that the wink command does not get sent if the device does not support
+// it.
+TEST_F(FidoHidDeviceTest, TestWinkNotSupported) {
+  constexpr uint8_t kChannelId[] = {0x01, 0x02, 0x03, 0x04};
+  constexpr uint8_t kWinkNotSupportedPayload[] = {0x00, 0x00, 0x00, 0x00, 0x00};
+
+  auto hid_device = TestHidDevice();
+
+  // Replace device HID connection with custom client connection bound to mock
+  // server-side mojo connection.
+  device::mojom::HidConnectionPtr connection_client;
+  MockFidoHidConnection mock_connection(
+      hid_device.Clone(), mojo::MakeRequest(&connection_client),
+      fido_parsing_utils::Materialize(kChannelId));
+
+  // Initial write for establishing a channel ID.
+  mock_connection.ExpectWriteHidInit();
+
+  EXPECT_CALL(mock_connection, ReadPtr(_))
+      // Respond to HID_INIT indicating the device does not support winking.
+      .WillOnce(Invoke([&](device::mojom::HidConnection::ReadCallback* cb) {
+        std::move(*cb).Run(
+            true, 0,
+            CreateMockInitResponse(mock_connection.nonce(),
+                                   mock_connection.connection_channel_id(),
+                                   kWinkNotSupportedPayload));
+      }));
+
+  // Add device and set mock connection to fake hid manager.
+  fake_hid_manager_->AddDeviceAndSetConnection(std::move(hid_device),
+                                               std::move(connection_client));
+  FidoDeviceEnumerateCallbackReceiver receiver(hid_manager_.get());
+  hid_manager_->GetDevices(receiver.callback());
+  receiver.WaitForCallback();
+
+  std::vector<std::unique_ptr<FidoHidDevice>> u2f_devices =
+      receiver.TakeReturnedDevicesFiltered();
+  ASSERT_EQ(1u, u2f_devices.size());
+  auto& device = u2f_devices.front();
+
+  device::test::TestCallbackReceiver<> callback_receiver;
+  device->TryWink(callback_receiver.callback());
+  scoped_task_environment_.FastForwardUntilNoTasksRemain();
+  EXPECT_TRUE(callback_receiver.was_called());
+}
+
+// Test that the wink command is sent to a device that supports it.
+TEST_F(FidoHidDeviceTest, TestSuccessfulWink) {
+  constexpr uint8_t kChannelId[] = {0x01, 0x02, 0x03, 0x04};
+  constexpr uint8_t kWinkSupportedPayload[] = {0x00, 0x00, 0x00, 0x00, 0x01};
+
+  auto hid_device = TestHidDevice();
+
+  // Replace device HID connection with custom client connection bound to mock
+  // server-side mojo connection.
+  device::mojom::HidConnectionPtr connection_client;
+  MockFidoHidConnection mock_connection(
+      hid_device.Clone(), mojo::MakeRequest(&connection_client),
+      fido_parsing_utils::Materialize(kChannelId));
+
+  // Initial write for establishing a channel ID.
+  mock_connection.ExpectWriteHidInit();
+
+  mock_connection.ExpectHidWriteWithCommand(FidoHidDeviceCommand::kWink);
+
+  EXPECT_CALL(mock_connection, ReadPtr(_))
+      // Respond to HID_INIT indicating the device supports winking.
+      .WillOnce(Invoke([&](device::mojom::HidConnection::ReadCallback* cb) {
+        std::move(*cb).Run(
+            true, 0,
+            CreateMockInitResponse(mock_connection.nonce(),
+                                   mock_connection.connection_channel_id(),
+                                   kWinkSupportedPayload));
+      }))
+      // Response to HID_WINK.
+      .WillOnce(Invoke([&](device::mojom::HidConnection::ReadCallback* cb) {
+        std::move(*cb).Run(true, 0,
+                           CreateMockResponseWithChannelId(
+                               mock_connection.connection_channel_id(),
+                               kU2fWinkResponseMessage));
+      }));
+
+  // Add device and set mock connection to fake hid manager.
+  fake_hid_manager_->AddDeviceAndSetConnection(std::move(hid_device),
+                                               std::move(connection_client));
+  FidoDeviceEnumerateCallbackReceiver receiver(hid_manager_.get());
+  hid_manager_->GetDevices(receiver.callback());
+  receiver.WaitForCallback();
+
+  std::vector<std::unique_ptr<FidoHidDevice>> u2f_devices =
+      receiver.TakeReturnedDevicesFiltered();
+  ASSERT_EQ(1u, u2f_devices.size());
+  auto& device = u2f_devices.front();
+
+  device::test::TestCallbackReceiver<> callback_receiver;
+  device->TryWink(callback_receiver.callback());
+  scoped_task_environment_.FastForwardUntilNoTasksRemain();
+  EXPECT_TRUE(callback_receiver.was_called());
+}
+
 }  // namespace device
diff --git a/device/fido/make_credential_task_unittest.cc b/device/fido/make_credential_task_unittest.cc
index 3e7e1d5..ec10daa 100644
--- a/device/fido/make_credential_task_unittest.cc
+++ b/device/fido/make_credential_task_unittest.cc
@@ -102,6 +102,7 @@
 
 TEST_F(FidoMakeCredentialTaskTest, FallbackToU2fRegisterSuccess) {
   auto device = MockFidoDevice::MakeU2f();
+  device->ExpectWinkedAtLeastOnce();
   device->ExpectRequestAndRespondWith(
       test_data::kU2fRegisterCommandApdu,
       test_data::kApduEncodedNoErrorRegisterResponse);
@@ -123,6 +124,7 @@
   device_info.options = std::move(options);
 
   auto device = MockFidoDevice::MakeCtap(std::move(device_info));
+  device->ExpectWinkedAtLeastOnce();
   device->ExpectRequestAndRespondWith(
       test_data::kU2fRegisterCommandApdu,
       test_data::kApduEncodedNoErrorRegisterResponse);
@@ -168,6 +170,7 @@
   // request, because the task is instantiated in U2F-only mode.
   auto device = MockFidoDevice::MakeCtap();
 
+  device->ExpectWinkedAtLeastOnce();
   device->ExpectRequestAndRespondWith(
       test_data::kU2fRegisterCommandApdu,
       test_data::kApduEncodedNoErrorRegisterResponse);
diff --git a/device/fido/mock_fido_device.cc b/device/fido/mock_fido_device.cc
index fc83966d..f74015a 100644
--- a/device/fido/mock_fido_device.cc
+++ b/device/fido/mock_fido_device.cc
@@ -48,6 +48,7 @@
   auto device = std::make_unique<MockFidoDevice>();
   device->StubGetId();
   device->StubGetDisplayName();
+  device->ExpectWinkedAtLeastOnce();
   device->ExpectCtap2CommandAndRespondWith(
       CtapRequestCommand::kAuthenticatorGetInfo, base::nullopt);
   return device;
@@ -108,6 +109,10 @@
   return DeviceTransactPtr(command, cb);
 }
 
+void MockFidoDevice::TryWink(base::OnceClosure cb) {
+  TryWinkRef(cb);
+}
+
 FidoTransportProtocol MockFidoDevice::DeviceTransport() const {
   return transport_protocol_;
 }
@@ -116,6 +121,12 @@
   return weak_factory_.GetWeakPtr();
 }
 
+void MockFidoDevice::ExpectWinkedAtLeastOnce() {
+  EXPECT_CALL(*this, TryWinkRef(::testing::_))
+      .Times(::testing::AtLeast(1))
+      .WillRepeatedly([](base::OnceClosure& cb) { std::move(cb).Run(); });
+}
+
 void MockFidoDevice::StubGetId() {
   // Use a counter to keep the device ID unique.
   static size_t i = 0;
diff --git a/device/fido/mock_fido_device.h b/device/fido/mock_fido_device.h
index f693212..1cb93d8 100644
--- a/device/fido/mock_fido_device.h
+++ b/device/fido/mock_fido_device.h
@@ -60,6 +60,11 @@
                  base::Optional<AuthenticatorGetInfoResponse> device_info);
   ~MockFidoDevice() override;
 
+  // TODO(crbug.com/729950): Remove these workarounds once support for move-only
+  // types is added to GMock.
+  MOCK_METHOD1(TryWinkRef, void(base::OnceClosure& cb));
+  void TryWink(base::OnceClosure cb) override;
+
   // GMock cannot mock a method taking a move-only type.
   // TODO(crbug.com/729950): Remove these workarounds once support for move-only
   // types is added to GMock.
diff --git a/device/fido/u2f_register_operation.cc b/device/fido/u2f_register_operation.cc
index e49c58f..3a85342a 100644
--- a/device/fido/u2f_register_operation.cc
+++ b/device/fido/u2f_register_operation.cc
@@ -37,9 +37,9 @@
   if (exclude_list && !exclude_list->empty()) {
     // First try signing with the excluded credentials to see whether this
     // device should be excluded.
-    TrySign();
+    WinkAndTrySign();
   } else {
-    TryRegistration();
+    WinkAndTryRegistration();
   }
 }
 
@@ -47,6 +47,11 @@
   canceled_ = true;
 }
 
+void U2fRegisterOperation::WinkAndTrySign() {
+  device()->TryWink(base::BindOnce(&U2fRegisterOperation::TrySign,
+                                   weak_factory_.GetWeakPtr()));
+}
+
 void U2fRegisterOperation::TrySign() {
   base::Optional<std::vector<uint8_t>> sign_command;
   if (probing_alternative_rp_id_) {
@@ -98,7 +103,7 @@
       // Duplicate registration found. Waiting for user touch.
       base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
           FROM_HERE,
-          base::BindOnce(&U2fRegisterOperation::TrySign,
+          base::BindOnce(&U2fRegisterOperation::WinkAndTrySign,
                          weak_factory_.GetWeakPtr()),
           kU2fRetryDelay);
       break;
@@ -116,11 +121,11 @@
         current_key_handle_index_ = 0;
       }
       if (current_key_handle_index_ < request().exclude_list->size()) {
-        TrySign();
+        WinkAndTrySign();
       } else {
         // Reached the end of exclude list with no duplicate credential.
         // Proceed with registration.
-        TryRegistration();
+        WinkAndTryRegistration();
       }
       break;
 
@@ -134,6 +139,11 @@
   }
 }
 
+void U2fRegisterOperation::WinkAndTryRegistration() {
+  device()->TryWink(base::BindOnce(&U2fRegisterOperation::TryRegistration,
+                                   weak_factory_.GetWeakPtr()));
+}
+
 void U2fRegisterOperation::TryRegistration() {
   DispatchDeviceRequest(
       ConvertToU2fRegisterCommand(request()),
@@ -176,7 +186,7 @@
       // Waiting for user touch, retry after delay.
       base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
           FROM_HERE,
-          base::BindOnce(&U2fRegisterOperation::TryRegistration,
+          base::BindOnce(&U2fRegisterOperation::WinkAndTryRegistration,
                          weak_factory_.GetWeakPtr()),
           kU2fRetryDelay);
       break;
diff --git a/device/fido/u2f_register_operation.h b/device/fido/u2f_register_operation.h
index f21958e..04cfa31 100644
--- a/device/fido/u2f_register_operation.h
+++ b/device/fido/u2f_register_operation.h
@@ -44,9 +44,11 @@
   using ExcludeListIterator =
       std::vector<PublicKeyCredentialDescriptor>::const_iterator;
 
+  void WinkAndTrySign();
   void TrySign();
   void OnCheckForExcludedKeyHandle(
       base::Optional<std::vector<uint8_t>> device_response);
+  void WinkAndTryRegistration();
   void TryRegistration();
   void OnRegisterResponseReceived(
       base::Optional<std::vector<uint8_t>> device_response);
diff --git a/device/fido/u2f_register_operation_unittest.cc b/device/fido/u2f_register_operation_unittest.cc
index 67693240..5e299d13 100644
--- a/device/fido/u2f_register_operation_unittest.cc
+++ b/device/fido/u2f_register_operation_unittest.cc
@@ -74,6 +74,7 @@
   auto request = CreateRegisterRequest();
   auto device = std::make_unique<MockFidoDevice>();
   EXPECT_CALL(*device, GetId()).WillRepeatedly(testing::Return("device"));
+  device->ExpectWinkedAtLeastOnce();
   device->ExpectRequestAndRespondWith(
       test_data::kU2fRegisterCommandApdu,
       test_data::kApduEncodedNoErrorRegisterResponse);
@@ -114,6 +115,7 @@
 
   auto device = std::make_unique<MockFidoDevice>();
   EXPECT_CALL(*device, GetId()).WillRepeatedly(testing::Return("device"));
+  device->ExpectWinkedAtLeastOnce();
 
   // Device error out once waiting for user presence before retrying.
   ::testing::InSequence s;
@@ -152,6 +154,7 @@
 
   auto device = std::make_unique<MockFidoDevice>();
   EXPECT_CALL(*device, GetId()).WillRepeatedly(::testing::Return("device"));
+  device->ExpectWinkedAtLeastOnce();
   // DeviceTransact() will be called three times including two check only sign-
   // in calls and one registration call. For the first two calls, device will
   // invoke MockFidoDevice::WrongData/WrongLength as the authenticator did not
@@ -200,11 +203,11 @@
 
   auto device = std::make_unique<MockFidoDevice>();
   EXPECT_CALL(*device, GetId()).WillRepeatedly(::testing::Return("device"));
-  // For three keys in exclude list, the first two keys will invoke
-  // MockFidoDevice::WrongData and the final duplicate key handle will invoke
-  // MockFidoDevice::NoErrorSign. Once duplicate key handle is found, bogus
-  // registration is called to confirm user presence. This invokes
-  // MockFidoDevice::NoErrorRegister.
+  device->ExpectWinkedAtLeastOnce();
+  // For three keys in exclude list, the first two keys will return
+  // SW_WRONG_DATA and the final duplicate key handle will invoke
+  // SW_NO_ERROR. This means user presence has already been collected, so the
+  // request is concluded with Ctap2ErrCredentialExcluded.
   ::testing::InSequence s;
   device->ExpectRequestAndRespondWith(
       test_data::kU2fSignCommandApduWithKeyAlpha,
@@ -240,6 +243,7 @@
 
     auto device = std::make_unique<MockFidoDevice>();
     EXPECT_CALL(*device, GetId()).WillRepeatedly(::testing::Return("device"));
+    device->ExpectWinkedAtLeastOnce();
 
     device->ExpectRequestAndRespondWith(
         individual_attestation
diff --git a/device/fido/u2f_sign_operation.cc b/device/fido/u2f_sign_operation.cc
index 02fd5046b..7413ff86 100644
--- a/device/fido/u2f_sign_operation.cc
+++ b/device/fido/u2f_sign_operation.cc
@@ -34,12 +34,12 @@
       // authenticator (at least) crashes if we try the wrong AppID first.
       app_param_type_ = ApplicationParameterType::kAlternative;
     }
-    TrySign();
+    WinkAndTrySign();
   } else {
     // In order to make U2F authenticators blink on sign request with an empty
     // allow list, we send fake enrollment to the device and error out when the
     // user has provided presence.
-    TryFakeEnrollment();
+    WinkAndTryFakeEnrollment();
   }
 }
 
@@ -47,6 +47,11 @@
   canceled_ = true;
 }
 
+void U2fSignOperation::WinkAndTrySign() {
+  device()->TryWink(
+      base::BindOnce(&U2fSignOperation::TrySign, weak_factory_.GetWeakPtr()));
+}
+
 void U2fSignOperation::TrySign() {
   DispatchDeviceRequest(
       ConvertToU2fSignCommand(request(), app_param_type_, key_handle()),
@@ -107,13 +112,13 @@
         // |application_parameter_| failed, but there is also
         // the primary value to try.
         app_param_type_ = ApplicationParameterType::kPrimary;
-        TrySign();
+        WinkAndTrySign();
       } else if (++current_key_handle_index_ < request().allow_list.size()) {
         // Key is not for this device. Try signing with the next key.
         if (request().alternative_application_parameter.has_value()) {
           app_param_type_ = ApplicationParameterType::kAlternative;
         }
-        TrySign();
+        WinkAndTrySign();
       } else {
         // No provided key was accepted by this device. Send registration
         // (i.e. fake enroll) request to device.
@@ -125,7 +130,7 @@
       // Waiting for user touch. Retry after 200 milliseconds delay.
       base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
           FROM_HERE,
-          base::BindOnce(&U2fSignOperation::TrySign,
+          base::BindOnce(&U2fSignOperation::WinkAndTrySign,
                          weak_factory_.GetWeakPtr()),
           kU2fRetryDelay);
       break;
@@ -138,6 +143,11 @@
   }
 }
 
+void U2fSignOperation::WinkAndTryFakeEnrollment() {
+  device()->TryWink(base::BindOnce(&U2fSignOperation::TryFakeEnrollment,
+                                   weak_factory_.GetWeakPtr()));
+}
+
 void U2fSignOperation::TryFakeEnrollment() {
   DispatchDeviceRequest(
       ConstructBogusU2fRegistrationCommand(),
diff --git a/device/fido/u2f_sign_operation.h b/device/fido/u2f_sign_operation.h
index 19a1606..4ea26ae 100644
--- a/device/fido/u2f_sign_operation.h
+++ b/device/fido/u2f_sign_operation.h
@@ -41,9 +41,11 @@
   void Cancel() override;
 
  private:
+  void WinkAndTrySign();
   void TrySign();
   void OnSignResponseReceived(
       base::Optional<std::vector<uint8_t>> device_response);
+  void WinkAndTryFakeEnrollment();
   void TryFakeEnrollment();
   void OnEnrollmentResponseReceived(
       base::Optional<std::vector<uint8_t>> device_response);
diff --git a/device/fido/u2f_sign_operation_unittest.cc b/device/fido/u2f_sign_operation_unittest.cc
index 6203d8b..6b814f2 100644
--- a/device/fido/u2f_sign_operation_unittest.cc
+++ b/device/fido/u2f_sign_operation_unittest.cc
@@ -60,6 +60,7 @@
 
   auto device = std::make_unique<MockFidoDevice>();
   EXPECT_CALL(*device, GetId()).WillRepeatedly(testing::Return("device"));
+  device->ExpectWinkedAtLeastOnce();
   InSequence s;
   device->ExpectRequestAndRespondWith(
       test_data::kU2fSignCommandApdu,
@@ -128,6 +129,7 @@
   // responding successfully.
   auto device = std::make_unique<MockFidoDevice>();
   EXPECT_CALL(*device, GetId()).WillRepeatedly(::testing::Return("device"));
+  device->ExpectWinkedAtLeastOnce();
 
   InSequence s;
   device->ExpectRequestAndRespondWith(
@@ -160,6 +162,7 @@
 
   auto device = std::make_unique<MockFidoDevice>();
   EXPECT_CALL(*device, GetId()).WillRepeatedly(::testing::Return("device"));
+  device->ExpectWinkedAtLeastOnce();
   InSequence s;
   // Wrong key would respond with SW_WRONG_DATA.
   device->ExpectRequestAndRespondWith(
@@ -193,6 +196,7 @@
 
   auto device = std::make_unique<MockFidoDevice>();
   EXPECT_CALL(*device, GetId()).WillRepeatedly(::testing::Return("device"));
+  device->ExpectWinkedAtLeastOnce();
   InSequence s;
 
   // Wrong key would respond with the key handle length.
@@ -224,6 +228,7 @@
        fido_parsing_utils::Materialize(test_data::kKeyHandleBeta)});
 
   auto device = std::make_unique<MockFidoDevice>();
+  device->ExpectWinkedAtLeastOnce();
   InSequence s;
   device->ExpectRequestAndRespondWith(
       test_data::kU2fSignCommandApduWithKeyAlpha,
@@ -255,6 +260,7 @@
   // enrollment.
   auto device = std::make_unique<MockFidoDevice>();
   EXPECT_CALL(*device, GetId()).WillRepeatedly(::testing::Return("device0"));
+  device->ExpectWinkedAtLeastOnce();
   InSequence s;
   device->ExpectRequestAndRespondWith(test_data::kU2fSignCommandApdu,
                                       test_data::kU2fWrongDataApduResponse);
@@ -286,6 +292,7 @@
   // to prevent the test from crashing or timing out.
   auto device = std::make_unique<MockFidoDevice>();
   EXPECT_CALL(*device, GetId()).WillRepeatedly(::testing::Return("device0"));
+  device->ExpectWinkedAtLeastOnce();
   InSequence s;
   device->ExpectRequestAndRespondWith(test_data::kU2fSignCommandApdu,
                                       test_data::kU2fWrongDataApduResponse);
@@ -310,6 +317,7 @@
 
   auto device = std::make_unique<MockFidoDevice>();
   EXPECT_CALL(*device, GetId()).WillRepeatedly(::testing::Return("device"));
+  device->ExpectWinkedAtLeastOnce();
   InSequence s;
   device->ExpectRequestAndRespondWith(test_data::kU2fSignCommandApdu,
                                       test_data::kTestCorruptedU2fSignResponse);
@@ -334,6 +342,7 @@
 
   auto device = std::make_unique<MockFidoDevice>();
   EXPECT_CALL(*device, GetId()).WillRepeatedly(::testing::Return("device"));
+  device->ExpectWinkedAtLeastOnce();
   InSequence s;
   // The first request will use the alternative app_param.
   device->ExpectRequestAndRespondWith(
@@ -368,6 +377,7 @@
 
   auto device = std::make_unique<MockFidoDevice>();
   EXPECT_CALL(*device, GetId()).WillRepeatedly(::testing::Return("device"));
+  device->ExpectWinkedAtLeastOnce();
   InSequence s;
   // The first request will use the alternative app_param, which will be
   // rejected.
diff --git a/device/fido/virtual_fido_device.cc b/device/fido/virtual_fido_device.cc
index 874b6a4..70cb9ee55 100644
--- a/device/fido/virtual_fido_device.cc
+++ b/device/fido/virtual_fido_device.cc
@@ -236,6 +236,10 @@
   return &it->second;
 }
 
+void VirtualFidoDevice::TryWink(base::OnceClosure cb) {
+  std::move(cb).Run();
+}
+
 std::string VirtualFidoDevice::GetId() const {
   // Use our heap address to get a unique-ish number. (0xffe1 is a prime).
   return "VirtualFidoDevice-" + std::to_string((size_t)this % 0xffe1);
diff --git a/device/fido/virtual_fido_device.h b/device/fido/virtual_fido_device.h
index ef94bba..b3563c4 100644
--- a/device/fido/virtual_fido_device.h
+++ b/device/fido/virtual_fido_device.h
@@ -226,6 +226,7 @@
       base::span<const uint8_t, kRpIdHashLength> application_parameter);
 
   // FidoDevice:
+  void TryWink(base::OnceClosure cb) override;
   std::string GetId() const override;
   FidoTransportProtocol DeviceTransport() const override;
 
diff --git a/docs/infra/cq_builders.md b/docs/infra/cq_builders.md
index aeded44..6ce52d3 100644
--- a/docs/infra/cq_builders.md
+++ b/docs/infra/cq_builders.md
@@ -142,6 +142,7 @@
 * [dawn-linux-x64-deps-rel](https://ci.chromium.org/p/chromium/builders/luci.chromium.try/dawn-linux-x64-deps-rel) ([`commit-queue.cfg` entry](https://cs.chromium.org/search/?q=package:%5Echromium$+file:commit-queue.cfg+chromium/try/dawn-linux-x64-deps-rel)) ([matching builders](https://cs.chromium.org/search/?q=file:trybots.py+dawn-linux-x64-deps-rel))
 
   Path regular expressions:
+    * [`//gpu/.+`](https://cs.chromium.org/chromium/src/gpu/)
     * [`//testing/buildbot/chromium.dawn.json`](https://cs.chromium.org/search/?q=package:%5Echromium$+file:testing/buildbot/chromium.dawn.json)
     * [`//third_party/blink/renderer/modules/webgpu/.+`](https://cs.chromium.org/chromium/src/third_party/blink/renderer/modules/webgpu/)
     * [`//third_party/blink/web_tests/FlagExpectations/enable-unsafe-webgpu`](https://cs.chromium.org/search/?q=package:%5Echromium$+file:third_party/blink/web_tests/FlagExpectations/enable-unsafe-webgpu)
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index 2b10bca0..1330b4e 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -1435,6 +1435,7 @@
   LOGINSCREENSTORAGE_STORECREDENTIALS = 1372,
   LOGINSCREENSTORAGE_RETRIEVECREDENTIALS = 1373,
   AUTOTESTPRIVATE_GETARCAPPWINDOWSTATE = 1374,
+  AUTOTESTPRIVATE_GETARCAPPWINDOWINFO = 1375,
   // Last entry: Add new entries above, then run:
   // python tools/metrics/histograms/update_extension_histograms.py
   ENUM_BOUNDARY
diff --git a/extensions/renderer/api/automation/automation_ax_tree_wrapper.cc b/extensions/renderer/api/automation/automation_ax_tree_wrapper.cc
index 587edbe..28efcd3 100644
--- a/extensions/renderer/api/automation/automation_ax_tree_wrapper.cc
+++ b/extensions/renderer/api/automation/automation_ax_tree_wrapper.cc
@@ -7,6 +7,7 @@
 #include "extensions/renderer/api/automation/automation_internal_custom_bindings.h"
 #include "ui/accessibility/ax_language_detection.h"
 #include "ui/accessibility/ax_node.h"
+#include "ui/accessibility/ax_node_position.h"
 
 namespace extensions {
 
@@ -413,6 +414,14 @@
   return true;
 }
 
+ui::AXTree::Selection AutomationAXTreeWrapper::GetUnignoredSelection() {
+  // As there is no Tree Manager, this is necessary for AXPositions to work.
+  ui::AXNodePosition::SetTree(tree());
+  ui::AXTree::Selection unignored_selection = tree()->GetUnignoredSelection();
+  ui::AXNodePosition::SetTree(nullptr);
+  return unignored_selection;
+}
+
 // static
 std::map<ui::AXTreeID, AutomationAXTreeWrapper*>&
 AutomationAXTreeWrapper::GetChildTreeIDReverseMap() {
diff --git a/extensions/renderer/api/automation/automation_ax_tree_wrapper.h b/extensions/renderer/api/automation/automation_ax_tree_wrapper.h
index 38a25b6..0413bed 100644
--- a/extensions/renderer/api/automation/automation_ax_tree_wrapper.h
+++ b/extensions/renderer/api/automation/automation_ax_tree_wrapper.h
@@ -47,6 +47,8 @@
   // document.activeElement (within the DOM).
   bool IsInFocusChain(int32_t node_id);
 
+  ui::AXTree::Selection GetUnignoredSelection();
+
   static std::map<ui::AXTreeID, AutomationAXTreeWrapper*>&
   GetChildTreeIDReverseMap();
 
diff --git a/extensions/renderer/api/automation/automation_internal_custom_bindings.cc b/extensions/renderer/api/automation/automation_internal_custom_bindings.cc
index a21fe17..91d70df 100644
--- a/extensions/renderer/api/automation/automation_internal_custom_bindings.cc
+++ b/extensions/renderer/api/automation/automation_internal_custom_bindings.cc
@@ -40,6 +40,7 @@
 #include "ui/accessibility/ax_event.h"
 #include "ui/accessibility/ax_language_detection.h"
 #include "ui/accessibility/ax_node.h"
+#include "ui/accessibility/ax_node_position.h"
 #include "ui/accessibility/ax_role_properties.h"
 #include "ui/accessibility/ax_text_utils.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -574,9 +575,8 @@
       "GetIsSelectionBackward",
       [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result,
          AutomationAXTreeWrapper* tree_wrapper) {
-        const ui::AXTreeData& tree_data = tree_wrapper->tree()->data();
-        const ui::AXNode* anchor =
-            tree_wrapper->tree()->GetFromId(tree_data.sel_anchor_object_id);
+        const ui::AXNode* anchor = tree_wrapper->tree()->GetFromId(
+            tree_wrapper->GetUnignoredSelection().anchor_object_id);
         if (!anchor)
           return;
 
@@ -587,103 +587,114 @@
       "GetAnchorObjectID",
       [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result,
          AutomationAXTreeWrapper* tree_wrapper) {
-        const ui::AXTreeData& tree_data = tree_wrapper->tree()->data();
-        result.Set(v8::Number::New(isolate, tree_data.sel_anchor_object_id));
+        result.Set(v8::Number::New(
+            isolate, tree_wrapper->GetUnignoredSelection().anchor_object_id));
       });
   RouteTreeIDFunction(
       "GetAnchorOffset",
       [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result,
          AutomationAXTreeWrapper* tree_wrapper) {
-        const ui::AXTreeData& tree_data = tree_wrapper->tree()->data();
-        result.Set(v8::Number::New(isolate, tree_data.sel_anchor_offset));
+        result.Set(v8::Number::New(
+            isolate, tree_wrapper->GetUnignoredSelection().anchor_offset));
       });
   RouteTreeIDFunction(
       "GetAnchorAffinity",
       [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result,
          AutomationAXTreeWrapper* tree_wrapper) {
-        const ui::AXTreeData& tree_data = tree_wrapper->tree()->data();
-        result.Set(CreateV8String(isolate,
-                                  ui::ToString(tree_data.sel_anchor_affinity)));
+        result.Set(CreateV8String(
+            isolate,
+            ui::ToString(
+                tree_wrapper->GetUnignoredSelection().anchor_affinity)));
       });
   RouteTreeIDFunction(
       "GetFocusObjectID",
       [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result,
          AutomationAXTreeWrapper* tree_wrapper) {
-        const ui::AXTreeData& tree_data = tree_wrapper->tree()->data();
-        result.Set(v8::Number::New(isolate, tree_data.sel_focus_object_id));
+        result.Set(v8::Number::New(
+            isolate, tree_wrapper->GetUnignoredSelection().focus_object_id));
       });
   RouteTreeIDFunction(
       "GetFocusOffset",
       [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result,
          AutomationAXTreeWrapper* tree_wrapper) {
-        const ui::AXTreeData& tree_data = tree_wrapper->tree()->data();
-        result.Set(v8::Number::New(isolate, tree_data.sel_focus_offset));
+        result.Set(v8::Number::New(
+            isolate, tree_wrapper->GetUnignoredSelection().focus_offset));
       });
   RouteTreeIDFunction(
       "GetFocusAffinity",
       [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result,
          AutomationAXTreeWrapper* tree_wrapper) {
-        const ui::AXTreeData& tree_data = tree_wrapper->tree()->data();
-        result.Set(CreateV8String(isolate,
-                                  ui::ToString(tree_data.sel_focus_affinity)));
+        result.Set(CreateV8String(
+            isolate,
+            ui::ToString(
+                tree_wrapper->GetUnignoredSelection().focus_affinity)));
       });
   RouteTreeIDFunction(
       "GetSelectionStartObjectID",
       [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result,
          AutomationAXTreeWrapper* tree_wrapper) {
-        const ui::AXTreeData& tree_data = tree_wrapper->tree()->data();
-        int32_t start_object_id = tree_data.sel_is_backward
-                                      ? tree_data.sel_focus_object_id
-                                      : tree_data.sel_anchor_object_id;
+        ui::AXTree::Selection unignored_selection =
+            tree_wrapper->GetUnignoredSelection();
+        int32_t start_object_id = unignored_selection.is_backward
+                                      ? unignored_selection.focus_object_id
+                                      : unignored_selection.anchor_object_id;
         result.Set(v8::Number::New(isolate, start_object_id));
       });
   RouteTreeIDFunction(
       "GetSelectionStartOffset",
       [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result,
          AutomationAXTreeWrapper* tree_wrapper) {
-        const ui::AXTreeData& tree_data = tree_wrapper->tree()->data();
-        int start_offset = tree_data.sel_is_backward
-                               ? tree_data.sel_focus_offset
-                               : tree_data.sel_anchor_offset;
+        ui::AXTree::Selection unignored_selection =
+            tree_wrapper->GetUnignoredSelection();
+        int start_offset = unignored_selection.is_backward
+                               ? unignored_selection.focus_offset
+                               : unignored_selection.anchor_offset;
         result.Set(v8::Number::New(isolate, start_offset));
       });
   RouteTreeIDFunction(
       "GetSelectionStartAffinity",
       [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result,
          AutomationAXTreeWrapper* tree_wrapper) {
-        const ui::AXTreeData& tree_data = tree_wrapper->tree()->data();
+        ui::AXTree::Selection unignored_selection =
+            tree_wrapper->GetUnignoredSelection();
         ax::mojom::TextAffinity start_affinity =
-            tree_data.sel_is_backward ? tree_data.sel_focus_affinity
-                                      : tree_data.sel_anchor_affinity;
+            unignored_selection.is_backward
+                ? unignored_selection.focus_affinity
+                : unignored_selection.anchor_affinity;
         result.Set(CreateV8String(isolate, ui::ToString(start_affinity)));
       });
   RouteTreeIDFunction(
       "GetSelectionEndObjectID",
       [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result,
          AutomationAXTreeWrapper* tree_wrapper) {
-        const ui::AXTreeData& tree_data = tree_wrapper->tree()->data();
-        int32_t end_object_id = tree_data.sel_is_backward
-                                    ? tree_data.sel_anchor_object_id
-                                    : tree_data.sel_focus_object_id;
+        ui::AXTree::Selection unignored_selection =
+            tree_wrapper->GetUnignoredSelection();
+        int32_t end_object_id = unignored_selection.is_backward
+                                    ? unignored_selection.anchor_object_id
+                                    : unignored_selection.focus_object_id;
         result.Set(v8::Number::New(isolate, end_object_id));
       });
   RouteTreeIDFunction(
       "GetSelectionEndOffset",
       [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result,
          AutomationAXTreeWrapper* tree_wrapper) {
-        const ui::AXTreeData& tree_data = tree_wrapper->tree()->data();
-        int end_offset = tree_data.sel_is_backward ? tree_data.sel_anchor_offset
-                                                   : tree_data.sel_focus_offset;
+        ui::AXTree::Selection unignored_selection =
+            tree_wrapper->GetUnignoredSelection();
+        int end_offset = unignored_selection.is_backward
+                             ? unignored_selection.anchor_offset
+                             : unignored_selection.focus_offset;
         result.Set(v8::Number::New(isolate, end_offset));
       });
   RouteTreeIDFunction(
       "GetSelectionEndAffinity",
       [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result,
          AutomationAXTreeWrapper* tree_wrapper) {
-        const ui::AXTreeData& tree_data = tree_wrapper->tree()->data();
+        ui::AXTree::Selection unignored_selection =
+            tree_wrapper->GetUnignoredSelection();
         ax::mojom::TextAffinity end_affinity =
-            tree_data.sel_is_backward ? tree_data.sel_anchor_affinity
-                                      : tree_data.sel_focus_affinity;
+            unignored_selection.is_backward
+                ? unignored_selection.anchor_affinity
+                : unignored_selection.focus_affinity;
         result.Set(CreateV8String(isolate, ui::ToString(end_affinity)));
       });
 
diff --git a/gpu/command_buffer/service/BUILD.gn b/gpu/command_buffer/service/BUILD.gn
index ca343d88..85abd825 100644
--- a/gpu/command_buffer/service/BUILD.gn
+++ b/gpu/command_buffer/service/BUILD.gn
@@ -307,6 +307,7 @@
     "//gpu/command_buffer/common:gles2_utils",
     "//gpu/config",
     "//gpu/ipc/common:surface_handle_type",
+    "//gpu/ipc/common:vulkan_ycbcr_info",
     "//gpu/vulkan:buildflags",
     "//third_party/angle:angle_image_util",
     "//third_party/angle:commit_id",
diff --git a/gpu/command_buffer/service/external_vk_image_backing.cc b/gpu/command_buffer/service/external_vk_image_backing.cc
index efc841e..d2a8081 100644
--- a/gpu/command_buffer/service/external_vk_image_backing.cc
+++ b/gpu/command_buffer/service/external_vk_image_backing.cc
@@ -14,6 +14,7 @@
 #include "components/viz/common/resources/resource_sizes.h"
 #include "gpu/command_buffer/service/external_vk_image_gl_representation.h"
 #include "gpu/command_buffer/service/external_vk_image_skia_representation.h"
+#include "gpu/ipc/common/vulkan_ycbcr_info.h"
 #include "gpu/vulkan/vulkan_command_buffer.h"
 #include "gpu/vulkan/vulkan_command_pool.h"
 #include "gpu/vulkan/vulkan_fence_helper.h"
@@ -37,12 +38,28 @@
                                   VkFormat vk_format,
                                   VkDeviceMemory memory,
                                   size_t memory_size,
-                                  bool use_protected_memory) {
+                                  bool use_protected_memory,
+                                  base::Optional<VulkanYCbCrInfo> ycbcr_info) {
+  GrVkYcbcrConversionInfo gr_ycbcr_info{};
+  if (ycbcr_info) {
+    gr_ycbcr_info = GrVkYcbcrConversionInfo(
+        static_cast<VkFormat>(ycbcr_info->image_format),
+        ycbcr_info->external_format,
+        static_cast<VkSamplerYcbcrModelConversion>(
+            ycbcr_info->suggested_ycbcr_model),
+        static_cast<VkSamplerYcbcrRange>(ycbcr_info->suggested_ycbcr_range),
+        static_cast<VkChromaLocation>(ycbcr_info->suggested_xchroma_offset),
+        static_cast<VkChromaLocation>(ycbcr_info->suggested_ychroma_offset),
+        static_cast<VkFilter>(VK_FILTER_LINEAR),
+        /*forceExplicitReconstruction=*/false,
+        static_cast<VkFormatFeatureFlags>(ycbcr_info->format_features));
+  }
   GrVkAlloc alloc(memory, 0 /* offset */, memory_size, 0 /* flags */);
   return GrVkImageInfo(
       image, alloc, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_LAYOUT_UNDEFINED,
       vk_format, 1 /* levelCount */, VK_QUEUE_FAMILY_IGNORED,
-      use_protected_memory ? GrProtected::kYes : GrProtected::kNo);
+      use_protected_memory ? GrProtected::kYes : GrProtected::kNo,
+      gr_ycbcr_info);
 }
 
 VkResult CreateVkImage(SharedContextState* context_state,
@@ -140,7 +157,8 @@
     const gfx::ColorSpace& color_space,
     uint32_t usage,
     base::span<const uint8_t> pixel_data,
-    bool using_gmb) {
+    bool using_gmb,
+    base::Optional<VulkanYCbCrInfo> ycbcr_info) {
   VkDevice device =
       context_state->vk_context_provider()->GetDeviceQueue()->GetVulkanDevice();
   VkFormat vk_format = ToVkFormat(format);
@@ -206,7 +224,7 @@
 
   auto backing = base::WrapUnique(new ExternalVkImageBacking(
       mailbox, format, size, color_space, usage, context_state, image, memory,
-      requirements.size, vk_format, command_pool));
+      requirements.size, vk_format, command_pool, ycbcr_info));
 
   if (!pixel_data.empty()) {
     backing->WritePixels(
@@ -229,11 +247,6 @@
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
     uint32_t usage) {
-  if (gfx::NumberOfPlanesForLinearBufferFormat(buffer_format) != 1) {
-    DLOG(ERROR) << "Invalid image format.";
-    return nullptr;
-  }
-
   if (!gpu::IsImageSizeValidForGpuMemoryBufferFormat(size, buffer_format)) {
     DLOG(ERROR) << "Invalid image size for format.";
     return nullptr;
@@ -250,17 +263,18 @@
     VkImageCreateInfo vk_image_info = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO};
     VkDeviceMemory vk_device_memory = VK_NULL_HANDLE;
     VkDeviceSize memory_size = 0;
+    base::Optional<gpu::VulkanYCbCrInfo> ycbcr_info;
 
     if (!vulkan_implementation->CreateImageFromGpuMemoryHandle(
             vk_device, std::move(handle), size, &vk_image, &vk_image_info,
-            &vk_device_memory, &memory_size)) {
+            &vk_device_memory, &memory_size, &ycbcr_info)) {
       DLOG(ERROR) << "Failed to create VkImage from GpuMemoryHandle.";
       return nullptr;
     }
 
     VkFormat expected_format = ToVkFormat(resource_format);
     if (expected_format != vk_image_info.format) {
-      DLOG(ERROR) << "BufferFormat doesn't match the buffer";
+      DLOG(ERROR) << "BufferFormat doesn't match the buffer ";
       vkFreeMemory(vk_device, vk_device_memory, nullptr);
       vkDestroyImage(vk_device, vk_image, nullptr);
       return nullptr;
@@ -269,7 +283,12 @@
     return base::WrapUnique(new ExternalVkImageBacking(
         mailbox, viz::GetResourceFormat(buffer_format), size, color_space,
         usage, context_state, vk_image, vk_device_memory, memory_size,
-        vk_image_info.format, command_pool));
+        vk_image_info.format, command_pool, ycbcr_info));
+  }
+
+  if (gfx::NumberOfPlanesForLinearBufferFormat(buffer_format) != 1) {
+    DLOG(ERROR) << "Invalid image format.";
+    return nullptr;
   }
 
   DCHECK_EQ(handle.type, gfx::SHARED_MEMORY_BUFFER);
@@ -363,7 +382,8 @@
     VkDeviceMemory memory,
     size_t memory_size,
     VkFormat vk_format,
-    VulkanCommandPool* command_pool)
+    VulkanCommandPool* command_pool,
+    base::Optional<VulkanYCbCrInfo> ycbcr_info)
     : SharedImageBacking(mailbox,
                          format,
                          size,
@@ -372,14 +392,14 @@
                          memory_size,
                          false /* is_thread_safe */),
       context_state_(context_state),
-      backend_texture_(
-          size.width(),
-          size.height(),
-          CreateGrVkImageInfo(image,
-                              vk_format,
-                              memory,
-                              memory_size,
-                              usage & SHARED_IMAGE_USAGE_PROTECTED)),
+      backend_texture_(size.width(),
+                       size.height(),
+                       CreateGrVkImageInfo(image,
+                                           vk_format,
+                                           memory,
+                                           memory_size,
+                                           usage & SHARED_IMAGE_USAGE_PROTECTED,
+                                           ycbcr_info)),
       command_pool_(command_pool) {}
 
 ExternalVkImageBacking::~ExternalVkImageBacking() {
diff --git a/gpu/command_buffer/service/external_vk_image_backing.h b/gpu/command_buffer/service/external_vk_image_backing.h
index 54d73b4e..cbb88467 100644
--- a/gpu/command_buffer/service/external_vk_image_backing.h
+++ b/gpu/command_buffer/service/external_vk_image_backing.h
@@ -10,11 +10,13 @@
 
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/shared_memory_mapping.h"
+#include "base/optional.h"
 #include "components/viz/common/gpu/vulkan_context_provider.h"
 #include "gpu/command_buffer/common/shared_image_usage.h"
 #include "gpu/command_buffer/service/shared_context_state.h"
 #include "gpu/command_buffer/service/shared_image_backing.h"
 #include "gpu/command_buffer/service/texture_manager.h"
+#include "gpu/ipc/common/vulkan_ycbcr_info.h"
 #include "gpu/vulkan/semaphore_handle.h"
 #include "gpu/vulkan/vulkan_device_queue.h"
 #include "ui/gfx/gpu_memory_buffer.h"
@@ -34,7 +36,8 @@
       const gfx::ColorSpace& color_space,
       uint32_t usage,
       base::span<const uint8_t> pixel_data,
-      bool using_gmb = false);
+      bool using_gmb = false,
+      base::Optional<VulkanYCbCrInfo> ycbcr_info = base::nullopt);
 
   static std::unique_ptr<ExternalVkImageBacking> CreateFromGMB(
       SharedContextState* context_state,
@@ -116,7 +119,8 @@
                          VkDeviceMemory memory,
                          size_t memory_size,
                          VkFormat vk_format,
-                         VulkanCommandPool* command_pool);
+                         VulkanCommandPool* command_pool,
+                         base::Optional<VulkanYCbCrInfo> ycbcr_info);
 
   // Install a shared memory GMB to the backing.
   void InstallSharedMemory(
diff --git a/gpu/command_buffer/service/swap_chain_factory_dxgi.cc b/gpu/command_buffer/service/swap_chain_factory_dxgi.cc
index b9ec152c..7d50383 100644
--- a/gpu/command_buffer/service/swap_chain_factory_dxgi.cc
+++ b/gpu/command_buffer/service/swap_chain_factory_dxgi.cc
@@ -204,6 +204,7 @@
   }
 
   bool PresentSwapChain() override {
+    TRACE_EVENT0("gpu", "SharedImageBackingDXGISwapChain::PresentSwapChain");
     if (buffer_index_ != 0) {
       DLOG(ERROR) << "Swap chain backing does not correspond to back buffer";
       return false;
@@ -213,8 +214,9 @@
     params.DirtyRectsCount = 0;
     params.pDirtyRects = nullptr;
 
-    HRESULT hr =
-        swap_chain_->Present1(0 /* interval */, 0 /* flags */, &params);
+    UINT flags = DXGI_PRESENT_ALLOW_TEARING;
+
+    HRESULT hr = swap_chain_->Present1(0 /* interval */, flags, &params);
     if (FAILED(hr)) {
       DLOG(ERROR) << "Present1 failed with error " << std::hex << hr;
       return false;
@@ -232,6 +234,11 @@
       DLOG(ERROR) << "GLImageDXGISwapChain::BindTexImage failed";
       return false;
     }
+
+    TRACE_EVENT0("gpu",
+                 "SharedImageBackingDXGISwapChain::PresentSwapChain::Flush");
+    // Flush device context through ANGLE otherwise present could be deferred.
+    api->glFlushFn();
     return true;
   }
 
@@ -290,7 +297,8 @@
 
 // static
 bool SwapChainFactoryDXGI::IsSupported() {
-  return gl::DirectCompositionSurfaceWin::IsDirectCompositionSupported();
+  return gl::DirectCompositionSurfaceWin::IsDirectCompositionSupported() &&
+         gl::DirectCompositionSurfaceWin::IsSwapChainTearingSupported();
 }
 
 std::unique_ptr<SharedImageBacking> SwapChainFactoryDXGI::MakeBacking(
@@ -413,7 +421,7 @@
   desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT;
   desc.Scaling = DXGI_SCALING_STRETCH;
   desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
-  desc.Flags = 0;
+  desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
 
   Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain;
 
diff --git a/gpu/ipc/client/shared_image_interface_proxy.cc b/gpu/ipc/client/shared_image_interface_proxy.cc
index 17c20a3..29126360 100644
--- a/gpu/ipc/client/shared_image_interface_proxy.cc
+++ b/gpu/ipc/client/shared_image_interface_proxy.cc
@@ -366,6 +366,7 @@
     last_flush_id_ = host_->EnqueueDeferredMessage(
         GpuChannelMsg_PresentSwapChain(route_id_, mailbox, release_id),
         std::move(dependencies));
+    host_->EnsureFlush(last_flush_id_);
   }
 #else
   NOTREACHED();
diff --git a/gpu/ipc/common/BUILD.gn b/gpu/ipc/common/BUILD.gn
index 50bab0e..25c3366 100644
--- a/gpu/ipc/common/BUILD.gn
+++ b/gpu/ipc/common/BUILD.gn
@@ -83,8 +83,6 @@
     "gpu_watchdog_timeout.h",
     "memory_stats.cc",
     "memory_stats.h",
-    "vulkan_ycbcr_info.cc",
-    "vulkan_ycbcr_info.h",
   ]
 
   if (is_mac) {
@@ -122,6 +120,7 @@
   public_deps = [
     ":command_buffer_traits_sources",
     ":surface_handle_type",
+    ":vulkan_ycbcr_info",
     "//ipc",
     "//url/ipc:url_ipc",
   ]
@@ -190,6 +189,16 @@
   ]
 }
 
+source_set("vulkan_ycbcr_info") {
+  sources = [
+    "vulkan_ycbcr_info.cc",
+    "vulkan_ycbcr_info.h",
+  ]
+  deps = [
+    "//base",
+  ]
+}
+
 mojom("interfaces") {
   sources = [
     "capabilities.mojom",
@@ -254,6 +263,7 @@
   deps = [
     ":interfaces_shared_cpp_sources",
     ":surface_handle_type",
+    ":vulkan_ycbcr_info",
     "//gpu/command_buffer/common",
     "//gpu/ipc/common",
     "//mojo/public/cpp/bindings:bindings",
diff --git a/gpu/ipc/common/vulkan_ycbcr_info.cc b/gpu/ipc/common/vulkan_ycbcr_info.cc
index ac0fbbe9..e6d7fab 100644
--- a/gpu/ipc/common/vulkan_ycbcr_info.cc
+++ b/gpu/ipc/common/vulkan_ycbcr_info.cc
@@ -4,21 +4,28 @@
 
 #include "gpu/ipc/common/vulkan_ycbcr_info.h"
 
+#include "base/logging.h"
+
 namespace gpu {
 
 VulkanYCbCrInfo::VulkanYCbCrInfo() = default;
 
-VulkanYCbCrInfo::VulkanYCbCrInfo(uint32_t suggested_ycbcr_model,
+VulkanYCbCrInfo::VulkanYCbCrInfo(uint32_t image_format,
+                                 uint64_t external_format,
+                                 uint32_t suggested_ycbcr_model,
                                  uint32_t suggested_ycbcr_range,
                                  uint32_t suggested_xchroma_offset,
                                  uint32_t suggested_ychroma_offset,
-                                 uint64_t external_format,
                                  uint32_t format_features)
-    : suggested_ycbcr_model(suggested_ycbcr_model),
+    : image_format(image_format),
+      external_format(external_format),
+      suggested_ycbcr_model(suggested_ycbcr_model),
       suggested_ycbcr_range(suggested_ycbcr_range),
       suggested_xchroma_offset(suggested_xchroma_offset),
       suggested_ychroma_offset(suggested_ychroma_offset),
-      external_format(external_format),
-      format_features(format_features) {}
+      format_features(format_features) {
+  // One and only one of the format fields must be non-zero.
+  DCHECK((image_format == 0) ^ (external_format == 0));
+}
 
 }  // namespace gpu
diff --git a/gpu/ipc/common/vulkan_ycbcr_info.h b/gpu/ipc/common/vulkan_ycbcr_info.h
index 4ac1728..2c99091 100644
--- a/gpu/ipc/common/vulkan_ycbcr_info.h
+++ b/gpu/ipc/common/vulkan_ycbcr_info.h
@@ -7,20 +7,28 @@
 
 #include <stdint.h>
 
-#include "gpu/gpu_export.h"
-
 namespace gpu {
 
 // Sampler Ycbcr conversion information.
-struct GPU_EXPORT VulkanYCbCrInfo {
+struct VulkanYCbCrInfo {
   VulkanYCbCrInfo();
-  VulkanYCbCrInfo(uint32_t suggested_ycbcr_model,
+  VulkanYCbCrInfo(uint32_t image_format,
+                  uint64_t external_format,
+                  uint32_t suggested_ycbcr_model,
                   uint32_t suggested_ycbcr_range,
                   uint32_t suggested_xchroma_offset,
                   uint32_t suggested_ychroma_offset,
-                  uint64_t external_format,
                   uint32_t format_features);
 
+  // Source image format.
+  // Corresponds to vulkan type: VkFormat.
+  uint32_t image_format;
+
+  // Implementation-defined external format identifier for use with
+  // VkExternalFormatANDROID.
+  // This property is driver specific.
+  uint64_t external_format;
+
   // Describes the color matrix for conversion between color models.
   // Corresponds to vulkan type: VkSamplerYcbcrModelConversion.
   uint32_t suggested_ycbcr_model;
@@ -42,14 +50,9 @@
   // Corresponds to vulkan type: VkChromaLocation.
   uint32_t suggested_ychroma_offset;
 
-  // Implementation-defined external format identifier for use with
-  // VkExternalFormatANDROID.
-  // This property is driver specific.
-  uint64_t external_format;
-
-  // Describes the capabilities of the external format when used with an image
-  // bound to memory imported from buffer.
-  // Corresponds to vulkan type: VkFormatFeatureFlags.
+  // Describes the capabilities of the format when used with an image bound to
+  // memory imported from buffer. Corresponds to vulkan type:
+  // VkFormatFeatureFlags.
   uint32_t format_features;
 };
 
diff --git a/gpu/ipc/common/vulkan_ycbcr_info.mojom b/gpu/ipc/common/vulkan_ycbcr_info.mojom
index 4c755cea..c606dd5 100644
--- a/gpu/ipc/common/vulkan_ycbcr_info.mojom
+++ b/gpu/ipc/common/vulkan_ycbcr_info.mojom
@@ -10,10 +10,11 @@
 // in chrome.
 // See gpu/ipc/common/vulkan_ycbcr_info.h.
 struct VulkanYCbCrInfo {
+  uint32 image_format;
+  uint64 external_format;
   uint32 suggested_ycbcr_model;
   uint32 suggested_ycbcr_range;
   uint32 suggested_xchroma_offset;
   uint32 suggested_ychroma_offset;
-  uint64 external_format;
   uint32 format_features;
 };
diff --git a/gpu/ipc/common/vulkan_ycbcr_info_mojom_traits.h b/gpu/ipc/common/vulkan_ycbcr_info_mojom_traits.h
index 88e8aa95..1cf343e6 100644
--- a/gpu/ipc/common/vulkan_ycbcr_info_mojom_traits.h
+++ b/gpu/ipc/common/vulkan_ycbcr_info_mojom_traits.h
@@ -12,6 +12,14 @@
 
 template <>
 struct StructTraits<gpu::mojom::VulkanYCbCrInfoDataView, gpu::VulkanYCbCrInfo> {
+  static uint32_t image_format(const gpu::VulkanYCbCrInfo& info) {
+    return info.image_format;
+  }
+
+  static uint64_t external_format(const gpu::VulkanYCbCrInfo& info) {
+    return info.external_format;
+  }
+
   static uint32_t suggested_ycbcr_model(const gpu::VulkanYCbCrInfo& info) {
     return info.suggested_ycbcr_model;
   }
@@ -28,21 +36,18 @@
     return info.suggested_ychroma_offset;
   }
 
-  static uint64_t external_format(const gpu::VulkanYCbCrInfo& info) {
-    return info.external_format;
-  }
-
   static uint32_t format_features(const gpu::VulkanYCbCrInfo& info) {
     return info.format_features;
   }
 
   static bool Read(gpu::mojom::VulkanYCbCrInfoDataView data,
                    gpu::VulkanYCbCrInfo* out) {
+    out->image_format = data.image_format();
+    out->external_format = data.external_format();
     out->suggested_ycbcr_model = data.suggested_ycbcr_model();
     out->suggested_ycbcr_range = data.suggested_ycbcr_range();
     out->suggested_xchroma_offset = data.suggested_xchroma_offset();
     out->suggested_ychroma_offset = data.suggested_ychroma_offset();
-    out->external_format = data.external_format();
     out->format_features = data.format_features();
     return true;
   }
diff --git a/gpu/vulkan/android/BUILD.gn b/gpu/vulkan/android/BUILD.gn
index b78a2ac..b56b34b 100644
--- a/gpu/vulkan/android/BUILD.gn
+++ b/gpu/vulkan/android/BUILD.gn
@@ -24,7 +24,8 @@
   defines = [ "IS_VULKAN_ANDROID_IMPL" ]
 
   deps = [
-    "//gpu/ipc/common:common",
+    "//gpu/ipc/common",
+    "//gpu/ipc/common:vulkan_ycbcr_info",
     "//ui/gfx",
   ]
 
diff --git a/gpu/vulkan/android/vulkan_implementation_android.cc b/gpu/vulkan/android/vulkan_implementation_android.cc
index dc64c36f..ccff9c94 100644
--- a/gpu/vulkan/android/vulkan_implementation_android.cc
+++ b/gpu/vulkan/android/vulkan_implementation_android.cc
@@ -52,19 +52,14 @@
   return true;
 }
 
-void PopulateYcbcrInfo(
-    const VkAndroidHardwareBufferFormatPropertiesANDROID& ahb_format_props,
-    VulkanYCbCrInfo* ycbcr_info) {
-  DCHECK(ycbcr_info);
-
-  ycbcr_info->suggested_ycbcr_model = ahb_format_props.suggestedYcbcrModel;
-  ycbcr_info->suggested_ycbcr_range = ahb_format_props.suggestedYcbcrRange;
-  ycbcr_info->suggested_xchroma_offset =
-      ahb_format_props.suggestedXChromaOffset;
-  ycbcr_info->suggested_ychroma_offset =
-      ahb_format_props.suggestedYChromaOffset;
-  ycbcr_info->external_format = ahb_format_props.externalFormat;
-  ycbcr_info->format_features = ahb_format_props.formatFeatures;
+VulkanYCbCrInfo GetYcbcrInfoFromBufferProps(
+    const VkAndroidHardwareBufferFormatPropertiesANDROID& ahb_format_props) {
+  return VulkanYCbCrInfo(VK_FORMAT_UNDEFINED, ahb_format_props.externalFormat,
+                         ahb_format_props.suggestedYcbcrModel,
+                         ahb_format_props.suggestedYcbcrRange,
+                         ahb_format_props.suggestedXChromaOffset,
+                         ahb_format_props.suggestedYChromaOffset,
+                         ahb_format_props.formatFeatures);
 }
 
 }  // namespace
@@ -189,7 +184,8 @@
     VkImage* vk_image,
     VkImageCreateInfo* vk_image_info,
     VkDeviceMemory* vk_device_memory,
-    VkDeviceSize* mem_allocation_size) {
+    VkDeviceSize* mem_allocation_size,
+    base::Optional<VulkanYCbCrInfo>* ycbcr_info) {
   // TODO(sergeyu): Move code from CreateVkImageAndImportAHB() here and remove
   // CreateVkImageAndImportAHB().
   NOTIMPLEMENTED();
@@ -371,7 +367,7 @@
 
   *mem_allocation_size = mem_alloc_info.allocationSize;
   if (ycbcr_info)
-    PopulateYcbcrInfo(ahb_format_props, ycbcr_info);
+    *ycbcr_info = GetYcbcrInfoFromBufferProps(ahb_format_props);
   return true;
 }
 
@@ -387,7 +383,7 @@
   if (!GetAhbProps(vk_device, ahb_handle.get(), &ahb_format_props, &ahb_props))
     return false;
 
-  PopulateYcbcrInfo(ahb_format_props, ycbcr_info);
+  *ycbcr_info = GetYcbcrInfoFromBufferProps(ahb_format_props);
   return true;
 }
 
diff --git a/gpu/vulkan/android/vulkan_implementation_android.h b/gpu/vulkan/android/vulkan_implementation_android.h
index 798a525..2f141cf9 100644
--- a/gpu/vulkan/android/vulkan_implementation_android.h
+++ b/gpu/vulkan/android/vulkan_implementation_android.h
@@ -50,7 +50,8 @@
       VkImage* vk_image,
       VkImageCreateInfo* vk_image_info,
       VkDeviceMemory* vk_device_memory,
-      VkDeviceSize* mem_allocation_size) override;
+      VkDeviceSize* mem_allocation_size,
+      base::Optional<VulkanYCbCrInfo>* ycbcr_info) override;
   bool CreateVkImageAndImportAHB(
       const VkDevice& vk_device,
       const VkPhysicalDevice& vk_physical_device,
diff --git a/gpu/vulkan/vulkan_device_queue.cc b/gpu/vulkan/vulkan_device_queue.cc
index 73a5ac7..6e351fa 100644
--- a/gpu/vulkan/vulkan_device_queue.cc
+++ b/gpu/vulkan/vulkan_device_queue.cc
@@ -133,7 +133,7 @@
     if (desired_layers.find(layer_property.layerName) != desired_layers.end())
       enabled_layer_names.push_back(layer_property.layerName);
   }
-#endif
+#endif  // DCHECK_IS_ON()
 
   std::vector<const char*> enabled_extensions;
   enabled_extensions.insert(std::end(enabled_extensions),
@@ -143,7 +143,8 @@
   uint32_t device_api_version =
       std::min(max_api_version, vk_physical_device_properties_.apiVersion);
 
-#if defined(OS_ANDROID)
+  // Android and Fuchsia need YCbCr sampler support.
+#if defined(OS_ANDROID) || defined(OS_FUCHSIA)
   if (!vkGetPhysicalDeviceFeatures2) {
     DLOG(ERROR) << "Vulkan 1.1 or VK_KHR_get_physical_device_properties2 "
                    "extension is required.";
@@ -151,54 +152,52 @@
   }
 
   // Query if VkPhysicalDeviceSamplerYcbcrConversionFeatures is supported by
-  // the implementation. This extension must be supported for android.
-  sampler_ycbcr_conversion_features_.sType =
-      VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES;
+  // the implementation. This extension must be supported for Android and
+  // Fuchsia.
   sampler_ycbcr_conversion_features_.pNext = nullptr;
-
-  // Add VkPhysicalDeviceSamplerYcbcrConversionFeatures struct to pNext chain
-  // of VkPhysicalDeviceFeatures2.
-  enabled_device_features_2_.sType =
-      VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
-  enabled_device_features_2_.pNext = &sampler_ycbcr_conversion_features_;
+  VkPhysicalDeviceFeatures2 supported_device_features_2 = {
+      VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
+      &sampler_ycbcr_conversion_features_};
   vkGetPhysicalDeviceFeatures2(vk_physical_device_,
-                               &enabled_device_features_2_);
+                               &supported_device_features_2);
   if (!sampler_ycbcr_conversion_features_.samplerYcbcrConversion) {
-    LOG(ERROR) << "samplerYcbcrConversion is not supported";
+    LOG(ERROR) << "samplerYcbcrConversion is not supported.";
     return false;
   }
 
-  // Disable all physical device features by default.
-  memset(&enabled_device_features_2_.features, 0,
-         sizeof(enabled_device_features_2_.features));
-#elif defined(OS_FUCHSIA)
-  // Used to Query if VkPhysicalDeviceProtectedMemoryFeatures is supported by
-  // the implementation on fuchsia.
-  VkPhysicalDeviceProtectedMemoryFeatures protected_memory_features = {
-      VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES};
-  protected_memory_features.protectedMemory = VK_TRUE;
+  // Add VkPhysicalDeviceSamplerYcbcrConversionFeatures struct to pNext chain
+  // of VkPhysicalDeviceFeatures2 to enable YCbCr sampler support.
+  sampler_ycbcr_conversion_features_.pNext = enabled_device_features_2_.pNext;
+  enabled_device_features_2_.pNext = &sampler_ycbcr_conversion_features_;
+#endif  // defined(OS_ANDROID) || defined(OS_FUCHSIA)
 
+#if defined(OS_FUCHSIA)
   if (allow_protected_memory) {
     if (device_api_version < VK_MAKE_VERSION(1, 1, 0)) {
       DLOG(ERROR) << "Vulkan 1.1 is required for protected memory";
       return false;
     }
 
-    enabled_device_features_2_.sType =
-        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
-    enabled_device_features_2_.pNext = &protected_memory_features;
+    protected_memory_features_.pNext = nullptr;
+    VkPhysicalDeviceFeatures2 supported_device_features_2 = {
+        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
+        &protected_memory_features_};
     vkGetPhysicalDeviceFeatures2(vk_physical_device_,
-                                 &enabled_device_features_2_);
-    if (!protected_memory_features.protectedMemory) {
+                                 &supported_device_features_2);
+    if (!protected_memory_features_.protectedMemory) {
       DLOG(ERROR) << "Protected memory is not supported";
       return false;
     }
 
-    // Disable all physical device features by default.
-    memset(&enabled_device_features_2_.features, 0,
-           sizeof(enabled_device_features_2_.features));
+    // Add VkPhysicalDeviceProtectedMemoryFeatures struct to pNext chain
+    // of VkPhysicalDeviceFeatures2 to enable YCbCr sampler support.
+    protected_memory_features_.pNext = enabled_device_features_2_.pNext;
+    enabled_device_features_2_.pNext = &protected_memory_features_;
   }
-#endif
+#endif  // defined(OS_FUCHSIA)
+
+  // Disable all physical device features by default.
+  enabled_device_features_2_.features = {};
 
   VkDeviceCreateInfo device_create_info = {};
   device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
diff --git a/gpu/vulkan/vulkan_device_queue.h b/gpu/vulkan/vulkan_device_queue.h
index c550980..db8800f 100644
--- a/gpu/vulkan/vulkan_device_queue.h
+++ b/gpu/vulkan/vulkan_device_queue.h
@@ -103,14 +103,22 @@
   uint32_t vk_queue_index_ = 0;
   const VkInstance vk_instance_;
   std::unique_ptr<VulkanFenceHelper> cleanup_helper_;
-  VkPhysicalDeviceFeatures2 enabled_device_features_2_ = {};
+  VkPhysicalDeviceFeatures2 enabled_device_features_2_ = {
+      VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
+
   const bool enforce_protected_memory_;
   bool allow_protected_memory_ = false;
 
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(OS_FUCHSIA)
   VkPhysicalDeviceSamplerYcbcrConversionFeatures
-      sampler_ycbcr_conversion_features_ = {};
-#endif
+      sampler_ycbcr_conversion_features_ = {
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES};
+#endif  // defined(OS_ANDROID) || defined(OS_FUCHSIA)
+
+#if defined(OS_FUCHSIA)
+  VkPhysicalDeviceProtectedMemoryFeatures protected_memory_features_ = {
+      VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES};
+#endif  // defined(OS_FUCHSIA)
 
   DISALLOW_COPY_AND_ASSIGN(VulkanDeviceQueue);
 };
diff --git a/gpu/vulkan/vulkan_implementation.h b/gpu/vulkan/vulkan_implementation.h
index db6a738..69bc0d8 100644
--- a/gpu/vulkan/vulkan_implementation.h
+++ b/gpu/vulkan/vulkan_implementation.h
@@ -11,6 +11,7 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "base/optional.h"
 #include "build/build_config.h"
 #include "gpu/vulkan/semaphore_handle.h"
 #include "gpu/vulkan/vulkan_export.h"
@@ -107,7 +108,8 @@
       VkImage* vk_image,
       VkImageCreateInfo* vk_image_info,
       VkDeviceMemory* vk_device_memory,
-      VkDeviceSize* mem_allocation_size) = 0;
+      VkDeviceSize* mem_allocation_size,
+      base::Optional<VulkanYCbCrInfo>* ycbcr_info) = 0;
 
 #if defined(OS_ANDROID)
   // Create a VkImage, import Android AHardwareBuffer object created outside of
diff --git a/gpu/vulkan/win32/vulkan_implementation_win32.cc b/gpu/vulkan/win32/vulkan_implementation_win32.cc
index 61b5a44..c59f36d 100644
--- a/gpu/vulkan/win32/vulkan_implementation_win32.cc
+++ b/gpu/vulkan/win32/vulkan_implementation_win32.cc
@@ -142,7 +142,8 @@
     VkImage* vk_image,
     VkImageCreateInfo* vk_image_info,
     VkDeviceMemory* vk_device_memory,
-    VkDeviceSize* mem_allocation_size) {
+    VkDeviceSize* mem_allocation_size,
+    base::Optional<VulkanYCbCrInfo>* ycbcr_info) {
   NOTIMPLEMENTED();
   return false;
 }
diff --git a/gpu/vulkan/win32/vulkan_implementation_win32.h b/gpu/vulkan/win32/vulkan_implementation_win32.h
index bbce467d..4d18e4f6 100644
--- a/gpu/vulkan/win32/vulkan_implementation_win32.h
+++ b/gpu/vulkan/win32/vulkan_implementation_win32.h
@@ -48,7 +48,8 @@
       VkImage* vk_image,
       VkImageCreateInfo* vk_image_info,
       VkDeviceMemory* vk_device_memory,
-      VkDeviceSize* mem_allocation_size) override;
+      VkDeviceSize* mem_allocation_size,
+      base::Optional<VulkanYCbCrInfo>* ycbcr_info) override;
 
  private:
   VulkanInstance vulkan_instance_;
diff --git a/gpu/vulkan/x/vulkan_implementation_x11.cc b/gpu/vulkan/x/vulkan_implementation_x11.cc
index 378ce1b4..39bef0a6 100644
--- a/gpu/vulkan/x/vulkan_implementation_x11.cc
+++ b/gpu/vulkan/x/vulkan_implementation_x11.cc
@@ -170,7 +170,8 @@
     VkImage* vk_image,
     VkImageCreateInfo* vk_image_info,
     VkDeviceMemory* vk_device_memory,
-    VkDeviceSize* mem_allocation_size) {
+    VkDeviceSize* mem_allocation_size,
+    base::Optional<VulkanYCbCrInfo>* ycbcr_info) {
   NOTIMPLEMENTED();
   return false;
 }
diff --git a/gpu/vulkan/x/vulkan_implementation_x11.h b/gpu/vulkan/x/vulkan_implementation_x11.h
index c9345f7..7a4b0c5 100644
--- a/gpu/vulkan/x/vulkan_implementation_x11.h
+++ b/gpu/vulkan/x/vulkan_implementation_x11.h
@@ -49,7 +49,8 @@
       VkImage* vk_image,
       VkImageCreateInfo* vk_image_info,
       VkDeviceMemory* vk_device_memory,
-      VkDeviceSize* mem_allocation_size) override;
+      VkDeviceSize* mem_allocation_size,
+      base::Optional<VulkanYCbCrInfo>* ycbcr_info) override;
 
  private:
   bool using_surface_ = true;
diff --git a/infra/config/commit-queue.cfg b/infra/config/commit-queue.cfg
index 4756be7..6bf6c37 100644
--- a/infra/config/commit-queue.cfg
+++ b/infra/config/commit-queue.cfg
@@ -204,6 +204,7 @@
       }
       builders {
         name: "chromium/try/dawn-linux-x64-deps-rel"
+        location_regexp: ".+/[+]/gpu/.+"
         location_regexp: ".+/[+]/testing/buildbot/chromium.dawn.json"
         location_regexp: ".+/[+]/third_party/blink/renderer/modules/webgpu/.+"
         location_regexp: ".+/[+]/third_party/blink/web_tests/FlagExpectations/enable-unsafe-webgpu"
diff --git a/infra/config/cr-buildbucket.cfg b/infra/config/cr-buildbucket.cfg
index 19f6bde..6dabf09 100644
--- a/infra/config/cr-buildbucket.cfg
+++ b/infra/config/cr-buildbucket.cfg
@@ -774,9 +774,9 @@
 builder_mixins {
   name: "xcode-caches"
   caches: {
-    # Cache for Xcode 10.1 (build version 10b61) needed for iOS builds.
-    name: "xcode_ios_10b61"
-    path: "xcode_ios_10b61.app"
+    # Cache for Xcode 10.1 (build version 11m382q) needed for iOS builds.
+    name: "xcode_ios_11m382q"
+    path: "xcode_ios_11m382q.app"
   }
 }
 
@@ -1284,6 +1284,7 @@
       name: "android-sdk-packager"
       mixins: "linux-xenial"
       mixins: "builderless"
+      service_account: "chromium-cipd-builder@chops-service-accounts.iam.gserviceaccount.com"
       recipe {
         name: "android/sdk_packager"
         properties_j: <<END
@@ -1815,6 +1816,14 @@
     }
 
     builders {
+      name: "Linux FYI Release (Intel UHD 630)"
+      mixins: "linux-gpu-fyi-ci-tester"
+      # TODO(https://crbug.com/986939): Remove this increased timeout once more
+      # devices are added.
+      execution_timeout_secs: 64800 # 18h.
+    }
+
+    builders {
       name: "Linux FYI dEQP Release (Intel HD 630)"
       mixins: "linux-gpu-fyi-ci-tester"
     }
@@ -2289,6 +2298,14 @@
       name: "GPU Win Builder (dbg)"
       mixins: "win-gpu-ci"
     }
+    builders {
+      name: "GPU Win x64 Builder"
+      mixins: "win-gpu-ci"
+    }
+    builders {
+      name: "GPU Win x64 Builder (dbg)"
+      mixins: "win-gpu-ci"
+    }
     # Note that the Win testers are all thin Linux VMs, triggering jobs on the
     # physical Win hardware in the Swarming pool, and therefore use the
     # linux-gpu-ci-tester mixin.
@@ -2300,7 +2317,14 @@
       name: "Win10 Release (NVIDIA)"
       mixins: "linux-gpu-ci-tester"
     }
-
+    builders {
+      name: "Win10 x64 Debug (NVIDIA)"
+      mixins: "linux-gpu-ci-tester"
+    }
+    builders {
+      name: "Win10 x64 Release (NVIDIA)"
+      mixins: "linux-gpu-ci-tester"
+    }
     # chromium.gpu.fyi
     builders {
       name: "GPU FYI Win Builder"
diff --git a/infra/config/luci-milo.cfg b/infra/config/luci-milo.cfg
index 262f79e..2bf46ec 100644
--- a/infra/config/luci-milo.cfg
+++ b/infra/config/luci-milo.cfg
@@ -3119,6 +3119,14 @@
     category: "Windows"
   }
   builders {
+    name: "buildbucket/luci.chromium.ci/GPU Win x64 Builder"
+    category: "Windows"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.ci/GPU Win x64 Builder (dbg)"
+    category: "Windows"
+  }
+  builders {
     name: "buildbucket/luci.chromium.ci/Win10 Debug (NVIDIA)"
     category: "Windows"
   }
@@ -3127,6 +3135,14 @@
     category: "Windows"
   }
   builders {
+    name: "buildbucket/luci.chromium.ci/Win10 x64 Debug (NVIDIA)"
+    category: "Windows"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.ci/Win10 x64 Release (NVIDIA)"
+    category: "Windows"
+  }
+  builders {
     name: "buildbucket/luci.chromium.ci/GPU Mac Builder"
     category: "Mac"
   }
@@ -3425,6 +3441,11 @@
     short_name: "rel"
   }
   builders {
+    name: "buildbucket/luci.chromium.ci/Linux FYI Release (Intel UHD 630)"
+    category: "Linux|Intel"
+    short_name: "uhd"
+  }
+  builders {
     name: "buildbucket/luci.chromium.ci/Linux FYI dEQP Release (Intel HD 630)"
     category: "Linux|Intel"
     short_name: "dqp"
diff --git a/infra/config/luci-scheduler.cfg b/infra/config/luci-scheduler.cfg
index 0554925..f3ff451 100644
--- a/infra/config/luci-scheduler.cfg
+++ b/infra/config/luci-scheduler.cfg
@@ -170,6 +170,8 @@
   triggers: "GPU Mac Builder"
   triggers: "GPU Win Builder (dbg)"
   triggers: "GPU Win Builder"
+  triggers: "GPU Win x64 Builder (dbg)"
+  triggers: "GPU Win x64 Builder"
   triggers: "Jumbo Linux x64"
   triggers: "Jumbo Mac"
   triggers: "Jumbo Win x64"
@@ -1530,6 +1532,17 @@
 }
 
 job {
+  id: "Linux FYI Release (Intel UHD 630)"
+  # Triggered by "GPU FYI Linux Builder".
+  acl_sets: "triggered-by-parent-builders"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Linux FYI Release (Intel UHD 630)"
+  }
+}
+
+job {
   id: "Linux FYI dEQP Release (Intel HD 630)"
   # Triggered by "GPU FYI Linux dEQP Builder".
   acl_sets: "triggered-by-parent-builders"
@@ -3042,6 +3055,48 @@
 }
 
 job {
+  id: "GPU Win x64 Builder"
+  acl_sets: "default"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "GPU Win x64 Builder"
+  }
+}
+
+job {
+  id: "Win10 x64 Release (NVIDIA)"
+  # Triggered by "GPU Win x64 Builder"
+  acl_sets: "triggered-by-parent-builders"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Win10 x64 Release (NVIDIA)"
+  }
+}
+
+job {
+  id: "GPU Win x64 Builder (dbg)"
+  acl_sets: "default"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "GPU Win x64 Builder (dbg)"
+  }
+}
+
+job {
+  id: "Win10 x64 Debug (NVIDIA)"
+  # Triggered by "GPU Win x64 Builder (dbg)"
+  acl_sets: "triggered-by-parent-builders"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Win10 x64 Debug (NVIDIA)"
+  }
+}
+
+job {
   id: "Win Builder (dbg)"
   acl_sets: "default"
   buildbucket: {
diff --git a/ios/build/bots/chromium.clang/ToTiOS.json b/ios/build/bots/chromium.clang/ToTiOS.json
index 777c747..5afbaf1c 100644
--- a/ios/build/bots/chromium.clang/ToTiOS.json
+++ b/ios/build/bots/chromium.clang/ToTiOS.json
@@ -2,7 +2,7 @@
   "comments": [
     "Clang tip-of-tree builder for iOS."
   ],
-  "xcode build version": "10b61",
+  "xcode build version": "11m382q",
   "gn_args": [
     "ios_enable_code_signing=false",
     "is_component_build=false",
@@ -22,119 +22,119 @@
     {
       "app": "base_unittests",
       "device type": "iPhone 6s",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool": "Chrome",
       "os": "12.1"
     },
     {
       "app": "boringssl_crypto_tests",
       "device type": "iPhone 6s",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool": "Chrome",
       "os": "12.1"
     },
     {
       "app": "boringssl_ssl_tests",
       "device type": "iPhone 6s",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool": "Chrome",
       "os": "12.1"
     },
     {
       "app": "components_unittests",
       "device type": "iPhone 6s",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool": "Chrome",
       "os": "12.1"
     },
     {
       "app": "crypto_unittests",
       "device type": "iPhone 6s",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool": "Chrome",
       "os": "12.1"
     },
     {
       "app": "gfx_unittests",
       "device type": "iPhone 6s",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool": "Chrome",
       "os": "12.1"
     },
     {
       "app": "google_apis_unittests",
       "device type": "iPhone 6s",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool": "Chrome",
       "os": "12.1"
     },
     {
       "app": "ios_chrome_unittests",
       "device type": "iPhone 6s",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool": "Chrome",
       "os": "12.1"
     },
     {
       "app": "ios_net_unittests",
       "device type": "iPhone 6s",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool": "Chrome",
       "os": "12.1"
     },
     {
       "app": "ios_web_inttests",
       "device type": "iPhone 6s",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool": "Chrome",
       "os": "12.1"
     },
     {
       "app": "ios_web_unittests",
       "device type": "iPhone 6s",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool": "Chrome",
       "os": "12.1"
     },
     {
       "app": "ios_web_view_inttests",
       "device type": "iPhone 6s",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool": "Chrome",
       "os": "12.1"
     },
     {
       "app": "net_unittests",
       "device type": "iPhone 6s",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool": "Chrome",
       "os": "12.1"
     },
     {
       "app": "skia_unittests",
       "device type": "iPhone 6s",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool": "Chrome",
       "os": "12.1"
     },
     {
       "app": "sql_unittests",
       "device type": "iPhone 6s",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool": "Chrome",
       "os": "12.1"
     },
     {
       "app": "ui_base_unittests",
       "device type": "iPhone 6s",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool": "Chrome",
       "os": "12.1"
     },
     {
       "app": "url_unittests",
       "device type": "iPhone 6s",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool": "Chrome",
       "os": "12.1"
     }
diff --git a/ios/build/bots/chromium.clang/ToTiOSDevice.json b/ios/build/bots/chromium.clang/ToTiOSDevice.json
index f3c769ca0..ccef88a 100644
--- a/ios/build/bots/chromium.clang/ToTiOSDevice.json
+++ b/ios/build/bots/chromium.clang/ToTiOSDevice.json
@@ -2,7 +2,7 @@
   "comments": [
     "Clang tip-of-tree builder for iOS device."
   ],
-  "xcode build version": "10b61",
+  "xcode build version": "11m382q",
   "gn_args": [
     "is_debug=false",
     "llvm_force_head_revision=true",
@@ -37,103 +37,86 @@
     {
       "app": "base_unittests",
       "device type": "iPhone 6s",
-      "xcode build version": "11m382q",
       "os": "12.3.1"
     },
     {
       "app": "boringssl_crypto_tests",
       "device type": "iPhone 6s",
-      "xcode build version": "11m382q",
       "os": "12.3.1"
     },
     {
       "app": "boringssl_ssl_tests",
       "device type": "iPhone 6s",
-      "xcode build version": "11m382q",
       "os": "12.3.1"
     },
     {
       "app": "components_unittests",
       "device type": "iPhone 6s",
-      "xcode build version": "11m382q",
       "os": "12.3.1"
     },
     {
       "app": "crypto_unittests",
       "device type": "iPhone 6s",
-      "xcode build version": "11m382q",
       "os": "12.3.1"
     },
     {
       "app": "gfx_unittests",
       "device type": "iPhone 6s",
-      "xcode build version": "11m382q",
       "os": "12.3.1"
     },
     {
       "app": "google_apis_unittests",
       "device type": "iPhone 6s",
-      "xcode build version": "11m382q",
       "os": "12.3.1"
     },
     {
       "app": "ios_chrome_unittests",
       "device type": "iPhone 6s",
-      "xcode build version": "11m382q",
       "os": "12.3.1"
     },
     {
       "app": "ios_net_unittests",
       "device type": "iPhone 6s",
-      "xcode build version": "11m382q",
       "os": "12.3.1"
     },
     {
       "app": "ios_web_inttests",
       "device type": "iPhone 6s",
-      "xcode build version": "11m382q",
       "os": "12.3.1"
     },
     {
       "app": "ios_web_unittests",
       "device type": "iPhone 6s",
-      "xcode build version": "11m382q",
       "os": "12.3.1"
     },
     {
       "app": "ios_web_view_inttests",
       "device type": "iPhone 6s",
-      "xcode build version": "11m382q",
       "os": "12.3.1"
     },
     {
       "app": "net_unittests",
       "device type": "iPhone 6s",
-      "xcode build version": "11m382q",
       "os": "12.3.1"
     },
     {
       "app": "skia_unittests",
       "device type": "iPhone 6s",
-      "xcode build version": "11m382q",
       "os": "12.3.1"
     },
     {
       "app": "sql_unittests",
       "device type": "iPhone 6s",
-      "xcode build version": "11m382q",
       "os": "12.3.1"
     },
     {
       "app": "ui_base_unittests",
       "device type": "iPhone 6s",
-      "xcode build version": "11m382q",
       "os": "12.3.1"
     },
     {
       "app": "url_unittests",
       "device type": "iPhone 6s",
-      "xcode build version": "11m382q",
       "os": "12.3.1"
     }
   ],
diff --git a/ios/build/bots/chromium.fyi/ios-device-goma-canary-clobber.json b/ios/build/bots/chromium.fyi/ios-device-goma-canary-clobber.json
index d89cf64f..bd5ca3a 100644
--- a/ios/build/bots/chromium.fyi/ios-device-goma-canary-clobber.json
+++ b/ios/build/bots/chromium.fyi/ios-device-goma-canary-clobber.json
@@ -3,7 +3,7 @@
     "Goma canary builder for iOS.",
     "It is chromium.mac/ios-device.json + use_goma_canary, clobber."
   ],
-  "xcode build version": "10b61",
+  "xcode build version": "11m382q",
   "gn_args": [
     "goma_dir=\"$(goma_dir)\"",
     "ios_enable_code_signing=false",
diff --git a/ios/build/bots/chromium.fyi/ios-device-goma-latest-clobber.json b/ios/build/bots/chromium.fyi/ios-device-goma-latest-clobber.json
index 70e71fe1..137bdbfb 100644
--- a/ios/build/bots/chromium.fyi/ios-device-goma-latest-clobber.json
+++ b/ios/build/bots/chromium.fyi/ios-device-goma-latest-clobber.json
@@ -3,7 +3,7 @@
     "Goma canary builder for iOS.",
     "It is chromium.mac/ios-device.json + use_goma_canary, clobber."
   ],
-  "xcode build version": "10b61",
+  "xcode build version": "11m382q",
   "gn_args": [
     "goma_dir=\"$(goma_dir)\"",
     "ios_enable_code_signing=false",
diff --git a/ios/build/bots/chromium.fyi/ios-simulator-cronet.json b/ios/build/bots/chromium.fyi/ios-simulator-cronet.json
index 05a098d..cdd4195 100644
--- a/ios/build/bots/chromium.fyi/ios-simulator-cronet.json
+++ b/ios/build/bots/chromium.fyi/ios-simulator-cronet.json
@@ -3,7 +3,7 @@
     "Cronet tests for 32- and 64-bit iOS 9.0 simulators.",
     "Tests run on iPhone 5s (64-bit) and iPad Retina (32-bit)."
   ],
-  "xcode build version": "10b61",
+  "xcode build version": "11m382q",
   "gn_args": [
     "additional_target_cpus=[\"x86\"]",
     "disable_brotli_filter=false",
@@ -27,106 +27,50 @@
       "app": "cronet_unittests_ios",
       "device type": "iPhone 5s",
       "os": "9.3",
-      "host os": "Mac-10.13.6",
-      "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      }
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome"
     },
     {
       "app": "cronet_test",
       "device type": "iPhone 5s",
       "os": "9.3",
-      "host os": "Mac-10.13.6",
-      "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      }
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome"
     },
     {
       "app": "cronet_test",
       "device type": "iPad Retina",
       "os": "9.3",
-      "host os": "Mac-10.13.6",
-      "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      }
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome"
     },
     {
       "app": "cronet_test",
       "device type": "iPhone 5s",
       "os": "11.4",
-      "host os": "Mac-10.13.6",
-      "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      }
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome"
     },
     {
       "app": "cronet_test",
       "device type": "iPad Air 2",
       "os": "11.4",
-      "host os": "Mac-10.13.6",
-      "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      }
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome"
     },
     {
       "app": "cronet_test",
       "device type": "iPhone X",
       "os": "11.4",
-      "host os": "Mac-10.13.6",
-      "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      }
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome"
     },
     {
       "app": "cronet_test",
       "device type": "iPhone X",
       "os": "12.1",
-      "host os": "Mac-10.13.6",
-      "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      }
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome"
     }
   ]
 }
diff --git a/ios/build/bots/chromium.fyi/ios-simulator.json b/ios/build/bots/chromium.fyi/ios-simulator.json
index 5104fe4..0d9481c0 100644
--- a/ios/build/bots/chromium.fyi/ios-simulator.json
+++ b/ios/build/bots/chromium.fyi/ios-simulator.json
@@ -2,7 +2,7 @@
   "comments": [
     "Runs tests on FYI on the latest simulators."
   ],
-  "xcode build version": "10b61",
+  "xcode build version": "11m382q",
   "gn_args": [
     "goma_dir=\"$(goma_dir)\"",
     "is_component_build=false",
@@ -21,16 +21,8 @@
       ],
       "device type": "iPhone 6s",
       "os": "12.1",
-      "host os": "Mac-10.13.6",
-      "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      }
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome"
     },
     {
       "app": "ios_chrome_integration_egtests",
@@ -40,16 +32,8 @@
       "device type": "iPhone 6s",
       "os": "12.1",
       "xctest": true,
-      "host os": "Mac-10.13.6",
-      "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      }
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome"
     },
     {
       "app": "ios_chrome_integration_egtests",
@@ -59,16 +43,8 @@
       "device type": "iPad Air 2",
       "os": "12.1",
       "xctest": true,
-      "host os": "Mac-10.13.6",
-      "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      }
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome"
     },
     {
       "app": "ios_chrome_integration_egtests",
@@ -78,16 +54,8 @@
       "device type": "iPhone 6s",
       "os": "12.1",
       "xctest": true,
-      "host os": "Mac-10.13.6",
-      "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      }
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome"
     },
     {
       "app": "ios_chrome_smoke_egtests",
@@ -97,16 +65,8 @@
       "device type": "iPhone 6s",
       "os": "12.1",
       "xctest": true,
-      "host os": "Mac-10.13.6",
-      "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      }
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome"
     },
     {
       "app": "ios_chrome_web_egtests",
@@ -116,16 +76,8 @@
       "device type": "iPhone 6s",
       "os": "12.1",
       "xctest": true,
-      "host os": "Mac-10.13.6",
-      "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-              "host os": "Mac-10.14.4"
-          }],
-          "60": [{
-              "host os": "Mac-10.14.3"
-          }]
-      }
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome"
     },
     {
       "app": "ios_web_shell_egtests",
@@ -135,16 +87,8 @@
       "device type": "iPhone 6s",
       "os": "12.1",
       "xctest": true,
-      "host os": "Mac-10.13.6",
-      "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      }
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome"
     },
     {
       "app": "ios_chrome_ui_egtests",
@@ -154,16 +98,8 @@
       "device type": "iPhone 6s",
       "os": "12.1",
       "xctest": true,
-      "host os": "Mac-10.13.6",
-      "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      }
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome"
     }
   ]
 }
diff --git a/ios/build/bots/chromium.fyi/ios13-sdk-device.json b/ios/build/bots/chromium.fyi/ios13-sdk-device.json
index fd1fd4e..1b4e4b3 100644
--- a/ios/build/bots/chromium.fyi/ios13-sdk-device.json
+++ b/ios/build/bots/chromium.fyi/ios13-sdk-device.json
@@ -3,7 +3,7 @@
     "Builder for Xcode 11 iOS 13 SDK",
     "Build is performed with gn+ninja."
   ],
-  "xcode build version": "10e125",
+  "xcode build version": "11m382q",
   "gn_args": [
     "goma_dir=\"$(goma_dir)\"",
     "ios_enable_code_signing=false",
diff --git a/ios/build/bots/chromium.mac/ios-device-xcode-clang.json b/ios/build/bots/chromium.mac/ios-device-xcode-clang.json
index 766c146..2e83f50 100644
--- a/ios/build/bots/chromium.mac/ios-device-xcode-clang.json
+++ b/ios/build/bots/chromium.mac/ios-device-xcode-clang.json
@@ -3,7 +3,7 @@
     "Builder for 32-bit devices.",
     "Build is performed with gn+ninja."
   ],
-  "xcode build version": "10b61",
+  "xcode build version": "11M382q",
   "gn_args": [
     "goma_dir=\"$(goma_dir)\"",
     "ios_enable_code_signing=false",
@@ -12,7 +12,7 @@
     "symbol_level=0",
     "target_cpu=\"arm64\"",
     "target_os=\"ios\"",
-    "use_goma=true",
+    "use_goma=false",
     "use_xcode_clang=true"
   ],
   "additional_compile_targets": [
diff --git a/ios/build/bots/chromium.mac/ios-device.json b/ios/build/bots/chromium.mac/ios-device.json
index ca354098..82c479f 100644
--- a/ios/build/bots/chromium.mac/ios-device.json
+++ b/ios/build/bots/chromium.mac/ios-device.json
@@ -4,7 +4,7 @@
     "Build is performed with gn+ninja.",
     "If modified, please change chromium.fyi/ios-device-goma-canary-clobber.json too."
   ],
-  "xcode build version": "10b61",
+  "xcode build version": "11M382q",
   "gn_args": [
     "goma_dir=\"$(goma_dir)\"",
     "ios_enable_code_signing=false",
diff --git a/ios/build/bots/chromium.mac/ios-simulator-cronet.json b/ios/build/bots/chromium.mac/ios-simulator-cronet.json
index 3689a5a4..e9d7b9f1 100644
--- a/ios/build/bots/chromium.mac/ios-simulator-cronet.json
+++ b/ios/build/bots/chromium.mac/ios-simulator-cronet.json
@@ -1,8 +1,8 @@
 {
   "comments": [
-    "Cronet tests 64-bit iOS 9.3, 10.3, 11.4 and 12 simulators."
+    "Cronet tests 64-bit iOS 9.3, 10.3, 11.4 and 12 and 13 simulators."
   ],
-  "xcode build version": "10b61",
+  "xcode build version": "11M382q",
   "gn_args": [
     "additional_target_cpus=[\"x86\"]",
     "disable_brotli_filter=false",
@@ -25,7 +25,7 @@
       "app": "cronet_unittests_ios",
       "device type": "iPhone 5s",
       "os": "9.3",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool": "Chrome",
       "priority": 30
     },
@@ -33,7 +33,7 @@
       "app": "cronet_unittests_ios",
       "device type": "iPhone 5s",
       "os": "11.4",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool": "Chrome",
       "priority": 30
     },
@@ -41,7 +41,7 @@
       "app": "cronet_unittests_ios",
       "device type": "iPhone 5s",
       "os": "12.1",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool": "Chrome",
       "priority": 30
     },
@@ -49,7 +49,7 @@
       "app": "cronet_test",
       "device type": "iPhone 5s",
       "os": "9.3",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool": "Chrome",
       "priority": 30
     },
@@ -57,7 +57,7 @@
       "app": "cronet_test",
       "device type": "iPad Air 2",
       "os": "11.4",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool": "Chrome",
       "priority": 30
     },
@@ -65,7 +65,7 @@
       "app": "cronet_test",
       "device type": "iPad Air 2",
       "os": "10.3",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool": "Chrome",
       "priority": 30
     },
@@ -73,7 +73,15 @@
       "app": "cronet_test",
       "device type": "iPad Air 2",
       "os": "12.1",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
+      "pool": "Chrome",
+      "priority": 30
+    },
+    {
+      "app": "cronet_test",
+      "device type": "iPad Air 2",
+      "os": "13.0",
+      "host os": "Mac-10.14.4",
       "pool": "Chrome",
       "priority": 30
     }
diff --git a/ios/build/bots/chromium.mac/ios-simulator-full-configs.json b/ios/build/bots/chromium.mac/ios-simulator-full-configs.json
index 35d159b..8b316a0 100644
--- a/ios/build/bots/chromium.mac/ios-simulator-full-configs.json
+++ b/ios/build/bots/chromium.mac/ios-simulator-full-configs.json
@@ -3,7 +3,7 @@
     "Runs tests on 64-bit iOS 11 and 12 tests on iPad, iPhone,",
     "@3x, and @2x on main waterfall ios-simulator-full-configs."
   ],
-  "xcode build version": "10b61",
+  "xcode build version": "11m382q",
   "gn_args": [
     "goma_dir=\"$(goma_dir)\"",
     "is_component_build=false",
@@ -22,80 +22,80 @@
       "include": "eg_tests.json",
       "device type": "iPhone 7",
       "os": "12.1",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      },
       "priority": 30
     },
     {
       "include": "eg_tests.json",
       "device type": "iPad Air 2",
       "os": "12.1",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      },
       "priority": 30
     },
     {
       "include": "eg_tests.json",
       "device type": "iPhone X",
       "os": "12.1",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      },
       "priority": 30
     },
     {
       "include": "eg_cq_tests.json",
       "device type": "iPhone X",
       "os": "12.1",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      },
       "priority": 30
     },
     {
       "include": "eg_cq_tests.json",
       "device type": "iPad Air 2",
       "os": "12.1",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      },
+      "priority": 30
+    },
+    {
+      "include": "eg_tests.json",
+      "device type": "iPhone 7",
+      "os": "13.0",
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome",
+      "priority": 30
+    },
+    {
+      "include": "eg_tests.json",
+      "device type": "iPad Air 2",
+      "os": "13.0",
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome",
+      "priority": 30
+    },
+    {
+      "include": "eg_tests.json",
+      "device type": "iPhone X",
+      "os": "13.0",
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome",
+      "priority": 30
+    },
+    {
+      "include": "eg_cq_tests.json",
+      "device type": "iPhone X",
+      "os": "13.0",
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome",
+      "priority": 30
+    },
+    {
+      "include": "eg_cq_tests.json",
+      "device type": "iPad Air 2",
+      "os": "13.0",
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome",
       "priority": 30
     }
   ]
diff --git a/ios/build/bots/chromium.mac/ios-simulator-xcode-clang.json b/ios/build/bots/chromium.mac/ios-simulator-xcode-clang.json
index 3f1cda60..489546d 100644
--- a/ios/build/bots/chromium.mac/ios-simulator-xcode-clang.json
+++ b/ios/build/bots/chromium.mac/ios-simulator-xcode-clang.json
@@ -4,7 +4,7 @@
     "This 'xcode build version' must exist in GOMA",
     "Build is performed with gn+ninja."
   ],
-  "xcode build version": "10b61",
+  "xcode build version": "11m382q",
   "use xcode build version": true,
   "gn_args": [
     "goma_dir=\"$(goma_dir)\"",
@@ -14,7 +14,7 @@
     "symbol_level=0",
     "target_cpu=\"x64\"",
     "target_os=\"ios\"",
-    "use_goma=true",
+    "use_goma=false",
     "use_xcode_clang=true"
   ],
   "env": {
diff --git a/ios/build/bots/chromium.mac/ios-simulator.json b/ios/build/bots/chromium.mac/ios-simulator.json
index 0736791..010fba6 100644
--- a/ios/build/bots/chromium.mac/ios-simulator.json
+++ b/ios/build/bots/chromium.mac/ios-simulator.json
@@ -4,7 +4,7 @@
     "main and CQ ios-simulator.",
     "Note: Xcode 10 requires Mac OS 10.13.4 or higher, hence 'host os'."
   ],
-  "xcode build version": "10b61",
+  "xcode build version": "11m382q",
   "gn_args": [
     "goma_dir=\"$(goma_dir)\"",
     "is_component_build=false",
@@ -23,80 +23,80 @@
       "include": "screen_size_dependent_tests.json",
       "device type": "iPhone 6s Plus",
       "os": "12.1",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      },
       "priority": 30
     },
     {
       "include": "screen_size_dependent_tests.json",
       "device type": "iPhone 6s",
       "os": "12.1",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      },
       "priority": 30
     },
     {
       "include": "common_tests.json",
       "device type": "iPhone 6s",
       "os": "12.1",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      },
       "priority": 30
     },
     {
       "include": "screen_size_dependent_tests.json",
       "device type": "iPad Air 2",
       "os": "12.1",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      },
       "priority": 30
     },
     {
       "include": "eg_cq_tests.json",
       "device type": "iPhone 6s",
       "os": "12.1",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      },
+      "priority": 30
+    },
+    {
+      "include": "screen_size_dependent_tests.json",
+      "device type": "iPhone 6s Plus",
+      "os": "13.0",
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome",
+      "priority": 30
+    },
+    {
+      "include": "screen_size_dependent_tests.json",
+      "device type": "iPhone 6s",
+      "os": "13.0",
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome",
+      "priority": 30
+    },
+    {
+      "include": "common_tests.json",
+      "device type": "iPhone 6s",
+      "os": "13.0",
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome",
+      "priority": 30
+    },
+    {
+      "include": "screen_size_dependent_tests.json",
+      "device type": "iPad Air 2",
+      "os": "13.0",
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome",
+      "priority": 30
+    },
+    {
+      "include": "eg_cq_tests.json",
+      "device type": "iPhone 6s",
+      "os": "13.0",
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome",
       "priority": 30
     }
   ]
diff --git a/ios/build/bots/chromium.mac/ios-slimnav.json b/ios/build/bots/chromium.mac/ios-slimnav.json
index 7dcefdf..67eb8f5 100644
--- a/ios/build/bots/chromium.mac/ios-slimnav.json
+++ b/ios/build/bots/chromium.mac/ios-slimnav.json
@@ -2,7 +2,7 @@
   "comments": [
     "Test the SlimNavigationManager feature."
   ],
-  "xcode build version": "10b61",
+  "xcode build version": "11m382q",
   "gn_args": [
     "goma_dir=\"$(goma_dir)\"",
     "is_component_build=false",
@@ -21,16 +21,8 @@
       ],
       "device type": "iPhone 6s Plus",
       "os": "12.1",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      },
       "priority": 30
     },
     {
@@ -40,16 +32,8 @@
       ],
       "device type": "iPhone 6s",
       "os": "12.1",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      },
       "priority": 30
     },
     {
@@ -59,16 +43,8 @@
       ],
       "device type": "iPhone 6s",
       "os": "12.1",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      },
       "priority": 30
     },
     {
@@ -78,16 +54,8 @@
       ],
       "device type": "iPad Air 2",
       "os": "12.1",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      },
       "priority": 30
     },
     {
@@ -97,16 +65,8 @@
       ],
       "device type": "iPhone 6s",
       "os": "12.1",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      },
       "priority": 30
     },
     {
@@ -119,16 +79,8 @@
       "device type": "iPad Air 2",
       "os": "12.1",
       "xctest": true,
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      },
       "priority": 30
     },
     {
@@ -139,16 +91,8 @@
       "device type": "iPad Air 2",
       "os": "12.1",
       "xctest": true,
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      },
       "priority": 30
     },
     {
@@ -159,16 +103,8 @@
       "device type": "iPad Air 2",
       "os": "12.1",
       "xctest": true,
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      },
       "priority": 30
     },
     {
@@ -179,16 +115,8 @@
       "device type": "iPad Air 2",
       "os": "12.1",
       "xctest": true,
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      },
       "priority": 30
     },
     {
@@ -199,16 +127,8 @@
       "device type": "iPad Air 2",
       "os": "12.1",
       "xctest": true,
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      },
       "priority": 30
     },
     {
@@ -219,16 +139,8 @@
       "device type": "iPad Air 2",
       "os": "12.1",
       "xctest": true,
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      },
       "priority": 30
     },
     {
@@ -241,16 +153,8 @@
       "device type": "iPhone X",
       "os": "12.1",
       "xctest": true,
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      },
       "priority": 30
     },
     {
@@ -261,16 +165,8 @@
       "device type": "iPhone X",
       "os": "12.1",
       "xctest": true,
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      },
       "priority": 30
     },
     {
@@ -281,16 +177,8 @@
       "device type": "iPhone X",
       "os": "12.1",
       "xctest": true,
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      },
       "priority": 30
     },
     {
@@ -301,16 +189,8 @@
       "device type": "iPhone X",
       "os": "12.1",
       "xctest": true,
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      },
       "priority": 30
     },
     {
@@ -321,16 +201,8 @@
       "device type": "iPhone X",
       "os": "12.1",
       "xctest": true,
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      },
       "priority": 30
     },
     {
@@ -341,16 +213,8 @@
       "device type": "iPhone X",
       "os": "12.1",
       "xctest": true,
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      },
       "priority": 30
     },
     {
@@ -360,16 +224,222 @@
       ],
       "device type": "iPhone X",
       "os": "12.1",
-      "host os": "Mac-10.13.6",
+      "host os": "Mac-10.14.4",
       "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.4"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      },
+      "priority": 30
+    },
+    {
+      "include": "screen_size_dependent_tests.json",
+      "test args": [
+        "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent"
+      ],
+      "device type": "iPhone 6s Plus",
+      "os": "13.0",
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome",
+      "priority": 30
+    },
+    {
+      "include": "screen_size_dependent_tests.json",
+      "test args": [
+        "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent"
+      ],
+      "device type": "iPhone 6s",
+      "os": "13.0",
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome",
+      "priority": 30
+    },
+    {
+      "include": "common_tests.json",
+      "test args": [
+        "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent"
+      ],
+      "device type": "iPhone 6s",
+      "os": "13.0",
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome",
+      "priority": 30
+    },
+    {
+      "include": "screen_size_dependent_tests.json",
+      "test args": [
+        "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent"
+      ],
+      "device type": "iPad Air 2",
+      "os": "13.0",
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome",
+      "priority": 30
+    },
+    {
+      "include": "eg_cq_tests.json",
+      "test args": [
+        "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent"
+      ],
+      "device type": "iPhone 6s",
+      "os": "13.0",
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome",
+      "priority": 30
+    },
+    {
+      "app": "ios_chrome_bookmarks_egtests",
+      "test args": [
+        "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent"
+      ],
+      "shards": 3,
+      "xcode parallelization": true,
+      "device type": "iPad Air 2",
+      "os": "13.0",
+      "xctest": true,
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome",
+      "priority": 30
+    },
+    {
+      "app": "ios_chrome_web_egtests",
+      "test args": [
+        "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent"
+      ],
+      "device type": "iPad Air 2",
+      "os": "13.0",
+      "xctest": true,
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome",
+      "priority": 30
+    },
+    {
+      "app": "ios_chrome_settings_egtests",
+      "test args": [
+        "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent"
+      ],
+      "device type": "iPad Air 2",
+      "os": "13.0",
+      "xctest": true,
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome",
+      "priority": 30
+    },
+    {
+      "app": "ios_chrome_translate_egtests",
+      "test args": [
+        "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent"
+      ],
+      "device type": "iPad Air 2",
+      "os": "13.0",
+      "xctest": true,
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome",
+      "priority": 30
+    },
+    {
+      "app": "ios_chrome_reading_list_egtests",
+      "test args": [
+        "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent"
+      ],
+      "device type": "iPad Air 2",
+      "os": "13.0",
+      "xctest": true,
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome",
+      "priority": 30
+    },
+    {
+      "app": "ios_showcase_egtests",
+      "test args": [
+        "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent"
+      ],
+      "device type": "iPad Air 2",
+      "os": "13.0",
+      "xctest": true,
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome",
+      "priority": 30
+    },
+    {
+      "app": "ios_chrome_bookmarks_egtests",
+      "test args": [
+        "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent"
+      ],
+      "shards": 3,
+      "xcode parallelization": true,
+      "device type": "iPhone X",
+      "os": "13.0",
+      "xctest": true,
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome",
+      "priority": 30
+    },
+    {
+      "app": "ios_chrome_web_egtests",
+      "test args": [
+        "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent"
+      ],
+      "device type": "iPhone X",
+      "os": "13.0",
+      "xctest": true,
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome",
+      "priority": 30
+    },
+    {
+      "app": "ios_chrome_settings_egtests",
+      "test args": [
+        "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent"
+      ],
+      "device type": "iPhone X",
+      "os": "13.0",
+      "xctest": true,
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome",
+      "priority": 30
+    },
+    {
+      "app": "ios_chrome_translate_egtests",
+      "test args": [
+        "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent"
+      ],
+      "device type": "iPhone X",
+      "os": "13.0",
+      "xctest": true,
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome",
+      "priority": 30
+    },
+    {
+      "app": "ios_chrome_reading_list_egtests",
+      "test args": [
+        "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent"
+      ],
+      "device type": "iPhone X",
+      "os": "13.0",
+      "xctest": true,
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome",
+      "priority": 30
+    },
+    {
+      "app": "ios_showcase_egtests",
+      "test args": [
+        "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent"
+      ],
+      "device type": "iPhone X",
+      "os": "13.0",
+      "xctest": true,
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome",
+      "priority": 30
+    },
+    {
+      "include": "eg_cq_tests.json",
+      "test args": [
+        "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent"
+      ],
+      "device type": "iPhone X",
+      "os": "13.0",
+      "host os": "Mac-10.14.4",
+      "pool":"Chrome",
       "priority": 30
     }
   ]
diff --git a/ios/build/bots/chromium.webrtc.fyi/WebRTC Chromium FYI ios-device.json b/ios/build/bots/chromium.webrtc.fyi/WebRTC Chromium FYI ios-device.json
index d591f35..652634cc 100644
--- a/ios/build/bots/chromium.webrtc.fyi/WebRTC Chromium FYI ios-device.json
+++ b/ios/build/bots/chromium.webrtc.fyi/WebRTC Chromium FYI ios-device.json
@@ -3,7 +3,7 @@
     "Builder for 64-bit devices.",
     "Build is performed with gn+ninja."
   ],
-  "xcode build version": "10b61",
+  "xcode build version": "11m382q",
   "gn_args": [
     "goma_dir=\"$(goma_dir)\"",
     "ios_enable_code_signing=false",
diff --git a/ios/build/bots/chromium.webrtc.fyi/WebRTC Chromium FYI ios-simulator.json b/ios/build/bots/chromium.webrtc.fyi/WebRTC Chromium FYI ios-simulator.json
index 806bb2c..535be8fbe 100644
--- a/ios/build/bots/chromium.webrtc.fyi/WebRTC Chromium FYI ios-simulator.json
+++ b/ios/build/bots/chromium.webrtc.fyi/WebRTC Chromium FYI ios-simulator.json
@@ -2,7 +2,7 @@
   "comments": [
     "Runs tests on @3x, @2x, 64-bit phone, tablet, iOS 11."
   ],
-  "xcode build version": "10b61",
+  "xcode build version": "11m382q",
   "gn_args": [
     "goma_dir=\"$(goma_dir)\"",
     "ios_enable_code_signing=false",
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index 83e9890..3da9143 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -2078,6 +2078,18 @@
        <message name="IDS_IOS_BOOKMARK_CONTEXT_MENU_EDIT_FOLDER" desc="Text on the bookmarks context menu to edit selected bookmark folder">
         Edit Folder
       </message>
+      <message name="IDS_IOS_VIEW_CONTROLLER_DISMISS_SAVE_CHANGES" desc="Text displayed on an alert button for Saving changes whenever trying
+      to dismiss a presented view with pending changes.">
+        Save Changes
+      </message>
+      <message name="IDS_IOS_VIEW_CONTROLLER_DISMISS_DISCARD_CHANGES" desc="Text displayed on an alert button for Discarding changes whenever trying
+      to dismiss a presented view with pending changes.">
+        Discard Changes
+      </message>
+      <message name="IDS_IOS_VIEW_CONTROLLER_DISMISS_CANCEL_CHANGES" desc="Text displayed on an alert button for Canceling the alert whenever trying
+      to dismiss a presented view with pending changes.">
+        Cancel
+      </message>
       <message name="IDS_IOS_OPEN_REPEATEDLY_ANOTHER_APP" desc="Alert to let the user know that the website is trying repeatedly to open another application. [iOS only]">
           This website is repeatedly trying to open another application.
       </message>
diff --git a/ios/chrome/browser/ui/badges/badge_button.h b/ios/chrome/browser/ui/badges/badge_button.h
index b2adfab..d9c134c 100644
--- a/ios/chrome/browser/ui/badges/badge_button.h
+++ b/ios/chrome/browser/ui/badges/badge_button.h
@@ -18,6 +18,9 @@
 // The badge type of the button.
 @property(nonatomic, assign, readonly) BadgeType badgeType;
 
+// Whether the button is in an accepted state.
+@property(nonatomic, assign, readonly) BOOL accepted;
+
 // Sets the badge color to the accepted color if |accepted| is YES or the
 // default color if |accepted| is NO. Will animate change if |animated| is YES.
 - (void)setAccepted:(BOOL)accepted animated:(BOOL)animated;
diff --git a/ios/chrome/browser/ui/badges/badge_button.mm b/ios/chrome/browser/ui/badges/badge_button.mm
index 75c88207..db79dcd1 100644
--- a/ios/chrome/browser/ui/badges/badge_button.mm
+++ b/ios/chrome/browser/ui/badges/badge_button.mm
@@ -24,6 +24,8 @@
 
 // Read/Write override.
 @property(nonatomic, assign, readwrite) BadgeType badgeType;
+// Read/Write override.
+@property(nonatomic, assign, readwrite) BOOL accepted;
 
 @end
 
@@ -49,6 +51,7 @@
 }
 
 - (void)setAccepted:(BOOL)accepted animated:(BOOL)animated {
+  self.accepted = accepted;
   void (^changeTintColor)() = ^{
     self.tintColor = accepted ? [UIColor colorNamed:kBlueColor]
                               : [UIColor colorNamed:kToolbarButtonColor];
diff --git a/ios/chrome/browser/ui/badges/badge_button_action_handler.mm b/ios/chrome/browser/ui/badges/badge_button_action_handler.mm
index ee2b3ce..7b05e6c 100644
--- a/ios/chrome/browser/ui/badges/badge_button_action_handler.mm
+++ b/ios/chrome/browser/ui/badges/badge_button_action_handler.mm
@@ -5,6 +5,8 @@
 #import "ios/chrome/browser/ui/badges/badge_button_action_handler.h"
 
 #include "base/mac/foundation_util.h"
+#include "base/metrics/user_metrics.h"
+#include "ios/chrome/browser/infobars/infobar_metrics_recorder.h"
 #import "ios/chrome/browser/infobars/infobar_type.h"
 #import "ios/chrome/browser/ui/badges/badge_button.h"
 #import "ios/chrome/browser/ui/commands/infobar_commands.h"
@@ -17,11 +19,28 @@
 
 - (void)passwordsBadgeButtonTapped:(id)sender {
   BadgeButton* badgeButton = base::mac::ObjCCastStrict<BadgeButton>(sender);
+  MobileMessagesBadgeState state;
+  if (badgeButton.accepted) {
+    state = MobileMessagesBadgeState::Active;
+    base::RecordAction(
+        base::UserMetricsAction("MobileMessagesBadgeAcceptedTapped"));
+  } else {
+    state = MobileMessagesBadgeState::Inactive;
+    base::RecordAction(
+        base::UserMetricsAction("MobileMessagesBadgeNonAcceptedTapped"));
+  }
+  InfobarMetricsRecorder* metricsRecorder;
   if (badgeButton.badgeType == BadgeType::kBadgeTypePasswordSave) {
+    metricsRecorder = [[InfobarMetricsRecorder alloc]
+        initWithType:InfobarType::kInfobarTypePasswordSave];
     [self.dispatcher displayModalInfobar:InfobarType::kInfobarTypePasswordSave];
   } else if (badgeButton.badgeType == BadgeType::kBadgeTypePasswordUpdate) {
-    [self.dispatcher displayModalInfobar:InfobarType::kInfobarTypePasswordSave];
+    metricsRecorder = [[InfobarMetricsRecorder alloc]
+        initWithType:InfobarType::kInfobarTypePasswordUpdate];
+    [self.dispatcher
+        displayModalInfobar:InfobarType::kInfobarTypePasswordUpdate];
   }
+  [metricsRecorder recordBadgeTappedInState:state];
 }
 
 @end
diff --git a/ios/chrome/browser/ui/bookmarks/BUILD.gn b/ios/chrome/browser/ui/bookmarks/BUILD.gn
index 6cbf9ec..3c9d1fc 100644
--- a/ios/chrome/browser/ui/bookmarks/BUILD.gn
+++ b/ios/chrome/browser/ui/bookmarks/BUILD.gn
@@ -31,6 +31,8 @@
     "bookmark_model_bridge_observer.mm",
     "bookmark_navigation_controller.h",
     "bookmark_navigation_controller.mm",
+    "bookmark_navigation_controller_delegate.h",
+    "bookmark_navigation_controller_delegate.mm",
     "bookmark_path_cache.h",
     "bookmark_path_cache.mm",
     "bookmark_promo_controller.h",
@@ -90,6 +92,7 @@
     "//ios/chrome/browser/ui/ntp",
     "//ios/chrome/browser/ui/signin_interaction/public",
     "//ios/chrome/browser/ui/table_view",
+    "//ios/chrome/browser/ui/table_view:feature_flags",
     "//ios/chrome/browser/ui/table_view:presentation",
     "//ios/chrome/browser/ui/table_view:styler",
     "//ios/chrome/browser/ui/util",
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.h b/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.h
index 1c5fb8c3..67d0a49 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.h
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.h
@@ -46,7 +46,8 @@
 // This view controller will also monitor bookmark model change events and react
 // accordingly depending on whether the bookmark and folder it is editing
 // changes underneath it.
-@interface BookmarkEditViewController : ChromeTableViewController
+@interface BookmarkEditViewController
+    : ChromeTableViewController <UIAdaptivePresentationControllerDelegate>
 
 @property(nonatomic, weak) id<BookmarkEditViewControllerDelegate> delegate;
 
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm
index 97e17dd..bab68798 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm
@@ -19,6 +19,7 @@
 #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/system_flags.h"
+#import "ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_folder_view_controller.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_mediator.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.h"
@@ -123,6 +124,9 @@
 // YES if the URL item is displaying a valid URL.
 @property(nonatomic, assign) BOOL displayingValidURL;
 
+// The action sheet coordinator, if one is currently being shown.
+@property(nonatomic, strong) ActionSheetCoordinator* actionSheetCoordinator;
+
 // Reports the changes to the delegate, that has the responsibility to save the
 // bookmark.
 - (void)commitBookmarkChanges;
@@ -337,7 +341,7 @@
 }
 
 - (void)dismiss {
-  [self.view resignFirstResponder];
+  [self.view endEditing:YES];
 
   // Dismiss this controller.
   [self.delegate bookmarkEditorWantsDismissal:self];
@@ -467,6 +471,11 @@
 #pragma mark - BookmarkTextFieldItemDelegate
 
 - (void)textDidChangeForItem:(BookmarkTextFieldItem*)item {
+  if (@available(iOS 13, *)) {
+#if defined(__IPHONE_13_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0)
+    self.modalInPresentation = YES;
+#endif
+  }
   [self updateSaveButtonState];
   if (self.displayingValidURL != [self inputURLIsValid]) {
     self.displayingValidURL = [self inputURLIsValid];
@@ -623,6 +632,57 @@
   [self.delegate bookmarkEditorWantsDismissal:self];
 }
 
+#pragma mark - UIAdaptivePresentationControllerDelegate
+
+- (void)presentationControllerDidAttemptToDismiss:
+    (UIPresentationController*)presentationController {
+  self.actionSheetCoordinator = [[ActionSheetCoordinator alloc]
+      initWithBaseViewController:self
+                           title:nil
+                         message:nil
+                   barButtonItem:self.cancelItem];
+
+  __weak __typeof(self) weakSelf = self;
+  [self.actionSheetCoordinator
+      addItemWithTitle:l10n_util::GetNSString(
+                           IDS_IOS_VIEW_CONTROLLER_DISMISS_SAVE_CHANGES)
+                action:^{
+                  [weakSelf save];
+                }
+                 style:UIAlertActionStyleDefault];
+  [self.actionSheetCoordinator
+      addItemWithTitle:l10n_util::GetNSString(
+                           IDS_IOS_VIEW_CONTROLLER_DISMISS_DISCARD_CHANGES)
+                action:^{
+                  [weakSelf cancel];
+                }
+                 style:UIAlertActionStyleDestructive];
+  [self.actionSheetCoordinator
+      addItemWithTitle:l10n_util::GetNSString(
+                           IDS_IOS_VIEW_CONTROLLER_DISMISS_CANCEL_CHANGES)
+                action:^{
+                  weakSelf.navigationItem.leftBarButtonItem.enabled = YES;
+                  weakSelf.navigationItem.rightBarButtonItem.enabled = YES;
+                }
+                 style:UIAlertActionStyleCancel];
+
+  self.navigationItem.leftBarButtonItem.enabled = NO;
+  self.navigationItem.rightBarButtonItem.enabled = NO;
+  [self.actionSheetCoordinator start];
+}
+
+- (void)presentationControllerWillDismiss:
+    (UIPresentationController*)presentationController {
+  // Resign first responder if trying to dismiss the VC so the keyboard doesn't
+  // linger until the VC dismissal has completed.
+  [self.view endEditing:YES];
+}
+
+- (void)presentationControllerDidDismiss:
+    (UIPresentationController*)presentationController {
+  [self dismiss];
+}
+
 #pragma mark - UIResponder
 
 - (NSArray*)keyCommands {
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.h b/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.h
index 36dc418..4b4b762 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.h
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.h
@@ -41,7 +41,8 @@
 // the title and selecting the parent folder of the bookmark.
 // This controller monitors the state of the bookmark model, so changes to the
 // bookmark model can affect this controller's state.
-@interface BookmarkFolderEditorViewController : ChromeTableViewController
+@interface BookmarkFolderEditorViewController
+    : ChromeTableViewController <UIAdaptivePresentationControllerDelegate>
 
 @property(nonatomic, weak) id<BookmarkFolderEditorViewControllerDelegate>
     delegate;
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.mm
index 9a7fce19..ab803a6 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.mm
@@ -14,6 +14,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/browser/bookmark_node.h"
+#import "ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_folder_view_controller.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_ui_constants.h"
@@ -70,6 +71,8 @@
 @property(nonatomic, weak) UIBarButtonItem* doneItem;
 @property(nonatomic, strong) BookmarkTextFieldItem* titleItem;
 @property(nonatomic, strong) BookmarkParentFolderItem* parentFolderItem;
+// The action sheet coordinator, if one is currently being shown.
+@property(nonatomic, strong) ActionSheetCoordinator* actionSheetCoordinator;
 
 // |bookmarkModel| must not be NULL and must be loaded.
 - (instancetype)initWithBookmarkModel:(bookmarks::BookmarkModel*)bookmarkModel
@@ -191,7 +194,7 @@
     UIBarButtonItem* cancelItem = [[UIBarButtonItem alloc]
         initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
                              target:self
-                             action:@selector(cancel)];
+                             action:@selector(dismiss)];
     cancelItem.accessibilityIdentifier = @"Cancel";
     self.navigationItem.leftBarButtonItem = cancelItem;
 
@@ -201,7 +204,7 @@
     UIBarButtonItem* backItem =
         [ChromeIcon templateBarButtonItemWithImage:[ChromeIcon backIcon]
                                             target:self
-                                            action:@selector(back)];
+                                            action:@selector(dismiss)];
     backItem.accessibilityLabel =
         l10n_util::GetNSString(IDS_IOS_BOOKMARK_NEW_BACK_LABEL);
     backItem.accessibilityIdentifier = @"Back";
@@ -230,17 +233,14 @@
 #pragma mark - Accessibility
 
 - (BOOL)accessibilityPerformEscape {
-  [self.delegate bookmarkFolderEditorDidCancel:self];
+  [self dismiss];
   return YES;
 }
 
 #pragma mark - Actions
 
-- (void)back {
-  [self.delegate bookmarkFolderEditorDidCancel:self];
-}
-
-- (void)cancel {
+- (void)dismiss {
+  [self.view endEditing:YES];
   [self.delegate bookmarkFolderEditorDidCancel:self];
 }
 
@@ -285,6 +285,7 @@
     self.folder = self.bookmarkModel->AddFolder(
         self.parentFolder, self.parentFolder->children().size(), folderTitle);
   }
+  [self.view endEditing:YES];
   [self.delegate bookmarkFolderEditor:self didFinishEditingFolder:self.folder];
 }
 
@@ -378,6 +379,11 @@
 #pragma mark - BookmarkTextFieldItemDelegate
 
 - (void)textDidChangeForItem:(BookmarkTextFieldItem*)item {
+  if (@available(iOS 13, *)) {
+#if defined(__IPHONE_13_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0)
+    self.modalInPresentation = YES;
+#endif
+  }
   [self updateSaveButtonState];
 }
 
@@ -405,6 +411,58 @@
   }
 }
 
+#pragma mark - UIAdaptivePresentationControllerDelegate
+
+- (void)presentationControllerDidAttemptToDismiss:
+    (UIPresentationController*)presentationController {
+  self.actionSheetCoordinator = [[ActionSheetCoordinator alloc]
+      initWithBaseViewController:self
+                           title:nil
+                         message:nil
+                   barButtonItem:self.navigationItem.leftBarButtonItem];
+
+  __weak __typeof(self) weakSelf = self;
+  [self.actionSheetCoordinator
+      addItemWithTitle:l10n_util::GetNSString(
+                           IDS_IOS_VIEW_CONTROLLER_DISMISS_SAVE_CHANGES)
+                action:^{
+                  [weakSelf saveFolder];
+                }
+                 style:UIAlertActionStyleDefault];
+  [self.actionSheetCoordinator
+      addItemWithTitle:l10n_util::GetNSString(
+                           IDS_IOS_VIEW_CONTROLLER_DISMISS_DISCARD_CHANGES)
+                action:^{
+                  [weakSelf dismiss];
+                }
+                 style:UIAlertActionStyleDestructive];
+  // IDS_IOS_NAVIGATION_BAR_CANCEL_BUTTON
+  [self.actionSheetCoordinator
+      addItemWithTitle:l10n_util::GetNSString(
+                           IDS_IOS_VIEW_CONTROLLER_DISMISS_CANCEL_CHANGES)
+                action:^{
+                  weakSelf.navigationItem.leftBarButtonItem.enabled = YES;
+                  weakSelf.navigationItem.rightBarButtonItem.enabled = YES;
+                }
+                 style:UIAlertActionStyleCancel];
+
+  self.navigationItem.leftBarButtonItem.enabled = NO;
+  self.navigationItem.rightBarButtonItem.enabled = NO;
+  [self.actionSheetCoordinator start];
+}
+
+- (void)presentationControllerWillDismiss:
+    (UIPresentationController*)presentationController {
+  // Resign first responder if trying to dismiss the VC so the keyboard doesn't
+  // linger until the VC dismissal has completed.
+  [self.view endEditing:YES];
+}
+
+- (void)presentationControllerDidDismiss:
+    (UIPresentationController*)presentationController {
+  [self dismiss];
+}
+
 #pragma mark - Private
 
 - (void)setParentFolder:(const BookmarkNode*)parentFolder {
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.h b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.h
index 0188897..ab010bc 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.h
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.h
@@ -42,7 +42,8 @@
 @end
 
 // Class to navigate the bookmark hierarchy.
-@interface BookmarkHomeViewController : ChromeTableViewController
+@interface BookmarkHomeViewController
+    : ChromeTableViewController <UIAdaptivePresentationControllerDelegate>
 
 // Delegate for presenters. Note that this delegate is currently being set only
 // in case of handset, and not tablet. In the future it will be used by both
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
index e2488a7b..368bc64 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
@@ -1982,4 +1982,21 @@
   }
 }
 
+#pragma mark UIAdaptivePresentationControllerDelegate
+
+- (void)presentationControllerWillDismiss:
+    (UIPresentationController*)presentationController {
+  if (self.searchController.active) {
+    // Dismiss the keyboard if trying to dismiss the VC so the keyboard doesn't
+    // linger until the VC dismissal has completed.
+    [self.searchController.searchBar endEditing:YES];
+  }
+}
+
+- (void)presentationControllerDidDismiss:
+    (UIPresentationController*)presentationController {
+  // Cleanup once the dismissal is complete.
+  [self dismissWithURL:GURL()];
+}
+
 @end
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm
index d542d5b..27e1e84 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm
@@ -24,14 +24,15 @@
 #import "ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller_delegate.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_mediator.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller.h"
+#import "ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller_delegate.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_path_cache.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_transitioning_delegate.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/commands/browser_commands.h"
 #import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
+#import "ios/chrome/browser/ui/table_view/feature_flags.h"
 #import "ios/chrome/browser/ui/table_view/table_view_navigation_controller.h"
-#import "ios/chrome/browser/ui/table_view/table_view_navigation_controller_delegate.h"
 #import "ios/chrome/browser/ui/table_view/table_view_presentation_controller.h"
 #import "ios/chrome/browser/ui/table_view/table_view_presentation_controller_delegate.h"
 #include "ios/chrome/browser/ui/util/uikit_ui_util.h"
@@ -95,7 +96,7 @@
 
 // The delegate provided to |self.bookmarkNavigationController|.
 @property(nonatomic, strong)
-    TableViewNavigationControllerDelegate* bookmarkNavigationControllerDelegate;
+    BookmarkNavigationControllerDelegate* bookmarkNavigationControllerDelegate;
 
 // The bookmark model in use.
 @property(nonatomic, assign) BookmarkModel* bookmarkModel;
@@ -255,7 +256,8 @@
     return;
   }
 
-  ChromeTableViewController* editorController = nil;
+  ChromeTableViewController<UIAdaptivePresentationControllerDelegate>*
+      editorController = nil;
   if (node->type() == BookmarkNode::URL) {
     self.currentPresentedState = PresentedState::BOOKMARK_EDITOR;
     BookmarkEditViewController* bookmarkEditor =
@@ -309,30 +311,33 @@
     [self openUrls:urlsToOpen inIncognito:inIncognito newTab:newTab];
   }
 
-  [_parentController
-      dismissViewControllerAnimated:animated
-                         completion:^{
-                           // TODO(crbug.com/940856): Make sure navigaton
-                           // controller doesn't keep any controllers. Without
-                           // this there's a memory leak of (almost) every BHVC
-                           // the user visits.
-                           [self.bookmarkNavigationController
-                               setViewControllers:@[]
-                                         animated:NO];
+  ProceduralBlock completion = ^{
+    // TODO(crbug.com/940856): Make sure navigaton
+    // controller doesn't keep any controllers. Without
+    // this there's a memory leak of (almost) every BHVC
+    // the user visits.
+    [self.bookmarkNavigationController setViewControllers:@[] animated:NO];
 
-                           self.bookmarkBrowser.homeDelegate = nil;
-                           self.bookmarkBrowser = nil;
-                           self.bookmarkTransitioningDelegate = nil;
-                           self.bookmarkNavigationController = nil;
-                           self.bookmarkNavigationControllerDelegate = nil;
+    self.bookmarkBrowser.homeDelegate = nil;
+    self.bookmarkBrowser = nil;
+    self.bookmarkTransitioningDelegate = nil;
+    self.bookmarkNavigationController = nil;
+    self.bookmarkNavigationControllerDelegate = nil;
 
-                           if (!openUrlsAfterDismissal) {
-                             return;
-                           }
-                           [self openUrls:urlsToOpenAfterDismissal
-                               inIncognito:inIncognito
-                                    newTab:newTab];
-                         }];
+    if (!openUrlsAfterDismissal) {
+      return;
+    }
+    [self openUrls:urlsToOpenAfterDismissal
+        inIncognito:inIncognito
+             newTab:newTab];
+  };
+
+  if (_parentController.presentedViewController) {
+    [_parentController dismissViewControllerAnimated:animated
+                                          completion:completion];
+  } else {
+    completion();
+  }
   self.currentPresentedState = PresentedState::NONE;
 }
 
@@ -512,7 +517,9 @@
 // transition requires those objects.  If |replacementViewControllers| is not
 // nil, those controllers are swapped in to the UINavigationController instead
 // of |viewController|.
-- (void)presentTableViewController:(ChromeTableViewController*)viewController
+- (void)presentTableViewController:
+            (ChromeTableViewController<
+                UIAdaptivePresentationControllerDelegate>*)viewController
     withReplacementViewControllers:
         (NSArray<ChromeTableViewController*>*)replacementViewControllers {
   TableViewNavigationController* navController =
@@ -524,23 +531,36 @@
 
   navController.toolbarHidden = YES;
   self.bookmarkNavigationControllerDelegate =
-      [[TableViewNavigationControllerDelegate alloc] init];
+      [[BookmarkNavigationControllerDelegate alloc] init];
   navController.delegate = self.bookmarkNavigationControllerDelegate;
-  self.bookmarkTransitioningDelegate =
-      [[BookmarkTransitioningDelegate alloc] init];
-  self.bookmarkTransitioningDelegate.presentationControllerModalDelegate = self;
-  navController.transitioningDelegate = self.bookmarkTransitioningDelegate;
-  navController.modalPresentationStyle = UIModalPresentationCustom;
+
+  BOOL useCustomPresentation = YES;
+  if (IsCollectionsCardPresentationStyleEnabled()) {
+    if (@available(iOS 13, *)) {
+#if defined(__IPHONE_13_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0)
+      [navController setModalPresentationStyle:UIModalPresentationFormSheet];
+      useCustomPresentation = NO;
+#endif
+    }
+  }
+
+  if (useCustomPresentation) {
+    self.bookmarkTransitioningDelegate =
+        [[BookmarkTransitioningDelegate alloc] init];
+    self.bookmarkTransitioningDelegate.presentationControllerModalDelegate =
+        self;
+    navController.transitioningDelegate = self.bookmarkTransitioningDelegate;
+    navController.modalPresentationStyle = UIModalPresentationCustom;
+    TableViewPresentationController* presentationController =
+        base::mac::ObjCCastStrict<TableViewPresentationController>(
+            navController.presentationController);
+    self.bookmarkNavigationControllerDelegate.modalController =
+        presentationController;
+  }
 
   [_parentController presentViewController:navController
                                   animated:YES
                                 completion:nil];
-
-  TableViewPresentationController* presentationController =
-      base::mac::ObjCCastStrict<TableViewPresentationController>(
-          navController.presentationController);
-  self.bookmarkNavigationControllerDelegate.modalController =
-      presentationController;
 }
 
 - (void)openURLInCurrentTab:(const GURL&)url {
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller_delegate.h b/ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller_delegate.h
new file mode 100644
index 0000000..efeafe9
--- /dev/null
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller_delegate.h
@@ -0,0 +1,24 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_NAVIGATION_CONTROLLER_DELEGATE_H_
+#define IOS_CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_NAVIGATION_CONTROLLER_DELEGATE_H_
+
+#import <UIKit/UIKit.h>
+
+@protocol TableViewModalPresenting;
+
+// BookmarkNavigationControllerDelegate serves as a delegate for
+// TableViewNavigationController. It uses |modalController| to update the modal
+// presentation state when view controllers are pushed onto or popped off of the
+// navigation stack.
+@interface BookmarkNavigationControllerDelegate
+    : NSObject <UINavigationControllerDelegate>
+
+// An object which controls the modal presentation of the navigation controller.
+@property(nonatomic, weak) id<TableViewModalPresenting> modalController;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_NAVIGATION_CONTROLLER_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/table_view/table_view_navigation_controller_delegate.mm b/ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller_delegate.mm
similarity index 67%
rename from ios/chrome/browser/ui/table_view/table_view_navigation_controller_delegate.mm
rename to ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller_delegate.mm
index dd4621f..8d34a4e 100644
--- a/ios/chrome/browser/ui/table_view/table_view_navigation_controller_delegate.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller_delegate.mm
@@ -2,24 +2,35 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ios/chrome/browser/ui/table_view/table_view_navigation_controller_delegate.h"
+#import "ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller_delegate.h"
 
 #include "base/mac/foundation_util.h"
 #import "ios/chrome/browser/ui/table_view/chrome_table_view_controller.h"
+#import "ios/chrome/browser/ui/table_view/feature_flags.h"
 #import "ios/chrome/browser/ui/table_view/table_view_modal_presenting.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
-@implementation TableViewNavigationControllerDelegate
-@synthesize modalController = _modalController;
+@implementation BookmarkNavigationControllerDelegate
 
 - (void)navigationController:(UINavigationController*)navigationController
       willShowViewController:(UIViewController*)viewController
                     animated:(BOOL)animated {
   BOOL shouldDismissOnTouchOutside = YES;
 
+  if (IsCollectionsCardPresentationStyleEnabled()) {
+    if (@available(iOS 13, *)) {
+      UIViewController<UIAdaptivePresentationControllerDelegate>*
+          adaptiveViewController = base::mac::ObjCCast<
+              UIViewController<UIAdaptivePresentationControllerDelegate>>(
+              viewController);
+      navigationController.presentationController.delegate =
+          adaptiveViewController;
+    }
+  }
+
   ChromeTableViewController* tableViewController =
       base::mac::ObjCCast<ChromeTableViewController>(viewController);
   if (tableViewController) {
diff --git a/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm b/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
index d936060..f1fa2e5 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
@@ -9,6 +9,7 @@
 
 #include "base/format_macros.h"
 #include "base/ios/ios_util.h"
+#include "base/mac/foundation_util.h"
 #include "base/strings/sys_string_conversions.h"
 #import "base/test/ios/wait_util.h"
 #include "base/test/scoped_feature_list.h"
@@ -1496,12 +1497,20 @@
 
 // Scroll the bookmarks to top.
 + (void)scrollToTop {
-  // Provide a start points since it prevents some tests timing out under
-  // certain configurations.
+  // On iOS 13 the settings menu appears as a card that can be dismissed with a
+  // downward swipe, for this reason we need to swipe up programatically to
+  // avoid dismissin the VC.
+  GREYPerformBlock scrollToTopBlock =
+      ^BOOL(id element, __strong NSError** error) {
+        UIScrollView* view = base::mac::ObjCCastStrict<UIScrollView>(element);
+        view.contentOffset = CGPointZero;
+        return YES;
+      };
+
   [[EarlGrey
       selectElementWithMatcher:grey_accessibilityID(@"bookmarksTableView")]
-      performAction:grey_scrollToContentEdgeWithStartPoint(kGREYContentEdgeTop,
-                                                           0.5, 0.5)];
+      performAction:[GREYActionBlock actionWithName:@"Scroll to top"
+                                       performBlock:scrollToTopBlock]];
 }
 
 // Scroll the bookmarks to bottom.
@@ -3954,6 +3963,7 @@
 
   // Interrupt the folder name editing by entering Folder 1
   [BookmarksTestCase scrollToTop];
+
   [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Folder 1")]
       performAction:grey_tap()];
   // Come back to Mobile Bookmarks.
@@ -3970,6 +3980,7 @@
 
   // Interrupt the folder name editing by tapping on First URL.
   [BookmarksTestCase scrollToTop];
+
   [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"First URL")]
       performAction:grey_tap()];
   // Reopen bookmarks.
diff --git a/ios/chrome/browser/ui/history/history_ui_egtest.mm b/ios/chrome/browser/ui/history/history_ui_egtest.mm
index e1d307e..093fc4f 100644
--- a/ios/chrome/browser/ui/history/history_ui_egtest.mm
+++ b/ios/chrome/browser/ui/history/history_ui_egtest.mm
@@ -405,7 +405,7 @@
 }
 
 // Tests that the VC can be dismissed by swiping down.
-- (void)testSwipeDownDismiss {
+- (void)DISABLED_testSwipeDownDismiss {
   if (!base::ios::IsRunningOnOrLater(13, 0, 0)) {
     EARL_GREY_TEST_SKIPPED(@"Test disabled on iOS 12 and lower.");
   }
@@ -429,7 +429,7 @@
 }
 
 // Tests that the VC can be dismissed by swiping down while its searching.
-- (void)testSwipeDownDismissWhileSearching {
+- (void)DISABLED_testSwipeDownDismissWhileSearching {
   if (!base::ios::IsRunningOnOrLater(13, 0, 0)) {
     EARL_GREY_TEST_SKIPPED(@"Test disabled on iOS 12 and lower.");
   }
diff --git a/ios/chrome/browser/ui/ntp_tile_views/ntp_shortcut_tile_view.mm b/ios/chrome/browser/ui/ntp_tile_views/ntp_shortcut_tile_view.mm
index f4ca471..db3f766 100644
--- a/ios/chrome/browser/ui/ntp_tile_views/ntp_shortcut_tile_view.mm
+++ b/ios/chrome/browser/ui/ntp_tile_views/ntp_shortcut_tile_view.mm
@@ -4,6 +4,7 @@
 
 #import "ios/chrome/browser/ui/ntp_tile_views/ntp_shortcut_tile_view.h"
 
+#import "ios/chrome/common/colors/semantic_color_names.h"
 #import "ios/chrome/common/ui_util/constraints_ui_util.h"
 #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 
@@ -27,6 +28,7 @@
   if (self) {
     _iconView = [[UIImageView alloc] initWithFrame:self.bounds];
     _iconView.translatesAutoresizingMaskIntoConstraints = NO;
+    _iconView.tintColor = [UIColor colorNamed:kBlueColor];
 
     [self.imageContainerView addSubview:_iconView];
     AddSameConstraints(self.imageContainerView, _iconView);
@@ -36,7 +38,7 @@
     ]];
 
     self.imageBackgroundView.tintColor =
-        [UIColor colorWithRed:0.91 green:0.95 blue:0.99 alpha:1.0];
+        [[UIColor colorNamed:kBlueColor] colorWithAlphaComponent:0.1];
   }
   return self;
 }
@@ -44,7 +46,7 @@
 - (UILabel*)countLabel {
   if (!_countLabel) {
     _countContainer = [[UIView alloc] init];
-    _countContainer.backgroundColor = [UIColor whiteColor];
+    _countContainer.backgroundColor = [UIColor colorNamed:kBackgroundColor];
     // Unfortunately, simply setting a CALayer borderWidth and borderColor
     // on |_countContainer|, and setting a background color on |_countLabel|
     // will result in the inner color bleeeding thru to the outside.
@@ -54,10 +56,9 @@
     _countLabel = [[UILabel alloc] init];
     _countLabel.layer.cornerRadius = kCountWidth / 2;
     _countLabel.layer.masksToBounds = YES;
-    _countLabel.textColor = [UIColor whiteColor];
+    _countLabel.textColor = [UIColor colorNamed:kSolidButtonTextColor];
     _countLabel.textAlignment = NSTextAlignmentCenter;
-    _countLabel.backgroundColor =
-        [UIColor colorWithRed:0.10 green:0.45 blue:0.91 alpha:1.0];
+    _countLabel.backgroundColor = [UIColor colorNamed:kBlueColor];
 
     _countContainer.translatesAutoresizingMaskIntoConstraints = NO;
     _countLabel.translatesAutoresizingMaskIntoConstraints = NO;
@@ -82,11 +83,4 @@
   return _countLabel;
 }
 
-+ (UIImage*)backgroundImage {
-  // This subclass uses tintColor on the background view, so use template
-  // rendering mode.
-  return [[super backgroundImage]
-      imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
-}
-
 @end
diff --git a/ios/chrome/browser/ui/ntp_tile_views/ntp_tile_view.h b/ios/chrome/browser/ui/ntp_tile_views/ntp_tile_view.h
index d4b1a774..1ee715ff 100644
--- a/ios/chrome/browser/ui/ntp_tile_views/ntp_tile_view.h
+++ b/ios/chrome/browser/ui/ntp_tile_views/ntp_tile_view.h
@@ -22,9 +22,6 @@
 @property(nonatomic, strong, readonly, nonnull)
     UIImageView* imageBackgroundView;
 
-// Image to be used as the image background. The default is the grey squircle.
-+ (nonnull UIImage*)backgroundImage;
-
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_NTP_TILE_VIEWS_NTP_TILE_VIEW_H_
diff --git a/ios/chrome/browser/ui/ntp_tile_views/ntp_tile_view.mm b/ios/chrome/browser/ui/ntp_tile_views/ntp_tile_view.mm
index 81990c3be..96d69d0 100644
--- a/ios/chrome/browser/ui/ntp_tile_views/ntp_tile_view.mm
+++ b/ios/chrome/browser/ui/ntp_tile_views/ntp_tile_view.mm
@@ -6,6 +6,7 @@
 
 #import "ios/chrome/browser/ui/util/dynamic_type_util.h"
 #import "ios/chrome/common/colors/UIColor+cr_semantic_colors.h"
+#import "ios/chrome/common/colors/semantic_color_names.h"
 #import "ios/chrome/common/ui_util/constraints_ui_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -43,7 +44,10 @@
     UIImageView* backgroundView =
         [[UIImageView alloc] initWithFrame:self.bounds];
     backgroundView.translatesAutoresizingMaskIntoConstraints = NO;
-    backgroundView.image = [[self class] backgroundImage];
+    UIImage* backgroundImage = [[UIImage imageNamed:@"ntp_most_visited_tile"]
+        imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
+    backgroundView.image = backgroundImage;
+    backgroundView.tintColor = [UIColor colorNamed:kGrey100Color];
     [self addSubview:backgroundView];
     [self addSubview:_imageContainerView];
 
@@ -75,10 +79,6 @@
       UIContentSizeCategoryAccessibilityLarge);
 }
 
-+ (UIImage*)backgroundImage {
-  return [UIImage imageNamed:@"ntp_most_visited_tile"];
-}
-
 #pragma mark - UIView
 
 - (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection {
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_egtest.mm b/ios/chrome/browser/ui/recent_tabs/recent_tabs_egtest.mm
index 3570436..6c6d8a3 100644
--- a/ios/chrome/browser/ui/recent_tabs/recent_tabs_egtest.mm
+++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_egtest.mm
@@ -243,7 +243,7 @@
 }
 
 // Tests that the VC can be dismissed by swiping down.
-- (void)testSwipeDownDismiss {
+- (void)DISABLED_testSwipeDownDismiss {
   if (!base::ios::IsRunningOnOrLater(13, 0, 0)) {
     EARL_GREY_TEST_SKIPPED(@"Test disabled on iOS 12 and lower.");
   }
diff --git a/ios/chrome/browser/ui/table_view/BUILD.gn b/ios/chrome/browser/ui/table_view/BUILD.gn
index f5216e54..51288f75 100644
--- a/ios/chrome/browser/ui/table_view/BUILD.gn
+++ b/ios/chrome/browser/ui/table_view/BUILD.gn
@@ -15,10 +15,9 @@
     "table_view_navigation_controller.mm",
     "table_view_navigation_controller_constants.h",
     "table_view_navigation_controller_constants.mm",
-    "table_view_navigation_controller_delegate.h",
-    "table_view_navigation_controller_delegate.mm",
   ]
   deps = [
+    ":feature_flags",
     ":presentation",
     ":styler",
     ":views",
diff --git a/ios/chrome/browser/ui/table_view/table_view_navigation_controller_delegate.h b/ios/chrome/browser/ui/table_view/table_view_navigation_controller_delegate.h
deleted file mode 100644
index c1d21987..0000000
--- a/ios/chrome/browser/ui/table_view/table_view_navigation_controller_delegate.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_TABLE_VIEW_TABLE_VIEW_NAVIGATION_CONTROLLER_DELEGATE_H_
-#define IOS_CHROME_BROWSER_UI_TABLE_VIEW_TABLE_VIEW_NAVIGATION_CONTROLLER_DELEGATE_H_
-
-#import <UIKit/UIKit.h>
-
-@protocol TableViewModalPresenting;
-
-// TableViewNavigationControllerDelegate serves as a delegate for
-// TableViewNavigationController. It uses |modalController| to update the modal
-// presentation state when view controllers are pushed onto or popped off of the
-// navigation stack.
-@interface TableViewNavigationControllerDelegate
-    : NSObject<UINavigationControllerDelegate>
-
-// An object which controls the modal presentation of the navigation controller.
-@property(nonatomic, weak) id<TableViewModalPresenting> modalController;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_TABLE_VIEW_TABLE_VIEW_NAVIGATION_CONTROLLER_DELEGATE_H_
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index d673484..973eab3 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -185,6 +185,10 @@
 
 namespace media {
 
+// Prefer FFmpeg to LibVPX for Vp8 decoding with opaque alpha mode.
+const base::Feature kFFmpegDecodeOpaqueVP8{"FFmpegDecodeOpaqueVP8",
+                                           base::FEATURE_ENABLED_BY_DEFAULT};
+
 // Only used for disabling overlay fullscreen (aka SurfaceView) in Clank.
 const base::Feature kOverlayFullscreenVideo{"overlay-fullscreen-video",
                                             base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/media/base/media_switches.h b/media/base/media_switches.h
index 9d8de56..35eaeef 100644
--- a/media/base/media_switches.h
+++ b/media/base/media_switches.h
@@ -102,6 +102,7 @@
 MEDIA_EXPORT extern const base::Feature kD3D11VideoDecoder;
 MEDIA_EXPORT extern const base::Feature kD3D11VideoDecoderIgnoreWorkarounds;
 MEDIA_EXPORT extern const base::Feature kExternalClearKeyForTesting;
+MEDIA_EXPORT extern const base::Feature kFFmpegDecodeOpaqueVP8;
 MEDIA_EXPORT extern const base::Feature kFailUrlProvisionFetcherForTesting;
 MEDIA_EXPORT extern const base::Feature kFallbackAfterDecodeError;
 MEDIA_EXPORT extern const base::Feature kGlobalMediaControls;
diff --git a/media/cast/sender/external_video_encoder.cc b/media/cast/sender/external_video_encoder.cc
index 2773d30b..d3f644e 100644
--- a/media/cast/sender/external_video_encoder.cc
+++ b/media/cast/sender/external_video_encoder.cc
@@ -208,7 +208,7 @@
           input_buffers_[index].get();
       DCHECK(input_buffer->first.IsValid());
       DCHECK(input_buffer->second.IsValid());
-      scoped_refptr<media::VideoFrame> frame = VideoFrame::WrapExternalData(
+      frame = VideoFrame::WrapExternalData(
           video_frame->format(), frame_coded_size_, video_frame->visible_rect(),
           video_frame->visible_rect().size(),
           input_buffer->second.GetMemoryAsSpan<uint8_t>().data(),
diff --git a/media/filters/vpx_video_decoder.cc b/media/filters/vpx_video_decoder.cc
index 7f88a6a..7d9e99e 100644
--- a/media/filters/vpx_video_decoder.cc
+++ b/media/filters/vpx_video_decoder.cc
@@ -13,6 +13,7 @@
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
+#include "base/feature_list.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/macros.h"
@@ -203,9 +204,11 @@
     return false;
 
 #if BUILDFLAG(ENABLE_FFMPEG_VIDEO_DECODERS)
-  // When FFmpegVideoDecoder is available it handles VP8 that doesn't have
-  // alpha, and VpxVideoDecoder will handle VP8 with alpha.
-  if (config.codec() == kCodecVP8 &&
+  // When enabled, ffmpeg handles VP8 that doesn't have alpha, and
+  // VpxVideoDecoder will handle VP8 with alpha. FFvp8 is being deprecated.
+  // See http://crbug.com/992235.
+  if (base::FeatureList::IsEnabled(kFFmpegDecodeOpaqueVP8) &&
+      config.codec() == kCodecVP8 &&
       config.alpha_mode() == VideoDecoderConfig::AlphaMode::kIsOpaque) {
     return false;
   }
diff --git a/media/gpu/test/video_player/video_decoder_client.cc b/media/gpu/test/video_player/video_decoder_client.cc
index 264151d..4fd7d2d 100644
--- a/media/gpu/test/video_player/video_decoder_client.cc
+++ b/media/gpu/test/video_player/video_decoder_client.cc
@@ -13,15 +13,19 @@
 #include "build/build_config.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/waiting.h"
+#include "media/gpu/buildflags.h"
 #include "media/gpu/macros.h"
 #include "media/gpu/test/video_decode_accelerator_unittest_helpers.h"
 #include "media/gpu/test/video_player/frame_renderer.h"
 #include "media/gpu/test/video_player/test_vda_video_decoder.h"
 #include "media/gpu/test/video_player/video.h"
 
+#if BUILDFLAG(USE_VAAPI) || BUILDFLAG(USE_V4L2_CODEC)
+#include "media/gpu/linux/platform_video_frame_pool.h"
+#endif  // BUILDFLAG(USE_VAAPI) || BUILDFLAG(USE_V4L2_CODEC)
+
 #if defined(OS_CHROMEOS)
 #include "media/gpu/chromeos/chromeos_video_decoder_factory.h"
-#include "media/gpu/linux/platform_video_frame_pool.h"
 #include "media/gpu/video_frame_converter.h"
 #endif  // defined(OS_CHROMEOS)
 
@@ -159,7 +163,7 @@
   LOG_ASSERT(!decoder_) << "Can't create decoder: already created";
 
   if (decoder_client_config_.use_vd) {
-#if defined(OS_CHROMEOS)
+#if defined(OS_CHROMEOS) && (BUILDFLAG(USE_VAAPI) || BUILDFLAG(USE_V4L2_CODEC))
     decoder_ = ChromeosVideoDecoderFactory::Create(
         base::ThreadTaskRunnerHandle::Get(),
         std::make_unique<PlatformVideoFramePool>(),
diff --git a/media/gpu/video_decode_accelerator_perf_tests.cc b/media/gpu/video_decode_accelerator_perf_tests.cc
index 13f5c1f..68302ac 100644
--- a/media/gpu/video_decode_accelerator_perf_tests.cc
+++ b/media/gpu/video_decode_accelerator_perf_tests.cc
@@ -87,8 +87,9 @@
   // The number of frames dropped because of the decoder running behind, only
   // relevant for capped performance tests.
   size_t frames_dropped_ = 0;
-  // The rate at which frames are dropped: dropped frames / non-dropped frames.
-  double dropped_frame_rate_ = 0;
+  // The percentage of frames dropped because of the decoder running behind,
+  // only relevant for capped performance tests.
+  double dropped_frame_percentage_ = 0.0;
   // Statistics about the time between subsequent frame deliveries.
   PerformanceTimeStats delivery_time_stats_;
   // Statistics about the time between decode start and frame deliveries.
@@ -165,12 +166,12 @@
                                      perf_metrics_.total_duration_.InSecondsF();
   perf_metrics_.frames_dropped_ = frame_renderer_->FramesDropped();
 
-  // Calculate the frame drop rate.
-  // TODO(dstaessens@) Find a better metric for dropped frames.
-  size_t frames_rendered =
-      perf_metrics_.frames_decoded_ - perf_metrics_.frames_dropped_;
-  perf_metrics_.dropped_frame_rate_ =
-      perf_metrics_.frames_dropped_ / std::max<size_t>(frames_rendered, 1ul);
+  // Calculate the dropped frame percentage.
+  perf_metrics_.dropped_frame_percentage_ =
+      static_cast<double>(perf_metrics_.frames_dropped_) /
+      static_cast<double>(
+          std::max<size_t>(perf_metrics_.frames_decoded_, 1ul)) *
+      100.0;
 
   // Calculate delivery and decode time metrics.
   perf_metrics_.delivery_time_stats_ =
@@ -186,8 +187,8 @@
             << std::endl;
   std::cout << "Frames Dropped:     " << perf_metrics_.frames_dropped_
             << std::endl;
-  std::cout << "Dropped frame rate: " << perf_metrics_.dropped_frame_rate_
-            << std::endl;
+  std::cout << "Dropped frame percentage: "
+            << perf_metrics_.dropped_frame_percentage_ << "%" << std::endl;
   std::cout << "Frame delivery time - average:       "
             << perf_metrics_.delivery_time_stats_.avg_ms_ << "ms" << std::endl;
   std::cout << "Frame delivery time - percentile 25: "
@@ -229,8 +230,8 @@
   metrics.SetKey(
       "FramesDropped",
       base::Value(base::checked_cast<int>(perf_metrics_.frames_dropped_)));
-  metrics.SetKey("DroppedFrameRate",
-                 base::Value(perf_metrics_.dropped_frame_rate_));
+  metrics.SetKey("DroppedFramePercentage",
+                 base::Value(perf_metrics_.dropped_frame_percentage_));
   metrics.SetKey("FrameDeliveryTimeAverage",
                  base::Value(perf_metrics_.delivery_time_stats_.avg_ms_));
   metrics.SetKey(
diff --git a/mojo/public/cpp/bindings/receiver.h b/mojo/public/cpp/bindings/receiver.h
index 0bac693..d3b4aa1 100644
--- a/mojo/public/cpp/bindings/receiver.h
+++ b/mojo/public/cpp/bindings/receiver.h
@@ -209,6 +209,11 @@
   // acknowledgement from the Remote is received.
   void FlushForTesting() { internal_state_.FlushForTesting(); }
 
+  // Allows test code to swap the interface implementation.
+  ImplPointerType SwapImplForTesting(ImplPointerType new_impl) {
+    return internal_state_.SwapImplForTesting(new_impl);
+  }
+
   // Reports the currently dispatching message as bad and resets this receiver.
   // Note that this is only legal to call from within the stack frame of a
   // message dispatch. If you need to do asynchronous work before determining
diff --git a/mojo/public/cpp/bindings/receiver_set.h b/mojo/public/cpp/bindings/receiver_set.h
index cf740d26..07ee744 100644
--- a/mojo/public/cpp/bindings/receiver_set.h
+++ b/mojo/public/cpp/bindings/receiver_set.h
@@ -237,6 +237,18 @@
     }
   }
 
+  // Swaps the interface implementation with a different one, to allow tests
+  // to modify behavior.
+  //
+  // Returns the existing interface implementation to the caller.
+  ImplPointerType SwapImplForTesting(ReceiverId id, ImplPointerType new_impl) {
+    auto it = receivers_.find(id);
+    if (it == receivers_.end())
+      return nullptr;
+
+    return it->second->SwapImplForTesting(new_impl);
+  }
+
  private:
   friend class Entry;
 
@@ -259,6 +271,10 @@
           base::BindOnce(&Entry::OnDisconnect, base::Unretained(this)));
     }
 
+    ImplPointerType SwapImplForTesting(ImplPointerType new_impl) {
+      return receiver_.SwapImplForTesting(new_impl);
+    }
+
     void FlushForTesting() { receiver_.FlushForTesting(); }
 
    private:
diff --git a/native_client_sdk/doc_generated/migration/index.html b/native_client_sdk/doc_generated/migration/index.html
index df685db..18a7eff8 100644
--- a/native_client_sdk/doc_generated/migration/index.html
+++ b/native_client_sdk/doc_generated/migration/index.html
@@ -5,10 +5,21 @@
 <h2 id="p-nacl-deprecation-announcements">(P)NaCl Deprecation Announcements</h2>
 <p>Given the momentum of cross-browser WebAssembly support, we plan to focus our
 native code efforts on WebAssembly going forward and plan to remove support for
-PNaCl in Q2 2019 (except for Chrome Apps). We believe that the vibrant
+PNaCl in Q4 2019 (except for Chrome Apps). We believe that the vibrant
 ecosystem around <a class="reference external" href="http://webassembly.org">WebAssembly</a>
 makes it a better fit for new and existing high-performance
 web apps and that usage of PNaCl is sufficiently low to warrant deprecation.</p>
+<p>As of Chrome 76, PNaCl on the open web has been moved behind an
+<a class="reference external" href="https://github.com/GoogleChrome/OriginTrials/blob/gh-pages/developer-guide.md">Origin Trial</a>
+which is a mechanism for web developers to register and get access to a feature that isn&#8217;t on by default.
+This is usually a new proposed feature but in this case it&#8217;s a feature being deprecated.
+A developer can register on the <a class="reference external" href="https://developers.chrome.com/origintrials/#/view_trial/3553340105995321345">Origin Trial Console</a>
+and receive a token, which can be embedded into a page and will enable the feature without the user needing to use a flag.
+(For more details see the linked guide). The trial is scheduled to last through Chrome 78, approximately until December 2019.
+This change is not intended to affect NaCl or PNaCl in Chrome Apps or extensions, and the "enable-nacl"
+flag in chrome://flags can also be used to enable PNaCl locally for testing
+(this flag also retains its current function of enabling non-PNaCl "native" NaCl on any page).
+</p>
 <p>We also recently announced the deprecation Q1 2018 of
 <a class="reference external" href="https://blog.chromium.org/2016/08/from-chrome-apps-to-web.html">Chrome Apps</a>
 outside of ChromeOS.</p>
diff --git a/native_client_sdk/src/doc/migration/index.rst b/native_client_sdk/src/doc/migration/index.rst
index 7f61dc5..6b43259 100644
--- a/native_client_sdk/src/doc/migration/index.rst
+++ b/native_client_sdk/src/doc/migration/index.rst
@@ -8,11 +8,24 @@
 
 Given the momentum of cross-browser WebAssembly support, we plan to focus our
 native code efforts on WebAssembly going forward and plan to remove support for
-PNaCl in Q2 2019 (except for Chrome Apps). We believe that the vibrant
+PNaCl in Q4 2019 (except for Chrome Apps). We believe that the vibrant
 ecosystem around `WebAssembly <http://webassembly.org>`_
 makes it a better fit for new and existing high-performance
 web apps and that usage of PNaCl is sufficiently low to warrant deprecation.
 
+As of Chrome 76, PNaCl on the open web has been moved behind an
+`Origin Trial
+<https://github.com/GoogleChrome/OriginTrials/blob/gh-pages/developer-guide.md>`_,
+which is a mechanism for web developers to register and get access to a feature that isn't on by default.
+This is usually a new proposed feature but in this case it's a feature being deprecated.
+A developer can register on the `Origin Trial Console
+<https://developers.chrome.com/origintrials/#/view_trial/3553340105995321345>`_
+and receive a token, which can be embedded into a page and will enable the feature without the user needing to use a flag.
+(For more details see the linked guide). The trial is scheduled to last through Chrome 78, approximately until December 2019.
+This change is not intended to affect NaCl or PNaCl in Chrome Apps or extensions, and the "enable-nacl"
+flag in chrome://flags can also be used to enable PNaCl locally for testing
+(this flag also retains its current function of enabling non-PNaCl "native" NaCl on any page).
+
 We also recently announced the deprecation Q1 2018 of
 `Chrome Apps
 <https://blog.chromium.org/2016/08/from-chrome-apps-to-web.html>`_
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 0d0b1691..a02cff2 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -5760,7 +5760,6 @@
     "//crypto:test_support",
     "//net/base/registry_controlled_domains",
     "//net/dns:tests",
-    "//net/dns/public:tests",
     "//net/http:transport_security_state_unittest_data",
     "//net/http:transport_security_state_unittest_data_default",
     "//net/tools/huffman_trie:huffman_trie_generator_sources",
diff --git a/net/dns/public/BUILD.gn b/net/dns/public/BUILD.gn
index 9b20ce9..9617ed0 100644
--- a/net/dns/public/BUILD.gn
+++ b/net/dns/public/BUILD.gn
@@ -29,15 +29,3 @@
     "//net:net_public_deps",
   ]
 }
-
-source_set("tests") {
-  testonly = true
-  sources = [
-    "util_unittest.cc",
-  ]
-
-  deps = [
-    "//net",
-    "//testing/gtest",
-  ]
-}
diff --git a/net/dns/public/util.cc b/net/dns/public/util.cc
index 69c911f..a75870e1e 100644
--- a/net/dns/public/util.cc
+++ b/net/dns/public/util.cc
@@ -28,35 +28,6 @@
 
 namespace dns_util {
 
-bool IsValidDoHTemplate(const string& server_template,
-                        const string& server_method) {
-  std::string url_string;
-  std::string test_query = "this_is_a_test_query";
-  std::unordered_map<std::string, std::string> template_params(
-      {{"dns", test_query}});
-  std::set<std::string> vars_found;
-  bool valid_template = uri_template::Expand(server_template, template_params,
-                                             &url_string, &vars_found);
-  if (!valid_template) {
-    // The URI template is malformed.
-    return false;
-  }
-  if (server_method != "POST" && vars_found.find("dns") == vars_found.end()) {
-    // GET requests require the template to have a dns variable.
-    return false;
-  }
-  GURL url(url_string);
-  if (!url.is_valid() || !url.SchemeIs("https")) {
-    // The expanded template must be a valid HTTPS URL.
-    return false;
-  }
-  if (url.host().find(test_query) != std::string::npos) {
-    // The dns variable may not be part of the hostname.
-    return false;
-  }
-  return true;
-}
-
 IPEndPoint GetMdnsGroupEndPoint(AddressFamily address_family) {
   switch (address_family) {
     case ADDRESS_FAMILY_IPV4:
diff --git a/net/dns/public/util.h b/net/dns/public/util.h
index 26b0aaa..fd0d977 100644
--- a/net/dns/public/util.h
+++ b/net/dns/public/util.h
@@ -13,16 +13,9 @@
 
 namespace net {
 
-// Basic utility functions for interaction with DNS, MDNS, and host resolution.
+// Basic utility functions for interaction with MDNS and host resolution.
 namespace dns_util {
 
-// Returns true if the URI template is acceptable for sending requests via the
-// given method. The template must be properly formatted, GET requests require
-// the template to contain a "dns" variable, an expanded template must parse
-// to a valid HTTPS URL, and the "dns" variable may not be part of the hostname.
-NET_EXPORT bool IsValidDoHTemplate(const std::string& server_template,
-                                   const std::string& server_method);
-
 // Gets the endpoint for the multicast group a socket should join to receive
 // MDNS messages. Such sockets should also bind to the endpoint from
 // GetMDnsReceiveEndPoint().
diff --git a/net/dns/public/util_unittest.cc b/net/dns/public/util_unittest.cc
deleted file mode 100644
index 761ef0f..0000000
--- a/net/dns/public/util_unittest.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/dns/public/util.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace dns_util {
-
-TEST(DnsPublicUtilTest, IsValidDoHTemplate) {
-  EXPECT_TRUE(IsValidDoHTemplate(
-      "https://dnsserver.example.net/dns-query{?dns}", "GET"));
-  EXPECT_TRUE(IsValidDoHTemplate(
-      "https://dnsserver.example.net/dns-query{?dns,extra}", "GET"));
-  EXPECT_TRUE(IsValidDoHTemplate(
-      "https://dnsserver.example.net/dns-query{?dns}", "POST"));
-  EXPECT_TRUE(IsValidDoHTemplate(
-      "https://dnsserver.example.net/dns-query{?query}", "POST"));
-  EXPECT_TRUE(
-      IsValidDoHTemplate("https://dnsserver.example.net/dns-query", "POST"));
-  EXPECT_TRUE(
-      IsValidDoHTemplate("https://query:{dns}@dnsserver.example.net", "GET"));
-  EXPECT_TRUE(IsValidDoHTemplate("https://dnsserver.example.net{/dns}", "GET"));
-  // Invalid template format
-  EXPECT_FALSE(IsValidDoHTemplate(
-      "https://dnsserver.example.net/dns-query{{?dns}}", "GET"));
-  // Must be HTTPS
-  EXPECT_FALSE(
-      IsValidDoHTemplate("http://dnsserver.example.net/dns-query", "POST"));
-  EXPECT_FALSE(IsValidDoHTemplate(
-      "http://dnsserver.example.net/dns-query{?dns}", "GET"));
-  // GET requests require the template to have a dns variable
-  EXPECT_FALSE(IsValidDoHTemplate(
-      "https://dnsserver.example.net/dns-query{?query}", "GET"));
-  // Template must expand to a valid URL
-  EXPECT_FALSE(IsValidDoHTemplate("https://{?dns}", "GET"));
-  // The hostname must not contain the dns variable
-  EXPECT_FALSE(IsValidDoHTemplate("https://{dns}.dnsserver.net", "GET"));
-}
-
-}  // namespace dns_util
-}  // namespace net
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index 437fa0b7..7cb0db43 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -32,6 +32,7 @@
 #include "net/socket/client_socket_pool_manager_impl.h"
 #include "net/socket/next_proto.h"
 #include "net/socket/ssl_client_socket.h"
+#include "net/spdy/spdy_session.h"
 #include "net/spdy/spdy_session_pool.h"
 #include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
 #include "net/third_party/quiche/src/quic/core/quic_packets.h"
@@ -80,6 +81,7 @@
       enable_spdy_ping_based_connection_checking(true),
       enable_http2(true),
       spdy_session_max_recv_window_size(kSpdySessionMaxRecvWindowSize),
+      spdy_session_max_queued_capped_frames(kSpdySessionMaxQueuedCappedFrames),
       time_func(&base::TimeTicks::Now),
       enable_http2_alternative_service(false),
       enable_websocket_over_http2(false),
@@ -173,6 +175,7 @@
                          params.enable_spdy_ping_based_connection_checking,
                          params.quic_params.support_ietf_format_quic_altsvc,
                          params.spdy_session_max_recv_window_size,
+                         params.spdy_session_max_queued_capped_frames,
                          AddDefaultHttp2Settings(params.http2_settings),
                          params.greased_http2_frame,
                          params.time_func,
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h
index e37b5eb..6375227 100644
--- a/net/http/http_network_session.h
+++ b/net/http/http_network_session.h
@@ -106,6 +106,8 @@
     bool enable_spdy_ping_based_connection_checking;
     bool enable_http2;
     size_t spdy_session_max_recv_window_size;
+    // Maximum number of capped frames that can be queued at any time.
+    int spdy_session_max_queued_capped_frames;
     // HTTP/2 connection settings.
     // Unknown settings will still be sent to the server.
     // Might contain unknown setting identifiers from a predefined set that
diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc
index 95678b2..5177cb98 100644
--- a/net/spdy/spdy_network_transaction_unittest.cc
+++ b/net/spdy/spdy_network_transaction_unittest.cc
@@ -7075,6 +7075,56 @@
   EXPECT_THAT(out.rv, IsError(ERR_HTTP2_FLOW_CONTROL_ERROR));
 }
 
+// Tests that we close the connection if we try to enqueue more frames than
+// the cap allows.
+TEST_F(SpdyNetworkTransactionTest, SessionMaxQueuedCappedFramesExceeded) {
+  const int kTestSessionMaxQueuedCappedFrames = 5;
+  const int kTestNumPings = kTestSessionMaxQueuedCappedFrames + 1;
+  spdy::SettingsMap settings;
+  settings[spdy::SETTINGS_INITIAL_WINDOW_SIZE] = 0xffff;
+  spdy::SpdySerializedFrame settings_frame(
+      spdy_util_.ConstructSpdySettings(settings));
+  std::vector<spdy::SpdySerializedFrame> ping_frames;
+
+  spdy::SpdySerializedFrame req(
+      spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
+  spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
+
+  std::vector<MockWrite> writes;
+  std::vector<MockRead> reads;
+  // Send request, receive SETTINGS and send a SETTINGS ACK.
+  writes.push_back(CreateMockWrite(req, writes.size() + reads.size()));
+  reads.push_back(CreateMockRead(settings_frame, writes.size() + reads.size()));
+  writes.push_back(CreateMockWrite(settings_ack, writes.size() + reads.size()));
+  // Receive more pings than our limit allows.
+  for (int i = 1; i <= kTestNumPings; ++i) {
+    ping_frames.push_back(
+        spdy_util_.ConstructSpdyPing(/*ping_id=*/i, /*is_ack=*/false));
+    reads.push_back(
+        CreateMockRead(ping_frames.back(), writes.size() + reads.size()));
+  }
+  // Only write PING ACKs after receiving all of them to ensure they are all in
+  // the write queue.
+  for (int i = 1; i <= kTestNumPings; ++i) {
+    ping_frames.push_back(
+        spdy_util_.ConstructSpdyPing(/*ping_id=*/i, /*is_ack=*/true));
+    writes.push_back(
+        CreateMockWrite(ping_frames.back(), writes.size() + reads.size()));
+  }
+  // Stop reading.
+  reads.push_back(MockRead(ASYNC, 0, writes.size() + reads.size()));
+
+  SequencedSocketData data(reads, writes);
+  auto session_deps = std::make_unique<SpdySessionDependencies>();
+  session_deps->session_max_queued_capped_frames =
+      kTestSessionMaxQueuedCappedFrames;
+  NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
+                                     std::move(session_deps));
+  helper.RunToCompletion(&data);
+  TransactionHelperResult out = helper.output();
+  EXPECT_THAT(out.rv, IsError(ERR_CONNECTION_CLOSED));
+}
+
 // Test that after hitting a send window size of 0, the write process
 // stalls and upon receiving WINDOW_UPDATE frame write resumes.
 
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc
index ba77973..3fa3e5c 100644
--- a/net/spdy/spdy_session.cc
+++ b/net/spdy/spdy_session.cc
@@ -865,6 +865,7 @@
     bool support_ietf_format_quic_altsvc,
     bool is_trusted_proxy,
     size_t session_max_recv_window_size,
+    int session_max_queued_capped_frames,
     const spdy::SettingsMap& initial_settings,
     const base::Optional<SpdySessionPool::GreasedHttp2Frame>&
         greased_http2_frame,
@@ -909,6 +910,7 @@
       check_ping_status_pending_(false),
       session_send_window_size_(0),
       session_max_recv_window_size_(session_max_recv_window_size),
+      session_max_queued_capped_frames_(session_max_queued_capped_frames),
       session_recv_window_size_(0),
       session_unacked_recv_window_bytes_(0),
       stream_initial_send_window_size_(kDefaultInitialWindowSize),
@@ -2712,6 +2714,16 @@
          frame_type == spdy::SpdyFrameType::WINDOW_UPDATE ||
          frame_type == spdy::SpdyFrameType::PING ||
          frame_type == spdy::SpdyFrameType::GOAWAY);
+  DCHECK(IsSpdyFrameTypeWriteCapped(frame_type));
+  if (write_queue_.num_queued_capped_frames() >
+      session_max_queued_capped_frames_) {
+    LOG(WARNING)
+        << "Draining session due to exceeding max queued capped frames";
+    // Use ERR_CONNECTION_CLOSED to avoid sending a GOAWAY frame since that
+    // frame would also exceed the cap.
+    DoDrainSession(ERR_CONNECTION_CLOSED, "Exceeded max queued capped frames");
+    return;
+  }
   auto buffer = std::make_unique<SpdyBuffer>(std::move(frame));
   EnqueueWrite(priority, frame_type,
                std::make_unique<SimpleBufferProducer>(std::move(buffer)),
diff --git a/net/spdy/spdy_session.h b/net/spdy/spdy_session.h
index 7de36a4..3f6638f 100644
--- a/net/spdy/spdy_session.h
+++ b/net/spdy/spdy_session.h
@@ -86,6 +86,9 @@
 const spdy::SpdyStreamId kFirstStreamId = 1;
 const spdy::SpdyStreamId kLastStreamId = 0x7fffffff;
 
+// Maximum number of capped frames that can be queued at any time.
+const int kSpdySessionMaxQueuedCappedFrames = 10000;
+
 class NetLog;
 class NetworkQualityEstimator;
 class SpdyStream;
@@ -321,6 +324,7 @@
               bool support_ietf_format_quic_altsvc,
               bool is_trusted_proxy,
               size_t session_max_recv_window_size,
+              int session_max_queued_capped_frames,
               const spdy::SettingsMap& initial_settings,
               const base::Optional<SpdySessionPool::GreasedHttp2Frame>&
                   greased_http2_frame,
@@ -1122,6 +1126,11 @@
   // control is turned on.
   int32_t session_max_recv_window_size_;
 
+  // Maximum number of capped frames that can be queued at any time.
+  // Every time we try to enqueue a capped frame, we check that there aren't
+  // more than this amount already queued, and close the connection if so.
+  int session_max_queued_capped_frames_;
+
   // Sum of |session_unacked_recv_window_bytes_| and current receive window
   // size.  Zero unless session flow control is turned on.
   // TODO(bnc): Rename or change semantics so that |window_size_| is actual
diff --git a/net/spdy/spdy_session_pool.cc b/net/spdy/spdy_session_pool.cc
index 8ffc3b7..fb550fa 100644
--- a/net/spdy/spdy_session_pool.cc
+++ b/net/spdy/spdy_session_pool.cc
@@ -85,6 +85,7 @@
     bool enable_ping_based_connection_checking,
     bool support_ietf_format_quic_altsvc,
     size_t session_max_recv_window_size,
+    int session_max_queued_capped_frames,
     const spdy::SettingsMap& initial_settings,
     const base::Optional<GreasedHttp2Frame>& greased_http2_frame,
     SpdySessionPool::TimeFunc time_func,
@@ -99,6 +100,7 @@
           enable_ping_based_connection_checking),
       support_ietf_format_quic_altsvc_(support_ietf_format_quic_altsvc),
       session_max_recv_window_size_(session_max_recv_window_size),
+      session_max_queued_capped_frames_(session_max_queued_capped_frames),
       initial_settings_(initial_settings),
       greased_http2_frame_(greased_http2_frame),
       time_func_(time_func),
@@ -662,7 +664,8 @@
       ssl_client_context_ ? ssl_client_context_->ssl_config_service() : nullptr,
       quic_supported_versions_, enable_sending_initial_data_,
       enable_ping_based_connection_checking_, support_ietf_format_quic_altsvc_,
-      is_trusted_proxy, session_max_recv_window_size_, initial_settings_,
+      is_trusted_proxy, session_max_recv_window_size_,
+      session_max_queued_capped_frames_, initial_settings_,
       greased_http2_frame_, time_func_, push_delegate_,
       network_quality_estimator_, net_log);
 }
diff --git a/net/spdy/spdy_session_pool.h b/net/spdy/spdy_session_pool.h
index e2ce4e7..29fabf3 100644
--- a/net/spdy/spdy_session_pool.h
+++ b/net/spdy/spdy_session_pool.h
@@ -140,6 +140,7 @@
                   bool enable_ping_based_connection_checking,
                   bool support_ietf_format_quic_altsvc,
                   size_t session_max_recv_window_size,
+                  int session_max_queued_capped_frames,
                   const spdy::SettingsMap& initial_settings,
                   const base::Optional<GreasedHttp2Frame>& greased_http2_frame,
                   SpdySessionPool::TimeFunc time_func,
@@ -427,6 +428,9 @@
 
   size_t session_max_recv_window_size_;
 
+  // Maximum number of capped frames that can be queued at any time.
+  int session_max_queued_capped_frames_;
+
   // Settings that are sent in the initial SETTINGS frame
   // (if |enable_sending_initial_data_| is true),
   // and also control SpdySession parameters like initial receive window size
diff --git a/net/spdy/spdy_test_util_common.cc b/net/spdy/spdy_test_util_common.cc
index c6f9033..ffe0a2c 100644
--- a/net/spdy/spdy_test_util_common.cc
+++ b/net/spdy/spdy_test_util_common.cc
@@ -337,6 +337,7 @@
       enable_quic(false),
       enable_server_push_cancellation(false),
       session_max_recv_window_size(kDefaultInitialWindowSize),
+      session_max_queued_capped_frames(kSpdySessionMaxQueuedCappedFrames),
       time_func(&base::TimeTicks::Now),
       enable_http2_alternative_service(false),
       enable_websocket_over_http2(false),
@@ -387,6 +388,8 @@
       session_deps->enable_server_push_cancellation;
   params.spdy_session_max_recv_window_size =
       session_deps->session_max_recv_window_size;
+  params.spdy_session_max_queued_capped_frames =
+      session_deps->session_max_queued_capped_frames;
   params.http2_settings = session_deps->http2_settings;
   params.time_func = session_deps->time_func;
   params.enable_http2_alternative_service =
diff --git a/net/spdy/spdy_test_util_common.h b/net/spdy/spdy_test_util_common.h
index b36208f..15f2868 100644
--- a/net/spdy/spdy_test_util_common.h
+++ b/net/spdy/spdy_test_util_common.h
@@ -228,6 +228,7 @@
   bool enable_quic;
   bool enable_server_push_cancellation;
   size_t session_max_recv_window_size;
+  int session_max_queued_capped_frames;
   spdy::SettingsMap http2_settings;
   SpdySession::TimeFunc time_func;
   bool enable_http2_alternative_service;
diff --git a/net/spdy/spdy_write_queue.cc b/net/spdy/spdy_write_queue.cc
index d1948c46..e7272b7 100644
--- a/net/spdy/spdy_write_queue.cc
+++ b/net/spdy/spdy_write_queue.cc
@@ -10,6 +10,7 @@
 
 #include "base/containers/circular_deque.h"
 #include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/trace_event/memory_usage_estimator.h"
 #include "net/spdy/spdy_buffer.h"
 #include "net/spdy/spdy_buffer_producer.h"
@@ -17,6 +18,14 @@
 
 namespace net {
 
+bool IsSpdyFrameTypeWriteCapped(spdy::SpdyFrameType frame_type) {
+  return frame_type == spdy::SpdyFrameType::RST_STREAM ||
+         frame_type == spdy::SpdyFrameType::SETTINGS ||
+         frame_type == spdy::SpdyFrameType::WINDOW_UPDATE ||
+         frame_type == spdy::SpdyFrameType::PING ||
+         frame_type == spdy::SpdyFrameType::GOAWAY;
+}
+
 SpdyWriteQueue::PendingWrite::PendingWrite() = default;
 
 SpdyWriteQueue::PendingWrite::PendingWrite(
@@ -43,6 +52,10 @@
 SpdyWriteQueue::SpdyWriteQueue() : removing_writes_(false) {}
 
 SpdyWriteQueue::~SpdyWriteQueue() {
+  DCHECK_GE(num_queued_capped_frames_, 0);
+  DCHECK_GT(highest_num_queued_capped_frames_, 0);
+  UMA_HISTOGRAM_COUNTS_100000("Net.SpdyHighestQueuedCappedFramesCount",
+                              highest_num_queued_capped_frames_);
   Clear();
 }
 
@@ -68,6 +81,15 @@
   queue_[priority].push_back(
       {frame_type, std::move(frame_producer), stream,
        MutableNetworkTrafficAnnotationTag(traffic_annotation)});
+  if (IsSpdyFrameTypeWriteCapped(frame_type)) {
+    DCHECK_GE(num_queued_capped_frames_, 0);
+    num_queued_capped_frames_++;
+    if (num_queued_capped_frames_ > highest_num_queued_capped_frames_) {
+      DCHECK_EQ(num_queued_capped_frames_,
+                highest_num_queued_capped_frames_ + 1);
+      highest_num_queued_capped_frames_ = num_queued_capped_frames_;
+    }
+  }
 }
 
 bool SpdyWriteQueue::Dequeue(
@@ -86,6 +108,10 @@
       *traffic_annotation = pending_write.traffic_annotation;
       if (pending_write.has_stream)
         DCHECK(stream->get());
+      if (IsSpdyFrameTypeWriteCapped(*frame_type)) {
+        num_queued_capped_frames_--;
+        DCHECK_GE(num_queued_capped_frames_, 0);
+      }
       return true;
     }
   }
@@ -116,6 +142,10 @@
   base::circular_deque<PendingWrite>& queue = queue_[priority];
   for (auto it = queue.begin(); it != queue.end();) {
     if (it->stream.get() == stream) {
+      if (IsSpdyFrameTypeWriteCapped(it->frame_type)) {
+        num_queued_capped_frames_--;
+        DCHECK_GE(num_queued_capped_frames_, 0);
+      }
       erased_buffer_producers.push_back(std::move(it->frame_producer));
       it = queue.erase(it);
     } else {
@@ -141,6 +171,10 @@
     for (auto it = queue.begin(); it != queue.end();) {
       if (it->stream.get() && (it->stream->stream_id() > last_good_stream_id ||
                                it->stream->stream_id() == 0)) {
+        if (IsSpdyFrameTypeWriteCapped(it->frame_type)) {
+          num_queued_capped_frames_--;
+          DCHECK_GE(num_queued_capped_frames_, 0);
+        }
         erased_buffer_producers.push_back(std::move(it->frame_producer));
         it = queue.erase(it);
       } else {
@@ -196,6 +230,7 @@
     queue_[i].clear();
   }
   removing_writes_ = false;
+  num_queued_capped_frames_ = 0;
 }
 
 size_t SpdyWriteQueue::EstimateMemoryUsage() const {
diff --git a/net/spdy/spdy_write_queue.h b/net/spdy/spdy_write_queue.h
index 7c05045..966a060 100644
--- a/net/spdy/spdy_write_queue.h
+++ b/net/spdy/spdy_write_queue.h
@@ -17,6 +17,11 @@
 
 namespace net {
 
+// Returns whether this frame type is subject to caps on how many
+// frames can be queued at any given time.
+NET_EXPORT_PRIVATE bool IsSpdyFrameTypeWriteCapped(
+    spdy::SpdyFrameType frame_type);
+
 class SpdyBufferProducer;
 class SpdyStream;
 
@@ -72,6 +77,10 @@
   // Returns the estimate of dynamically allocated memory in bytes.
   size_t EstimateMemoryUsage() const;
 
+  // Returns the number of currently queued capped frames including all
+  // priorities.
+  int num_queued_capped_frames() const { return num_queued_capped_frames_; }
+
  private:
   // A struct holding a frame producer and its associated stream.
   struct PendingWrite {
@@ -99,6 +108,11 @@
 
   bool removing_writes_;
 
+  // Number of currently queued capped frames including all priorities.
+  int num_queued_capped_frames_ = 0;
+  // Highest seen value of num_queued_capped_frames_.
+  int highest_num_queued_capped_frames_ = 1;
+
   // The actual write queue, binned by priority.
   base::circular_deque<PendingWrite> queue_[NUM_PRIORITIES];
 
diff --git a/remoting/protocol/webrtc_video_stream.cc b/remoting/protocol/webrtc_video_stream.cc
index 8839b64..07245da 100644
--- a/remoting/protocol/webrtc_video_stream.cc
+++ b/remoting/protocol/webrtc_video_stream.cc
@@ -9,7 +9,6 @@
 
 #include "base/bind.h"
 #include "base/logging.h"
-#include "base/memory/ptr_util.h"
 #include "build/build_config.h"
 #include "remoting/base/constants.h"
 #include "remoting/codec/webrtc_video_encoder_proxy.h"
@@ -83,12 +82,16 @@
 
 WebrtcVideoStream::WebrtcVideoStream(const SessionOptions& session_options)
     : video_stats_dispatcher_(kStreamLabel), session_options_(session_options) {
+  // WeakPtr can't be used here, as the Create...() methods return a value
+  // which would be undefined if the pointer were invalidated. But
+  // Unretained(this) is safe because |encoder_selector_| is owned by this
+  // object.
   encoder_selector_.RegisterEncoder(
       base::Bind(&WebrtcVideoEncoderVpx::IsSupportedByVP8),
-      base::Bind(&WebrtcVideoEncoderVpx::CreateForVP8));
+      base::Bind(&WebrtcVideoStream::CreateVP8Encoder, base::Unretained(this)));
   encoder_selector_.RegisterEncoder(
       base::Bind(&WebrtcVideoEncoderVpx::IsSupportedByVP9),
-      base::Bind(&WebrtcVideoEncoderVpx::CreateForVP9));
+      base::Bind(&WebrtcVideoStream::CreateVP9Encoder, base::Unretained(this)));
 #if defined(USE_H264_ENCODER)
   encoder_selector_.RegisterEncoder(
       base::Bind(&WebrtcVideoEncoderGpu::IsSupportedByH264),
@@ -341,5 +344,15 @@
   }
 }
 
+std::unique_ptr<WebrtcVideoEncoder> WebrtcVideoStream::CreateVP8Encoder() {
+  return std::make_unique<WebrtcVideoEncoderProxy>(
+      WebrtcVideoEncoderVpx::CreateForVP8(), encode_task_runner_);
+}
+
+std::unique_ptr<WebrtcVideoEncoder> WebrtcVideoStream::CreateVP9Encoder() {
+  return std::make_unique<WebrtcVideoEncoderProxy>(
+      WebrtcVideoEncoderVpx::CreateForVP9(), encode_task_runner_);
+}
+
 }  // namespace protocol
 }  // namespace remoting
diff --git a/remoting/protocol/webrtc_video_stream.h b/remoting/protocol/webrtc_video_stream.h
index f3b0dde..7f1332e 100644
--- a/remoting/protocol/webrtc_video_stream.h
+++ b/remoting/protocol/webrtc_video_stream.h
@@ -75,13 +75,17 @@
 
   void OnEncoderCreated(webrtc::VideoCodecType codec_type);
 
+  // Helper functions to create software encoders that run on the encode thread.
+  std::unique_ptr<WebrtcVideoEncoder> CreateVP8Encoder();
+  std::unique_ptr<WebrtcVideoEncoder> CreateVP9Encoder();
+
   // Capturer used to capture the screen.
   std::unique_ptr<webrtc::DesktopCapturer> capturer_;
   // Used to send across encoded frames.
   WebrtcTransport* webrtc_transport_ = nullptr;
-  // Task runner used to run |encoder_|.
+  // Task runner used by software encoders.
   scoped_refptr<base::SequencedTaskRunner> encode_task_runner_;
-  // Used to encode captured frames. Always accessed on the encode thread.
+  // Used to encode captured frames.
   std::unique_ptr<WebrtcVideoEncoder> encoder_;
 
   scoped_refptr<InputEventTimestampsSource> event_timestamps_source_;
diff --git a/services/data_decoder/bundled_exchanges_parser.cc b/services/data_decoder/bundled_exchanges_parser.cc
index dcc90b7..8a13ae9 100644
--- a/services/data_decoder/bundled_exchanges_parser.cc
+++ b/services/data_decoder/bundled_exchanges_parser.cc
@@ -967,13 +967,7 @@
       return;
     }
 
-    // Step 9. "If headers does not contain a Content-Type header, return an
-    // error."
-
-    // TODO(crbug.com/966753): Implement this once
-    // https://github.com/WICG/webpackage/issues/445 is resolved.
-
-    // Step 10. "Let payloadLength be the result of getting the length of a CBOR
+    // Step 9. "Let payloadLength be the result of getting the length of a CBOR
     // bytestring header from stream (Section 3.5.2). If payloadLength is an
     // error, return that error."
     auto payload_length = input.ReadCBORHeader(CBORType::kByteString);
@@ -982,6 +976,15 @@
       return;
     }
 
+    // Step 10. "If payloadLength is greater than 0 and headers does not contain
+    // a Content-Type header, return an error."
+    if (*payload_length > 0 &&
+        !parsed_headers->headers.contains("content-type")) {
+      RunErrorCallbackAndDestroy(
+          "Non-empty response must have a content-type header.");
+      return;
+    }
+
     // Step 11. "If stream.currentOffset + payloadLength !=
     // requestMetadata.offset + requestMetadata.length, return an error."
     if (input.CurrentOffset() + *payload_length != response_length_) {
diff --git a/services/data_decoder/bundled_exchanges_parser_unittest.cc b/services/data_decoder/bundled_exchanges_parser_unittest.cc
index d929e2c3..d476feb 100644
--- a/services/data_decoder/bundled_exchanges_parser_unittest.cc
+++ b/services/data_decoder/bundled_exchanges_parser_unittest.cc
@@ -443,6 +443,31 @@
   ASSERT_FALSE(ParseResponse(&data_source, location));
 }
 
+TEST_F(BundledExchangeParserTest, NoContentTypeWithNonEmptyContent) {
+  BundleBuilder builder(kFallbackUrl, kManifestUrl);
+  builder.AddExchange("https://test.example.com/", {{":status", "200"}},
+                      "payload");
+  TestDataSource data_source(builder.CreateBundle());
+
+  mojom::BundleMetadataPtr metadata = ParseBundle(&data_source).first;
+  ASSERT_TRUE(metadata);
+  auto location = FindResponse(metadata, GURL("https://test.example.com/"));
+  ASSERT_TRUE(location);
+  ASSERT_FALSE(ParseResponse(&data_source, location));
+}
+
+TEST_F(BundledExchangeParserTest, NoContentTypeWithEmptyContent) {
+  BundleBuilder builder(kFallbackUrl, kManifestUrl);
+  builder.AddExchange("https://test.example.com/", {{":status", "301"}}, "");
+  TestDataSource data_source(builder.CreateBundle());
+
+  mojom::BundleMetadataPtr metadata = ParseBundle(&data_source).first;
+  ASSERT_TRUE(metadata);
+  auto location = FindResponse(metadata, GURL("https://test.example.com/"));
+  ASSERT_TRUE(location);
+  ASSERT_TRUE(ParseResponse(&data_source, location));
+}
+
 TEST_F(BundledExchangeParserTest, Variants) {
   BundleBuilder builder(kFallbackUrl, kManifestUrl);
   auto location1 = builder.AddResponse(
diff --git a/services/device/public/mojom/nfc.mojom b/services/device/public/mojom/nfc.mojom
index 69a0476..3f4afc7b 100644
--- a/services/device/public/mojom/nfc.mojom
+++ b/services/device/public/mojom/nfc.mojom
@@ -112,7 +112,7 @@
 interface NFC {
   // NFCClient interface is used to notify |client| when NDEFMessage matches one
   // or more pending watch operations.
-  SetClient(NFCClient client);
+  SetClient(pending_remote<NFCClient> client);
 
   // Pushes data to NFC device.
   // NFCPushOptions specify timeout and type of device where data should be
diff --git a/services/viz/public/cpp/gpu/gpu.cc b/services/viz/public/cpp/gpu/gpu.cc
index ac31199..e72e736 100644
--- a/services/viz/public/cpp/gpu/gpu.cc
+++ b/services/viz/public/cpp/gpu/gpu.cc
@@ -270,9 +270,18 @@
     service_manager::Connector* connector,
     const std::string& service_name,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
-  mojom::GpuPtr gpu_ptr;
-  connector->BindInterface(service_name, &gpu_ptr);
-  return base::WrapUnique(new Gpu(std::move(gpu_ptr), std::move(task_runner)));
+  mojo::PendingRemote<mojom::Gpu> remote;
+  connector->Connect(service_name, remote.InitWithNewPipeAndPassReceiver());
+  return Create(std::move(remote), std::move(task_runner));
+}
+
+// static
+std::unique_ptr<Gpu> Gpu::Create(
+    mojo::PendingRemote<mojom::Gpu> remote,
+    scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) {
+  mojom::GpuPtr gpu_ptr(std::move(remote));
+  return base::WrapUnique(
+      new Gpu(std::move(gpu_ptr), std::move(io_task_runner)));
 }
 
 #if defined(OS_CHROMEOS)
diff --git a/services/viz/public/cpp/gpu/gpu.h b/services/viz/public/cpp/gpu/gpu.h
index a9458c44..eaa7cbf 100644
--- a/services/viz/public/cpp/gpu/gpu.h
+++ b/services/viz/public/cpp/gpu/gpu.h
@@ -13,6 +13,7 @@
 #include "base/single_thread_task_runner.h"
 #include "components/viz/common/gpu/context_provider.h"
 #include "gpu/ipc/client/gpu_channel_host.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "services/viz/public/cpp/gpu/client_gpu_memory_buffer_manager.h"
 #include "services/viz/public/mojom/gpu.mojom.h"
 
@@ -30,6 +31,9 @@
       service_manager::Connector* connector,
       const std::string& service_name,
       scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
+  static std::unique_ptr<Gpu> Create(
+      mojo::PendingRemote<mojom::Gpu> remote,
+      scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
 
   ~Gpu() override;
 
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index ad1eb50..ee7556f5 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -8994,6 +8994,633 @@
       }
     ]
   },
+  "Linux FYI Release (Intel UHD 630)": {
+    "gtest_tests": [
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--test-launcher-retry-limit=0"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "intel-uhd-630-ubuntu-stable",
+              "os": "Ubuntu-19.04",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 14400,
+          "shards": 4
+        },
+        "test": "angle_end2end_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--test-launcher-retry-limit=0",
+          "--no-xvfb"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "intel-uhd-630-ubuntu-stable",
+              "os": "Ubuntu-19.04",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 14400
+        },
+        "test": "angle_unittests"
+      },
+      {
+        "args": [
+          "--test-launcher-retry-limit=0"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "intel-uhd-630-ubuntu-stable",
+              "os": "Ubuntu-19.04",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 14400
+        },
+        "test": "angle_white_box_tests"
+      },
+      {
+        "args": [
+          "--enable-gpu",
+          "--test-launcher-bot-mode",
+          "--test-launcher-jobs=1",
+          "--test-launcher-filter-file=../../testing/buildbot/filters/vulkan.content_browsertests.filter",
+          "--enable-features=VizDisplayCompositor,UseSkiaRenderer,UiGpuRasterization",
+          "--use-vulkan=native",
+          "--enable-oop-rasterization",
+          "--enable-gpu-rasterization",
+          "--force-gpu-rasterization",
+          "--disable-software-compositing-fallback",
+          "--disable-vulkan-fallback-to-gl-for-testing",
+          "--disable-headless-mode",
+          "--no-xvfb"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "vulkan_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "intel-uhd-630-ubuntu-stable",
+              "os": "Ubuntu-19.04",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 14400
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--use-cmd-decoder=validating"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "intel-uhd-630-ubuntu-stable",
+              "os": "Ubuntu-19.04",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 14400
+        },
+        "test": "gl_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--no-xvfb"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "intel-uhd-630-ubuntu-stable",
+              "os": "Ubuntu-19.04",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 14400
+        },
+        "test": "gl_unittests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "intel-uhd-630-ubuntu-stable",
+              "os": "Ubuntu-19.04",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 14400
+        },
+        "test": "gles2_conform_test"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "intel-uhd-630-ubuntu-stable",
+              "os": "Ubuntu-19.04",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 14400
+        },
+        "test": "swiftshader_unittests"
+      }
+    ],
+    "isolated_scripts": [
+      {
+        "args": [
+          "context_lost",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "context_lost_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "intel-uhd-630-ubuntu-stable",
+              "os": "Ubuntu-19.04",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 14400,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "depth_capture",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "depth_capture_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "intel-uhd-630-ubuntu-stable",
+              "os": "Ubuntu-19.04",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 14400,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "gpu_process",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "gpu_process_launch_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "intel-uhd-630-ubuntu-stable",
+              "os": "Ubuntu-19.04",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 14400,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "hardware_accelerated_feature",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "hardware_accelerated_feature_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "intel-uhd-630-ubuntu-stable",
+              "os": "Ubuntu-19.04",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 14400,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "info_collection",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--expected-vendor-id",
+          "8086",
+          "--expected-device-id",
+          "3e92"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "info_collection_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "intel-uhd-630-ubuntu-stable",
+              "os": "Ubuntu-19.04",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 14400,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "maps",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--dont-restore-color-profile-after-test",
+          "--os-type",
+          "linux",
+          "--build-revision",
+          "${got_revision}",
+          "--test-machine-name",
+          "${buildername}"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "maps_pixel_test",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "intel-uhd-630-ubuntu-stable",
+              "os": "Ubuntu-19.04",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 14400,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "pixel",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--dont-restore-color-profile-after-test",
+          "--os-type",
+          "linux",
+          "--build-revision",
+          "${got_revision}",
+          "--test-machine-name",
+          "${buildername}"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "pixel_skia_gold_test",
+        "precommit_args": [
+          "--review-patch-issue",
+          "${patch_issue}",
+          "--review-patch-set",
+          "${patch_set}",
+          "--buildbucket-build-id",
+          "${buildbucket_build_id}"
+        ],
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "intel-uhd-630-ubuntu-stable",
+              "os": "Ubuntu-19.04",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 14400,
+          "idempotent": false,
+          "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com"
+        }
+      },
+      {
+        "args": [
+          "screenshot_sync",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--dont-restore-color-profile-after-test"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "screenshot_sync_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "intel-uhd-630-ubuntu-stable",
+              "os": "Ubuntu-19.04",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 14400,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "trace_test",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "trace_test",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "intel-uhd-630-ubuntu-stable",
+              "os": "Ubuntu-19.04",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 14400,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=gl --use-cmd-decoder=passthrough",
+          "--webgl-conformance-version=2.0.1",
+          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl2_conformance_gl_passthrough_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "intel-uhd-630-ubuntu-stable",
+              "os": "Ubuntu-19.04",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 14400,
+          "idempotent": false,
+          "shards": 20
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--webgl-conformance-version=2.0.1",
+          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl2_conformance_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "intel-uhd-630-ubuntu-stable",
+              "os": "Ubuntu-19.04",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 14400,
+          "idempotent": false,
+          "shards": 20
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=gl --use-cmd-decoder=passthrough"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_gl_passthrough_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "intel-uhd-630-ubuntu-stable",
+              "os": "Ubuntu-19.04",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 14400,
+          "idempotent": false,
+          "shards": 2
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "intel-uhd-630-ubuntu-stable",
+              "os": "Ubuntu-19.04",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 14400,
+          "idempotent": false,
+          "shards": 2
+        }
+      }
+    ]
+  },
   "Linux FYI Release (NVIDIA)": {
     "gtest_tests": [
       {
@@ -9980,7 +10607,8 @@
           "--skipped=always",
           "--test-list=../../testing/buildbot/filters/gpu.skiarenderer_vulkan_blink_web_tests.filter",
           "--additional-expectations=../../third_party/blink/web_tests/FlagExpectations/enable-features=UseSkiaRenderer",
-          "--additional-expectations=../../third_party/blink/web_tests/FlagExpectations/enable-gpu-rasterization"
+          "--additional-expectations=../../third_party/blink/web_tests/FlagExpectations/enable-gpu-rasterization",
+          "--additional-expectations=../../third_party/blink/web_tests/FlagExpectations/use-gl=any"
         ],
         "isolate_name": "blink_web_tests_exparchive",
         "merge": {
@@ -10491,7 +11119,8 @@
           "--skipped=always",
           "--test-list=../../testing/buildbot/filters/gpu.skiarenderer_vulkan_blink_web_tests.filter",
           "--additional-expectations=../../third_party/blink/web_tests/FlagExpectations/enable-features=UseSkiaRenderer",
-          "--additional-expectations=../../third_party/blink/web_tests/FlagExpectations/enable-gpu-rasterization"
+          "--additional-expectations=../../third_party/blink/web_tests/FlagExpectations/enable-gpu-rasterization",
+          "--additional-expectations=../../third_party/blink/web_tests/FlagExpectations/use-gl=any"
         ],
         "isolate_name": "blink_web_tests_exparchive",
         "merge": {
diff --git a/testing/buildbot/chromium.gpu.json b/testing/buildbot/chromium.gpu.json
index 8eafeb8..d6ea9f3 100644
--- a/testing/buildbot/chromium.gpu.json
+++ b/testing/buildbot/chromium.gpu.json
@@ -4245,5 +4245,1128 @@
         }
       }
     ]
+  },
+  "Win10 x64 Debug (NVIDIA)": {
+    "gtest_tests": [
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--test-launcher-retry-limit=0"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        },
+        "test": "angle_unittests"
+      },
+      {
+        "args": [
+          "--enable-gpu",
+          "--test-launcher-bot-mode",
+          "--test-launcher-jobs=1",
+          "--gtest_filter=CastStreamingApiTestWithPixelOutput.EndToEnd*:TabCaptureApiPixelTest.EndToEnd*"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "tab_capture_end2end_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        },
+        "test": "browser_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--use-cmd-decoder=validating"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        },
+        "test": "gl_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--use-cmd-decoder=passthrough"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "gl_tests_passthrough",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        },
+        "test": "gl_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        },
+        "test": "gl_unittests"
+      },
+      {
+        "args": [
+          "--use-angle=d3d11",
+          "--use-test-data-path",
+          "--test_video_data=test-25fps.h264:320:240:250:258:::1"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "video_decode_accelerator_d3d11_unittest",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        },
+        "test": "video_decode_accelerator_unittest"
+      },
+      {
+        "args": [
+          "--ignore-runtime-requirements=*"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "xr_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        },
+        "test": "xr_browser_tests"
+      }
+    ],
+    "isolated_scripts": [
+      {
+        "args": [
+          "context_lost",
+          "--show-stdout",
+          "--browser=debug_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "context_lost_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "depth_capture",
+          "--show-stdout",
+          "--browser=debug_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "depth_capture_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "gpu_process",
+          "--show-stdout",
+          "--browser=debug_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "gpu_process_launch_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "hardware_accelerated_feature",
+          "--show-stdout",
+          "--browser=debug_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "hardware_accelerated_feature_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "info_collection",
+          "--show-stdout",
+          "--browser=debug_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--expected-vendor-id",
+          "10de",
+          "--expected-device-id",
+          "1cb3"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "info_collection_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "maps",
+          "--show-stdout",
+          "--browser=debug_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--dont-restore-color-profile-after-test",
+          "--os-type",
+          "win",
+          "--build-revision",
+          "${got_revision}",
+          "--test-machine-name",
+          "${buildername}"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "maps_pixel_test",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "pixel",
+          "--show-stdout",
+          "--browser=debug_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--dont-restore-color-profile-after-test",
+          "--os-type",
+          "win",
+          "--build-revision",
+          "${got_revision}",
+          "--test-machine-name",
+          "${buildername}"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "pixel_skia_gold_test",
+        "precommit_args": [
+          "--review-patch-issue",
+          "${patch_issue}",
+          "--review-patch-set",
+          "${patch_set}",
+          "--buildbucket-build-id",
+          "${buildbucket_build_id}"
+        ],
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false,
+          "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com"
+        }
+      },
+      {
+        "args": [
+          "screenshot_sync",
+          "--show-stdout",
+          "--browser=debug_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--dont-restore-color-profile-after-test"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "screenshot_sync_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "trace_test",
+          "--show-stdout",
+          "--browser=debug_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "trace_test",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=debug_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false,
+          "shards": 2
+        }
+      }
+    ]
+  },
+  "Win10 x64 Release (NVIDIA)": {
+    "gtest_tests": [
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--test-launcher-retry-limit=0"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        },
+        "test": "angle_unittests",
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
+          "--enable-gpu",
+          "--test-launcher-bot-mode",
+          "--test-launcher-jobs=1",
+          "--gtest_filter=CastStreamingApiTestWithPixelOutput.EndToEnd*:TabCaptureApiPixelTest.EndToEnd*"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "tab_capture_end2end_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        },
+        "test": "browser_tests",
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--use-cmd-decoder=validating"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        },
+        "test": "gl_tests",
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--use-cmd-decoder=passthrough"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "gl_tests_passthrough",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        },
+        "test": "gl_tests",
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        },
+        "test": "gl_unittests",
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
+          "--use-angle=d3d11",
+          "--use-test-data-path",
+          "--test_video_data=test-25fps.h264:320:240:250:258:::1"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "video_decode_accelerator_d3d11_unittest",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        },
+        "test": "video_decode_accelerator_unittest",
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
+          "--ignore-runtime-requirements=*"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "xr_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        },
+        "test": "xr_browser_tests",
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      }
+    ],
+    "isolated_scripts": [
+      {
+        "args": [
+          "context_lost",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "context_lost_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        },
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
+          "depth_capture",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "depth_capture_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        },
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
+          "gpu_process",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "gpu_process_launch_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        },
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
+          "hardware_accelerated_feature",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "hardware_accelerated_feature_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        },
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
+          "info_collection",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--expected-vendor-id",
+          "10de",
+          "--expected-device-id",
+          "1cb3"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "info_collection_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        },
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
+          "maps",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--dont-restore-color-profile-after-test",
+          "--os-type",
+          "win",
+          "--build-revision",
+          "${got_revision}",
+          "--test-machine-name",
+          "${buildername}"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "maps_pixel_test",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        },
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
+          "pixel",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--dont-restore-color-profile-after-test",
+          "--os-type",
+          "win",
+          "--build-revision",
+          "${got_revision}",
+          "--test-machine-name",
+          "${buildername}"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "pixel_skia_gold_test",
+        "precommit_args": [
+          "--review-patch-issue",
+          "${patch_issue}",
+          "--review-patch-set",
+          "${patch_set}",
+          "--buildbucket-build-id",
+          "${buildbucket_build_id}"
+        ],
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false,
+          "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
+          "screenshot_sync",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--dont-restore-color-profile-after-test"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "screenshot_sync_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        },
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
+          "trace_test",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "trace_test",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        },
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false,
+          "shards": 2
+        },
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      }
+    ]
   }
 }
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index e9c158c..70f195f 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -1572,7 +1572,7 @@
       "--also-run-disabled-tests",
       "-v",
       "--use-live-sites",
-      "--output-format=chartjson",
+      "--output-format=histograms",
       "--output-dir=${ISOLATED_OUTDIR}",
     ],
     "label": "//chrome/test/media_router:media_router_perf_tests",
diff --git a/testing/buildbot/mixins.pyl b/testing/buildbot/mixins.pyl
index e34ebc9..6c439e18 100644
--- a/testing/buildbot/mixins.pyl
+++ b/testing/buildbot/mixins.pyl
@@ -295,6 +295,20 @@
       },
     },
   },
+  'linux_intel_uhd_630': {
+    'swarming': {
+      'dimensions': {
+        # Defined in bot_config.py in internal infradata/config workspace
+        'gpu': 'intel-uhd-630-ubuntu-stable',
+        'os': 'Ubuntu-19.04',
+        'pool': 'Chrome-GPU',
+      },
+      # Same long expiration as win10_intel_uhd_630_stable due to capacity.
+      # TODO(https://crbug.com/986939): Remove this when more devices
+      # are added.
+      'expiration': 14400,
+    }
+  },
   'linux_nvidia_quadro_p400': {
     'swarming': {
       'dimensions': {
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index e30d126..38beb708 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -1452,6 +1452,7 @@
       'Win7 FYI Debug (AMD)',
       # Disabled due to dbus crashes crbug.com/927465
       'Linux FYI Release (Intel HD 630)',
+      'Linux FYI Release (Intel UHD 630)',
       'Linux FYI Release (NVIDIA)',
       'Linux FYI SkiaRenderer Vulkan (Intel HD 630)',
       'Linux FYI SkiaRenderer Vulkan (NVIDIA)',
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index b019f75..b226aaa 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -3236,6 +3236,7 @@
           '--test-list=../../testing/buildbot/filters/gpu.skiarenderer_vulkan_blink_web_tests.filter',
           '--additional-expectations=../../third_party/blink/web_tests/FlagExpectations/enable-features=UseSkiaRenderer',
           '--additional-expectations=../../third_party/blink/web_tests/FlagExpectations/enable-gpu-rasterization',
+          '--additional-expectations=../../third_party/blink/web_tests/FlagExpectations/use-gl=any',
         ],
         'isolate_name': 'blink_web_tests_exparchive',
         'merge': {
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 9db8255c..b088d11 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -2232,6 +2232,30 @@
         # We keep this value enabled to provide minimal regression testing.
         'use_multi_dimension_trigger_script': True,
       },
+      'Win10 x64 Debug (NVIDIA)': {
+        'browser_config': 'debug_x64',
+        'os_type': 'win',
+        'mixins': [
+          'win10_nvidia_quadro_p400_stable',
+        ],
+        'test_suites': {
+          'gtest_tests': 'gpu_win_gtests',
+          'gpu_telemetry_tests': 'gpu_common_win_and_linux_telemetry_tests',
+        },
+      },
+      'Win10 x64 Release (NVIDIA)': {
+        'browser_config': 'release_x64',
+        'os_type': 'win',
+        'mixins': [
+          'win10_nvidia_quadro_p400_stable',
+        ],
+        'test_suites': {
+          'gtest_tests': 'gpu_win_gtests',
+          'gpu_telemetry_tests': 'gpu_common_win_and_linux_telemetry_tests',
+        },
+        # We keep this value enabled to provide minimal regression testing.
+        'use_multi_dimension_trigger_script': True,
+      },
     },
   },
   {
@@ -2643,6 +2667,17 @@
           'gpu_telemetry_tests': 'gpu_fyi_linux_intel_and_nvidia_release_telemetry_tests',
         },
       },
+      'Linux FYI Release (Intel UHD 630)': {
+        'os_type': 'linux',
+        'browser_config': 'release',
+        'mixins': [
+          'linux_intel_uhd_630',
+        ],
+        'test_suites': {
+          'gtest_tests': 'gpu_fyi_linux_release_gtests',
+          'gpu_telemetry_tests': 'gpu_fyi_linux_intel_and_nvidia_release_telemetry_tests',
+        },
+      },
       'Linux FYI Release (NVIDIA)': {
         'os_type': 'linux',
         'browser_config': 'release',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 4e04c96f..0417141 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1866,7 +1866,11 @@
                 {
                     "name": "Enabled",
                     "enable_features": [
-                        "DirectCompositionGpuVSync"
+                        "DirectCompositionGpuVSync",
+                        "DirectCompositionPresentationFeedback"
+                    ],
+                    "disable_features": [
+                        "DirectCompositionLowLatencyPresentation"
                     ]
                 }
             ]
diff --git a/third_party/blink/public/mojom/broadcastchannel/broadcast_channel.mojom b/third_party/blink/public/mojom/broadcastchannel/broadcast_channel.mojom
index 740aa500..f986930 100644
--- a/third_party/blink/public/mojom/broadcastchannel/broadcast_channel.mojom
+++ b/third_party/blink/public/mojom/broadcastchannel/broadcast_channel.mojom
@@ -31,6 +31,6 @@
   // be sent to the channel using |sender|, and messages to the channel will be
   // received by |receiver|.
   ConnectToChannel(url.mojom.Origin origin, string name,
-                   associated BroadcastChannelClient receiver,
-                   associated BroadcastChannelClient& sender);
+                   pending_associated_remote<BroadcastChannelClient> receiver,
+                   pending_associated_receiver<BroadcastChannelClient> sender);
 };
diff --git a/third_party/blink/public/mojom/idle/idle_manager.mojom b/third_party/blink/public/mojom/idle/idle_manager.mojom
index 09118ab00..8c5e496 100644
--- a/third_party/blink/public/mojom/idle/idle_manager.mojom
+++ b/third_party/blink/public/mojom/idle/idle_manager.mojom
@@ -34,6 +34,7 @@
   // initial state. It will be notified by calls to Update() per the threshold
   // registered for this instance. It can be unregistered by simply closing
   // the pipe.
-  AddMonitor(mojo_base.mojom.TimeDelta threshold, IdleMonitor monitor)
+  AddMonitor(mojo_base.mojom.TimeDelta threshold,
+             pending_remote<IdleMonitor> monitor)
       => (IdleState state);
 };
diff --git a/third_party/blink/renderer/core/animation/animation_test.cc b/third_party/blink/renderer/core/animation/animation_test.cc
index 3d1e7bf3..3d5c7cdc 100644
--- a/third_party/blink/renderer/core/animation/animation_test.cc
+++ b/third_party/blink/renderer/core/animation/animation_test.cc
@@ -165,14 +165,8 @@
 
   bool SimulateFrame(double time_ms) {
     last_frame_time = time_ms;
-    const PaintArtifactCompositor* paint_artifact_compositor = nullptr;
-    if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
-        RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-      paint_artifact_compositor = GetDocument()
-                                      .GetFrame()
-                                      ->View()
-                                      ->GetPaintArtifactCompositorForTesting();
-    }
+    const auto* paint_artifact_compositor =
+        GetDocument().GetFrame()->View()->GetPaintArtifactCompositor();
     GetDocument().GetAnimationClock().UpdateTime(
         base::TimeTicks() + base::TimeDelta::FromMillisecondsD(time_ms));
     GetDocument().GetPendingAnimations().Update(paint_artifact_compositor,
diff --git a/third_party/blink/renderer/core/animation/compositor_animations.cc b/third_party/blink/renderer/core/animation/compositor_animations.cc
index a6da04b..db9e627 100644
--- a/third_party/blink/renderer/core/animation/compositor_animations.cc
+++ b/third_party/blink/renderer/core/animation/compositor_animations.cc
@@ -151,12 +151,6 @@
 
 CompositorElementIdNamespace CompositorElementNamespaceForProperty(
     CSSPropertyID property) {
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
-      !RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-    // Pre-BlinkGenPropertyTrees, all animations affect the primary
-    // ElementId namespace.
-    return CompositorElementIdNamespace::kPrimary;
-  }
   switch (property) {
     case CSSPropertyID::kOpacity:
     case CSSPropertyID::kBackdropFilter:
@@ -517,16 +511,12 @@
 
   CompositorElementIdNamespace element_id_namespace =
       CompositorElementIdNamespace::kPrimary;
-  // With BlinkGenPropertyTrees we create an animation namespace element id
-  // when an element has created all property tree nodes which may be required
-  // by the keyframe effects. The animation affects multiple element ids, and
-  // one is pushed each KeyframeModel. See |GetAnimationOnCompositor|.
-  // Currently we use the kPrimaryEffect node to know if nodes have been
-  // created for animations.
-  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
-      RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-    element_id_namespace = CompositorElementIdNamespace::kPrimaryEffect;
-  }
+  // We create an animation namespace element id when an element has created all
+  // property tree nodes which may be required by the keyframe effects. The
+  // animation affects multiple element ids, and one is pushed each
+  // KeyframeModel. See |GetAnimationOnCompositor|. We use the kPrimaryEffect
+  // node to know if nodes have been created for animations.
+  element_id_namespace = CompositorElementIdNamespace::kPrimaryEffect;
   compositor_animation->AttachElement(CompositorElementIdFromUniqueObjectId(
       element.GetLayoutObject()->UniqueId(), element_id_namespace));
 }
diff --git a/third_party/blink/renderer/core/animation/compositor_animations_test.cc b/third_party/blink/renderer/core/animation/compositor_animations_test.cc
index 358dfd0..23c040a 100644
--- a/third_party/blink/renderer/core/animation/compositor_animations_test.cc
+++ b/third_party/blink/renderer/core/animation/compositor_animations_test.cc
@@ -1835,9 +1835,8 @@
 }
 
 TEST_P(AnimationCompositorAnimationsTest, CompositedTransformAnimation) {
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
-      // TODO(wangxianzhu): Fix this test for CompositeAfterPaint.
-      RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+  // TODO(wangxianzhu): Fix this test for CompositeAfterPaint.
+  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
     return;
 
   LoadTestData("transform-animation.html");
@@ -1873,9 +1872,8 @@
 }
 
 TEST_P(AnimationCompositorAnimationsTest, CompositedScaleAnimation) {
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
-      // TODO(wangxianzhu): Fix this test for CompositeAfterPaint.
-      RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+  // TODO(wangxianzhu): Fix this test for CompositeAfterPaint.
+  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
     return;
 
   LoadTestData("scale-animation.html");
@@ -1912,11 +1910,8 @@
 
 TEST_P(AnimationCompositorAnimationsTest,
        NonAnimatedTransformPropertyChangeGetsUpdated) {
-  // This test doesn't apply for pre-BlinkGenPropertyTrees due to the element id
-  // namespaces.
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
-      // TODO(wangxianzhu): Fix this test for CompositeAfterPaint.
-      RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+  // TODO(wangxianzhu): Fix this test for CompositeAfterPaint.
+  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
     return;
 
   LoadTestData("transform-animation-update.html");
diff --git a/third_party/blink/renderer/core/animation/length_interpolation_functions.cc b/third_party/blink/renderer/core/animation/length_interpolation_functions.cc
index 33910e6..9bab07c 100644
--- a/third_party/blink/renderer/core/animation/length_interpolation_functions.cc
+++ b/third_party/blink/renderer/core/animation/length_interpolation_functions.cc
@@ -111,6 +111,11 @@
   if (!length.IsSpecified())
     return nullptr;
 
+  if (length.IsCalculated() && length.GetCalculationValue().IsExpression()) {
+    // TODO(crbug.com/991672): Support interpolation on min/max results.
+    return nullptr;
+  }
+
   PixelsAndPercent pixels_and_percent = length.GetPixelsAndPercent();
   auto values = CreateNeutralInterpolableValue();
   values->Set(
diff --git a/third_party/blink/renderer/core/css/css_primitive_value.cc b/third_party/blink/renderer/core/css/css_primitive_value.cc
index 224ded2..1b382fa9 100644
--- a/third_party/blink/renderer/core/css/css_primitive_value.cc
+++ b/third_party/blink/renderer/core/css/css_primitive_value.cc
@@ -32,6 +32,7 @@
 #include "third_party/blink/renderer/core/css/css_to_length_conversion_data.h"
 #include "third_party/blink/renderer/core/css/css_value_pool.h"
 #include "third_party/blink/renderer/platform/geometry/layout_unit.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/size_assertions.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
@@ -183,6 +184,11 @@
                                             UnitType::kPixels);
     case Length::kCalculated: {
       const CalculationValue& calc = length.GetCalculationValue();
+      if (calc.IsExpression()) {
+        // TODO(crbug.com/825895): Implement min() and max().
+        DCHECK(RuntimeEnabledFeatures::CSSComparisonFunctionsEnabled());
+        return nullptr;
+      }
       if (calc.Pixels() && calc.Percent())
         return CSSMathFunctionValue::Create(length, zoom);
       if (calc.Percent()) {
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
index 2a4cb1b..9553dba 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
@@ -1410,12 +1410,6 @@
 
 TEST_F(DisplayLockContextTest,
        CompositedLayerLockCausesGraphicsLayersCollection) {
-  // This test only tests the BGPT path.
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
-      RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-    return;
-  }
-
   ResizeAndFocus();
   GetDocument().GetSettings()->SetPreferCompositingToLCDTextEnabled(true);
 
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 8274888..59ddfc2 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -1923,28 +1923,30 @@
       GetElementData()->presentation_attribute_style_is_dirty_ = true;
       SetNeedsStyleRecalc(kLocalStyleChange,
                           StyleChangeReasonForTracing::FromAttribute(name));
+
+      if (RuntimeEnabledFeatures::DisplayLockingEnabled() &&
+          name == html_names::kRendersubtreeAttr &&
+          params.old_value != params.new_value) {
+        const bool should_be_invisible =
+            EqualIgnoringASCIICase(params.new_value, "invisible");
+        const bool should_be_invisible_activatable =
+            EqualIgnoringASCIICase(params.new_value, "invisible-activatable");
+        if (should_be_invisible || should_be_invisible_activatable) {
+          // Getting locked.
+          EnsureDisplayLockContext().SetActivatable(
+              should_be_invisible_activatable);
+          if (!GetDisplayLockContext()->IsLocked())
+            GetDisplayLockContext()->StartAcquire();
+        } else {
+          // Getting unlocked.
+          if (EnsureDisplayLockContext().IsLocked())
+            GetDisplayLockContext()->StartCommit();
+        }
+      }
     } else if (RuntimeEnabledFeatures::InvisibleDOMEnabled() &&
                name == html_names::kInvisibleAttr &&
                params.old_value != params.new_value) {
       InvisibleAttributeChanged(params.old_value, params.new_value);
-    } else if (RuntimeEnabledFeatures::DisplayLockingEnabled() &&
-               name == html_names::kRendersubtreeAttr &&
-               params.old_value != params.new_value) {
-      const bool should_be_invisible =
-          EqualIgnoringASCIICase(params.new_value, "invisible");
-      const bool should_be_invisible_activatable =
-          EqualIgnoringASCIICase(params.new_value, "invisible-activatable");
-      if (should_be_invisible || should_be_invisible_activatable) {
-        // Getting locked.
-        EnsureDisplayLockContext().SetActivatable(
-            should_be_invisible_activatable);
-        if (!GetDisplayLockContext()->IsLocked())
-          GetDisplayLockContext()->StartAcquire();
-      } else {
-        // Getting unlocked.
-        if (EnsureDisplayLockContext().IsLocked())
-          GetDisplayLockContext()->StartCommit();
-      }
     }
   }
 
diff --git a/third_party/blink/renderer/core/dom/element.h b/third_party/blink/renderer/core/dom/element.h
index 68f4bdc..f924460 100644
--- a/third_party/blink/renderer/core/dom/element.h
+++ b/third_party/blink/renderer/core/dom/element.h
@@ -444,7 +444,7 @@
   void SynchronizeStyleAttributeInternal() const;
 
   const CSSPropertyValueSet* PresentationAttributeStyle();
-  virtual bool IsPresentationAttribute(const QualifiedName&) const {
+  virtual bool IsPresentationAttribute(const QualifiedName& attr) const {
     return false;
   }
   virtual void CollectStyleForPresentationAttribute(
diff --git a/third_party/blink/renderer/core/exported/web_layer_test.cc b/third_party/blink/renderer/core/exported/web_layer_test.cc
index ffbd4a4..9125fd8 100644
--- a/third_party/blink/renderer/core/exported/web_layer_test.cc
+++ b/third_party/blink/renderer/core/exported/web_layer_test.cc
@@ -107,7 +107,7 @@
 
  private:
   PaintArtifactCompositor* paint_artifact_compositor() {
-    return GetLocalFrameView()->GetPaintArtifactCompositorForTesting();
+    return GetLocalFrameView()->GetPaintArtifactCompositor();
   }
 
   frame_test_helpers::TestWebWidgetClient web_widget_client_;
@@ -282,7 +282,7 @@
   }
 
   PaintArtifactCompositor* paint_artifact_compositor() {
-    return MainFrame().GetFrameView()->GetPaintArtifactCompositorForTesting();
+    return MainFrame().GetFrameView()->GetPaintArtifactCompositor();
   }
 };
 
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc
index 8be58c3..86b38e80 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -1535,8 +1535,7 @@
     MainFrameImpl()->GetFrame()->View()->EnsureUkmAggregator().RecordSample(
         LocalFrameUkmAggregator::kUpdateLayers,
         update_layers_start_time_.value(), base::TimeTicks::Now());
-    if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-      probe::LayerTreeDidChange(MainFrameImpl()->GetFrame());
+    probe::LayerTreeDidChange(MainFrameImpl()->GetFrame());
   }
   update_layers_start_time_.reset();
 }
diff --git a/third_party/blink/renderer/core/frame/frame_overlay.cc b/third_party/blink/renderer/core/frame/frame_overlay.cc
index 775930a..b80d012 100644
--- a/third_party/blink/renderer/core/frame/frame_overlay.cc
+++ b/third_party/blink/renderer/core/frame/frame_overlay.cc
@@ -72,16 +72,6 @@
     layer_ = std::make_unique<GraphicsLayer>(*this);
     layer_->SetDrawsContent(true);
     layer_->SetHitTestable(false);
-
-    if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-      // This is required for contents of overlay to stay in sync with the page
-      // while scrolling. When BlinkGenPropertyTrees is enabled, scrolling is
-      // prevented by using the root scroll node in the root property tree
-      // state.
-      cc::Layer* cc_layer = layer_->CcLayer();
-      cc_layer->AddMainThreadScrollingReasons(
-          cc::MainThreadScrollingReason::kFrameOverlay);
-    }
   }
 
   DCHECK(parent_layer);
diff --git a/third_party/blink/renderer/core/frame/frame_test_helpers.cc b/third_party/blink/renderer/core/frame/frame_test_helpers.cc
index 4154bc9..f156ac7 100644
--- a/third_party/blink/renderer/core/frame/frame_test_helpers.cc
+++ b/third_party/blink/renderer/core/frame/frame_test_helpers.cc
@@ -624,13 +624,7 @@
   // Use synchronous compositing so that the MessageLoop becomes idle and the
   // test makes progress.
   settings.single_thread_proxy_scheduler = false;
-  // Both BlinkGenPropertyTrees and CompositeAfterPaint should imply layer lists
-  // in the compositor. Some code across the boundaries makes assumptions based
-  // on this so ensure tests run using this configuration as well.
-  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
-      RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-    settings.use_layer_lists = true;
-  }
+  settings.use_layer_lists = true;
 
   layer_tree_view_ = std::make_unique<content::LayerTreeView>(
       specified_delegate ? specified_delegate : &delegate_,
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index f4e7059..5b19041 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -494,9 +494,7 @@
 
 void LocalFrame::DidFreeze() {
   if (GetDocument()) {
-    auto* document_resource_coordinator =
-        GetDocument()->GetResourceCoordinator();
-    if (document_resource_coordinator) {
+    if (GetDocument()->GetResourceCoordinator()) {
       // Determine if there is a beforeunload handler by dispatching a
       // beforeunload that will *not* launch a user dialog. If
       // |proceed| is false then there is a non-empty beforeunload
@@ -504,13 +502,21 @@
       bool unused_did_allow_navigation = false;
       bool proceed = GetDocument()->DispatchBeforeUnloadEvent(
           nullptr, false /* is_reload */, unused_did_allow_navigation);
-      document_resource_coordinator->SetHasNonEmptyBeforeUnload(!proceed);
+      // Running the beforeunload event may invalidate the
+      // DocumentResourceCoordinator. Because of that, it can't be stored in a
+      // local variable that is reused throughout the method.
+      // https://crbug.com/991380.
+      auto* document_resource_coordinator =
+          GetDocument()->GetResourceCoordinator();
+      if (document_resource_coordinator)
+        document_resource_coordinator->SetHasNonEmptyBeforeUnload(!proceed);
     }
 
     GetDocument()->DispatchFreezeEvent();
     // TODO(fmeawad): Move the following logic to the page once we have a
     // PageResourceCoordinator in Blink. http://crbug.com/838415
-    if (document_resource_coordinator) {
+    if (auto* document_resource_coordinator =
+            GetDocument()->GetResourceCoordinator()) {
       document_resource_coordinator->SetLifecycleState(
           resource_coordinator::mojom::LifecycleState::kFrozen);
     }
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc
index c2c3ef9..c1e6eb8 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -2425,8 +2425,7 @@
       // PrePaintTreeWalk can reach this frame.
       frame_view.SetNeedsPaintPropertyUpdate();
       // We may record more foreign layers under the frame.
-      if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-        frame_view.GraphicsLayersDidChange();
+      frame_view.GraphicsLayersDidChange();
       if (auto* owner = frame_view.GetLayoutEmbeddedContent())
         owner->SetShouldCheckForPaintInvalidation();
     }
@@ -2495,56 +2494,51 @@
     }
   }
 
-  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
-      RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-    if (!print_mode_enabled) {
-      bool needed_update = !paint_artifact_compositor_ ||
-                           paint_artifact_compositor_->NeedsUpdate();
-      PushPaintArtifactToCompositor();
-      ForAllNonThrottledLocalFrameViews([this](LocalFrameView& frame_view) {
-        DocumentAnimations::UpdateAnimations(
-            frame_view.GetLayoutView()->GetDocument(),
-            DocumentLifecycle::kPaintClean, paint_artifact_compositor_.get());
-      });
+  if (!print_mode_enabled) {
+    bool needed_update = !paint_artifact_compositor_ ||
+                         paint_artifact_compositor_->NeedsUpdate();
+    PushPaintArtifactToCompositor();
+    ForAllNonThrottledLocalFrameViews([this](LocalFrameView& frame_view) {
+      DocumentAnimations::UpdateAnimations(
+          frame_view.GetLayoutView()->GetDocument(),
+          DocumentLifecycle::kPaintClean, paint_artifact_compositor_.get());
+    });
 
-      // Initialize animation properties in the newly created paint property
-      // nodes according to the current animation state. This is mainly for
-      // the running composited animations which didn't change state during
-      // above UpdateAnimations() but associated with new paint property nodes.
-      if (needed_update) {
-        auto* root_layer = RootCcLayer();
-        if (root_layer && root_layer->layer_tree_host()) {
-          root_layer->layer_tree_host()
-              ->mutator_host()
-              ->InitClientAnimationState();
-        }
+    // Initialize animation properties in the newly created paint property
+    // nodes according to the current animation state. This is mainly for
+    // the running composited animations which didn't change state during
+    // above UpdateAnimations() but associated with new paint property nodes.
+    if (needed_update) {
+      auto* root_layer = RootCcLayer();
+      if (root_layer && root_layer->layer_tree_host()) {
+        root_layer->layer_tree_host()
+            ->mutator_host()
+            ->InitClientAnimationState();
       }
+    }
 
-      // Notify the controller that the artifact has been pushed and some
-      // lifecycle state can be freed (such as raster invalidations).
-      if (paint_controller_)
-        paint_controller_->FinishCycle();
+    // Notify the controller that the artifact has been pushed and some
+    // lifecycle state can be freed (such as raster invalidations).
+    if (paint_controller_)
+      paint_controller_->FinishCycle();
 
-      // PaintController for BlinkGenPropertyTrees is transient.
-      if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
-          !RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-        // Property tree changed state is typically cleared through
-        // |PaintController::FinishCycle| but that will be a no-op because
-        // the paint controller is transient, so force the changed state to be
-        // cleared here.
-        if (paint_controller_) {
-          paint_controller_->ClearPropertyTreeChangedStateTo(
-              PropertyTreeState::Root());
-        }
-        auto* root = GetLayoutView()->Compositor()->PaintRootGraphicsLayer();
-        if (root) {
-          ForAllGraphicsLayers(*root, [](GraphicsLayer& layer) {
-            if (layer.PaintsContentOrHitTest() && layer.HasLayerState()) {
-              layer.GetPaintController().ClearPropertyTreeChangedStateTo(
-                  layer.GetPropertyTreeState());
-            }
-          });
-        }
+    if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+      // Property tree changed state is typically cleared through
+      // |PaintController::FinishCycle| but that will be a no-op because
+      // the paint controller is transient, so force the changed state to be
+      // cleared here.
+      if (paint_controller_) {
+        paint_controller_->ClearPropertyTreeChangedStateTo(
+            PropertyTreeState::Root());
+      }
+      auto* root = GetLayoutView()->Compositor()->PaintRootGraphicsLayer();
+      if (root) {
+        ForAllGraphicsLayers(*root, [](GraphicsLayer& layer) {
+          if (layer.PaintsContentOrHitTest() && layer.HasLayerState()) {
+            layer.GetPaintController().ClearPropertyTreeChangedStateTo(
+                layer.GetPropertyTreeState());
+          }
+        });
       }
     }
   }
@@ -2591,7 +2585,6 @@
 
 static void CollectViewportLayersForLayerList(GraphicsContext& context,
                                               VisualViewport& visual_viewport) {
-  DCHECK(RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled());
   RecordGraphicsLayerAsForeignLayer(context, visual_viewport.ContainerLayer());
   RecordGraphicsLayerAsForeignLayer(context, visual_viewport.PageScaleLayer());
   RecordGraphicsLayerAsForeignLayer(context, visual_viewport.ScrollLayer());
@@ -2600,8 +2593,6 @@
 static void CollectDrawableLayersForLayerListRecursively(
     GraphicsContext& context,
     const GraphicsLayer* layer) {
-  DCHECK(RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled());
-
   if (!layer || layer->Client().ShouldThrottleRendering() ||
       layer->Client().IsUnderSVGHiddenContainer()) {
     return;
@@ -2629,7 +2620,6 @@
                        layer->GetContentsPropertyTreeState());
   }
 
-  DCHECK(!layer->ContentsClippingMaskLayer());
   for (const auto* child : layer->Children())
     CollectDrawableLayersForLayerListRecursively(context, child);
   CollectDrawableLayersForLayerListRecursively(context, layer->MaskLayer());
@@ -2638,8 +2628,6 @@
 static void CollectLinkHighlightLayersForLayerListRecursively(
     GraphicsContext& context,
     const GraphicsLayer* layer) {
-  DCHECK(RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled());
-
   if (!layer || layer->Client().ShouldThrottleRendering())
     return;
 
@@ -2748,25 +2736,12 @@
 }
 
 const cc::Layer* LocalFrameView::RootCcLayer() const {
-  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
-      RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-    return paint_artifact_compositor_ ? paint_artifact_compositor_->RootLayer()
-                                      : nullptr;
-  }
-
-  if (const auto* root_graphics_layer =
-          frame_->GetPage()->GetVisualViewport().RootGraphicsLayer()) {
-    return root_graphics_layer->CcLayer();
-  }
-  return nullptr;
+  return paint_artifact_compositor_ ? paint_artifact_compositor_->RootLayer()
+                                    : nullptr;
 }
 
 void LocalFrameView::PushPaintArtifactToCompositor() {
   TRACE_EVENT0("blink", "LocalFrameView::pushPaintArtifactToCompositor");
-
-  DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
-         RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled());
-
   if (!frame_->GetSettings()->GetAcceleratedCompositingEnabled())
     return;
 
@@ -2781,8 +2756,7 @@
             // The layer being scrolled is destroyed before the
             // ScrollingCoordinator.
             WrapWeakPersistent(page->GetScrollingCoordinator())));
-    if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-      GetLayoutView()->Compositor()->AttachRootLayerViaChromeClient();
+    GetLayoutView()->Compositor()->AttachRootLayerViaChromeClient();
     page->GetChromeClient().AttachRootLayer(
         paint_artifact_compositor_->RootLayer(), &GetFrame());
   }
@@ -2809,8 +2783,7 @@
   settings.prefer_compositing_to_lcd_text =
       page->GetSettings().GetPreferCompositingToLCDTextEnabled();
 
-  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
-      !RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
+  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
       !paint_controller_) {
     // BlinkGenPropertyTrees just needs a transient PaintController to collect
     // the foreign layers which doesn't need caching. It also shouldn't affect
@@ -4017,8 +3990,7 @@
   DCHECK(!frame_->GetDocument() || !frame_->GetDocument()->InStyleRecalc());
 
   // We may record more/less foreign layers under the frame.
-  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    GraphicsLayersDidChange();
+  GraphicsLayersDidChange();
 
   if (!CanThrottleRendering())
     InvalidateForThrottlingChange();
@@ -4361,21 +4333,10 @@
 
 String LocalFrameView::MainThreadScrollingReasonsAsText() {
   MainThreadScrollingReasons reasons = 0;
-  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
-      RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-    DCHECK(Lifecycle().GetState() >= DocumentLifecycle::kPrePaintClean);
-    const auto* properties = GetLayoutView()->FirstFragment().PaintProperties();
-    if (properties && properties->Scroll())
-      reasons = properties->Scroll()->GetMainThreadScrollingReasons();
-  } else {
-    DCHECK(Lifecycle().GetState() >= DocumentLifecycle::kCompositingClean);
-    reasons = main_thread_scrolling_reasons_;
-    if (auto* layer_for_scrolling = LayoutViewport()->LayerForScrolling()) {
-      if (cc::Layer* cc_layer = layer_for_scrolling->CcLayer())
-        reasons = cc_layer->GetMainThreadScrollingReasons();
-    }
-  }
-
+  DCHECK(Lifecycle().GetState() >= DocumentLifecycle::kPrePaintClean);
+  const auto* properties = GetLayoutView()->FirstFragment().PaintProperties();
+  if (properties && properties->Scroll())
+    reasons = properties->Scroll()->GetMainThreadScrollingReasons();
   return String(cc::MainThreadScrollingReason::AsText(reasons).c_str());
 }
 
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.h b/third_party/blink/renderer/core/frame/local_frame_view.h
index 1558182..af00d79 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.h
+++ b/third_party/blink/renderer/core/frame/local_frame_view.h
@@ -670,12 +670,6 @@
   void ScrollRectToVisibleInRemoteParent(const PhysicalRect&,
                                          const WebScrollIntoViewParams&);
 
-  PaintArtifactCompositor* GetPaintArtifactCompositorForTesting() {
-    DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
-           RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled());
-    return paint_artifact_compositor_.get();
-  }
-
   PaintArtifactCompositor* GetPaintArtifactCompositor() const;
 
   const cc::Layer* RootCcLayer() const;
diff --git a/third_party/blink/renderer/core/frame/visual_viewport.cc b/third_party/blink/renderer/core/frame/visual_viewport.cc
index e85b9cf95..847d84e 100644
--- a/third_party/blink/renderer/core/frame/visual_viewport.cc
+++ b/third_party/blink/renderer/core/frame/visual_viewport.cc
@@ -547,18 +547,8 @@
 
     // SVG runs with accelerated compositing disabled so no
     // ScrollingCoordinator.
-    if (ScrollingCoordinator* coordinator =
-            GetPage().GetScrollingCoordinator()) {
-      // In BGPT, scroll offsets and related properties are set directly on the
-      // property trees so all we need to do is update the scroll offset on the
-      // corresponding cc::Layer. Pre-BGPT we used ScrollLayerDidChange but
-      // since all we need this for is to update the cc::Layer's offset, we now
-      // use the more purpose-built UpdateCompositedScrollOffset, as in PLSA.
-      if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-        coordinator->ScrollableAreaScrollLayerDidChange(this);
-      else
-        coordinator->UpdateCompositedScrollOffset(this);
-    }
+    if (auto* coordinator = GetPage().GetScrollingCoordinator())
+      coordinator->UpdateCompositedScrollOffset(this);
 
     EnqueueScrollEvent();
 
@@ -593,34 +583,18 @@
     return;
 
   DCHECK(!overlay_scrollbar_horizontal_ && !overlay_scrollbar_vertical_ &&
-         !overscroll_elasticity_layer_ && !page_scale_layer_ &&
-         !inner_viewport_container_layer_);
+         !page_scale_layer_ && !inner_viewport_container_layer_);
 
   needs_paint_property_update_ = true;
 
   // FIXME: The root transform layer should only be created on demand.
   root_transform_layer_ = std::make_unique<GraphicsLayer>(*this);
   inner_viewport_container_layer_ = std::make_unique<GraphicsLayer>(*this);
-  // TODO(crbug.com/836884) Should remove overscroll_elasticity_layer_ after
-  // BGPT landed.
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-    overscroll_elasticity_layer_ = std::make_unique<GraphicsLayer>(*this);
-    overscroll_elasticity_layer_->SetElementId(
-        GetCompositorOverscrollElasticityElementId());
-  }
   page_scale_layer_ = std::make_unique<GraphicsLayer>(*this);
   inner_viewport_scroll_layer_ = std::make_unique<GraphicsLayer>(*this);
 
   ScrollingCoordinator* coordinator = GetPage().GetScrollingCoordinator();
   DCHECK(coordinator);
-  // Only used by the cc property tree builder and is not needed when blink
-  // generates property trees.
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
-      !RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-    inner_viewport_scroll_layer_->SetIsContainerForFixedPositionLayers(true);
-  }
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    coordinator->UpdateUserInputScrollable(this);
 
   // Set masks to bounds so the compositor doesn't clobber a manually
   // set inner viewport container layer size.
@@ -636,17 +610,8 @@
   page_scale_layer_->SetElementId(GetCompositorElementId());
 
   root_transform_layer_->AddChild(inner_viewport_container_layer_.get());
-  // TODO(crbug.com/836884) Should remove overscroll_elasticity_layer_ after
-  // BGPT landed.
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-    inner_viewport_container_layer_->AddChild(
-        overscroll_elasticity_layer_.get());
-    overscroll_elasticity_layer_->AddChild(page_scale_layer_.get());
-    page_scale_layer_->AddChild(inner_viewport_scroll_layer_.get());
-  } else {
-    inner_viewport_container_layer_->AddChild(page_scale_layer_.get());
-    page_scale_layer_->AddChild(inner_viewport_scroll_layer_.get());
-  }
+  inner_viewport_container_layer_->AddChild(page_scale_layer_.get());
+  page_scale_layer_->AddChild(inner_viewport_scroll_layer_.get());
 
   // Ensure this class is set as the scroll layer's ScrollableArea.
   coordinator->ScrollableAreaScrollLayerDidChange(this);
@@ -1206,8 +1171,6 @@
   String name;
   if (graphics_layer == inner_viewport_container_layer_.get()) {
     name = "Inner Viewport Container Layer";
-  } else if (graphics_layer == overscroll_elasticity_layer_.get()) {
-    name = "Overscroll Elasticity Layer";
   } else if (graphics_layer == page_scale_layer_.get()) {
     name = "Page Scale Layer";
   } else if (graphics_layer == inner_viewport_scroll_layer_.get()) {
@@ -1247,7 +1210,6 @@
 void VisualViewport::DisposeImpl() {
   root_transform_layer_.reset();
   inner_viewport_container_layer_.reset();
-  overscroll_elasticity_layer_.reset();
   page_scale_layer_.reset();
   inner_viewport_scroll_layer_.reset();
   // scrollbar_layer_group_* are referenced from overlay_scrollbar_*, thus
diff --git a/third_party/blink/renderer/core/frame/visual_viewport.h b/third_party/blink/renderer/core/frame/visual_viewport.h
index 91a8808..ffa1ebd7 100644
--- a/third_party/blink/renderer/core/frame/visual_viewport.h
+++ b/third_party/blink/renderer/core/frame/visual_viewport.h
@@ -112,9 +112,6 @@
   }
   GraphicsLayer* ScrollLayer() { return inner_viewport_scroll_layer_.get(); }
   GraphicsLayer* PageScaleLayer() { return page_scale_layer_.get(); }
-  GraphicsLayer* OverscrollElasticityLayer() {
-    return overscroll_elasticity_layer_.get();
-  }
 
   void InitializeScrollbars();
 
@@ -336,7 +333,6 @@
   Member<Page> page_;
   std::unique_ptr<GraphicsLayer> root_transform_layer_;
   std::unique_ptr<GraphicsLayer> inner_viewport_container_layer_;
-  std::unique_ptr<GraphicsLayer> overscroll_elasticity_layer_;
   std::unique_ptr<GraphicsLayer> page_scale_layer_;
   std::unique_ptr<GraphicsLayer> inner_viewport_scroll_layer_;
 
diff --git a/third_party/blink/renderer/core/frame/visual_viewport_test.cc b/third_party/blink/renderer/core/frame/visual_viewport_test.cc
index 72d1df7..bbe80ca 100644
--- a/third_party/blink/renderer/core/frame/visual_viewport_test.cc
+++ b/third_party/blink/renderer/core/frame/visual_viewport_test.cc
@@ -127,7 +127,7 @@
 
   PaintArtifactCompositor* paint_artifact_compositor() {
     LocalFrameView& frame_view = *WebView()->MainFrameImpl()->GetFrameView();
-    return frame_view.GetPaintArtifactCompositorForTesting();
+    return frame_view.GetPaintArtifactCompositor();
   }
 
   void ForceFullCompositingUpdate() { UpdateAllLifecyclePhases(); }
@@ -386,8 +386,7 @@
                        visual_viewport.VisibleRect().Size());
 
   // Verify the paint property nodes and GeometryMapper cache.
-  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
-      RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
+  {
     UpdateAllLifecyclePhases();
     EXPECT_EQ(TransformationMatrix().Scale(2),
               visual_viewport.GetPageScaleNode()->Matrix());
@@ -411,8 +410,7 @@
   EXPECT_FLOAT_SIZE_EQ(FloatSize(0, 75), visual_viewport.GetScrollOffset());
 
   // Verify the paint property nodes and GeometryMapper cache.
-  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
-      RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
+  {
     UpdateAllLifecyclePhases();
     EXPECT_EQ(TransformationMatrix().Scale(4),
               visual_viewport.GetPageScaleNode()->Matrix());
@@ -476,8 +474,7 @@
                        visual_viewport.VisibleRect().Size());
 
   // Verify the paint property nodes and GeometryMapper cache.
-  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
-      RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
+  {
     UpdateAllLifecyclePhases();
     EXPECT_EQ(TransformationMatrix().Scale(2),
               visual_viewport.GetPageScaleNode()->Matrix());
@@ -500,8 +497,7 @@
   EXPECT_FLOAT_SIZE_EQ(FloatSize(150, 0), visual_viewport.GetScrollOffset());
 
   // Verify the paint property nodes and GeometryMapper cache.
-  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
-      RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
+  {
     UpdateAllLifecyclePhases();
     EXPECT_EQ(TransformationMatrix().Scale(4),
               visual_viewport.GetPageScaleNode()->Matrix());
@@ -539,11 +535,8 @@
   VisualViewport& visual_viewport = GetFrame()->GetPage()->GetVisualViewport();
   EXPECT_FLOAT_SIZE_EQ(IntSize(320, 240),
                        IntSize(visual_viewport.ContainerLayer()->Size()));
-
-  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-    EXPECT_EQ(IntSize(320, 240),
-              visual_viewport.GetScrollNode()->ContainerRect().Size());
-  }
+  EXPECT_EQ(IntSize(320, 240),
+            visual_viewport.GetScrollNode()->ContainerRect().Size());
 }
 
 // Make sure that the visibleRect method acurately reflects the scale and scroll
@@ -863,11 +856,7 @@
     EXPECT_EQ(IntSize(320, 240),
               IntSize(visual_viewport.ScrollLayer()->Size()));
   }
-  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
-      RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-    EXPECT_EQ(IntSize(320, 240),
-              visual_viewport.GetScrollNode()->ContentsSize());
-  }
+  EXPECT_EQ(IntSize(320, 240), visual_viewport.GetScrollNode()->ContentsSize());
 
   // Ensure the location and scale were reset.
   EXPECT_EQ(FloatSize(), visual_viewport.GetScrollOffset());
@@ -1712,14 +1701,11 @@
       frame_view.LayoutViewport()->LayerForScrolling()->CcLayer();
 
   EXPECT_EQ(gfx::Size(1500, 2400), scroll_layer->bounds());
-
-  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-    EXPECT_EQ(IntSize(1500, 2400), frame_view.GetLayoutView()
-                                       ->FirstFragment()
-                                       .PaintProperties()
-                                       ->Scroll()
-                                       ->ContentsSize());
-  }
+  EXPECT_EQ(IntSize(1500, 2400), frame_view.GetLayoutView()
+                                     ->FirstFragment()
+                                     .PaintProperties()
+                                     ->Scroll()
+                                     ->ContentsSize());
 }
 
 // Tests that resizing the visual viepwort keeps its bounds within the outer
@@ -2415,9 +2401,6 @@
 
 // Ensure we create transform node for overscroll elasticity properly.
 TEST_P(VisualViewportTest, EnsureOverscrollElasticityTransformNode) {
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    return;
-
   InitializeWithAndroidSettings();
   WebView()->MainFrameWidget()->Resize(IntSize(400, 400));
   NavigateTo("about:blank");
@@ -2433,9 +2416,8 @@
 
 // Ensure we create effect node for scrollbar properly.
 TEST_P(VisualViewportTest, EnsureEffectNodeForScrollbars) {
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
-      // TODO(wangxianzhu): Should this work for CompositeAfterPaint?
-      RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+  // TODO(wangxianzhu): Should this work for CompositeAfterPaint?
+  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
     return;
 
   InitializeWithAndroidSettings();
@@ -2539,12 +2521,9 @@
   EXPECT_EQ(gfx::Size(320, 480),
             visual_viewport.ScrollLayer()->CcLayer()->bounds());
 
-  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-    EXPECT_EQ(IntSize(400, 600),
-              visual_viewport.GetScrollNode()->ContainerRect().Size());
-    EXPECT_EQ(IntSize(320, 480),
-              visual_viewport.GetScrollNode()->ContentsSize());
-  }
+  EXPECT_EQ(IntSize(400, 600),
+            visual_viewport.GetScrollNode()->ContainerRect().Size());
+  EXPECT_EQ(IntSize(320, 480), visual_viewport.GetScrollNode()->ContentsSize());
 
   WebView().MainFrameWidget()->ApplyViewportChanges(
       {gfx::ScrollOffset(1, 1), gfx::Vector2dF(), 2, false, 1,
@@ -2556,12 +2535,9 @@
   EXPECT_EQ(gfx::Size(320, 480),
             visual_viewport.ScrollLayer()->CcLayer()->bounds());
 
-  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-    EXPECT_EQ(IntSize(400, 600),
-              visual_viewport.GetScrollNode()->ContainerRect().Size());
-    EXPECT_EQ(IntSize(320, 480),
-              visual_viewport.GetScrollNode()->ContentsSize());
-  }
+  EXPECT_EQ(IntSize(400, 600),
+            visual_viewport.GetScrollNode()->ContainerRect().Size());
+  EXPECT_EQ(IntSize(320, 480), visual_viewport.GetScrollNode()->ContentsSize());
 }
 
 class VisualViewportScrollIntoViewTest : public VisualViewportSimTest {
@@ -2669,8 +2645,7 @@
 TEST_P(VisualViewportTest, DirectPinchZoomPropertyUpdate) {
   // TODO(crbug.com/953322): Implement this optimization for
   // CompositeAfterPaint.
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
-      RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
     return;
 
   InitializeWithAndroidSettings();
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
index 566ecf3..be4b873 100644
--- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
+++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
@@ -318,8 +318,7 @@
     LocalRootImpl()->GetFrame()->View()->EnsureUkmAggregator().RecordSample(
         LocalFrameUkmAggregator::kUpdateLayers,
         update_layers_start_time_.value(), base::TimeTicks::Now());
-    if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-      probe::LayerTreeDidChange(LocalRootImpl()->GetFrame());
+    probe::LayerTreeDidChange(LocalRootImpl()->GetFrame());
   }
   update_layers_start_time_.reset();
 }
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.cc b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.cc
index bdce3d4f..df0f5e49 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.cc
+++ b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.cc
@@ -124,11 +124,13 @@
     const base::PendingTask& /* pending_task */) {
   StopListeningForDidProcessTask();
 
+  // Call FinalizeFrame() on self first before informing host so that we can
+  // present swap chain before exporting it.
+  FinalizeFrame();
   // The end of a script task that drew content to the canvas is the point
   // at which the current frame may be considered complete.
   if (Host())
     Host()->FinalizeFrame();
-  FinalizeFrame();
 }
 
 CanvasRenderingContext::ContextType CanvasRenderingContext::ContextTypeFromId(
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
index 4c1d788..0da7750 100644
--- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
+++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -451,7 +451,7 @@
     if (GetOrCreateCanvasResourceProvider(kPreferAcceleration)) {
       const bool webgl_overlay_enabled =
           RuntimeEnabledFeatures::WebGLImageChromiumEnabled() ||
-          RuntimeEnabledFeatures::WebGLSwapChainEnabled();
+          context_->UsingSwapChain();
       // TryEnableSingleBuffering() the first time we FinalizeFrame().
       if (!ResourceProvider()->IsSingleBuffered()) {
         ResourceProvider()->TryEnableSingleBuffering();
diff --git a/third_party/blink/renderer/core/html/html_element.cc b/third_party/blink/renderer/core/html/html_element.cc
index a6f6cb34..7c7c782 100644
--- a/third_party/blink/renderer/core/html/html_element.cc
+++ b/third_party/blink/renderer/core/html/html_element.cc
@@ -30,9 +30,11 @@
 #include "third_party/blink/renderer/bindings/core/v8/string_or_trusted_script.h"
 #include "third_party/blink/renderer/bindings/core/v8/string_treat_null_as_empty_string_or_trusted_script.h"
 #include "third_party/blink/renderer/core/css/css_color_value.h"
+#include "third_party/blink/renderer/core/css/css_identifier_value.h"
 #include "third_party/blink/renderer/core/css/css_markup.h"
 #include "third_party/blink/renderer/core/css/css_property_names.h"
 #include "third_party/blink/renderer/core/css/css_property_value_set.h"
+#include "third_party/blink/renderer/core/css/css_value_list.h"
 #include "third_party/blink/renderer/core/css/style_change_reason.h"
 #include "third_party/blink/renderer/core/css_value_keywords.h"
 #include "third_party/blink/renderer/core/dom/document_fragment.h"
@@ -244,7 +246,9 @@
   if (name == kAlignAttr || name == kContenteditableAttr ||
       name == kHiddenAttr || name == kLangAttr ||
       name.Matches(xml_names::kLangAttr) || name == kDraggableAttr ||
-      name == kDirAttr)
+      name == kDirAttr ||
+      (RuntimeEnabledFeatures::DisplayLockingEnabled() &&
+       name == kRendersubtreeAttr))
     return true;
   return Element::IsPresentationAttribute(name);
 }
@@ -333,6 +337,18 @@
     // xml:lang has a higher priority than lang.
     if (!FastHasAttribute(xml_names::kLangAttr))
       MapLanguageAttributeToLocale(value, style);
+  } else if (RuntimeEnabledFeatures::DisplayLockingEnabled() &&
+             name == kRendersubtreeAttr) {
+    // Add contain: style layout size.
+    CSSValueList* list = CSSValueList::CreateSpaceSeparated();
+    list->Append(*CSSIdentifierValue::Create(CSSValueID::kStyle));
+    list->Append(*CSSIdentifierValue::Create(CSSValueID::kLayout));
+    if (EqualIgnoringASCIICase(value, "invisible") ||
+        EqualIgnoringASCIICase(value, "invisible-activatable")) {
+      list->Append(*CSSIdentifierValue::Create(CSSValueID::kSize));
+    }
+    AddPropertyToPresentationAttributeStyle(style, CSSPropertyID::kContain,
+                                            *list);
   } else {
     Element::CollectStyleForPresentationAttribute(name, value, style);
   }
diff --git a/third_party/blink/renderer/core/inspector/inspector_layer_tree_agent.cc b/third_party/blink/renderer/core/inspector/inspector_layer_tree_agent.cc
index 4c6388b..b1dd96b5 100644
--- a/third_party/blink/renderer/core/inspector/inspector_layer_tree_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_layer_tree_agent.cc
@@ -177,23 +177,20 @@
     const cc::Layer* root,
     const cc::Layer* layer,
     bool report_wheel_event_listeners) {
-  bool using_layer_list =
-      RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
-      RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled();
-
   // When the front-end doesn't show internal layers, it will use the the first
   // DrawsContent layer as the root of the shown layer tree. This doesn't work
-  // for layer list because the non-DrawsContent root layer is the parent of
-  // all DrawsContent layers. We have to cheat the front-end by setting
-  // drawsContent to true for the root layer.
-  bool draws_content =
-      (using_layer_list && root == layer) || layer->DrawsContent();
+  // because the non-DrawsContent root layer is the parent of all DrawsContent
+  // layers. We have to cheat the front-end by setting drawsContent to true for
+  // the root layer.
+  bool draws_content = root == layer || layer->DrawsContent();
 
+  // TODO(pdr): Now that BlinkGenPropertyTrees has launched, we can remove
+  // setOffsetX and setOffsetY.
   std::unique_ptr<protocol::LayerTree::Layer> layer_object =
       protocol::LayerTree::Layer::create()
           .setLayerId(IdForLayer(layer))
-          .setOffsetX(using_layer_list ? 0 : layer->position().x())
-          .setOffsetY(using_layer_list ? 0 : layer->position().y())
+          .setOffsetX(0)
+          .setOffsetY(0)
           .setWidth(layer->bounds().width())
           .setHeight(layer->bounds().height())
           .setPaintCount(layer->paint_count())
@@ -206,14 +203,7 @@
   if (const auto* parent = layer->parent())
     layer_object->setParentLayerId(IdForLayer(parent));
 
-  gfx::Transform transform;
-  gfx::Point3F transform_origin;
-  if (using_layer_list) {
-    transform = layer->ScreenSpaceTransform();
-  } else {
-    transform = layer->transform();
-    transform_origin = layer->transform_origin();
-  }
+  gfx::Transform transform = layer->ScreenSpaceTransform();
 
   if (!transform.IsIdentity()) {
     auto transform_array = std::make_unique<protocol::Array<double>>();
@@ -223,17 +213,11 @@
     }
     layer_object->setTransform(std::move(transform_array));
     // FIXME: rename these to setTransformOrigin*
-    if (layer->bounds().width() > 0) {
-      layer_object->setAnchorX(transform_origin.x() / layer->bounds().width());
-    } else {
-      layer_object->setAnchorX(0.f);
-    }
-    if (layer->bounds().height() > 0) {
-      layer_object->setAnchorY(transform_origin.y() / layer->bounds().height());
-    } else {
-      layer_object->setAnchorY(0.f);
-    }
-    layer_object->setAnchorZ(transform_origin.z());
+    // TODO(pdr): Now that BlinkGenPropertyTrees has launched, we can remove
+    // setAnchorX, setAnchorY, and setAnchorZ.
+    layer_object->setAnchorX(0.f);
+    layer_object->setAnchorY(0.f);
+    layer_object->setAnchorZ(0.f);
   }
   std::unique_ptr<Array<protocol::LayerTree::ScrollRect>> scroll_rects =
       BuildScrollRectsForLayer(layer, report_wheel_event_listeners);
@@ -272,14 +256,8 @@
   if (!document)
     return Response::Error("The root frame doesn't have document");
 
-  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
-      RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-    if (document->Lifecycle().GetState() >= DocumentLifecycle::kPaintClean) {
-      LayerTreePainted();
-      LayerTreeDidChange();
-    }
-  } else if (document->Lifecycle().GetState() >=
-             DocumentLifecycle::kCompositingClean) {
+  if (document->Lifecycle().GetState() >= DocumentLifecycle::kPaintClean) {
+    LayerTreePainted();
     LayerTreeDidChange();
   }
   return Response::OK();
@@ -295,31 +273,7 @@
   GetFrontend()->layerTreeDidChange(BuildLayerTree());
 }
 
-void InspectorLayerTreeAgent::DidPaint(const cc::Layer* layer,
-                                       const LayoutRect& rect) {
-  DCHECK(!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
-         !RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
-  if (suppress_layer_paint_events_)
-    return;
-
-  // Should only happen for LocalFrameView paints when compositing is off.
-  // Consider different instrumentation method for that.
-  if (!layer)
-    return;
-
-  std::unique_ptr<protocol::DOM::Rect> dom_rect = protocol::DOM::Rect::create()
-                                                      .setX(rect.X())
-                                                      .setY(rect.Y())
-                                                      .setWidth(rect.Width())
-                                                      .setHeight(rect.Height())
-                                                      .build();
-  GetFrontend()->layerPainted(IdForLayer(layer), std::move(dom_rect));
-}
-
 void InspectorLayerTreeAgent::LayerTreePainted() {
-  DCHECK(RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
-         RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
-
   for (const auto& layer :
        inspected_frames_->Root()->View()->RootCcLayer()->children()) {
     if (!layer->update_rect().IsEmpty()) {
diff --git a/third_party/blink/renderer/core/inspector/inspector_layer_tree_agent.h b/third_party/blink/renderer/core/inspector/inspector_layer_tree_agent.h
index 93afdc46..8eb4a83 100644
--- a/third_party/blink/renderer/core/inspector/inspector_layer_tree_agent.h
+++ b/third_party/blink/renderer/core/inspector/inspector_layer_tree_agent.h
@@ -45,7 +45,6 @@
 namespace blink {
 
 class InspectedFrames;
-class LayoutRect;
 class PictureSnapshot;
 
 class CORE_EXPORT InspectorLayerTreeAgent final
@@ -65,7 +64,6 @@
 
   // Called from InspectorInstrumentation
   void LayerTreeDidChange();
-  void DidPaint(const cc::Layer*, const LayoutRect&);
   void LayerTreePainted();
 
   // Called from the front-end.
diff --git a/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc b/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
index d0d9c8a..614ae4a 100644
--- a/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
@@ -39,7 +39,7 @@
 FlexItem::FlexItem(LayoutBox* box,
                    LayoutUnit flex_base_content_size,
                    MinMaxSize min_max_sizes,
-                   LayoutUnit main_axis_border_and_padding,
+                   LayoutUnit main_axis_border_padding,
                    LayoutUnit main_axis_margin)
     : algorithm(nullptr),
       line_number(0),
@@ -48,7 +48,7 @@
       min_max_sizes(min_max_sizes),
       hypothetical_main_content_size(
           min_max_sizes.ClampSizeToMinAndMax(flex_base_content_size)),
-      main_axis_border_and_padding(main_axis_border_and_padding),
+      main_axis_border_padding(main_axis_border_padding),
       main_axis_margin(main_axis_margin),
       frozen(false),
       ng_input_node(/* LayoutBox* */ nullptr) {
diff --git a/third_party/blink/renderer/core/layout/flexible_box_algorithm.h b/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
index 47ed35200..46e8f5c 100644
--- a/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
+++ b/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
@@ -77,26 +77,24 @@
   FlexItem(LayoutBox*,
            LayoutUnit flex_base_content_size,
            MinMaxSize min_max_sizes,
-           LayoutUnit main_axis_border_and_padding,
+           LayoutUnit main_axis_border_padding,
            LayoutUnit main_axis_margin);
 
   LayoutUnit HypotheticalMainAxisMarginBoxSize() const {
-    return hypothetical_main_content_size + main_axis_border_and_padding +
+    return hypothetical_main_content_size + main_axis_border_padding +
            main_axis_margin;
   }
 
   LayoutUnit FlexBaseMarginBoxSize() const {
-    return flex_base_content_size + main_axis_border_and_padding +
-           main_axis_margin;
+    return flex_base_content_size + main_axis_border_padding + main_axis_margin;
   }
 
   LayoutUnit FlexedBorderBoxSize() const {
-    return flexed_content_size + main_axis_border_and_padding;
+    return flexed_content_size + main_axis_border_padding;
   }
 
   LayoutUnit FlexedMarginBoxSize() const {
-    return flexed_content_size + main_axis_border_and_padding +
-           main_axis_margin;
+    return flexed_content_size + main_axis_border_padding + main_axis_margin;
   }
 
   LayoutUnit ClampSizeToMinAndMax(LayoutUnit size) const {
@@ -132,7 +130,7 @@
   const LayoutUnit flex_base_content_size;
   const MinMaxSize min_max_sizes;
   const LayoutUnit hypothetical_main_content_size;
-  const LayoutUnit main_axis_border_and_padding;
+  const LayoutUnit main_axis_border_padding;
   const LayoutUnit main_axis_margin;
   LayoutUnit flexed_content_size;
 
diff --git a/third_party/blink/renderer/core/layout/layout_flexible_box.cc b/third_party/blink/renderer/core/layout/layout_flexible_box.cc
index f76c78a..a7cb2b7 100644
--- a/third_party/blink/renderer/core/layout/layout_flexible_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_flexible_box.cc
@@ -1495,7 +1495,7 @@
     // But it turns out that tables ignore the override size, and so we have
     // to re-check the size so that we place the flex item correctly.
     flex_item.flexed_content_size =
-        MainAxisExtentForChild(*child) - flex_item.main_axis_border_and_padding;
+        MainAxisExtentForChild(*child) - flex_item.main_axis_border_padding;
     flex_item.cross_axis_size = CrossAxisUnstretchedExtentForChild(*child);
   }
 }
diff --git a/third_party/blink/renderer/core/layout/layout_theme_linux.cc b/third_party/blink/renderer/core/layout/layout_theme_linux.cc
index 6033536b..694fdf6 100644
--- a/third_party/blink/renderer/core/layout/layout_theme_linux.cc
+++ b/third_party/blink/renderer/core/layout/layout_theme_linux.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/layout/layout_theme_linux.h"
 
+#include "third_party/blink/public/resources/grit/blink_resources.h"
 #include "third_party/blink/renderer/platform/data_resource_helper.h"
 
 namespace blink {
@@ -19,7 +20,7 @@
 
 String LayoutThemeLinux::ExtraDefaultStyleSheet() {
   return LayoutThemeDefault::ExtraDefaultStyleSheet() +
-         GetDataResourceAsASCIIString("linux.css");
+         UncompressResourceAsASCIIString(IDR_UASTYLE_THEME_CHROMIUM_LINUX_CSS);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/layout_theme_mobile.cc b/third_party/blink/renderer/core/layout/layout_theme_mobile.cc
index 5ab8c8b9..f9a610cf 100644
--- a/third_party/blink/renderer/core/layout/layout_theme_mobile.cc
+++ b/third_party/blink/renderer/core/layout/layout_theme_mobile.cc
@@ -28,6 +28,7 @@
 #include "build/build_config.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/web_theme_engine.h"
+#include "third_party/blink/public/resources/grit/blink_resources.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
 #include "third_party/blink/renderer/platform/data_resource_helper.h"
 #include "third_party/blink/renderer/platform/web_test_support.h"
@@ -42,12 +43,13 @@
 
 String LayoutThemeMobile::ExtraDefaultStyleSheet() {
   return LayoutThemeDefault::ExtraDefaultStyleSheet() +
-         GetDataResourceAsASCIIString("linux.css") +
-         GetDataResourceAsASCIIString("android.css");
+         UncompressResourceAsASCIIString(IDR_UASTYLE_THEME_CHROMIUM_LINUX_CSS) +
+         UncompressResourceAsASCIIString(
+             IDR_UASTYLE_THEME_CHROMIUM_ANDROID_CSS);
 }
 
 String LayoutThemeMobile::ExtraFullscreenStyleSheet() {
-  return GetDataResourceAsASCIIString("fullscreenAndroid.css");
+  return UncompressResourceAsASCIIString(IDR_UASTYLE_FULLSCREEN_ANDROID_CSS);
 }
 
 void LayoutThemeMobile::AdjustInnerSpinButtonStyle(ComputedStyle& style) const {
diff --git a/third_party/blink/renderer/core/layout/layout_theme_touchless.cc b/third_party/blink/renderer/core/layout/layout_theme_touchless.cc
index 27f1f67..ec54d8b 100644
--- a/third_party/blink/renderer/core/layout/layout_theme_touchless.cc
+++ b/third_party/blink/renderer/core/layout/layout_theme_touchless.cc
@@ -22,7 +22,7 @@
 
 String LayoutThemeTouchless::ExtraDefaultStyleSheet() {
   return LayoutThemeMobile::ExtraDefaultStyleSheet() +
-         GetDataResourceAsASCIIString("touchless.css");
+         UncompressResourceAsASCIIString(IDR_UASTYLE_THEME_TOUCHLESS_CSS);
 }
 
 bool LayoutThemeTouchless::IsFocusRingOutset() const {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc
index 3ecba77..78d93ed 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc
@@ -167,21 +167,26 @@
             .SetPercentageResolutionSize(content_box_size_)
             .ToConstraintSpace();
 
-    NGBoxStrut border_scrollbar_padding_in_child_writing_mode =
+    NGBoxStrut border_padding_in_child_writing_mode =
         ComputeBorders(child_space, child) +
-        ComputeScrollbars(child_space, child) +
         ComputePadding(child_space, child_style);
+    NGBoxStrut border_scrollbar_padding_in_child_writing_mode =
+        border_padding_in_child_writing_mode +
+        ComputeScrollbars(child_space, child);
+
     NGPhysicalBoxStrut physical_border_padding(
+        border_padding_in_child_writing_mode.ConvertToPhysical(
+            child_style.GetWritingMode(), child_style.Direction()));
+    NGPhysicalBoxStrut physical_border_scrollbar_padding(
         border_scrollbar_padding_in_child_writing_mode.ConvertToPhysical(
             child_style.GetWritingMode(), child_style.Direction()));
-    LayoutUnit main_axis_border_scrollbar_padding =
+
+    LayoutUnit main_axis_border_padding =
         is_horizontal_flow_ ? physical_border_padding.HorizontalSum()
                             : physical_border_padding.VerticalSum();
-    LayoutUnit main_axis_border_and_padding =
-        main_axis_border_scrollbar_padding -
-        (is_horizontal_flow_
-             ? child.GetLayoutBox()->VerticalScrollbarWidth()
-             : child.GetLayoutBox()->HorizontalScrollbarHeight());
+    LayoutUnit main_axis_border_scrollbar_padding =
+        is_horizontal_flow_ ? physical_border_scrollbar_padding.HorizontalSum()
+                            : physical_border_scrollbar_padding.VerticalSum();
 
     // We want the child's min/max size in its writing mode, not ours. We'll
     // only ever use it if the child's inline axis is our main axis.
@@ -220,16 +225,14 @@
 
       if (MainAxisIsInlineAxis(child)) {
         flex_base_border_box = ResolveMainInlineLength(
-            child_space, child_style,
-            border_scrollbar_padding_in_child_writing_mode,
+            child_space, child_style, border_padding_in_child_writing_mode,
             intrinsic_sizes_border_box, length_to_resolve);
       } else {
         // Flex container's main axis is in child's block direction. Child's
         // flex basis is in child's block direction.
         flex_base_border_box = ResolveMainBlockLength(
-            child_space, child_style,
-            border_scrollbar_padding_in_child_writing_mode, length_to_resolve,
-            fragment_in_child_writing_mode.BlockSize(),
+            child_space, child_style, border_padding_in_child_writing_mode,
+            length_to_resolve, fragment_in_child_writing_mode.BlockSize(),
             LengthResolvePhase::kLayout);
       }
     }
@@ -239,7 +242,7 @@
     // Blink's FlexibleBoxAlgorithm expects it to be content + scrollbar widths,
     // but no padding or border.
     LayoutUnit flex_base_content_size =
-        flex_base_border_box - main_axis_border_and_padding;
+        flex_base_border_box - main_axis_border_padding;
 
     NGPhysicalBoxStrut physical_child_margins =
         ComputePhysicalMargins(child_space, child_style);
@@ -254,14 +257,12 @@
                                                   : child.Style().MaxHeight();
     if (MainAxisIsInlineAxis(child)) {
       min_max_sizes_in_main_axis_direction.max_size = ResolveMaxInlineLength(
-          child_space, child_style,
-          border_scrollbar_padding_in_child_writing_mode,
+          child_space, child_style, border_padding_in_child_writing_mode,
           intrinsic_sizes_border_box, max_property_in_main_axis,
           LengthResolvePhase::kLayout);
     } else {
       min_max_sizes_in_main_axis_direction.max_size = ResolveMaxBlockLength(
-          child_space, child_style,
-          border_scrollbar_padding_in_child_writing_mode,
+          child_space, child_style, border_padding_in_child_writing_mode,
           max_property_in_main_axis, fragment_in_child_writing_mode.BlockSize(),
           LengthResolvePhase::kLayout);
     }
@@ -290,8 +291,7 @@
             // resolved specified_length_in_main_axis in the flex basis
             // calculation. Reuse that if possible.
             specified_size_suggestion = ResolveMainInlineLength(
-                child_space, child_style,
-                border_scrollbar_padding_in_child_writing_mode,
+                child_space, child_style, border_padding_in_child_writing_mode,
                 intrinsic_sizes_border_box, specified_length_in_main_axis);
           }
         } else if (!specified_length_in_main_axis.IsAuto() &&
@@ -299,8 +299,7 @@
                                             specified_length_in_main_axis,
                                             LengthResolvePhase::kLayout)) {
           specified_size_suggestion = ResolveMainBlockLength(
-              child_space, child_style,
-              border_scrollbar_padding_in_child_writing_mode,
+              child_space, child_style, border_padding_in_child_writing_mode,
               specified_length_in_main_axis,
               layout_result->IntrinsicBlockSize(), LengthResolvePhase::kLayout);
           DCHECK_NE(specified_size_suggestion, kIndefiniteSize);
@@ -317,18 +316,17 @@
       }
     } else if (MainAxisIsInlineAxis(child)) {
       min_max_sizes_in_main_axis_direction.min_size =
-          ResolveMinInlineLength(child_space, child_style,
-                                 border_scrollbar_padding_in_child_writing_mode,
-                                 intrinsic_sizes_border_box, min,
-                                 LengthResolvePhase::kLayout) -
+          ResolveMinInlineLength(
+              child_space, child_style, border_padding_in_child_writing_mode,
+              intrinsic_sizes_border_box, min, LengthResolvePhase::kLayout) -
           main_axis_border_scrollbar_padding;
       // TODO(dgrogan): No tests changed status as result of subtracting
       // main_axis_border_scrollbar_padding. It may be untested.
     } else {
       min_max_sizes_in_main_axis_direction.min_size =
           ResolveMinBlockLength(child_space, child_style,
-                                border_scrollbar_padding_in_child_writing_mode,
-                                min, fragment_in_child_writing_mode.BlockSize(),
+                                border_padding_in_child_writing_mode, min,
+                                fragment_in_child_writing_mode.BlockSize(),
                                 LengthResolvePhase::kLayout) -
           main_axis_border_scrollbar_padding;
       // TODO(dgrogan): Same as above WRT subtracting
@@ -338,7 +336,7 @@
     algorithm_
         ->emplace_back(child.GetLayoutBox(), flex_base_content_size,
                        min_max_sizes_in_main_axis_direction,
-                       main_axis_border_and_padding, main_axis_margin)
+                       main_axis_border_padding, main_axis_margin)
         .ng_input_node = child;
   }
 }
@@ -383,15 +381,15 @@
       LogicalSize available_size;
       if (is_column_) {
         available_size.inline_size = content_box_size_.inline_size;
-        available_size.block_size = flex_item.flexed_content_size +
-                                    flex_item.main_axis_border_and_padding;
+        available_size.block_size =
+            flex_item.flexed_content_size + flex_item.main_axis_border_padding;
         space_builder.SetIsFixedBlockSize(true);
         // TODO(dgrogan): Set IsFixedBlockSizeIndefinite if neither the item's
         // nor container's main size is definite. (The latter being exception 2
         // from https://drafts.csswg.org/css-flexbox/#definite-sizes )
       } else {
-        available_size.inline_size = flex_item.flexed_content_size +
-                                     flex_item.main_axis_border_and_padding;
+        available_size.inline_size =
+            flex_item.flexed_content_size + flex_item.main_axis_border_padding;
         available_size.block_size = content_box_size_.block_size;
         space_builder.SetIsFixedInlineSize(true);
       }
@@ -468,9 +466,9 @@
         SetOrthogonalFallbackInlineSizeIfNeeded(
             Style(), flex_item.ng_input_node, &space_builder);
 
-        LogicalSize available_size(flex_item.flexed_content_size +
-                                       flex_item.main_axis_border_and_padding,
-                                   flex_item.cross_axis_size);
+        LogicalSize available_size(
+            flex_item.flexed_content_size + flex_item.main_axis_border_padding,
+            flex_item.cross_axis_size);
         if (is_column_) {
           available_size.Transpose();
           // TODO(dgrogan): Set IsFixedBlockSizeIndefinite if neither the item's
diff --git a/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc b/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc
index 571ecdfd..294e9cf 100644
--- a/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc
+++ b/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc
@@ -26,6 +26,7 @@
 #include "third_party/blink/renderer/core/layout/layout_table_col.h"
 #include "third_party/blink/renderer/core/layout/layout_table_section.h"
 #include "third_party/blink/renderer/core/layout/text_autosizer.h"
+#include "third_party/blink/renderer/platform/geometry/calculation_value.h"
 
 namespace blink {
 
@@ -84,14 +85,14 @@
           // FIXME: Other browsers have a lower limit for the cell's max width.
           const int kCCellMaxWidth = 32760;
           Length cell_logical_width = cell->StyleOrColLogicalWidth();
-          // FIXME: calc() on tables should be handled consistently with other
-          // lengths.
-          // Currently, only calc(% + 0px) case is handled as calc(%).
-          // See bug: https://crbug.com/382725
+          // TODO(crbug.com/382725): CSS math function results on tables should
+          // be handled consistently with other lengths. Currently, only calc(%
+          // + 0px) case is handled as calc(%).
           if (cell_logical_width.IsCalculated()) {
-            if (!cell_logical_width.GetPixelsAndPercent().pixels) {
-              cell_logical_width = Length::Percent(
-                  cell_logical_width.GetPixelsAndPercent().percent);
+            const CalculationValue& calc =
+                cell_logical_width.GetCalculationValue();
+            if (!calc.IsExpression() && !calc.Pixels()) {
+              cell_logical_width = Length::Percent(calc.Percent());
             } else {
               cell_logical_width = Length();  // Make it Auto
             }
diff --git a/third_party/blink/renderer/core/page/scrolling/main_thread_scrolling_reasons_test.cc b/third_party/blink/renderer/core/page/scrolling/main_thread_scrolling_reasons_test.cc
index 97200aa..503226a 100644
--- a/third_party/blink/renderer/core/page/scrolling/main_thread_scrolling_reasons_test.cc
+++ b/third_party/blink/renderer/core/page/scrolling/main_thread_scrolling_reasons_test.cc
@@ -24,14 +24,9 @@
 
 namespace blink {
 
-class MainThreadScrollingReasonsTest
-    : public testing::Test,
-      public testing::WithParamInterface<bool>,
-      private ScopedBlinkGenPropertyTreesForTest {
+class MainThreadScrollingReasonsTest : public testing::Test {
  public:
-  MainThreadScrollingReasonsTest()
-      : ScopedBlinkGenPropertyTreesForTest(GetParam()),
-        base_url_("http://www.test.com/") {
+  MainThreadScrollingReasonsTest() : base_url_("http://www.test.com/") {
     helper_.InitializeWithSettings(&ConfigureSettings);
     GetWebView()->MainFrameWidget()->Resize(IntSize(320, 240));
 
@@ -77,14 +72,6 @@
   }
 
   uint32_t GetViewMainThreadScrollingReasons() const {
-    // Pre-BlinkGenPropertyTrees, main thread scrolling reasons are set on
-    // cc::Layer in ScrollingCoordinator.
-    if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-      auto* layer = GetFrame()->View()->LayoutViewport()->LayerForScrolling();
-      return layer->CcLayer()->GetMainThreadScrollingReasons();
-    }
-    // With BlinkGenPropertyTrees, main thread scrolling reasons are calculated
-    // in the blink property tree builder and set on set on scroll nodes.
     const auto* scroll = GetFrame()
                              ->View()
                              ->GetLayoutView()
@@ -108,9 +95,7 @@
   frame_test_helpers::WebViewHelper helper_;
 };
 
-INSTANTIATE_TEST_SUITE_P(All, MainThreadScrollingReasonsTest, testing::Bool());
-
-TEST_P(MainThreadScrollingReasonsTest,
+TEST_F(MainThreadScrollingReasonsTest,
        BackgroundAttachmentFixedShouldTriggerMainThreadScroll) {
   // This test needs the |FastMobileScrolling| feature to be disabled
   // although it is stable on Android.
@@ -201,7 +186,7 @@
 
 // Upon resizing the content size, the main thread scrolling reason
 // kHasNonLayerViewportConstrainedObject should be updated on all frames
-TEST_P(MainThreadScrollingReasonsTest,
+TEST_F(MainThreadScrollingReasonsTest,
        RecalculateMainThreadScrollingReasonsUponResize) {
   // This test needs the |FastMobileScrolling| feature to be disabled
   // although it is stable on Android.
@@ -236,7 +221,7 @@
   EXPECT_FALSE(GetViewMainThreadScrollingReasons());
 }
 
-TEST_P(MainThreadScrollingReasonsTest, FastScrollingCanBeDisabledWithSetting) {
+TEST_F(MainThreadScrollingReasonsTest, FastScrollingCanBeDisabledWithSetting) {
   GetWebView()->MainFrameWidget()->Resize(WebSize(800, 600));
   LoadHTML("<div id='spacer' style='height: 1000px'></div>");
   GetWebView()->GetSettings()->SetThreadedScrollingEnabled(false);
@@ -253,7 +238,7 @@
   EXPECT_TRUE(inner_viewport_scroll_layer->GetMainThreadScrollingReasons());
 }
 
-TEST_P(MainThreadScrollingReasonsTest, FastScrollingForFixedPosition) {
+TEST_F(MainThreadScrollingReasonsTest, FastScrollingForFixedPosition) {
   RegisterMockedHttpURLLoad("fixed-position.html");
   NavigateTo(base_url_ + "fixed-position.html");
   ForceFullCompositingUpdate();
@@ -262,7 +247,7 @@
   EXPECT_FALSE(GetViewMainThreadScrollingReasons());
 }
 
-TEST_P(MainThreadScrollingReasonsTest, FastScrollingForStickyPosition) {
+TEST_F(MainThreadScrollingReasonsTest, FastScrollingForStickyPosition) {
   RegisterMockedHttpURLLoad("sticky-position.html");
   NavigateTo(base_url_ + "sticky-position.html");
   ForceFullCompositingUpdate();
@@ -271,7 +256,7 @@
   EXPECT_FALSE(GetViewMainThreadScrollingReasons());
 }
 
-TEST_P(MainThreadScrollingReasonsTest, FastScrollingByDefault) {
+TEST_F(MainThreadScrollingReasonsTest, FastScrollingByDefault) {
   GetWebView()->MainFrameWidget()->Resize(WebSize(800, 600));
   LoadHTML("<div id='spacer' style='height: 1000px'></div>");
   ForceFullCompositingUpdate();
@@ -285,7 +270,7 @@
   EXPECT_FALSE(inner_viewport_scroll_layer->GetMainThreadScrollingReasons());
 }
 
-TEST_P(MainThreadScrollingReasonsTest,
+TEST_F(MainThreadScrollingReasonsTest,
        ScrollbarsForceMainThreadOrHaveCompositorScrollbarLayer) {
   RegisterMockedHttpURLLoad("trivial-scroller.html");
   NavigateTo(base_url_ + "trivial-scroller.html");
@@ -381,32 +366,28 @@
   }
 };
 
-INSTANTIATE_TEST_SUITE_P(All,
-                         NonCompositedMainThreadScrollingReasonsTest,
-                         testing::Bool());
-
-TEST_P(NonCompositedMainThreadScrollingReasonsTest, TransparentTest) {
+TEST_F(NonCompositedMainThreadScrollingReasonsTest, TransparentTest) {
   TestNonCompositedReasons(
       "transparent", cc::MainThreadScrollingReason::kHasOpacityAndLCDText);
 }
 
-TEST_P(NonCompositedMainThreadScrollingReasonsTest, TransformTest) {
+TEST_F(NonCompositedMainThreadScrollingReasonsTest, TransformTest) {
   TestNonCompositedReasons(
       "transform", cc::MainThreadScrollingReason::kHasTransformAndLCDText);
 }
 
-TEST_P(NonCompositedMainThreadScrollingReasonsTest, BackgroundNotOpaqueTest) {
+TEST_F(NonCompositedMainThreadScrollingReasonsTest, BackgroundNotOpaqueTest) {
   TestNonCompositedReasons(
       "background-not-opaque",
       cc::MainThreadScrollingReason::kBackgroundNotOpaqueInRectAndLCDText);
 }
 
-TEST_P(NonCompositedMainThreadScrollingReasonsTest, ClipTest) {
+TEST_F(NonCompositedMainThreadScrollingReasonsTest, ClipTest) {
   TestNonCompositedReasons(
       "clip", cc::MainThreadScrollingReason::kHasClipRelatedProperty);
 }
 
-TEST_P(NonCompositedMainThreadScrollingReasonsTest, ClipPathTest) {
+TEST_F(NonCompositedMainThreadScrollingReasonsTest, ClipPathTest) {
   uint32_t clip_reason = cc::MainThreadScrollingReason::kHasClipRelatedProperty;
   GetWebView()->GetSettings()->SetPreferCompositingToLCDTextEnabled(false);
   Document* document = GetFrame()->GetDocument();
@@ -451,18 +432,18 @@
   EXPECT_FALSE(GetViewMainThreadScrollingReasons() & clip_reason);
 }
 
-TEST_P(NonCompositedMainThreadScrollingReasonsTest, LCDTextEnabledTest) {
+TEST_F(NonCompositedMainThreadScrollingReasonsTest, LCDTextEnabledTest) {
   TestNonCompositedReasons(
       "transparent", cc::MainThreadScrollingReason::kHasOpacityAndLCDText);
 }
 
-TEST_P(NonCompositedMainThreadScrollingReasonsTest, BoxShadowTest) {
+TEST_F(NonCompositedMainThreadScrollingReasonsTest, BoxShadowTest) {
   TestNonCompositedReasons(
       "box-shadow",
       cc::MainThreadScrollingReason::kHasBoxShadowFromNonRootLayer);
 }
 
-TEST_P(NonCompositedMainThreadScrollingReasonsTest, StackingContextTest) {
+TEST_F(NonCompositedMainThreadScrollingReasonsTest, StackingContextTest) {
   GetWebView()->GetSettings()->SetPreferCompositingToLCDTextEnabled(false);
 
   Document* document = GetFrame()->GetDocument();
@@ -491,7 +472,7 @@
   EXPECT_FALSE(scrollable_area->GetNonCompositedMainThreadScrollingReasons());
 }
 
-TEST_P(NonCompositedMainThreadScrollingReasonsTest,
+TEST_F(NonCompositedMainThreadScrollingReasonsTest,
        CompositedWithLCDTextRelatedReasonsTest) {
   // With "will-change:transform" we composite elements with
   // LCDTextRelatedReasons only. For elements with other
diff --git a/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc b/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc
index fc700e6..b99badf 100644
--- a/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc
+++ b/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc
@@ -31,7 +31,6 @@
 #include "build/build_config.h"
 #include "cc/animation/animation_host.h"
 #include "cc/input/main_thread_scrolling_reason.h"
-#include "cc/layers/layer_position_constraint.h"
 #include "cc/layers/painted_overlay_scrollbar_layer.h"
 #include "cc/layers/painted_scrollbar_layer.h"
 #include "cc/layers/picture_layer.h"
@@ -177,31 +176,12 @@
 
   if (should_scroll_on_main_thread_dirty ||
       frame_view->FrameIsScrollableDidChange()) {
-    // When blink generates property trees, main thread scrolling reasons are
-    // stored on scroll nodes.
-    if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-      // TODO(pdr): This also takes over scroll animations if main thread
-      // reasons are present. This needs to be implemented for
-      // BlinkGenPropertyTrees.
-      // TODO(bokan): Does this work for scrollers other than FrameViews? If
-      // not, this will need to account for root scrollers.
-      SetShouldUpdateScrollLayerPositionOnMainThread(
-          frame, frame_view->GetMainThreadScrollingReasons());
-
-      // Need to update scroll on main thread reasons for subframe because
-      // subframe (e.g. iframe with background-attachment:fixed) should
-      // scroll on main thread while the main frame scrolls on impl.
-      frame_view->UpdateSubFrameScrollOnMainReason(*frame, 0);
-    }
+    // TODO(pdr): Now that BlinkGenPropertyTrees has launched, we should remove
+    // FrameIsScrollableDidChange.
     frame_view->GetScrollingContext()->SetShouldScrollOnMainThreadIsDirty(
         false);
   }
   frame_view->ClearFrameIsScrollableDidChange();
-
-  // When blink generates property trees, the user input scrollable bits are
-  // stored on scroll nodes instead of layers.
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    UpdateUserInputScrollable(&page_->GetVisualViewport());
 }
 
 template <typename Function>
@@ -291,70 +271,6 @@
                                                   paint_chunks);
 }
 
-static void ClearPositionConstraintExceptForLayer(GraphicsLayer* layer,
-                                                  GraphicsLayer* except) {
-  // When blink generates property trees, the layer position constraints are
-  // not set on cc::Layer because they are only used by the cc property tree
-  // builder.
-  DCHECK(!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
-         !RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
-  if (layer && layer != except && GraphicsLayerToCcLayer(layer)) {
-    GraphicsLayerToCcLayer(layer)->SetPositionConstraint(
-        cc::LayerPositionConstraint());
-  }
-}
-
-static cc::LayerPositionConstraint ComputePositionConstraint(
-    const PaintLayer* layer) {
-  DCHECK(!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
-         !RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
-  DCHECK(layer->HasCompositedLayerMapping());
-  do {
-    if (layer->GetLayoutObject().Style()->GetPosition() == EPosition::kFixed) {
-      const LayoutObject& fixed_position_object = layer->GetLayoutObject();
-      bool fixed_to_right = !fixed_position_object.Style()->Right().IsAuto();
-      bool fixed_to_bottom = fixed_position_object.Style()->IsFixedToBottom();
-      cc::LayerPositionConstraint constraint;
-      constraint.set_is_fixed_position(true);
-      constraint.set_is_fixed_to_right_edge(fixed_to_right);
-      constraint.set_is_fixed_to_bottom_edge(fixed_to_bottom);
-      return constraint;
-    }
-
-    layer = layer->Parent();
-
-    // Composited layers that inherit a fixed position state will be positioned
-    // with respect to the nearest compositedLayerMapping's GraphicsLayer.
-    // So, once we find a layer that has its own compositedLayerMapping, we can
-    // stop searching for a fixed position LayoutObject.
-  } while (layer && !layer->HasCompositedLayerMapping());
-  return cc::LayerPositionConstraint();
-}
-
-void ScrollingCoordinator::UpdateLayerPositionConstraint(PaintLayer* layer) {
-  // When blink generates property trees, the layer position constraints are
-  // not set on cc::Layer because they are only used by the cc property tree
-  // builder.
-  DCHECK(!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
-         !RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
-
-  DCHECK(layer->HasCompositedLayerMapping());
-  CompositedLayerMapping* composited_layer_mapping =
-      layer->GetCompositedLayerMapping();
-  GraphicsLayer* main_layer = composited_layer_mapping->ChildForSuperlayers();
-
-  // Avoid unnecessary commits
-  ClearPositionConstraintExceptForLayer(
-      composited_layer_mapping->SquashingContainmentLayer(), main_layer);
-  ClearPositionConstraintExceptForLayer(
-      composited_layer_mapping->AncestorClippingLayer(), main_layer);
-  ClearPositionConstraintExceptForLayer(
-      composited_layer_mapping->MainGraphicsLayer(), main_layer);
-
-  if (cc::Layer* scrollable_layer = GraphicsLayerToCcLayer(main_layer))
-    scrollable_layer->SetPositionConstraint(ComputePositionConstraint(layer));
-}
-
 void ScrollingCoordinator::WillDestroyScrollableArea(
     ScrollableArea* scrollable_area) {
   RemoveScrollbarLayerGroup(scrollable_area, kHorizontalScrollbar);
@@ -548,9 +464,6 @@
   if (!page_ || !page_->MainFrame())
     return;
 
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    UpdateUserInputScrollable(scrollable_area);
-
   cc::Layer* cc_layer =
       GraphicsLayerToCcLayer(scrollable_area->LayerForScrolling());
   cc::Layer* container_layer =
@@ -558,17 +471,6 @@
   if (cc_layer) {
     cc_layer->SetScrollable(container_layer->bounds());
 
-    // The scroll offset is pushed to cc::Layers separately in
-    // UpdateCompositedScrolloffset. This is needed for the visual viewport
-    // scroll offsets which aren't updated as part of a compositing update. In
-    // BlinkGenPropertyTrees, the visual viewport sets scroll offsets directly
-    // into its transform paint property nodes so this becomes unneeded.
-    if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-      FloatPoint scroll_position(scrollable_area->ScrollPosition());
-      cc_layer->SetScrollOffset(
-          static_cast<gfx::ScrollOffset>(scroll_position));
-    }
-
     // TODO(bokan): This method shouldn't be resizing the layer geometry. That
     // happens in CompositedLayerMapping::UpdateScrollingLayerGeometry.
     PhysicalOffset subpixel_accumulation =
@@ -656,22 +558,6 @@
     ForAllPaintingGraphicsLayers(*root, UpdateLayerTouchActionRects);
 }
 
-void ScrollingCoordinator::UpdateUserInputScrollable(
-    ScrollableArea* scrollable_area) {
-  // When blink generates property trees, the user input scrollable bits are
-  // stored on scroll nodes instead of layers so this is not needed.
-  DCHECK(!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled());
-  cc::Layer* cc_layer =
-      GraphicsLayerToCcLayer(scrollable_area->LayerForScrolling());
-  if (cc_layer) {
-    bool can_scroll_x =
-        scrollable_area->UserInputScrollable(kHorizontalScrollbar);
-    bool can_scroll_y =
-        scrollable_area->UserInputScrollable(kVerticalScrollbar);
-    cc_layer->SetUserScrollable(can_scroll_x, can_scroll_y);
-  }
-}
-
 void ScrollingCoordinator::Reset(LocalFrame* frame) {
   for (const auto& scrollbar : horizontal_scrollbars_)
     GraphicsLayer::UnregisterContentsLayer(scrollbar.value->layer.get());
diff --git a/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h b/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h
index 9b4c6427..4f4dc21 100644
--- a/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h
+++ b/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h
@@ -138,7 +138,6 @@
   void ScrollableAreaScrollLayerDidChange(ScrollableArea*);
   void ScrollableAreaScrollbarLayerDidChange(ScrollableArea*,
                                              ScrollbarOrientation);
-  void UpdateLayerPositionConstraint(PaintLayer*);
   // LocalFrame* must be a local root if non-null.
   void TouchEventTargetRectsDidChange(LocalFrame*);
 
@@ -165,8 +164,6 @@
   void UpdateNonFastScrollableRegions(LocalFrame*);
   void UpdateTouchEventTargetRectsIfNeeded(LocalFrame*);
 
-  void UpdateUserInputScrollable(ScrollableArea*);
-
   cc::AnimationHost* GetCompositorAnimationHost() { return animation_host_; }
   CompositorAnimationTimeline* GetCompositorAnimationTimeline() {
     return programmatic_scroll_animator_timeline_.get();
diff --git a/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator_test.cc b/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator_test.cc
index 866e4233..5997a70 100644
--- a/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator_test.cc
+++ b/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator_test.cc
@@ -68,28 +68,13 @@
 
 namespace blink {
 
-// kScrollingCoordinatorTestNoFlags runs with BlinkGenPropertyTrees and
-// PaintNonFastScrollableRegions disabled. Using
-// (kScrollingCoordinatorTestBlinkGenPropertyTrees |
-// kScrollingCoordinatorTestPaintNonFastScrollableRegions) enables both.
-enum {
-  kScrollingCoordinatorTestNoFlags = 1 << 0,
-  kScrollingCoordinatorTestBlinkGenPropertyTrees = 1 << 1,
-  kScrollingCoordinatorTestPaintNonFastScrollableRegions = 1 << 2,
-};
-
 class ScrollingCoordinatorTest
     : public testing::Test,
-      public testing::WithParamInterface<unsigned>,
-      private ScopedBlinkGenPropertyTreesForTest,
+      public testing::WithParamInterface<bool>,
       private ScopedPaintNonFastScrollableRegionsForTest {
  public:
   ScrollingCoordinatorTest()
-      : ScopedBlinkGenPropertyTreesForTest(
-            GetParam() & kScrollingCoordinatorTestBlinkGenPropertyTrees),
-        ScopedPaintNonFastScrollableRegionsForTest(
-            GetParam() &
-            kScrollingCoordinatorTestPaintNonFastScrollableRegions),
+      : ScopedPaintNonFastScrollableRegionsForTest(GetParam()),
         base_url_("http://www.test.com/") {
     helper_.Initialize(nullptr, nullptr, nullptr, &ConfigureSettings);
     GetWebView()->MainFrameWidget()->Resize(IntSize(320, 240));
@@ -160,15 +145,7 @@
   frame_test_helpers::WebViewHelper helper_;
 };
 
-INSTANTIATE_TEST_SUITE_P(
-    All,
-    ScrollingCoordinatorTest,
-    ::testing::Values(
-        kScrollingCoordinatorTestNoFlags,
-        kScrollingCoordinatorTestBlinkGenPropertyTrees,
-        kScrollingCoordinatorTestPaintNonFastScrollableRegions,
-        (kScrollingCoordinatorTestBlinkGenPropertyTrees |
-         kScrollingCoordinatorTestPaintNonFastScrollableRegions)));
+INSTANTIATE_TEST_SUITE_P(All, ScrollingCoordinatorTest, testing::Bool());
 
 TEST_P(ScrollingCoordinatorTest, fastScrollingByDefault) {
   GetWebView()->MainFrameWidget()->Resize(WebSize(800, 600));
@@ -200,14 +177,11 @@
   ASSERT_FALSE(inner_viewport_scroll_layer->GetMainThreadScrollingReasons());
 }
 
-TEST_P(ScrollingCoordinatorTest, fastFractionalScrollingDiv) {
+// TODO(920417): Re-enable this test when main thread scrolling supports
+// fractional scroll offsets.
+TEST_P(ScrollingCoordinatorTest, DISABLED_fastFractionalScrollingDiv) {
   ScopedFractionalScrollOffsetsForTest fractional_scroll_offsets(true);
 
-  // TODO(920417): Re-enable this test when main thread scrolling supports
-  // fractional scroll offsets.
-  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    return;
-
   RegisterMockedHttpURLLoad("fractional-scroll-div.html");
   NavigateTo(base_url_ + "fractional-scroll-div.html");
   ForceFullCompositingUpdate();
@@ -241,25 +215,6 @@
   ASSERT_NEAR(1.2f, cc_scroll_layer->CurrentScrollOffset().y(), 0.01f);
 }
 
-static cc::Layer* CcLayerFromElement(Element* element) {
-  if (!element)
-    return nullptr;
-  LayoutObject* layout_object = element->GetLayoutObject();
-  if (!layout_object || !layout_object->IsBoxModelObject())
-    return nullptr;
-  PaintLayer* layer = ToLayoutBoxModelObject(layout_object)->Layer();
-  if (!layer)
-    return nullptr;
-  if (!layer->HasCompositedLayerMapping())
-    return nullptr;
-  CompositedLayerMapping* composited_layer_mapping =
-      layer->GetCompositedLayerMapping();
-  GraphicsLayer* graphics_layer = composited_layer_mapping->MainGraphicsLayer();
-  if (!graphics_layer)
-    return nullptr;
-  return graphics_layer->CcLayer();
-}
-
 TEST_P(ScrollingCoordinatorTest, fastScrollingForFixedPosition) {
   RegisterMockedHttpURLLoad("fixed-position.html");
   NavigateTo(base_url_ + "fixed-position.html");
@@ -269,106 +224,10 @@
   cc::Layer* root_scroll_layer = GetRootScrollLayer();
   ASSERT_TRUE(root_scroll_layer);
   ASSERT_FALSE(root_scroll_layer->GetMainThreadScrollingReasons());
-
-  // Layer position constraints are only used by the cc property tree builder
-  // and are not set when blink generates property trees.
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
-      !RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-    Document* document = GetFrame()->GetDocument();
-    {
-      Element* element = document->getElementById("div-tl");
-      ASSERT_TRUE(element);
-      cc::Layer* layer = CcLayerFromElement(element);
-      ASSERT_TRUE(layer);
-      cc::LayerPositionConstraint constraint = layer->position_constraint();
-      ASSERT_TRUE(constraint.is_fixed_position());
-      ASSERT_TRUE(!constraint.is_fixed_to_right_edge() &&
-                  !constraint.is_fixed_to_bottom_edge());
-    }
-    {
-      Element* element = document->getElementById("div-tr");
-      ASSERT_TRUE(element);
-      cc::Layer* layer = CcLayerFromElement(element);
-      ASSERT_TRUE(layer);
-      cc::LayerPositionConstraint constraint = layer->position_constraint();
-      ASSERT_TRUE(constraint.is_fixed_position());
-      ASSERT_TRUE(constraint.is_fixed_to_right_edge() &&
-                  !constraint.is_fixed_to_bottom_edge());
-    }
-    {
-      Element* element = document->getElementById("div-bl");
-      ASSERT_TRUE(element);
-      cc::Layer* layer = CcLayerFromElement(element);
-      ASSERT_TRUE(layer);
-      cc::LayerPositionConstraint constraint = layer->position_constraint();
-      ASSERT_TRUE(constraint.is_fixed_position());
-      ASSERT_TRUE(!constraint.is_fixed_to_right_edge() &&
-                  constraint.is_fixed_to_bottom_edge());
-    }
-    {
-      Element* element = document->getElementById("div-br");
-      ASSERT_TRUE(element);
-      cc::Layer* layer = CcLayerFromElement(element);
-      ASSERT_TRUE(layer);
-      cc::LayerPositionConstraint constraint = layer->position_constraint();
-      ASSERT_TRUE(constraint.is_fixed_position());
-      ASSERT_TRUE(constraint.is_fixed_to_right_edge() &&
-                  constraint.is_fixed_to_bottom_edge());
-    }
-    {
-      Element* element = document->getElementById("span-tl");
-      ASSERT_TRUE(element);
-      cc::Layer* layer = CcLayerFromElement(element);
-      ASSERT_TRUE(layer);
-      cc::LayerPositionConstraint constraint = layer->position_constraint();
-      ASSERT_TRUE(constraint.is_fixed_position());
-      ASSERT_TRUE(!constraint.is_fixed_to_right_edge() &&
-                  !constraint.is_fixed_to_bottom_edge());
-    }
-    {
-      Element* element = document->getElementById("span-tr");
-      ASSERT_TRUE(element);
-      cc::Layer* layer = CcLayerFromElement(element);
-      ASSERT_TRUE(layer);
-      cc::LayerPositionConstraint constraint = layer->position_constraint();
-      ASSERT_TRUE(constraint.is_fixed_position());
-      ASSERT_TRUE(constraint.is_fixed_to_right_edge() &&
-                  !constraint.is_fixed_to_bottom_edge());
-    }
-    {
-      Element* element = document->getElementById("span-bl");
-      ASSERT_TRUE(element);
-      cc::Layer* layer = CcLayerFromElement(element);
-      ASSERT_TRUE(layer);
-      cc::LayerPositionConstraint constraint = layer->position_constraint();
-      ASSERT_TRUE(constraint.is_fixed_position());
-      ASSERT_TRUE(!constraint.is_fixed_to_right_edge() &&
-                  constraint.is_fixed_to_bottom_edge());
-    }
-    {
-      Element* element = document->getElementById("span-br");
-      ASSERT_TRUE(element);
-      cc::Layer* layer = CcLayerFromElement(element);
-      ASSERT_TRUE(layer);
-      cc::LayerPositionConstraint constraint = layer->position_constraint();
-      ASSERT_TRUE(constraint.is_fixed_position());
-      ASSERT_TRUE(constraint.is_fixed_to_right_edge() &&
-                  constraint.is_fixed_to_bottom_edge());
-    }
-  }
 }
 
-// BlinkGenPropertyTrees (BGPT) changes where the sticky constraints are stored.
-// Without BGPT, sticky constraints are stored on cc::Layer (via
-// GraphicsLayer::SetStickyPositionConstraint). With BGPT, sticky constraints
-// are stored on transform property tree nodes.
+// Sticky constraints are stored on transform property tree nodes.
 static cc::LayerStickyPositionConstraint GetStickyConstraint(Element* element) {
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-    cc::Layer* layer = CcLayerFromElement(element);
-    DCHECK(layer);
-    return layer->sticky_position_constraint();
-  }
-
   const auto* properties =
       element->GetLayoutObject()->FirstFragment().PaintProperties();
   DCHECK(properties);
@@ -1745,9 +1604,6 @@
 }
 
 TEST_P(ScrollingCoordinatorTest, ScrollOffsetClobberedBeforeCompositingUpdate) {
-  // This test fails without BGPT enabled. https://crbug.com/930636.
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    return;
   LoadHTML(R"HTML(
           <!DOCTYPE html>
           <style>
@@ -1793,9 +1649,6 @@
 }
 
 TEST_P(ScrollingCoordinatorTest, UpdateVisualViewportScrollLayer) {
-  // This test fails without BGPT enabled. https://crbug.com/930636.
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    return;
   LoadHTML(R"HTML(
           <!DOCTYPE html>
           <style>
@@ -1862,10 +1715,9 @@
 // PaintNonFastScrollableRegions is launched.
 using PaintNonFastScrollableRegionsScrollingCoordinatorTest =
     ScrollingCoordinatorTest;
-INSTANTIATE_TEST_SUITE_P(
-    All,
-    PaintNonFastScrollableRegionsScrollingCoordinatorTest,
-    ::testing::Values(kScrollingCoordinatorTestPaintNonFastScrollableRegions));
+INSTANTIATE_TEST_SUITE_P(All,
+                         PaintNonFastScrollableRegionsScrollingCoordinatorTest,
+                         ::testing::Values(true));
 
 TEST_P(PaintNonFastScrollableRegionsScrollingCoordinatorTest,
        NonCompositedNonFastScrollableRegion) {
@@ -1997,15 +1849,9 @@
   FakeGLES2Interface gl_;
 };
 
-INSTANTIATE_TEST_SUITE_P(
-    All,
-    ScrollingCoordinatorTestWithAcceleratedContext,
-    ::testing::Values(
-        kScrollingCoordinatorTestNoFlags,
-        kScrollingCoordinatorTestBlinkGenPropertyTrees,
-        kScrollingCoordinatorTestPaintNonFastScrollableRegions,
-        (kScrollingCoordinatorTestBlinkGenPropertyTrees |
-         kScrollingCoordinatorTestPaintNonFastScrollableRegions)));
+INSTANTIATE_TEST_SUITE_P(All,
+                         ScrollingCoordinatorTestWithAcceleratedContext,
+                         testing::Bool());
 
 TEST_P(ScrollingCoordinatorTestWithAcceleratedContext, CanvasTouchActionRects) {
   LoadHTML(R"HTML(
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
index 0def054..c6f9e1b0 100644
--- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
+++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
@@ -119,17 +119,6 @@
   return false;
 }
 
-static inline bool IsCompositedCanvas(const LayoutObject& layout_object) {
-  if (layout_object.IsCanvas()) {
-    auto* canvas = To<HTMLCanvasElement>(layout_object.GetNode());
-    if (canvas->SurfaceLayerBridge())
-      return true;
-    if (CanvasRenderingContext* context = canvas->RenderingContext())
-      return context->IsComposited();
-  }
-  return false;
-}
-
 static bool HasBoxDecorationsOrBackgroundImage(const ComputedStyle& style) {
   return style.HasBoxDecorations() || style.HasBackgroundImage();
 }
@@ -155,14 +144,6 @@
   return ToLayoutEmbeddedObject(layout_object).Plugin();
 }
 
-static inline bool IsAcceleratedContents(LayoutObject& layout_object) {
-  return IsCompositedCanvas(layout_object) ||
-         (layout_object.IsEmbeddedObject() &&
-          ToLayoutEmbeddedObject(layout_object)
-              .RequiresAcceleratedCompositing()) ||
-         layout_object.IsVideo();
-}
-
 // Returns true if the compositor will be responsible for applying the sticky
 // position offset for this composited layer.
 static bool UsesCompositedStickyPosition(PaintLayer& layer) {
@@ -236,12 +217,10 @@
     }
   }
 
-  UpdateClippingLayers(false, false, false);
-  UpdateOverflowControlsLayers(false, false, false, false);
+  UpdateOverflowControlsLayers(false, false, false);
   UpdateChildTransformLayer(false);
   UpdateForegroundLayer(false);
   UpdateMaskLayer(false);
-  UpdateChildClippingMaskLayer(false);
   UpdateScrollingLayers(false);
   UpdateSquashingLayers(false);
   DestroyGraphicsLayers();
@@ -270,10 +249,6 @@
   graphics_layer_->SetHitTestable(true);
   UpdateOpacity(GetLayoutObject().StyleRef());
   UpdateTransform(GetLayoutObject().StyleRef());
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    OwningLayer().UpdateFilterReferenceBox();
-  UpdateFilters();
-  UpdateBackdropFilters();
   UpdateLayerBlendMode(GetLayoutObject().StyleRef());
   UpdateIsRootForIsolatedGroup();
 }
@@ -282,14 +257,10 @@
   if (graphics_layer_)
     graphics_layer_->RemoveFromParent();
 
-  ancestor_clipping_layer_ = nullptr;
-  ancestor_clipping_mask_layer_ = nullptr;
   graphics_layer_ = nullptr;
   foreground_layer_ = nullptr;
-  child_containment_layer_ = nullptr;
   child_transform_layer_ = nullptr;
   mask_layer_ = nullptr;
-  child_clipping_mask_layer_ = nullptr;
 
   scrolling_layer_ = nullptr;
   scrolling_contents_layer_ = nullptr;
@@ -315,84 +286,6 @@
   graphics_layer_->SetTransform(t);
 }
 
-void CompositedLayerMapping::UpdateFilters() {
-  // Filters will be handled by property tree
-  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    return;
-  CompositorFilterOperations operations;
-  OwningLayer().UpdateCompositorFilterOperationsForFilter(operations);
-  graphics_layer_->SetFilters(std::move(operations));
-}
-
-void CompositedLayerMapping::UpdateBackdropFilters() {
-  // Filters will be handled by property tree
-  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    return;
-  CompositorFilterOperations backdrop_filters =
-      OwningLayer().CreateCompositorFilterOperationsForBackdropFilter();
-  gfx::RRectF backdrop_filter_bounds = OwningLayer().BackdropFilterBounds(
-      OwningLayer().BackdropFilterReferenceBox());
-  graphics_layer_->SetBackdropFilters(backdrop_filters, backdrop_filter_bounds);
-}
-
-void CompositedLayerMapping::UpdateStickyConstraints(
-    const ComputedStyle& style) {
-  // Sticky offsets will be applied by property tree instead,
-  // see PaintArtifactCompositor/PropertyTreeManager.
-  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    return;
-
-  cc::LayerStickyPositionConstraint constraint;
-  if (!UsesCompositedStickyPosition(owning_layer_)) {
-    // Clear the previous sticky position constraint - if set.
-    graphics_layer_->SetStickyPositionConstraint(constraint);
-    return;
-  }
-
-  const PaintLayer* ancestor_overflow_layer =
-      owning_layer_.AncestorOverflowLayer();
-  const StickyConstraintsMap& constraints_map =
-      ancestor_overflow_layer->GetScrollableArea()->GetStickyConstraintsMap();
-  const StickyPositionScrollingConstraints& constraints =
-      constraints_map.at(&owning_layer_);
-
-  constraint.is_sticky = true;
-  constraint.is_anchored_left = constraints.is_anchored_left;
-  constraint.is_anchored_right = constraints.is_anchored_right;
-  constraint.is_anchored_top = constraints.is_anchored_top;
-  constraint.is_anchored_bottom = constraints.is_anchored_bottom;
-  constraint.left_offset = constraints.left_offset;
-  constraint.right_offset = constraints.right_offset;
-  constraint.top_offset = constraints.top_offset;
-  constraint.bottom_offset = constraints.bottom_offset;
-  constraint.constraint_box_rect =
-      RoundedIntRect(GetLayoutObject().ComputeStickyConstrainingRect());
-  constraint.scroll_container_relative_sticky_box_rect =
-      RoundedIntRect(constraints.scroll_container_relative_sticky_box_rect);
-  constraint.scroll_container_relative_containing_block_rect = RoundedIntRect(
-      constraints.scroll_container_relative_containing_block_rect);
-  PaintLayer* sticky_box_shifting_ancestor =
-      constraints.nearest_sticky_layer_shifting_sticky_box;
-  if (sticky_box_shifting_ancestor &&
-      sticky_box_shifting_ancestor->GetCompositedLayerMapping()) {
-    constraint.nearest_element_shifting_sticky_box =
-        sticky_box_shifting_ancestor->GetCompositedLayerMapping()
-            ->MainGraphicsLayer()
-            ->GetElementId();
-  }
-  PaintLayer* containing_block_shifting_ancestor =
-      constraints.nearest_sticky_layer_shifting_containing_block;
-  if (containing_block_shifting_ancestor &&
-      containing_block_shifting_ancestor->GetCompositedLayerMapping()) {
-    constraint.nearest_element_shifting_containing_block =
-        containing_block_shifting_ancestor->GetCompositedLayerMapping()
-            ->MainGraphicsLayer()
-            ->GetElementId();
-  }
-
-  graphics_layer_->SetStickyPositionConstraint(constraint);
-}
-
 void CompositedLayerMapping::UpdateLayerBlendMode(const ComputedStyle& style) {
   SetBlendMode(style.GetBlendMode());
 }
@@ -565,13 +458,8 @@
 void CompositedLayerMapping::UpdateAfterPartResize() {
   if (GetLayoutObject().IsLayoutEmbeddedContent()) {
     if (GraphicsLayer* document_layer = FrameContentsGraphicsLayer()) {
-      FloatPoint parent_position =
-          child_containment_layer_
-              ? FloatPoint(child_containment_layer_->GetPosition())
-              : FloatPoint();
-      document_layer->SetPosition(FloatPoint(RoundedIntPoint(
-          ContentsBox().offset -
-          PhysicalOffset::FromFloatPointRound(parent_position))));
+      document_layer->SetPosition(
+          FloatPoint(RoundedIntPoint(ContentsBox().offset)));
     }
   }
 }
@@ -584,117 +472,6 @@
       owning_layer_.GetSquashingDisallowedReasons());
 }
 
-static bool InContainingBlockChain(const PaintLayer* start_layer,
-                                   const PaintLayer* end_layer) {
-  if (start_layer == end_layer)
-    return true;
-
-  LayoutView* view = start_layer->GetLayoutObject().View();
-  for (const LayoutBlock* current_block =
-           start_layer->GetLayoutObject().ContainingBlock();
-       current_block && current_block != view;
-       current_block = current_block->ContainingBlock()) {
-    if (current_block->Layer() == end_layer)
-      return true;
-  }
-
-  return false;
-}
-
-bool CompositedLayerMapping::AncestorRoundedCornersWillClip(
-    const FloatRect& bounds_in_ancestor_space) const {
-  // Check border-radius clips between us and the state we inherited.
-  for (const PaintLayer* layer = owning_layer_.Parent(); layer;
-       layer = layer->Parent()) {
-    // Check clips for embedded content despite their lack of overflow,
-    // because in practice they do need to clip. However, the clip is only
-    // used when painting child clipping masks to avoid clipping out border
-    // decorations.
-    if ((layer->GetLayoutObject().HasOverflowClip() ||
-         layer->GetLayoutObject().IsLayoutEmbeddedContent()) &&
-        layer->GetLayoutObject().StyleRef().HasBorderRadius() &&
-        InContainingBlockChain(&owning_layer_, layer)) {
-      PhysicalOffset delta;
-      layer->ConvertToLayerCoords(clip_inheritance_ancestor_, delta);
-
-      // The PaintLayer's size is pixel-snapped if it is a LayoutBox. We can't
-      // use a pre-snapped border rect for clipping, since
-      // getRoundedInnerBorderFor assumes it has not been snapped yet.
-      LayoutSize size(layer->GetLayoutBox()
-                          ? ToLayoutBox(layer->GetLayoutObject()).Size()
-                          : LayoutSize(layer->Size()));
-      auto clip_rect =
-          layer->GetLayoutObject().StyleRef().GetRoundedInnerBorderFor(
-              LayoutRect(delta.ToLayoutPoint(), size));
-      auto inner_clip_rect = clip_rect.RadiusCenterRect();
-
-      // The first condition catches cases where the child is certainly inside
-      // the rounded corner portion of the border, and cannot be clipped by
-      // the rounded portion. The second catches cases where the child is
-      // entirely outside the rectangular border (ignoring rounded corners) so
-      // is also unaffected by the rounded corners. In both cases the existing
-      // rectangular clip is adequate and the mask is unnecessary.
-      if (!inner_clip_rect.Contains(bounds_in_ancestor_space) &&
-          bounds_in_ancestor_space.Intersects(clip_rect.Rect())) {
-        return true;
-      }
-    }
-    if (layer == clip_inheritance_ancestor_)
-      break;
-  }
-  return false;
-}
-
-void CompositedLayerMapping::
-    OwningLayerClippedOrMaskedByLayerNotAboveCompositedAncestor(
-        bool& owning_layer_is_clipped,
-        bool& owning_layer_is_masked) const {
-  owning_layer_is_clipped = false;
-  owning_layer_is_masked = false;
-
-  if (!clip_inheritance_ancestor_)
-    return;
-
-  // Compute the clips below the layer we inherit clip state from.
-  // Ignore the clips of the inherited layer, because they are already a part
-  // of the inherited state.
-  // FIXME: this should use cached clip rects, but this sometimes give
-  // inaccurate results (and trips the ASSERTS in PaintLayerClipper).
-  ClipRectsContext clip_rects_context(
-      clip_inheritance_ancestor_,
-      &clip_inheritance_ancestor_->GetLayoutObject().FirstFragment(),
-      kUncachedClipRects, kIgnorePlatformOverlayScrollbarSize,
-      kIgnoreOverflowClip);
-
-  ClipRect clip_rect;
-  owning_layer_
-      .Clipper(PaintLayer::GeometryMapperOption::kDoNotUseGeometryMapper)
-      .CalculateBackgroundClipRect(clip_rects_context, clip_rect);
-  if (clip_rect.Rect() == PhysicalRect(LayoutRect::InfiniteIntRect()))
-    return;
-
-  owning_layer_is_clipped = true;
-
-  // TODO(schenney): CSS clips are not applied to composited children, and
-  // should be via mask or by compositing the parent too.
-  // https://bugs.chromium.org/p/chromium/issues/detail?id=615870
-  if (!clip_rect.HasRadius())
-    return;
-
-  // If there are any rounded corners we must use a mask in the presence of
-  // composited descendants because we have no efficient way to determine the
-  // bounds of those children for optimizing the mask.
-  if (owning_layer_.HasCompositingDescendant()) {
-    owning_layer_is_masked = true;
-    return;
-  }
-
-  FloatRect bounds_in_ancestor_space(GetLayoutObject().LocalToAncestorRect(
-      composited_bounds_, &clip_inheritance_ancestor_->GetLayoutObject()));
-  owning_layer_is_masked =
-      AncestorRoundedCornersWillClip(bounds_in_ancestor_space);
-}
-
 const PaintLayer* CompositedLayerMapping::ScrollParent() const {
   const PaintLayer* scroll_parent = owning_layer_.ScrollParent();
   if (scroll_parent && !scroll_parent->NeedsCompositedScrolling())
@@ -709,22 +486,6 @@
                      : nullptr;
 }
 
-void CompositedLayerMapping::UpdateClipInheritanceAncestor(
-    const PaintLayer* compositing_container) {
-  // Determine the clip state we are going to inherit.
-  // There are three sources a layer inherits its clip state from, in the
-  // order of priority (see cc/trees/property_tree_builder.cc):
-  // 1. Clip parent
-  // 2. Scroll parent
-  // 3. Parent layer
-  if (const PaintLayer* clip_parent = CompositedClipParent())
-    clip_inheritance_ancestor_ = clip_parent;
-  else if (const PaintLayer* scroll_parent = ScrollParent())
-    clip_inheritance_ancestor_ = scroll_parent;
-  else
-    clip_inheritance_ancestor_ = compositing_container;
-}
-
 bool CompositedLayerMapping::UpdateGraphicsLayerConfiguration(
     const PaintLayer* compositing_container) {
   DCHECK_EQ(owning_layer_.Compositor()->Lifecycle().GetState(),
@@ -745,32 +506,6 @@
           compositor->NeedsContentsCompositingLayer(&owning_layer_)))
     layer_config_changed = true;
 
-  bool needs_descendants_clipping_layer =
-      compositor->ClipsCompositingDescendants(&owning_layer_);
-
-  // Our scrolling layer will clip.
-  if (owning_layer_.NeedsCompositedScrolling())
-    needs_descendants_clipping_layer = false;
-
-  const PaintLayer* scroll_parent = ScrollParent();
-
-  // This is required because compositing layers are parented according to the
-  // z-order hierarchy, yet clipping goes down the layoutObject hierarchy. Thus,
-  // a PaintLayer can be clipped by a PaintLayer that is an ancestor in the
-  // layoutObject hierarchy, but a sibling in the z-order hierarchy. Further,
-  // that sibling need not be composited at all. In such scenarios, an ancestor
-  // clipping layer is necessary to apply the composited clip for this layer.
-  bool needs_ancestor_clip = false;
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-    bool needs_ancestor_clipping_mask = false;
-    UpdateClipInheritanceAncestor(compositing_container);
-    OwningLayerClippedOrMaskedByLayerNotAboveCompositedAncestor(
-        needs_ancestor_clip, needs_ancestor_clipping_mask);
-    if (UpdateClippingLayers(needs_ancestor_clip, needs_ancestor_clipping_mask,
-                             needs_descendants_clipping_layer))
-      layer_config_changed = true;
-  }
-
   if (UpdateScrollingLayers(owning_layer_.NeedsCompositedScrolling()))
     layer_config_changed = true;
 
@@ -783,9 +518,9 @@
   if (UpdateDecorationOutlineLayer(needs_decoration_outline_layer))
     layer_config_changed = true;
 
-  if (UpdateOverflowControlsLayers(
-          RequiresHorizontalScrollbarLayer(), RequiresVerticalScrollbarLayer(),
-          RequiresScrollCornerLayer(), needs_ancestor_clip))
+  if (UpdateOverflowControlsLayers(RequiresHorizontalScrollbarLayer(),
+                                   RequiresVerticalScrollbarLayer(),
+                                   RequiresScrollCornerLayer()))
     layer_config_changed = true;
 
   bool has_perspective = style.HasPerspective();
@@ -796,6 +531,7 @@
   if (UpdateSquashingLayers(!squashed_layers_.IsEmpty()))
     layer_config_changed = true;
 
+  const PaintLayer* scroll_parent = ScrollParent();
   UpdateScrollParent(scroll_parent);
   UpdateClipParent(scroll_parent);
 
@@ -816,34 +552,6 @@
     layer_config_changed = true;
   }
 
-  // If we have a border radius on a scrolling layer, we need a clipping mask
-  // to properly clip the scrolled contents, even if there are no composited
-  // descendants.
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-    bool is_accelerated_contents = IsAcceleratedContents(layout_object);
-    bool has_children_subject_to_overflow_clip =
-        HasClippingLayer() || HasScrollingLayer() || is_accelerated_contents;
-    bool needs_child_clipping_mask =
-        style.HasBorderRadius() && has_children_subject_to_overflow_clip;
-    if (UpdateChildClippingMaskLayer(needs_child_clipping_mask))
-      layer_config_changed = true;
-    {
-      // Attach child clipping mask layer to the first layer that can be applied
-      // and clear the rest.
-      // TODO(trchen): Verify if the 3 cases are mutually exclusive.
-      GraphicsLayer* first_come_first_served = child_clipping_mask_layer_.get();
-      if (HasClippingLayer()) {
-        ClippingLayer()->SetMaskLayer(first_come_first_served);
-        first_come_first_served = nullptr;
-      }
-      if (HasScrollingLayer()) {
-        ScrollingLayer()->SetMaskLayer(first_come_first_served);
-        first_come_first_served = nullptr;
-      }
-      graphics_layer_->SetContentsClippingMaskLayer(first_come_first_served);
-    }
-  }
-
   UpdateBackgroundColor();
 
   if (layout_object.IsImage()) {
@@ -1162,17 +870,6 @@
   if (!GetLayoutObject().StyleRef().IsRunningOpacityAnimationOnCompositor())
     UpdateOpacity(GetLayoutObject().StyleRef());
 
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    OwningLayer().UpdateFilterReferenceBox();
-
-  if (!GetLayoutObject().StyleRef().IsRunningFilterAnimationOnCompositor())
-    UpdateFilters();
-
-  if (!GetLayoutObject()
-           .StyleRef()
-           .IsRunningBackdropFilterAnimationOnCompositor())
-    UpdateBackdropFilters();
-
   IntRect local_compositing_bounds;
   IntRect relative_compositing_bounds;
   PhysicalOffset offset_from_composited_ancestor;
@@ -1186,11 +883,6 @@
   ComputeGraphicsLayerParentLocation(compositing_container,
                                      graphics_layer_parent_location);
 
-  // Might update graphicsLayerParentLocation.
-  UpdateAncestorClippingLayerGeometry(compositing_container,
-                                      snapped_offset_from_composited_ancestor,
-                                      graphics_layer_parent_location);
-
   IntSize contents_size(relative_compositing_bounds.Size());
 
   UpdateMainGraphicsLayerGeometry(
@@ -1199,14 +891,12 @@
   UpdateOverflowControlsHostLayerGeometry(compositing_stacking_context,
                                           compositing_container,
                                           graphics_layer_parent_location);
-  UpdateStickyConstraints(GetLayoutObject().StyleRef());
   UpdateSquashingLayerGeometry(
       graphics_layer_parent_location, compositing_container,
       snapped_offset_from_composited_ancestor, squashed_layers_,
       layers_needing_paint_invalidation);
 
   UpdateChildTransformLayerGeometry();
-  UpdateChildContainmentLayerGeometry();
 
   UpdateMaskLayerGeometry();
   UpdateTransformGeometry(snapped_offset_from_composited_ancestor,
@@ -1217,7 +907,6 @@
   UpdateDecorationOutlineLayerGeometry(contents_size);
   UpdateScrollingLayerGeometry(local_compositing_bounds);
   UpdateForegroundLayerGeometry();
-  UpdateChildClippingMaskLayerGeometry();
 
   if (owning_layer_.GetScrollableArea() &&
       owning_layer_.GetScrollableArea()->ScrollsOverflow())
@@ -1251,47 +940,10 @@
   UpdateShouldFlattenTransform();
   UpdateChildrenTransform();
   UpdateScrollParent(ScrollParent());
-  UpdateOverscrollBehavior();
-  UpdateSnapContainerData();
-  RegisterScrollingLayers();
 
   UpdateCompositingReasons();
 }
 
-void CompositedLayerMapping::UpdateOverscrollBehavior() {
-  // OverscrollBehavior directly set to scroll node when BGPT enabled.
-  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    return;
-
-  EOverscrollBehavior behavior_x =
-      GetLayoutObject().StyleRef().OverscrollBehaviorX();
-  EOverscrollBehavior behavior_y =
-      GetLayoutObject().StyleRef().OverscrollBehaviorY();
-  if (scrolling_contents_layer_) {
-    scrolling_contents_layer_->SetOverscrollBehavior(cc::OverscrollBehavior(
-        static_cast<cc::OverscrollBehavior::OverscrollBehaviorType>(behavior_x),
-        static_cast<cc::OverscrollBehavior::OverscrollBehaviorType>(
-            behavior_y)));
-  }
-}
-
-void CompositedLayerMapping::UpdateSnapContainerData() {
-  // SnapContainerData directly set to scroll node when BGPT enabled.
-  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    return;
-
-  if (!GetLayoutObject().IsBox() || !scrolling_contents_layer_)
-    return;
-
-  SnapCoordinator* snap_coordinator =
-      GetLayoutObject().GetDocument().GetSnapCoordinator();
-  if (!snap_coordinator)
-    return;
-
-  scrolling_contents_layer_->SetSnapContainerData(
-      snap_coordinator->GetSnapContainerData(ToLayoutBox(GetLayoutObject())));
-}
-
 void CompositedLayerMapping::UpdateMainGraphicsLayerGeometry(
     const IntRect& relative_compositing_bounds,
     const IntRect& local_compositing_bounds,
@@ -1347,15 +999,6 @@
   // For now, there is no need to set graphics_layer_'s hit testable bit here,
   // because it is always hit testable from cc's perspective.
   graphics_layer_->SetContentsVisible(contents_visible);
-
-  // In BGPT mode, we do not need to update the backface visibility here, as it
-  // will already be set by PaintArtifactCompsitor based on
-  // TransformPaintPropertyNode::IsBackfaceHidden.
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-    graphics_layer_->SetBackfaceVisibility(
-        GetLayoutObject().StyleRef().BackfaceVisibility() ==
-        EBackfaceVisibility::kVisible);
-  }
 }
 
 void CompositedLayerMapping::ComputeGraphicsLayerParentLocation(
@@ -1385,99 +1028,6 @@
   }
 }
 
-void CompositedLayerMapping::UpdateAncestorClippingLayerGeometry(
-    const PaintLayer* compositing_container,
-    const IntPoint& snapped_offset_from_composited_ancestor,
-    IntPoint& graphics_layer_parent_location) {
-  if (!compositing_container || !ancestor_clipping_layer_)
-    return;
-
-  ClipRectsContext clip_rects_context(
-      clip_inheritance_ancestor_,
-      &clip_inheritance_ancestor_->GetLayoutObject().FirstFragment(),
-      kPaintingClipRectsIgnoringOverflowClip,
-      kIgnorePlatformOverlayScrollbarSize, kIgnoreOverflowClipAndScroll);
-
-  ClipRect clip_rect;
-  owning_layer_
-      .Clipper(PaintLayer::GeometryMapperOption::kDoNotUseGeometryMapper)
-      .CalculateBackgroundClipRect(clip_rects_context, clip_rect);
-  // Scroll offset is not included in the clip rect returned above
-  // (see kIgnoreOverflowClipAndScroll), so we need to add it in
-  // now. Scroll offset is excluded so that we do not need to invalidate
-  // the clip rect cache on scroll.
-  if (clip_inheritance_ancestor_->GetScrollableArea()) {
-    clip_rect.Move(PhysicalOffset::FromFloatSizeRound(
-        -clip_inheritance_ancestor_->GetScrollableArea()->GetScrollOffset()));
-  }
-
-  DCHECK(clip_rect.Rect() != PhysicalRect(LayoutRect::InfiniteIntRect()));
-
-  // The accumulated clip rect is in the space of clip_inheritance_ancestor_.
-  // It needs to be converted to the space of our compositing container because
-  // our layer position is based on that.
-  PhysicalRect clip_rect_in_compositing_container_space = clip_rect.Rect();
-  // The following two branches are doing exact the same conversion, but
-  // ConvertToLayerCoords can only handle descendant-to-ancestor conversion.
-  // Inversion needs to be done manually if clip_inheritance_container is not
-  // a descendant of compositing_container.
-  if (clip_inheritance_ancestor_ == compositing_container) {
-    // No needs to convert.
-  } else if (clip_inheritance_ancestor_ == ScrollParent()) {
-    // Having a scroll parent implies that the inherited clip is a sibling to
-    // us in paint order, thus our compositing container must be an ancestor
-    // of the scroll parent.
-    // See CompositingInputsUpdater::UpdateRecursive().
-    DCHECK(clip_inheritance_ancestor_->GetLayoutObject().IsDescendantOf(
-        &compositing_container->GetLayoutObject()));
-    clip_inheritance_ancestor_->ConvertToLayerCoords(
-        compositing_container, clip_rect_in_compositing_container_space);
-  } else {
-    // Inherits from clip parent. The clip parent is set only when we need to
-    // escape some clip that was applied to our compositing container. As such,
-    // the clip parent must be some ancestor of our compositing container.
-    DCHECK(compositing_container->GetLayoutObject().IsDescendantOf(
-        &clip_inheritance_ancestor_->GetLayoutObject()));
-    PhysicalOffset compositing_container_origin_in_clip_ancestor_space;
-    compositing_container->ConvertToLayerCoords(
-        clip_inheritance_ancestor_,
-        compositing_container_origin_in_clip_ancestor_space);
-    clip_rect_in_compositing_container_space.offset -=
-        compositing_container_origin_in_clip_ancestor_space;
-  }
-  clip_rect_in_compositing_container_space.offset +=
-      compositing_container->SubpixelAccumulation();
-
-  IntRect snapped_clip_rect =
-      PixelSnappedIntRect(clip_rect_in_compositing_container_space);
-
-  ancestor_clipping_layer_->SetPosition(FloatPoint(
-      snapped_clip_rect.Location() - graphics_layer_parent_location));
-  ancestor_clipping_layer_->SetSize(gfx::Size(snapped_clip_rect.Size()));
-
-  // backgroundRect is relative to compositingContainer, so subtract
-  // snappedOffsetFromCompositedAncestor.X/snappedOffsetFromCompositedAncestor.Y
-  // to get back to local coords.
-  ancestor_clipping_layer_->SetOffsetFromLayoutObject(
-      snapped_clip_rect.Location() - snapped_offset_from_composited_ancestor);
-
-  if (ancestor_clipping_mask_layer_) {
-    // Need to update LayerState for the new offset.
-    // The pre-paint tree walk does this.
-    if (ancestor_clipping_layer_->OffsetFromLayoutObject() !=
-        ancestor_clipping_mask_layer_->OffsetFromLayoutObject())
-      GetLayoutObject().SetNeedsPaintPropertyUpdate();
-    ancestor_clipping_mask_layer_->SetOffsetFromLayoutObject(
-        ancestor_clipping_layer_->OffsetFromLayoutObject());
-    ancestor_clipping_mask_layer_->SetSize(ancestor_clipping_layer_->Size());
-    ancestor_clipping_mask_layer_->SetNeedsDisplay();
-  }
-
-  // The primary layer is then parented in, and positioned relative to this
-  // clipping layer.
-  graphics_layer_parent_location = snapped_clip_rect.Location();
-}
-
 void CompositedLayerMapping::UpdateOverflowControlsHostLayerGeometry(
     const PaintLayer* compositing_stacking_context,
     const PaintLayer* compositing_container,
@@ -1501,51 +1051,22 @@
         compositing_stacking_context->GetCompositedLayerMapping();
     DCHECK(stacking_clm);
 
-    // Either m_overflowControlsHostLayer or
-    // m_overflowControlsAncestorClippingLayer (if it exists) will be a child of
-    // the main GraphicsLayer of the compositing stacking context.
+    // overflow_controls_host_layer_ will be a child of the main GraphicsLayer
+    // of the compositing stacking context.
     IntSize stacking_offset_from_layout_object =
         stacking_clm->MainGraphicsLayer()->OffsetFromLayoutObject();
 
-    if (overflow_controls_ancestor_clipping_layer_) {
-      overflow_controls_ancestor_clipping_layer_->SetSize(
-          ancestor_clipping_layer_->Size());
-      overflow_controls_ancestor_clipping_layer_->SetOffsetFromLayoutObject(
-          ancestor_clipping_layer_->OffsetFromLayoutObject());
-      overflow_controls_ancestor_clipping_layer_->SetMasksToBounds(true);
-
-      FloatPoint position;
-      if (compositing_stacking_context == compositing_container) {
-        position = FloatPoint(ancestor_clipping_layer_->GetPosition());
-      } else {
-        // graphicsLayerParentLocation is the location of
-        // m_ancestorClippingLayer relative to compositingContainer (including
-        // any offset from compositingContainer's m_childContainmentLayer).
-        PhysicalOffset offset(graphics_layer_parent_location);
-        compositing_container->ConvertToLayerCoords(
-            compositing_stacking_context, offset);
-        position =
-            FloatPoint(offset) - FloatSize(stacking_offset_from_layout_object);
-      }
-
-      overflow_controls_ancestor_clipping_layer_->SetPosition(position);
-      host_layer_position =
-          -PhysicalOffset(ancestor_clipping_layer_->OffsetFromLayoutObject());
-    } else {
-      // The controls are in the same 2D space as the compositing container, so
-      // we can map them into the space of the container.
-      host_layer_position =
-          owning_layer_.GetLayoutObject().LocalToAncestorPoint(
-              PhysicalOffset(),
-              &compositing_stacking_context->GetLayoutObject(),
-              kIgnoreTransforms);
-      if (PaintLayerScrollableArea* scrollable_area =
-              compositing_stacking_context->GetScrollableArea()) {
-        host_layer_position += PhysicalOffset::FromFloatPointRound(
-            scrollable_area->ScrollPosition());
-      }
-      host_layer_position -= PhysicalOffset(stacking_offset_from_layout_object);
+    // The controls are in the same 2D space as the compositing container, so
+    // we can map them into the space of the container.
+    host_layer_position = owning_layer_.GetLayoutObject().LocalToAncestorPoint(
+        PhysicalOffset(), &compositing_stacking_context->GetLayoutObject(),
+        kIgnoreTransforms);
+    if (PaintLayerScrollableArea* scrollable_area =
+            compositing_stacking_context->GetScrollableArea()) {
+      host_layer_position += PhysicalOffset::FromFloatPointRound(
+          scrollable_area->ScrollPosition());
     }
+    host_layer_position -= PhysicalOffset(stacking_offset_from_layout_object);
   } else {
     host_layer_position -=
         PhysicalOffset(graphics_layer_->OffsetFromLayoutObject());
@@ -1558,57 +1079,6 @@
           owning_layer_.SubpixelAccumulation());
   overflow_controls_host_layer_->SetSize(gfx::Size(border_box.Size()));
   overflow_controls_host_layer_->SetMasksToBounds(true);
-
-  // In BGPT mode, we do not need to update the backface visibility here, as it
-  // will already be set by PaintArtifactCompsitor based on
-  // TransformPaintPropertyNode::IsBackfaceHidden.
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-    overflow_controls_host_layer_->SetBackfaceVisibility(
-        owning_layer_.GetLayoutObject().StyleRef().BackfaceVisibility() ==
-        EBackfaceVisibility::kVisible);
-  }
-}
-
-void CompositedLayerMapping::UpdateChildContainmentLayerGeometry() {
-  if (!child_containment_layer_)
-    return;
-  DCHECK(GetLayoutObject().IsBox());
-
-  if (GetLayoutObject().IsLayoutEmbeddedContent()) {
-    // Embedded content layers do not have a clipping rect defined,
-    // so use the PaddingBoxRect.
-    IntRect clipping_box = PixelSnappedIntRect(
-        ToLayoutBox(GetLayoutObject()).PhysicalPaddingBoxRect());
-    child_containment_layer_->SetSize(gfx::Size(clipping_box.Size()));
-    child_containment_layer_->SetOffsetFromLayoutObject(
-        ToIntSize(clipping_box.Location()));
-    IntPoint parent_location(
-        child_containment_layer_->Parent()->OffsetFromLayoutObject());
-    child_containment_layer_->SetPosition(
-        FloatPoint(clipping_box.Location() - parent_location));
-  } else {
-    IntRect clipping_box = PixelSnappedIntRect(
-        ToLayoutBox(GetLayoutObject())
-            .ClippingRect(owning_layer_.SubpixelAccumulation()));
-    child_containment_layer_->SetSize(gfx::Size(clipping_box.Size()));
-    child_containment_layer_->SetOffsetFromLayoutObject(
-        ToIntSize(clipping_box.Location()));
-    IntPoint parent_location(
-        child_containment_layer_->Parent()->OffsetFromLayoutObject());
-    child_containment_layer_->SetPosition(
-        FloatPoint(clipping_box.Location() - parent_location));
-  }
-
-  if (child_clipping_mask_layer_ && !scrolling_layer_ &&
-      !GetLayoutObject().StyleRef().ClipPath()) {
-    if (child_clipping_mask_layer_->Size() !=
-        child_containment_layer_->Size()) {
-      child_clipping_mask_layer_->SetSize(child_containment_layer_->Size());
-      child_clipping_mask_layer_->SetNeedsDisplay();
-    }
-    child_clipping_mask_layer_->SetOffsetFromLayoutObject(
-        child_containment_layer_->OffsetFromLayoutObject());
-  }
 }
 
 void CompositedLayerMapping::UpdateChildTransformLayerGeometry() {
@@ -1696,17 +1166,6 @@
   scrolling_layer_->SetOffsetFromLayoutObject(
       ToIntSize(overflow_clip_rect.Location()));
 
-  if (child_clipping_mask_layer_ && !GetLayoutObject().StyleRef().ClipPath()) {
-    child_clipping_mask_layer_->SetPosition(
-        FloatPoint(scrolling_layer_->GetPosition()));
-    if (child_clipping_mask_layer_->Size() != scrolling_layer_->Size()) {
-      child_clipping_mask_layer_->SetSize(scrolling_layer_->Size());
-      child_clipping_mask_layer_->SetNeedsDisplay();
-    }
-    child_clipping_mask_layer_->SetOffsetFromLayoutObject(
-        ToIntSize(overflow_clip_rect.Location()));
-  }
-
   PaintLayerScrollableArea* scrollable_area = owning_layer_.GetScrollableArea();
   IntSize scroll_size = scrollable_area->PixelSnappedContentsSize(
       owning_layer_.SubpixelAccumulation());
@@ -1729,25 +1188,6 @@
       overflow_clip_rect.Location() - scrollable_area->ScrollOrigin());
 }
 
-void CompositedLayerMapping::UpdateChildClippingMaskLayerGeometry() {
-  if (!child_clipping_mask_layer_ || !GetLayoutObject().StyleRef().ClipPath() ||
-      !GetLayoutObject().IsBox())
-    return;
-  LayoutBox& layout_box = ToLayoutBox(GetLayoutObject());
-  IntRect padding_box = EnclosingIntRect(layout_box.PhysicalPaddingBoxRect());
-
-  child_clipping_mask_layer_->SetPosition(
-      FloatPoint(graphics_layer_->GetPosition()));
-  if (child_clipping_mask_layer_->Size() != graphics_layer_->Size()) {
-    child_clipping_mask_layer_->SetSize(graphics_layer_->Size());
-    child_clipping_mask_layer_->SetNeedsDisplay();
-  }
-  child_clipping_mask_layer_->SetOffsetFromLayoutObject(
-      ToIntSize(padding_box.Location()));
-
-  // NOTE: also some stuff happening in updateChildContainmentLayerGeometry().
-}
-
 bool CompositedLayerMapping::RequiresHorizontalScrollbarLayer() const {
   return owning_layer_.GetScrollableArea() &&
          owning_layer_.GetScrollableArea()->HorizontalScrollbar();
@@ -1779,16 +1219,6 @@
     compositing_bounds =
         IntRect(IntPoint(scrolling_contents_layer_->OffsetFromLayoutObject()),
                 IntSize(scrolling_contents_layer_->Size()));
-  } else if (child_containment_layer_) {
-    // If we have a clipping layer, shrink compositing bounds to the clip rect.
-    // Note: this is technically incorrect because non-composited positive
-    // z-index children can paint into the foreground layer, and positioned
-    // elements can escape clips. We currently always composite layers that
-    // escape clips, thus shrinking the layer won't cause bug.
-    IntRect clipping_box(
-        IntPoint(child_containment_layer_->OffsetFromLayoutObject()),
-        IntSize(child_containment_layer_->Size()));
-    compositing_bounds.Intersect(clipping_box);
   }
 
   IntRect old_compositing_bounds(
@@ -1822,14 +1252,8 @@
 void CompositedLayerMapping::UpdateInternalHierarchy() {
   // m_foregroundLayer has to be inserted in the correct order with child
   // layers, so it's not inserted here.
-  if (ancestor_clipping_layer_)
-    ancestor_clipping_layer_->RemoveAllChildren();
-
   graphics_layer_->RemoveFromParent();
 
-  if (ancestor_clipping_layer_)
-    ancestor_clipping_layer_->AddChild(graphics_layer_.get());
-
   // Layer to which children should be attached as we build the hierarchy.
   GraphicsLayer* bottom_layer = graphics_layer_.get();
   auto update_bottom_layer = [&bottom_layer](GraphicsLayer* layer) {
@@ -1840,7 +1264,6 @@
   };
 
   update_bottom_layer(child_transform_layer_.get());
-  update_bottom_layer(child_containment_layer_.get());
   update_bottom_layer(scrolling_layer_.get());
 
   // Now constructing the subtree for the overflow controls.
@@ -1855,7 +1278,6 @@
                        ->GetVisualViewport()
                        .ContainerLayer();
   }
-  update_bottom_layer(overflow_controls_ancestor_clipping_layer_.get());
   update_bottom_layer(overflow_controls_host_layer_.get());
   if (layer_for_horizontal_scrollbar_) {
     overflow_controls_host_layer_->AddChild(
@@ -1874,17 +1296,10 @@
 
   // The squashing containment layer, if it exists, becomes a no-op parent.
   if (squashing_layer_) {
-    DCHECK((ancestor_clipping_layer_ && !squashing_containment_layer_) ||
-           (!ancestor_clipping_layer_ && squashing_containment_layer_));
-
     if (squashing_containment_layer_) {
       squashing_containment_layer_->RemoveAllChildren();
       squashing_containment_layer_->AddChild(graphics_layer_.get());
       squashing_containment_layer_->AddChild(squashing_layer_.get());
-    } else {
-      // The ancestor clipping layer is already set up and has m_graphicsLayer
-      // under it.
-      ancestor_clipping_layer_->AddChild(squashing_layer_.get());
     }
   }
 }
@@ -1977,14 +1392,8 @@
   if (decoration_outline_layer_)
     decoration_outline_layer_->SetDrawsContent(true);
 
-  if (ancestor_clipping_mask_layer_)
-    ancestor_clipping_mask_layer_->SetDrawsContent(true);
-
   if (mask_layer_)
     mask_layer_->SetDrawsContent(true);
-
-  if (child_clipping_mask_layer_)
-    child_clipping_mask_layer_->SetDrawsContent(true);
 }
 
 void CompositedLayerMapping::UpdateChildrenTransform() {
@@ -1997,68 +1406,6 @@
   UpdateShouldFlattenTransform();
 }
 
-// Return true if the layers changed.
-bool CompositedLayerMapping::UpdateClippingLayers(
-    bool needs_ancestor_clip,
-    bool needs_ancestor_clipping_mask,
-    bool needs_descendant_clip) {
-  bool layers_changed = false;
-
-  if (needs_ancestor_clip) {
-    if (!ancestor_clipping_layer_) {
-      ancestor_clipping_layer_ =
-          CreateGraphicsLayer(CompositingReason::kLayerForAncestorClip);
-      ancestor_clipping_layer_->SetMasksToBounds(true);
-      ancestor_clipping_layer_->SetShouldFlattenTransform(false);
-      layers_changed = true;
-    }
-  } else if (ancestor_clipping_layer_) {
-    if (ancestor_clipping_mask_layer_) {
-      ancestor_clipping_mask_layer_->RemoveFromParent();
-      ancestor_clipping_mask_layer_ = nullptr;
-    }
-    ancestor_clipping_layer_->RemoveFromParent();
-    ancestor_clipping_layer_ = nullptr;
-    layers_changed = true;
-  }
-
-  if (needs_ancestor_clipping_mask) {
-    DCHECK(ancestor_clipping_layer_);
-    if (!ancestor_clipping_mask_layer_) {
-      ancestor_clipping_mask_layer_ =
-          CreateGraphicsLayer(CompositingReason::kLayerForAncestorClippingMask);
-      ancestor_clipping_mask_layer_->SetPaintingPhase(
-          kGraphicsLayerPaintAncestorClippingMask);
-      ancestor_clipping_layer_->SetMaskLayer(
-          ancestor_clipping_mask_layer_.get());
-      layers_changed = true;
-    }
-  } else if (ancestor_clipping_mask_layer_) {
-    ancestor_clipping_mask_layer_->RemoveFromParent();
-    ancestor_clipping_mask_layer_ = nullptr;
-    ancestor_clipping_layer_->SetMaskLayer(nullptr);
-    layers_changed = true;
-  }
-
-  if (needs_descendant_clip) {
-    // We don't need a child containment layer if we're the main frame layout
-    // view layer. It's redundant as the frame clip above us will handle this
-    // clipping.
-    if (!child_containment_layer_ && !is_main_frame_layout_view_layer_) {
-      child_containment_layer_ =
-          CreateGraphicsLayer(CompositingReason::kLayerForDescendantClip);
-      child_containment_layer_->SetMasksToBounds(true);
-      layers_changed = true;
-    }
-  } else if (HasClippingLayer()) {
-    child_containment_layer_->RemoveFromParent();
-    child_containment_layer_ = nullptr;
-    layers_changed = true;
-  }
-
-  return layers_changed;
-}
-
 bool CompositedLayerMapping::UpdateChildTransformLayer(
     bool needs_child_transform_layer) {
   bool layers_changed = false;
@@ -2106,8 +1453,7 @@
 bool CompositedLayerMapping::UpdateOverflowControlsLayers(
     bool needs_horizontal_scrollbar_layer,
     bool needs_vertical_scrollbar_layer,
-    bool needs_scroll_corner_layer,
-    bool needs_ancestor_clip) {
+    bool needs_scroll_corner_layer) {
   if (PaintLayerScrollableArea* scrollable_area =
           owning_layer_.GetScrollableArea()) {
     // If the scrollable area is marked as needing a new scrollbar layer,
@@ -2162,12 +1508,6 @@
   ToggleScrollbarLayerIfNeeded(
       overflow_controls_host_layer_, needs_overflow_controls_host_layer,
       CompositingReason::kLayerForOverflowControlsHost);
-  bool needs_overflow_ancestor_clip_layer =
-      needs_overflow_controls_host_layer && needs_ancestor_clip;
-  ToggleScrollbarLayerIfNeeded(
-      overflow_controls_ancestor_clipping_layer_,
-      needs_overflow_ancestor_clip_layer,
-      CompositingReason::kLayerForOverflowControlsHost);
 
   return horizontal_scrollbar_layer_changed ||
          vertical_scrollbar_layer_changed || scroll_corner_layer_changed;
@@ -2244,8 +1584,6 @@
 // Foreground           *       *     *
 // Squashing              *
 // Mask                       * *   *
-// ChildClippingMask          * *   *
-// AncestorClippingMask       * *   *
 // HorizontalScrollbar      *
 // VerticalScrollbar        *
 // ScrollCorner             *
@@ -2267,10 +1605,6 @@
     f(mapping->MainGraphicsLayer());
   if (((mode & kApplyToLayersAffectedByPreserve3D) ||
        (mode & kApplyToChildContainingLayers)) &&
-      mapping->ClippingLayer())
-    f(mapping->ClippingLayer());
-  if (((mode & kApplyToLayersAffectedByPreserve3D) ||
-       (mode & kApplyToChildContainingLayers)) &&
       mapping->ScrollingLayer())
     f(mapping->ScrollingLayer());
   if (((mode & kApplyToLayersAffectedByPreserve3D) ||
@@ -2292,14 +1626,6 @@
        (mode & kApplyToNonScrollingContentLayers)) &&
       mapping->MaskLayer())
     f(mapping->MaskLayer());
-  if (((mode & kApplyToMaskLayers) || (mode & kApplyToContentLayers) ||
-       (mode & kApplyToNonScrollingContentLayers)) &&
-      mapping->ChildClippingMaskLayer())
-    f(mapping->ChildClippingMaskLayer());
-  if (((mode & kApplyToMaskLayers) || (mode & kApplyToContentLayers) ||
-       (mode & kApplyToNonScrollingContentLayers)) &&
-      mapping->AncestorClippingMaskLayer())
-    f(mapping->AncestorClippingMaskLayer());
 
   if ((mode & kApplyToScrollbarLayers) &&
       mapping->LayerForHorizontalScrollbar())
@@ -2365,8 +1691,6 @@
   if (GraphicsLayer* layer = ScrollingLayer())
     layer->SetShouldFlattenTransform(false);
   graphics_layer_->SetShouldFlattenTransform(is_flat && !HasScrollingLayer());
-  if (GraphicsLayer* layer = ClippingLayer())
-    layer->SetShouldFlattenTransform(is_flat && !HasChildTransformLayer());
   if (GraphicsLayer* layer = ScrollingContentsLayer())
     layer->SetShouldFlattenTransform(is_flat && !HasChildTransformLayer());
   if (GraphicsLayer* layer = ForegroundLayer())
@@ -2454,22 +1778,6 @@
   return layer_changed;
 }
 
-bool CompositedLayerMapping::UpdateChildClippingMaskLayer(
-    bool needs_child_clipping_mask_layer) {
-  if (needs_child_clipping_mask_layer && !child_clipping_mask_layer_) {
-    child_clipping_mask_layer_ =
-        CreateGraphicsLayer(CompositingReason::kLayerForClippingMask);
-    child_clipping_mask_layer_->SetPaintingPhase(
-        kGraphicsLayerPaintChildClippingMask);
-    return true;
-  }
-  if (!needs_child_clipping_mask_layer && child_clipping_mask_layer_) {
-    child_clipping_mask_layer_ = nullptr;
-    return true;
-  }
-  return false;
-}
-
 bool CompositedLayerMapping::UpdateScrollingLayers(
     bool needs_scrolling_layers) {
   ScrollingCoordinator* scrolling_coordinator =
@@ -2481,16 +1789,7 @@
 
   bool layer_changed = false;
   if (needs_scrolling_layers) {
-    if (scrolling_layer_) {
-      // When blink generates property trees, the user input scrollable bits are
-      // stored on scroll nodes instead of layers so there is no need to update
-      // them here.
-      if (scrolling_coordinator &&
-          !RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-        scrolling_coordinator->UpdateUserInputScrollable(
-            owning_layer_.GetScrollableArea());
-      }
-    } else {
+    if (!scrolling_layer_) {
       // Outer layer which corresponds with the scroll view.
       scrolling_layer_ =
           CreateGraphicsLayer(CompositingReason::kLayerForScrollingContainer);
@@ -2558,9 +1857,6 @@
     UpdateScrollParentForGraphicsLayer(squashing_containment_layer_.get(),
                                        topmost_layer, scroll_parent,
                                        scrolling_coordinator);
-    UpdateScrollParentForGraphicsLayer(ancestor_clipping_layer_.get(),
-                                       topmost_layer, scroll_parent,
-                                       scrolling_coordinator);
     UpdateScrollParentForGraphicsLayer(graphics_layer_.get(), topmost_layer,
                                        scroll_parent, scrolling_coordinator);
   }
@@ -2591,64 +1887,11 @@
     UpdateClipParentForGraphicsLayer(squashing_containment_layer_.get(),
                                      topmost_layer, clip_parent,
                                      scrolling_coordinator);
-    UpdateClipParentForGraphicsLayer(ancestor_clipping_layer_.get(),
-                                     topmost_layer, clip_parent,
-                                     scrolling_coordinator);
     UpdateClipParentForGraphicsLayer(graphics_layer_.get(), topmost_layer,
                                      clip_parent, scrolling_coordinator);
   }
 }
 
-void CompositedLayerMapping::RegisterScrollingLayers() {
-  // Register fixed position layers and their containers with the scrolling
-  // coordinator.
-  ScrollingCoordinator* scrolling_coordinator =
-      owning_layer_.GetScrollingCoordinator();
-  if (!scrolling_coordinator)
-    return;
-
-  // When blink generates property trees, the layer position constraints are
-  // not set on cc::Layer because they are only used by the cc property tree
-  // builder.
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
-      !RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-    scrolling_coordinator->UpdateLayerPositionConstraint(&owning_layer_);
-  }
-
-  bool is_fixed_container =
-      owning_layer_.GetLayoutObject().CanContainFixedPositionObjects();
-  bool resized_by_url_bar =
-      owning_layer_.GetLayoutObject().IsLayoutView() &&
-      owning_layer_.Compositor()->IsRootScrollerAncestor();
-  // These values are only used by the cc property tree builder and are not
-  // needed when blink generates property trees.
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
-      !RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-    graphics_layer_->SetIsContainerForFixedPositionLayers(is_fixed_container);
-    graphics_layer_->SetIsResizedByBrowserControls(resized_by_url_bar);
-  }
-  // Fixed-pos descendants inherits the space that has all CSS property applied,
-  // including perspective, overflow scroll/clip. Thus we also mark every layers
-  // below the main graphics layer so transforms implemented by them don't get
-  // skipped.
-  ApplyToGraphicsLayers(
-      this,
-      [is_fixed_container, resized_by_url_bar](GraphicsLayer* layer) {
-        // These values are only used by the cc property tree builder and are
-        // not needed when blink generates property trees.
-        if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
-            !RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-          layer->SetIsContainerForFixedPositionLayers(is_fixed_container);
-          layer->SetIsResizedByBrowserControls(resized_by_url_bar);
-        }
-        // TODO(pdr): This prevents clipping and should not be needed, but
-        // CaptureScreenshotTest.CaptureScreenshotArea depends on this.
-        if (resized_by_url_bar)
-          layer->SetMasksToBounds(false);
-      },
-      kApplyToChildContainingLayers);
-}
-
 bool CompositedLayerMapping::UpdateSquashingLayers(
     bool needs_squashing_layers) {
   bool layers_changed = false;
@@ -2661,24 +1904,12 @@
       squashing_layer_->SetHitTestable(true);
       layers_changed = true;
     }
-
-    if (ancestor_clipping_layer_) {
-      if (squashing_containment_layer_) {
-        squashing_containment_layer_->RemoveFromParent();
-        squashing_containment_layer_ = nullptr;
-        layers_changed = true;
-      }
-    } else {
-      if (!squashing_containment_layer_) {
-        squashing_containment_layer_ =
-            CreateGraphicsLayer(CompositingReason::kLayerForSquashingContainer);
-        squashing_containment_layer_->SetShouldFlattenTransform(false);
-        layers_changed = true;
-      }
+    if (!squashing_containment_layer_) {
+      squashing_containment_layer_ =
+          CreateGraphicsLayer(CompositingReason::kLayerForSquashingContainer);
+      squashing_containment_layer_->SetShouldFlattenTransform(false);
+      layers_changed = true;
     }
-
-    DCHECK((ancestor_clipping_layer_ && !squashing_containment_layer_) ||
-           (!ancestor_clipping_layer_ && squashing_containment_layer_));
     DCHECK(squashing_layer_);
   } else {
     if (squashing_layer_) {
@@ -2968,11 +2199,8 @@
 }
 
 GraphicsLayer* CompositedLayerMapping::DetachLayerForOverflowControls() {
-  GraphicsLayer* host = overflow_controls_ancestor_clipping_layer_.get();
-  if (!host)
-    host = overflow_controls_host_layer_.get();
-  host->RemoveFromParent();
-  return host;
+  overflow_controls_host_layer_->RemoveFromParent();
+  return overflow_controls_host_layer_.get();
 }
 
 GraphicsLayer* CompositedLayerMapping::DetachLayerForDecorationOutline() {
@@ -2986,9 +2214,6 @@
   if (scrolling_contents_layer_)
     return scrolling_contents_layer_.get();
 
-  if (child_containment_layer_)
-    return child_containment_layer_.get();
-
   if (child_transform_layer_)
     return child_transform_layer_.get();
 
@@ -2998,9 +2223,7 @@
 void CompositedLayerMapping::SetSublayers(
     const GraphicsLayerVector& sublayers) {
   GraphicsLayer* overflow_controls_container =
-      overflow_controls_ancestor_clipping_layer_
-          ? overflow_controls_ancestor_clipping_layer_.get()
-          : overflow_controls_host_layer_.get();
+      overflow_controls_host_layer_.get();
   GraphicsLayer* parent = ParentForSublayers();
   bool needs_overflow_controls_reattached =
       overflow_controls_container &&
@@ -3020,19 +2243,11 @@
   if (squashing_containment_layer_)
     return squashing_containment_layer_.get();
 
-  if (ancestor_clipping_layer_)
-    return ancestor_clipping_layer_.get();
-
   return graphics_layer_.get();
 }
 
 void CompositedLayerMapping::SetBlendMode(BlendMode blend_mode) {
-  if (ancestor_clipping_layer_) {
-    ancestor_clipping_layer_->SetBlendMode(blend_mode);
-    graphics_layer_->SetBlendMode(BlendMode::kNormal);
-  } else {
-    graphics_layer_->SetBlendMode(blend_mode);
-  }
+  graphics_layer_->SetBlendMode(blend_mode);
 }
 
 GraphicsLayerUpdater::UpdateType CompositedLayerMapping::UpdateTypeForChildren(
@@ -3150,8 +2365,7 @@
   IntRect dirty_rect(clip);
   dirty_rect.Move(offset);
 
-  if (paint_layer_flags & (kPaintLayerPaintingOverflowContents |
-                           kPaintLayerPaintingAncestorClippingMaskPhase)) {
+  if (paint_layer_flags & (kPaintLayerPaintingOverflowContents)) {
     dirty_rect.MoveBy(
         RoundedIntPoint(paint_info.paint_layer->SubpixelAccumulation()));
   } else {
@@ -3442,10 +2656,6 @@
     paint_layer_flags |= kPaintLayerPaintingCompositingForegroundPhase;
   if (graphics_layer_painting_phase & kGraphicsLayerPaintMask)
     paint_layer_flags |= kPaintLayerPaintingCompositingMaskPhase;
-  if (graphics_layer_painting_phase & kGraphicsLayerPaintChildClippingMask)
-    paint_layer_flags |= kPaintLayerPaintingChildClippingMaskPhase;
-  if (graphics_layer_painting_phase & kGraphicsLayerPaintAncestorClippingMask)
-    paint_layer_flags |= kPaintLayerPaintingAncestorClippingMaskPhase;
   if (graphics_layer_painting_phase & kGraphicsLayerPaintOverflowContents)
     paint_layer_flags |= kPaintLayerPaintingOverflowContents;
   if (graphics_layer_painting_phase & kGraphicsLayerPaintCompositedScroll)
@@ -3456,10 +2666,8 @@
   if (graphics_layer == graphics_layer_.get() ||
       graphics_layer == foreground_layer_.get() ||
       graphics_layer == mask_layer_.get() ||
-      graphics_layer == child_clipping_mask_layer_.get() ||
       graphics_layer == scrolling_contents_layer_.get() ||
-      graphics_layer == decoration_outline_layer_.get() ||
-      graphics_layer == ancestor_clipping_mask_layer_.get()) {
+      graphics_layer == decoration_outline_layer_.get()) {
     if (background_paints_onto_scrolling_contents_layer_) {
       if (graphics_layer == scrolling_contents_layer_.get())
         paint_layer_flags &= ~kPaintLayerPaintingSkipRootBackground;
@@ -3488,11 +2696,6 @@
     PaintScrollableArea(graphics_layer, context, interest_rect);
   }
 
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-    probe::DidPaint(owning_layer_.GetLayoutObject().GetFrame(),
-                    graphics_layer->CcLayer(), LayoutRect(interest_rect));
-  }
-
 #if DCHECK_IS_ON()
   if (Page* page = GetLayoutObject().GetFrame()->GetPage())
     page->SetIsPainting(false);
@@ -3729,20 +2932,12 @@
                 ? squashed_layers_[0].paint_layer->DebugName()
                 : "") +
            ")";
-  } else if (graphics_layer == ancestor_clipping_layer_.get()) {
-    name = "Ancestor Clipping Layer";
-  } else if (graphics_layer == ancestor_clipping_mask_layer_.get()) {
-    name = "Ancestor Clipping Mask Layer";
   } else if (graphics_layer == foreground_layer_.get()) {
     name = owning_layer_.DebugName() + " (foreground) Layer";
-  } else if (graphics_layer == child_containment_layer_.get()) {
-    name = "Child Containment Layer";
   } else if (graphics_layer == child_transform_layer_.get()) {
     name = "Child Transform Layer";
   } else if (graphics_layer == mask_layer_.get()) {
     name = "Mask Layer";
-  } else if (graphics_layer == child_clipping_mask_layer_.get()) {
-    name = "Child Clipping Mask Layer";
   } else if (graphics_layer == layer_for_horizontal_scrollbar_.get()) {
     name = "Horizontal Scrollbar Layer";
   } else if (graphics_layer == layer_for_vertical_scrollbar_.get()) {
@@ -3751,9 +2946,6 @@
     name = "Scroll Corner Layer";
   } else if (graphics_layer == overflow_controls_host_layer_.get()) {
     name = "Overflow Controls Host Layer";
-  } else if (graphics_layer ==
-             overflow_controls_ancestor_clipping_layer_.get()) {
-    name = "Overflow Controls Ancestor Clipping Layer";
   } else if (graphics_layer == scrolling_layer_.get()) {
     name = "Scrolling Layer";
   } else if (graphics_layer == scrolling_contents_layer_.get()) {
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h
index ca63283..863c409 100644
--- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h
+++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h
@@ -115,24 +115,6 @@
 
   GraphicsLayer* MainGraphicsLayer() const { return graphics_layer_.get(); }
 
-  // Layer to clip children
-  bool HasClippingLayer() const { return child_containment_layer_.get(); }
-  GraphicsLayer* ClippingLayer() const {
-    return child_containment_layer_.get();
-  }
-
-  // Layer to get clipped by ancestor
-  bool HasAncestorClippingLayer() const {
-    return ancestor_clipping_layer_.get();
-  }
-  GraphicsLayer* AncestorClippingLayer() const {
-    return ancestor_clipping_layer_.get();
-  }
-
-  GraphicsLayer* AncestorClippingMaskLayer() const {
-    return ancestor_clipping_mask_layer_.get();
-  }
-
   GraphicsLayer* ForegroundLayer() const { return foreground_layer_.get(); }
 
   GraphicsLayer* DecorationOutlineLayer() const {
@@ -148,13 +130,6 @@
   bool HasMaskLayer() const { return mask_layer_.get(); }
   GraphicsLayer* MaskLayer() const { return mask_layer_.get(); }
 
-  bool HasChildClippingMaskLayer() const {
-    return child_clipping_mask_layer_.get();
-  }
-  GraphicsLayer* ChildClippingMaskLayer() const {
-    return child_clipping_mask_layer_.get();
-  }
-
   GraphicsLayer* ParentForSublayers() const;
   GraphicsLayer* ChildForSuperlayers() const;
   void SetSublayers(const GraphicsLayerVector&);
@@ -253,7 +228,6 @@
   // We may similarly need to reattach the layer for outlines and decorations.
   GraphicsLayer* DetachLayerForDecorationOutline();
 
-  void UpdateFilters();
   void UpdateBackdropFilters();
 
   void SetBlendMode(BlendMode);
@@ -318,15 +292,6 @@
     return draws_background_onto_content_layer_;
   }
 
-  // Returns the PaintLayer which establishes the clip state that
-  // MainGraphicsLayer will inherit from the composited layer hierarchy, after
-  // taking scroll parent and clip parent into consideration. The clip state can
-  // be different from the inherited clip state as defined by CSS spec.
-  // Those differences then need to be applied by AncestorClippingLayer.
-  const PaintLayer* ClipInheritanceAncestor() const {
-    return clip_inheritance_ancestor_;
-  }
-
  private:
   IntRect RecomputeInterestRect(const GraphicsLayer*) const;
   static bool InterestRectChangedEnoughToRepaint(
@@ -363,15 +328,10 @@
       const IntRect& local_compositing_bounds,
       const IntPoint& graphics_layer_parent_location,
       GraphicsLayerUpdater::UpdateContext& update_context);
-  void UpdateAncestorClippingLayerGeometry(
-      const PaintLayer* compositing_container,
-      const IntPoint& snapped_offset_from_composited_ancestor,
-      IntPoint& graphics_layer_parent_location);
   void UpdateOverflowControlsHostLayerGeometry(
       const PaintLayer* compositing_stacking_context,
       const PaintLayer* compositing_container,
       IntPoint graphics_layer_parent_location);
-  void UpdateChildContainmentLayerGeometry();
   void UpdateChildTransformLayerGeometry();
   void UpdateMaskLayerGeometry();
   void UpdateTransformGeometry(
@@ -381,8 +341,6 @@
   void UpdateDecorationOutlineLayerGeometry(
       const IntSize& relative_compositing_bounds_size);
   void UpdateScrollingLayerGeometry(const IntRect& local_compositing_bounds);
-  void UpdateChildClippingMaskLayerGeometry();
-  void UpdateStickyConstraints(const ComputedStyle&);
 
   void CreatePrimaryGraphicsLayer();
   void DestroyGraphicsLayers();
@@ -403,20 +361,13 @@
 
   void UpdateInternalHierarchy();
   void UpdatePaintingPhases();
-  bool UpdateClippingLayers(bool needs_ancestor_clip,
-                            bool needs_descendant_clip);
-  bool UpdateClippingLayers(bool needs_ancestor_clip,
-                            bool needs_ancestor_clipping_mask,
-                            bool needs_descendant_clip);
   bool UpdateChildTransformLayer(bool needs_child_transform_layer);
   bool UpdateOverflowControlsLayers(bool needs_horizontal_scrollbar_layer,
                                     bool needs_vertical_scrollbar_layer,
-                                    bool needs_scroll_corner_layer,
-                                    bool needs_ancestor_clip);
+                                    bool needs_scroll_corner_layer);
   bool UpdateForegroundLayer(bool needs_foreground_layer);
   bool UpdateDecorationOutlineLayer(bool needs_decoration_outline_layer);
   bool UpdateMaskLayer(bool needs_mask_layer);
-  bool UpdateChildClippingMaskLayer(bool needs_child_clipping_mask_layer);
   bool RequiresHorizontalScrollbarLayer() const;
   bool RequiresVerticalScrollbarLayer() const;
   bool RequiresScrollCornerLayer() const;
@@ -427,9 +378,7 @@
   void UpdateDrawsContentAndPaintsHitTest();
   void UpdateChildrenTransform();
   void UpdateCompositedBounds();
-  void UpdateOverscrollBehavior();
   void UpdateSnapContainerData();
-  void RegisterScrollingLayers();
 
   // Also sets subpixelAccumulation on the layer.
   void ComputeBoundsOfOwningLayer(
@@ -480,38 +429,11 @@
   // contains this squashed layer's clipping ancestor.  The clip rect is
   // returned in the coordinate space of the given squashed layer.  If there is
   // no such containing layer, returns the infinite rect.
-  // FIXME: unify this code with the code that sets up ancestor_clipping_layer_.
-  // They are doing very similar things.
   static void LocalClipRectForSquashedLayer(
       const PaintLayer& reference_layer,
       const Vector<GraphicsLayerPaintInfo>& layers,
       GraphicsLayerPaintInfo&);
 
-  // Conservatively check whether there exists any border-radius clip that
-  // must be applied by an ancestor clipping mask layer. There are two inputs
-  // to this function: the bounds of contents that are going to be clipped
-  // by ancestor clipping layer, and the compositing ancestor which we are
-  // going to inherit clip state from.
-  // The function works by collecting all border-radius clips between the
-  // current layer and the inherited clip, i.e. those are the clips that are
-  // going to be applied by the ancestor clipping mask layer. A fast
-  // approximation test is used to determine whether the contents exceed
-  // the bounds of any of the clips. The function may return false positive
-  // (apply mask layer when not strictly needed), but never false negative,
-  // as its purpose is only for optimization.
-  bool AncestorRoundedCornersWillClip(
-      const FloatRect& bounds_in_ancestor_space) const;
-
-  // Return true in |owningLayerIsClipped| iff there is any clip in between
-  // the current layer and the inherited clip state. The inherited clip state
-  // is determined by the interoperation between compositing container, clip
-  // parent, and scroll parent.
-  // Return true in |owningLayerIsMasked| iff |owningLayerIsClipped| is true
-  // and any of the clip needs to be applied as a painted mask.
-  void OwningLayerClippedOrMaskedByLayerNotAboveCompositedAncestor(
-      bool& owning_layer_is_clipped,
-      bool& owning_layer_is_masked) const;
-
   const PaintLayer* ScrollParent() const;
   const PaintLayer* CompositedClipParent() const;
   void UpdateClipInheritanceAncestor(const PaintLayer* compositing_container);
@@ -528,13 +450,9 @@
   // The hierarchy of layers that is maintained by the CompositedLayerMapping
   // looks like this:
   //
-  //  + ancestor_clipping_layer_ [OPTIONAL]
   //    + graphics_layer_
   //      + child_transform_layer_ [OPTIONAL]
-  //      | + child_containment_layer_ [OPTIONAL]
-  //      |   <-OR->
   //      |   (scrolling_layer_ + scrolling_contents_layer_) [OPTIONAL]
-  //      + overflow_controls_ancestor_clipping_layer_ [OPTIONAL]
   //      | + overflow_controls_host_layer_ [OPTIONAL]
   //      |   + layer_for_vertical_scrollbar_ [OPTIONAL]
   //      |   + layer_for_horizontal_scrollbar_ [OPTIONAL]
@@ -542,48 +460,9 @@
   //      + decoration_outline_layer_ [OPTIONAL]
   // The overflow controls may need to be repositioned in the graphics layer
   // tree by the RLC to ensure that they stack above scrolling content.
-  //
-  // We need an ancestor clipping layer if our clipping ancestor is not our
-  // ancestor in the clipping tree. Here's what that might look like.
-  //
-  // Let A = the clipping ancestor,
-  //     B = the clip descendant, and
-  //     SC = the stacking context that is the ancestor of A and B in the
-  //          stacking tree.
-  //
-  // SC
-  //  + A = graphics_layer_
-  //  |  + child_containment_layer_
-  //  |     + ...
-  //  ...
-  //  |
-  //  + B = ancestor_clipping_layer_ [+]
-  //     + graphics_layer_
-  //        + ...
-  //
-  // In this case B is clipped by another layer that doesn't happen to be its
-  // ancestor: A.  So we create an ancestor clipping layer for B, [+], which
-  // ensures that B is clipped as if it had been A's descendant.
-  // In addition, the ancestor_clipping_layer_ will have an associated
-  // mask layer if the ancestor, A, has a border radius that requires a
-  // rounded corner clip rect. The mask is not part of the layer tree; rather
-  // it is attached to the ancestor_clipping_layer_ itself.
-  //
-  // Layers that require a CSS mask also have a mask layer attached to them.
-
-  // Only used if we are clipped by an ancestor which is not a stacking context.
-  std::unique_ptr<GraphicsLayer> ancestor_clipping_layer_;
-
-  // Only used is there is an ancestor_clipping_layer_ that also needs to apply
-  // a clipping mask (for CSS clips or border radius).
-  std::unique_ptr<GraphicsLayer> ancestor_clipping_mask_layer_;
 
   std::unique_ptr<GraphicsLayer> graphics_layer_;
 
-  // Only used if we have clipping on a stacking context with compositing
-  // children.
-  std::unique_ptr<GraphicsLayer> child_containment_layer_;
-
   // Only used if we have perspective.
   std::unique_ptr<GraphicsLayer> child_transform_layer_;
 
@@ -600,10 +479,6 @@
   // Only used if we have a mask.
   std::unique_ptr<GraphicsLayer> mask_layer_;
 
-  // Only used if we have to clip child layers or accelerated contents with
-  // border radius or clip-path.
-  std::unique_ptr<GraphicsLayer> child_clipping_mask_layer_;
-
   // There is one other (optional) layer whose painting is managed by the
   // CompositedLayerMapping, but whose position in the hierarchy is maintained
   // by the PaintLayerCompositor. This is the foreground layer. The foreground
@@ -626,41 +501,21 @@
   // ensure that scrollbars appear above scrolling content.
   std::unique_ptr<GraphicsLayer> overflow_controls_host_layer_;
 
-  // The reparented overflow controls sometimes need to be clipped by a
-  // non-ancestor. In just the same way we need an ancestor clipping layer to
-  // clip this CLM's internal hierarchy, we add another layer to clip the
-  // overflow controls. We could combine this with
-  // overflow_controls_host_layer_, but that would require manually intersecting
-  // their clips, and shifting the overflow controls to compensate for this
-  // clip's offset. By using a separate layer, the overflow controls can remain
-  // ignorant of ancestor clipping.
-  std::unique_ptr<GraphicsLayer> overflow_controls_ancestor_clipping_layer_;
-
   // DecorationLayer which paints outline.
   std::unique_ptr<GraphicsLayer> decoration_outline_layer_;
 
-  // A squashing CLM has two possible squashing-related structures.
-  //
-  // If ancestor_clipping_layer_ is present:
-  //
-  // ancestor_clipping_layer_
-  //   + graphics_layer_
-  //   + squashing_layer_
-  //
-  // If not:
-  //
+  // A squashing CLM has the following structure:
   // squashing_containment_layer_
   //   + graphics_layer_
   //   + squashing_layer_
   //
   // Stacking children of a squashed layer receive graphics layers that are
-  // parented to the compositd ancestor of the squashed layer (i.e. nearest
+  // parented to the composited ancestor of the squashed layer (i.e. nearest
   // enclosing composited layer that is not
   // squashed).
 
-  // Only used if any squashed layers exist and ancestor_clipping_layer_ is
-  // not present, to contain the squashed layers as siblings to the rest of the
-  // GraphicsLayer tree chunk.
+  // Only used if any squashed layers exist, this contains the squashed layers
+  // as siblings to the rest of the GraphicsLayer tree chunk.
   std::unique_ptr<GraphicsLayer> squashing_containment_layer_;
 
   // Only used if any squashed layers exist, this is the backing that squashed
@@ -677,8 +532,6 @@
   // TODO(bokan): scrolling_contents_offset_ can be removed when BGPT ships.
   DoubleSize scrolling_contents_offset_;
 
-  const PaintLayer* clip_inheritance_ancestor_;
-
   unsigned pending_update_scope_ : 2;
   unsigned is_main_frame_layout_view_layer_ : 1;
 
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc
index 5a791c2..95e7e53 100644
--- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc
+++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc
@@ -56,17 +56,6 @@
   }
 };
 
-// Tests the pre-BlinkGenPropertyTrees composited layer mapping code. With BGPT,
-// some layer updates are skipped (see: CLM::UpdateGraphicsLayerConfiguration
-// and CLM::UpdateStickyConstraints).
-class CompositedLayerMappingTestWithoutBGPT
-    : private ScopedBlinkGenPropertyTreesForTest,
-      public CompositedLayerMappingTest {
- public:
-  CompositedLayerMappingTestWithoutBGPT()
-      : ScopedBlinkGenPropertyTreesForTest(false) {}
-};
-
 TEST_F(CompositedLayerMappingTest, SubpixelAccumulationChange) {
   SetBodyInnerHTML(
       "<div id='target' style='will-change: transform; background: lightblue; "
@@ -511,45 +500,6 @@
             RecomputeInterestRect(paint_layer->GraphicsLayerBacking()));
 }
 
-TEST_F(CompositedLayerMappingTestWithoutBGPT, ClippingMaskLayer) {
-  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
-    return;
-
-  const AtomicString style_without_clipping =
-      "backface-visibility: hidden; width: 200px; height: 200px";
-  const AtomicString style_with_border_radius =
-      style_without_clipping + "; border-radius: 10px";
-  const AtomicString style_with_clip_path =
-      style_without_clipping + "; -webkit-clip-path: inset(10px)";
-
-  SetBodyInnerHTML("<video id='video' src='x' style='" +
-                   style_without_clipping + "'></video>");
-
-  UpdateAllLifecyclePhasesForTest();
-  Element* video_element = GetDocument().getElementById("video");
-  GraphicsLayer* graphics_layer =
-      ToLayoutBoxModelObject(video_element->GetLayoutObject())
-          ->Layer()
-          ->GraphicsLayerBacking();
-  EXPECT_FALSE(graphics_layer->MaskLayer());
-  EXPECT_FALSE(graphics_layer->ContentsClippingMaskLayer());
-
-  video_element->setAttribute(html_names::kStyleAttr, style_with_border_radius);
-  UpdateAllLifecyclePhasesForTest();
-  EXPECT_FALSE(graphics_layer->MaskLayer());
-  EXPECT_TRUE(graphics_layer->ContentsClippingMaskLayer());
-
-  video_element->setAttribute(html_names::kStyleAttr, style_with_clip_path);
-  UpdateAllLifecyclePhasesForTest();
-  EXPECT_TRUE(graphics_layer->MaskLayer());
-  EXPECT_FALSE(graphics_layer->ContentsClippingMaskLayer());
-
-  video_element->setAttribute(html_names::kStyleAttr, style_without_clipping);
-  UpdateAllLifecyclePhasesForTest();
-  EXPECT_FALSE(graphics_layer->MaskLayer());
-  EXPECT_FALSE(graphics_layer->ContentsClippingMaskLayer());
-}
-
 TEST_F(CompositedLayerMappingTest, ScrollContentsFlattenForScroller) {
   SetBodyInnerHTML(R"HTML(
     <style>div::-webkit-scrollbar{ width: 5px; }</style>
@@ -1291,927 +1241,6 @@
   EXPECT_FLOAT_EQ(10, scrolling_layer2->GetPosition().y());
 }
 
-TEST_F(CompositedLayerMappingTestWithoutBGPT,
-       AncestorClippingMaskLayerUpdates) {
-  SetBodyInnerHTML(R"HTML(
-    <style>
-      #ancestor { width: 100px; height: 100px; overflow: hidden; }
-      #child { width: 120px; height: 120px; background-color: green; }
-    </style>
-    <div id='ancestor'>
-      <div id='child'></div>
-    </div>
-  )HTML");
-  UpdateAllLifecyclePhasesForTest();
-
-  Element* ancestor = GetDocument().getElementById("ancestor");
-  ASSERT_TRUE(ancestor);
-  PaintLayer* ancestor_paint_layer =
-      ToLayoutBoxModelObject(ancestor->GetLayoutObject())->Layer();
-  ASSERT_TRUE(ancestor_paint_layer);
-
-  CompositedLayerMapping* ancestor_mapping =
-      ancestor_paint_layer->GetCompositedLayerMapping();
-  ASSERT_FALSE(ancestor_mapping);
-
-  Element* child = GetDocument().getElementById("child");
-  ASSERT_TRUE(child);
-  PaintLayer* child_paint_layer =
-      ToLayoutBoxModelObject(child->GetLayoutObject())->Layer();
-  ASSERT_FALSE(child_paint_layer);
-
-  // Making the child conposited causes creation of an AncestorClippingLayer.
-  child->setAttribute(html_names::kStyleAttr, "will-change: transform");
-  UpdateAllLifecyclePhasesForTest();
-  child_paint_layer = ToLayoutBoxModelObject(child->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child_paint_layer);
-  CompositedLayerMapping* child_mapping =
-      child_paint_layer->GetCompositedLayerMapping();
-  ASSERT_TRUE(child_mapping);
-  EXPECT_TRUE(child_mapping->AncestorClippingLayer());
-  EXPECT_FALSE(child_mapping->AncestorClippingLayer()->MaskLayer());
-  EXPECT_FALSE(child_mapping->AncestorClippingMaskLayer());
-
-  // Adding border radius to the ancestor requires an
-  // ancestorClippingMaskLayer for the child
-  ancestor->setAttribute(html_names::kStyleAttr, "border-radius: 40px;");
-  UpdateAllLifecyclePhasesForTest();
-  child_paint_layer = ToLayoutBoxModelObject(child->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child_paint_layer);
-  child_mapping = child_paint_layer->GetCompositedLayerMapping();
-  ASSERT_TRUE(child_mapping);
-  EXPECT_TRUE(child_mapping->AncestorClippingLayer());
-  EXPECT_TRUE(child_mapping->AncestorClippingLayer()->MaskLayer());
-  EXPECT_TRUE(child_mapping->AncestorClippingMaskLayer());
-
-  // Removing the border radius should remove the ancestorClippingMaskLayer
-  // for the child
-  ancestor->setAttribute(html_names::kStyleAttr, "border-radius: 0px;");
-  UpdateAllLifecyclePhasesForTest();
-  child_paint_layer = ToLayoutBoxModelObject(child->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child_paint_layer);
-  child_mapping = child_paint_layer->GetCompositedLayerMapping();
-  ASSERT_TRUE(child_mapping);
-  EXPECT_TRUE(child_mapping->AncestorClippingLayer());
-  EXPECT_FALSE(child_mapping->AncestorClippingLayer()->MaskLayer());
-  EXPECT_FALSE(child_mapping->AncestorClippingMaskLayer());
-
-  // Add border radius back so we can test one more case
-  ancestor->setAttribute(html_names::kStyleAttr, "border-radius: 40px;");
-  UpdateAllLifecyclePhasesForTest();
-
-  // Now change the overflow to remove the need for an ancestor clip
-  // on the child
-  ancestor->setAttribute(html_names::kStyleAttr, "overflow: visible");
-  UpdateAllLifecyclePhasesForTest();
-  child_paint_layer = ToLayoutBoxModelObject(child->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child_paint_layer);
-  child_mapping = child_paint_layer->GetCompositedLayerMapping();
-  ASSERT_TRUE(child_mapping);
-  EXPECT_FALSE(child_mapping->AncestorClippingLayer());
-  EXPECT_FALSE(child_mapping->AncestorClippingMaskLayer());
-}
-
-TEST_F(CompositedLayerMappingTestWithoutBGPT,
-       AncestorClippingMaskLayerSiblingUpdates) {
-  SetBodyInnerHTML(R"HTML(
-    <style>
-      #ancestor { width: 200px; height: 200px; overflow: hidden; }
-      #child1 { width: 10px;; height: 260px; position: relative;
-                left: 0px; top: -30px; background-color: green; }
-      #child2 { width: 10px;; height: 260px; position: relative;
-                left: 190px; top: -260px; background-color: green; }
-    </style>
-    <div id='ancestor'>
-      <div id='child1'></div>
-      <div id='child2'></div>
-    </div>
-  )HTML");
-  UpdateAllLifecyclePhasesForTest();
-
-  Element* ancestor = GetDocument().getElementById("ancestor");
-  ASSERT_TRUE(ancestor);
-  PaintLayer* ancestor_paint_layer =
-      ToLayoutBoxModelObject(ancestor->GetLayoutObject())->Layer();
-  ASSERT_TRUE(ancestor_paint_layer);
-
-  CompositedLayerMapping* ancestor_mapping =
-      ancestor_paint_layer->GetCompositedLayerMapping();
-  ASSERT_FALSE(ancestor_mapping);
-
-  Element* child1 = GetDocument().getElementById("child1");
-  ASSERT_TRUE(child1);
-  PaintLayer* child1_paint_layer =
-      ToLayoutBoxModelObject(child1->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child1_paint_layer);
-  CompositedLayerMapping* child1_mapping =
-      child1_paint_layer->GetCompositedLayerMapping();
-  ASSERT_FALSE(child1_mapping);
-
-  Element* child2 = GetDocument().getElementById("child2");
-  ASSERT_TRUE(child2);
-  PaintLayer* child2_paint_layer =
-      ToLayoutBoxModelObject(child2->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child2_paint_layer);
-  CompositedLayerMapping* child2_mapping =
-      child2_paint_layer->GetCompositedLayerMapping();
-  ASSERT_FALSE(child2_mapping);
-
-  // Making child1 composited causes creation of an AncestorClippingLayer.
-  child1->setAttribute(html_names::kStyleAttr, "will-change: transform");
-  UpdateAllLifecyclePhasesForTest();
-  child1_paint_layer =
-      ToLayoutBoxModelObject(child1->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child1_paint_layer);
-  child1_mapping = child1_paint_layer->GetCompositedLayerMapping();
-  ASSERT_TRUE(child1_mapping);
-  EXPECT_TRUE(child1_mapping->AncestorClippingLayer());
-  EXPECT_FALSE(child1_mapping->AncestorClippingLayer()->MaskLayer());
-  EXPECT_FALSE(child1_mapping->AncestorClippingMaskLayer());
-  child2_paint_layer =
-      ToLayoutBoxModelObject(child2->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child2_paint_layer);
-  child2_mapping = child2_paint_layer->GetCompositedLayerMapping();
-  ASSERT_FALSE(child2_mapping);
-
-  // Adding border radius to the ancestor requires an
-  // ancestorClippingMaskLayer for child1
-  ancestor->setAttribute(html_names::kStyleAttr, "border-radius: 40px;");
-  UpdateAllLifecyclePhasesForTest();
-  child1_paint_layer =
-      ToLayoutBoxModelObject(child1->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child1_paint_layer);
-  child1_mapping = child1_paint_layer->GetCompositedLayerMapping();
-  ASSERT_TRUE(child1_mapping);
-  EXPECT_TRUE(child1_mapping->AncestorClippingLayer());
-  EXPECT_TRUE(child1_mapping->AncestorClippingLayer()->MaskLayer());
-  EXPECT_TRUE(child1_mapping->AncestorClippingMaskLayer());
-  child2_paint_layer =
-      ToLayoutBoxModelObject(child2->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child2_paint_layer);
-  child2_mapping = child2_paint_layer->GetCompositedLayerMapping();
-  ASSERT_FALSE(child2_mapping);
-
-  // Making child2 composited causes creation of an AncestorClippingLayer
-  // and a mask layer.
-  child2->setAttribute(html_names::kStyleAttr, "will-change: transform");
-  UpdateAllLifecyclePhasesForTest();
-  child1_paint_layer =
-      ToLayoutBoxModelObject(child1->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child1_paint_layer);
-  child1_mapping = child1_paint_layer->GetCompositedLayerMapping();
-  ASSERT_TRUE(child1_mapping);
-  ASSERT_TRUE(child1_mapping->AncestorClippingLayer());
-  EXPECT_TRUE(child1_mapping->AncestorClippingLayer()->MaskLayer());
-  EXPECT_TRUE(child1_mapping->AncestorClippingMaskLayer());
-  child2_paint_layer =
-      ToLayoutBoxModelObject(child2->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child2_paint_layer);
-  child2_mapping = child2_paint_layer->GetCompositedLayerMapping();
-  ASSERT_TRUE(child2_mapping);
-  ASSERT_TRUE(child2_mapping->AncestorClippingLayer());
-  EXPECT_TRUE(child2_mapping->AncestorClippingLayer()->MaskLayer());
-  EXPECT_TRUE(child2_mapping->AncestorClippingMaskLayer());
-
-  // Removing will-change: transform on child1 should result in the removal
-  // of all clipping and masking layers
-  child1->setAttribute(html_names::kStyleAttr, "will-change: none");
-  UpdateAllLifecyclePhasesForTest();
-  child1_paint_layer =
-      ToLayoutBoxModelObject(child1->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child1_paint_layer);
-  child1_mapping = child1_paint_layer->GetCompositedLayerMapping();
-  EXPECT_FALSE(child1_mapping);
-  child2_paint_layer =
-      ToLayoutBoxModelObject(child2->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child2_paint_layer);
-  child2_mapping = child2_paint_layer->GetCompositedLayerMapping();
-  ASSERT_TRUE(child2_mapping);
-  ASSERT_TRUE(child2_mapping->AncestorClippingLayer());
-  EXPECT_TRUE(child2_mapping->AncestorClippingLayer()->MaskLayer());
-  EXPECT_TRUE(child2_mapping->AncestorClippingMaskLayer());
-
-  // Now change the overflow to remove the need for an ancestor clip
-  // on the children
-  ancestor->setAttribute(html_names::kStyleAttr, "overflow: visible");
-  UpdateAllLifecyclePhasesForTest();
-  child1_paint_layer =
-      ToLayoutBoxModelObject(child1->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child1_paint_layer);
-  child1_mapping = child1_paint_layer->GetCompositedLayerMapping();
-  EXPECT_FALSE(child1_mapping);
-  child2_paint_layer =
-      ToLayoutBoxModelObject(child2->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child2_paint_layer);
-  child2_mapping = child2_paint_layer->GetCompositedLayerMapping();
-  ASSERT_TRUE(child2_mapping);
-  EXPECT_FALSE(child2_mapping->AncestorClippingLayer());
-  EXPECT_FALSE(child2_mapping->AncestorClippingMaskLayer());
-}
-
-TEST_F(CompositedLayerMappingTestWithoutBGPT,
-       AncestorClippingMaskLayerGrandchildUpdates) {
-  SetBodyInnerHTML(R"HTML(
-    <style>
-      #ancestor { width: 200px; height: 200px; overflow: hidden; }
-      #child { width: 10px;; height: 260px; position: relative;
-               left: 0px; top: -30px; background-color: green; }
-      #grandchild { width: 10px;; height: 260px; position: relative;
-                    left: 190px; top: -30px; background-color: green; }
-    </style>
-    <div id='ancestor'>
-      <div id='child'>
-        <div id='grandchild'></div>
-      </div>
-    </div>
-  )HTML");
-  UpdateAllLifecyclePhasesForTest();
-
-  Element* ancestor = GetDocument().getElementById("ancestor");
-  ASSERT_TRUE(ancestor);
-  PaintLayer* ancestor_paint_layer =
-      ToLayoutBoxModelObject(ancestor->GetLayoutObject())->Layer();
-  ASSERT_TRUE(ancestor_paint_layer);
-
-  CompositedLayerMapping* ancestor_mapping =
-      ancestor_paint_layer->GetCompositedLayerMapping();
-  ASSERT_FALSE(ancestor_mapping);
-
-  Element* child = GetDocument().getElementById("child");
-  ASSERT_TRUE(child);
-  PaintLayer* child_paint_layer =
-      ToLayoutBoxModelObject(child->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child_paint_layer);
-  CompositedLayerMapping* child_mapping =
-      child_paint_layer->GetCompositedLayerMapping();
-  ASSERT_FALSE(child_mapping);
-
-  Element* grandchild = GetDocument().getElementById("grandchild");
-  ASSERT_TRUE(grandchild);
-  PaintLayer* grandchild_paint_layer =
-      ToLayoutBoxModelObject(grandchild->GetLayoutObject())->Layer();
-  ASSERT_TRUE(grandchild_paint_layer);
-  CompositedLayerMapping* grandchild_mapping =
-      grandchild_paint_layer->GetCompositedLayerMapping();
-  ASSERT_FALSE(grandchild_mapping);
-
-  // Making grandchild composited causes creation of an AncestorClippingLayer.
-  grandchild->setAttribute(html_names::kStyleAttr, "will-change: transform");
-  UpdateAllLifecyclePhasesForTest();
-  child_paint_layer = ToLayoutBoxModelObject(child->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child_paint_layer);
-  child_mapping = child_paint_layer->GetCompositedLayerMapping();
-  ASSERT_FALSE(child_mapping);
-  grandchild_paint_layer =
-      ToLayoutBoxModelObject(grandchild->GetLayoutObject())->Layer();
-  ASSERT_TRUE(grandchild_paint_layer);
-  grandchild_mapping = grandchild_paint_layer->GetCompositedLayerMapping();
-  ASSERT_TRUE(grandchild_mapping);
-  EXPECT_TRUE(grandchild_mapping->AncestorClippingLayer());
-  EXPECT_FALSE(grandchild_mapping->AncestorClippingLayer()->MaskLayer());
-  EXPECT_FALSE(grandchild_mapping->AncestorClippingMaskLayer());
-
-  // Adding border radius to the ancestor requires an
-  // ancestorClippingMaskLayer for grandchild
-  ancestor->setAttribute(html_names::kStyleAttr, "border-radius: 40px;");
-  UpdateAllLifecyclePhasesForTest();
-  child_paint_layer = ToLayoutBoxModelObject(child->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child_paint_layer);
-  child_mapping = child_paint_layer->GetCompositedLayerMapping();
-  ASSERT_FALSE(child_mapping);
-  grandchild_paint_layer =
-      ToLayoutBoxModelObject(grandchild->GetLayoutObject())->Layer();
-  ASSERT_TRUE(grandchild_paint_layer);
-  grandchild_mapping = grandchild_paint_layer->GetCompositedLayerMapping();
-  ASSERT_TRUE(grandchild_mapping);
-  ASSERT_TRUE(grandchild_mapping->AncestorClippingLayer());
-  EXPECT_TRUE(grandchild_mapping->AncestorClippingLayer()->MaskLayer());
-  EXPECT_TRUE(grandchild_mapping->AncestorClippingMaskLayer());
-
-  // Moving the grandchild out of the clip region should result in removal
-  // of the mask layer. It also removes the grandchild from its own mapping
-  // because it is now squashed.
-  grandchild->setAttribute(html_names::kStyleAttr,
-                           "left: 250px; will-change: transform");
-  UpdateAllLifecyclePhasesForTest();
-  child_paint_layer = ToLayoutBoxModelObject(child->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child_paint_layer);
-  child_mapping = child_paint_layer->GetCompositedLayerMapping();
-  ASSERT_FALSE(child_mapping);
-  grandchild_paint_layer =
-      ToLayoutBoxModelObject(grandchild->GetLayoutObject())->Layer();
-  ASSERT_TRUE(grandchild_paint_layer);
-  grandchild_mapping = grandchild_paint_layer->GetCompositedLayerMapping();
-  ASSERT_TRUE(grandchild_mapping);
-  ASSERT_TRUE(grandchild_mapping->AncestorClippingLayer());
-  EXPECT_FALSE(grandchild_mapping->AncestorClippingLayer()->MaskLayer());
-  EXPECT_FALSE(grandchild_mapping->AncestorClippingMaskLayer());
-
-  // Now change the overflow to remove the need for an ancestor clip
-  // on the children
-  ancestor->setAttribute(html_names::kStyleAttr, "overflow: visible");
-  UpdateAllLifecyclePhasesForTest();
-  child_paint_layer = ToLayoutBoxModelObject(child->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child_paint_layer);
-  child_mapping = child_paint_layer->GetCompositedLayerMapping();
-  ASSERT_FALSE(child_mapping);
-  grandchild_paint_layer =
-      ToLayoutBoxModelObject(grandchild->GetLayoutObject())->Layer();
-  ASSERT_TRUE(grandchild_paint_layer);
-  grandchild_mapping = grandchild_paint_layer->GetCompositedLayerMapping();
-  ASSERT_TRUE(grandchild_mapping);
-  EXPECT_FALSE(grandchild_mapping->AncestorClippingLayer());
-}
-
-TEST_F(CompositedLayerMappingTestWithoutBGPT,
-       AncestorClipMaskRequiredByBorderRadius) {
-  // Verify that we create the mask layer when the child is contained within
-  // the rectangular clip but not contained within the rounded rect clip.
-  SetBodyInnerHTML(R"HTML(
-    <style>
-      #ancestor {
-        width: 100px; height: 100px; overflow: hidden; border-radius: 20px;
-      }
-      #child { position: relative; left: 2px; top: 2px; width: 96px;
-               height: 96px; background-color: green;
-               will-change: transform;
-      }
-    </style>
-    <div id='ancestor'>
-      <div id='child'></div>
-    </div>
-  )HTML");
-  UpdateAllLifecyclePhasesForTest();
-
-  Element* ancestor = GetDocument().getElementById("ancestor");
-  ASSERT_TRUE(ancestor);
-  PaintLayer* ancestor_paint_layer =
-      ToLayoutBoxModelObject(ancestor->GetLayoutObject())->Layer();
-  ASSERT_TRUE(ancestor_paint_layer);
-
-  CompositedLayerMapping* ancestor_mapping =
-      ancestor_paint_layer->GetCompositedLayerMapping();
-  ASSERT_FALSE(ancestor_mapping);
-
-  Element* child = GetDocument().getElementById("child");
-  ASSERT_TRUE(child);
-  PaintLayer* child_paint_layer =
-      ToLayoutBoxModelObject(child->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child_paint_layer);
-  CompositedLayerMapping* child_mapping =
-      child_paint_layer->GetCompositedLayerMapping();
-  ASSERT_TRUE(child_mapping);
-  EXPECT_TRUE(child_mapping->AncestorClippingLayer());
-  EXPECT_TRUE(child_mapping->AncestorClippingLayer()->MaskLayer());
-  EXPECT_TRUE(child_mapping->AncestorClippingMaskLayer());
-}
-
-TEST_F(CompositedLayerMappingTestWithoutBGPT,
-       AncestorClipMaskNotRequiredByNestedBorderRadius) {
-  // This case has the child within all ancestors and does not require a
-  // mask.
-  SetBodyInnerHTML(R"HTML(
-    <style>
-      #grandparent {
-        width: 200px; height: 200px; overflow: hidden; border-radius: 25px;
-      }
-      #parent { position: relative; left: 40px; top: 40px; width: 120px;
-               height: 120px; border-radius: 10px; overflow: hidden;
-      }
-      #child { position: relative; left: 10px; top: 10px; width: 100px;
-               height: 100px; background-color: green;
-               will-change: transform;
-      }
-    </style>
-    <div id='grandparent'>
-      <div id='parent'>
-        <div id='child'></div>
-      </div>
-    </div>
-  )HTML");
-  UpdateAllLifecyclePhasesForTest();
-
-  Element* child = GetDocument().getElementById("child");
-  ASSERT_TRUE(child);
-  PaintLayer* child_paint_layer =
-      ToLayoutBoxModelObject(child->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child_paint_layer);
-  CompositedLayerMapping* child_mapping =
-      child_paint_layer->GetCompositedLayerMapping();
-  ASSERT_TRUE(child_mapping);
-  EXPECT_TRUE(child_mapping->AncestorClippingLayer());
-  EXPECT_FALSE(child_mapping->AncestorClippingLayer()->MaskLayer());
-  EXPECT_FALSE(child_mapping->AncestorClippingMaskLayer());
-}
-
-TEST_F(CompositedLayerMappingTestWithoutBGPT,
-       AncestorClipMaskRequiredByParentBorderRadius) {
-  // This case has the child within the grandparent but not the parent, and does
-  // require a mask so that the parent will clip the corners.
-  SetBodyInnerHTML(R"HTML(
-    <style>
-      #grandparent {
-        width: 200px; height: 200px; overflow: hidden; border-radius: 25px;
-      }
-      #parent { position: relative; left: 40px; top: 40px; width: 120px;
-               height: 120px; border-radius: 10px; overflow: hidden;
-      }
-      #child { position: relative; left: 1px; top: 1px; width: 118px;
-               height: 118px; background-color: green;
-               will-change: transform;
-      }
-    </style>
-    <div id='grandparent'>
-      <div id='parent'>
-        <div id='child'></div>
-      </div>
-    </div>
-  )HTML");
-  UpdateAllLifecyclePhasesForTest();
-
-  Element* child = GetDocument().getElementById("child");
-  ASSERT_TRUE(child);
-  PaintLayer* child_paint_layer =
-      ToLayoutBoxModelObject(child->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child_paint_layer);
-  CompositedLayerMapping* child_mapping =
-      child_paint_layer->GetCompositedLayerMapping();
-  ASSERT_TRUE(child_mapping);
-  ASSERT_TRUE(child_mapping->AncestorClippingLayer());
-  EXPECT_TRUE(child_mapping->AncestorClippingLayer()->MaskLayer());
-  ASSERT_TRUE(child_mapping->AncestorClippingMaskLayer());
-  auto layer_size = child_mapping->AncestorClippingMaskLayer()->Size();
-  EXPECT_EQ(120, layer_size.width());
-  EXPECT_EQ(120, layer_size.height());
-}
-
-TEST_F(CompositedLayerMappingTestWithoutBGPT,
-       AncestorClipMaskNotRequiredByParentBorderRadius) {
-  // This case has the child within the grandparent but not the parent, and does
-  // not require a mask because the parent does not have border radius
-  SetBodyInnerHTML(R"HTML(
-    <style>
-      #grandparent {
-        width: 200px; height: 200px; overflow: hidden; border-radius: 25px;
-      }
-      #parent { position: relative; left: 40px; top: 40px; width: 120px;
-               height: 120px; overflow: hidden;
-      }
-      #child { position: relative; left: -10px; top: -10px; width: 140px;
-               height: 140px; background-color: green;
-               will-change: transform;
-      }
-    </style>
-    <div id='grandparent'>
-      <div id='parent'>
-        <div id='child'></div>
-      </div>
-    </div>
-  )HTML");
-  UpdateAllLifecyclePhasesForTest();
-
-  Element* child = GetDocument().getElementById("child");
-  ASSERT_TRUE(child);
-  PaintLayer* child_paint_layer =
-      ToLayoutBoxModelObject(child->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child_paint_layer);
-  CompositedLayerMapping* child_mapping =
-      child_paint_layer->GetCompositedLayerMapping();
-  ASSERT_TRUE(child_mapping);
-  EXPECT_TRUE(child_mapping->AncestorClippingLayer());
-  EXPECT_FALSE(child_mapping->AncestorClippingLayer()->MaskLayer());
-  EXPECT_FALSE(child_mapping->AncestorClippingMaskLayer());
-}
-
-TEST_F(CompositedLayerMappingTestWithoutBGPT,
-       AncestorClipMaskRequiredByGrandparentBorderRadius1) {
-  // This case has the child clipped by the grandparent border radius but not
-  // the parent, and requires a mask to clip to the grandparent. Although in
-  // an optimized world we would not need this because the parent clips out
-  // the child before it is clipped by the grandparent.
-  SetBodyInnerHTML(R"HTML(
-    <style>
-      #grandparent {
-        width: 200px; height: 200px; overflow: hidden; border-radius: 25px;
-      }
-      #parent { position: relative; left: 40px; top: 40px; width: 120px;
-               height: 120px; overflow: hidden;
-      }
-      #child { position: relative; left: -10px; top: -10px; width: 180px;
-               height: 180px; background-color: green;
-               will-change: transform;
-      }
-    </style>
-    <div id='grandparent'>
-      <div id='parent'>
-        <div id='child'></div>
-      </div>
-    </div>
-  )HTML");
-  UpdateAllLifecyclePhasesForTest();
-
-  Element* child = GetDocument().getElementById("child");
-  ASSERT_TRUE(child);
-  PaintLayer* child_paint_layer =
-      ToLayoutBoxModelObject(child->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child_paint_layer);
-  CompositedLayerMapping* child_mapping =
-      child_paint_layer->GetCompositedLayerMapping();
-  ASSERT_TRUE(child_mapping);
-  ASSERT_TRUE(child_mapping->AncestorClippingLayer());
-  EXPECT_TRUE(child_mapping->AncestorClippingLayer()->MaskLayer());
-  ASSERT_TRUE(child_mapping->AncestorClippingMaskLayer());
-  auto layer_size = child_mapping->AncestorClippingMaskLayer()->Size();
-  EXPECT_EQ(120, layer_size.width());
-  EXPECT_EQ(120, layer_size.height());
-}
-
-TEST_F(CompositedLayerMappingTestWithoutBGPT,
-       AncestorClipMaskRequiredByGrandparentBorderRadius2) {
-  // Similar to the previous case, but here we really do need the mask.
-  SetBodyInnerHTML(R"HTML(
-    <style>
-      #grandparent {
-        width: 200px; height: 200px; overflow: hidden; border-radius: 25px;
-      }
-      #parent { position: relative; left: 40px; top: 40px; width: 180px;
-               height: 180px; overflow: hidden;
-      }
-      #child { position: relative; left: -10px; top: -10px; width: 180px;
-               height: 180px; background-color: green;
-               will-change: transform;
-      }
-    </style>
-    <div id='grandparent'>
-      <div id='parent'>
-        <div id='child'></div>
-      </div>
-    </div>
-  )HTML");
-  UpdateAllLifecyclePhasesForTest();
-
-  Element* child = GetDocument().getElementById("child");
-  ASSERT_TRUE(child);
-  PaintLayer* child_paint_layer =
-      ToLayoutBoxModelObject(child->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child_paint_layer);
-  CompositedLayerMapping* child_mapping =
-      child_paint_layer->GetCompositedLayerMapping();
-  ASSERT_TRUE(child_mapping);
-  ASSERT_TRUE(child_mapping->AncestorClippingLayer());
-  EXPECT_TRUE(child_mapping->AncestorClippingLayer()->MaskLayer());
-  ASSERT_TRUE(child_mapping->AncestorClippingMaskLayer());
-  auto layer_size = child_mapping->AncestorClippingMaskLayer()->Size();
-  EXPECT_EQ(160, layer_size.width());
-  EXPECT_EQ(160, layer_size.height());
-}
-
-TEST_F(CompositedLayerMappingTestWithoutBGPT,
-       AncestorClipMaskNotRequiredByBorderRadiusInside) {
-  // Verify that we do not create the mask layer when the child is contained
-  // within the rounded rect clip.
-  SetBodyInnerHTML(R"HTML(
-    <style>
-      #ancestor {
-        width: 100px; height: 100px; overflow: hidden; border-radius: 5px;
-      }
-      #child { position: relative; left: 10px; top: 10px; width: 80px;
-               height: 80px; background-color: green;
-               will-change: transform;
-      }
-    </style>
-    <div id='ancestor'>
-      <div id='child'></div>
-    </div>
-  )HTML");
-  UpdateAllLifecyclePhasesForTest();
-
-  Element* ancestor = GetDocument().getElementById("ancestor");
-  ASSERT_TRUE(ancestor);
-  PaintLayer* ancestor_paint_layer =
-      ToLayoutBoxModelObject(ancestor->GetLayoutObject())->Layer();
-  ASSERT_TRUE(ancestor_paint_layer);
-
-  CompositedLayerMapping* ancestor_mapping =
-      ancestor_paint_layer->GetCompositedLayerMapping();
-  ASSERT_FALSE(ancestor_mapping);
-
-  Element* child = GetDocument().getElementById("child");
-  ASSERT_TRUE(child);
-  PaintLayer* child_paint_layer =
-      ToLayoutBoxModelObject(child->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child_paint_layer);
-  CompositedLayerMapping* child_mapping =
-      child_paint_layer->GetCompositedLayerMapping();
-  ASSERT_TRUE(child_mapping);
-  EXPECT_TRUE(child_mapping->AncestorClippingLayer());
-  EXPECT_FALSE(child_mapping->AncestorClippingLayer()->MaskLayer());
-  EXPECT_FALSE(child_mapping->AncestorClippingMaskLayer());
-}
-
-TEST_F(CompositedLayerMappingTestWithoutBGPT,
-       AncestorClipMaskNotRequiredByBorderRadiusOutside) {
-  // Verify that we do not create the mask layer when the child is outside
-  // the ancestors rectangular clip.
-  SetBodyInnerHTML(R"HTML(
-    <style>
-      #ancestor {
-        width: 100px; height: 100px; overflow: hidden; border-radius: 5px;
-      }
-      #child { position: relative; left: 110px; top: 10px; width: 80px;
-               height: 80px; background-color: green;
-               will-change: transform;
-    }
-    </style>
-    <div id='ancestor'>
-      <div id='child'></div>
-    </div>
-  )HTML");
-  UpdateAllLifecyclePhasesForTest();
-
-  Element* ancestor = GetDocument().getElementById("ancestor");
-  ASSERT_TRUE(ancestor);
-  PaintLayer* ancestor_paint_layer =
-      ToLayoutBoxModelObject(ancestor->GetLayoutObject())->Layer();
-  ASSERT_TRUE(ancestor_paint_layer);
-
-  CompositedLayerMapping* ancestor_mapping =
-      ancestor_paint_layer->GetCompositedLayerMapping();
-  ASSERT_FALSE(ancestor_mapping);
-
-  Element* child = GetDocument().getElementById("child");
-  ASSERT_TRUE(child);
-  PaintLayer* child_paint_layer =
-      ToLayoutBoxModelObject(child->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child_paint_layer);
-  CompositedLayerMapping* child_mapping =
-      child_paint_layer->GetCompositedLayerMapping();
-  ASSERT_TRUE(child_mapping);
-  EXPECT_TRUE(child_mapping->AncestorClippingLayer());
-  EXPECT_FALSE(child_mapping->AncestorClippingLayer()->MaskLayer());
-  EXPECT_FALSE(child_mapping->AncestorClippingMaskLayer());
-}
-
-TEST_F(CompositedLayerMappingTestWithoutBGPT,
-       AncestorClipMaskRequiredDueToScaleUp) {
-  // Verify that we include the mask when the untransformed child does not
-  // intersect the border radius but the transformed child does. Here the
-  // child is inside the parent and scaled to expand to be clipped.
-  SetBodyInnerHTML(R"HTML(
-    <style>
-      #parent { position: relative; left: 40px; top: 40px; width: 120px;
-               height: 120px; overflow: hidden; border-radius: 10px
-      }
-      #child { position: relative; left: 32px; top: 32px; width: 56px;
-               height: 56px; background-color: green;
-               transform: scale3d(2, 2, 1);
-               will-change: transform;
-      }
-    </style>
-    <div id='parent'>
-      <div id='child'></div>
-    </div>
-  )HTML");
-  UpdateAllLifecyclePhasesForTest();
-
-  Element* child = GetDocument().getElementById("child");
-  ASSERT_TRUE(child);
-  PaintLayer* child_paint_layer =
-      ToLayoutBoxModelObject(child->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child_paint_layer);
-  CompositedLayerMapping* child_mapping =
-      child_paint_layer->GetCompositedLayerMapping();
-  ASSERT_TRUE(child_mapping);
-  EXPECT_TRUE(child_mapping->AncestorClippingLayer());
-  EXPECT_TRUE(child_mapping->AncestorClippingLayer()->MaskLayer());
-  EXPECT_TRUE(child_mapping->AncestorClippingMaskLayer());
-}
-
-TEST_F(CompositedLayerMappingTestWithoutBGPT,
-       AncestorClipMaskNotRequiredDueToScaleDown) {
-  // Verify that we exclude the mask when the untransformed child does
-  // intersect the border radius but the transformed child does not. Here the
-  // child is bigger than the parent and scaled down such that it does not
-  // need a mask.
-  SetBodyInnerHTML(R"HTML(
-    <style>
-      #parent { position: relative; left: 40px; top: 40px; width: 120px;
-               height: 120px; overflow: hidden; border-radius: 10px
-      }
-      #child { position: relative; left: -10px; top: -10px; width: 140px;
-               height: 140px; background-color: green;
-               transform: scale3d(0.5, 0.5, 1);
-               will-change: transform;
-      }
-    </style>
-    <div id='parent'>
-      <div id='child'></div>
-    </div>
-  )HTML");
-  UpdateAllLifecyclePhasesForTest();
-
-  Element* child = GetDocument().getElementById("child");
-  ASSERT_TRUE(child);
-  PaintLayer* child_paint_layer =
-      ToLayoutBoxModelObject(child->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child_paint_layer);
-  CompositedLayerMapping* child_mapping =
-      child_paint_layer->GetCompositedLayerMapping();
-  ASSERT_TRUE(child_mapping);
-  EXPECT_TRUE(child_mapping->AncestorClippingLayer());
-  EXPECT_FALSE(child_mapping->AncestorClippingLayer()->MaskLayer());
-  EXPECT_FALSE(child_mapping->AncestorClippingMaskLayer());
-}
-
-TEST_F(CompositedLayerMappingTestWithoutBGPT,
-       AncestorClipMaskRequiredDueToTranslateInto) {
-  // Verify that we include the mask when the untransformed child does not
-  // intersect the border radius but the transformed child does. Here the
-  // child is outside the parent and translated to be clipped.
-  SetBodyInnerHTML(R"HTML(
-    <style>
-      #parent { position: relative; left: 40px; top: 40px; width: 120px;
-               height: 120px; overflow: hidden; border-radius: 10px
-      }
-      #child { position: relative; left: 140px; top: 140px; width: 100px;
-               height: 100px; background-color: green;
-               transform: translate(-120px, -120px);
-               will-change: transform;
-      }
-    </style>
-    <div id='parent'>
-      <div id='child'></div>
-    </div>
-  )HTML");
-  UpdateAllLifecyclePhasesForTest();
-
-  Element* child = GetDocument().getElementById("child");
-  ASSERT_TRUE(child);
-  PaintLayer* child_paint_layer =
-      ToLayoutBoxModelObject(child->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child_paint_layer);
-  CompositedLayerMapping* child_mapping =
-      child_paint_layer->GetCompositedLayerMapping();
-  ASSERT_TRUE(child_mapping);
-  EXPECT_TRUE(child_mapping->AncestorClippingLayer());
-  EXPECT_TRUE(child_mapping->AncestorClippingLayer()->MaskLayer());
-  EXPECT_TRUE(child_mapping->AncestorClippingMaskLayer());
-}
-
-TEST_F(CompositedLayerMappingTestWithoutBGPT,
-       AncestorClipMaskNotRequiredDueToTranslateOut) {
-  // Verify that we exclude the mask when the untransformed child does
-  // intersect the border radius but the transformed child does not. Here the
-  // child is inside the parent and translated outside.
-  SetBodyInnerHTML(R"HTML(
-    <style>
-      #parent { position: relative; left: 40px; top: 40px; width: 120px;
-               height: 120px; overflow: hidden; border-radius: 10px
-      }
-      #child { position: relative; left: 15px; top: 15px; width: 100px;
-               height: 100px; background-color: green;
-               transform: translate(110px, 110px);
-               will-change: transform;
-      }
-    </style>
-    <div id='parent'>
-      <div id='child'></div>
-    </div>
-  )HTML");
-  UpdateAllLifecyclePhasesForTest();
-
-  Element* child = GetDocument().getElementById("child");
-  ASSERT_TRUE(child);
-  PaintLayer* child_paint_layer =
-      ToLayoutBoxModelObject(child->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child_paint_layer);
-  CompositedLayerMapping* child_mapping =
-      child_paint_layer->GetCompositedLayerMapping();
-  ASSERT_TRUE(child_mapping);
-  EXPECT_TRUE(child_mapping->AncestorClippingLayer());
-  EXPECT_FALSE(child_mapping->AncestorClippingLayer()->MaskLayer());
-  EXPECT_FALSE(child_mapping->AncestorClippingMaskLayer());
-}
-
-TEST_F(CompositedLayerMappingTestWithoutBGPT,
-       AncestorClipMaskRequiredDueToRotation) {
-  // Verify that we include the mask when the untransformed child does not
-  // intersect the border radius but the transformed child does. Here the
-  // child is just within the mask-not-required area but when rotated requires
-  // a mask.
-  SetBodyInnerHTML(R"HTML(
-    <style>
-      #parent { position: relative; left: 40px; top: 40px; width: 120px;
-               height: 120px; overflow: hidden; border-radius: 10px
-      }
-      #child { position: relative; left: 11px; top: 11px; width: 98px;
-               height: 98px; background-color: green;
-               transform: rotate3d(0, 0, 1, 5deg);
-               will-change: transform;
-      }
-    </style>
-    <div id='parent'>
-      <div id='child'></div>
-    </div>
-  )HTML");
-  UpdateAllLifecyclePhasesForTest();
-
-  Element* child = GetDocument().getElementById("child");
-  ASSERT_TRUE(child);
-  PaintLayer* child_paint_layer =
-      ToLayoutBoxModelObject(child->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child_paint_layer);
-  CompositedLayerMapping* child_mapping =
-      child_paint_layer->GetCompositedLayerMapping();
-  ASSERT_TRUE(child_mapping);
-  EXPECT_TRUE(child_mapping->AncestorClippingLayer());
-  EXPECT_TRUE(child_mapping->AncestorClippingLayer()->MaskLayer());
-  EXPECT_TRUE(child_mapping->AncestorClippingMaskLayer());
-}
-
-TEST_F(CompositedLayerMappingTestWithoutBGPT,
-       AncestorClipMaskRequiredByBorderRadiusWithCompositedDescendant) {
-  // This case has the child and grandchild within the ancestors and would
-  // in principle not need a mask, but does because we cannot efficiently
-  // check the bounds of the composited descendant for intersection with the
-  // border.
-  SetBodyInnerHTML(R"HTML(
-    <style>
-      #grandparent {
-        width: 200px; height: 200px; overflow: hidden; border-radius: 25px;
-      }
-      #parent { position: relative; left: 30px; top: 30px; width: 140px;
-               height: 140px; overflow: hidden; will-change: transform;
-      }
-      #child { position: relative; left: 10px; top: 10px; width: 120px;
-               height: 120px; will-change: transform;
-      }
-    </style>
-    <div id='grandparent'>
-      <div id='parent'>
-        <div id='child'></div>
-      </div>
-    </div>
-  )HTML");
-  UpdateAllLifecyclePhasesForTest();
-
-  Element* parent = GetDocument().getElementById("parent");
-  ASSERT_TRUE(parent);
-  PaintLayer* parent_paint_layer =
-      ToLayoutBoxModelObject(parent->GetLayoutObject())->Layer();
-  ASSERT_TRUE(parent_paint_layer);
-  CompositedLayerMapping* parent_mapping =
-      parent_paint_layer->GetCompositedLayerMapping();
-  ASSERT_TRUE(parent_mapping);
-  EXPECT_TRUE(parent_mapping->AncestorClippingLayer());
-  EXPECT_TRUE(parent_mapping->AncestorClippingLayer()->MaskLayer());
-  EXPECT_TRUE(parent_mapping->AncestorClippingMaskLayer());
-}
-
-TEST_F(CompositedLayerMappingTestWithoutBGPT,
-       AncestorClipMaskGrandparentBorderRadiusCompositedDescendant) {
-  // This case has the child clipped by the grandparent border radius but not
-  // the parent, and does not itself require a mask to clip to the grandparent.
-  // But the child has it's own composited child, so we force the mask in case
-  // the child's child needs it.
-  SetBodyInnerHTML(R"HTML(
-    <style>
-      #grandparent {
-        width: 200px; height: 200px; overflow: hidden; border-radius: 25px;
-      }
-      #parent { position: relative; left: 30px; top: 30px; width: 140px;
-               height: 140px; overflow: hidden;
-      }
-      #child { position: relative; left: 10px; top: 10px; width: 120px;
-               height: 120px; will-change: transform;
-      }
-      #grandchild { position: relative; left: 10px; top: 10px; width: 200px;
-               height: 200px; will-change: transform;
-      }
-    </style>
-    <div id='grandparent'>
-      <div id='parent'>
-        <div id='child'>
-          <div id='grandchild'></div>
-        </div>
-      </div>
-    </div>
-  )HTML");
-  UpdateAllLifecyclePhasesForTest();
-
-  Element* child = GetDocument().getElementById("child");
-  ASSERT_TRUE(child);
-  PaintLayer* child_paint_layer =
-      ToLayoutBoxModelObject(child->GetLayoutObject())->Layer();
-  ASSERT_TRUE(child_paint_layer);
-  CompositedLayerMapping* child_mapping =
-      child_paint_layer->GetCompositedLayerMapping();
-  ASSERT_TRUE(child_mapping);
-  ASSERT_TRUE(child_mapping->AncestorClippingLayer());
-  EXPECT_TRUE(child_mapping->AncestorClippingLayer()->MaskLayer());
-  ASSERT_TRUE(child_mapping->AncestorClippingMaskLayer());
-}
-
 TEST_F(CompositedLayerMappingTest, StickyPositionMainThreadOffset) {
   SetBodyInnerHTML(R"HTML(
     <style>.composited { backface-visibility: hidden; }
@@ -2425,57 +1454,6 @@
       target_graphics_layer->CcLayer()->transformed_rasterization_allowed());
 }
 
-// This tests that when the scroller becomes no longer scrollable if a sticky
-// element is promoted for another reason we do remove its composited sticky
-// constraint as it doesn't need to move on the compositor.
-TEST_F(CompositedLayerMappingTestWithoutBGPT,
-       CompositedStickyConstraintRemovedAndAdded) {
-  SetBodyInnerHTML(R"HTML(
-    <style>
-    .scroller { overflow: auto; height: 200px; }
-    .sticky { position: sticky; top: 0; width: 10px; height: 10px; }
-    .composited { will-change: transform; }
-    </style>
-    <div class='composited scroller'>
-      <div id='sticky' class='composited sticky'></div>
-      <div id='spacer' style='height: 2000px;'></div>
-    </div>
-  )HTML");
-  UpdateAllLifecyclePhasesForTest();
-  PaintLayer* sticky_layer =
-      ToLayoutBoxModelObject(GetLayoutObjectByElementId("sticky"))->Layer();
-  EXPECT_TRUE(sticky_layer->GraphicsLayerBacking()
-                  ->CcLayer()
-                  ->sticky_position_constraint()
-                  .is_sticky);
-
-  // Make the scroller no longer scrollable.
-  GetDocument().getElementById("spacer")->setAttribute(html_names::kStyleAttr,
-                                                       "height: 0;");
-  UpdateAllLifecyclePhasesForTest();
-
-  // The sticky position element is composited due to a compositing trigger but
-  // should no longer have a sticky position constraint on the compositor.
-  sticky_layer =
-      ToLayoutBoxModelObject(GetLayoutObjectByElementId("sticky"))->Layer();
-  EXPECT_FALSE(sticky_layer->GraphicsLayerBacking()
-                   ->CcLayer()
-                   ->sticky_position_constraint()
-                   .is_sticky);
-
-  // Make the scroller scrollable again.
-  GetDocument().getElementById("spacer")->setAttribute(html_names::kStyleAttr,
-                                                       "height: 2000px;");
-  UpdateAllLifecyclePhasesForTest();
-
-  sticky_layer =
-      ToLayoutBoxModelObject(GetLayoutObjectByElementId("sticky"))->Layer();
-  EXPECT_TRUE(sticky_layer->GraphicsLayerBacking()
-                  ->CcLayer()
-                  ->sticky_position_constraint()
-                  .is_sticky);
-}
-
 TEST_F(CompositedLayerMappingTest, ScrollingContainerBoundsChange) {
   GetDocument().GetFrame()->GetSettings()->SetPreferCompositingToLCDTextEnabled(
       true);
@@ -2563,44 +1541,6 @@
   EXPECT_EQ(Color(0, 0, 255), scrolling_contents_layer->BackgroundColor());
 }
 
-TEST_F(CompositedLayerMappingTest, ClipPathNoChildContainmentLayer) {
-  // This test verifies only the presence of clip path does not induce child
-  // containment layer.
-  SetBodyInnerHTML(R"HTML(
-    <div id='target' style='width:100px; height:100px; clip-path:circle();'>
-      <div style='will-change:transform; width:200px; height:200px;'></div>
-    </div>
-  )HTML");
-  auto* mapping = ToLayoutBoxModelObject(GetLayoutObjectByElementId("target"))
-                      ->Layer()
-                      ->GetCompositedLayerMapping();
-  ASSERT_TRUE(mapping);
-  ASSERT_FALSE(mapping->ClippingLayer());
-}
-
-TEST_F(CompositedLayerMappingTestWithoutBGPT, ForegroundLayerSizing) {
-  // This test verifies the foreground layer is sized to the clip rect.
-  SetBodyInnerHTML(R"HTML(
-    <div id='target' style='position:relative; z-index:0; width:100px;
-    height:100px; border:10px solid black; overflow:hidden;'>
-      <div style='width:200px; height:200px; background:green;'></div>
-      <div style='position:relative; z-index:-1;
-    will-change:transform;'></div>
-    </div>
-  )HTML");
-  auto* mapping = ToLayoutBoxModelObject(GetLayoutObjectByElementId("target"))
-                      ->Layer()
-                      ->GetCompositedLayerMapping();
-  ASSERT_TRUE(mapping);
-  EXPECT_EQ(gfx::Size(120, 120), mapping->MainGraphicsLayer()->Size());
-  ASSERT_TRUE(mapping->ClippingLayer());
-  EXPECT_EQ(gfx::PointF(10, 10), mapping->ClippingLayer()->GetPosition());
-  EXPECT_EQ(gfx::Size(100, 100), mapping->ClippingLayer()->Size());
-  ASSERT_TRUE(mapping->ForegroundLayer());
-  EXPECT_EQ(gfx::PointF(0, 0), mapping->ForegroundLayer()->GetPosition());
-  EXPECT_EQ(gfx::Size(100, 100), mapping->ForegroundLayer()->Size());
-}
-
 TEST_F(CompositedLayerMappingTest, ScrollLayerSizingSubpixelAccumulation) {
   // This test verifies that when subpixel accumulation causes snapping it
   // applies to both the scrolling and scrolling contents layers. Verify that
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_layer_assigner.cc b/third_party/blink/renderer/core/paint/compositing/compositing_layer_assigner.cc
index f5379aa..e7efc68 100644
--- a/third_party/blink/renderer/core/paint/compositing/compositing_layer_assigner.cc
+++ b/third_party/blink/renderer/core/paint/compositing/compositing_layer_assigner.cc
@@ -163,12 +163,6 @@
           squashing_state.next_squashed_layer_index))
     return SquashingDisallowedReason::kClippingContainerMismatch;
 
-  // Composited descendants need to be clipped by a child containment graphics
-  // layer, which would not be available if the layer is squashed (and therefore
-  // has no CLM nor a child containment graphics layer).
-  if (compositor_->ClipsCompositingDescendants(layer))
-    return SquashingDisallowedReason::kSquashedLayerClipsCompositingDescendants;
-
   if (layer->ScrollsWithRespectTo(&squashing_layer))
     return SquashingDisallowedReason::kScrollsWithRespectToSquashingLayer;
 
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater.cc b/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater.cc
index f218ad5..331af07 100644
--- a/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater.cc
+++ b/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater.cc
@@ -67,20 +67,8 @@
       [&fragment_data, &snapped_paint_offset,
        &container_layer_state](GraphicsLayer* graphics_layer) {
         if (graphics_layer) {
-          if (!container_layer_state) {
+          if (!container_layer_state)
             container_layer_state = fragment_data.LocalBorderBoxProperties();
-            // Before BlinkGenPropertyTrees, CSS clip could not be composited so
-            // we should avoid setting it on the layer itself.
-            if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
-                !RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-              if (const auto* properties = fragment_data.PaintProperties()) {
-                if (const auto* css_clip = properties->CssClip()) {
-                  DCHECK(css_clip->Parent());
-                  container_layer_state->SetClip(*css_clip->Parent());
-                }
-              }
-            }
-          }
           graphics_layer->SetLayerState(
               *container_layer_state,
               snapped_paint_offset + graphics_layer->OffsetFromLayoutObject());
@@ -88,7 +76,6 @@
       };
   SetContainerLayerState(mapping->MainGraphicsLayer());
   SetContainerLayerState(mapping->DecorationOutlineLayer());
-  SetContainerLayerState(mapping->ChildClippingMaskLayer());
 
   bool is_root_scroller =
       CompositingReasonFinder::RequiresCompositingForRootScroller(*paint_layer);
@@ -215,31 +202,6 @@
     mask_layer->SetLayerState(
         state, snapped_paint_offset + mask_layer->OffsetFromLayoutObject());
   }
-
-  if (auto* ancestor_clipping_mask_layer =
-          mapping->AncestorClippingMaskLayer()) {
-    PropertyTreeState state(
-        fragment_data.PreTransform(),
-        mapping->ClipInheritanceAncestor()
-            ->GetLayoutObject()
-            .FirstFragment()
-            .PostOverflowClip(),
-        // This is a hack to incorporate mask-based clip-path. Really should be
-        // nullptr or some dummy.
-        fragment_data.PreFilter());
-    ancestor_clipping_mask_layer->SetLayerState(
-        state, snapped_paint_offset +
-                   ancestor_clipping_mask_layer->OffsetFromLayoutObject());
-  }
-
-  if (auto* child_clipping_mask_layer = mapping->ChildClippingMaskLayer()) {
-    PropertyTreeState state = fragment_data.LocalBorderBoxProperties();
-    // Same hack as for ancestor_clipping_mask_layer.
-    state.SetEffect(fragment_data.PreFilter());
-    child_clipping_mask_layer->SetLayerState(
-        state, snapped_paint_offset +
-                   child_clipping_mask_layer->OffsetFromLayoutObject());
-  }
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_as_text.cc b/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_as_text.cc
index 4de6550..16ba772 100644
--- a/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_as_text.cc
+++ b/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_as_text.cc
@@ -148,12 +148,6 @@
       painting_phases_json->PushString("GraphicsLayerPaintForeground");
     if (painting_phase & kGraphicsLayerPaintMask)
       painting_phases_json->PushString("GraphicsLayerPaintMask");
-    if (painting_phase & kGraphicsLayerPaintChildClippingMask)
-      painting_phases_json->PushString("GraphicsLayerPaintChildClippingMask");
-    if (painting_phase & kGraphicsLayerPaintAncestorClippingMask) {
-      painting_phases_json->PushString(
-          "GraphicsLayerPaintAncestorClippingMask");
-    }
     if (painting_phase & kGraphicsLayerPaintOverflowContents)
       painting_phases_json->PushString("GraphicsLayerPaintOverflowContents");
     if (painting_phase & kGraphicsLayerPaintCompositedScroll)
@@ -205,15 +199,6 @@
     json->SetArray("maskLayer", std::move(mask_layer_json));
   }
 
-  if (layer->ContentsClippingMaskLayer()) {
-    auto contents_clipping_mask_layer_json = std::make_unique<JSONArray>();
-    contents_clipping_mask_layer_json->PushObject(GraphicsLayerAsJSON(
-        layer->ContentsClippingMaskLayer(), flags, rendering_context_map,
-        FloatPoint(layer->ContentsClippingMaskLayer()->GetPosition())));
-    json->SetArray("contentsClippingMaskLayer",
-                   std::move(contents_clipping_mask_layer_json));
-  }
-
   if (layer->HasLayerState() && (flags & (kLayerTreeIncludesDebugInfo |
                                           kLayerTreeIncludesPaintRecords))) {
     json->SetString("layerState", layer->GetPropertyTreeState().ToString());
diff --git a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
index 838e1ea..6f1a5d9 100644
--- a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
+++ b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
@@ -278,18 +278,6 @@
   // crbug.com/667547
   if (!layout_view_.GetDocument().Printing() ||
       RuntimeEnabledFeatures::PrintBrowserEnabled()) {
-    // Although BlinkGenPropertyTreesEnabled still uses PaintLayerCompositor to
-    // generate the composited layer tree/list, it also has the CAP behavior of
-    // removing layers that do not draw content. As such, we use the same path
-    // as CAP for updating composited animations once we know the final set of
-    // composited elements (see LocalFrameView::UpdateLifecyclePhasesInternal,
-    // during kPaintClean).
-    if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-      DocumentAnimations::UpdateAnimations(layout_view_.GetDocument(),
-                                           DocumentLifecycle::kCompositingClean,
-                                           nullptr);
-    }
-
     layout_view_.GetFrameView()
         ->GetScrollableArea()
         ->UpdateCompositorScrollAnimations();
@@ -569,15 +557,6 @@
         layers_needing_paint_invalidation[i]->GetLayoutObject());
   }
 
-  // When BlinkGenPropertyTrees is enabled, layer attachment, including the root
-  // layer, must occur in the paint lifecycle step.
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    AttachRootLayerViaChromeClient();
-
-  // Inform the inspector that the layer tree has changed.
-  if (IsMainFrame() && !RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    probe::LayerTreeDidChange(layout_view_.GetFrame());
-
   Lifecycle().AdvanceTo(DocumentLifecycle::kCompositingClean);
 }
 
@@ -808,21 +787,6 @@
          !layer->GetLayoutObject().IsSVGForeignObject();
 }
 
-// Return true if the given layer is a stacking context and has compositing
-// child layers that it needs to clip, or is an embedded object with a border
-// radius. In these cases we insert a clipping GraphicsLayer into the hierarchy
-// between this layer and its children in the z-order hierarchy.
-bool PaintLayerCompositor::ClipsCompositingDescendants(
-    const PaintLayer* layer) const {
-  if (!layer->HasCompositingDescendant())
-    return false;
-  if (!layer->GetLayoutObject().IsBox())
-    return false;
-  const LayoutBox& box = ToLayoutBox(layer->GetLayoutObject());
-  return box.ShouldClipOverflow() || box.HasClip() ||
-         (box.IsLayoutEmbeddedContent() && box.StyleRef().HasBorderRadius());
-}
-
 // If an element has composited negative z-index children, those children paint
 // in front of the layer background, so we need an extra 'contents' layer for
 // the foreground of the layer object.
@@ -845,10 +809,6 @@
 
   if (GraphicsLayer* mask_layer = graphics_layer->MaskLayer())
     UpdateTrackingRasterInvalidationsRecursive(mask_layer);
-
-  if (GraphicsLayer* clipping_mask_layer =
-          graphics_layer->ContentsClippingMaskLayer())
-    UpdateTrackingRasterInvalidationsRecursive(clipping_mask_layer);
 }
 
 void PaintLayerCompositor::UpdateTrackingRasterInvalidations() {
diff --git a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h
index 9c5608e..d62d067 100644
--- a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h
+++ b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h
@@ -113,10 +113,6 @@
   // frame that gets drawn.
   void SetNeedsCompositingUpdate(CompositingUpdateType);
 
-  // Whether layer's compositedLayerMapping needs a GraphicsLayer to clip
-  // z-order children of the given Layer.
-  bool ClipsCompositingDescendants(const PaintLayer*) const;
-
   // Whether the given layer needs an extra 'contents' layer.
   bool NeedsContentsCompositingLayer(const PaintLayer*) const;
 
diff --git a/third_party/blink/renderer/core/paint/link_highlight_impl.cc b/third_party/blink/renderer/core/paint/link_highlight_impl.cc
index 2fd5f1c5..f577d13 100644
--- a/third_party/blink/renderer/core/paint/link_highlight_impl.cc
+++ b/third_party/blink/renderer/core/paint/link_highlight_impl.cc
@@ -90,12 +90,8 @@
 }  // namespace
 
 static CompositorElementId NewElementId() {
-  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
-      RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-    return CompositorElementIdFromUniqueObjectId(
-        NewUniqueObjectId(), CompositorElementIdNamespace::kPrimaryEffect);
-  }
-  return CompositorElementIdFromUniqueObjectId(NewUniqueObjectId());
+  return CompositorElementIdFromUniqueObjectId(
+      NewUniqueObjectId(), CompositorElementIdNamespace::kPrimaryEffect);
 }
 
 LinkHighlightImpl::LinkHighlightImpl(Node* node)
@@ -110,12 +106,6 @@
   DCHECK(node_);
   fragments_.emplace_back();
 
-  // The layer's element id is required for animating layers in layer trees.
-  // When using layer lists, the element id is set on the effect node.
-  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
-      !RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    fragments_[0].Layer()->SetElementId(element_id_);
-
   compositor_animation_ = CompositorAnimation::Create();
   DCHECK(compositor_animation_);
   compositor_animation_->SetAnimationDelegate(this);
@@ -297,12 +287,10 @@
 
   layer->SetPosition(bounding_rect.Location());
 
-  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-    offset_from_transform_node_ =
-        FloatPoint(current_graphics_layer_->GetOffsetFromTransformNode());
-    offset_from_transform_node_.MoveBy(bounding_rect.Location());
-    SetPaintArtifactCompositorNeedsUpdate();
-  }
+  offset_from_transform_node_ =
+      FloatPoint(current_graphics_layer_->GetOffsetFromTransformNode());
+  offset_from_transform_node_.MoveBy(bounding_rect.Location());
+  SetPaintArtifactCompositorNeedsUpdate();
 
   return path_has_changed;
 }
diff --git a/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc b/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc
index e4b7e0b8..6d2eedb 100644
--- a/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc
+++ b/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc
@@ -105,7 +105,7 @@
 
   PaintArtifactCompositor* paint_artifact_compositor() {
     auto* local_frame_view = web_view_helper_.LocalMainFrame()->GetFrameView();
-    return local_frame_view->GetPaintArtifactCompositorForTesting();
+    return local_frame_view->GetPaintArtifactCompositor();
   }
 
   void UpdateAllLifecyclePhases() {
@@ -290,11 +290,6 @@
 }
 
 TEST_P(LinkHighlightImplTest, HighlightLayerEffectNode) {
-  // This is testing the blink->cc layer integration.
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
-      !RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
-    return;
-
   bool was_running_web_test = WebTestSupport::IsRunningWebTest();
   WebTestSupport::SetIsRunningWebTest(false);
   int page_width = 640;
@@ -361,11 +356,6 @@
 }
 
 TEST_P(LinkHighlightImplTest, MultiColumn) {
-  // This is testing the blink->cc layer integration.
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
-      !RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
-    return;
-
   int page_width = 640;
   int page_height = 480;
   WebViewImpl* web_view_impl = web_view_helper_.GetWebView();
diff --git a/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc b/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
index 2e3daa8..42e7d3b8 100644
--- a/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
+++ b/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
@@ -70,7 +70,7 @@
         RuntimeEnabledFeatures::CompositeAfterPaintEnabled()
             ? GetDocument()
                   .View()
-                  ->GetPaintArtifactCompositorForTesting()
+                  ->GetPaintArtifactCompositor()
                   ->RootLayer()
                   ->children()[0]
                   .get()
diff --git a/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.h b/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.h
index 8512b20..d1da3ab 100644
--- a/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.h
+++ b/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.h
@@ -23,7 +23,7 @@
     DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
     const auto& clients = GetDocument()
                               .View()
-                              ->GetPaintArtifactCompositorForTesting()
+                              ->GetPaintArtifactCompositor()
                               ->ContentLayerClientsForTesting();
     return index < clients.size() ? clients[index].get() : nullptr;
   }
@@ -47,10 +47,7 @@
     if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
       layer_tree_ = std::make_unique<LayerTreeHostEmbedder>();
       layer_tree_->layer_tree_host()->SetRootLayer(
-          GetDocument()
-              .View()
-              ->GetPaintArtifactCompositorForTesting()
-              ->RootLayer());
+          GetDocument().View()->GetPaintArtifactCompositor()->RootLayer());
     }
   }
 
diff --git a/third_party/blink/renderer/core/paint/paint_layer_painter.cc b/third_party/blink/renderer/core/paint/paint_layer_painter.cc
index 0c26d37..5d84dd7 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_painter.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_painter.cc
@@ -40,9 +40,7 @@
 static ShouldRespectOverflowClipType ShouldRespectOverflowClip(
     PaintLayerFlags paint_flags,
     const LayoutObject& layout_object) {
-  return (paint_flags & kPaintLayerPaintingOverflowContents ||
-          (paint_flags & kPaintLayerPaintingChildClippingMaskPhase &&
-           layout_object.HasClipPath()))
+  return (paint_flags & kPaintLayerPaintingOverflowContents)
              ? kIgnoreOverflowClip
              : kRespectOverflowClip;
 }
@@ -425,30 +423,7 @@
       is_painting_overlay_scrollbars) {
     // Collect the fragments. This will compute the clip rectangles and paint
     // offsets for each layer fragment.
-    PhysicalOffset offset_to_clipper;
-    const PaintLayer* paint_layer_for_fragments = &paint_layer_;
-    if (paint_flags & kPaintLayerPaintingAncestorClippingMaskPhase) {
-      // Compute fragments and their clips with respect to the outermost
-      // clipping container. This handles nested border radius by including
-      // all of them in the mask.
-      //
-      // The cull rect is in this layer's space, so convert it to the clipper's
-      // layer's space. The root_layer is also changed to the clipper's layer to
-      // simplify coordinate system adjustments. The change to root_layer must
-      // persist to correctly record the clips.
-      paint_layer_for_fragments =
-          paint_layer_.EnclosingLayerWithCompositedLayerMapping(kExcludeSelf);
-      local_painting_info.root_layer = paint_layer_for_fragments;
-      paint_layer_.ConvertToLayerCoords(local_painting_info.root_layer,
-                                        offset_to_clipper);
-      PhysicalRect new_cull_rect(local_painting_info.cull_rect.Rect());
-      new_cull_rect.Move(offset_to_clipper);
-      local_painting_info.cull_rect = CullRect(EnclosingIntRect(new_cull_rect));
-      // Overflow clip of the compositing container is irrelevant.
-      respect_overflow_clip = kIgnoreOverflowClip;
-    }
-
-    paint_layer_for_fragments->CollectFragments(
+    paint_layer_.CollectFragments(
         layer_fragments, local_painting_info.root_layer,
         &local_painting_info.cull_rect, kIgnorePlatformOverlayScrollbarSize,
         respect_overflow_clip, &offset_from_root,
@@ -460,17 +435,7 @@
     if (layer_fragments.size() > 1)
       result = kMayBeClippedByCullRect;
 
-    if (paint_flags & kPaintLayerPaintingAncestorClippingMaskPhase) {
-      // Fragment offsets have been computed in the clipping container's
-      // layer's coordinate system, but for the rest of painting we need
-      // them in the layer coordinate. So move them and the
-      // foreground/background rects that are also in the clipper's space.
-      PhysicalOffset negative_offset = -offset_to_clipper;
-      for (auto& fragment : layer_fragments) {
-        fragment.background_rect.Move(negative_offset);
-        fragment.foreground_rect.Move(negative_offset);
-      }
-    } else if (should_paint_content) {
+    if (should_paint_content) {
       should_paint_content = AtLeastOneFragmentIntersectsDamageRect(
           layer_fragments, local_painting_info, paint_flags, offset_from_root);
       if (!should_paint_content)
@@ -622,21 +587,6 @@
 
   clip_path_clipper = base::nullopt;
 
-  if (should_paint_content && !selection_only) {
-    // Paint the border radius mask for the fragments.
-    if (paint_flags & kPaintLayerPaintingAncestorClippingMaskPhase) {
-      // |layer_fragments| comes from the compositing container which doesn't
-      // have multiple fragments.
-      DCHECK_EQ(1u, layer_fragments.size());
-      PaintAncestorClippingMask(layer_fragments[0], context,
-                                local_painting_info, paint_flags);
-    }
-    if (paint_flags & kPaintLayerPaintingChildClippingMaskPhase) {
-      PaintChildClippingMaskForFragments(layer_fragments, context,
-                                         local_painting_info, paint_flags);
-    }
-  }
-
   paint_layer_.SetPreviousPaintResult(result);
   paint_layer_.SetPreviousCullRect(local_painting_info.cull_rect);
   return result;
@@ -899,52 +849,6 @@
                   });
 }
 
-void PaintLayerPainter::PaintAncestorClippingMask(
-    const PaintLayerFragment& fragment,
-    GraphicsContext& context,
-    const PaintLayerPaintingInfo& local_painting_info,
-    PaintLayerFlags paint_flags) {
-  const DisplayItemClient& client =
-      *paint_layer_.GetCompositedLayerMapping()->AncestorClippingMaskLayer();
-  const auto& layer_fragment = paint_layer_.GetLayoutObject().FirstFragment();
-  auto state = layer_fragment.PreEffectProperties();
-  // This is a hack to incorporate mask-based clip-path.
-  // See CompositingLayerPropertyUpdater.cpp about AncestorClippingMaskLayer.
-  state.SetEffect(layer_fragment.PreFilter());
-  ScopedPaintChunkProperties properties(context.GetPaintController(), state,
-                                        client, DisplayItem::kClippingMask);
-  ClipRect mask_rect = fragment.background_rect;
-  mask_rect.Move(layer_fragment.PaintOffset());
-  FillMaskingFragment(context, mask_rect, client);
-}
-
-void PaintLayerPainter::PaintChildClippingMaskForFragments(
-    const PaintLayerFragments& layer_fragments,
-    GraphicsContext& context,
-    const PaintLayerPaintingInfo& local_painting_info,
-    PaintLayerFlags paint_flags) {
-  const DisplayItemClient& client =
-      *paint_layer_.GetCompositedLayerMapping()->ChildClippingMaskLayer();
-  ForAllFragments(
-      context, layer_fragments, [&](const PaintLayerFragment& fragment) {
-        // Use the LocalBorderboxProperties as a starting point to ensure that
-        // we don't include the scroll offset when painting the mask layer.
-        auto state = fragment.fragment_data->LocalBorderBoxProperties();
-        // This is a hack to incorporate mask-based clip-path.
-        // See CompositingLayerPropertyUpdater.cpp about
-        // ChildClippingMaskLayer.
-        state.SetEffect(fragment.fragment_data->PreFilter());
-        // Update the clip to be the ContentsProperties clip, since it
-        // includes the InnerBorderRadiusClip.
-        state.SetClip(fragment.fragment_data->ContentsProperties().Clip());
-        ScopedPaintChunkProperties fragment_paint_chunk_properties(
-            context.GetPaintController(), state, client,
-            DisplayItem::kClippingMask);
-        ClipRect mask_rect = fragment.background_rect;
-        FillMaskingFragment(context, mask_rect, client);
-      });
-}
-
 void PaintLayerPainter::PaintOverlayScrollbars(
     GraphicsContext& context,
     const CullRect& cull_rect,
diff --git a/third_party/blink/renderer/core/paint/paint_layer_painter.h b/third_party/blink/renderer/core/paint/paint_layer_painter.h
index 03be2fc..a6777bc 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_painter.h
+++ b/third_party/blink/renderer/core/paint/paint_layer_painter.h
@@ -102,14 +102,6 @@
                              GraphicsContext&,
                              const PaintLayerPaintingInfo&,
                              PaintLayerFlags);
-  void PaintAncestorClippingMask(const PaintLayerFragment&,
-                                 GraphicsContext&,
-                                 const PaintLayerPaintingInfo&,
-                                 PaintLayerFlags);
-  void PaintChildClippingMaskForFragments(const PaintLayerFragments&,
-                                          GraphicsContext&,
-                                          const PaintLayerPaintingInfo&,
-                                          PaintLayerFlags);
 
   void FillMaskingFragment(GraphicsContext&,
                            const ClipRect&,
diff --git a/third_party/blink/renderer/core/paint/paint_layer_painting_info.h b/third_party/blink/renderer/core/paint/paint_layer_painting_info.h
index c3aa21e..2c5c0bc 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_painting_info.h
+++ b/third_party/blink/renderer/core/paint/paint_layer_painting_info.h
@@ -71,8 +71,6 @@
   kPaintLayerPaintingCompositingScrollingPhase = 1 << 7,
   kPaintLayerPaintingOverflowContents = 1 << 8,
   kPaintLayerPaintingSkipRootBackground = 1 << 10,
-  kPaintLayerPaintingChildClippingMaskPhase = 1 << 11,
-  kPaintLayerPaintingAncestorClippingMaskPhase = 1 << 12,
   kPaintLayerPaintingRenderingClipPathAsMask = 1 << 13,
   kPaintLayerPaintingCompositingDecorationPhase = 1 << 14,
   kPaintLayerPaintingRenderingResourceSubtree = 1 << 15,
@@ -149,10 +147,6 @@
     append("kPaintLayerPaintingOverflowContents");
   if (flags & kPaintLayerPaintingSkipRootBackground)
     append("kPaintLayerPaintingSkipRootBackground");
-  if (flags & kPaintLayerPaintingChildClippingMaskPhase)
-    append("kPaintLayerPaintingChildClippingMaskPhase");
-  if (flags & kPaintLayerPaintingAncestorClippingMaskPhase)
-    append("kPaintLayerPaintingAncestorClippingMaskPhase");
   if (flags & kPaintLayerPaintingRenderingClipPathAsMask)
     append("kPaintLayerPaintingRenderingClipPathAsMask");
   if (flags & kPaintLayerPaintingRenderingResourceSubtree)
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
index f636537..59025b0 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -2179,21 +2179,10 @@
     DCHECK(Layer()->HasCompositedLayerMapping());
     ScrollingCoordinator* scrolling_coordinator = GetScrollingCoordinator();
     bool handled_scroll =
-        (Layer()->IsRootLayer() ||
-         RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) &&
         scrolling_coordinator &&
         scrolling_coordinator->UpdateCompositedScrollOffset(this);
 
     if (!handled_scroll) {
-      if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-        // In non-BGPT mode, we need to do a full sub-tree update here, because
-        // we need to update the position property to compute
-        // offset_to_transform_parent. For more context, see the comment from
-        // chrishtr@ here:
-        // https://chromium-review.googlesource.com/c/chromium/src/+/1403639/6/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
-        Layer()->GetCompositedLayerMapping()->SetNeedsGraphicsLayerUpdate(
-            kGraphicsLayerUpdateSubtree);
-      }
       compositor->SetNeedsCompositingUpdate(
           kCompositingUpdateAfterGeometryChange);
     }
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
index bc1bd55..d178419 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -489,9 +489,7 @@
     state.direct_compositing_reasons =
         full_context_.direct_compositing_reasons &
         CompositingReason::kScrollDependentPosition;
-    if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
-        RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-      state.rendering_context_id = context_.current.rendering_context_id;
+    state.rendering_context_id = context_.current.rendering_context_id;
     OnUpdate(properties_->UpdatePaintOffsetTranslation(
         *context_.current.transform, std::move(state)));
     context_.current.transform = properties_->PaintOffsetTranslation();
@@ -660,9 +658,7 @@
   if (object.IsText())
     return false;
 
-  if ((RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
-       RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) &&
-      object.StyleRef().BackfaceVisibility() == EBackfaceVisibility::kHidden)
+  if (object.StyleRef().BackfaceVisibility() == EBackfaceVisibility::kHidden)
     return true;
 
   if (direct_compositing_reasons & CompositingReasonsForTransformProperty())
@@ -729,43 +725,36 @@
                 matrix, TransformOrigin(box),
                 disable_2d_translation_optimization);
 
-        if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
-            RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-          // TODO(trchen): transform-style should only be respected if a
-          // PaintLayer is created. If a node with transform-style: preserve-3d
-          // does not exist in an existing rendering context, it establishes a
-          // new one.
-          state.rendering_context_id = context_.current.rendering_context_id;
-          if (style.Preserves3D() && !state.rendering_context_id) {
-            state.rendering_context_id =
-                PtrHash<const LayoutObject>::GetHash(&object_);
-          }
-          state.direct_compositing_reasons =
-              full_context_.direct_compositing_reasons &
-              CompositingReasonsForTransformProperty();
-          // TODO(flackr): This only needs to consider composited transform
-          // animations. This is currently a cyclic dependency but we could
-          // calculate most of the compositable animation reasons up front to
-          // only consider animations which are candidates for compositing.
-          state.flags.animation_is_axis_aligned =
-              ActiveTransformAnimationIsAxisAligned(
-                  object_, full_context_.direct_compositing_reasons);
+        // TODO(trchen): transform-style should only be respected if a
+        // PaintLayer is created. If a node with transform-style: preserve-3d
+        // does not exist in an existing rendering context, it establishes a
+        // new one.
+        state.rendering_context_id = context_.current.rendering_context_id;
+        if (style.Preserves3D() && !state.rendering_context_id) {
+          state.rendering_context_id =
+              PtrHash<const LayoutObject>::GetHash(&object_);
         }
+        state.direct_compositing_reasons =
+            full_context_.direct_compositing_reasons &
+            CompositingReasonsForTransformProperty();
+        // TODO(flackr): This only needs to consider composited transform
+        // animations. This is currently a cyclic dependency but we could
+        // calculate most of the compositable animation reasons up front to
+        // only consider animations which are candidates for compositing.
+        state.flags.animation_is_axis_aligned =
+            ActiveTransformAnimationIsAxisAligned(
+                object_, full_context_.direct_compositing_reasons);
       }
 
       state.flags.flattens_inherited_transform =
           context_.current.should_flatten_inherited_transform;
 
-      if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
-          RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-        state.backface_visibility =
-            object_.HasHiddenBackface()
-                ? TransformPaintPropertyNode::BackfaceVisibility::kHidden
-                : TransformPaintPropertyNode::BackfaceVisibility::kVisible;
-        state.compositor_element_id = CompositorElementIdFromUniqueObjectId(
-            object_.UniqueId(),
-            CompositorElementIdNamespace::kPrimaryTransform);
-      }
+      state.backface_visibility =
+          object_.HasHiddenBackface()
+              ? TransformPaintPropertyNode::BackfaceVisibility::kHidden
+              : TransformPaintPropertyNode::BackfaceVisibility::kVisible;
+      state.compositor_element_id = CompositorElementIdFromUniqueObjectId(
+          object_.UniqueId(), CompositorElementIdNamespace::kPrimaryTransform);
 
       TransformPaintPropertyNode::AnimationState animation_state;
       animation_state.is_running_animation_on_compositor =
@@ -824,18 +813,16 @@
 static CompositingReasons CompositingReasonsForEffectProperty() {
   CompositingReasons reasons =
       CompositingReason::kDirectReasonsForEffectProperty;
-  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-    // TODO(crbug.com/900241): Check for nodes for each KeyframeModel target
-    // property instead of creating all nodes and only create a transform/
-    // effect/filter node if needed.
-    reasons |= CompositingReason::kComboActiveAnimation;
-    // We also need to create effect node if the transform node is created for
-    // will-change:transform to avoid raster invalidation (caused by otherwise a
-    // created/deleted effect node) when we start/stop a transform animation.
-    // https://crbug.com/942681
-    if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
-      reasons |= CompositingReason::kWillChangeTransform;
-  }
+  // TODO(crbug.com/900241): Check for nodes for each KeyframeModel target
+  // property instead of creating all nodes and only create a transform/
+  // effect/filter node if needed.
+  reasons |= CompositingReason::kComboActiveAnimation;
+  // We also need to create effect node if the transform node is created for
+  // will-change:transform to avoid raster invalidation (caused by otherwise a
+  // created/deleted effect node) when we start/stop a transform animation.
+  // https://crbug.com/942681
+  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+    reasons |= CompositingReason::kWillChangeTransform;
   return reasons;
 }
 
@@ -885,8 +872,7 @@
 
     // An effect node is required by cc if the layer flattens its subtree but it
     // is treated as a 3D object by its parent.
-    if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
-        !layer->Preserves3D() && layer->HasSelfPaintingLayerDescendant() &&
+    if (!layer->Preserves3D() && layer->HasSelfPaintingLayerDescendant() &&
         layer->Parent() && layer->Parent()->Preserves3D())
       return true;
   }
@@ -1009,8 +995,7 @@
       }
 
       CompositorElementId mask_compositor_element_id;
-      if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
-          (mask_clip || has_spv1_composited_clip_path)) {
+      if (mask_clip || has_spv1_composited_clip_path) {
         mask_compositor_element_id = CompositorElementIdFromUniqueObjectId(
             object_.UniqueId(), CompositorElementIdNamespace::kEffectMask);
       }
@@ -1039,36 +1024,33 @@
           }
         }
       }
-      if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
-          RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-        // We may begin to composite our subtree prior to an animation starts,
-        // but a compositor element ID is only needed when an animation is
-        // current.
-        //
-        // Currently, we use the existence of this id to check if effect nodes
-        // have been created for animations on this element.
-        state.direct_compositing_reasons =
-            full_context_.direct_compositing_reasons &
-            CompositingReasonsForEffectProperty();
-        if (state.direct_compositing_reasons) {
-          state.compositor_element_id = CompositorElementIdFromUniqueObjectId(
-              object_.UniqueId(), CompositorElementIdNamespace::kPrimaryEffect);
-        } else {
-          // The effect node CompositorElementId is used to uniquely identify
-          // renderpasses so even if we don't need one for animations we still
-          // need to set an id. Using kPrimary avoids confusing cc::Animation
-          // into thinking the element has been composited for animations.
-          state.compositor_element_id = CompositorElementIdFromUniqueObjectId(
-              object_.UniqueId(), CompositorElementIdNamespace::kPrimary);
-        }
 
-        // TODO(crbug.com/900241): Remove these setters when we can use
-        // state.direct_compositing_reasons to check for active animations.
-        state.has_active_opacity_animation = style.HasCurrentOpacityAnimation();
-        state.has_active_backdrop_filter_animation =
-            style.HasCurrentBackdropFilterAnimation();
+      // We may begin to composite our subtree prior to an animation starts, but
+      // a compositor element ID is only needed when an animation is current.
+      //
+      // Currently, we use the existence of this id to check if effect nodes
+      // have been created for animations on this element.
+      state.direct_compositing_reasons =
+          full_context_.direct_compositing_reasons &
+          CompositingReasonsForEffectProperty();
+      if (state.direct_compositing_reasons) {
+        state.compositor_element_id = CompositorElementIdFromUniqueObjectId(
+            object_.UniqueId(), CompositorElementIdNamespace::kPrimaryEffect);
+      } else {
+        // The effect node CompositorElementId is used to uniquely identify
+        // renderpasses so even if we don't need one for animations we still
+        // need to set an id. Using kPrimary avoids confusing cc::Animation
+        // into thinking the element has been composited for animations.
+        state.compositor_element_id = CompositorElementIdFromUniqueObjectId(
+            object_.UniqueId(), CompositorElementIdNamespace::kPrimary);
       }
 
+      // TODO(crbug.com/900241): Remove these setters when we can use
+      // state.direct_compositing_reasons to check for active animations.
+      state.has_active_opacity_animation = style.HasCurrentOpacityAnimation();
+      state.has_active_backdrop_filter_animation =
+          style.HasCurrentBackdropFilterAnimation();
+
       EffectPaintPropertyNode::AnimationState animation_state;
       animation_state.is_running_opacity_animation_on_compositor =
           style.IsRunningOpacityAnimationOnCompositor();
@@ -1103,10 +1085,7 @@
         mask_state.output_clip = output_clip;
         mask_state.color_filter = CSSMaskPainter::MaskColorFilter(object_);
         mask_state.blend_mode = SkBlendMode::kDstIn;
-        if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
-            RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-          mask_state.compositor_element_id = mask_compositor_element_id;
-        }
+        mask_state.compositor_element_id = mask_compositor_element_id;
         OnUpdate(properties_->UpdateMask(*properties_->Effect(),
                                          std::move(mask_state)));
       } else {
@@ -1121,13 +1100,10 @@
         clip_path_state.local_transform_space = context_.current.transform;
         clip_path_state.output_clip = output_clip;
         clip_path_state.blend_mode = SkBlendMode::kDstIn;
-        if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
-            RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-          clip_path_state.compositor_element_id =
-              CompositorElementIdFromUniqueObjectId(
-                  object_.UniqueId(),
-                  CompositorElementIdNamespace::kEffectClipPath);
-        }
+        clip_path_state.compositor_element_id =
+            CompositorElementIdFromUniqueObjectId(
+                object_.UniqueId(),
+                CompositorElementIdNamespace::kEffectClipPath);
         OnUpdate(
             properties_->UpdateClipPath(parent, std::move(clip_path_state)));
       } else {
@@ -1160,19 +1136,17 @@
 static CompositingReasons CompositingReasonsForFilterProperty() {
   CompositingReasons reasons =
       CompositingReason::kDirectReasonsForFilterProperty;
-  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-    // TODO(crbug.com/900241): Check for nodes for each KeyframeModel target
-    // property instead of creating all nodes and only create a transform/
-    // effect/filter node if needed.
-    reasons |= CompositingReason::kComboActiveAnimation;
-    // We also need to create filter node if the transform/effect node is
-    // created for will-change:transform/opacity to avoid raster invalidation
-    // (caused by otherwise a created/deleted filter node) when we start/stop a
-    // transform/opacity animation. https://crbug.com/942681
-    if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-      reasons |= CompositingReason::kWillChangeTransform |
-                 CompositingReason::kWillChangeOpacity;
-    }
+  // TODO(crbug.com/900241): Check for nodes for each KeyframeModel target
+  // property instead of creating all nodes and only create a transform/
+  // effect/filter node if needed.
+  reasons |= CompositingReason::kComboActiveAnimation;
+  // We also need to create filter node if the transform/effect node is
+  // created for will-change:transform/opacity to avoid raster invalidation
+  // (caused by otherwise a created/deleted filter node) when we start/stop a
+  // transform/opacity animation. https://crbug.com/942681
+  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+    reasons |= CompositingReason::kWillChangeTransform |
+               CompositingReason::kWillChangeOpacity;
   }
   return reasons;
 }
@@ -1202,17 +1176,9 @@
 
       if (auto* layer = ToLayoutBoxModelObject(object_).Layer()) {
         // Try to use the cached filter.
-        if (properties_->Filter()) {
+        if (properties_->Filter())
           state.filter = properties_->Filter()->Filter();
-        }
-
-        // With BGPT disabled, UpdateFilterReferenceBox gets called from
-        // CompositedLayerMapping::UpdateGraphicsLayerGeometry, but only
-        // for composited layers.
-        if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
-            layer->GetCompositingState() != kPaintsIntoOwnBacking) {
-          layer->UpdateFilterReferenceBox();
-        }
+        layer->UpdateFilterReferenceBox();
         layer->UpdateCompositorFilterOperationsForFilter(state.filter);
         layer->ClearFilterOnEffectNodeDirty();
       }
@@ -1242,22 +1208,19 @@
       // output pixel may depend on an input pixel outside of the output clip.
       // We should generate a special clip node to represent this expansion.
 
-      if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
-          RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-        // We may begin to composite our subtree prior to an animation starts,
-        // but a compositor element ID is only needed when an animation is
-        // current.
-        state.direct_compositing_reasons =
-            full_context_.direct_compositing_reasons &
-            CompositingReasonsForFilterProperty();
-        state.compositor_element_id = CompositorElementIdFromUniqueObjectId(
-            object_.UniqueId(), CompositorElementIdNamespace::kEffectFilter);
+      // We may begin to composite our subtree prior to an animation starts,
+      // but a compositor element ID is only needed when an animation is
+      // current.
+      state.direct_compositing_reasons =
+          full_context_.direct_compositing_reasons &
+          CompositingReasonsForFilterProperty();
+      state.compositor_element_id = CompositorElementIdFromUniqueObjectId(
+          object_.UniqueId(), CompositorElementIdNamespace::kEffectFilter);
 
-        // TODO(crbug.com/900241): Remove the setter when we can use
-        // state.direct_compositing_reasons to check for active animations.
-        state.has_active_filter_animation =
-            object_.StyleRef().HasCurrentFilterAnimation();
-      }
+      // TODO(crbug.com/900241): Remove the setter when we can use
+      // state.direct_compositing_reasons to check for active animations.
+      state.has_active_filter_animation =
+          object_.StyleRef().HasCurrentFilterAnimation();
 
       EffectPaintPropertyNode::AnimationState animation_state;
       animation_state.is_running_filter_animation_on_compositor =
@@ -1692,9 +1655,7 @@
                   FloatSize(context_.current.paint_offset))};
       state.flags.flattens_inherited_transform =
           context_.current.should_flatten_inherited_transform;
-      if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
-          RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-        state.rendering_context_id = context_.current.rendering_context_id;
+      state.rendering_context_id = context_.current.rendering_context_id;
       OnUpdate(properties_->UpdatePerspective(*context_.current.transform,
                                               std::move(state)));
     } else {
@@ -1880,9 +1841,7 @@
         }
       }
 
-      if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
-          RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-        state.compositor_element_id = scrollable_area->GetCompositorElementId();
+      state.compositor_element_id = scrollable_area->GetCompositorElementId();
 
       state.overscroll_behavior = cc::OverscrollBehavior(
           static_cast<cc::OverscrollBehavior::OverscrollBehaviorType>(
@@ -1953,10 +1912,7 @@
           full_context_.direct_compositing_reasons &
           (CompositingReason::kRootScroller |
            CompositingReason::kScrollTimelineTarget);
-      if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
-          RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-        state.rendering_context_id = context_.current.rendering_context_id;
-      }
+      state.rendering_context_id = context_.current.rendering_context_id;
       state.scroll = properties_->Scroll();
       auto effective_change_type = properties_->UpdateScrollTranslation(
           *context_.current.transform, std::move(state));
@@ -2335,13 +2291,7 @@
 void FragmentPaintPropertyTreeBuilder::SetNeedsPaintPropertyUpdateIfNeeded() {
   if (object_.HasLayer()) {
     PaintLayer* layer = ToLayoutBoxModelObject(object_).Layer();
-    // With BGPT disabled, UpdateFilterReferenceBox gets called from
-    // CompositedLayerMapping::UpdateGraphicsLayerGeometry, but only
-    // for composited layers.
-    if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
-        layer->GetCompositingState() != kPaintsIntoOwnBacking) {
-      layer->UpdateFilterReferenceBox();
-    }
+    layer->UpdateFilterReferenceBox();
   }
 
   if (!object_.IsBox())
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
index 524cf4e..c814d520 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
@@ -717,10 +717,6 @@
 
 TEST_P(PaintPropertyTreeBuilderTest,
        TransformNodeWithActiveAnimationHasDirectCompositingReason) {
-  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
-      !RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    return;
-
   LoadTestData("transform-animation.html");
   EXPECT_TRUE(PaintPropertiesForElement("target")
                   ->Transform()
@@ -733,14 +729,8 @@
   // TODO(flackr): Verify that after https://crbug.com/900241 is fixed we no
   // longer create opacity or filter nodes for transform animations.
   EXPECT_NE(nullptr, PaintPropertiesForElement("target")->Transform());
-  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
-      RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-    EXPECT_NE(nullptr, PaintPropertiesForElement("target")->Effect());
-    EXPECT_NE(nullptr, PaintPropertiesForElement("target")->Filter());
-  } else {
-    EXPECT_EQ(nullptr, PaintPropertiesForElement("target")->Effect());
-    EXPECT_EQ(nullptr, PaintPropertiesForElement("target")->Filter());
-  }
+  EXPECT_NE(nullptr, PaintPropertiesForElement("target")->Effect());
+  EXPECT_NE(nullptr, PaintPropertiesForElement("target")->Filter());
 }
 
 TEST_P(PaintPropertyTreeBuilderTest,
@@ -750,19 +740,11 @@
   // longer create transform or filter nodes for opacity animations.
   EXPECT_NE(nullptr, PaintPropertiesForElement("target")->Transform());
   EXPECT_NE(nullptr, PaintPropertiesForElement("target")->Effect());
-  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
-      RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
-    EXPECT_NE(nullptr, PaintPropertiesForElement("target")->Filter());
-  else
-    EXPECT_EQ(nullptr, PaintPropertiesForElement("target")->Filter());
+  EXPECT_NE(nullptr, PaintPropertiesForElement("target")->Filter());
 }
 
 TEST_P(PaintPropertyTreeBuilderTest,
        EffectNodeWithActiveAnimationHasDirectCompositingReason) {
-  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
-      !RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    return;
-
   LoadTestData("opacity-animation.html");
   EXPECT_TRUE(PaintPropertiesForElement("target")
                   ->Effect()
@@ -3185,9 +3167,6 @@
 }
 
 TEST_P(PaintPropertyTreeBuilderTest, FlatteningIn3DContext) {
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    return;
-
   SetBodyInnerHTML(R"HTML(
     <div id="a" style="transform-style: preserve-3d">
       <div id="b" style="transform: translate3d(0, 0, 33px)">
@@ -4870,10 +4849,6 @@
 
 TEST_P(PaintPropertyTreeBuilderTest,
        TransformNodeNotAnimatedStillHasCompositorElementId) {
-  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
-      !RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    return;
-
   SetBodyInnerHTML("<div id='target' style='transform: translateX(2em)'></div");
   const ObjectPaintProperties* properties = PaintPropertiesForElement("target");
   EXPECT_TRUE(properties->Transform());
@@ -4883,10 +4858,6 @@
 
 TEST_P(PaintPropertyTreeBuilderTest,
        EffectNodeNotAnimatedStillHasCompositorElementId) {
-  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
-      !RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    return;
-
   SetBodyInnerHTML("<div id='target' style='opacity: 0.5'></div");
   const ObjectPaintProperties* properties = PaintPropertiesForElement("target");
   EXPECT_TRUE(properties->Effect());
@@ -4899,10 +4870,6 @@
 
 TEST_P(PaintPropertyTreeBuilderTest,
        TransformNodeAnimatedHasCompositorElementId) {
-  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
-      !RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    return;
-
   LoadTestData("transform-animation.html");
   const ObjectPaintProperties* properties = PaintPropertiesForElement("target");
   EXPECT_TRUE(properties->Transform());
@@ -4912,10 +4879,6 @@
 }
 
 TEST_P(PaintPropertyTreeBuilderTest, EffectNodeAnimatedHasCompositorElementId) {
-  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
-      !RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    return;
-
   LoadTestData("opacity-animation.html");
   const ObjectPaintProperties* properties = PaintPropertiesForElement("target");
   EXPECT_TRUE(properties->Effect());
@@ -4952,10 +4915,6 @@
 }
 
 TEST_P(PaintPropertyTreeBuilderTest, ScrollNodeHasCompositorElementId) {
-  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
-      !RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    return;
-
   SetBodyInnerHTML(R"HTML(
     <div id='target' style='overflow: auto; width: 100px; height: 100px'>
       <div style='width: 200px; height: 200px'></div>
@@ -5369,15 +5328,10 @@
   }
 
   const auto* transform = target_properties->Transform();
-  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
-      RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-    ASSERT_NE(nullptr, transform);
-    EXPECT_TRUE(transform->IsIdentity());
-    EXPECT_EQ(TransformPaintPropertyNode::BackfaceVisibility::kHidden,
-              transform->GetBackfaceVisibilityForTesting());
-  } else {
-    EXPECT_EQ(nullptr, transform);
-  }
+  ASSERT_NE(nullptr, transform);
+  EXPECT_TRUE(transform->IsIdentity());
+  EXPECT_EQ(TransformPaintPropertyNode::BackfaceVisibility::kHidden,
+            transform->GetBackfaceVisibilityForTesting());
 
   To<Element>(target->GetNode())->setAttribute(html_names::kStyleAttr, "");
   UpdateAllLifecyclePhasesForTest();
@@ -5591,11 +5545,10 @@
   opacity_element->setAttribute(html_names::kStyleAttr, "opacity: 0.5");
   GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
 
-  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
-      !RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-    // TODO(crbug.com/900241): In BlinkGenPropertyTrees (but not
-    // CompoisteAfterPaint) we create effect and filter nodes when the transform
-    // node needs compositing for will-change:transform, for crbug.com/942681.
+  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+    // TODO(crbug.com/900241): Without CompositeAfterPaint, we create effect and
+    // filter nodes when the transform node needs compositing for
+    // will-change:transform, for crbug.com/942681.
     EXPECT_FALSE(ToLayoutBoxModelObject(target)->Layer()->NeedsRepaint());
   } else {
     // All paint chunks contained by the new opacity effect node need to be
@@ -5670,9 +5623,7 @@
   )HTML");
 
   // When the root scrolls, there should be direct compositing reasons.
-  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
-      RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    EXPECT_TRUE(DocScrollTranslation()->HasDirectCompositingReasons());
+  EXPECT_TRUE(DocScrollTranslation()->HasDirectCompositingReasons());
 
   // Remove scrolling from the root.
   Element* force_scroll_element = GetDocument().getElementById("forceScroll");
@@ -5699,9 +5650,7 @@
   )HTML");
   UpdateAllLifecyclePhasesForTest();
 
-  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
-      RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    EXPECT_TRUE(DocScrollTranslation()->HasDirectCompositingReasons());
+  EXPECT_TRUE(DocScrollTranslation()->HasDirectCompositingReasons());
 
   // When the child iframe scrolls, there should not be direct compositing
   // reasons because only the root frame needs scrolling compositing reasons.
@@ -6466,9 +6415,7 @@
   const auto* transform = properties->Transform();
   ASSERT_NE(nullptr, transform);
   EXPECT_EQ(properties->PaintOffsetTranslation(), transform->Parent());
-  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
-      RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    EXPECT_TRUE(transform->HasDirectCompositingReasons());
+  EXPECT_TRUE(transform->HasDirectCompositingReasons());
 
   if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
     EXPECT_EQ(nullptr, properties->MaskClip());
@@ -6530,11 +6477,9 @@
 }
 
 TEST_P(PaintPropertyTreeBuilderTest, SimpleOpacityChangeDoesNotCausePacUpdate) {
-  // This is a BGPT test only.
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
-      // TODO(vmpstr): For CompositeAfterPaint, we don't seem to get a
-      // cc_effect, which we need to investigate.
-      RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+  // TODO(vmpstr): For CompositeAfterPaint, we don't seem to get a
+  // cc_effect, which we need to investigate.
+  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
     return;
 
   SetHtmlInnerHTML(R"HTML(
@@ -6587,10 +6532,8 @@
 }
 
 TEST_P(PaintPropertyTreeBuilderTest, SimpleScrollChangeDoesNotCausePacUpdate) {
-  // This is a BGPT test only.
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
-      // TODO(vmpstr): Make this test pass for CompositeAfterPaint.
-      RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+  // TODO(vmpstr): Make this test pass for CompositeAfterPaint.
+  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
     return;
 
   SetHtmlInnerHTML(R"HTML(
@@ -6686,15 +6629,10 @@
                                    .LocalBorderBoxProperties();
   EXPECT_EQ(clip_path_properties->MaskClip(),
             span_all_state.Clip().Parent()->Parent());
-  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-    // TODO(crbug.com/900241): In BlinkGenPropertyTrees/CompositeAfterPaint we
-    // create effect and filter nodes when the transform node needs compositing,
-    // for crbug.com/942681.
-    EXPECT_EQ(clip_path_properties->Effect(),
-              span_all_state.Effect().Parent()->Parent()->Parent());
-  } else {
-    EXPECT_EQ(clip_path_properties->Effect(), span_all_state.Effect().Parent());
-  }
+  // TODO(crbug.com/900241): We create effect and filter nodes when the
+  // transform node needs compositing, for crbug.com/942681.
+  EXPECT_EQ(clip_path_properties->Effect(),
+            span_all_state.Effect().Parent()->Parent()->Parent());
 }
 
 TEST_P(PaintPropertyTreeBuilderTest, VideoClipRect) {
@@ -6876,8 +6814,6 @@
 }
 
 TEST_P(PaintPropertyTreeBuilderTest, TransformAnimationAxisAlignment) {
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    return;
   SetBodyInnerHTML(R"HTML(
       <!DOCTYPE html>
       <style>
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc b/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
index 3903a41..82a23e8 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
@@ -1619,10 +1619,6 @@
 }
 
 TEST_P(PaintPropertyTreeUpdateTest, ChangeDuringAnimation) {
-  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
-      !RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    return;
-
   SetBodyInnerHTML(R"HTML(
       <!DOCTYPE html>
       <style>
@@ -1659,7 +1655,7 @@
   EXPECT_EQ(FloatPoint3D(50, 50, 0), transform_node->Origin());
   // Change of animation status should update PaintArtifactCompositor.
   auto* paint_artifact_compositor =
-      GetDocument().View()->GetPaintArtifactCompositorForTesting();
+      GetDocument().View()->GetPaintArtifactCompositor();
   EXPECT_TRUE(paint_artifact_compositor->NeedsUpdate());
   // PaintArtifactCompositor can't clear the NeedsUpdate flag by itself when
   // there is no cc::LayerTreeHost.
diff --git a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
index caccba06..481f857 100644
--- a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
+++ b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
@@ -247,11 +247,10 @@
 bool PrePaintTreeWalk::NeedsTreeBuilderContextUpdate(
     const LocalFrameView& frame_view,
     const PrePaintTreeWalkContext& context) {
-  if ((RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
-       RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) &&
-      frame_view.GetFrame().IsMainFrame() &&
-      frame_view.GetPage()->GetVisualViewport().NeedsPaintPropertyUpdate())
+  if (frame_view.GetFrame().IsMainFrame() &&
+      frame_view.GetPage()->GetVisualViewport().NeedsPaintPropertyUpdate()) {
     return true;
+  }
 
   return frame_view.GetLayoutView() &&
          (ObjectRequiresTreeBuilderContext(*frame_view.GetLayoutView()) ||
diff --git a/third_party/blink/renderer/core/paint/video_painter.cc b/third_party/blink/renderer/core/paint/video_painter.cc
index efc55f2..c3698d3 100644
--- a/third_party/blink/renderer/core/paint/video_painter.cc
+++ b/third_party/blink/renderer/core/paint/video_painter.cc
@@ -42,9 +42,8 @@
   content_box_rect.Move(paint_offset);
 
   // Since we may have changed the location of the replaced content, we need to
-  // notify PAC.
-  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
-      layout_video_.GetFrameView())
+  // notify PaintArtifactCompositor.
+  if (layout_video_.GetFrameView())
     layout_video_.GetFrameView()->SetPaintArtifactCompositorNeedsUpdate();
 
   // Video frames are only painted in software for printing or capturing node
diff --git a/third_party/blink/renderer/core/probe/core_probes.json5 b/third_party/blink/renderer/core/probe/core_probes.json5
index 7324fab..72894e0 100644
--- a/third_party/blink/renderer/core/probe/core_probes.json5
+++ b/third_party/blink/renderer/core/probe/core_probes.json5
@@ -107,7 +107,6 @@
     },
     InspectorLayerTreeAgent: {
       probes: [
-        "DidPaint",
         "LayerTreeDidChange",
         "LayerTreePainted",
       ]
diff --git a/third_party/blink/renderer/core/probe/core_probes.pidl b/third_party/blink/renderer/core/probe/core_probes.pidl
index 37b7945..a42bac5 100644
--- a/third_party/blink/renderer/core/probe/core_probes.pidl
+++ b/third_party/blink/renderer/core/probe/core_probes.pidl
@@ -83,8 +83,6 @@
   void DidFireWebGLWarning(Element*);
   void DidFireWebGLErrorOrWarning(Element*, const String& message);
   void DidResizeMainFrame(LocalFrame*);
-  /* This is for pre-BlinkGenPropertyTrees. TODO(wangxianzhu): Remove this function for BlinkGenPropertyTrees. */
-  void DidPaint(LocalFrame*, const cc::Layer*, const LayoutRect&);
   void ApplyAcceptLanguageOverride(ExecutionContext*, String* accept_language);
   void ApplyUserAgentOverride(CoreProbeSink*, String* user_agent);
   void DidBlockRequest(CoreProbeSink*, const ResourceRequest&, DocumentLoader*, const KURL& fetch_context_url, const FetchInitiatorInfo&, ResourceRequestBlockedReason, ResourceType);
diff --git a/third_party/blink/renderer/core/scheduler_integration_tests/frame_throttling_test.cc b/third_party/blink/renderer/core/scheduler_integration_tests/frame_throttling_test.cc
index cb1b2a1..e2f50be 100644
--- a/third_party/blink/renderer/core/scheduler_integration_tests/frame_throttling_test.cc
+++ b/third_party/blink/renderer/core/scheduler_integration_tests/frame_throttling_test.cc
@@ -1391,8 +1391,7 @@
 
 TEST_P(FrameThrottlingTest, GraphicsLayerCollection) {
   // This test is for BlinkGenPropertyTrees only.
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
-      RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
     return;
 
   SimRequest main_resource("https://example.com/", "text/html");
diff --git a/third_party/blink/renderer/core/svg/graphics/svg_image.cc b/third_party/blink/renderer/core/svg/graphics/svg_image.cc
index 01dd12d..d8d7af3e8 100644
--- a/third_party/blink/renderer/core/svg/graphics/svg_image.cc
+++ b/third_party/blink/renderer/core/svg/graphics/svg_image.cc
@@ -655,18 +655,14 @@
   LocalFrameView* frame_view = To<LocalFrame>(page_->MainFrame())->View();
   frame_view->UpdateAllLifecyclePhasesExceptPaint();
 
-  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
-      RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-    // For CAP/BGPT we run UpdateAnimations after the paint phase, but per the
-    // above comment, we don't want to run lifecycle through to paint for SVG
-    // images. Since we know SVG images never have composited animations we can
-    // update animations directly without worrying about including
-    // PaintArtifactCompositor analysis of whether animations should be
-    // composited.
-    DocumentAnimations::UpdateAnimations(
-        frame_view->GetLayoutView()->GetDocument(),
-        DocumentLifecycle::kLayoutClean, nullptr);
-  }
+  // We run UpdateAnimations after the paint phase, but per the above comment,
+  // we don't want to run lifecycle through to paint for SVG images. Since we
+  // know SVG images never have composited animations, we can update animations
+  // directly without worrying about including PaintArtifactCompositor's
+  // analysis of whether animations should be composited.
+  DocumentAnimations::UpdateAnimations(
+      frame_view->GetLayoutView()->GetDocument(),
+      DocumentLifecycle::kLayoutClean, nullptr);
 }
 
 void SVGImage::AdvanceAnimationForTesting() {
diff --git a/third_party/blink/renderer/core/testing/internals.cc b/third_party/blink/renderer/core/testing/internals.cc
index 38b6212..659bd8ae 100644
--- a/third_party/blink/renderer/core/testing/internals.cc
+++ b/third_party/blink/renderer/core/testing/internals.cc
@@ -1831,7 +1831,7 @@
   }
 
   if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-    auto* pac = document->View()->GetPaintArtifactCompositorForTesting();
+    auto* pac = document->View()->GetPaintArtifactCompositor();
     pac->EnableExtraDataForTesting();
     document->View()->UpdateAllLifecyclePhases(
         DocumentLifecycle::LifecycleUpdateReason::kTest);
@@ -2227,7 +2227,7 @@
       DocumentLifecycle::LifecycleUpdateReason::kTest);
 
   if (RuntimeEnabledFeatures::PaintNonFastScrollableRegionsEnabled()) {
-    auto* pac = document->View()->GetPaintArtifactCompositorForTesting();
+    auto* pac = document->View()->GetPaintArtifactCompositor();
     auto* layer_tree_host = pac->RootLayer()->layer_tree_host();
     // Ensure |cc::TransformTree| has updated the correct ToScreen transforms.
     layer_tree_host->UpdateLayers();
diff --git a/third_party/blink/renderer/core/xml/document_xml_tree_viewer.cc b/third_party/blink/renderer/core/xml/document_xml_tree_viewer.cc
index ab291a28..a2dad717 100644
--- a/third_party/blink/renderer/core/xml/document_xml_tree_viewer.cc
+++ b/third_party/blink/renderer/core/xml/document_xml_tree_viewer.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/xml/document_xml_tree_viewer.h"
 
+#include "third_party/blink/public/resources/grit/blink_resources.h"
 #include "third_party/blink/renderer/bindings/core/v8/sanitize_script_errors.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_source_code.h"
@@ -18,8 +19,9 @@
 
 void TransformDocumentToXMLTreeView(Document& document) {
   String script_string =
-      GetDataResourceAsASCIIString("DocumentXMLTreeViewer.js");
-  String css_string = GetDataResourceAsASCIIString("DocumentXMLTreeViewer.css");
+      UncompressResourceAsASCIIString(IDR_DOCUMENTXMLTREEVIEWER_JS);
+  String css_string =
+      UncompressResourceAsASCIIString(IDR_DOCUMENTXMLTREEVIEWER_CSS);
 
   v8::HandleScope handle_scope(V8PerIsolateData::MainThreadIsolate());
 
diff --git a/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc b/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
index 1a9ba17..103e9ee0 100644
--- a/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
+++ b/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
@@ -1472,9 +1472,15 @@
                             : network::mojom::CredentialsMode::kSameOrigin,
           response_);
 
-  HTTPHeaderMap::const_iterator end = response_.HttpHeaderFields().end();
-  for (HTTPHeaderMap::const_iterator it = response_.HttpHeaderFields().begin();
-       it != end; ++it) {
+  // "Let |headers| be the result of sorting |initialHeaders| in ascending
+  // order, with |a| being less than |b| if |a|’s name is legacy-uppercased-byte
+  // less than |b|’s name."
+  Vector<std::pair<String, String>> headers;
+  // Although we omit some headers in |response_.HttpHeaderFields()| below,
+  // we pre-allocate the buffer for performance.
+  headers.ReserveInitialCapacity(response_.HttpHeaderFields().size());
+  for (auto it = response_.HttpHeaderFields().begin();
+       it != response_.HttpHeaderFields().end(); ++it) {
     // Hide any headers whose name is a forbidden response-header name.
     // This is required for all kinds of filtered responses.
     //
@@ -1491,10 +1497,18 @@
       continue;
     }
 
-    string_builder.Append(it->key.LowerASCII());
+    headers.push_back(std::make_pair(it->key.UpperASCII(), it->value));
+  }
+  std::sort(headers.begin(), headers.end(),
+            [](const std::pair<String, String>& x,
+               const std::pair<String, String>& y) {
+              return CodeUnitCompareLessThan(x.first, y.first);
+            });
+  for (const auto& header : headers) {
+    string_builder.Append(header.first.LowerASCII());
     string_builder.Append(':');
     string_builder.Append(' ');
-    string_builder.Append(it->value);
+    string_builder.Append(header.second);
     string_builder.Append('\r');
     string_builder.Append('\n');
   }
diff --git a/third_party/blink/renderer/devtools/front_end/ui/SoftDropDown.js b/third_party/blink/renderer/devtools/front_end/ui/SoftDropDown.js
index 799b2e2..b41831f 100644
--- a/third_party/blink/renderer/devtools/front_end/ui/SoftDropDown.js
+++ b/third_party/blink/renderer/devtools/front_end/ui/SoftDropDown.js
@@ -22,6 +22,7 @@
     this._titleElement = this.element.createChild('span', 'title');
     const dropdownArrowIcon = UI.Icon.create('smallicon-triangle-down');
     this.element.appendChild(dropdownArrowIcon);
+    UI.ARIAUtils.setExpanded(this.element, false);
 
     this._glassPane = new UI.GlassPane();
     this._glassPane.setMarginBehavior(UI.GlassPane.MarginBehavior.NoMargin);
@@ -33,7 +34,9 @@
     this._rowHeight = 36;
     this._width = 315;
     UI.createShadowRootWithCoreStyles(this._glassPane.contentElement, 'ui/softDropDown.css')
+        .createChild('div', 'list-container')  // issue #972755
         .appendChild(this._list.element);
+    UI.ARIAUtils.markAsMenu(this._list.element);
 
     this._listWasShowing200msAgo = false;
     this.element.addEventListener('mousedown', event => {
@@ -42,8 +45,9 @@
       else if (!this.element.disabled)
         this._show(event);
     }, false);
-    this.element.addEventListener('keydown', this._onKeyDown.bind(this), false);
-    this.element.addEventListener('focusout', this._hide.bind(this), false);
+    this.element.addEventListener('keydown', this._onKeyDownButton.bind(this), false);
+    this._list.element.addEventListener('keydown', this._onKeyDownList.bind(this), false);
+    this._list.element.addEventListener('focusout', this._hide.bind(this), false);
     this._list.element.addEventListener('mousedown', event => event.consume(true), false);
     this._list.element.addEventListener('mouseup', event => {
       if (event.target === this._list.element)
@@ -65,10 +69,11 @@
       return;
     this._glassPane.setContentAnchorBox(this.element.boxInWindow());
     this._glassPane.show(/** @type {!Document} **/ (this.element.ownerDocument));
+    this._list.element.focus();
+    UI.ARIAUtils.setExpanded(this.element, true);
     this._updateGlasspaneSize();
     if (this._selectedItem)
       this._list.selectItem(this._selectedItem);
-    this.element.focus();
     event.consume(true);
     setTimeout(() => this._listWasShowing200msAgo = true, 200);
   }
@@ -86,29 +91,52 @@
     setTimeout(() => this._listWasShowing200msAgo = false, 200);
     this._glassPane.hide();
     this._list.selectItem(null);
+    UI.ARIAUtils.setExpanded(this.element, false);
+    this.element.focus();
     event.consume(true);
   }
 
   /**
    * @param {!Event} event
    */
-  _onKeyDown(event) {
+  _onKeyDownButton(event) {
+    let handled = false;
+    switch (event.key) {
+      case 'ArrowUp':
+        this._show(event);
+        this._list.selectItemNextPage();
+        handled = true;
+        break;
+      case 'ArrowDown':
+        this._show(event);
+        this._list.selectItemPreviousPage();
+        handled = true;
+        break;
+      case 'Enter':
+      case ' ':
+        this._show(event);
+        handled = true;
+        break;
+      default:
+        break;
+    }
+
+    if (handled)
+      event.consume(true);
+  }
+
+  /**
+   * @param {!Event} event
+   */
+  _onKeyDownList(event) {
     let handled = false;
     switch (event.key) {
       case 'ArrowLeft':
-      case 'ArrowUp':
         handled = this._list.selectPreviousItem(false, false);
         break;
       case 'ArrowRight':
-      case 'ArrowDown':
         handled = this._list.selectNextItem(false, false);
         break;
-      case 'PageUp':
-        handled = this._list.selectItemPreviousPage(false);
-        break;
-      case 'PageDown':
-        handled = this._list.selectItemNextPage(false);
-        break;
       case 'Home':
         for (let i = 0; i < this._model.length; i++) {
           if (this.isItemSelectable(this._model.at(i))) {
@@ -129,23 +157,14 @@
         break;
       case 'Escape':
         this._hide(event);
+        handled = true;
         break;
       case 'Tab':
-        if (!this._glassPane.isShowing())
-          break;
-        this._selectHighlightedItem();
-        this._hide(event);
-        break;
       case 'Enter':
-        if (!this._glassPane.isShowing()) {
-          this._show(event);
-          break;
-        }
+      case ' ':
         this._selectHighlightedItem();
         this._hide(event);
-        break;
-      case ' ':
-        this._show(event);
+        handled = true;
         break;
       default:
         if (event.key.length === 1) {
@@ -163,10 +182,8 @@
         break;
     }
 
-    if (handled) {
+    if (handled)
       event.consume(true);
-      this._selectHighlightedItem();
-    }
   }
 
   /**
@@ -231,6 +248,7 @@
     element.classList.toggle('disabled', !this._delegate.isItemSelectable(item));
     element.classList.toggle('highlighted', this._list.selectedItem() === item);
 
+    UI.ARIAUtils.markAsMenuItem(element);
     element.appendChild(this._delegate.createElementForItem(item));
 
     return element;
@@ -266,6 +284,8 @@
       fromElement.classList.remove('highlighted');
     if (toElement)
       toElement.classList.add('highlighted');
+
+    UI.ARIAUtils.setActiveDescendant(this._list.element, toElement);
     this._delegate.highlightedItemChanged(
         from, to, fromElement && fromElement.firstElementChild, toElement && toElement.firstElementChild);
   }
diff --git a/third_party/blink/renderer/devtools/front_end/ui/softDropDown.css b/third_party/blink/renderer/devtools/front_end/ui/softDropDown.css
index 7b14baf..c3a80d7 100644
--- a/third_party/blink/renderer/devtools/front_end/ui/softDropDown.css
+++ b/third_party/blink/renderer/devtools/front_end/ui/softDropDown.css
@@ -20,3 +20,7 @@
     color: var(--selection-fg-color);
     background-color: var(--selection-bg-color);
 }
+
+.list-container {
+    width: 100%;
+}
diff --git a/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.cc b/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.cc
index 4bad2ce..e963f70 100644
--- a/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.cc
+++ b/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.h"
 
+#include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/blink/public/platform/interface_provider.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
@@ -20,12 +21,14 @@
 // connection as basis for all connections to channels from the same thread. The
 // actual connections used to send/receive messages are then created using
 // associated interfaces, ensuring proper message ordering.
-mojom::blink::BroadcastChannelProviderPtr& GetThreadSpecificProvider() {
+mojo::Remote<mojom::blink::BroadcastChannelProvider>&
+GetThreadSpecificProvider() {
   DEFINE_THREAD_SAFE_STATIC_LOCAL(
-      ThreadSpecific<mojom::blink::BroadcastChannelProviderPtr>, provider, ());
+      ThreadSpecific<mojo::Remote<mojom::blink::BroadcastChannelProvider>>,
+      provider, ());
   if (!provider.IsSet()) {
     Platform::Current()->GetInterfaceProvider()->GetInterface(
-        mojo::MakeRequest(&*provider));
+        provider->BindNewPipeAndPassReceiver());
   }
   return *provider;
 }
@@ -55,7 +58,7 @@
 
 void BroadcastChannel::postMessage(const ScriptValue& message,
                                    ExceptionState& exception_state) {
-  if (!binding_.is_bound()) {
+  if (!receiver_.is_bound()) {
     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
                                       "Channel is closed");
     return;
@@ -73,8 +76,8 @@
 
 void BroadcastChannel::close() {
   remote_client_.reset();
-  if (binding_.is_bound())
-    binding_.Close();
+  if (receiver_.is_bound())
+    receiver_.reset();
   feature_handle_for_scheduler_.reset();
 }
 
@@ -83,7 +86,7 @@
 }
 
 bool BroadcastChannel::HasPendingActivity() const {
-  return binding_.is_bound() && HasEventListeners(event_type_names::kMessage);
+  return receiver_.is_bound() && HasEventListeners(event_type_names::kMessage);
 }
 
 void BroadcastChannel::ContextDestroyed(ExecutionContext*) {
@@ -128,17 +131,13 @@
     : ContextLifecycleObserver(execution_context),
       origin_(execution_context->GetSecurityOrigin()),
       name_(name),
-      binding_(this),
       feature_handle_for_scheduler_(
           execution_context->GetScheduler()->RegisterFeature(
               SchedulingPolicy::Feature::kBroadcastChannel,
               {SchedulingPolicy::RecordMetricsForBackForwardCache()})) {
-  mojom::blink::BroadcastChannelProviderPtr& provider =
+  mojo::Remote<mojom::blink::BroadcastChannelProvider>& provider =
       GetThreadSpecificProvider();
 
-  // Local BroadcastChannelClient for messages send from the browser to this
-  // channel.
-  mojom::blink::BroadcastChannelClientAssociatedPtrInfo local_client_info;
   // Note: We cannot associate per-frame task runner here, but postTask
   //       to it manually via EnqueueEvent, since the current expectation
   //       is to receive messages even after close for which queued before
@@ -146,18 +145,17 @@
   //       https://github.com/whatwg/html/issues/1319
   //       Relying on Mojo binding will cancel the enqueued messages
   //       at close().
-  binding_.Bind(mojo::MakeRequest(&local_client_info));
-  binding_.set_connection_error_handler(
-      WTF::Bind(&BroadcastChannel::OnError, WrapWeakPersistent(this)));
 
-  // Remote BroadcastChannelClient for messages send from this channel to the
-  // browser.
-  auto remote_cient_request = mojo::MakeRequest(&remote_client_);
-  remote_client_.set_connection_error_handler(
+  // Local BroadcastChannelClient for messages send from the browser to this
+  // channel and Remote BroadcastChannelClient for messages send from this
+  // channel to the browser.
+  provider->ConnectToChannel(origin_, name_,
+                             receiver_.BindNewEndpointAndPassRemote(),
+                             remote_client_.BindNewEndpointAndPassReceiver());
+  receiver_.set_disconnect_handler(
       WTF::Bind(&BroadcastChannel::OnError, WrapWeakPersistent(this)));
-
-  provider->ConnectToChannel(origin_, name_, std::move(local_client_info),
-                             std::move(remote_cient_request));
+  remote_client_.set_disconnect_handler(
+      WTF::Bind(&BroadcastChannel::OnError, WrapWeakPersistent(this)));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.h b/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.h
index 6db0dfa..b0c2c523 100644
--- a/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.h
+++ b/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.h
@@ -6,7 +6,8 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_BROADCASTCHANNEL_BROADCAST_CHANNEL_H_
 
 #include "base/macros.h"
-#include "mojo/public/cpp/bindings/associated_binding.h"
+#include "mojo/public/cpp/bindings/associated_receiver.h"
+#include "mojo/public/cpp/bindings/associated_remote.h"
 #include "third_party/blink/public/mojom/broadcastchannel/broadcast_channel.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
 #include "third_party/blink/renderer/core/dom/events/event_target.h"
@@ -66,8 +67,9 @@
   scoped_refptr<const SecurityOrigin> origin_;
   String name_;
 
-  mojo::AssociatedBinding<mojom::blink::BroadcastChannelClient> binding_;
-  mojom::blink::BroadcastChannelClientAssociatedPtr remote_client_;
+  mojo::AssociatedReceiver<mojom::blink::BroadcastChannelClient> receiver_{
+      this};
+  mojo::AssociatedRemote<mojom::blink::BroadcastChannelClient> remote_client_;
 
   // Notifies the scheduler that a broadcast channel is active.
   FrameOrWorkerScheduler::SchedulingAffectingFeatureHandle
diff --git a/third_party/blink/renderer/modules/idle/idle_detector.cc b/third_party/blink/renderer/modules/idle/idle_detector.cc
index be8c8ea..c80c440 100644
--- a/third_party/blink/renderer/modules/idle/idle_detector.cc
+++ b/third_party/blink/renderer/modules/idle/idle_detector.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "third_party/blink/public/mojom/idle/idle_manager.mojom-blink.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
@@ -52,7 +53,7 @@
 }
 
 IdleDetector::IdleDetector(ExecutionContext* context, base::TimeDelta threshold)
-    : ContextClient(context), threshold_(threshold), binding_(this) {}
+    : ContextClient(context), threshold_(threshold), receiver_(this) {}
 
 IdleDetector::~IdleDetector() = default;
 
@@ -98,7 +99,7 @@
 }
 
 void IdleDetector::StartMonitoring() {
-  if (binding_.is_bound()) {
+  if (receiver_.is_bound()) {
     return;
   }
 
@@ -108,19 +109,20 @@
 
   if (!service_) {
     GetExecutionContext()->GetInterfaceProvider()->GetInterface(
-        mojo::MakeRequest(&service_, task_runner));
+        service_.BindNewPipeAndPassReceiver());
   }
 
-  mojom::blink::IdleMonitorPtr monitor_ptr;
-  binding_.Bind(mojo::MakeRequest(&monitor_ptr, task_runner), task_runner);
+  mojo::PendingRemote<mojom::blink::IdleMonitor> idle_monitor_remote;
+  receiver_.Bind(idle_monitor_remote.InitWithNewPipeAndPassReceiver(),
+                 task_runner);
 
   service_->AddMonitor(
-      threshold_, std::move(monitor_ptr),
+      threshold_, std::move(idle_monitor_remote),
       WTF::Bind(&IdleDetector::OnAddMonitor, WrapWeakPersistent(this)));
 }
 
 void IdleDetector::StopMonitoring() {
-  binding_.Close();
+  receiver_.reset();
 }
 
 void IdleDetector::OnAddMonitor(mojom::blink::IdleStatePtr state) {
@@ -132,7 +134,7 @@
 }
 
 void IdleDetector::Update(mojom::blink::IdleStatePtr state) {
-  DCHECK(binding_.is_bound());
+  DCHECK(receiver_.is_bound());
   if (!GetExecutionContext() || GetExecutionContext()->IsContextDestroyed())
     return;
 
diff --git a/third_party/blink/renderer/modules/idle/idle_detector.h b/third_party/blink/renderer/modules/idle/idle_detector.h
index 67cf6775..95786de 100644
--- a/third_party/blink/renderer/modules/idle/idle_detector.h
+++ b/third_party/blink/renderer/modules/idle/idle_detector.h
@@ -6,7 +6,8 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_IDLE_IDLE_DETECTOR_H_
 
 #include "base/macros.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/blink/public/mojom/idle/idle_manager.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
@@ -69,12 +70,12 @@
 
   // Holds a pipe which the service uses to notify this object
   // when the idle state has changed.
-  mojo::Binding<mojom::blink::IdleMonitor> binding_;
+  mojo::Receiver<mojom::blink::IdleMonitor> receiver_;
 
   void StartMonitoring();
   void StopMonitoring();
 
-  mojom::blink::IdleManagerPtr service_;
+  mojo::Remote<mojom::blink::IdleManager> service_;
 
   DISALLOW_COPY_AND_ASSIGN(IdleDetector);
 };
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.cc b/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.cc
index 8f7d836..2f74d7c 100644
--- a/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.cc
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.cc
@@ -192,12 +192,9 @@
     // Post with CrossThreadBind here, instead of CrossThreadBindOnce,
     // otherwise the |new_frame_callback_| ivar can be nulled out
     // unintentionally.
-    //
-    // TODO(crbug.com/964922): Consider cloning |new_frame_callback_|
-    // and use CrossThreadBind
     PostCrossThreadTask(
         *io_task_runner_, FROM_HERE,
-        CrossThreadBindRepeating(new_frame_callback_, frame, current_time));
+        CrossThreadBindOnce(new_frame_callback_, frame, current_time));
   }
 
   // Calculate the time in the future where the next frame should be created.
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source_test.cc b/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source_test.cc
index 49a8fa4..9ba6db13 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source_test.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source_test.cc
@@ -54,7 +54,7 @@
   void SetRunning(bool is_running) {
     PostCrossThreadTask(*scheduler::GetSingleThreadTaskRunnerForTesting(),
                         FROM_HERE,
-                        CrossThreadBindRepeating(running_cb_, is_running));
+                        CrossThreadBindOnce(running_cb_, is_running));
   }
   const media::VideoCaptureParams& capture_params() const {
     return capture_params_;
@@ -246,9 +246,9 @@
   const scoped_refptr<media::VideoFrame> frame =
       media::VideoFrame::CreateBlackFrame(gfx::Size(2, 2));
   frame->metadata()->SetDouble(media::VideoFrameMetadata::FRAME_RATE, 30.0);
-  PostCrossThreadTask(*Platform::Current()->GetIOTaskRunner(), FROM_HERE,
-                      CrossThreadBindRepeating(deliver_frame_cb, frame,
-                                               reference_capture_time));
+  PostCrossThreadTask(
+      *Platform::Current()->GetIOTaskRunner(), FROM_HERE,
+      CrossThreadBindOnce(deliver_frame_cb, frame, reference_capture_time));
   run_loop.Run();
   fake_sink.DisconnectFromTrack();
   EXPECT_EQ(reference_capture_time, capture_time);
diff --git a/third_party/blink/renderer/modules/nfc/nfc.cc b/third_party/blink/renderer/modules/nfc/nfc.cc
index 8126d1fe..a1915f99 100644
--- a/third_party/blink/renderer/modules/nfc/nfc.cc
+++ b/third_party/blink/renderer/modules/nfc/nfc.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
@@ -29,8 +30,7 @@
 
 NFC::NFC(LocalFrame* frame)
     : PageVisibilityObserver(frame->GetPage()),
-      ContextLifecycleObserver(frame->GetDocument()),
-      client_binding_(this) {
+      ContextLifecycleObserver(frame->GetDocument()) {
   String error_message;
 
   // Only connect to NFC if we are in a context that supports it.
@@ -40,12 +40,11 @@
   // See https://bit.ly/2S0zRAS for task types.
   auto task_runner = frame->GetTaskRunner(TaskType::kMiscPlatformAPI);
   frame->GetInterfaceProvider().GetInterface(
-      mojo::MakeRequest(&nfc_, task_runner));
-  nfc_.set_connection_error_handler(
+      nfc_remote_.BindNewPipeAndPassReceiver());
+  nfc_remote_.set_disconnect_handler(
       WTF::Bind(&NFC::OnConnectionError, WrapWeakPersistent(this)));
-  device::mojom::blink::NFCClientPtr client;
-  client_binding_.Bind(mojo::MakeRequest(&client, task_runner), task_runner);
-  nfc_->SetClient(std::move(client));
+  nfc_remote_->SetClient(
+      client_receiver_.BindNewPipeAndPassRemote(task_runner));
 }
 
 NFC* NFC::Create(LocalFrame* frame) {
@@ -60,11 +59,11 @@
 }
 
 void NFC::Dispose() {
-  client_binding_.Close();
+  client_receiver_.reset();
 }
 
 void NFC::ContextDestroyed(ExecutionContext*) {
-  nfc_.reset();
+  nfc_remote_.reset();
   requests_.clear();
   callbacks_.clear();
 }
@@ -121,9 +120,9 @@
   requests_.insert(resolver);
   auto callback = WTF::Bind(&NFC::OnRequestCompleted, WrapPersistent(this),
                             WrapPersistent(resolver));
-  nfc_->Push(std::move(message),
-             device::mojom::blink::NFCPushOptions::From(options),
-             std::move(callback));
+  nfc_remote_->Push(std::move(message),
+                    device::mojom::blink::NFCPushOptions::From(options),
+                    std::move(callback));
 
   return resolver->Promise();
 }
@@ -138,7 +137,7 @@
   requests_.insert(resolver);
   auto callback = WTF::Bind(&NFC::OnRequestCompleted, WrapPersistent(this),
                             WrapPersistent(resolver));
-  nfc_->CancelPush(StringToNFCPushTarget(target), std::move(callback));
+  nfc_remote_->CancelPush(StringToNFCPushTarget(target), std::move(callback));
 
   return resolver->Promise();
 }
@@ -168,8 +167,8 @@
   auto watch_callback = WTF::Bind(&NFC::OnWatchRegistered, WrapPersistent(this),
                                   WrapPersistent(callback),
                                   WrapPersistent(resolver), next_watch_id_);
-  nfc_->Watch(device::mojom::blink::NFCReaderOptions::From(options),
-              next_watch_id_, std::move(watch_callback));
+  nfc_remote_->Watch(device::mojom::blink::NFCReaderOptions::From(options),
+                     next_watch_id_, std::move(watch_callback));
   next_watch_id_++;
   return resolver->Promise();
 }
@@ -190,9 +189,9 @@
   callbacks_.erase(id);
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
   requests_.insert(resolver);
-  nfc_->CancelWatch(id,
-                    WTF::Bind(&NFC::OnRequestCompleted, WrapPersistent(this),
-                              WrapPersistent(resolver)));
+  nfc_remote_->CancelWatch(
+      id, WTF::Bind(&NFC::OnRequestCompleted, WrapPersistent(this),
+                    WrapPersistent(resolver)));
   return resolver->Promise();
 }
 
@@ -206,23 +205,23 @@
   callbacks_.clear();
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
   requests_.insert(resolver);
-  nfc_->CancelAllWatches(WTF::Bind(&NFC::OnRequestCompleted,
-                                   WrapPersistent(this),
-                                   WrapPersistent(resolver)));
+  nfc_remote_->CancelAllWatches(WTF::Bind(&NFC::OnRequestCompleted,
+                                          WrapPersistent(this),
+                                          WrapPersistent(resolver)));
   return resolver->Promise();
 }
 
 void NFC::PageVisibilityChanged() {
   // If service is not initialized, there cannot be any pending NFC activities
-  if (!nfc_)
+  if (!nfc_remote_)
     return;
 
   // NFC operations should be suspended.
   // https://w3c.github.io/web-nfc/#nfc-suspended
   if (GetPage()->IsPageVisible())
-    nfc_->ResumeNFCOperations();
+    nfc_remote_->ResumeNFCOperations();
   else
-    nfc_->SuspendNFCOperations();
+    nfc_remote_->SuspendNFCOperations();
 }
 
 void NFC::OnRequestCompleted(ScriptPromiseResolver* resolver,
@@ -238,8 +237,8 @@
 }
 
 void NFC::OnConnectionError() {
-  nfc_.reset();
-  client_binding_.Close();
+  nfc_remote_.reset();
+  client_receiver_.reset();
   callbacks_.clear();
 
   // If NFCService is not available or disappears when NFC hardware is
@@ -294,7 +293,7 @@
                           DOMExceptionCode::kNotAllowedError, error_message));
   }
 
-  if (!nfc_) {
+  if (!nfc_remote_) {
     return ScriptPromise::RejectWithDOMException(
         script_state,
         MakeGarbageCollected<DOMException>(DOMExceptionCode::kNotSupportedError,
diff --git a/third_party/blink/renderer/modules/nfc/nfc.h b/third_party/blink/renderer/modules/nfc/nfc.h
index 4a4ac01..d979cb0 100644
--- a/third_party/blink/renderer/modules/nfc/nfc.h
+++ b/third_party/blink/renderer/modules/nfc/nfc.h
@@ -5,7 +5,8 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_NFC_NFC_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_NFC_NFC_H_
 
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/device/public/mojom/nfc.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_message_callback.h"
@@ -88,8 +89,8 @@
                device::mojom::blink::NDEFMessagePtr) override;
 
  private:
-  device::mojom::blink::NFCPtr nfc_;
-  mojo::Binding<device::mojom::blink::NFCClient> client_binding_;
+  mojo::Remote<device::mojom::blink::NFC> nfc_remote_;
+  mojo::Receiver<device::mojom::blink::NFCClient> client_receiver_{this};
   HeapHashSet<Member<ScriptPromiseResolver>> requests_;
   using WatchCallbacksMap = HeapHashMap<uint32_t, Member<V8MessageCallback>>;
   WatchCallbacksMap callbacks_;
diff --git a/third_party/blink/renderer/modules/nfc/nfc_proxy.cc b/third_party/blink/renderer/modules/nfc/nfc_proxy.cc
index 1a1ce084..28ac909 100644
--- a/third_party/blink/renderer/modules/nfc/nfc_proxy.cc
+++ b/third_party/blink/renderer/modules/nfc/nfc_proxy.cc
@@ -38,12 +38,12 @@
     : PageVisibilityObserver(document.GetPage()),
       FocusChangedObserver(document.GetPage()),
       Supplement<Document>(document),
-      client_binding_(this) {}
+      client_receiver_(this) {}
 
 NFCProxy::~NFCProxy() = default;
 
 void NFCProxy::Dispose() {
-  client_binding_.Close();
+  client_receiver_.reset();
 }
 
 void NFCProxy::Trace(blink::Visitor* visitor) {
@@ -60,10 +60,11 @@
     return;
 
   EnsureMojoConnection();
-  nfc_->Watch(device::mojom::blink::NFCReaderOptions::From(reader->options()),
-              next_watch_id_,
-              WTF::Bind(&NFCProxy::OnReaderRegistered, WrapPersistent(this),
-                        WrapPersistent(reader), next_watch_id_));
+  nfc_remote_->Watch(
+      device::mojom::blink::NFCReaderOptions::From(reader->options()),
+      next_watch_id_,
+      WTF::Bind(&NFCProxy::OnReaderRegistered, WrapPersistent(this),
+                WrapPersistent(reader), next_watch_id_));
   readers_.insert(reader, next_watch_id_);
   next_watch_id_++;
 }
@@ -72,10 +73,10 @@
   DCHECK(reader);
   auto iter = readers_.find(reader);
   if (iter != readers_.end()) {
-    if (nfc_) {
+    if (nfc_remote_) {
       // We do not need to notify |reader| of anything.
-      nfc_->CancelWatch(iter->value,
-                        device::mojom::blink::NFC::CancelWatchCallback());
+      nfc_remote_->CancelWatch(
+          iter->value, device::mojom::blink::NFC::CancelWatchCallback());
     }
     readers_.erase(iter);
   }
@@ -95,14 +96,14 @@
                     device::mojom::blink::NFCPushOptionsPtr options,
                     device::mojom::blink::NFC::PushCallback cb) {
   EnsureMojoConnection();
-  nfc_->Push(std::move(message), std::move(options), std::move(cb));
+  nfc_remote_->Push(std::move(message), std::move(options), std::move(cb));
 }
 
 void NFCProxy::CancelPush(
     const String& target,
     device::mojom::blink::NFC::CancelPushCallback callback) {
-  DCHECK(nfc_);
-  nfc_->CancelPush(StringToNFCPushTarget(target), std::move(callback));
+  DCHECK(nfc_remote_);
+  nfc_remote_->CancelPush(StringToNFCPushTarget(target), std::move(callback));
 }
 
 // device::mojom::blink::NFCClient implementation.
@@ -153,7 +154,7 @@
 
 void NFCProxy::UpdateSuspendedStatus() {
   // If service is not initialized, there cannot be any pending NFC activities.
-  if (!nfc_)
+  if (!nfc_remote_)
     return;
 
   // NFC operations should be suspended.
@@ -161,9 +162,9 @@
   // TODO(https://crbug.com/520391): Suspend/Resume NFC in the browser process
   // instead to prevent a compromised renderer from using NFC in the background.
   if (ShouldSuspendNFC())
-    nfc_->SuspendNFCOperations();
+    nfc_remote_->SuspendNFCOperations();
   else
-    nfc_->ResumeNFCOperations();
+    nfc_remote_->ResumeNFCOperations();
 }
 
 bool NFCProxy::ShouldSuspendNFC() const {
@@ -183,27 +184,25 @@
 }
 
 void NFCProxy::EnsureMojoConnection() {
-  if (nfc_)
+  if (nfc_remote_)
     return;
 
+  GetSupplementable()->GetInterfaceProvider()->GetInterface(
+      nfc_remote_.BindNewPipeAndPassReceiver());
+  nfc_remote_.set_disconnect_handler(
+      WTF::Bind(&NFCProxy::OnMojoConnectionError, WrapWeakPersistent(this)));
+
   // See https://bit.ly/2S0zRAS for task types.
   auto task_runner =
       GetSupplementable()->GetTaskRunner(TaskType::kMiscPlatformAPI);
-  GetSupplementable()->GetInterfaceProvider()->GetInterface(
-      mojo::MakeRequest(&nfc_, task_runner));
-  nfc_.set_connection_error_handler(
-      WTF::Bind(&NFCProxy::OnMojoConnectionError, WrapWeakPersistent(this)));
-
   // Set client for OnWatch event.
-  DCHECK(!client_binding_);
-  device::mojom::blink::NFCClientPtr client;
-  client_binding_.Bind(mojo::MakeRequest(&client, task_runner), task_runner);
-  nfc_->SetClient(std::move(client));
+  nfc_remote_->SetClient(
+      client_receiver_.BindNewPipeAndPassRemote(task_runner));
 }
 
 void NFCProxy::OnMojoConnectionError() {
-  nfc_.reset();
-  client_binding_.Close();
+  nfc_remote_.reset();
+  client_receiver_.reset();
 
   // Notify all active readers about the connection error and clear the list.
   ReaderMap readers = std::move(readers_);
diff --git a/third_party/blink/renderer/modules/nfc/nfc_proxy.h b/third_party/blink/renderer/modules/nfc/nfc_proxy.h
index 28c2ccd1ae..f2c6ed07 100644
--- a/third_party/blink/renderer/modules/nfc/nfc_proxy.h
+++ b/third_party/blink/renderer/modules/nfc/nfc_proxy.h
@@ -5,7 +5,8 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_NFC_NFC_PROXY_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_NFC_NFC_PROXY_H_
 
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/device/public/mojom/nfc.mojom-blink.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/page/focus_changed_observer.h"
@@ -90,8 +91,8 @@
   using WriterSet = HeapHashSet<WeakMember<NFCWriter>>;
   WriterSet writers_;
 
-  device::mojom::blink::NFCPtr nfc_;
-  mojo::Binding<device::mojom::blink::NFCClient> client_binding_;
+  mojo::Remote<device::mojom::blink::NFC> nfc_remote_;
+  mojo::Receiver<device::mojom::blink::NFCClient> client_receiver_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/nfc/nfc_proxy_test.cc b/third_party/blink/renderer/modules/nfc/nfc_proxy_test.cc
index c873865c..c23a81d2 100644
--- a/third_party/blink/renderer/modules/nfc/nfc_proxy_test.cc
+++ b/third_party/blink/renderer/modules/nfc/nfc_proxy_test.cc
@@ -8,6 +8,7 @@
 
 #include "base/run_loop.h"
 #include "base/test/bind_test_util.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
@@ -57,20 +58,18 @@
 
 class FakeNfcService : public device::mojom::blink::NFC {
  public:
-  FakeNfcService() : binding_(this) {}
+  FakeNfcService() : receiver_(this) {}
   ~FakeNfcService() override = default;
 
   void BindRequest(mojo::ScopedMessagePipeHandle handle) {
-    DCHECK(!binding_.is_bound());
-    binding_.Bind(device::mojom::blink::NFCRequest(std::move(handle)));
-    binding_.set_connection_error_handler(
+    DCHECK(!receiver_.is_bound());
+    receiver_.Bind(device::mojom::blink::NFCRequest(std::move(handle)));
+    receiver_.set_disconnect_handler(
         WTF::Bind(&FakeNfcService::OnConnectionError, WTF::Unretained(this)));
   }
 
   void OnConnectionError() {
-    if (binding_.is_bound())
-      binding_.Unbind();
-
+    receiver_.reset();
     client_.reset();
   }
 
@@ -106,8 +105,9 @@
 
  private:
   // Override methods from device::mojom::blink::NFC.
-  void SetClient(device::mojom::blink::NFCClientPtr client) override {
-    client_ = std::move(client);
+  void SetClient(
+      mojo::PendingRemote<device::mojom::blink::NFCClient> client) override {
+    client_.Bind(std::move(client));
   }
   void Push(device::mojom::blink::NDEFMessagePtr message,
             device::mojom::blink::NFCPushOptionsPtr options,
@@ -141,9 +141,9 @@
   void ResumeNFCOperations() override {}
 
   device::mojom::blink::NDEFMessagePtr tag_message_;
-  device::mojom::blink::NFCClientPtr client_;
+  mojo::Remote<device::mojom::blink::NFCClient> client_;
   std::map<uint32_t, device::mojom::blink::NFCReaderOptionsPtr> watches_;
-  mojo::Binding<device::mojom::blink::NFC> binding_;
+  mojo::Receiver<device::mojom::blink::NFC> receiver_;
 };
 
 // Overrides requests for NFC mojo requests with FakeNfcService instances.
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
index 5f7850a1..2c62278 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
@@ -1277,9 +1277,9 @@
   // We use CrossThreadBindOnce() here because the callback may be destroyed on
   // the main thread if the worker thread has already terminated.
   To<ServiceWorkerGlobalScopeProxy>(ReportingProxy())
-      .RequestTermination(ConvertToBaseOnceCallback(
+      .RequestTermination(
           CrossThreadBindOnce(&ServiceWorkerGlobalScope::OnRequestedTermination,
-                              WrapCrossThreadWeakPersistent(this))));
+                              WrapCrossThreadWeakPersistent(this)));
 }
 
 void ServiceWorkerGlobalScope::OnRequestedTermination(bool will_be_terminated) {
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
index 69fb50e..0f2aa72 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
@@ -301,9 +301,9 @@
 }
 
 void ServiceWorkerGlobalScopeProxy::RequestTermination(
-    base::OnceCallback<void(bool)> callback) {
+    CrossThreadOnceFunction<void(bool)> callback) {
   DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  Client().RequestTermination(std::move(callback));
+  Client().RequestTermination(ConvertToBaseOnceCallback(std::move(callback)));
 }
 
 ServiceWorkerGlobalScopeProxy::ServiceWorkerGlobalScopeProxy(
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h
index 08e3e46..ff536d1 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h
@@ -129,7 +129,7 @@
       int fetch_event_id,
       const KURL& url,
       mojom::blink::FetchEventPreloadHandlePtr preload_handle);
-  void RequestTermination(base::OnceCallback<void(bool)> callback);
+  void RequestTermination(WTF::CrossThreadOnceFunction<void(bool)> callback);
 
   // Detaches this proxy object entirely from the outside world, clearing out
   // all references.
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index f985824f..4575cc24 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -737,6 +737,9 @@
     "fonts/win/font_unique_name_lookup_win.cc",
     "fonts/win/font_unique_name_lookup_win.h",
     "geometry/blend.h",
+    "geometry/calculation_expression_node.cc",
+    "geometry/calculation_expression_node.h",
+    "geometry/calculation_value.cc",
     "geometry/calculation_value.h",
     "geometry/cg/float_point_cg.cc",
     "geometry/cg/float_rect_cg.cc",
@@ -1694,6 +1697,7 @@
     "geometry/layout_rect_test.cc",
     "geometry/layout_size_test.cc",
     "geometry/layout_unit_test.cc",
+    "geometry/length_test.cc",
     "geometry/region_test.cc",
     "graphics/accelerated_static_bitmap_image_test.cc",
     "graphics/bitmap_image_test.cc",
diff --git a/third_party/blink/renderer/platform/animation/animated_layers_test.cc b/third_party/blink/renderer/platform/animation/animated_layers_test.cc
index 196cc0a9..4ed2a36 100644
--- a/third_party/blink/renderer/platform/animation/animated_layers_test.cc
+++ b/third_party/blink/renderer/platform/animation/animated_layers_test.cc
@@ -33,10 +33,6 @@
   ViewportLayersSetup layers_;
 };
 
-INSTANTIATE_TEST_SUITE_P(All,
-                         AnimatedLayersTest,
-                         testing::Values(0, kBlinkGenPropertyTrees));
-
 class AnimationForTesting : public CompositorAnimationClient {
  public:
   AnimationForTesting() {
@@ -50,13 +46,11 @@
   std::unique_ptr<CompositorAnimation> compositor_animation_;
 };
 
-TEST_P(AnimatedLayersTest, updateLayerShouldFlattenTransformWithAnimations) {
-  // TODO(bokan): This test doesn't yet work in blink-gen-property-trees
-  // because cc::Layers can't set an element id in that mode. We fail at
-  // AttachElement since the element id is invalid. https://crbug.com/836897.
-  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    return;
-
+// TODO(bokan): This test doesn't yet work because cc::Layers can't set an
+// element id in that mode. We fail at AttachElement since the element id is
+// invalid. https://crbug.com/993386.
+TEST_F(AnimatedLayersTest,
+       DISABLED_updateLayerShouldFlattenTransformWithAnimations) {
   cc::Layer* cc_layer = layers_.graphics_layer().CcLayer();
   cc::MutatorHost* mutator = layers_.layer_tree_host()->mutator_host();
   EXPECT_FALSE(
diff --git a/third_party/blink/renderer/platform/data_resource_helper.cc b/third_party/blink/renderer/platform/data_resource_helper.cc
index 0ca2276..87fd4da 100644
--- a/third_party/blink/renderer/platform/data_resource_helper.cc
+++ b/third_party/blink/renderer/platform/data_resource_helper.cc
@@ -4,30 +4,10 @@
 
 #include "third_party/blink/renderer/platform/data_resource_helper.h"
 
-#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/public/platform/web_data.h"
-#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 #include "ui/base/resource/resource_bundle.h"
 
 namespace blink {
 
-String GetDataResourceAsASCIIString(const char* resource) {
-  StringBuilder builder;
-  const WebData& resource_data = Platform::Current()->GetDataResource(resource);
-  builder.ReserveCapacity(resource_data.size());
-  resource_data.ForEachSegment([&builder](const char* segment,
-                                          size_t segment_size,
-                                          size_t segment_offset) {
-    builder.Append(segment, segment_size);
-    return true;
-  });
-
-  String data_string = builder.ToString();
-  DCHECK(!data_string.IsEmpty());
-  DCHECK(data_string.ContainsOnlyASCIIOrEmpty());
-  return data_string;
-}
-
 String UncompressResourceAsString(int resource_id) {
   ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
   std::string uncompressed = bundle.DecompressDataResourceScaled(
diff --git a/third_party/blink/renderer/platform/data_resource_helper.h b/third_party/blink/renderer/platform/data_resource_helper.h
index a7ba438..64df28a 100644
--- a/third_party/blink/renderer/platform/data_resource_helper.h
+++ b/third_party/blink/renderer/platform/data_resource_helper.h
@@ -13,10 +13,6 @@
 
 // Helper functions providing access to ui::ResourceBundle in Blink.
 
-// Returns the contents of a resource as a string specified by the
-// resource name.
-PLATFORM_EXPORT String GetDataResourceAsASCIIString(const char* resource);
-
 // Uncompresses a gzipped resource and returns it as a string. The resource
 // is specified by the resource id from Grit.
 PLATFORM_EXPORT String UncompressResourceAsString(int resource_id);
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 2a710ada..effd11e 100644
--- a/third_party/blink/renderer/platform/exported/web_runtime_features.cc
+++ b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
@@ -65,7 +65,9 @@
 }
 
 bool WebRuntimeFeatures::IsBlinkGenPropertyTreesEnabled() {
-  return RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled();
+  // TODO(pdr): Remove this function now that BlinkGenPropertyTrees has
+  // launched.
+  return true;
 }
 
 bool WebRuntimeFeatures::IsFractionalScrollOffsetsEnabled() {
diff --git a/third_party/blink/renderer/platform/geometry/calculation_expression_node.cc b/third_party/blink/renderer/platform/geometry/calculation_expression_node.cc
new file mode 100644
index 0000000..f9e1935
--- /dev/null
+++ b/third_party/blink/renderer/platform/geometry/calculation_expression_node.cc
@@ -0,0 +1,187 @@
+// 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/platform/geometry/calculation_expression_node.h"
+
+namespace blink {
+
+// ------ CalculationExpressionLeafNode ------
+
+float CalculationExpressionLeafNode::Evaluate(float max_value) const {
+  return value_.pixels + value_.percent / 100 * max_value;
+}
+
+bool CalculationExpressionLeafNode::operator==(
+    const CalculationExpressionNode& other) const {
+  if (!other.IsLeaf())
+    return false;
+  const auto& other_leaf = To<CalculationExpressionLeafNode>(other);
+  return value_.pixels == other_leaf.value_.pixels &&
+         value_.percent == other_leaf.value_.percent;
+}
+
+scoped_refptr<const CalculationExpressionNode>
+CalculationExpressionLeafNode::Zoom(double factor) const {
+  PixelsAndPercent result(value_.pixels * factor, value_.percent);
+  return base::MakeRefCounted<CalculationExpressionLeafNode>(result);
+}
+
+// ------ CalculationExpressionMultiplicationNode ------
+
+// static
+scoped_refptr<const CalculationExpressionNode>
+CalculationExpressionMultiplicationNode::CreateSimplified(
+    scoped_refptr<const CalculationExpressionNode> node,
+    float factor) {
+  if (!node->IsLeaf()) {
+    return base::MakeRefCounted<CalculationExpressionMultiplicationNode>(
+        std::move(node), factor);
+  }
+  const auto& leaf = To<CalculationExpressionLeafNode>(*node);
+  PixelsAndPercent value(leaf.Pixels() * factor, leaf.Percent() * factor);
+  return base::MakeRefCounted<CalculationExpressionLeafNode>(value);
+}
+
+float CalculationExpressionMultiplicationNode::Evaluate(float max_value) const {
+  return child_->Evaluate(max_value) * factor_;
+}
+
+bool CalculationExpressionMultiplicationNode::operator==(
+    const CalculationExpressionNode& other) const {
+  if (!other.IsMultiplication())
+    return false;
+  const auto& other_multiply =
+      To<CalculationExpressionMultiplicationNode>(other);
+  return factor_ == other_multiply.factor_ && *child_ == *other_multiply.child_;
+}
+
+scoped_refptr<const CalculationExpressionNode>
+CalculationExpressionMultiplicationNode::Zoom(double factor) const {
+  return CreateSimplified(child_->Zoom(factor), factor_);
+}
+
+// ------ CalculationExpressionAdditiveNode ------
+
+// static
+scoped_refptr<const CalculationExpressionNode>
+CalculationExpressionAdditiveNode::CreateSimplified(
+    scoped_refptr<const CalculationExpressionNode> lhs,
+    scoped_refptr<const CalculationExpressionNode> rhs,
+    Type type) {
+  if (!lhs->IsLeaf() || !rhs->IsLeaf()) {
+    return base::MakeRefCounted<CalculationExpressionAdditiveNode>(
+        std::move(lhs), std::move(rhs), type);
+  }
+  const auto& left_leaf = To<CalculationExpressionLeafNode>(*lhs);
+  const auto& right_leaf = To<CalculationExpressionLeafNode>(*rhs);
+  PixelsAndPercent value = left_leaf.GetPixelsAndPercent();
+  if (type == Type::kAdd) {
+    value.pixels += right_leaf.Pixels();
+    value.percent += right_leaf.Percent();
+  } else {
+    value.pixels -= right_leaf.Pixels();
+    value.percent -= right_leaf.Percent();
+  }
+  return base::MakeRefCounted<CalculationExpressionLeafNode>(value);
+}
+
+float CalculationExpressionAdditiveNode::Evaluate(float max_value) const {
+  if (IsAdd())
+    return lhs_->Evaluate(max_value) + rhs_->Evaluate(max_value);
+  if (IsSubtract())
+    return lhs_->Evaluate(max_value) - rhs_->Evaluate(max_value);
+  NOTREACHED();
+  return 0;
+}
+
+bool CalculationExpressionAdditiveNode::operator==(
+    const CalculationExpressionNode& other) const {
+  if (!other.IsAdditive())
+    return false;
+  const auto& other_add_subtract = To<CalculationExpressionAdditiveNode>(other);
+  // Do we need to consider add as commutative?
+  return type_ == other_add_subtract.type_ &&
+         *lhs_ == *other_add_subtract.lhs_ && *rhs_ == *other_add_subtract.rhs_;
+}
+
+scoped_refptr<const CalculationExpressionNode>
+CalculationExpressionAdditiveNode::Zoom(double factor) const {
+  return CreateSimplified(lhs_->Zoom(factor), rhs_->Zoom(factor), type_);
+}
+
+// ------ CalculationExpressionComparisonNode ------
+
+// static
+scoped_refptr<const CalculationExpressionNode>
+CalculationExpressionComparisonNode::CreateSimplified(
+    Vector<scoped_refptr<const CalculationExpressionNode>>&& operands,
+    Type type) {
+  DCHECK(operands.size());
+  float simplified_px;
+  bool can_simplify = true;
+  for (wtf_size_t i = 0; i < operands.size(); ++i) {
+    const auto* leaf = DynamicTo<CalculationExpressionLeafNode>(*operands[i]);
+    if (!leaf || leaf->Percent()) {
+      can_simplify = false;
+      break;
+    }
+    if (!i) {
+      simplified_px = leaf->Pixels();
+    } else {
+      if (type == Type::kMin)
+        simplified_px = std::min(simplified_px, leaf->Pixels());
+      else
+        simplified_px = std::max(simplified_px, leaf->Pixels());
+    }
+  }
+  if (can_simplify) {
+    return base::MakeRefCounted<CalculationExpressionLeafNode>(
+        PixelsAndPercent(simplified_px, 0));
+  }
+  return base::MakeRefCounted<CalculationExpressionComparisonNode>(
+      std::move(operands), type);
+}
+
+float CalculationExpressionComparisonNode::Evaluate(float max_value) const {
+  float result = operands_.front()->Evaluate(max_value);
+  if (IsMin()) {
+    for (wtf_size_t i = 1; i < operands_.size(); ++i)
+      result = std::min(result, operands_[i]->Evaluate(max_value));
+  } else if (IsMax()) {
+    for (wtf_size_t i = 1; i < operands_.size(); ++i)
+      result = std::max(result, operands_[i]->Evaluate(max_value));
+  } else {
+    NOTREACHED();
+  }
+  return result;
+}
+
+bool CalculationExpressionComparisonNode::operator==(
+    const CalculationExpressionNode& other) const {
+  if (!other.IsComparison())
+    return false;
+  const auto& other_comparison = To<CalculationExpressionComparisonNode>(other);
+  if (type_ != other_comparison.type_)
+    return false;
+  if (operands_.size() != other_comparison.operands_.size())
+    return false;
+  // We may consider ignoring operand ordering to allow better memory
+  // optimization. The code complexity might not pay off, though.
+  for (wtf_size_t i = 0; i < operands_.size(); ++i) {
+    if (*operands_[i] != *other_comparison.operands_[i])
+      return false;
+  }
+  return true;
+}
+
+scoped_refptr<const CalculationExpressionNode>
+CalculationExpressionComparisonNode::Zoom(double factor) const {
+  Vector<scoped_refptr<const CalculationExpressionNode>> cloned_operands;
+  cloned_operands.ReserveCapacity(operands_.size());
+  for (const auto& operand : operands_)
+    cloned_operands.push_back(operand->Zoom(factor));
+  return CreateSimplified(std::move(cloned_operands), type_);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/geometry/calculation_expression_node.h b/third_party/blink/renderer/platform/geometry/calculation_expression_node.h
new file mode 100644
index 0000000..7123200
--- /dev/null
+++ b/third_party/blink/renderer/platform/geometry/calculation_expression_node.h
@@ -0,0 +1,187 @@
+// 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_PLATFORM_GEOMETRY_CALCULATION_EXPRESSION_NODE_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GEOMETRY_CALCULATION_EXPRESSION_NODE_H_
+
+#include "third_party/blink/renderer/platform/geometry/length.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
+#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+
+namespace blink {
+
+// Represents an expression composed of |PixelsAndPercent| and multiple types of
+// operators. To be consumed by |Length| values that involve non-trivial math
+// functions like min() and max().
+class PLATFORM_EXPORT CalculationExpressionNode
+    : public RefCounted<CalculationExpressionNode> {
+ public:
+  virtual float Evaluate(float max_value) const = 0;
+  virtual bool operator==(const CalculationExpressionNode& other) const = 0;
+  bool operator!=(const CalculationExpressionNode& other) const {
+    return !operator==(other);
+  }
+
+  virtual bool IsLeaf() const { return false; }
+  virtual bool IsMultiplication() const { return false; }
+  virtual bool IsAdditive() const { return false; }
+  virtual bool IsComparison() const { return false; }
+
+  virtual scoped_refptr<const CalculationExpressionNode> Zoom(
+      double factor) const = 0;
+
+  virtual ~CalculationExpressionNode() = default;
+};
+
+class PLATFORM_EXPORT CalculationExpressionLeafNode final
+    : public CalculationExpressionNode {
+ public:
+  CalculationExpressionLeafNode(PixelsAndPercent value) : value_(value) {}
+
+  float Pixels() const { return value_.pixels; }
+  float Percent() const { return value_.percent; }
+  PixelsAndPercent GetPixelsAndPercent() const { return value_; }
+
+  // Implement |CalculationExpressionNode|:
+  float Evaluate(float max_value) const final;
+  bool operator==(const CalculationExpressionNode& other) const final;
+  scoped_refptr<const CalculationExpressionNode> Zoom(
+      double factor) const final;
+  bool IsLeaf() const final { return true; }
+  ~CalculationExpressionLeafNode() final = default;
+
+ private:
+  PixelsAndPercent value_;
+};
+
+template <>
+struct DowncastTraits<CalculationExpressionLeafNode> {
+  static bool AllowFrom(const CalculationExpressionNode& node) {
+    return node.IsLeaf();
+  }
+};
+
+class PLATFORM_EXPORT CalculationExpressionMultiplicationNode final
+    : public CalculationExpressionNode {
+ public:
+  static scoped_refptr<const CalculationExpressionNode> CreateSimplified(
+      scoped_refptr<const CalculationExpressionNode> node,
+      float factor);
+
+  CalculationExpressionMultiplicationNode(
+      scoped_refptr<const CalculationExpressionNode> node,
+      float factor)
+      : child_(std::move(node)), factor_(factor) {}
+
+  const CalculationExpressionNode& GetChild() const { return *child_; }
+  float GetFactor() const { return factor_; }
+
+  // Implement |CalculationExpressionNode|:
+  float Evaluate(float max_value) const final;
+  bool operator==(const CalculationExpressionNode& other) const final;
+  scoped_refptr<const CalculationExpressionNode> Zoom(
+      double factor) const final;
+  bool IsMultiplication() const final { return true; }
+  ~CalculationExpressionMultiplicationNode() final = default;
+
+ private:
+  scoped_refptr<const CalculationExpressionNode> child_;
+  float factor_;
+};
+
+template <>
+struct DowncastTraits<CalculationExpressionMultiplicationNode> {
+  static bool AllowFrom(const CalculationExpressionNode& node) {
+    return node.IsMultiplication();
+  }
+};
+
+class PLATFORM_EXPORT CalculationExpressionAdditiveNode final
+    : public CalculationExpressionNode {
+ public:
+  enum class Type { kAdd, kSubtract };
+
+  static scoped_refptr<const CalculationExpressionNode> CreateSimplified(
+      scoped_refptr<const CalculationExpressionNode> lhs,
+      scoped_refptr<const CalculationExpressionNode> rhs,
+      Type type);
+
+  CalculationExpressionAdditiveNode(
+      scoped_refptr<const CalculationExpressionNode> lhs,
+      scoped_refptr<const CalculationExpressionNode> rhs,
+      Type type)
+      : lhs_(std::move(lhs)), rhs_(std::move(rhs)), type_(type) {}
+
+  const CalculationExpressionNode& GetLeftSide() const { return *lhs_; }
+  const CalculationExpressionNode& GetRightSide() const { return *rhs_; }
+  bool IsAdd() const { return type_ == Type::kAdd; }
+  bool IsSubtract() const { return type_ == Type::kSubtract; }
+
+  // Implement |CalculationExpressionNode|:
+  float Evaluate(float max_value) const final;
+  bool operator==(const CalculationExpressionNode& other) const final;
+  scoped_refptr<const CalculationExpressionNode> Zoom(
+      double factor) const final;
+  bool IsAdditive() const final { return true; }
+  ~CalculationExpressionAdditiveNode() final = default;
+
+ private:
+  scoped_refptr<const CalculationExpressionNode> lhs_;
+  scoped_refptr<const CalculationExpressionNode> rhs_;
+  Type type_;
+};
+
+template <>
+struct DowncastTraits<CalculationExpressionAdditiveNode> {
+  static bool AllowFrom(const CalculationExpressionNode& node) {
+    return node.IsAdditive();
+  }
+};
+
+class PLATFORM_EXPORT CalculationExpressionComparisonNode final
+    : public CalculationExpressionNode {
+ public:
+  enum class Type { kMin, kMax };
+
+  static scoped_refptr<const CalculationExpressionNode> CreateSimplified(
+      Vector<scoped_refptr<const CalculationExpressionNode>>&& operands,
+      Type type);
+
+  CalculationExpressionComparisonNode(
+      Vector<scoped_refptr<const CalculationExpressionNode>>&& operands,
+      Type type)
+      : operands_(std::move(operands)), type_(type) {}
+
+  const Vector<scoped_refptr<const CalculationExpressionNode>>& GetOperands()
+      const {
+    return operands_;
+  }
+
+  bool IsMin() const { return type_ == Type::kMin; }
+  bool IsMax() const { return type_ == Type::kMax; }
+
+  // Implement |CalculationExpressionNode|:
+  float Evaluate(float max_value) const final;
+  bool operator==(const CalculationExpressionNode& other) const final;
+  scoped_refptr<const CalculationExpressionNode> Zoom(
+      double factor) const final;
+  bool IsComparison() const final { return true; }
+  ~CalculationExpressionComparisonNode() final = default;
+
+ private:
+  Vector<scoped_refptr<const CalculationExpressionNode>> operands_;
+  Type type_;
+};
+
+template <>
+struct DowncastTraits<CalculationExpressionComparisonNode> {
+  static bool AllowFrom(const CalculationExpressionNode& node) {
+    return node.IsComparison();
+  }
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GEOMETRY_CALCULATION_EXPRESSION_NODE_H_
diff --git a/third_party/blink/renderer/platform/geometry/calculation_value.cc b/third_party/blink/renderer/platform/geometry/calculation_value.cc
new file mode 100644
index 0000000..ed54016
--- /dev/null
+++ b/third_party/blink/renderer/platform/geometry/calculation_value.cc
@@ -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.
+
+#include "third_party/blink/renderer/platform/geometry/calculation_value.h"
+
+#include "third_party/blink/renderer/platform/geometry/blend.h"
+#include "third_party/blink/renderer/platform/geometry/calculation_expression_node.h"
+#include "third_party/blink/renderer/platform/wtf/size_assertions.h"
+
+namespace blink {
+
+CalculationValue::DataUnion::DataUnion(
+    scoped_refptr<const CalculationExpressionNode> expression)
+    : expression(std::move(expression)) {}
+
+CalculationValue::DataUnion::~DataUnion() {
+  // Release of |expression| is left to CalculationValue::~CalculationValue().
+}
+
+// static
+scoped_refptr<CalculationValue> CalculationValue::CreateSimplified(
+    scoped_refptr<const CalculationExpressionNode> expression,
+    ValueRange range) {
+  if (expression->IsLeaf()) {
+    return Create(
+        To<CalculationExpressionLeafNode>(*expression).GetPixelsAndPercent(),
+        range);
+  }
+  return base::AdoptRef(new CalculationValue(std::move(expression), range));
+}
+
+CalculationValue::CalculationValue(
+    scoped_refptr<const CalculationExpressionNode> expression,
+    ValueRange range)
+    : data_(std::move(expression)),
+      is_expression_(true),
+      is_non_negative_(range == kValueRangeNonNegative) {}
+
+CalculationValue::~CalculationValue() {
+  if (is_expression_)
+    data_.expression.~scoped_refptr<const CalculationExpressionNode>();
+  else
+    data_.value.~PixelsAndPercent();
+}
+
+float CalculationValue::Evaluate(float max_value) const {
+  float value = is_expression_ ? value = data_.expression->Evaluate(max_value)
+                               : value = Pixels() + Percent() / 100 * max_value;
+  return (IsNonNegative() && value < 0) ? 0 : value;
+}
+
+bool CalculationValue::operator==(const CalculationValue& other) const {
+  if (IsExpression())
+    return other.IsExpression() && *data_.expression == *other.data_.expression;
+  return !other.IsExpression() && Pixels() == other.Pixels() &&
+         Percent() == other.Percent();
+}
+
+scoped_refptr<const CalculationExpressionNode>
+CalculationValue::GetOrCreateExpression() const {
+  if (IsExpression())
+    return data_.expression;
+  return base::MakeRefCounted<CalculationExpressionLeafNode>(
+      GetPixelsAndPercent());
+}
+
+scoped_refptr<CalculationValue> CalculationValue::Blend(
+    const CalculationValue& from,
+    double progress,
+    ValueRange range) const {
+  if (!IsExpression() && !from.IsExpression()) {
+    PixelsAndPercent from_pixels_and_percent = from.GetPixelsAndPercent();
+    PixelsAndPercent to_pixels_and_percent = GetPixelsAndPercent();
+    const float pixels = blink::Blend(from_pixels_and_percent.pixels,
+                                      to_pixels_and_percent.pixels, progress);
+    const float percent = blink::Blend(from_pixels_and_percent.percent,
+                                       to_pixels_and_percent.percent, progress);
+    return Create(PixelsAndPercent(pixels, percent), range);
+  }
+
+  auto blended_from = CalculationExpressionMultiplicationNode::CreateSimplified(
+      from.GetOrCreateExpression(), 1.0 - progress);
+  auto blended_to = CalculationExpressionMultiplicationNode::CreateSimplified(
+      GetOrCreateExpression(), progress);
+  auto result_expression = CalculationExpressionAdditiveNode::CreateSimplified(
+      std::move(blended_from), std::move(blended_to),
+      CalculationExpressionAdditiveNode::Type::kAdd);
+  return CreateSimplified(std::move(result_expression), range);
+}
+
+scoped_refptr<CalculationValue>
+CalculationValue::SubtractFromOneHundredPercent() const {
+  if (!IsExpression()) {
+    PixelsAndPercent result(-Pixels(), 100 - Percent());
+    return Create(result, kValueRangeAll);
+  }
+  auto hundred_percent = base::MakeRefCounted<CalculationExpressionLeafNode>(
+      PixelsAndPercent(0, 100));
+  auto result_expression = CalculationExpressionAdditiveNode::CreateSimplified(
+      std::move(hundred_percent), GetOrCreateExpression(),
+      CalculationExpressionAdditiveNode::Type::kSubtract);
+  return CreateSimplified(std::move(result_expression), kValueRangeAll);
+}
+
+scoped_refptr<CalculationValue> CalculationValue::Zoom(double factor) const {
+  if (!IsExpression()) {
+    PixelsAndPercent result(Pixels() * factor, Percent());
+    return Create(result, GetValueRange());
+  }
+  return CreateSimplified(data_.expression->Zoom(factor), GetValueRange());
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/geometry/calculation_value.h b/third_party/blink/renderer/platform/geometry/calculation_value.h
index bea5a86..9f7e915 100644
--- a/third_party/blink/renderer/platform/geometry/calculation_value.h
+++ b/third_party/blink/renderer/platform/geometry/calculation_value.h
@@ -39,6 +39,10 @@
 
 namespace blink {
 
+class CalculationExpressionNode;
+
+// TODO(xiaochengh): Make |CalculationValue| immutable, namely, accessible only
+// via const pointers and references.
 class PLATFORM_EXPORT CalculationValue : public RefCounted<CalculationValue> {
   USING_FAST_MALLOC(CalculationValue);
 
@@ -48,27 +52,65 @@
     return base::AdoptRef(new CalculationValue(value, range));
   }
 
-  float Evaluate(float max_value) const {
-    float value = Pixels() + Percent() / 100 * max_value;
-    return (IsNonNegative() && value < 0) ? 0 : value;
-  }
-  bool operator==(const CalculationValue& o) const {
-    return Pixels() == o.Pixels() && Percent() == o.Percent();
-  }
+  // If |expression| simply wraps a |PixelsAndPercent| value, this function
+  // takes that value directly and discards |expression|.
+  static scoped_refptr<CalculationValue> CreateSimplified(
+      scoped_refptr<const CalculationExpressionNode> expression,
+      ValueRange range);
+
+  ~CalculationValue();
+
+  float Evaluate(float max_value) const;
+  bool operator==(const CalculationValue& o) const;
+  bool IsExpression() const { return is_expression_; }
   bool IsNonNegative() const { return is_non_negative_; }
   ValueRange GetValueRange() const {
     return is_non_negative_ ? kValueRangeNonNegative : kValueRangeAll;
   }
-  float Pixels() const { return value_.pixels; }
-  float Percent() const { return value_.percent; }
-  PixelsAndPercent GetPixelsAndPercent() const { return value_; }
+
+  float Pixels() const {
+    DCHECK(!IsExpression());
+    return data_.value.pixels;
+  }
+  float Percent() const {
+    DCHECK(!IsExpression());
+    return data_.value.percent;
+  }
+  PixelsAndPercent GetPixelsAndPercent() const {
+    DCHECK(!IsExpression());
+    return data_.value;
+  }
+
+  // If |this| is an expression, returns the underlying expression. Otherwise,
+  // creates one from the underlying |PixelsAndPercent| value.
+  scoped_refptr<const CalculationExpressionNode> GetOrCreateExpression() const;
+
+  scoped_refptr<CalculationValue> Blend(const CalculationValue& from,
+                                        double progress,
+                                        ValueRange) const;
+  scoped_refptr<CalculationValue> SubtractFromOneHundredPercent() const;
+  scoped_refptr<CalculationValue> Zoom(double factor) const;
 
  private:
   CalculationValue(PixelsAndPercent value, ValueRange range)
-      : value_(value), is_non_negative_(range == kValueRangeNonNegative) {}
+      : data_(value),
+        is_expression_(false),
+        is_non_negative_(range == kValueRangeNonNegative) {}
 
-  PixelsAndPercent value_;
-  bool is_non_negative_;
+  CalculationValue(scoped_refptr<const CalculationExpressionNode> expression,
+                   ValueRange range);
+
+  union DataUnion {
+    explicit DataUnion(PixelsAndPercent value) : value(value) {}
+    explicit DataUnion(
+        scoped_refptr<const CalculationExpressionNode> expression);
+    ~DataUnion();
+
+    PixelsAndPercent value;
+    scoped_refptr<const CalculationExpressionNode> expression;
+  } data_;
+  unsigned is_expression_ : 1;
+  unsigned is_non_negative_ : 1;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/geometry/length.cc b/third_party/blink/renderer/platform/geometry/length.cc
index bb079d9d..13eec26 100644
--- a/third_party/blink/renderer/platform/geometry/length.cc
+++ b/third_party/blink/renderer/platform/geometry/length.cc
@@ -96,14 +96,8 @@
                                ValueRange range) const {
   DCHECK(from.IsSpecified());
   DCHECK(IsSpecified());
-  PixelsAndPercent from_pixels_and_percent = from.GetPixelsAndPercent();
-  PixelsAndPercent to_pixels_and_percent = GetPixelsAndPercent();
-  const float pixels = blink::Blend(from_pixels_and_percent.pixels,
-                                    to_pixels_and_percent.pixels, progress);
-  const float percent = blink::Blend(from_pixels_and_percent.percent,
-                                     to_pixels_and_percent.percent, progress);
   return Length(
-      CalculationValue::Create(PixelsAndPercent(pixels, percent), range));
+      AsCalculationValue()->Blend(*from.AsCalculationValue(), progress, range));
 }
 
 Length Length::BlendSameTypes(const Length& from,
@@ -133,27 +127,33 @@
   }
 }
 
+scoped_refptr<CalculationValue> Length::AsCalculationValue() const {
+  if (IsCalculated())
+    return &GetCalculationValue();
+  return CalculationValue::Create(GetPixelsAndPercent(), kValueRangeAll);
+}
+
 Length Length::SubtractFromOneHundredPercent() const {
-  PixelsAndPercent result = GetPixelsAndPercent();
-  result.pixels = -result.pixels;
-  result.percent = 100 - result.percent;
-  if (result.pixels && result.percent)
-    return Length(CalculationValue::Create(result, kValueRangeAll));
-  if (result.percent)
-    return Length::Percent(result.percent);
-  return Length::Fixed(result.pixels);
+  if (IsPercent())
+    return Length::Percent(100 - Value());
+  DCHECK(IsSpecified());
+  scoped_refptr<CalculationValue> result =
+      AsCalculationValue()->SubtractFromOneHundredPercent();
+  if (result->IsExpression() ||
+      (result->Pixels() != 0 && result->Percent() != 0)) {
+    return Length(std::move(result));
+  }
+  if (result->Percent())
+    return Length::Percent(result->Percent());
+  return Length::Fixed(result->Pixels());
 }
 
 Length Length::Zoom(double factor) const {
   switch (GetType()) {
     case kFixed:
       return Length::Fixed(GetFloatValue() * factor);
-    case kCalculated: {
-      PixelsAndPercent result = GetPixelsAndPercent();
-      result.pixels *= factor;
-      return Length(CalculationValue::Create(
-          result, GetCalculationValue().GetValueRange()));
-    }
+    case kCalculated:
+      return Length(GetCalculationValue().Zoom(factor));
     default:
       return *this;
   }
diff --git a/third_party/blink/renderer/platform/geometry/length.h b/third_party/blink/renderer/platform/geometry/length.h
index f35afdd..01c1c46 100644
--- a/third_party/blink/renderer/platform/geometry/length.h
+++ b/third_party/blink/renderer/platform/geometry/length.h
@@ -181,6 +181,11 @@
 
   CalculationValue& GetCalculationValue() const;
 
+  // If |this| is calculated, returns the underlying |CalculationValue|. If not,
+  // returns a |CalculationValue| constructed from |GetPixelsAndPercent()|. Hits
+  // a DCHECK if |this| is not a specified value (e.g., 'auto').
+  scoped_refptr<CalculationValue> AsCalculationValue() const;
+
   Length::Type GetType() const { return static_cast<Length::Type>(type_); }
   bool Quirk() const { return quirk_; }
 
diff --git a/third_party/blink/renderer/platform/geometry/length_test.cc b/third_party/blink/renderer/platform/geometry/length_test.cc
new file mode 100644
index 0000000..4f1f638d
--- /dev/null
+++ b/third_party/blink/renderer/platform/geometry/length_test.cc
@@ -0,0 +1,289 @@
+// 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/platform/geometry/length.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/geometry/calculation_expression_node.h"
+#include "third_party/blink/renderer/platform/geometry/calculation_value.h"
+
+namespace blink {
+
+namespace {
+
+const PixelsAndPercent ten_px(10, 0);
+const PixelsAndPercent twenty_px(20, 0);
+const PixelsAndPercent ten_percent(0, 10);
+const PixelsAndPercent twenty_percent(0, 20);
+
+}  // namespace
+
+class LengthTest : public ::testing::Test {
+ public:
+  using Pointer = scoped_refptr<const CalculationExpressionNode>;
+
+  Pointer Leaf(PixelsAndPercent value) {
+    return base::MakeRefCounted<CalculationExpressionLeafNode>(value);
+  }
+
+  Pointer Add(Pointer lhs, Pointer rhs) {
+    return base::MakeRefCounted<CalculationExpressionAdditiveNode>(
+        std::move(lhs), std::move(rhs),
+        CalculationExpressionAdditiveNode::Type::kAdd);
+  }
+
+  Pointer Subtract(Pointer lhs, Pointer rhs) {
+    return base::MakeRefCounted<CalculationExpressionAdditiveNode>(
+        std::move(lhs), std::move(rhs),
+        CalculationExpressionAdditiveNode::Type::kSubtract);
+  }
+
+  Pointer Multiply(Pointer node, float factor) {
+    return base::MakeRefCounted<CalculationExpressionMultiplicationNode>(
+        std::move(node), factor);
+  }
+
+  Pointer Min(Pointer op1, Pointer op2) {
+    Vector<Pointer> operands;
+    operands.push_back(std::move(op1));
+    operands.push_back(std::move(op2));
+    return base::MakeRefCounted<CalculationExpressionComparisonNode>(
+        std::move(operands), CalculationExpressionComparisonNode::Type::kMin);
+  }
+
+  Pointer Max(Pointer op1, Pointer op2) {
+    Vector<Pointer> operands;
+    operands.push_back(std::move(op1));
+    operands.push_back(std::move(op2));
+    return base::MakeRefCounted<CalculationExpressionComparisonNode>(
+        std::move(operands), CalculationExpressionComparisonNode::Type::kMax);
+  }
+
+  Length CreateLength(Pointer expression) {
+    return Length(CalculationValue::CreateSimplified(std::move(expression),
+                                                     kValueRangeAll));
+  }
+};
+
+TEST_F(LengthTest, EvaluateSimpleComparison) {
+  // min(10px, 20px)
+  {
+    Length length = CreateLength(Min(Leaf(ten_px), Leaf(twenty_px)));
+    EXPECT_EQ(10.0f, length.GetCalculationValue().Evaluate(-200));
+    EXPECT_EQ(10.0f, length.GetCalculationValue().Evaluate(-100));
+    EXPECT_EQ(10.0f, length.GetCalculationValue().Evaluate(0));
+    EXPECT_EQ(10.0f, length.GetCalculationValue().Evaluate(100));
+    EXPECT_EQ(10.0f, length.GetCalculationValue().Evaluate(200));
+  }
+
+  // min(10%, 20%)
+  {
+    Length length = CreateLength(Min(Leaf(ten_percent), Leaf(twenty_percent)));
+    EXPECT_EQ(-40.0f, length.GetCalculationValue().Evaluate(-200));
+    EXPECT_EQ(-20.0f, length.GetCalculationValue().Evaluate(-100));
+    EXPECT_EQ(0.0f, length.GetCalculationValue().Evaluate(0));
+    EXPECT_EQ(10.0f, length.GetCalculationValue().Evaluate(100));
+    EXPECT_EQ(20.0f, length.GetCalculationValue().Evaluate(200));
+  }
+
+  // min(10px, 10%)
+  {
+    Length length = CreateLength(Min(Leaf(ten_px), Leaf(twenty_percent)));
+    EXPECT_EQ(-40.0f, length.GetCalculationValue().Evaluate(-200));
+    EXPECT_EQ(-20.0f, length.GetCalculationValue().Evaluate(-100));
+    EXPECT_EQ(0.0f, length.GetCalculationValue().Evaluate(0));
+    EXPECT_EQ(10.0f, length.GetCalculationValue().Evaluate(100));
+    EXPECT_EQ(10.0f, length.GetCalculationValue().Evaluate(200));
+  }
+
+  // max(10px, 20px)
+  {
+    Length length = CreateLength(Max(Leaf(ten_px), Leaf(twenty_px)));
+    EXPECT_EQ(20.0f, length.GetCalculationValue().Evaluate(-200));
+    EXPECT_EQ(20.0f, length.GetCalculationValue().Evaluate(-100));
+    EXPECT_EQ(20.0f, length.GetCalculationValue().Evaluate(0));
+    EXPECT_EQ(20.0f, length.GetCalculationValue().Evaluate(100));
+    EXPECT_EQ(20.0f, length.GetCalculationValue().Evaluate(200));
+  }
+
+  // max(10%, 20%)
+  {
+    Length length = CreateLength(Max(Leaf(ten_percent), Leaf(twenty_percent)));
+    EXPECT_EQ(-20.0f, length.GetCalculationValue().Evaluate(-200));
+    EXPECT_EQ(-10.0f, length.GetCalculationValue().Evaluate(-100));
+    EXPECT_EQ(0.0f, length.GetCalculationValue().Evaluate(0));
+    EXPECT_EQ(20.0f, length.GetCalculationValue().Evaluate(100));
+    EXPECT_EQ(40.0f, length.GetCalculationValue().Evaluate(200));
+  }
+
+  // max(10px, 10%)
+  {
+    Length length = CreateLength(Max(Leaf(ten_px), Leaf(ten_percent)));
+    EXPECT_EQ(10.0f, length.GetCalculationValue().Evaluate(-200));
+    EXPECT_EQ(10.0f, length.GetCalculationValue().Evaluate(-100));
+    EXPECT_EQ(10.0f, length.GetCalculationValue().Evaluate(0));
+    EXPECT_EQ(10.0f, length.GetCalculationValue().Evaluate(100));
+    EXPECT_EQ(20.0f, length.GetCalculationValue().Evaluate(200));
+  }
+}
+
+TEST_F(LengthTest, EvaluateNestedComparisons) {
+  // max(10px, min(10%, 20px))
+  {
+    Length length = CreateLength(
+        Max(Leaf(ten_px), Min(Leaf(ten_percent), Leaf(twenty_px))));
+    EXPECT_EQ(10.0f, length.GetCalculationValue().Evaluate(50));
+    EXPECT_EQ(15.0f, length.GetCalculationValue().Evaluate(150));
+    EXPECT_EQ(20.0f, length.GetCalculationValue().Evaluate(250));
+  }
+
+  // max(10%, min(10px, 20%))
+  {
+    Length length = CreateLength(
+        Max(Leaf(ten_percent), Min(Leaf(ten_px), Leaf(twenty_percent))));
+    EXPECT_EQ(5.0f, length.GetCalculationValue().Evaluate(25));
+    EXPECT_EQ(10.0f, length.GetCalculationValue().Evaluate(50));
+    EXPECT_EQ(10.0f, length.GetCalculationValue().Evaluate(75));
+    EXPECT_EQ(10.0f, length.GetCalculationValue().Evaluate(100));
+    EXPECT_EQ(12.5f, length.GetCalculationValue().Evaluate(125));
+  }
+
+  // min(max(10px, 10%), 20px)
+  {
+    Length length = CreateLength(
+        Min(Max(Leaf(ten_px), Leaf(ten_percent)), Leaf(twenty_px)));
+    EXPECT_EQ(10.0f, length.GetCalculationValue().Evaluate(50));
+    EXPECT_EQ(15.0f, length.GetCalculationValue().Evaluate(150));
+    EXPECT_EQ(20.0f, length.GetCalculationValue().Evaluate(250));
+  }
+
+  // min(max(10%, 10px), 20%)
+  {
+    Length length = CreateLength(
+        Min(Max(Leaf(ten_percent), Leaf(ten_px)), Leaf(twenty_percent)));
+    EXPECT_EQ(5.0f, length.GetCalculationValue().Evaluate(25));
+    EXPECT_EQ(10.0f, length.GetCalculationValue().Evaluate(50));
+    EXPECT_EQ(10.0f, length.GetCalculationValue().Evaluate(75));
+    EXPECT_EQ(10.0f, length.GetCalculationValue().Evaluate(100));
+    EXPECT_EQ(12.5f, length.GetCalculationValue().Evaluate(125));
+  }
+}
+
+TEST_F(LengthTest, EvaluateAdditive) {
+  // min(10%, 10px) + 10px
+  {
+    Length length =
+        CreateLength(Add(Min(Leaf(ten_percent), Leaf(ten_px)), Leaf(ten_px)));
+    EXPECT_EQ(15.0f, length.GetCalculationValue().Evaluate(50));
+    EXPECT_EQ(20.0f, length.GetCalculationValue().Evaluate(100));
+    EXPECT_EQ(20.0f, length.GetCalculationValue().Evaluate(150));
+  }
+
+  // min(10%, 10px) - 10px
+  {
+    Length length = CreateLength(
+        Subtract(Min(Leaf(ten_percent), Leaf(ten_px)), Leaf(ten_px)));
+    EXPECT_EQ(-5.0f, length.GetCalculationValue().Evaluate(50));
+    EXPECT_EQ(0.0f, length.GetCalculationValue().Evaluate(100));
+    EXPECT_EQ(0.0f, length.GetCalculationValue().Evaluate(150));
+  }
+
+  // 10px + max(10%, 10px)
+  {
+    Length length =
+        CreateLength(Add(Leaf(ten_px), Max(Leaf(ten_percent), Leaf(ten_px))));
+    EXPECT_EQ(20.0f, length.GetCalculationValue().Evaluate(50));
+    EXPECT_EQ(20.0f, length.GetCalculationValue().Evaluate(100));
+    EXPECT_EQ(25.0f, length.GetCalculationValue().Evaluate(150));
+  }
+
+  // 10px - max(10%, 10px)
+  {
+    Length length = CreateLength(
+        Subtract(Leaf(ten_px), Max(Leaf(ten_percent), Leaf(ten_px))));
+    EXPECT_EQ(0.0f, length.GetCalculationValue().Evaluate(50));
+    EXPECT_EQ(0.0f, length.GetCalculationValue().Evaluate(100));
+    EXPECT_EQ(-5.0f, length.GetCalculationValue().Evaluate(150));
+  }
+}
+
+TEST_F(LengthTest, EvaluateMultiplicative) {
+  // min(10px, 10%) * 2
+  {
+    Length length =
+        CreateLength(Multiply(Min(Leaf(ten_px), Leaf(ten_percent)), 2));
+    EXPECT_EQ(10.0f, length.GetCalculationValue().Evaluate(50));
+    EXPECT_EQ(20.0f, length.GetCalculationValue().Evaluate(100));
+    EXPECT_EQ(20.0f, length.GetCalculationValue().Evaluate(150));
+  }
+
+  // max(10px, 10%) * 0.5
+  {
+    Length length =
+        CreateLength(Multiply(Max(Leaf(ten_px), Leaf(ten_percent)), 0.5));
+    EXPECT_EQ(5.0f, length.GetCalculationValue().Evaluate(50));
+    EXPECT_EQ(5.0f, length.GetCalculationValue().Evaluate(100));
+    EXPECT_EQ(10.0f, length.GetCalculationValue().Evaluate(200));
+  }
+}
+
+TEST_F(LengthTest, BlendExpressions) {
+  // From: min(10px, 20%)
+  // To: max(20px, 10%)
+  // Progress: 0.25
+
+  Length from_length = CreateLength(Min(Leaf(ten_px), Leaf(twenty_percent)));
+  Length to_length = CreateLength(Max(Leaf(twenty_px), Leaf(ten_percent)));
+  Length blended = to_length.Blend(from_length, 0.25, kValueRangeAll);
+
+  EXPECT_EQ(8.75f, blended.GetCalculationValue().Evaluate(25));
+  EXPECT_EQ(12.5f, blended.GetCalculationValue().Evaluate(50));
+  EXPECT_EQ(12.5f, blended.GetCalculationValue().Evaluate(100));
+  EXPECT_EQ(12.5f, blended.GetCalculationValue().Evaluate(200));
+  EXPECT_EQ(17.5f, blended.GetCalculationValue().Evaluate(400));
+}
+
+TEST_F(LengthTest, ZoomExpression) {
+  // Original: min(10px, 10%)
+  // Factor: 2.0
+  {
+    Length original = CreateLength(Min(Leaf(ten_px), Leaf(ten_percent)));
+    Length zoomed = original.Zoom(2);
+    EXPECT_EQ(10.0f, zoomed.GetCalculationValue().Evaluate(100));
+    EXPECT_EQ(20.0f, zoomed.GetCalculationValue().Evaluate(200));
+    EXPECT_EQ(20.0f, zoomed.GetCalculationValue().Evaluate(400));
+  }
+
+  // Original: max(10px, 10%)
+  // Factor: 0.5
+  {
+    Length original = CreateLength(Max(Leaf(ten_px), Leaf(ten_percent)));
+    Length zoomed = original.Zoom(0.5);
+    EXPECT_EQ(5.0f, zoomed.GetCalculationValue().Evaluate(25));
+    EXPECT_EQ(5.0f, zoomed.GetCalculationValue().Evaluate(50));
+    EXPECT_EQ(10.0f, zoomed.GetCalculationValue().Evaluate(100));
+  }
+}
+
+TEST_F(LengthTest, SubtractExpressionFromOneHundredPercent) {
+  // min(10px, 20%)
+  {
+    Length original = CreateLength(Min(Leaf(ten_px), Leaf(twenty_percent)));
+    Length result = original.SubtractFromOneHundredPercent();
+    EXPECT_EQ(20.0f, result.GetCalculationValue().Evaluate(25));
+    EXPECT_EQ(40.0f, result.GetCalculationValue().Evaluate(50));
+    EXPECT_EQ(90.0f, result.GetCalculationValue().Evaluate(100));
+  }
+
+  // max(20px, 10%)
+  {
+    Length original = CreateLength(Max(Leaf(twenty_px), Leaf(ten_percent)));
+    Length result = original.SubtractFromOneHundredPercent();
+    EXPECT_EQ(80.0f, result.GetCalculationValue().Evaluate(100));
+    EXPECT_EQ(180.0f, result.GetCalculationValue().Evaluate(200));
+    EXPECT_EQ(360.0f, result.GetCalculationValue().Evaluate(400));
+  }
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
index bc4365f0..1a5796c8 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
@@ -47,22 +47,10 @@
     : scroll_callback_(std::move(scroll_callback)),
       tracks_raster_invalidations_(false),
       needs_update_(true) {
-  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
-      !RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    return;
   root_layer_ = cc::Layer::Create();
 }
 
-PaintArtifactCompositor::~PaintArtifactCompositor() {
-  // TODO(crbug.com/836897, crbug.com/836912):
-  // In BlinkGenPropertyTrees mode, some of the layers passed from Blink core
-  // have pre-filled element ID. Need to figure out what is the best place to
-  // setup them.
-  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    return;
-  for (auto child : root_layer_->children())
-    DCHECK(!child->element_id());
-}
+PaintArtifactCompositor::~PaintArtifactCompositor() {}
 
 void PaintArtifactCompositor::EnableExtraDataForTesting() {
   if (extra_data_for_testing_enabled_)
@@ -942,12 +930,6 @@
 
   TRACE_EVENT0("blink", "PaintArtifactCompositor::Update");
 
-  // When using BlinkGenPropertyTrees, the compositor accepts a list of layers
-  // and property trees instead of building property trees. This DCHECK ensures
-  // we have not forgotten to set |use_layer_lists|.
-  DCHECK(!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
-         host->GetSettings().use_layer_lists);
-
   if (extra_data_for_testing_enabled_)
     extra_data_for_testing_.reset(new ExtraDataForTesting);
 
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
index 7711f6d..28585b45 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
@@ -170,47 +170,34 @@
                              const TransformPaintPropertyNode& scroll_offset,
                              const ClipPaintPropertyNode& clip,
                              const EffectPaintPropertyNode& effect) {
-    if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-      // Create a foreign layer for scrolling, roughly matching the layer
-      // created by ScrollingCoordinator.
-      const auto* scroll_node = scroll_offset.ScrollNode();
-      scoped_refptr<cc::Layer> layer = cc::Layer::Create();
-      auto rect = scroll_node->ContainerRect();
-      layer->SetScrollable(gfx::Size(rect.Size()));
-      layer->SetBounds(gfx::Size(rect.Size()));
-      layer->SetElementId(scroll_node->GetCompositorElementId());
-      layer->set_did_scroll_callback(
-          paint_artifact_compositor_->scroll_callback_);
-      artifact.Chunk(scroll_offset, clip, effect)
-          .ForeignLayer(layer, FloatPoint(rect.Location()));
-      return;
-    }
-    // Scroll hit test layers are marked as scrollable for hit testing but are
-    // in the unscrolled transform space (scroll offset's parent).
-    artifact.Chunk(*scroll_offset.Parent(), clip, effect)
-        .ScrollHitTest(&scroll_offset,
-                       scroll_offset.ScrollNode()->ContainerRect());
+    // Create a foreign layer for scrolling, roughly matching the layer
+    // created by ScrollingCoordinator.
+    const auto* scroll_node = scroll_offset.ScrollNode();
+    scoped_refptr<cc::Layer> layer = cc::Layer::Create();
+    auto rect = scroll_node->ContainerRect();
+    layer->SetScrollable(gfx::Size(rect.Size()));
+    layer->SetBounds(gfx::Size(rect.Size()));
+    layer->SetElementId(scroll_node->GetCompositorElementId());
+    layer->set_did_scroll_callback(
+        paint_artifact_compositor_->scroll_callback_);
+    artifact.Chunk(scroll_offset, clip, effect)
+        .ForeignLayer(layer, FloatPoint(rect.Location()));
   }
 
   // Returns the |num|th scrollable layer. In CompositeAfterPaint, this will be
   // a scroll hit test layer, whereas in BlinkGenPropertyTrees this will be a
   // content layer.
   cc::Layer* ScrollableLayerAt(size_t num) {
-    if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-      for (size_t content_layer_index = 0;
-           content_layer_index < ContentLayerCount(); content_layer_index++) {
-        auto* content_layer = ContentLayerAt(content_layer_index);
-        if (content_layer->scrollable()) {
-          if (num == 0)
-            return content_layer;
-          num--;
-        }
+    for (size_t content_layer_index = 0;
+         content_layer_index < ContentLayerCount(); content_layer_index++) {
+      auto* content_layer = ContentLayerAt(content_layer_index);
+      if (content_layer->scrollable()) {
+        if (num == 0)
+          return content_layer;
+        num--;
       }
-      return nullptr;
     }
-    return paint_artifact_compositor_->GetExtraDataForTesting()
-        ->scroll_hit_test_layers[num]
-        .get();
+    return nullptr;
   }
 
   // Returns the |num|th non-scrollable layer. In CompositeAfterPaint, content
diff --git a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
index 60a3456..d54fa99 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
@@ -1437,6 +1437,9 @@
   DCHECK(UsingSwapChain());
   DCHECK_EQ(texture_target_, static_cast<unsigned>(GL_TEXTURE_2D));
 
+  if (!contents_changed_)
+    return;
+
   ScopedStateRestorer scoped_state_restorer(this);
   ResolveIfNeeded();
 
@@ -1472,6 +1475,7 @@
                                 GL_FALSE, GL_FALSE);
   }
   ResetBuffersToAutoClear();
+  contents_changed_ = false;
 }
 
 scoped_refptr<DrawingBuffer::ColorBuffer> DrawingBuffer::CreateColorBuffer(
diff --git a/third_party/blink/renderer/platform/graphics/graphics_layer.cc b/third_party/blink/renderer/platform/graphics/graphics_layer.cc
index e472408..2f55a3c1 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_layer.cc
+++ b/third_party/blink/renderer/platform/graphics/graphics_layer.cc
@@ -83,7 +83,6 @@
       painting_phase_(kGraphicsLayerPaintAllWithOverflowClip),
       parent_(nullptr),
       mask_layer_(nullptr),
-      contents_clipping_mask_layer_(nullptr),
       contents_layer_(nullptr),
       contents_layer_id_(0),
       rendering_context3d_(0) {
@@ -118,8 +117,7 @@
   // This ensures we clean-up the ElementId to cc::Layer mapping in
   // LayerTreeHost before a new layer with the same ElementId is added.
   // Regression from BGPT: https://crbug.com/979002
-  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    SetElementId(CompositorElementId());
+  SetElementId(CompositorElementId());
 }
 
 IntRect GraphicsLayer::VisualRect() const {
@@ -132,29 +130,6 @@
   CcLayer()->SetHasWillChangeTransformHint(has_will_change_transform);
 }
 
-void GraphicsLayer::SetOverscrollBehavior(
-    const cc::OverscrollBehavior& behavior) {
-  CcLayer()->SetOverscrollBehavior(behavior);
-}
-
-void GraphicsLayer::SetSnapContainerData(
-    base::Optional<cc::SnapContainerData> data) {
-  CcLayer()->SetSnapContainerData(std::move(data));
-}
-
-void GraphicsLayer::SetIsResizedByBrowserControls(
-    bool is_resized_by_browser_controls) {
-  DCHECK(!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
-         !RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
-  CcLayer()->SetIsResizedByBrowserControls(is_resized_by_browser_controls);
-}
-
-void GraphicsLayer::SetIsContainerForFixedPositionLayers(bool is_container) {
-  DCHECK(!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
-         !RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
-  CcLayer()->SetIsContainerForFixedPositionLayers(is_container);
-}
-
 void GraphicsLayer::SetCompositingReasons(CompositingReasons reasons) {
   CcLayer()->set_compositing_reasons(reasons);
 }
@@ -258,14 +233,9 @@
     SetParent(nullptr);
   }
 
-  // When using layer lists, cc::Layers are created and removed in
-  // PaintArtifactCompositor.
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
-      !RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-    CcLayer()->RemoveFromParent();
-  } else {
-    client_.GraphicsLayersDidChange();
-  }
+  // cc::Layers are created and removed in PaintArtifactCompositor so ensure it
+  // is notified that something has changed.
+  client_.GraphicsLayersDidChange();
 }
 
 void GraphicsLayer::SetOffsetFromLayoutObject(const IntSize& offset) {
@@ -318,8 +288,6 @@
 
   if (MaskLayer())
     MaskLayer()->PaintRecursivelyInternal(repainted_layers);
-  if (ContentsClippingMaskLayer())
-    ContentsClippingMaskLayer()->PaintRecursivelyInternal(repainted_layers);
 
   for (auto* child : Children())
     child->PaintRecursivelyInternal(repainted_layers);
@@ -421,31 +389,8 @@
 }
 
 void GraphicsLayer::UpdateChildList() {
-  // When using layer lists, cc::Layers are created in PaintArtifactCompositor.
-  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
-      RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-    client_.GraphicsLayersDidChange();
-    return;
-  }
-
-  cc::Layer* child_host = layer_.get();
-  child_host->RemoveAllChildren();
-
-  ClearContentsLayerIfUnregistered();
-
-  if (contents_layer_) {
-    // FIXME: Add the contents layer in the correct order with negative z-order
-    // children. This does not currently cause visible rendering issues because
-    // contents layers are only used for replaced elements that don't have
-    // children.
-    child_host->AddChild(contents_layer_);
-  }
-
-  for (size_t i = 0; i < children_.size(); ++i)
-    child_host->AddChild(children_[i]->CcLayer());
-
-  for (size_t i = 0; i < link_highlights_.size(); ++i)
-    child_host->AddChild(link_highlights_[i]->Layer());
+  // cc::Layers are created in PaintArtifactCompositor.
+  client_.GraphicsLayersDidChange();
 }
 
 void GraphicsLayer::UpdateLayerIsDrawable() {
@@ -495,18 +440,6 @@
       image_layer_->SetBounds(static_cast<gfx::Size>(image_size_));
     }
   }
-
-  if (contents_clipping_mask_layer_) {
-    if (IntSize(contents_clipping_mask_layer_->Size()) !=
-        contents_rect_.Size()) {
-      contents_clipping_mask_layer_->SetSize(gfx::Size(contents_rect_.Size()));
-      contents_clipping_mask_layer_->SetNeedsDisplay();
-    }
-    contents_clipping_mask_layer_->SetPosition(FloatPoint());
-    contents_clipping_mask_layer_->SetOffsetFromLayoutObject(
-        OffsetFromLayoutObject() +
-        IntSize(contents_rect_.Location().X(), contents_rect_.Location().Y()));
-  }
 }
 
 static HashSet<int>* g_registered_layer_set;
@@ -562,17 +495,7 @@
   // SetDrawsContent() and SetContentsVisible().
   contents_layer_->SetIsDrawable(contents_visible_);
   contents_layer_->SetHitTestable(contents_visible_);
-
-  // Insert the content layer first. Video elements require this, because they
-  // have shadow content that must display in front of the video.
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
-      !RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-    CcLayer()->InsertChild(contents_layer_, 0);
-  }
-  cc::PictureLayer* border_cc_layer =
-      contents_clipping_mask_layer_ ? contents_clipping_mask_layer_->CcLayer()
-                                    : nullptr;
-  contents_layer_->SetMaskLayer(border_cc_layer);
+  contents_layer_->SetMaskLayer(nullptr);
   contents_layer_->Set3dSortingContextId(rendering_context3d_);
 }
 
@@ -795,34 +718,12 @@
     return;
 
   mask_layer_ = mask_layer;
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
-    CcLayer()->SetMaskLayer(mask_layer_ ? mask_layer_->CcLayer() : nullptr);
-}
-
-void GraphicsLayer::SetContentsClippingMaskLayer(
-    GraphicsLayer* contents_clipping_mask_layer) {
-  if (contents_clipping_mask_layer == contents_clipping_mask_layer_)
-    return;
-
-  contents_clipping_mask_layer_ = contents_clipping_mask_layer;
-  cc::Layer* contents_layer = ContentsLayerIfRegistered();
-  if (!contents_layer)
-    return;
-  cc::PictureLayer* contents_clipping_mask_cc_layer =
-      contents_clipping_mask_layer_ ? contents_clipping_mask_layer_->CcLayer()
-                                    : nullptr;
-  contents_layer->SetMaskLayer(contents_clipping_mask_cc_layer);
-  UpdateContentsRect();
 }
 
 bool GraphicsLayer::BackfaceVisibility() const {
   return CcLayer()->double_sided();
 }
 
-void GraphicsLayer::SetBackfaceVisibility(bool visible) {
-  CcLayer()->SetDoubleSided(visible);
-}
-
 void GraphicsLayer::SetOpacity(float opacity) {
   CcLayer()->SetOpacity(opacity);
 }
@@ -952,22 +853,6 @@
   return layer_.get();
 }
 
-void GraphicsLayer::SetFilters(CompositorFilterOperations filters) {
-  CcLayer()->SetFilters(filters.ReleaseCcFilterOperations());
-}
-
-void GraphicsLayer::SetBackdropFilters(
-    CompositorFilterOperations filters,
-    const gfx::RRectF& backdrop_filter_bounds) {
-  CcLayer()->SetBackdropFilters(filters.ReleaseCcFilterOperations());
-  CcLayer()->SetBackdropFilterBounds(backdrop_filter_bounds);
-}
-
-void GraphicsLayer::SetStickyPositionConstraint(
-    const cc::LayerStickyPositionConstraint& sticky_constraint) {
-  CcLayer()->SetStickyPositionConstraint(sticky_constraint);
-}
-
 void GraphicsLayer::SetFilterQuality(SkFilterQuality filter_quality) {
   if (image_layer_)
     image_layer_->SetNearestNeighbor(filter_quality == kNone_SkFilterQuality);
@@ -1080,11 +965,9 @@
         std::make_unique<LayerState>(LayerState{layer_state, layer_offset});
   }
 
-  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-    if (auto* layer = CcLayer())
-      layer->SetSubtreePropertyChanged();
-    client_.GraphicsLayersDidChange();
-  }
+  if (auto* layer = CcLayer())
+    layer->SetSubtreePropertyChanged();
+  client_.GraphicsLayersDidChange();
 }
 
 void GraphicsLayer::SetContentsLayerState(const PropertyTreeState& layer_state,
@@ -1102,10 +985,8 @@
         std::make_unique<LayerState>(LayerState{layer_state, layer_offset});
   }
 
-  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-    ContentsLayer()->SetSubtreePropertyChanged();
-    client_.GraphicsLayersDidChange();
-  }
+  ContentsLayer()->SetSubtreePropertyChanged();
+  client_.GraphicsLayersDidChange();
 }
 
 scoped_refptr<cc::DisplayItemList> GraphicsLayer::PaintContentsToDisplayList(
diff --git a/third_party/blink/renderer/platform/graphics/graphics_layer.h b/third_party/blink/renderer/platform/graphics/graphics_layer.h
index 151b39c..f2f6f66 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_layer.h
+++ b/third_party/blink/renderer/platform/graphics/graphics_layer.h
@@ -62,12 +62,10 @@
 namespace cc {
 class PictureImageLayer;
 class PictureLayer;
-struct OverscrollBehavior;
 }  // namespace cc
 
 namespace blink {
 
-class CompositorFilterOperations;
 class Image;
 class LinkHighlight;
 class PaintController;
@@ -119,11 +117,6 @@
   GraphicsLayer* MaskLayer() const { return mask_layer_; }
   void SetMaskLayer(GraphicsLayer*);
 
-  GraphicsLayer* ContentsClippingMaskLayer() const {
-    return contents_clipping_mask_layer_;
-  }
-  void SetContentsClippingMaskLayer(GraphicsLayer*);
-
   // The offset is the origin of the layoutObject minus the origin of the
   // graphics layer (so either zero or negative).
   IntSize OffsetFromLayoutObject() const { return offset_from_layout_object_; }
@@ -182,7 +175,6 @@
   void SetContentsOpaque(bool);
 
   bool BackfaceVisibility() const;
-  void SetBackfaceVisibility(bool visible);
 
   float Opacity() const;
   void SetOpacity(float);
@@ -195,11 +187,6 @@
   void SetHitTestable(bool);
   bool GetHitTestable() const { return hit_testable_; }
 
-  void SetFilters(CompositorFilterOperations);
-  void SetBackdropFilters(CompositorFilterOperations, const gfx::RRectF&);
-
-  void SetStickyPositionConstraint(const cc::LayerStickyPositionConstraint&);
-
   void SetFilterQuality(SkFilterQuality);
 
   // Some GraphicsLayers paint only the foreground or the background content
@@ -280,13 +267,6 @@
 
   void SetHasWillChangeTransformHint(bool);
 
-  void SetOverscrollBehavior(const cc::OverscrollBehavior&);
-
-  void SetSnapContainerData(base::Optional<cc::SnapContainerData>);
-
-  void SetIsResizedByBrowserControls(bool);
-  void SetIsContainerForFixedPositionLayers(bool);
-
   bool HasLayerState() const { return layer_state_.get(); }
   void SetLayerState(const PropertyTreeState&, const IntPoint& layer_offset);
   const PropertyTreeState& GetPropertyTreeState() const {
@@ -391,8 +371,6 @@
 
   // Reference to mask layer. We don't own this.
   GraphicsLayer* mask_layer_;
-  // Reference to clipping mask layer. We don't own this.
-  GraphicsLayer* contents_clipping_mask_layer_;
 
   IntRect contents_rect_;
 
diff --git a/third_party/blink/renderer/platform/graphics/graphics_layer_client.h b/third_party/blink/renderer/platform/graphics/graphics_layer_client.h
index efe7a2a..23c2ba9 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_layer_client.h
+++ b/third_party/blink/renderer/platform/graphics/graphics_layer_client.h
@@ -43,9 +43,7 @@
   kGraphicsLayerPaintMask = (1 << 2),
   kGraphicsLayerPaintOverflowContents = (1 << 3),
   kGraphicsLayerPaintCompositedScroll = (1 << 4),
-  kGraphicsLayerPaintChildClippingMask = (1 << 5),
-  kGraphicsLayerPaintAncestorClippingMask = (1 << 6),
-  kGraphicsLayerPaintDecoration = (1 << 7),
+  kGraphicsLayerPaintDecoration = (1 << 5),
   kGraphicsLayerPaintAllWithOverflowClip =
       (kGraphicsLayerPaintBackground | kGraphicsLayerPaintForeground |
        kGraphicsLayerPaintMask | kGraphicsLayerPaintDecoration)
diff --git a/third_party/blink/renderer/platform/graphics/graphics_layer_test.cc b/third_party/blink/renderer/platform/graphics/graphics_layer_test.cc
index 68593d4..c230eb53 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_layer_test.cc
+++ b/third_party/blink/renderer/platform/graphics/graphics_layer_test.cc
@@ -71,9 +71,7 @@
   ViewportLayersSetup layers_;
 };
 
-INSTANTIATE_TEST_SUITE_P(All,
-                         GraphicsLayerTest,
-                         testing::Values(0, kBlinkGenPropertyTrees));
+INSTANTIATE_TEST_SUITE_P(All, GraphicsLayerTest, testing::Values(0));
 
 TEST_P(GraphicsLayerTest, Paint) {
   IntRect interest_rect(1, 2, 3, 4);
@@ -134,14 +132,6 @@
                                   transform_root));
   layers_.graphics_layer_client().SetNeedsRepaint(true);
   layers_.graphics_layer().PaintRecursively();
-
-  // With BlinkGenPropertyTrees, these are not cleared until after paint.
-  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-    EXPECT_FALSE(transform1->Changed(
-        PaintPropertyChangeType::kChangedOnlyCompositedValues, transform_root));
-    EXPECT_FALSE(transform2->Changed(
-        PaintPropertyChangeType::kChangedOnlyCompositedValues, transform_root));
-  }
 }
 
 TEST_P(GraphicsLayerTest, SetDrawsContentFalse) {
diff --git a/third_party/blink/renderer/platform/graphics/paint/display_item_raster_invalidator_test.cc b/third_party/blink/renderer/platform/graphics/paint/display_item_raster_invalidator_test.cc
index 4b6cfb00..f3d5ff7 100644
--- a/third_party/blink/renderer/platform/graphics/paint/display_item_raster_invalidator_test.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/display_item_raster_invalidator_test.cc
@@ -29,10 +29,8 @@
         // invalidation rects.
         IntRect(0, 0, 20000, 20000), PropertyTreeState::Root());
     GetPaintController().FinishCycle();
-    if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-      GetPaintController().ClearPropertyTreeChangedStateTo(
-          PropertyTreeState::Root());
-    }
+    GetPaintController().ClearPropertyTreeChangedStateTo(
+        PropertyTreeState::Root());
 
     if (invalidator_.GetTracking())
       return invalidator_.GetTracking()->Invalidations();
diff --git a/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.cc b/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.cc
index 17acefc..aedb6cac 100644
--- a/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.cc
@@ -55,8 +55,6 @@
                   type,
                   sizeof(*this)),
       offset_(offset) {
-  DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
-         RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled());
   DCHECK(IsForeignLayerType(type));
   DCHECK(GetLayer());
   DCHECK(!IsCacheable());
diff --git a/third_party/blink/renderer/platform/graphics/paint/paint_artifact.cc b/third_party/blink/renderer/platform/graphics/paint/paint_artifact.cc
index be5ce07..aca3dfa 100644
--- a/third_party/blink/renderer/platform/graphics/paint/paint_artifact.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/paint_artifact.cc
@@ -190,7 +190,6 @@
   // for clearing the property tree changed state at the end of paint instead of
   // in FinishCycle. See: LocalFrameView::RunPaintLifecyclePhase.
   bool clear_property_tree_changed =
-      !RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
       RuntimeEnabledFeatures::CompositeAfterPaintEnabled();
   for (auto& chunk : chunks_) {
     chunk.client_is_just_created = false;
diff --git a/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc b/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc
index 779177e..983c720 100644
--- a/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc
@@ -560,8 +560,6 @@
 
 void PaintController::ClearPropertyTreeChangedStateTo(
     const PropertyTreeState& to) {
-  DCHECK(RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled());
-
   // Calling |ClearChangedTo| for every chunk is O(|property nodes|^2) and
   // could be optimized by caching which nodes that have already been cleared.
   for (const auto& chunk : current_paint_artifact_->PaintChunks()) {
diff --git a/third_party/blink/renderer/platform/graphics/paint/paint_controller_test.cc b/third_party/blink/renderer/platform/graphics/paint/paint_controller_test.cc
index ccf493c..098e3f31 100644
--- a/third_party/blink/renderer/platform/graphics/paint/paint_controller_test.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/paint_controller_test.cc
@@ -34,10 +34,8 @@
     All,
     PaintControllerTest,
     testing::Values(0,
-                    kBlinkGenPropertyTrees,
                     kCompositeAfterPaint,
                     kUnderInvalidationChecking,
-                    kBlinkGenPropertyTrees | kUnderInvalidationChecking,
                     kCompositeAfterPaint | kUnderInvalidationChecking));
 
 TEST_P(PaintControllerTest, NestedRecorders) {
diff --git a/third_party/blink/renderer/platform/graphics/paint/raster_invalidator_test.cc b/third_party/blink/renderer/platform/graphics/paint/raster_invalidator_test.cc
index 6d8f3913..f4ad986 100644
--- a/third_party/blink/renderer/platform/graphics/paint/raster_invalidator_test.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/raster_invalidator_test.cc
@@ -37,11 +37,9 @@
   void FinishCycle(PaintArtifact& artifact) {
     artifact.FinishCycle();
     ClearGeometryMapperCache();
-    if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-      // See PaintArtifact::FinishCycle() for the reason of doing this.
-      for (auto& chunk : artifact.PaintChunks())
-        chunk.properties.ClearChangedToRoot();
-    }
+    // See PaintArtifact::FinishCycle() for the reason of doing this.
+    for (auto& chunk : artifact.PaintChunks())
+      chunk.properties.ClearChangedToRoot();
   }
 
   const Vector<RasterInvalidationInfo>& TrackedRasterInvalidations() {
diff --git a/third_party/blink/renderer/platform/graphics/squashing_disallowed_reasons.cc b/third_party/blink/renderer/platform/graphics/squashing_disallowed_reasons.cc
index 0e8d14de..6aa6dd0 100644
--- a/third_party/blink/renderer/platform/graphics/squashing_disallowed_reasons.cc
+++ b/third_party/blink/renderer/platform/graphics/squashing_disallowed_reasons.cc
@@ -46,10 +46,6 @@
          "Cannot be squashed without breaking paint order"},
         {SquashingDisallowedReason::kSquashingVideoIsDisallowed,
          "squashingVideoIsDisallowed", "Squashing video is not supported"},
-        {SquashingDisallowedReason::kSquashedLayerClipsCompositingDescendants,
-         "squashedLayerClipsSquashingDisallowedDescendants",
-         "Squashing a layer that clips composited descendants is not "
-         "supported."},
         {SquashingDisallowedReason::kSquashingLayoutEmbeddedContentIsDisallowed,
          "squashingLayoutEmbeddedContentIsDisallowed",
          "Squashing a frame, iframe or plugin is not supported."},
diff --git a/third_party/blink/renderer/platform/graphics/squashing_disallowed_reasons.h b/third_party/blink/renderer/platform/graphics/squashing_disallowed_reasons.h
index a3d986d7..99102b24 100644
--- a/third_party/blink/renderer/platform/graphics/squashing_disallowed_reasons.h
+++ b/third_party/blink/renderer/platform/graphics/squashing_disallowed_reasons.h
@@ -21,7 +21,6 @@
   V(FilterMismatch)                             \
   V(WouldBreakPaintOrder)                       \
   V(SquashingVideoIsDisallowed)                 \
-  V(SquashedLayerClipsCompositingDescendants)   \
   V(SquashingLayoutEmbeddedContentIsDisallowed) \
   V(SquashingBlendingIsDisallowed)              \
   V(NearestFixedPositionMismatch)               \
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index c2e494c1..85afb7df 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -177,11 +177,6 @@
       name: "BidiCaretAffinity",
     },
     {
-      name: "BlinkGenPropertyTrees",
-      status: "stable",
-      implied_by: ["CompositeAfterPaint"],
-    },
-    {
       name: "BlinkRuntimeCallStats",
     },
     {
diff --git a/third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h b/third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h
index 7ca9810..ad6a9ee 100644
--- a/third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h
+++ b/third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h
@@ -16,13 +16,6 @@
 // For cross-thread posting. Can be called from any thread.
 inline void PostCrossThreadTask(base::SequencedTaskRunner& task_runner,
                                 const base::Location& location,
-                                WTF::CrossThreadClosure task) {
-  task_runner.PostDelayedTask(location, ConvertToBaseCallback(std::move(task)),
-                              base::TimeDelta());
-}
-
-inline void PostCrossThreadTask(base::SequencedTaskRunner& task_runner,
-                                const base::Location& location,
                                 WTF::CrossThreadOnceClosure task) {
   task_runner.PostDelayedTask(
       location, ConvertToBaseOnceCallback(std::move(task)), base::TimeDelta());
@@ -30,14 +23,6 @@
 
 inline void PostDelayedCrossThreadTask(base::SequencedTaskRunner& task_runner,
                                        const base::Location& location,
-                                       WTF::CrossThreadClosure task,
-                                       base::TimeDelta delay) {
-  task_runner.PostDelayedTask(location, ConvertToBaseCallback(std::move(task)),
-                              delay);
-}
-
-inline void PostDelayedCrossThreadTask(base::SequencedTaskRunner& task_runner,
-                                       const base::Location& location,
                                        WTF::CrossThreadOnceClosure task,
                                        base::TimeDelta delay) {
   task_runner.PostDelayedTask(
diff --git a/third_party/blink/renderer/platform/testing/layer_tree_host_embedder.cc b/third_party/blink/renderer/platform/testing/layer_tree_host_embedder.cc
index 2cdfabe..4a192d5f 100644
--- a/third_party/blink/renderer/platform/testing/layer_tree_host_embedder.cc
+++ b/third_party/blink/renderer/platform/testing/layer_tree_host_embedder.cc
@@ -18,10 +18,7 @@
     cc::LayerTreeHostSingleThreadClient* single_thread_client) {
   cc::LayerTreeSettings settings;
   settings.single_thread_proxy_scheduler = false;
-  settings.use_layer_lists =
-      RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
-      RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled();
-
+  settings.use_layer_lists = true;
   animation_host_ = cc::AnimationHost::CreateMainInstance();
   cc::LayerTreeHost::InitParams params;
   params.client = client ? client : &layer_tree_host_client_;
diff --git a/third_party/blink/renderer/platform/testing/paint_test_configurations.h b/third_party/blink/renderer/platform/testing/paint_test_configurations.h
index 93c3686..fb5b973 100644
--- a/third_party/blink/renderer/platform/testing/paint_test_configurations.h
+++ b/third_party/blink/renderer/platform/testing/paint_test_configurations.h
@@ -12,24 +12,21 @@
 namespace blink {
 
 enum {
-  kBlinkGenPropertyTrees = 1 << 0,
-  kCompositeAfterPaint = 1 << 1,
-  kUnderInvalidationChecking = 1 << 2,
-  kFastBorderRadius = 1 << 3,
-  kPaintNonFastScrollableRegions = 1 << 4,
+  kCompositeAfterPaint = 1 << 0,
+  kUnderInvalidationChecking = 1 << 1,
+  kFastBorderRadius = 1 << 2,
+  kPaintNonFastScrollableRegions = 1 << 3,
 };
 
 class PaintTestConfigurations
     : public testing::WithParamInterface<unsigned>,
-      private ScopedBlinkGenPropertyTreesForTest,
       private ScopedCompositeAfterPaintForTest,
       private ScopedPaintUnderInvalidationCheckingForTest,
       private ScopedFastBorderRadiusForTest,
       private ScopedPaintNonFastScrollableRegionsForTest {
  public:
   PaintTestConfigurations()
-      : ScopedBlinkGenPropertyTreesForTest(GetParam() & kBlinkGenPropertyTrees),
-        ScopedCompositeAfterPaintForTest(GetParam() & kCompositeAfterPaint),
+      : ScopedCompositeAfterPaintForTest(GetParam() & kCompositeAfterPaint),
         ScopedPaintUnderInvalidationCheckingForTest(GetParam() &
                                                     kUnderInvalidationChecking),
         ScopedFastBorderRadiusForTest(GetParam() & kFastBorderRadius),
@@ -46,22 +43,17 @@
 };
 
 #define INSTANTIATE_PAINT_TEST_SUITE_P(test_class) \
-  INSTANTIATE_TEST_SUITE_P(                        \
-      All, test_class,                             \
-      ::testing::Values(0, kBlinkGenPropertyTrees, \
-                        kBlinkGenPropertyTrees | kCompositeAfterPaint))
+  INSTANTIATE_TEST_SUITE_P(All, test_class,        \
+                           ::testing::Values(0, kCompositeAfterPaint))
 
 #define INSTANTIATE_CAP_TEST_SUITE_P(test_class) \
-  INSTANTIATE_TEST_SUITE_P(                      \
-      All, test_class,                           \
-      ::testing::Values(kBlinkGenPropertyTrees | kCompositeAfterPaint))
+  INSTANTIATE_TEST_SUITE_P(All, test_class,      \
+                           ::testing::Values(kCompositeAfterPaint))
 
-#define INSTANTIATE_LAYER_LIST_TEST_SUITE_P(test_class)                \
-  INSTANTIATE_TEST_SUITE_P(                                            \
-      All, test_class,                                                 \
-      ::testing::Values(kBlinkGenPropertyTrees,                        \
-                        kBlinkGenPropertyTrees | kCompositeAfterPaint, \
-                        kBlinkGenPropertyTrees | kFastBorderRadius))
+#define INSTANTIATE_LAYER_LIST_TEST_SUITE_P(test_class) \
+  INSTANTIATE_TEST_SUITE_P(                             \
+      All, test_class,                                  \
+      ::testing::Values(0, kCompositeAfterPaint, kFastBorderRadius))
 
 #define INSTANTIATE_SCROLL_HIT_TEST_SUITE_P(test_class) \
   INSTANTIATE_TEST_SUITE_P(                             \
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-features=UseSkiaRenderer b/third_party/blink/web_tests/FlagExpectations/enable-features=UseSkiaRenderer
index c0ccb3ca..4c0d83b 100644
--- a/third_party/blink/web_tests/FlagExpectations/enable-features=UseSkiaRenderer
+++ b/third_party/blink/web_tests/FlagExpectations/enable-features=UseSkiaRenderer
@@ -1,6 +1,5 @@
 # Tests fail even with a fuzzy pixel diff. They require a re-baseline.
 crbug.com/954328 compositing/lots-of-img-layers.html [ Failure ]
-crbug.com/954328 css3/filters/effect-blur-hw.html [ Failure ]
 crbug.com/954328 media/video-layer-crash.html [ Failure ]
 crbug.com/954328 transforms/3d/point-mapping/3d-point-mapping-deep.html [ Failure ]
 
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-gpu-rasterization b/third_party/blink/web_tests/FlagExpectations/enable-gpu-rasterization
index 70a3fffe..fe65588d 100644
--- a/third_party/blink/web_tests/FlagExpectations/enable-gpu-rasterization
+++ b/third_party/blink/web_tests/FlagExpectations/enable-gpu-rasterization
@@ -22,7 +22,6 @@
 crbug.com/972621 css3/filters/blur-filter-page-scroll-parents.html [ Skip ]
 crbug.com/972621 css3/filters/blur-filter-page-scroll.html [ Skip ]
 crbug.com/972621 css3/filters/crash-filter-change.html [ Skip ]
-crbug.com/972621 css3/filters/effect-blur-hw.html [ Skip ]
 crbug.com/972621 css3/filters/effect-blur.html [ Skip ]
 crbug.com/972621 css3/filters/effect-brightness-clamping.html [ Skip ]
 crbug.com/972621 css3/filters/effect-combined.html [ Skip ]
@@ -85,23 +84,6 @@
 crbug.com/954328 compositing/fixed-background-after-style-recalc.html [ Failure ]
 crbug.com/954328 compositing/overflow/mask-with-filter.html [ Failure ]
 crbug.com/954328 compositing/overflow/scrollbar-layer-placement-negative-z-index-child.html [ Failure ]
-crbug.com/954328 css3/blending/background-blend-mode-crossfade-image-gradient.html [ Failure ]
-crbug.com/954328 css3/blending/background-blend-mode-default-value.html [ Failure ]
-crbug.com/954328 css3/blending/background-blend-mode-gradient-gradient.html [ Failure ]
-crbug.com/954328 css3/blending/background-blend-mode-gradient-image.html [ Failure ]
-crbug.com/954328 css3/blending/background-blend-mode-image-color.html [ Failure ]
-crbug.com/954328 css3/blending/background-blend-mode-image-image.html [ Failure ]
-crbug.com/954328 css3/blending/background-blend-mode-image-svg.html [ Failure ]
-crbug.com/954328 css3/blending/background-blend-mode-multiple-background-layers.html [ Failure ]
-crbug.com/954328 css3/blending/background-blend-mode-single-layer-no-blending.html [ Failure ]
-crbug.com/954328 css3/blending/background-blend-mode-svg-color.html [ Failure ]
-crbug.com/954328 css3/blending/background-blend-mode-tiled-gradient.html [ Failure ]
-crbug.com/954328 css3/blending/effect-background-blend-mode-stacking.html [ Failure ]
-crbug.com/954328 css3/blending/effect-background-blend-mode-tiled.html [ Failure ]
-crbug.com/954328 css3/blending/effect-background-blend-mode.html [ Failure ]
-crbug.com/954328 css3/blending/mix-blend-mode-isolated-group-1.html [ Failure ]
-crbug.com/954328 css3/blending/mix-blend-mode-isolated-group-2.html [ Failure ]
-crbug.com/954328 css3/blending/mix-blend-mode-isolated-group-3.html [ Failure ]
 crbug.com/954328 css3/filters/filter-change-repaint.html [ Failure ]
 crbug.com/954328 css3/filters/filter-repaint-blur.html [ Failure ]
 crbug.com/954328 css3/filters/filter-repaint-child-layers.html [ Failure ]
diff --git a/third_party/blink/web_tests/FlagExpectations/use-gl=any b/third_party/blink/web_tests/FlagExpectations/use-gl=any
new file mode 100644
index 0000000..94a7f8e
--- /dev/null
+++ b/third_party/blink/web_tests/FlagExpectations/use-gl=any
@@ -0,0 +1,9 @@
+# Need a Skia GL specific baseline.
+crbug.com/993384 css3/blending/background-blend-mode-crossfade-image-gradient.html [ Skip ]
+crbug.com/993384 css3/blending/background-blend-mode-gradient-image.html [ Skip ]
+crbug.com/993384 css3/blending/background-blend-mode-image-color.html [ Skip ]
+crbug.com/993384 css3/blending/background-blend-mode-image-image.html [ Skip ]
+crbug.com/993384 css3/blending/background-blend-mode-image-svg.html [ Skip ]
+crbug.com/993384 css3/blending/background-blend-mode-tiled-gradient.html [ Skip ]
+crbug.com/993384 css3/blending/effect-background-blend-mode-tiled.html [ Skip ]
+crbug.com/993384 css3/blending/effect-background-blend-mode.html [ Skip ]
diff --git a/third_party/blink/web_tests/FlagExpectations/use-vulkan=native b/third_party/blink/web_tests/FlagExpectations/use-vulkan=native
index e9afe045..1a82e940 100644
--- a/third_party/blink/web_tests/FlagExpectations/use-vulkan=native
+++ b/third_party/blink/web_tests/FlagExpectations/use-vulkan=native
@@ -1,6 +1,5 @@
 # Tests fail even with a fuzzy pixel diff. They require a re-baseline.
 crbug.com/954328 compositing/lots-of-img-layers.html [ Failure ]
-crbug.com/954328 css3/filters/effect-blur-hw.html [ Failure ]
 crbug.com/954328 media/video-layer-crash.html [ Failure ]
 crbug.com/954328 transforms/3d/point-mapping/3d-point-mapping-deep.html [ Failure ]
 
@@ -106,23 +105,6 @@
 
 # Rebaseline
 crbug.com/972637 compositing/fixed-background-after-style-recalc.html [ Skip ]
-crbug.com/972637 css3/blending/background-blend-mode-crossfade-image-gradient.html [ Skip ]
-crbug.com/972637 css3/blending/background-blend-mode-default-value.html [ Skip ]
-crbug.com/972637 css3/blending/background-blend-mode-gradient-gradient.html [ Skip ]
-crbug.com/972637 css3/blending/background-blend-mode-gradient-image.html [ Skip ]
-crbug.com/972637 css3/blending/background-blend-mode-image-color.html [ Skip ]
-crbug.com/972637 css3/blending/background-blend-mode-image-image.html [ Skip ]
-crbug.com/972637 css3/blending/background-blend-mode-image-svg.html [ Skip ]
-crbug.com/972637 css3/blending/background-blend-mode-multiple-background-layers.html [ Skip ]
-crbug.com/972637 css3/blending/background-blend-mode-single-layer-no-blending.html [ Skip ]
-crbug.com/972637 css3/blending/background-blend-mode-svg-color.html [ Skip ]
-crbug.com/972637 css3/blending/background-blend-mode-tiled-gradient.html [ Skip ]
-crbug.com/972637 css3/blending/effect-background-blend-mode-stacking.html [ Skip ]
-crbug.com/972637 css3/blending/effect-background-blend-mode-tiled.html [ Skip ]
-crbug.com/972637 css3/blending/effect-background-blend-mode.html [ Skip ]
-crbug.com/972637 css3/blending/mix-blend-mode-isolated-group-1.html [ Skip ]
-crbug.com/972637 css3/blending/mix-blend-mode-isolated-group-2.html [ Skip ]
-crbug.com/972637 css3/blending/mix-blend-mode-isolated-group-3.html [ Skip ]
 crbug.com/972637 css3/masking/mask-luminance-png.html [ Skip ]
 crbug.com/972637 css3/masking/mask-repeat-space-border.html [ Skip ]
 crbug.com/972637 images/color-profile-animate-rotate.html [ Skip ]
@@ -149,3 +131,5 @@
 crbug.com/972637 images/webp-color-profile-lossy.html [ Skip ]
 crbug.com/972637 media/video-poster-scale.html [ Skip ]
 
+# Need a Vulkan native specific baseline.
+crbug.com/993384 css3/blending/background-blend-mode-image-svg.html [ Skip ]
diff --git a/third_party/blink/web_tests/FlagExpectations/use-vulkan=swiftshader b/third_party/blink/web_tests/FlagExpectations/use-vulkan=swiftshader
index 3d4f400c..0d68b65 100644
--- a/third_party/blink/web_tests/FlagExpectations/use-vulkan=swiftshader
+++ b/third_party/blink/web_tests/FlagExpectations/use-vulkan=swiftshader
@@ -4,32 +4,9 @@
 
 # Flaky BlinkTestController::OnPixelDumpCaptured Crash. We want to still run to
 # detect failures other than the crash.
-crbug.com/963542 animations/svg/animated-filter-svg-element.html [ Failure Pass ]
-crbug.com/963542 compositing/background-color/background-color-outside-document.html [ Failure Pass ]
-crbug.com/963542 compositing/color-matching/image-color-matching.html [ Failure Pass ]
-crbug.com/963542 compositing/culling/filter-occlusion-blur.html [ Failure Pass ]
-crbug.com/963542 compositing/geometry/bounds-ignores-hidden-dynamic.html [ Failure Pass ]
-crbug.com/963542 compositing/geometry/horizontal-scroll-composited.html [ Failure Pass ]
-crbug.com/963542 compositing/opacity-with-mask.html [ Failure Pass ]
-crbug.com/963542 compositing/overflow/border-radius-on-parent-composited-grandchild.html [ Failure Pass ]
-crbug.com/963542 compositing/overflow/nested-border-radius-clipping.html [ Failure Pass ]
-crbug.com/963542 compositing/overflow/scrolling-content-layer-should-not-be-clipped.html [ Failure Pass ]
-crbug.com/963542 compositing/overlap-blending/reflection-opacity-huge.html [ Failure Pass ]
-crbug.com/963542 compositing/squashing/squash-onto-nephew-subpixel-3.html [ Failure Pass ]
-crbug.com/963542 compositing/squashing/squash-with-ancestor-mask.html [ Failure Pass ]
-crbug.com/963542 compositing/squashing/squash-with-ancestor-reflection.html [ Failure Pass ]
-crbug.com/963542 css3/blending/svg-blend-multiply.html [ Failure Pass ]
-crbug.com/963542 css3/filters/backdrop-filter-basic-blur.html [ Failure Pass ]
-crbug.com/963542 css3/flexbox/button.html [ Failure Pass ]
-crbug.com/963542 css3/flexbox/columns-center-with-margins-and-wrap.html [ Failure Pass ]
-crbug.com/963542 images/color-profile-border-radius.html [ Failure Pass ]
-crbug.com/963542 images/feature-policy-oversized-images-forced-layout.html [ Failure Pass ]
 crbug.com/963542 media/alpha-video-playback.html [ Skip ]
 crbug.com/963542 media/video-layer-crash.html [ Skip ]
 
-# Flaky VkImage::Copy Asset Crash
-crbug.com/972087 compositing/layer-creation/overlap-negative-z-index-multiple.html [ Failure Pass ]
-
 # SwiftShader Unimplemented Blend Mode
 crbug.com/972096 compositing/reflections/animation-inside-reflection.html [ Skip ]
 crbug.com/972096 compositing/reflections/nested-reflection-anchor-point.html [ Skip ]
@@ -43,9 +20,6 @@
 crbug.com/972096 css3/filters/composited-reflected.html [ Skip ]
 crbug.com/972096 media/controls/video-enter-exit-fullscreen-without-hovering-doesnt-show-controls.html [ Skip ]
 
-# Flaky SwiftShader Invalid VkFormat
-crbug.com/972109 css3/flexbox/auto-height-column-with-border-and-padding.html [ Failure Pass ]
-
 # Incorrect Blurring
 crbug.com/972621 compositing/culling/filter-occlusion-blur-large.html [ Skip ]
 crbug.com/972621 compositing/culling/scrolled-within-boxshadow.html [ Skip ]
@@ -101,28 +75,11 @@
 crbug.com/972621 transforms/transformed-document-element.html [ Skip ]
 
 # Blurring - Needs Rebaseline for GPU Rasterization
-crbug.com/972637 css3/blending/background-blend-mode-crossfade-image-gradient.html [ Skip ]
-crbug.com/972637 css3/blending/background-blend-mode-default-value.html [ Skip ]
-crbug.com/972637 css3/blending/background-blend-mode-gradient-gradient.html [ Skip ]
-crbug.com/972637 css3/blending/background-blend-mode-gradient-image.html [ Skip ]
-crbug.com/972637 css3/blending/background-blend-mode-image-color.html [ Skip ]
-crbug.com/972637 css3/blending/background-blend-mode-image-image.html [ Skip ]
-crbug.com/972637 css3/blending/background-blend-mode-image-svg.html [ Skip ]
-crbug.com/972637 css3/blending/background-blend-mode-multiple-background-layers.html [ Skip ]
-crbug.com/972637 css3/blending/background-blend-mode-single-layer-no-blending.html [ Skip ]
-crbug.com/972637 css3/blending/background-blend-mode-svg-color.html [ Skip ]
-crbug.com/972637 css3/blending/background-blend-mode-tiled-gradient.html [ Skip ]
-crbug.com/972637 css3/blending/mix-blend-mode-isolated-group-1.html [ Skip ]
-crbug.com/972637 css3/blending/mix-blend-mode-isolated-group-2.html [ Skip ]
-crbug.com/972637 css3/blending/mix-blend-mode-isolated-group-3.html [ Skip ]
 crbug.com/972637 images/rgb-png-with-cmyk-color-profile.html [ Skip ]
 crbug.com/972637 images/ycbcr-with-cmyk-color-profile.html [ Skip ]
 crbug.com/972637 media/video-poster-scale.html [ Skip ]
 
 # Gradients - Needs Rebaseline for GPU Rasterization
-crbug.com/972684 css3/blending/effect-background-blend-mode-stacking.html [ Skip ]
-crbug.com/972684 css3/blending/effect-background-blend-mode-tiled.html [ Skip ]
-crbug.com/972684 css3/blending/effect-background-blend-mode.html [ Skip ]
 crbug.com/972684 css3/filters/crash-filter-change.html [ Skip ]
 crbug.com/972684 css3/filters/effect-blur.html [ Skip ]
 crbug.com/972684 css3/filters/effect-brightness-clamping.html [ Skip ]
@@ -168,19 +125,6 @@
 crbug.com/963542 media/track/track-cue-rendering-horizontal.html [ Skip ]
 crbug.com/963542 media/video-frame-accurate-seek.html [ Skip ]
 
-# Flaky GPU process crashes with no stack trace. They may be crbug.com/963542
-# We will run them to detect failures other than crashes.
-Bug(none) compositing/gestures/gesture-tapHighlight-2-overflow-div-composited-outer-scroll-outer.html [ Failure Pass ]
-Bug(none) compositing/masks/masked-ancestor.html [ Failure Pass ]
-Bug(none) css3/filters/filter-repaint-shadow-layer-child.html [ Failure Pass ]
-Bug(none) css3/motion-path/offset-anchor-rotation.html [ Failure Pass ]
-Bug(none) media/media-captions-no-controls.html [ Failure Pass ]
-Bug(none) media/media-fragments/TC0014.html [ Failure Pass ]
-Bug(none) media/track/media-element-enqueue-event-crash.html [ Failure Pass ]
-Bug(none) media/video-controls-overflow-menu-fullscreen-button.html [ Failure Pass ]
-Bug(none) media/video-move-to-new-document-srcobject.html [ Failure Pass ]
-Bug(none) transforms/3d/point-mapping/3d-point-mapping-origins.html [ Failure Pass ]
-
 # Test consistently hitting default timeout.
 Bug(none) css3/filters/effect-reference-subregion.html [ Skip ]
 
diff --git a/third_party/blink/web_tests/SlowTests b/third_party/blink/web_tests/SlowTests
index 04218e2..325bb37 100644
--- a/third_party/blink/web_tests/SlowTests
+++ b/third_party/blink/web_tests/SlowTests
@@ -12,7 +12,6 @@
 crbug.com/24182 storage/indexeddb/mozilla/test_objectStore_openKeyCursor.html [ Slow ]
 crbug.com/24182 editing/selection/modify_move/move-by-word-visually-mac.html [ Slow ]
 crbug.com/24182 compositing/culling/filter-occlusion-blur-large.html [ Slow ]
-crbug.com/24182 compositing/video-frame-size-change.html [ Slow ]
 crbug.com/24182 editing/selection/caret-at-bidi-boundary.html [ Slow ]
 crbug.com/24182 editing/selection/modify_move/move-by-word-visually-crash-test-5.html [ Slow ]
 crbug.com/24182 fast/canvas/canvas-toBlob-toDataURL-race-imageEncoder-jpeg.html [ Slow ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 5e50d8c..2359ef6 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -259,7 +259,6 @@
 # Display locking failures
 crbug.com/955533 wpt_internal/display-lock/sizing/overflow-auto-with-overflow.html [ Failure ]
 # Skip some tests for rendersubtree
-crbug.com/991095 wpt_internal/display-lock/rendersubtree/containment [ Skip ]
 crbug.com/991095 wpt_internal/display-lock/rendersubtree/sizing [ Skip ]
 
 # virtual-scroller failures
@@ -2001,7 +2000,6 @@
 crbug.com/336604 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_visibility-collapse.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_wrap-reverse.html [ Failure ]
 crbug.com/467127 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/negative-margins-001.html [ Failure ]
-crbug.com/972227 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/overflow-auto-001.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/order_value.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/overflow-top-left.html [ Failure ]
 crbug.com/467127 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/percentage-heights-003.html [ Failure ]
@@ -6217,7 +6215,6 @@
 # Sheriff 2019-05-16
 crbug.com/963141 [ Linux ] media/video-object-fit.html [ Pass Failure ]
 crbug.com/963141 [ Linux ] virtual/audio-service/media/video-object-fit.html [ Pass Failure ]
-crbug.com/963740 compositing/video-frame-size-change.html [ Pass Failure ]
 
 # Sheriff 2019-05-17
 crbug.com/964239 virtual/threaded/external/wpt/css/css-scroll-snap/scroll-margin.html [ Pass Failure ]
@@ -6462,3 +6459,6 @@
 #Sheriff 2019-08-12
 crbug.com/783154 [ Linux Debug ] virtual/audio-service/media/controls/doubletap-to-jump-backwards.html [ Failure ]
 crbug.com/993238 fast/frames/frame-name-reset.html [ Pass Failure ]
+
+# Sheriff 2019-08-14
+crbug.com/993328 [ Mac ] virtual/audio-service/media/video-currentTime.html [ Pass Failure ]
diff --git a/third_party/blink/web_tests/compositing/video-frame-size-change.html b/third_party/blink/web_tests/compositing/video-frame-size-change.html
deleted file mode 100644
index 9e61dae2..0000000
--- a/third_party/blink/web_tests/compositing/video-frame-size-change.html
+++ /dev/null
@@ -1,52 +0,0 @@
-<!DOCTYPE html>
-<html>
-    <body onload="load()">
-        <p>Tests decoding and rendering a video element that has a changing resolution.</p>
-        <video width=320></video>
-        <video width=320></video>
-        <script>
-            if (window.testRunner) {
-                testRunner.waitUntilDone();
-            }
-
-            function load() {
-                function oncanplay() {
-                    // Make sure we render the first frame.
-                    requestAnimationFrame(function() {
-                        video.play();
-                    });
-                };
-
-                // Get the first video to stay on frame zero for comparison purposes.
-                var video = document.getElementsByTagName("video")[0];
-                video.src = "../media/resources/frame_size_change.webm";
-                video.addEventListener('canplay', oncanplay, {once: true});
-
-                // Get the second video to play through the clip with changing dimensions.
-                video = document.getElementsByTagName("video")[1];
-                video.src = "../media/resources/frame_size_change.webm";
-                video.addEventListener('canplay', oncanplay, {once: true});
-
-                video.addEventListener('playing', function() {
-                    // Make sure the video plays for a bit.
-                    video.addEventListener('timeupdate', function() {
-                        if (video.currentTime > 1.0) {
-                            video.pause();
-                        }
-                    });
-                });
-
-                video.addEventListener('pause', function() {
-                    // Now seek back to a point where resolution should be different.
-                    video.addEventListener('seeked', function() {
-                        if (window.testRunner) {
-                            testRunner.notifyDone();
-                        }
-                    });
-
-                    video.currentTime = 0.5;
-                });
-            }
-        </script>
-   </body>
-</html>
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 b22b82c..81c2bcb 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
@@ -131246,9 +131246,6 @@
    "css/css-animations/CSSAnimation-canceling.tentative-expected.txt": [
     []
    ],
-   "css/css-animations/CSSAnimation-id.tentative-expected.txt": [
-    []
-   ],
    "css/css-animations/CSSAnimation-playState.tentative-expected.txt": [
     []
    ],
@@ -201046,12 +201043,6 @@
      {}
     ]
    ],
-   "css/css-animations/parsing/transition-timing-function-computed.html": [
-    [
-     "css/css-animations/parsing/transition-timing-function-computed.html",
-     {}
-    ]
-   ],
    "css/css-animations/pending-style-changes-001.html": [
     [
      "css/css-animations/pending-style-changes-001.html",
@@ -211924,6 +211915,12 @@
      {}
     ]
    ],
+   "css/css-transitions/parsing/transition-timing-function-computed.html": [
+    [
+     "css/css-transitions/parsing/transition-timing-function-computed.html",
+     {}
+    ]
+   ],
    "css/css-transitions/parsing/transition-timing-function-invalid.html": [
     [
      "css/css-transitions/parsing/transition-timing-function-invalid.html",
@@ -344763,10 +344760,6 @@
    "4a0b9bdce744d9f452f4989b41025bd94931dc4b",
    "testharness"
   ],
-  "css/css-animations/CSSAnimation-id.tentative-expected.txt": [
-   "ba5b2dd663af787ad497a48428063bf1aa2e17c3",
-   "support"
-  ],
   "css/css-animations/CSSAnimation-id.tentative.html": [
    "623e01d2354aad5dc746558dbc40821d09173472",
    "testharness"
@@ -345307,10 +345300,6 @@
    "7ab823ea1da1535606ac4aad30fb21f423ba6703",
    "testharness"
   ],
-  "css/css-animations/parsing/transition-timing-function-computed.html": [
-   "9834dfdbf0dde78d0d2c1b468c5badddc2460ac9",
-   "testharness"
-  ],
   "css/css-animations/pending-style-changes-001.html": [
    "fb74d7fa7d062d60153d47913df9eb2b0c7267c8",
    "testharness"
@@ -391003,6 +390992,10 @@
    "4e3894f5aa94e00aa59406ee1aab92b9226483af",
    "testharness"
   ],
+  "css/css-transitions/parsing/transition-timing-function-computed.html": [
+   "9834dfdbf0dde78d0d2c1b468c5badddc2460ac9",
+   "testharness"
+  ],
   "css/css-transitions/parsing/transition-timing-function-invalid.html": [
    "00bd2131e0927ba38e633ad7be404b8ec26e51a9",
    "testharness"
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/transition-timing-function-computed.html b/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-timing-function-computed.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/css/css-animations/parsing/transition-timing-function-computed.html
rename to third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-timing-function-computed.html
diff --git a/third_party/blink/web_tests/external/wpt/xhr/getallresponseheaders-expected.txt b/third_party/blink/web_tests/external/wpt/xhr/getallresponseheaders-expected.txt
deleted file mode 100644
index 69617d19..0000000
--- a/third_party/blink/web_tests/external/wpt/xhr/getallresponseheaders-expected.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-This is a testharness.js-based test.
-FAIL XMLHttpRequest: getAllResponseHeaders() assert_equals: expected "also-here: Mr. PB\r\newok: lego\r\nfoo-test: 1, 2\r\n__custom: token\r\n" but got "__custom: token\r\nalso-here: Mr. PB\r\nfoo-test: 1, 2\r\newok: lego\r\n"
-PASS XMLHttpRequest: getAllResponseHeaders() 1
-PASS XMLHttpRequest: getAllResponseHeaders() 2
-PASS XMLHttpRequest: getAllResponseHeaders() 3
-PASS XMLHttpRequest: getAllResponseHeaders() 4
-PASS XMLHttpRequest: getAllResponseHeaders() 5
-PASS XMLHttpRequest: getAllResponseHeaders() 6
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-crossfade-image-gradient-expected.png b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-crossfade-image-gradient-expected.png
new file mode 100644
index 0000000..5bb473b
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-crossfade-image-gradient-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-default-value-expected.png b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-default-value-expected.png
new file mode 100644
index 0000000..09b22d4
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-default-value-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-gradient-gradient-expected.png b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-gradient-gradient-expected.png
new file mode 100644
index 0000000..45fc8b1a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-gradient-gradient-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-gradient-image-expected.png b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-gradient-image-expected.png
new file mode 100644
index 0000000..ccc18d9
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-gradient-image-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-image-color-expected.png b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-image-color-expected.png
new file mode 100644
index 0000000..e7c4934
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-image-color-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-image-image-expected.png b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-image-image-expected.png
new file mode 100644
index 0000000..4e813b0f4
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-image-image-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-image-svg-expected.png b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-image-svg-expected.png
new file mode 100644
index 0000000..0b0057dd
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-image-svg-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-multiple-background-layers-expected.png b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-multiple-background-layers-expected.png
new file mode 100644
index 0000000..2cad506
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-multiple-background-layers-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-single-layer-no-blending-expected.png b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-single-layer-no-blending-expected.png
new file mode 100644
index 0000000..0a510a6
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-single-layer-no-blending-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-svg-color-expected.png b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-svg-color-expected.png
new file mode 100644
index 0000000..085df7a2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-svg-color-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-tiled-gradient-expected.png b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-tiled-gradient-expected.png
new file mode 100644
index 0000000..ad76f8f
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/background-blend-mode-tiled-gradient-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/effect-background-blend-mode-expected.png b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/effect-background-blend-mode-expected.png
new file mode 100644
index 0000000..916b9b7
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/effect-background-blend-mode-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/effect-background-blend-mode-stacking-expected.png b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/effect-background-blend-mode-stacking-expected.png
new file mode 100644
index 0000000..4bbe4ad
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/effect-background-blend-mode-stacking-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/effect-background-blend-mode-tiled-expected.png b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/effect-background-blend-mode-tiled-expected.png
new file mode 100644
index 0000000..2016231
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/effect-background-blend-mode-tiled-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/mix-blend-mode-isolated-group-1-expected.png b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/mix-blend-mode-isolated-group-1-expected.png
new file mode 100644
index 0000000..d0e25d5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/mix-blend-mode-isolated-group-1-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/mix-blend-mode-isolated-group-2-expected.png b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/mix-blend-mode-isolated-group-2-expected.png
new file mode 100644
index 0000000..e501063
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/mix-blend-mode-isolated-group-2-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/mix-blend-mode-isolated-group-3-expected.png b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/mix-blend-mode-isolated-group-3-expected.png
new file mode 100644
index 0000000..1afcc1c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/css3/blending/mix-blend-mode-isolated-group-3-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/http/tests/devtools/unit/soft-drop-down-expected.txt b/third_party/blink/web_tests/http/tests/devtools/unit/soft-drop-down-expected.txt
index 01bd99d..e124cb8 100644
--- a/third_party/blink/web_tests/http/tests/devtools/unit/soft-drop-down-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/unit/soft-drop-down-expected.txt
@@ -3,35 +3,24 @@
 Item highlighted: fifth
 ArrowDown
 Item highlighted: sixth
-Item selected: sixth
 ArrowDown
 Item highlighted: seventh
-Item selected: seventh
 ArrowDown
 Item highlighted: eighth
-Item selected: eighth
 ArrowUp
 Item highlighted: seventh
-Item selected: seventh
 ArrowUp
 Item highlighted: sixth
-Item selected: sixth
 ArrowUp
 Item highlighted: fifth
-Item selected: fifth
 ArrowDown
 Item highlighted: sixth
-Item selected: sixth
 ArrowDown
 Item highlighted: seventh
-Item selected: seventh
 f
 Item highlighted: first
-Item selected: first
 f
 Item highlighted: fourth
-Item selected: fourth
 t
 Item highlighted: third
-Item selected: third
 
diff --git a/third_party/blink/web_tests/http/tests/media/resources/media-source/webm/test-v-128k-640x480-30fps-10kfr.webm b/third_party/blink/web_tests/http/tests/media/resources/media-source/webm/test-v-128k-640x480-30fps-10kfr.webm
new file mode 100644
index 0000000..75e38b0
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/media/resources/media-source/webm/test-v-128k-640x480-30fps-10kfr.webm
Binary files differ
diff --git a/third_party/blink/web_tests/http/tests/media/resources/media-source/webm/test-v-256k-320x240-30fps-10kfr.webm b/third_party/blink/web_tests/http/tests/media/resources/media-source/webm/test-v-256k-320x240-30fps-10kfr.webm
new file mode 100644
index 0000000..0250d26
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/media/resources/media-source/webm/test-v-256k-320x240-30fps-10kfr.webm
Binary files differ
diff --git a/third_party/blink/web_tests/http/tests/media/video-frame-size-change.html b/third_party/blink/web_tests/http/tests/media/video-frame-size-change.html
new file mode 100644
index 0000000..0527b93
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/media/video-frame-size-change.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<style>
+/* Keep videos side-by-side and top-aligned for a nice pixel diff */
+#wrapper {
+  white-space: nowrap;
+}
+#wrapper > video {
+  vertical-align: top;
+}
+</style>
+<div id='wrapper'>
+  <video id='single_size'></video><video id='mixed_size' ></video></div>
+<script>
+
+  if (window.testRunner) {
+      testRunner.waitUntilDone();
+  }
+
+  async function setupMse(video, contentType) {
+    let promise = new Promise((resolve, reject) => {
+      let mediaSource = new MediaSource();
+      video.src = window.URL.createObjectURL(mediaSource);
+
+      mediaSource.addEventListener('sourceopen', function(e) {
+        let sourceBuffer = mediaSource.addSourceBuffer(contentType);
+        resolve(sourceBuffer);
+      });
+    });
+    return promise;
+  }
+
+  async function appendBuffer(sourceBuffer, data) {
+    let promise = new Promise((resolve, reject) => {
+      sourceBuffer.addEventListener('updateend', resolve);
+      sourceBuffer.appendBuffer(data);
+    });
+    return promise;
+  }
+
+  (async _ => {
+    let response = await fetch('/media/resources/media-source/webm/test-v-256k-320x240-30fps-10kfr.webm');
+    let videoData240p = await response.arrayBuffer();
+
+    response = await fetch('/media/resources/media-source/webm/test-v-128k-640x480-30fps-10kfr.webm');
+    let videoData480p = await response.arrayBuffer();
+
+    // Set up the first video with content of a single size.
+    let singleSizeVideo = document.getElementById('single_size');
+    let ss_sourceBuffer = await setupMse(singleSizeVideo, 'video/webm; codecs="vp8"');
+    await appendBuffer(ss_sourceBuffer, videoData240p);
+
+    // Setup the second video with a single size for 1 second, followed by a larger size for 2 additional seconds.
+    let mixedSizeVideo = document.getElementById('mixed_size');
+    let ms_sourceBuffer = await setupMse(mixedSizeVideo, 'video/webm; codecs="vp8"');
+    await appendBuffer(ms_sourceBuffer, videoData240p);
+    ms_sourceBuffer.timestampOffset = 1;
+    await appendBuffer(ms_sourceBuffer, videoData480p);
+
+    // Seek the second video beyond the first size.
+    mixedSizeVideo.addEventListener('seeked', () => {
+      if (window.testRunner) {
+        // Make sure we render the seeked frame.
+        requestAnimationFrame(() => {
+          testRunner.notifyDone();
+        });
+      }
+    });
+    mixedSizeVideo.currentTime = 2;
+  })();
+</script>
diff --git a/third_party/blink/web_tests/platform/linux/compositing/video-frame-size-change-expected.png b/third_party/blink/web_tests/platform/linux/compositing/video-frame-size-change-expected.png
deleted file mode 100644
index bc7cd35..0000000
--- a/third_party/blink/web_tests/platform/linux/compositing/video-frame-size-change-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/http/tests/media/video-frame-size-change-expected.png b/third_party/blink/web_tests/platform/linux/http/tests/media/video-frame-size-change-expected.png
new file mode 100644
index 0000000..cf21510
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/http/tests/media/video-frame-size-change-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/compositing/video-frame-size-change-expected.png b/third_party/blink/web_tests/platform/mac/compositing/video-frame-size-change-expected.png
deleted file mode 100644
index 7c64dbac..0000000
--- a/third_party/blink/web_tests/platform/mac/compositing/video-frame-size-change-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/http/tests/media/video-frame-size-change-expected.png b/third_party/blink/web_tests/platform/mac/http/tests/media/video-frame-size-change-expected.png
new file mode 100644
index 0000000..d7120e9
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/http/tests/media/video-frame-size-change-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/compositing/video-frame-size-change-expected.png b/third_party/blink/web_tests/platform/win/compositing/video-frame-size-change-expected.png
deleted file mode 100644
index e7baa18..0000000
--- a/third_party/blink/web_tests/platform/win/compositing/video-frame-size-change-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/http/tests/media/video-frame-size-change-expected.png b/third_party/blink/web_tests/platform/win/http/tests/media/video-frame-size-change-expected.png
new file mode 100644
index 0000000..cf21510
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/http/tests/media/video-frame-size-change-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/http/tests/media/video-frame-size-change-expected.png b/third_party/blink/web_tests/platform/win7/http/tests/media/video-frame-size-change-expected.png
new file mode 100644
index 0000000..cf21510
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win7/http/tests/media/video-frame-size-change-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-commit.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-commit.html
index c80e6082..d268f2d5 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-commit.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-commit.html
@@ -10,7 +10,6 @@
 
 <style>
 #container {
-  contain: style layout;
   width: 150px;
   height: 150px;
   background: lightblue;
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-immediate-commit-resolves.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-immediate-commit-resolves.html
index 0ce33a0..a2747980 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-immediate-commit-resolves.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-immediate-commit-resolves.html
@@ -10,7 +10,6 @@
 
 <style>
 #container {
-  contain: style layout;
   width: 150px;
   height: 150px;
   background: lightblue;
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-immediate-update-and-commit.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-immediate-update-and-commit.html
index 5f480c1b7..5973fda 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-immediate-update-and-commit.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-immediate-update-and-commit.html
@@ -10,7 +10,6 @@
 
 <style>
 #container {
-  contain: style layout;
   width: 150px;
   height: 150px;
   background: lightblue;
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-in-breakable-div.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-in-breakable-div.html
index 2f04d777..e355b12f 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-in-breakable-div.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-in-breakable-div.html
@@ -10,7 +10,6 @@
 
 <style>
 #container {
-  contain: style layout;
   border-top: solid green 50px;
   border-bottom: solid green 50px;
 }
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-in-iframe.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-in-iframe.html
index bd9b32a..a6507310 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-in-iframe.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-in-iframe.html
@@ -12,7 +12,6 @@
 <iframe id="frame" srcdoc='
   <style>
   #container {
-    contain: style layout;
     width: 100px;
     height: 100px;
   }
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-on-composited-layer.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-on-composited-layer.html
index 4efc5c3..0dbb75d 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-on-composited-layer.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-on-composited-layer.html
@@ -11,7 +11,6 @@
 <style>
 #container {
   will-change: transform;
-  contain: style layout;
   width: 150px;
   height: 150px;
 }
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-on-display-contents.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-on-display-contents.html
index c6c5de2..59efa75 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-on-display-contents.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-on-display-contents.html
@@ -13,7 +13,7 @@
 <script>
 async_test(async (t) => {
   let div = document.createElement("div");
-  div.style = "display: contents; contain: style layout;";
+  div.style = "display: contents;";
   document.body.appendChild(div);
   await setInvisible(div).then(() => {
       // TODO(rakina): Change this once we support non-contained locking.
@@ -24,7 +24,6 @@
 
 async_test(async (t) => {
   let slot = document.createElement("slot");
-  slot.style = "contain: style layout;";
   document.body.appendChild(slot);
   await setInvisible(slot).then(() => {
       // TODO(rakina): Change this once we support non-contained locking.
@@ -35,7 +34,7 @@
 
 async_test(async (t) => {
   let slot = document.createElement("slot");
-  slot.style = "display: block; contain: style layout;";
+  slot.style = "display: block;";
   document.body.appendChild(slot);
   await setInvisible(slot).then(() => {
     // TODO(rakina): Change this once we support non-contained locking.
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-on-positioned-element.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-on-positioned-element.html
index 54537e53..89ea607 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-on-positioned-element.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-on-positioned-element.html
@@ -10,7 +10,6 @@
 
 <style>
 #container {
-  contain: style layout;
   width: 150px;
   height: 150px;
 
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-then-mark-for-reattach.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-then-mark-for-reattach.html
index b9a107f..79e4cd9a 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-then-mark-for-reattach.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-then-mark-for-reattach.html
@@ -22,7 +22,6 @@
   let shadowRoot = host.attachShadow({ mode: "open" });
   let locked = document.createElement("div");
   shadowRoot.appendChild(locked);
-  locked.style = "contain: style layout";
   locked.innerHTML = "<slot></slot>";
   locked.getBoundingClientRect();
   setInvisible(locked);
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-update-disconnect-commit.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-update-disconnect-commit.html
index 5035343f8..b96a466b 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-update-disconnect-commit.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-update-disconnect-commit.html
@@ -10,7 +10,6 @@
 
 <style>
 #container {
-  contain: style layout;
   width: 150px;
   height: 150px;
   background: lightblue;
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/activatable-locked-element-allows-anchor-links.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/activatable-locked-element-allows-anchor-links.html
index ca8e6e7..056dcd17 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/activatable-locked-element-allows-anchor-links.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/activatable-locked-element-allows-anchor-links.html
@@ -15,7 +15,6 @@
   background: lightblue;
 }
 #container {
-  contain: style layout;
   width: 150px;
   height: 150px;
   background: lightgreen;
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/activate-commit-same-frame.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/activate-commit-same-frame.html
index e52e254..b1de819 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/activate-commit-same-frame.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/activate-commit-same-frame.html
@@ -16,7 +16,6 @@
   background: lightblue;
 }
 #container {
-  contain: style layout;
   width: 150px;
   height: 150px;
   background: lightgreen;
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/activate-update-and-commit-same-frame.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/activate-update-and-commit-same-frame.html
index 6f2df7b..b29e869 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/activate-update-and-commit-same-frame.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/activate-update-and-commit-same-frame.html
@@ -16,7 +16,6 @@
   background: lightblue;
 }
 #container {
-  contain: style layout;
   width: 150px;
   height: 150px;
   background: lightgreen;
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/activate-update-same-frame.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/activate-update-same-frame.html
index 40228ab..2bac122 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/activate-update-same-frame.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/activate-update-same-frame.html
@@ -16,7 +16,6 @@
   background: lightblue;
 }
 #container {
-  contain: style layout;
   width: 150px;
   height: 150px;
   background: lightgreen;
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/anchor-links-ancestor.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/anchor-links-ancestor.html
index e3a5009..f728786 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/anchor-links-ancestor.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/anchor-links-ancestor.html
@@ -8,11 +8,6 @@
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="../resources/utils.js"></script>
-<style>
-  div {
-    contain: style layout;
-  }
-</style>
 <div id="outermost">
   Outermost
   <div id="outer">
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/anchor-links.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/anchor-links.html
index 6b250eb..5e51e40d 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/anchor-links.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/anchor-links.html
@@ -8,11 +8,6 @@
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="../resources/utils.js"></script>
-<style>
-  div {
-    contain: style layout;
-  }
-</style>
 <div id="outer">
   Outer
   <div id="inner">
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/commit-in-beforeactivate.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/commit-in-beforeactivate.html
index 5f17252d..c24b72a 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/commit-in-beforeactivate.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/commit-in-beforeactivate.html
@@ -9,11 +9,6 @@
 <script src="/resources/testharnessreport.js"></script>
 <script src="../resources/utils.js"></script>
 
-<style>
-div {
-  contain: style layout;
-}
-</style>
 <div id="target"></div>
 
 <script>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/focus-empty-layout.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/focus-empty-layout.html
index 76aa47e..961df3b 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/focus-empty-layout.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/focus-empty-layout.html
@@ -10,8 +10,7 @@
 Focus on a div that doesn't have style/layout value yet.
 -->
 
-<div id="container" style ="contain:style layout">
-</div>
+<div id="container"></div>
 
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/focus-next-updated-style.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/focus-next-updated-style.html
index 3838981..ba3cfad9 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/focus-next-updated-style.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/focus-next-updated-style.html
@@ -10,7 +10,7 @@
 Focus on a div that has updated style/layout.
 -->
 
-<div id="container" style ="contain:style layout;">
+<div id="container">
   <div id="focusableA" tabindex="0">a</div>
   <div id="focusableB" tabindex="0">b</div>
 </div>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/focus-shadow.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/focus-shadow.html
index 0a3ff4c3a..ed7b81a 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/focus-shadow.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/focus-shadow.html
@@ -16,7 +16,6 @@
 <script>
 promise_test((t) => {
   const container = document.createElement("div");
-  container.style = "contain: style layout;";
   container.innerHTML = "<slot></slot>";
 
   const shadowRoot = host.attachShadow({ mode: "open" });
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/focus-updated-style.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/focus-updated-style.html
index 6964e7bb..b640776 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/focus-updated-style.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/focus-updated-style.html
@@ -9,7 +9,7 @@
 Focus on a div that has updated style/layout.
 -->
 
-<div id="container" style ="contain:style layout">
+<div id="container">
   <div id="focusable" tabIndex="0">
     focusable thing
   </div>
@@ -17,10 +17,11 @@
 
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src="../resources/utils.js"></script>
 
 <script>
 promise_test((t) => {
-  const acquirePromise = container.displayLock.acquire({ timeout: Infinity, activatable: true });
+  const acquirePromise = setInvisibleActivatable(container);
   return new Promise((resolve, reject) => {
     acquirePromise.then(() => {
       container.onbeforeactivate = reject;
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/locked-element-focus.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/locked-element-focus.html
index cac92fdc..96a83ec 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/locked-element-focus.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/locked-element-focus.html
@@ -5,7 +5,7 @@
 <link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
 <link rel="help" href="https://github.com/WICG/display-locking">
 
-<div id="container" style ="contain:style layout">
+<div id="container">
   <div id="focusable" tabIndex="0">
     Focusable div
   </div>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/locked-element-prevents-anchor-links.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/locked-element-prevents-anchor-links.html
index b15bb308..92a459a8 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/locked-element-prevents-anchor-links.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/locked-element-prevents-anchor-links.html
@@ -15,7 +15,6 @@
   background: lightblue;
 }
 #container {
-  contain: style layout;
   width: 150px;
   height: 150px;
   background: lightgreen;
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/locked-element-prevents-scroll-into-view.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/locked-element-prevents-scroll-into-view.html
index 7553cca..0467c3c 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/locked-element-prevents-scroll-into-view.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/locked-element-prevents-scroll-into-view.html
@@ -15,7 +15,6 @@
   background: lightblue;
 }
 #container {
-  contain: style layout;
   width: 150px;
   height: 150px;
   background: lightgreen;
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/scroll-into-view-beforeactivate.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/scroll-into-view-beforeactivate.html
index 04c9617..a672504 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/scroll-into-view-beforeactivate.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/scroll-into-view-beforeactivate.html
@@ -8,11 +8,6 @@
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="../resources/utils.js"></script>
-<style>
-  div {
-    contain: style layout;
-  }
-</style>
 <div id="outermost">
   Outermost
   <div id="outer">
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/scroll-into-view.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/scroll-into-view.html
index 837c3890..4442db5 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/scroll-into-view.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/scroll-into-view.html
@@ -15,7 +15,6 @@
   background: lightblue;
 }
 #container {
-  contain: style layout;
   width: 150px;
   height: 150px;
   background: lightgreen;
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/commit-immediate-acquire.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/commit-immediate-acquire.html
index eb4aa24..b6e0646c 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/commit-immediate-acquire.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/commit-immediate-acquire.html
@@ -10,7 +10,6 @@
 
 <style>
 #container {
-  contain: style layout;
   width: 150px;
   height: 150px;
   background: lightblue;
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-changed-containment.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-changed-containment.html
index c1ef658f..13bec941 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-changed-containment.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-changed-containment.html
@@ -4,8 +4,9 @@
 <title>Display Locking: acquire, containment changes</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-no-containment-with-child-ref.html">
+<link rel="match" href="pass-containment-added-ref.html">
 <script src="/common/reftest-wait.js"></script>
+<script src="../resources/utils.js"></script>
 
 <style>
 #container {
@@ -35,9 +36,8 @@
   // Recalc child and container when acquiring.
   container.style = "";
   child.style = "";
-  container.displayLock.acquire({ timeout: Infinity }).then(
-    () => { finishTest("FAIL"); },
-    (e) => { finishTest("PASS " + e.message); });
+  setInvisible(container).then(
+    () => { finishTest("PASS, contain: " + getComputedStyle(container).contain ); });
 }
 
 window.onload = runTest;
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-on-added-containment-after-acquire.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-on-added-containment-after-acquire.html
deleted file mode 100644
index b2cae3a..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-on-added-containment-after-acquire.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: acquire, then add containment</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="acquire-on-added-containment-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-#container {
-  width: 150px;
-  height: 150px;
-}
-.contained {
-  contain: style layout;
-}
-</style>
-
-<div id="log"></div>
-<div id="container">foo</div>
-
-<script>
-function finishTest(status_string) {
-  if (document.getElementById("log").innerHTML === "")
-    document.getElementById("log").innerHTML = status_string;
-  takeScreenshot();
-}
-
-function runTest() {
-  const container = document.getElementById("container");
-  container.displayLock.acquire({ timeout: Infinity }).then(
-    () => { finishTest("PASS"); },
-    (e) => { finishTest("FAIL " + e.message); });
-  container.classList = "contained";
-}
-
-window.onload = runTest;
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-on-added-containment-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-on-added-containment-ref.html
deleted file mode 100644
index 1802299..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-on-added-containment-ref.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: acquire on added containment (reference)</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<style>
-#container {
-  width: 150px;
-  height: 150px;
-}
-</style>
-
-<div id="log">PASS</div>
-<div id="container"></div>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-on-no-containment.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-on-no-containment.html
index 52711d3..90b9cd4 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-on-no-containment.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-on-no-containment.html
@@ -4,8 +4,9 @@
 <title>Display Locking: acquire, no containment</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-no-containment-ref.html">
+<link rel="match" href="pass-containment-added-ref.html">
 <script src="/common/reftest-wait.js"></script>
+<script src="../resources/utils.js"></script>
 
 <style>
 #container {
@@ -27,9 +28,9 @@
 
 function runTest() {
   const container = document.getElementById("container");
-  container.displayLock.acquire({ timeout: Infinity }).then(
-    () => { finishTest("FAIL"); },
-    (e) => { finishTest("PASS " + e.message); });
+  setInvisible(container).then(() => {
+    finishTest("PASS, contain: " + getComputedStyle(container).contain);
+  });
 }
 
 window.onload = runTest;
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-on-added-containment.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-only-style-containment.html
similarity index 63%
rename from third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-on-added-containment.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-only-style-containment.html
index f875978..f5b53606 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-on-added-containment.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-only-style-containment.html
@@ -1,19 +1,19 @@
-<!doctype HTML>
+<!doctype html>
 <html class="reftest-wait">
 <meta charset="utf8">
-<title>Display Locking: acquire after added containment</title>
+<title>Display Locking: acquire, containment got overridden</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="acquire-on-added-containment-ref.html">
+<link rel="match" href="pass-contain-style-only-with-child-ref.html">
 <script src="/common/reftest-wait.js"></script>
+<script src="../resources/utils.js"></script>
 
 <style>
 #container {
   width: 150px;
   height: 150px;
-}
-.contained {
-  contain: style layout;
+  background: lightblue;
+  contain: style;
 }
 #child {
   width: 50px;
@@ -23,7 +23,7 @@
 </style>
 
 <div id="log"></div>
-<div id="container">Lorem</div>
+<div id="container"><div id="child"></div></div>
 
 <script>
 function finishTest(status_string) {
@@ -34,10 +34,9 @@
 
 function runTest() {
   const container = document.getElementById("container");
-  container.classList = "contained";
-  container.displayLock.acquire({ timeout: Infinity }).then(
-    () => { finishTest("PASS"); },
-    (e) => { finishTest("FAIL " + e.message); });
+  setInvisible(container).then(() => {
+    finishTest("PASS, contain: " + getComputedStyle(container).contain );
+  });
 }
 
 window.onload = runTest;
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-on-added-containment.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-overridden-containment.html
similarity index 62%
copy from third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-on-added-containment.html
copy to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-overridden-containment.html
index f875978..3b7463e 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-on-added-containment.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-overridden-containment.html
@@ -1,19 +1,18 @@
-<!doctype HTML>
+<!doctype html>
 <html class="reftest-wait">
 <meta charset="utf8">
-<title>Display Locking: acquire after added containment</title>
+<title>Display Locking: acquire, containment got overridden</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="acquire-on-added-containment-ref.html">
+<link rel="match" href="pass-containment-style-layout-ref.html">
 <script src="/common/reftest-wait.js"></script>
+<script src="../resources/utils.js"></script>
 
 <style>
 #container {
   width: 150px;
   height: 150px;
-}
-.contained {
-  contain: style layout;
+  background: lightblue;
 }
 #child {
   width: 50px;
@@ -23,7 +22,7 @@
 </style>
 
 <div id="log"></div>
-<div id="container">Lorem</div>
+<div id="container" style="contain: style layout;"><div id="child"></div></div>
 
 <script>
 function finishTest(status_string) {
@@ -34,10 +33,8 @@
 
 function runTest() {
   const container = document.getElementById("container");
-  container.classList = "contained";
-  container.displayLock.acquire({ timeout: Infinity }).then(
-    () => { finishTest("PASS"); },
-    (e) => { finishTest("FAIL " + e.message); });
+  setInvisible(container).then(
+    () => { finishTest("PASS, contain: " + getComputedStyle(container).contain ); });
 }
 
 window.onload = runTest;
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/nested-containment.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/nested-containment.html
deleted file mode 100644
index d64beb1..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/nested-containment.html
+++ /dev/null
@@ -1,86 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: containment checks with nested locks</title>
-<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<body>
-<style>
-.lockable, .parentOfLockable > div {
-  contain: style layout;
-}
-.randomClass > div {
-  color: red;
-}
-</style>
-<script>
-function forceLayout(el) {
-  el.offsetTop;
-}
-
-function createParentAndChild() {
-  let parent = document.createElement("div");
-  let child = document.createElement("div");
-  parent.appendChild(child);
-  document.body.appendChild(parent);
-  parent.classList.add("lockable");
-  forceLayout(child);
-  return parent;
-}
-
-async_test(async(t) => {
-  let parent = createParentAndChild();
-  let child = parent.firstChild;
-  await parent.displayLock.acquire({timeout: Infinity});
-  t.step(() => assert_equals(parent.displayLock.locked, true));
-
-  let childPromise = child.displayLock.acquire({timeout: Infinity});
-  childPromise.then(() => {
-    t.step(() => assert_equals(child.displayLock.locked, true));
-    t.done();
-  });
-}, "Nested locked element with clean style should not enforce containment requirement");
-
-async_test(async(t) => {
-  let parent = createParentAndChild();
-  let child = parent.firstChild;
-  await parent.displayLock.acquire({timeout: Infinity});
-  t.step(() => assert_equals(parent.displayLock.locked, true));
-
-  // Will mark #child for style recalc.
-  parent.classList.add("randomClass");
-  let childPromise = child.displayLock.acquire({timeout: Infinity});
-  childPromise.then(() => {
-    // Lifecycle update has finished but since #child is within a locked subtree,
-    // its style is still dirty and we keep it locked.
-    t.step(() => assert_equals(child.displayLock.locked, true));
-    forceLayout(child);
-    // Gets unlocked after forced recalc on #child.
-    t.step(() => assert_equals(child.displayLock.locked, false));
-    t.done();
-  });
-}, "Nested locked element that needs recalc should not enforce containment requirement");
-
-async_test(async(t) => {
-  let parent = createParentAndChild();
-  let child = parent.firstChild;
-  await parent.displayLock.acquire({timeout: Infinity});
-  t.step(() => assert_equals(parent.displayLock.locked, true));
-
-  // Will mark #child for style recalc.
-  parent.classList.add("parentOfLockable");
-  let childPromise = child.displayLock.acquire({timeout: Infinity});
-  childPromise.then(() => {
-    t.step(() => assert_equals(child.displayLock.locked, true));
-    forceLayout(child);
-    // Is still locked after forced recalc on #child because of added containment.
-    t.step(() => assert_equals(child.displayLock.locked, true));
-    t.done();
-  });
-}, "Nested locked element recalcs correctly when forced");
-</script>
-</body>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/pass-no-containment-with-child-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/pass-contain-style-only-with-child-ref.html
similarity index 74%
rename from third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/pass-no-containment-with-child-ref.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/pass-contain-style-only-with-child-ref.html
index 00127f4..3b74a582 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/pass-no-containment-with-child-ref.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/pass-contain-style-only-with-child-ref.html
@@ -7,7 +7,7 @@
 
 <style>
 #container {
-  contain: style layout;
+  contain: style;
   width: 150px;
   height: 150px;
   background: lightblue;
@@ -18,7 +18,7 @@
   background: lightgreen;
 }
 </style>
-
-<div id="log">PASS Containment requirement is not satisfied.</div>
+<!-- TODO(rakina): Make this actually lock/not render the subtree even without layout containment -->
+<div id="log">PASS, contain: style</div>
 <div id="container"><div id="child"></div></div>
 </html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/pass-no-containment-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/pass-containment-added-ref.html
similarity index 84%
rename from third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/pass-no-containment-ref.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/pass-containment-added-ref.html
index 9cce14b2..7cb48fd 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/pass-no-containment-ref.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/pass-containment-added-ref.html
@@ -13,6 +13,6 @@
 }
 </style>
 
-<div id="log">PASS Containment requirement is not satisfied.</div>
+<div id="log">PASS, contain: size layout style</div>
 <div id="container"></div>
 </html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/pass-no-containment-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/pass-containment-style-layout-ref.html
similarity index 84%
copy from third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/pass-no-containment-ref.html
copy to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/pass-containment-style-layout-ref.html
index 9cce14b2..21f6e605 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/pass-no-containment-ref.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/pass-containment-style-layout-ref.html
@@ -13,6 +13,6 @@
 }
 </style>
 
-<div id="log">PASS Containment requirement is not satisfied.</div>
+<div id="log">PASS, contain: layout style</div>
 <div id="container"></div>
 </html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/rendersubtree-adds-containment.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/rendersubtree-adds-containment.html
new file mode 100644
index 0000000..36a13da1
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/rendersubtree-adds-containment.html
@@ -0,0 +1,53 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Display Locking: rendersubtree adds containment</title>
+<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
+<link rel="help" href="https://github.com/WICG/display-locking">
+
+<div id="container"></div>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/utils.js"></script>
+
+<script>
+function setUp() {
+  container.removeAttribute("rendersubtree");
+  assert_equals(getComputedStyle(container).contain, "none");
+}
+
+test(() => {
+  setUp();
+  container.setAttribute("rendersubtree", "invisible");
+  assert_equals(getComputedStyle(container).contain, "size layout style");
+}, "rendersubtree=invisible adds contain: size layout style;");
+
+test(() => {
+  setUp();
+  container.setAttribute("rendersubtree", "invisible-activatable");
+  assert_equals(getComputedStyle(container).contain, "size layout style");
+}, "rendersubtree=invisible-activatable adds contain: size layout style;");
+
+test(() => {
+  setUp();
+  container.setAttribute("rendersubtree", "visible");
+  assert_equals(getComputedStyle(container).contain, "layout style");
+}, "rendersubtree=visible adds contain: layout style;");
+
+test(() => {
+  setUp();
+  container.setAttribute("rendersubtree", "invalid");
+  assert_equals(getComputedStyle(container).contain, "layout style");
+}, "rendersubtree=invalid adds contain: layout style;");
+
+
+test(() => {
+  setUp();
+  container.setAttribute("rendersubtree", "invisible");
+  container.style = "contain: style;";
+  assert_equals(getComputedStyle(container).contain, "style");
+  container.style = "";
+  assert_equals(getComputedStyle(container).contain, "size layout style");
+}, "rendersubtree=invisible adds contain: size layout style, but can be overridden");
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/delayed-acquire-removes-painted-output.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/delayed-acquire-removes-painted-output.html
index e63bf1a..0a89b9a 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/delayed-acquire-removes-painted-output.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/delayed-acquire-removes-painted-output.html
@@ -10,7 +10,6 @@
 
 <style>
 #container {
-  contain: style layout;
   width: 150px;
   height: 150px;
 }
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/inner-text.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/inner-text.html
index e253d193..5b97b35 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/inner-text.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/inner-text.html
@@ -9,12 +9,6 @@
 <script src="/resources/testharnessreport.js"></script>
 <script src="resources/utils.js"></script>
 
-<style>
-#container {
-  contain: style layout;
-}
-</style>
-
 This text should be visible.
 <div id="container">
   This text should not be visible.
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/intersection-observer.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/intersection-observer.html
index 206d117..8eae086 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/intersection-observer.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/intersection-observer.html
@@ -11,7 +11,6 @@
 
 <style>
 div {
-  contain: style layout;
   width: 100px;
   height: 100px;
 }
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/lock-crossorigin-iframe-and-change-size.sub.https.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/lock-crossorigin-iframe-and-change-size.sub.https.html
index 1fc8487..3903e8c 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/lock-crossorigin-iframe-and-change-size.sub.https.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/lock-crossorigin-iframe-and-change-size.sub.https.html
@@ -8,11 +8,6 @@
 <script src="/common/reftest-wait.js"></script>
 <script src="resources/utils.js"></script>
 
-<style>
-iframe {
-  contain: style layout;
-}
-</style>
 <iframe id="frame" width=200 height=200 src='https://{{domains[www]}}:{{ports[https][0]}}/wpt_internal/display-lock/paint/resources/frame.html'></iframe>
 
 <script>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/lock-iframe-and-change-size.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/lock-iframe-and-change-size.html
index 187ea1db..c0541484 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/lock-iframe-and-change-size.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/lock-iframe-and-change-size.html
@@ -8,11 +8,6 @@
 <script src="/common/reftest-wait.js"></script>
 <script src="resources/utils.js"></script>
 
-<style>
-iframe {
-  contain: style layout;
-}
-</style>
 <iframe id=frame width=200 height=200 srcdoc='Lorem ipsum'></iframe>
 
 <script>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/locked-attribute.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/locked-attribute.html
index 906047b..451a491 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/locked-attribute.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/locked-attribute.html
@@ -5,12 +5,6 @@
 <link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
 <link rel="help" href="https://github.com/WICG/display-locking">
 
-<style>
-#container {
-  contain: style layout;
-}
-</style>
-
 <div id="container"></div>
 
 <script src="/resources/testharness.js"></script>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/locked-element-shifted-down.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/locked-element-shifted-down.html
index 8b7aea9..98c717a6 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/locked-element-shifted-down.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/locked-element-shifted-down.html
@@ -10,7 +10,6 @@
 
 <style>
 #container {
-  contain: style layout;
   width: 150px;
   height: 150px;
 }
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/locked-shadow-descendant.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/locked-shadow-descendant.html
index 8923a71..8ac91c1 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/locked-shadow-descendant.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/locked-shadow-descendant.html
@@ -15,7 +15,6 @@
 
 <script>
 let container = document.createElement("div");
-container.style = "contain: style layout;";
 container.innerHTML = "<slot></slot>";
 
 let shadowRoot = host.attachShadow({ mode: "open" });
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/locked-style.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/locked-style.html
index 45758ea..6636e03a 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/locked-style.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/locked-style.html
@@ -5,11 +5,6 @@
 <link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
 <link rel="help" href="https://github.com/WICG/display-locking">
 <script src="resources/utils.js"></script>
-<style>
-#container {
-  contain: style layout;
-}
-</style>
 
 <div id="container">
   <div id="child">
@@ -36,9 +31,10 @@
     t.step(() => assert_equals(getComputedStyle(child).color, "rgb(0, 128, 0)", "child color changed to green"));
     t.step(() => assert_equals(getComputedStyle(grandchild).color, "rgb(0, 128, 0)", "grandchild inherits green color"));
 
+    child.style = "";
+
     // Commit container, lock child.
     await setVisible(container);
-    child.style = "contain: style layout";
     await setInvisible(child);
 
     // Update style outside of the locked subtree.
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/nested-acquire.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/nested-acquire.html
index 7e2b0758..bafe07a 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/nested-acquire.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/nested-acquire.html
@@ -9,9 +9,6 @@
 <script src="resources/utils.js"></script>
 
 <style>
-.container {
-  contain: style layout;
-}
 #outer {
   width: 100px;
   height: 100px;
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/nested-commit.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/nested-commit.html
index 37890231..9f5ad38 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/nested-commit.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/nested-commit.html
@@ -9,9 +9,6 @@
 <script src="resources/utils.js"></script>
 
 <style>
-.container {
-  contain: style layout;
-}
 #outer {
   width: 100px;
   height: 100px;
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/nested-update-and-commit.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/nested-update-and-commit.html
index 1a95dd8..fcc233f 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/nested-update-and-commit.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/nested-update-and-commit.html
@@ -9,9 +9,6 @@
 <script src="resources/utils.js"></script>
 
 <style>
-.container {
-  contain: style layout;
-}
 #outer {
   width: 100px;
   height: 100px;
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/nested-update.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/nested-update.html
index f3a7584..e6488547 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/nested-update.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/nested-update.html
@@ -9,9 +9,6 @@
 <script src="resources/utils.js"></script>
 
 <style>
-.container {
-  contain: style layout;
-}
 #outer {
   width: 100px;
   height: 100px;
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index c9460b9..6dd7379 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -367,6 +367,8 @@
       'GPU Linux Builder (dbg)': 'gpu_tests_debug_trybot',
       'GPU Win Builder': 'gpu_tests_release_trybot_x86_resource_whitelisting',
       'GPU Win Builder (dbg)': 'gpu_tests_debug_trybot_x86',
+      'GPU Win x64 Builder': 'gpu_tests_release_trybot_resource_whitelisting',
+      'GPU Win x64 Builder (dbg)': 'gpu_tests_debug_trybot',
       'Android Release (Nexus 5X)': 'gpu_tests_android_release_trybot_arm64',
     },
 
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index e86cc49..af303f4 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -4082,6 +4082,7 @@
   <int value="5" label="Get upload details RPC failed"/>
   <int value="6" label="All cards are unsupported"/>
   <int value="7" label="Single local card"/>
+  <int value="8" label="User used unsupported local card"/>
 </enum>
 
 <enum name="AutofillLocalCardMigrationDialogOffer">
@@ -20285,6 +20286,7 @@
   <int value="1372" label="LOGINSCREENSTORAGE_STORECREDENTIALS"/>
   <int value="1373" label="LOGINSCREENSTORAGE_RETRIEVECREDENTIALS"/>
   <int value="1374" label="AUTOTESTPRIVATE_GETARCAPPWINDOWSTATE"/>
+  <int value="1375" label="AUTOTESTPRIVATE_GETARCAPPWINDOWINFO"/>
 </enum>
 
 <enum name="ExtensionIconState">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 862e8ce0..05a38d21 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -77981,6 +77981,13 @@
   </summary>
 </histogram>
 
+<histogram name="Net.SpdyHighestQueuedCappedFramesCount" expires_after="M82">
+  <owner>dschinazi@chromium.org</owner>
+  <summary>
+    The highest number of capped frames queued in the SPDY write queue.
+  </summary>
+</histogram>
+
 <histogram name="Net.SpdyHpackDecompressionPercentage" units="%">
   <owner>ckrasic@chromium.org</owner>
   <summary>
diff --git a/ui/accessibility/ax_assistant_structure.cc b/ui/accessibility/ax_assistant_structure.cc
index 82a302c..36f1a84 100644
--- a/ui/accessibility/ax_assistant_structure.cc
+++ b/ui/accessibility/ax_assistant_structure.cc
@@ -336,8 +336,9 @@
   if (IsLeaf(node) && update.has_tree_data) {
     int start_selection = 0;
     int end_selection = 0;
-    if (update.tree_data.sel_anchor_object_id == node->id()) {
-      start_selection = update.tree_data.sel_anchor_offset;
+    AXTree::Selection unignored_selection = tree->GetUnignoredSelection();
+    if (unignored_selection.anchor_object_id == node->id()) {
+      start_selection = unignored_selection.anchor_offset;
       config->should_select_leaf = true;
     }
 
@@ -346,8 +347,8 @@
           static_cast<int32_t>(GetText(node, config->show_password).length());
     }
 
-    if (update.tree_data.sel_focus_object_id == node->id()) {
-      end_selection = update.tree_data.sel_focus_offset;
+    if (unignored_selection.focus_object_id == node->id()) {
+      end_selection = unignored_selection.focus_offset;
       config->should_select_leaf = false;
     }
     if (end_selection > 0)
diff --git a/ui/accessibility/ax_node.cc b/ui/accessibility/ax_node.cc
index 05cb96d..3eef272 100644
--- a/ui/accessibility/ax_node.cc
+++ b/ui/accessibility/ax_node.cc
@@ -76,6 +76,30 @@
   return ComputeLastUnignoredChildRecursive();
 }
 
+AXNode* AXNode::GetDeepestFirstUnignoredChild() const {
+  if (!GetUnignoredChildCount())
+    return nullptr;
+
+  AXNode* deepest_child = GetFirstUnignoredChild();
+  while (deepest_child->GetUnignoredChildCount()) {
+    deepest_child = deepest_child->GetFirstUnignoredChild();
+  }
+
+  return deepest_child;
+}
+
+AXNode* AXNode::GetDeepestLastUnignoredChild() const {
+  if (!GetUnignoredChildCount())
+    return nullptr;
+
+  AXNode* deepest_child = GetLastUnignoredChild();
+  while (deepest_child->GetUnignoredChildCount()) {
+    deepest_child = deepest_child->GetLastUnignoredChild();
+  }
+
+  return deepest_child;
+}
+
 AXNode* AXNode::GetNextUnignoredSibling() const {
   DCHECK(!tree_->GetTreeUpdateInProgressState());
   AXNode* parent_node = parent();
@@ -135,6 +159,33 @@
   return nullptr;
 }
 
+AXNode* AXNode::GetNextUnignoredInTreeOrder() const {
+  if (GetUnignoredChildCount())
+    return GetFirstUnignoredChild();
+
+  const AXNode* node = this;
+  while (node) {
+    AXNode* sibling = node->GetNextUnignoredSibling();
+    if (sibling)
+      return sibling;
+
+    node = node->GetUnignoredParent();
+  }
+
+  return nullptr;
+}
+
+AXNode* AXNode::GetPreviousUnignoredInTreeOrder() const {
+  AXNode* sibling = GetPreviousUnignoredSibling();
+  if (!sibling)
+    return GetUnignoredParent();
+
+  if (sibling->GetUnignoredChildCount())
+    return sibling->GetDeepestLastUnignoredChild();
+
+  return sibling;
+}
+
 AXNode::UnignoredChildIterator AXNode::UnignoredChildrenBegin() const {
   DCHECK(!tree_->GetTreeUpdateInProgressState());
   return UnignoredChildIterator(this, GetFirstUnignoredChild());
diff --git a/ui/accessibility/ax_node.h b/ui/accessibility/ax_node.h
index 40814d27..25ec866 100644
--- a/ui/accessibility/ax_node.h
+++ b/ui/accessibility/ax_node.h
@@ -25,12 +25,29 @@
 // One node in an AXTree.
 class AX_EXPORT AXNode final {
  public:
+  // Defines the type used for AXNode IDs.
+  using AXID = int32_t;
+
+  // If a node is not yet or no longer valid, its ID should have a value of
+  // kInvalidAXID.
+  static constexpr AXID kInvalidAXID = 0;
+
   // Interface to the tree class that owns an AXNode. We use this instead
   // of letting AXNode have a pointer to its AXTree directly so that we're
   // forced to think twice before calling an AXTree interface that might not
   // be necessary.
   class OwnerTree {
    public:
+    struct Selection {
+      bool is_backward;
+      AXID anchor_object_id;
+      int anchor_offset;
+      ax::mojom::TextAffinity anchor_affinity;
+      AXID focus_object_id;
+      int focus_offset;
+      ax::mojom::TextAffinity focus_affinity;
+    };
+
     // See AXTree.
     virtual AXTableInfo* GetTableInfo(const AXNode* table_node) const = 0;
     // See AXTree.
@@ -40,6 +57,7 @@
                                 const AXNode* ordered_set) = 0;
     virtual int32_t GetSetSize(const AXNode& node,
                                const AXNode* ordered_set) = 0;
+    virtual Selection GetUnignoredSelection() const = 0;
     virtual bool GetTreeUpdateInProgressState() const = 0;
     virtual bool HasPaginationSupport() const = 0;
   };
@@ -66,13 +84,6 @@
     NodeType* child_;
   };
 
-  // Defines the type used for AXNode IDs.
-  using AXID = int32_t;
-
-  // If a node is not yet or no longer valid, its ID should have a value of
-  // kInvalidAXID.
-  static constexpr AXID kInvalidAXID = 0;
-
   // The constructor requires a parent, id, and index in parent, but
   // the data is not required. After initialization, only index_in_parent
   // and unignored_index_in_parent is allowed to change, the others are
@@ -102,8 +113,12 @@
   size_t GetUnignoredIndexInParent() const;
   AXNode* GetFirstUnignoredChild() const;
   AXNode* GetLastUnignoredChild() const;
+  AXNode* GetDeepestFirstUnignoredChild() const;
+  AXNode* GetDeepestLastUnignoredChild() const;
   AXNode* GetNextUnignoredSibling() const;
   AXNode* GetPreviousUnignoredSibling() const;
+  AXNode* GetNextUnignoredInTreeOrder() const;
+  AXNode* GetPreviousUnignoredInTreeOrder() const;
 
   using UnignoredChildIterator =
       ChildIteratorBase<AXNode,
diff --git a/ui/accessibility/ax_node_position.cc b/ui/accessibility/ax_node_position.cc
index 3bb7eb1c..f448bf46 100644
--- a/ui/accessibility/ax_node_position.cc
+++ b/ui/accessibility/ax_node_position.cc
@@ -43,6 +43,83 @@
   return text;
 }
 
+// static
+AXNodePosition::AXPositionInstance AXNodePosition::CreatePosition(
+    AXTreeID tree_id,
+    const AXNode& node,
+    int offset,
+    ax::mojom::TextAffinity affinity) {
+  AXPositionInstance position = CreateNullPosition();
+  // If either the current anchor, or the 'child after tree position' is
+  // ignored, we must 'fix' the position by finding the nearest unignored
+  // position. 'child after tree position' being the child at the child_offset
+  // that tree position refers to.
+  if (node.IsText()) {
+    position = CreateTextPosition(tree_id, node.id(), offset, affinity);
+  } else {
+    position = CreateTreePosition(tree_id, node.id(), offset);
+  }
+  return position;
+}
+
+bool AXNodePosition::IsIgnoredPosition() const {
+  if (IsNullPosition())
+    return false;
+
+  // If this position is pointing to an ignored node, then consider this
+  // position as ignored.
+  if (GetAnchor()->IsIgnored())
+    return true;
+
+  // If there are any ignored nodes in the parent chain from the leaf node to
+  // this node's anchor, consider the position to be ignored.
+  AXPositionInstance leaf_position = AsLeafTextPosition();
+  AXNode* descendant = leaf_position->GetAnchor();
+  while (descendant && descendant->id() != anchor_id()) {
+    if (descendant->IsIgnored())
+      return true;
+    descendant = descendant->parent();
+  }
+
+  return false;
+}
+
+AXNodePosition::AXPositionInstance AXNodePosition::AsUnignoredTextPosition(
+    AdjustmentBehavior adjustment_behavior) const {
+  if (IsNullPosition())
+    return CreateNullPosition();
+
+  if (!IsLeafTextPosition())
+    return AsLeafTextPosition()->AsUnignoredTextPosition(adjustment_behavior);
+
+  if (!GetAnchor()->IsIgnored())
+    return Clone();
+
+  // Find the next/previous node that is not ignored.
+  AXNode* unignored_node = GetAnchor();
+  while (unignored_node) {
+    switch (adjustment_behavior) {
+      case AdjustmentBehavior::kMoveRight:
+        unignored_node = unignored_node->GetNextUnignoredInTreeOrder();
+        break;
+      case AdjustmentBehavior::kMoveLeft:
+        unignored_node = unignored_node->GetPreviousUnignoredInTreeOrder();
+    }
+    if (unignored_node && unignored_node->IsText()) {
+      switch (adjustment_behavior) {
+        case AdjustmentBehavior::kMoveRight:
+          return CreateTextPosition(tree_id(), unignored_node->id(), 0,
+                                    ax::mojom::TextAffinity::kDownstream);
+        case AdjustmentBehavior::kMoveLeft:
+          return CreateTextPosition(tree_id(), unignored_node->id(), 0,
+                                    ax::mojom::TextAffinity::kDownstream)
+              ->CreatePositionAtEndOfAnchor();
+      }
+    }
+  }
+  return CreateNullPosition();
+}
+
 int AXNodePosition::MaxTextOffset() const {
   if (IsNullPosition())
     return INVALID_INDEX;
@@ -159,7 +236,7 @@
   if (node_id == INVALID_ANCHOR_ID)
     return nullptr;
 
-  // Used for testing via AXNodePosition::SetTreeForTesting
+  // Used for testing via AXNodePosition::SetTree
   if (AXNodePosition::tree_)
     return AXNodePosition::tree_->GetFromId(node_id);
 
diff --git a/ui/accessibility/ax_node_position.h b/ui/accessibility/ax_node_position.h
index dc20fc2..4da2880 100644
--- a/ui/accessibility/ax_node_position.h
+++ b/ui/accessibility/ax_node_position.h
@@ -25,6 +25,13 @@
   AXNodePosition();
   ~AXNodePosition() override;
 
+  static AXPositionInstance CreatePosition(AXTreeID tree_id,
+                                           const AXNode& node,
+                                           int32_t offset,
+                                           ax::mojom::TextAffinity affinity);
+
+  static void SetTree(AXTree* tree) { tree_ = tree; }
+
   AXPositionInstance Clone() const override;
 
   int MaxTextOffset() const override;
@@ -33,7 +40,9 @@
   bool IsInWhiteSpace() const override;
   base::string16 GetText() const override;
 
-  static void SetTreeForTesting(AXTree* tree) { tree_ = tree; }
+  bool IsIgnoredPosition() const override;
+  AXPositionInstance AsUnignoredTextPosition(
+      AdjustmentBehavior adjustment_behavior) const override;
 
  protected:
   AXNodePosition(const AXNodePosition& other) = default;
diff --git a/ui/accessibility/ax_node_position_unittest.cc b/ui/accessibility/ax_node_position_unittest.cc
index f92f31d..8f00c18 100644
--- a/ui/accessibility/ax_node_position_unittest.cc
+++ b/ui/accessibility/ax_node_position_unittest.cc
@@ -56,7 +56,7 @@
                                   AXNodeData& page_2_text_data,
                                   AXNodeData& page_3_data,
                                   AXNodeData& page_3_text_data) {
-    AXNodePosition::SetTreeForTesting(nullptr);
+    AXNodePosition::SetTree(nullptr);
 
     root_data.id = 1;
     root_data.role = ax::mojom::Role::kDocument;
@@ -139,7 +139,7 @@
     tree_data.tree_id = AXTreeID::CreateNewAXTreeID();
     update.tree_data = tree_data;
     std::unique_ptr<AXTree> tree = std::make_unique<AXTree>(update);
-    AXNodePosition::SetTreeForTesting(tree.get());
+    AXNodePosition::SetTree(tree.get());
     return tree;
   }
 
@@ -315,11 +315,11 @@
   AXTreeUpdate update;
   serializer.SerializeChanges(src_tree.root(), &update);
   ASSERT_TRUE(tree_.Unserialize(update));
-  AXNodePosition::SetTreeForTesting(&tree_);
+  AXNodePosition::SetTree(&tree_);
 }
 
 void AXPositionTest::TearDown() {
-  AXNodePosition::SetTreeForTesting(nullptr);
+  AXNodePosition::SetTree(nullptr);
 }
 
 }  // namespace
@@ -518,7 +518,7 @@
 }
 
 TEST_F(AXPositionTest, GetMaxTextOffsetUpdate) {
-  AXNodePosition::SetTreeForTesting(nullptr);
+  AXNodePosition::SetTree(nullptr);
 
   AXNodeData root_data;
   root_data.id = 1;
@@ -930,7 +930,7 @@
   // ++++++5 kStaticText
   // ++++++++6 kInlineTextBox "\n" isLineBreakingObject
   // ++++++++7 kInlineTextBox "more text"
-  AXNodePosition::SetTreeForTesting(nullptr);
+  AXNodePosition::SetTree(nullptr);
 
   AXNodeData root_data;
   root_data.id = 1;
@@ -1082,7 +1082,7 @@
   // ++++10 kGenericContainer isLineBreakingObject
   // ++++++11 kStaticText
   // ++++++++12 kInlineTextBox "\n" isLineBreakingObject
-  AXNodePosition::SetTreeForTesting(nullptr);
+  AXNodePosition::SetTree(nullptr);
 
   AXNodeData root_data;
   root_data.id = 1;
@@ -1939,7 +1939,7 @@
   // This test updates the tree structure to test a specific edge case -
   // CreatePositionAtFormatBoundary when text lies at the beginning and end
   // of the AX tree.
-  AXNodePosition::SetTreeForTesting(nullptr);
+  AXNodePosition::SetTree(nullptr);
 
   AXNodeData root_data;
   root_data.id = 1;
@@ -1959,6 +1959,7 @@
 
   std::unique_ptr<AXTree> new_tree =
       CreateAXTree({root_data, text_data, more_text_data});
+  AXNodePosition::SetTree(new_tree.get());
 
   // Test CreatePreviousFormatStartPosition at the start of the document.
   TestPositionType text_position = AXNodePosition::CreateTextPosition(
@@ -1984,17 +1985,18 @@
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(more_text_data.id, test_position->anchor_id());
   EXPECT_EQ(9, test_position->text_offset());
+  AXNodePosition::SetTree(&tree_);
 }
 
 TEST_F(AXPositionTest, CreatePositionAtPageBoundaryWithTextPosition) {
-  AXNodePosition::SetTreeForTesting(nullptr);
+  AXNodePosition::SetTree(nullptr);
 
   AXNodeData root_data, page_1_data, page_1_text_data, page_2_data,
       page_2_text_data, page_3_data, page_3_text_data;
   std::unique_ptr<AXTree> new_tree(CreateMultipageDocument(
       root_data, page_1_data, page_1_text_data, page_2_data, page_2_text_data,
       page_3_data, page_3_text_data));
-  AXNodePosition::SetTreeForTesting(new_tree.get());
+  AXNodePosition::SetTree(new_tree.get());
 
   // Test CreateNextPageStartPosition at the start of the document.
   TestPositionType text_position = AXNodePosition::CreateTextPosition(
@@ -2107,17 +2109,18 @@
       AXBoundaryBehavior::CrossBoundary);
   EXPECT_NE(nullptr, null_position);
   EXPECT_TRUE(null_position->IsNullPosition());
+  AXNodePosition::SetTree(&tree_);
 }
 
 TEST_F(AXPositionTest, CreatePositionAtPageBoundaryWithTreePosition) {
-  AXNodePosition::SetTreeForTesting(nullptr);
+  AXNodePosition::SetTree(nullptr);
 
   AXNodeData root_data, page_1_data, page_1_text_data, page_2_data,
       page_2_text_data, page_3_data, page_3_text_data;
   std::unique_ptr<AXTree> new_tree(CreateMultipageDocument(
       root_data, page_1_data, page_1_text_data, page_2_data, page_2_text_data,
       page_3_data, page_3_text_data));
-  AXNodePosition::SetTreeForTesting(new_tree.get());
+  AXNodePosition::SetTree(new_tree.get());
 
   // Test CreateNextPageStartPosition at the start of the document.
   TestPositionType tree_position = AXNodePosition::CreateTreePosition(
@@ -2229,6 +2232,7 @@
       AXBoundaryBehavior::CrossBoundary);
   EXPECT_NE(nullptr, null_position);
   EXPECT_TRUE(null_position->IsNullPosition());
+  AXNodePosition::SetTree(&tree_);
 }
 
 TEST_F(AXPositionTest, CreatePagePositionWithNullPosition) {
@@ -3665,7 +3669,7 @@
 TEST_F(AXPositionTest, CreateNextAnchorPosition) {
   // This test updates the tree structure to test a specific edge case -
   // CreateNextAnchorPosition on an empty text field.
-  AXNodePosition::SetTreeForTesting(nullptr);
+  AXNodePosition::SetTree(nullptr);
 
   AXNodeData root_data;
   root_data.id = 1;
@@ -3695,6 +3699,7 @@
 
   std::unique_ptr<AXTree> new_tree = CreateAXTree(
       {root_data, text_data, text_field_data, empty_text_data, more_text_data});
+  AXNodePosition::SetTree(new_tree.get());
 
   // Test that CreateNextAnchorPosition will successfully navigate past the
   // empty text field.
@@ -3720,7 +3725,7 @@
   // ++++++++6 kInlineTextBox "inside" kPreviousOnLineId=3 kNextOnLineId=8
   // ++++7 kStaticText
   // ++++++8 kInlineTextBox "after" kPreviousOnLineId=6
-  AXNodePosition::SetTreeForTesting(nullptr);
+  AXNodePosition::SetTree(&tree_);
 
   AXNodeData root;
   AXNodeData inline_box1;
diff --git a/ui/accessibility/ax_position.h b/ui/accessibility/ax_position.h
index 5f1bd11..5e00722 100644
--- a/ui/accessibility/ax_position.h
+++ b/ui/accessibility/ax_position.h
@@ -94,6 +94,10 @@
   using BoundaryConditionPredicate =
       base::RepeatingCallback<bool(const AXPositionInstance&)>;
 
+  // When converting an unignored position, determines how to adjust the new
+  // position in order to make it valid.
+  enum class AdjustmentBehavior { kMoveLeft, kMoveRight };
+
   static const int32_t INVALID_ANCHOR_ID = -1;
   static const int BEFORE_TEXT = -1;
   static const int INVALID_INDEX = -2;
@@ -132,6 +136,13 @@
 
   virtual AXPositionInstance Clone() const = 0;
 
+  virtual bool IsIgnoredPosition() const { return false; }
+
+  virtual AXPositionInstance AsUnignoredTextPosition(
+      AdjustmentBehavior adjustment_behavior) const {
+    return Clone();
+  }
+
   std::string ToString() const {
     std::string str;
     switch (kind_) {
diff --git a/ui/accessibility/ax_range_unittest.cc b/ui/accessibility/ax_range_unittest.cc
index 2b8e1e2..af2a803 100644
--- a/ui/accessibility/ax_range_unittest.cc
+++ b/ui/accessibility/ax_range_unittest.cc
@@ -274,13 +274,13 @@
   initial_state.tree_data.title = "Dialog title";
 
   tree_.reset(new AXTree(initial_state));
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
   AXTreeManagerMap::GetInstance().AddTreeManager(
       initial_state.tree_data.tree_id, this);
 }
 
 void AXRangeTest::TearDown() {
-  AXNodePosition::SetTreeForTesting(nullptr);
+  AXNodePosition::SetTree(nullptr);
   AXTreeManagerMap::GetInstance().RemoveTreeManager(tree_->data().tree_id);
 }
 
diff --git a/ui/accessibility/ax_tree.cc b/ui/accessibility/ax_tree.cc
index ac5e3a40..f64680d 100644
--- a/ui/accessibility/ax_tree.cc
+++ b/ui/accessibility/ax_tree.cc
@@ -18,6 +18,7 @@
 #include "ui/accessibility/accessibility_switches.h"
 #include "ui/accessibility/ax_language_detection.h"
 #include "ui/accessibility/ax_node.h"
+#include "ui/accessibility/ax_node_position.h"
 #include "ui/accessibility/ax_role_properties.h"
 #include "ui/accessibility/ax_table_info.h"
 #include "ui/accessibility/ax_tree_observer.h"
@@ -1956,6 +1957,75 @@
   return ordered_set_info_map_[node.id()].set_size;
 }
 
+AXTree::Selection AXTree::GetUnignoredSelection() const {
+  Selection unignored_selection = {
+      data().sel_is_backward,     data().sel_anchor_object_id,
+      data().sel_anchor_offset,   data().sel_anchor_affinity,
+      data().sel_focus_object_id, data().sel_focus_offset,
+      data().sel_focus_affinity};
+  AXNode* anchor_node = GetFromId(data().sel_anchor_object_id);
+  AXNode* focus_node = GetFromId(data().sel_focus_object_id);
+
+  AXNodePosition::AXPositionInstance anchor_position =
+      anchor_node ? AXNodePosition::CreatePosition(data().tree_id, *anchor_node,
+                                                   data().sel_anchor_offset,
+                                                   data().sel_anchor_affinity)
+                  : AXNodePosition::CreateNullPosition();
+  if (anchor_position->IsIgnoredPosition()) {
+    anchor_position = anchor_position->AsUnignoredTextPosition(
+        data().sel_is_backward ? AXNodePosition::AdjustmentBehavior::kMoveRight
+                               : AXNodePosition::AdjustmentBehavior::kMoveLeft);
+    // We do not expect the selection to have an endpoint on an inline text
+    // box.
+    if (!anchor_position->IsNullPosition() &&
+        anchor_position->GetAnchor()->data().role ==
+            ax::mojom::Role::kInlineTextBox)
+      anchor_position = anchor_position->CreateParentPosition();
+    unignored_selection.anchor_object_id = anchor_position->anchor_id();
+    unignored_selection.anchor_offset = anchor_position->text_offset();
+    unignored_selection.anchor_affinity = anchor_position->affinity();
+  } else if (anchor_position->IsTreePosition()) {
+    // Fix offset to be in terms of the unignored index.
+    if (data().sel_anchor_offset == int32_t{anchor_node->children().size()}) {
+      unignored_selection.anchor_offset = anchor_node->GetUnignoredChildCount();
+    } else {
+      AXNode* child = anchor_node->children()[data().sel_anchor_offset];
+      unignored_selection.anchor_offset = child->GetUnignoredIndexInParent();
+    }
+  }
+
+  AXNodePosition::AXPositionInstance focus_position =
+      focus_node ? AXNodePosition::CreatePosition(data().tree_id, *focus_node,
+                                                  data().sel_focus_offset,
+                                                  data().sel_focus_affinity)
+                 : AXNodePosition::CreateNullPosition();
+  if (focus_position->IsIgnoredPosition()) {
+    focus_position = focus_position->AsUnignoredTextPosition(
+        !data().sel_is_backward
+            ? AXNodePosition::AdjustmentBehavior::kMoveRight
+            : AXNodePosition::AdjustmentBehavior::kMoveLeft);
+    // We do not expect the selection to have an endpoint on an inline text
+    // box.
+    if (!focus_position->IsNullPosition() &&
+        focus_position->GetAnchor()->data().role ==
+            ax::mojom::Role::kInlineTextBox)
+      focus_position = focus_position->CreateParentPosition();
+    unignored_selection.focus_object_id = focus_position->anchor_id();
+    unignored_selection.focus_offset = focus_position->text_offset();
+    unignored_selection.focus_affinity = focus_position->affinity();
+  } else if (focus_position->IsTreePosition()) {
+    // Fix offset to be in terms of the unignored index.
+    if (data().sel_focus_offset == int32_t{focus_node->children().size()}) {
+      unignored_selection.focus_offset = focus_node->GetUnignoredChildCount();
+    } else {
+      AXNode* child = focus_node->children()[data().sel_focus_offset];
+      unignored_selection.focus_offset = child->GetUnignoredIndexInParent();
+    }
+  }
+
+  return unignored_selection;
+}
+
 bool AXTree::GetTreeUpdateInProgressState() const {
   return tree_update_in_progress_;
 }
diff --git a/ui/accessibility/ax_tree.h b/ui/accessibility/ax_tree.h
index d20a32df..9e048cb 100644
--- a/ui/accessibility/ax_tree.h
+++ b/ui/accessibility/ax_tree.h
@@ -147,6 +147,8 @@
   // set_size values, minimizing the size of the cache.
   int32_t GetSetSize(const AXNode& node, const AXNode* ordered_set) override;
 
+  Selection GetUnignoredSelection() const override;
+
   bool GetTreeUpdateInProgressState() const override;
   void SetTreeUpdateInProgressState(bool set_tree_update_value);
 
diff --git a/ui/accessibility/ax_tree_data.h b/ui/accessibility/ax_tree_data.h
index 39e88c6..a2268da 100644
--- a/ui/accessibility/ax_tree_data.h
+++ b/ui/accessibility/ax_tree_data.h
@@ -60,6 +60,7 @@
   // (selection end). If the offset could correspond to a position on two
   // different lines, sel_upstream_affinity means the cursor is on the first
   // line, otherwise it's on the second line.
+  // Most use cases will want to use ui::OwnerTree::GetUnignoredSelection.
   bool sel_is_backward = false;
   int32_t sel_anchor_object_id = -1;
   int32_t sel_anchor_offset = -1;
diff --git a/ui/accessibility/ax_tree_unittest.cc b/ui/accessibility/ax_tree_unittest.cc
index e4a5a63a..18c3433f 100644
--- a/ui/accessibility/ax_tree_unittest.cc
+++ b/ui/accessibility/ax_tree_unittest.cc
@@ -15,11 +15,29 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/accessibility/ax_enum_util.h"
 #include "ui/accessibility/ax_node.h"
+#include "ui/accessibility/ax_node_position.h"
 #include "ui/accessibility/ax_serializable_tree.h"
 #include "ui/accessibility/ax_tree_observer.h"
 #include "ui/accessibility/ax_tree_serializer.h"
 #include "ui/gfx/transform.h"
 
+// Helper macro for testing selection values and maintain
+// correct stack tracing and failure causality.
+#define TEST_SELECTION(tree_update, tree, input, expected)         \
+  {                                                                \
+    tree_update.has_tree_data = true;                              \
+    tree_update.tree_data.sel_anchor_object_id = input.anchor_id;  \
+    tree_update.tree_data.sel_anchor_offset = input.anchor_offset; \
+    tree_update.tree_data.sel_focus_object_id = input.focus_id;    \
+    tree_update.tree_data.sel_focus_offset = input.focus_offset;   \
+    EXPECT_TRUE(tree.Unserialize(tree_update));                    \
+    ui::AXTree::Selection actual = tree.GetUnignoredSelection();   \
+    EXPECT_EQ(expected.anchor_id, actual.anchor_object_id);        \
+    EXPECT_EQ(expected.anchor_offset, actual.anchor_offset);       \
+    EXPECT_EQ(expected.focus_id, actual.focus_object_id);          \
+    EXPECT_EQ(expected.focus_offset, actual.focus_offset);         \
+  }
+
 namespace ui {
 
 namespace {
@@ -2070,6 +2088,197 @@
   EXPECT_EQ(nullptr, tree.GetFromId(16)->GetPreviousUnignoredSibling());
 }
 
+TEST(AXTreeTest, UnignoredSelection) {
+  AXTreeUpdate tree_update;
+  // (i) => node is ignored
+  // 1
+  // |__________
+  // |     |   |
+  // 2(i)  3   4
+  // |_______________________
+  // |   |      |           |
+  // 5   6      7(i)        8(i)
+  // |   |      |________
+  // |   |      |       |
+  // 9   10(i)  11(i)  12
+  //     |      |____
+  //     |      |   |
+  //     13(i)  14  15
+  //     |
+  //     16
+  // Unignored Tree (conceptual)
+  // 1
+  // |______________________
+  // |  |    |   |   |  |  |
+  // 5  6   14  15  12  3  4
+  // |  |
+  // 9  16
+  tree_update.has_tree_data = true;
+  tree_update.tree_data.tree_id = ui::AXTreeID::CreateNewAXTreeID();
+  tree_update.root_id = 1;
+  tree_update.nodes.resize(16);
+  tree_update.nodes[0].id = 1;
+  tree_update.nodes[0].role = ax::mojom::Role::kGenericContainer;
+  tree_update.nodes[0].child_ids = {2, 3, 4};
+
+  tree_update.nodes[1].id = 2;
+  tree_update.nodes[1].child_ids = {5, 6, 7, 8};
+  tree_update.nodes[1].role = ax::mojom::Role::kGenericContainer;
+  tree_update.nodes[1].AddState(ax::mojom::State::kIgnored);
+
+  tree_update.nodes[2].id = 3;
+  tree_update.nodes[2].role = ax::mojom::Role::kStaticText;
+  tree_update.nodes[2].AddStringAttribute(ax::mojom::StringAttribute::kName,
+                                          "text");
+
+  tree_update.nodes[3].id = 4;
+  tree_update.nodes[3].role = ax::mojom::Role::kStaticText;
+  tree_update.nodes[3].AddStringAttribute(ax::mojom::StringAttribute::kName,
+                                          "text");
+
+  tree_update.nodes[4].id = 5;
+  tree_update.nodes[4].role = ax::mojom::Role::kGenericContainer;
+  tree_update.nodes[4].child_ids = {9};
+
+  tree_update.nodes[5].id = 6;
+  tree_update.nodes[5].role = ax::mojom::Role::kGenericContainer;
+  tree_update.nodes[5].child_ids = {10};
+
+  tree_update.nodes[6].id = 7;
+  tree_update.nodes[6].child_ids = {11, 12};
+  tree_update.nodes[6].role = ax::mojom::Role::kGenericContainer;
+  tree_update.nodes[6].AddState(ax::mojom::State::kIgnored);
+
+  tree_update.nodes[7].id = 8;
+  tree_update.nodes[7].role = ax::mojom::Role::kGenericContainer;
+  tree_update.nodes[7].AddState(ax::mojom::State::kIgnored);
+
+  tree_update.nodes[8].id = 9;
+  tree_update.nodes[8].role = ax::mojom::Role::kStaticText;
+  tree_update.nodes[8].AddStringAttribute(ax::mojom::StringAttribute::kName,
+                                          "text");
+
+  tree_update.nodes[9].id = 10;
+  tree_update.nodes[9].child_ids = {13};
+  tree_update.nodes[9].role = ax::mojom::Role::kGenericContainer;
+  tree_update.nodes[9].AddState(ax::mojom::State::kIgnored);
+
+  tree_update.nodes[10].id = 11;
+  tree_update.nodes[10].child_ids = {14, 15};
+  tree_update.nodes[10].role = ax::mojom::Role::kGenericContainer;
+  tree_update.nodes[10].AddState(ax::mojom::State::kIgnored);
+
+  tree_update.nodes[11].id = 12;
+  tree_update.nodes[11].role = ax::mojom::Role::kStaticText;
+  tree_update.nodes[11].AddStringAttribute(ax::mojom::StringAttribute::kName,
+                                           "text");
+
+  tree_update.nodes[12].id = 13;
+  tree_update.nodes[12].child_ids = {16};
+  tree_update.nodes[12].role = ax::mojom::Role::kGenericContainer;
+  tree_update.nodes[12].AddState(ax::mojom::State::kIgnored);
+
+  tree_update.nodes[13].id = 14;
+  tree_update.nodes[13].role = ax::mojom::Role::kStaticText;
+  tree_update.nodes[13].AddStringAttribute(ax::mojom::StringAttribute::kName,
+                                           "text");
+
+  tree_update.nodes[14].id = 15;
+  tree_update.nodes[14].role = ax::mojom::Role::kStaticText;
+  tree_update.nodes[14].AddStringAttribute(ax::mojom::StringAttribute::kName,
+                                           "text");
+
+  tree_update.nodes[15].id = 16;
+  tree_update.nodes[15].role = ax::mojom::Role::kStaticText;
+  tree_update.nodes[15].AddStringAttribute(ax::mojom::StringAttribute::kName,
+                                           "text");
+
+  AXTree tree(tree_update);
+  AXNodePosition::SetTree(&tree);
+  AXTree::Selection unignored_selection = tree.GetUnignoredSelection();
+
+  EXPECT_EQ(-1, unignored_selection.anchor_object_id);
+  EXPECT_EQ(-1, unignored_selection.anchor_offset);
+  EXPECT_EQ(-1, unignored_selection.focus_object_id);
+  EXPECT_EQ(-1, unignored_selection.focus_offset);
+  struct SelectionData {
+    int32_t anchor_id;
+    int32_t anchor_offset;
+    int32_t focus_id;
+    int32_t focus_offset;
+  };
+
+  SelectionData input = {1, 0, 1, 0};
+  SelectionData expected = {9, 0, 9, 0};
+  TEST_SELECTION(tree_update, tree, input, expected);
+
+  input = {1, 0, 2, 2};
+  expected = {9, 0, 14, 0};
+  TEST_SELECTION(tree_update, tree, input, expected);
+
+  input = {2, 1, 5, 0};
+  expected = {16, 0, 5, 0};
+  TEST_SELECTION(tree_update, tree, input, expected);
+
+  input = {5, 0, 9, 0};
+  expected = {5, 0, 9, 0};
+  TEST_SELECTION(tree_update, tree, input, expected);
+
+  input = {9, 0, 6, 0};
+  expected = {9, 0, 16, 0};
+  TEST_SELECTION(tree_update, tree, input, expected);
+
+  input = {6, 0, 10, 0};
+  expected = {16, 0, 16, 0};
+  TEST_SELECTION(tree_update, tree, input, expected);
+
+  input = {10, 0, 13, 0};
+  expected = {16, 0, 16, 0};
+  TEST_SELECTION(tree_update, tree, input, expected);
+
+  input = {13, 0, 16, 0};
+  expected = {16, 0, 16, 0};
+  TEST_SELECTION(tree_update, tree, input, expected);
+
+  input = {16, 0, 7, 0};
+  expected = {16, 0, 14, 0};
+  TEST_SELECTION(tree_update, tree, input, expected);
+
+  input = {7, 0, 11, 0};
+  expected = {14, 0, 14, 0};
+  TEST_SELECTION(tree_update, tree, input, expected);
+
+  input = {11, 1, 14, 2};
+  expected = {15, 0, 14, 2};
+  TEST_SELECTION(tree_update, tree, input, expected);
+
+  input = {14, 2, 15, 3};
+  expected = {14, 2, 15, 3};
+  TEST_SELECTION(tree_update, tree, input, expected);
+
+  input = {15, 0, 12, 0};
+  expected = {15, 0, 12, 0};
+  TEST_SELECTION(tree_update, tree, input, expected);
+
+  input = {12, 0, 8, 0};
+  expected = {12, 0, 3, 0};
+  TEST_SELECTION(tree_update, tree, input, expected);
+
+  input = {8, 0, 3, 0};
+  expected = {12, 4, 3, 0};
+  TEST_SELECTION(tree_update, tree, input, expected);
+
+  input = {3, 0, 4, 0};
+  expected = {3, 0, 4, 0};
+  TEST_SELECTION(tree_update, tree, input, expected);
+
+  input = {4, 0, 4, 0};
+  expected = {4, 0, 4, 0};
+  TEST_SELECTION(tree_update, tree, input, expected);
+
+  AXNodePosition::SetTree(nullptr);
+}
+
 TEST(AXTreeTest, ChildTreeIds) {
   ui::AXTreeID tree_id_1 = ui::AXTreeID::CreateNewAXTreeID();
   ui::AXTreeID tree_id_2 = ui::AXTreeID::CreateNewAXTreeID();
diff --git a/ui/accessibility/platform/ax_platform_node_base.cc b/ui/accessibility/platform/ax_platform_node_base.cc
index fe081ae..ab536e0 100644
--- a/ui/accessibility/platform/ax_platform_node_base.cc
+++ b/ui/accessibility/platform/ax_platform_node_base.cc
@@ -673,7 +673,7 @@
   }
 
   // The caret is always at the focus of the selection.
-  int32_t focus_id = delegate_->GetTreeData().sel_focus_object_id;
+  int32_t focus_id = delegate_->GetUnignoredSelection().focus_object_id;
   AXPlatformNodeBase* focus_object =
       static_cast<AXPlatformNodeBase*>(delegate_->GetFromNodeID(focus_id));
 
@@ -1416,25 +1416,30 @@
   return -1;
 }
 
-int AXPlatformNodeBase::GetSelectionAnchor() {
-  int32_t anchor_id = GetDelegate()->GetTreeData().sel_anchor_object_id;
+int AXPlatformNodeBase::GetUnignoredSelectionAnchor() {
+  ui::AXTree::Selection unignored_selection =
+      delegate_->GetUnignoredSelection();
+  int32_t anchor_id = unignored_selection.anchor_object_id;
   AXPlatformNodeBase* anchor_object =
-      static_cast<AXPlatformNodeBase*>(GetDelegate()->GetFromNodeID(anchor_id));
+      static_cast<AXPlatformNodeBase*>(delegate_->GetFromNodeID(anchor_id));
+
   if (!anchor_object)
     return -1;
 
-  int anchor_offset = int{GetDelegate()->GetTreeData().sel_anchor_offset};
+  int anchor_offset = int{unignored_selection.anchor_offset};
   return GetHypertextOffsetFromEndpoint(anchor_object, anchor_offset);
 }
 
-int AXPlatformNodeBase::GetSelectionFocus() {
-  int32_t focus_id = GetDelegate()->GetTreeData().sel_focus_object_id;
+int AXPlatformNodeBase::GetUnignoredSelectionFocus() {
+  ui::AXTree::Selection unignored_selection =
+      delegate_->GetUnignoredSelection();
+  int32_t focus_id = unignored_selection.focus_object_id;
   AXPlatformNodeBase* focus_object =
       static_cast<AXPlatformNodeBase*>(GetDelegate()->GetFromNodeID(focus_id));
   if (!focus_object)
     return -1;
 
-  int focus_offset = int{GetDelegate()->GetTreeData().sel_focus_offset};
+  int focus_offset = int{unignored_selection.focus_offset};
   return GetHypertextOffsetFromEndpoint(focus_object, focus_offset);
 }
 
@@ -1449,8 +1454,8 @@
     return;
   }
 
-  *selection_start = GetSelectionAnchor();
-  *selection_end = GetSelectionFocus();
+  *selection_start = GetUnignoredSelectionAnchor();
+  *selection_end = GetUnignoredSelectionFocus();
   if (*selection_start < 0 || *selection_end < 0)
     return;
 
diff --git a/ui/accessibility/platform/ax_platform_node_base.h b/ui/accessibility/platform/ax_platform_node_base.h
index 53ce1d01..6b3a553 100644
--- a/ui/accessibility/platform/ax_platform_node_base.h
+++ b/ui/accessibility/platform/ax_platform_node_base.h
@@ -359,8 +359,8 @@
   // First they check for a local selection found on the current control, e.g.
   // when querying the selection on a textarea.
   // If not found they retrieve the global selection found on the current frame.
-  int GetSelectionAnchor();
-  int GetSelectionFocus();
+  int GetUnignoredSelectionAnchor();
+  int GetUnignoredSelectionFocus();
 
   // Retrieves the selection offsets in the way required by the IA2 APIs.
   // selection_start and selection_end are -1 when there is no selection active
diff --git a/ui/accessibility/platform/ax_platform_node_delegate.h b/ui/accessibility/platform/ax_platform_node_delegate.h
index e81aa848..5cebb45 100644
--- a/ui/accessibility/platform/ax_platform_node_delegate.h
+++ b/ui/accessibility/platform/ax_platform_node_delegate.h
@@ -38,6 +38,7 @@
 struct AXActionData;
 struct AXNodeData;
 struct AXTreeData;
+class AXTree;
 class AXPlatformNode;
 
 // An object that wants to be accessible should derive from this class.
@@ -65,6 +66,9 @@
   // Get the accessibility tree data for this node.
   virtual const AXTreeData& GetTreeData() const = 0;
 
+  // Get the unignored selection from the tree
+  virtual const AXTree::Selection GetUnignoredSelection() const = 0;
+
   // Creates a text position rooted at this object.
   virtual AXNodePosition::AXPositionInstance CreateTextPositionAt(
       int offset,
diff --git a/ui/accessibility/platform/ax_platform_node_delegate_base.cc b/ui/accessibility/platform/ax_platform_node_delegate_base.cc
index b330d65..32f0061 100644
--- a/ui/accessibility/platform/ax_platform_node_delegate_base.cc
+++ b/ui/accessibility/platform/ax_platform_node_delegate_base.cc
@@ -30,6 +30,11 @@
   return *empty_data;
 }
 
+const AXTree::Selection AXPlatformNodeDelegateBase::GetUnignoredSelection()
+    const {
+  return AXTree::Selection{-1, -1, -1, ax::mojom::TextAffinity::kDownstream};
+}
+
 AXNodePosition::AXPositionInstance
 AXPlatformNodeDelegateBase::CreateTextPositionAt(
     int offset,
diff --git a/ui/accessibility/platform/ax_platform_node_delegate_base.h b/ui/accessibility/platform/ax_platform_node_delegate_base.h
index 066cccae..b5ed307 100644
--- a/ui/accessibility/platform/ax_platform_node_delegate_base.h
+++ b/ui/accessibility/platform/ax_platform_node_delegate_base.h
@@ -35,6 +35,9 @@
   // Get the accessibility tree data for this node.
   const AXTreeData& GetTreeData() const override;
 
+  // Get the unignored selection from the tree
+  const AXTree::Selection GetUnignoredSelection() const override;
+
   // Creates a text position rooted at this object.
   AXNodePosition::AXPositionInstance CreateTextPositionAt(
       int offset,
diff --git a/ui/accessibility/platform/ax_platform_node_textchildprovider_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_textchildprovider_win_unittest.cc
index e3d9a09..b8825da 100644
--- a/ui/accessibility/platform/ax_platform_node_textchildprovider_win_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_textchildprovider_win_unittest.cc
@@ -70,7 +70,7 @@
     Init(update);
 
     AXNode* root_node = GetRootNode();
-    AXNodePosition::SetTreeForTesting(tree_.get());
+    AXNodePosition::SetTree(tree_.get());
     AXNode* nontext_child_of_root_node = root_node->children()[0];
     AXNode* text_child_of_root_node = root_node->children()[1];
     AXNode* nontext_child_of_nontext_node =
@@ -98,7 +98,7 @@
                            text_child_of_text_text_child_provider_);
   }
 
-  void TearDown() override { AXNodePosition::SetTreeForTesting(nullptr); }
+  void TearDown() override { AXNodePosition::SetTree(nullptr); }
 
   void InitITextChildProvider(
       AXNode* node,
diff --git a/ui/accessibility/platform/ax_platform_node_textprovider_win.cc b/ui/accessibility/platform/ax_platform_node_textprovider_win.cc
index 5b47ce7..20d55a347 100644
--- a/ui/accessibility/platform/ax_platform_node_textprovider_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_textprovider_win.cc
@@ -64,10 +64,12 @@
 
   AXPlatformNodeDelegate* delegate = owner()->GetDelegate();
 
+  ui::AXTree::Selection unignored_selection = delegate->GetUnignoredSelection();
+
   AXPlatformNode* anchor_object =
-      delegate->GetFromNodeID(delegate->GetTreeData().sel_anchor_object_id);
+      delegate->GetFromNodeID(unignored_selection.anchor_object_id);
   AXPlatformNode* focus_object =
-      delegate->GetFromNodeID(delegate->GetTreeData().sel_focus_object_id);
+      delegate->GetFromNodeID(unignored_selection.focus_object_id);
 
   // If there's no selected object (or the selected object is not in the
   // subtree), return success and don't fill the SAFEARRAY
@@ -81,12 +83,12 @@
       (!anchor_object->IsDescendantOf(owner())))
     return S_OK;
 
-  // sel_anchor_offset corresponds to the selection start index
-  // and sel_focus_offset is where the selection ends.
+  // anchor_offset corresponds to the selection start index
+  // and focus_offset is where the selection ends.
   // If they are equal, that indicates a caret on editable text,
   // which should return a degenerate (empty) text range.
-  auto start_offset = delegate->GetTreeData().sel_anchor_offset;
-  auto end_offset = delegate->GetTreeData().sel_focus_offset;
+  auto start_offset = unignored_selection.anchor_offset;
+  auto end_offset = unignored_selection.focus_offset;
 
   // Reverse start and end if the selection goes backwards
   if (start_offset > end_offset)
diff --git a/ui/accessibility/platform/ax_platform_node_textprovider_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_textprovider_win_unittest.cc
index e5fe26b..f56927c0 100644
--- a/ui/accessibility/platform/ax_platform_node_textprovider_win_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_textprovider_win_unittest.cc
@@ -117,7 +117,7 @@
   Init(update);
 
   AXNode* root_node = GetRootNode();
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
   AXNode* text_node = root_node->children()[0];
   AXNode* empty_text_node = root_node->children()[1];
 
@@ -194,7 +194,7 @@
   Init(root_data, text_data);
 
   AXNode* root_node = GetRootNode();
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
   AXNode* text_node = root_node->children()[0];
 
   struct NearestTextIndexTestData {
@@ -346,7 +346,7 @@
   update.nodes.push_back(textbox_data);
   Init(update);
 
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
 
   ComPtr<IRawElementProviderSimple> root_node =
       GetRootIRawElementProviderSimple();
@@ -463,7 +463,7 @@
   EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
             text_edit_provider->GetSelection(selections.Receive()));
 
-  AXNodePosition::SetTreeForTesting(nullptr);
+  AXNodePosition::SetTree(nullptr);
 }
 
 TEST_F(AXPlatformNodeTextProviderTest, TestITextProviderGetActiveComposition) {
@@ -488,7 +488,7 @@
   update.nodes.push_back(text_data);
   Init(update);
 
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
 
   ComPtr<IRawElementProviderSimple> root_node =
       GetRootIRawElementProviderSimple();
@@ -550,7 +550,7 @@
   update.nodes.push_back(text_data);
   Init(update);
 
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
 
   ComPtr<IRawElementProviderSimple> root_node =
       GetRootIRawElementProviderSimple();
diff --git a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
index feb79f4..b0d3ef65 100644
--- a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
@@ -837,7 +837,7 @@
 
 TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderClone) {
   Init(BuildTextDocument({"some text"}));
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider,
@@ -868,7 +868,7 @@
 TEST_F(AXPlatformNodeTextRangeProviderTest,
        TestITextRangeProviderCompareEndpoints) {
   Init(BuildTextDocument({"some text", "more text"}));
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
   AXNode* root_node = GetRootNode();
 
   // Get the textRangeProvider for the document,
@@ -949,7 +949,7 @@
 TEST_F(AXPlatformNodeTextRangeProviderTest,
        TestITextRangeProviderExpandToEnclosingCharacter) {
   Init(BuildTextDocument({"some text", "more text"}));
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
   AXNode* root_node = GetRootNode();
 
   ComPtr<ITextRangeProvider> text_range_provider;
@@ -1027,7 +1027,7 @@
        TestITextRangeProviderExpandToEnclosingWord) {
   Init(BuildTextDocument({"some text", "definitely not text"},
                          /*build_word_boundaries_offsets*/ true));
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider,
@@ -1076,7 +1076,7 @@
 TEST_F(AXPlatformNodeTextRangeProviderTest,
        TestITextRangeProviderExpandToEnclosingLine) {
   Init(BuildTextDocument({"line #1", "maybe line #1?", "not line #1"}));
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider,
@@ -1125,7 +1125,7 @@
 TEST_F(AXPlatformNodeTextRangeProviderTest,
        TestITextRangeProviderExpandToEnclosingParagraph) {
   Init(BuildAXTreeForMove());
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
   AXNode* root_node = GetRootNode();
 
   ComPtr<ITextRangeProvider> text_range_provider;
@@ -1185,7 +1185,7 @@
 TEST_F(AXPlatformNodeTextRangeProviderTest,
        TestITextRangeProviderExpandToEnclosingFormat) {
   Init(BuildAXTreeForMoveByFormat());
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
   AXNode* root_node = GetRootNode();
 
   ComPtr<ITextRangeProvider> text_range_provider;
@@ -1249,7 +1249,7 @@
 TEST_F(AXPlatformNodeTextRangeProviderTest,
        TestITextRangeProviderExpandToEnclosingDocument) {
   Init(BuildTextDocument({"some text", "more text", "even more text"}));
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
 
   AXNode* root_node = GetRootNode();
   AXNode* text_node = root_node->children()[0];
@@ -1289,7 +1289,7 @@
   // validate call.
   {
     Init(BuildTextDocument({}));
-    AXNodePosition::SetTreeForTesting(nullptr);
+    AXNodePosition::SetTree(nullptr);
 
     ComPtr<ITextRangeProvider> text_range_provider;
     GetTextRangeProviderFromTextNode(text_range_provider, GetRootNode());
@@ -1326,7 +1326,7 @@
   // performed on the other provider.
   {
     Init(BuildTextDocument({}));
-    AXNodePosition::SetTreeForTesting(tree_.get());
+    AXNodePosition::SetTree(tree_.get());
 
     ComPtr<ITextRangeProvider> this_provider;
     GetTextRangeProviderFromTextNode(this_provider, GetRootNode());
@@ -1352,7 +1352,7 @@
 
 TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderGetText) {
   Init(BuildTextDocument({"some text", "more text"}));
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
 
   AXNode* root_node = GetRootNode();
   AXNode* text_node = root_node->children()[0];
@@ -1405,7 +1405,7 @@
        TestITextRangeProviderMoveCharacter) {
   Init(BuildAXTreeForMove());
   AXNode* root_node = GetRootNode();
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider, root_node);
@@ -1486,13 +1486,13 @@
                   /*expected_text*/ L"",
                   /*expected_count*/ -2);
 
-  AXNodePosition::SetTreeForTesting(nullptr);
+  AXNodePosition::SetTree(nullptr);
 }
 
 TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderMoveFormat) {
   Init(BuildAXTreeForMoveByFormat());
   AXNode* root_node = GetRootNode();
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider, root_node);
@@ -1618,13 +1618,13 @@
                   /*expected_text*/ L"",
                   /*expected_count*/ -2);
 
-  AXNodePosition::SetTreeForTesting(nullptr);
+  AXNodePosition::SetTree(nullptr);
 }
 
 TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderMovePage) {
   Init(BuildAXTreeForMoveByPage());
   AXNode* root_node = GetRootNode();
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider, root_node);
@@ -1697,13 +1697,13 @@
                   L"some text on page 2",
                   /*expected_count*/ 0);
 
-  AXNodePosition::SetTreeForTesting(nullptr);
+  AXNodePosition::SetTree(nullptr);
 }
 
 TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderMoveWord) {
   Init(BuildAXTreeForMove());
   AXNode* root_node = GetRootNode();
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider, root_node);
@@ -1791,13 +1791,13 @@
                   /*expected_text*/ L"",
                   /*expected_count*/ -2);
 
-  AXNodePosition::SetTreeForTesting(nullptr);
+  AXNodePosition::SetTree(nullptr);
 }
 
 TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderMoveLine) {
   Init(BuildAXTreeForMove());
   AXNode* root_node = GetRootNode();
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider, root_node);
@@ -1869,14 +1869,14 @@
                   /*expected_text*/ L"",
                   /*expected_count*/ -2);
 
-  AXNodePosition::SetTreeForTesting(nullptr);
+  AXNodePosition::SetTree(nullptr);
 }
 
 TEST_F(AXPlatformNodeTextRangeProviderTest,
        TestITextRangeProviderMoveParagraph) {
   Init(BuildAXTreeForMove());
   AXNode* root_node = GetRootNode();
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider, root_node);
@@ -2001,14 +2001,14 @@
                   /*expected_text*/ L"",
                   /*expected_count*/ -2);
 
-  AXNodePosition::SetTreeForTesting(nullptr);
+  AXNodePosition::SetTree(nullptr);
 }
 
 TEST_F(AXPlatformNodeTextRangeProviderTest,
        TestITextRangeProviderMoveDocument) {
   Init(BuildAXTreeForMove());
   AXNode* root_node = GetRootNode();
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider, root_node);
@@ -2056,25 +2056,25 @@
                   /*expected_text*/ L"",
                   /*expected_count*/ 0);
 
-  AXNodePosition::SetTreeForTesting(nullptr);
+  AXNodePosition::SetTree(nullptr);
 }
 
 TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderMove) {
   Init(BuildAXTreeForMove());
   AXNode* root_node = GetRootNode();
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider, root_node);
 
   // TODO(https://crbug.com/928948): test intermixed unit types
-  AXNodePosition::SetTreeForTesting(nullptr);
+  AXNodePosition::SetTree(nullptr);
 }
 
 TEST_F(AXPlatformNodeTextRangeProviderTest,
        TestITextRangeProviderMoveEndpointByDocument) {
   Init(BuildTextDocument({"some text", "more text", "even more text"}));
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
   AXNode* text_node = GetRootNode()->children()[1];
 
   // Run the test twice, one for TextUnit_Document and once for TextUnit_Page,
@@ -2141,7 +2141,7 @@
 TEST_F(AXPlatformNodeTextRangeProviderTest,
        TestITextRangeProviderMoveEndpointByCharacter) {
   Init(BuildTextDocument({"some text", "more text", "even more text"}));
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider,
@@ -2247,7 +2247,7 @@
        TestITextRangeProviderMoveEndpointByWord) {
   Init(BuildTextDocument({"some text", "more text", "even more text"},
                          /*build_word_boundaries_offsets*/ true));
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider,
@@ -2345,7 +2345,7 @@
 TEST_F(AXPlatformNodeTextRangeProviderTest,
        TestITextRangeProviderMoveEndpointByLine) {
   Init(BuildTextDocument({"0", "1", "2", "3", "4", "5", "6"}));
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider,
@@ -2502,7 +2502,7 @@
 
   // Set up variables from the tree for testing.
   AXNode* root_node = GetRootNode();
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
   AXNode* text_node = root_node->children()[0]->children()[0];
 
   ComPtr<ITextRangeProvider> text_range_provider;
@@ -2544,14 +2544,14 @@
   ASSERT_EQ(-1, count);
   EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"some text");
 
-  AXNodePosition::SetTreeForTesting(nullptr);
+  AXNodePosition::SetTree(nullptr);
 }
 
 TEST_F(AXPlatformNodeTextRangeProviderTest,
        TestITextRangeProviderMoveEndpointByFormat) {
   Init(BuildAXTreeForMoveByFormat());
   AXNode* root_node = GetRootNode();
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider, root_node);
@@ -2609,12 +2609,12 @@
       /*expected_text*/ L"",
       /*expected_count*/ -6);
 
-  AXNodePosition::SetTreeForTesting(nullptr);
+  AXNodePosition::SetTree(nullptr);
 }
 
 TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderCompare) {
   Init(BuildTextDocument({"some text", "some text"}));
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
   AXNode* root_node = GetRootNode();
 
   // Get the textRangeProvider for the document,
@@ -2656,7 +2656,7 @@
 
 TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderSelection) {
   Init(BuildTextDocument({"some text"}));
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider, GetRootNode());
@@ -2669,7 +2669,7 @@
        TestITextRangeProviderGetBoundingRectangles) {
   ui::AXTreeUpdate update = BuildAXTreeForBoundingRectangles();
   Init(update);
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
   AXTreeManagerMap::GetInstance().AddTreeManager(update.tree_data.tree_id,
                                                  this);
   ComPtr<ITextRangeProvider> text_range_provider;
@@ -2739,7 +2739,7 @@
 TEST_F(AXPlatformNodeTextRangeProviderTest,
        TestITextRangeProviderGetEnclosingElement) {
   Init(BuildTextDocument({"some text", "more text"}));
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
   AXNode* root_node = GetRootNode();
 
   // Test GetEnclosingElement for each child text node.
@@ -2767,7 +2767,7 @@
   Init(BuildTextDocument({"some text", "more text"}));
 
   AXNode* root_node = GetRootNode();
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
   AXNode* text_node = root_node->children()[0];
   AXNode* more_text_node = root_node->children()[1];
 
@@ -3018,7 +3018,7 @@
 
   // Set up variables from the tree for testing.
   AXNode* rootnode = GetRootNode();
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
   AXNode* node1 = rootnode->children()[0];
   AXNode* node2 = rootnode->children()[1];
   AXNode* node3 = node1->children()[0];
@@ -3211,7 +3211,7 @@
   update.nodes.push_back(list_item2_text_data);
 
   Init(update);
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
   AXTreeManagerMap::GetInstance().AddTreeManager(tree_data.tree_id, this);
 
   AXNode* root_node = GetRootNode();
@@ -3427,7 +3427,7 @@
   update.nodes.push_back(text_data_second);
 
   Init(update);
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
   AXTreeManagerMap::GetInstance().AddTreeManager(tree_data.tree_id, this);
 
   ComPtr<ITextRangeProvider> document_range_provider;
@@ -3487,7 +3487,7 @@
 
 TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderSelect) {
   Init(BuildTextDocument({"some text", "more text2"}));
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
   AXNode* root_node = GetRootNode();
 
   // Text range for the document, which contains text "some textmore text2".
@@ -3531,10 +3531,11 @@
     text_range_provider->Select();
 
     // Verify selection.
-    EXPECT_EQ(2, delegate->GetTreeData().sel_anchor_object_id);
-    EXPECT_EQ(2, delegate->GetTreeData().sel_focus_object_id);
-    EXPECT_EQ(0, delegate->GetTreeData().sel_anchor_offset);
-    EXPECT_EQ(9, delegate->GetTreeData().sel_focus_offset);
+    AXTree::Selection unignored_selection = delegate->GetUnignoredSelection();
+    EXPECT_EQ(2, unignored_selection.anchor_object_id);
+    EXPECT_EQ(2, unignored_selection.focus_object_id);
+    EXPECT_EQ(0, unignored_selection.anchor_offset);
+    EXPECT_EQ(9, unignored_selection.focus_offset);
 
     // Verify the content of the selection.
     document_provider->GetSelection(selection.Receive());
@@ -3557,10 +3558,11 @@
     more_text_range_provider->Select();
 
     // Verify selection
-    EXPECT_EQ(3, delegate->GetTreeData().sel_anchor_object_id);
-    EXPECT_EQ(3, delegate->GetTreeData().sel_focus_object_id);
-    EXPECT_EQ(0, delegate->GetTreeData().sel_anchor_offset);
-    EXPECT_EQ(10, delegate->GetTreeData().sel_focus_offset);
+    AXTree::Selection unignored_selection = delegate->GetUnignoredSelection();
+    EXPECT_EQ(3, unignored_selection.anchor_object_id);
+    EXPECT_EQ(3, unignored_selection.focus_object_id);
+    EXPECT_EQ(0, unignored_selection.anchor_offset);
+    EXPECT_EQ(10, unignored_selection.focus_offset);
 
     // Verify the content of the selection.
     document_provider->GetSelection(selection.Receive());
@@ -3583,10 +3585,11 @@
     document_text_range_provider->Select();
 
     // Verify selection.
-    EXPECT_EQ(2, delegate->GetTreeData().sel_anchor_object_id);
-    EXPECT_EQ(3, delegate->GetTreeData().sel_focus_object_id);
-    EXPECT_EQ(0, delegate->GetTreeData().sel_anchor_offset);
-    EXPECT_EQ(10, delegate->GetTreeData().sel_focus_offset);
+    AXTree::Selection unignored_selection = delegate->GetUnignoredSelection();
+    EXPECT_EQ(2, unignored_selection.anchor_object_id);
+    EXPECT_EQ(3, unignored_selection.focus_object_id);
+    EXPECT_EQ(0, unignored_selection.anchor_offset);
+    EXPECT_EQ(10, unignored_selection.focus_offset);
 
     // When selection spans multiple nodes ITextProvider::GetSelection is not
     // supported. But the text range is still selected.
@@ -3603,10 +3606,11 @@
     text_range_provider->Select();
 
     // Verify selection.
-    EXPECT_EQ(2, delegate->GetTreeData().sel_anchor_object_id);
-    EXPECT_EQ(2, delegate->GetTreeData().sel_focus_object_id);
-    EXPECT_EQ(9, delegate->GetTreeData().sel_anchor_offset);
-    EXPECT_EQ(9, delegate->GetTreeData().sel_focus_offset);
+    AXTree::Selection unignored_selection = delegate->GetUnignoredSelection();
+    EXPECT_EQ(2, unignored_selection.anchor_object_id);
+    EXPECT_EQ(2, unignored_selection.focus_object_id);
+    EXPECT_EQ(9, unignored_selection.anchor_offset);
+    EXPECT_EQ(9, unignored_selection.focus_offset);
 
     // Verify the content of the selection.
     document_provider->GetSelection(selection.Receive());
@@ -3627,7 +3631,7 @@
 
 TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderFindText) {
   Init(BuildTextDocument({"some text", "more text"}));
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
 
   AXNode* root_node = GetRootNode();
   ComPtr<ITextRangeProvider> range;
@@ -3656,7 +3660,7 @@
 TEST_F(AXPlatformNodeTextRangeProviderTest,
        TestITextRangeProviderFindTextBackwards) {
   Init(BuildTextDocument({"text", "some", "text"}));
-  AXNodePosition::SetTreeForTesting(tree_.get());
+  AXNodePosition::SetTree(tree_.get());
   AXNode* root_node = GetRootNode();
 
   ComPtr<ITextRangeProvider> root_range_provider;
@@ -3723,7 +3727,7 @@
     update.nodes = {root_data};
 
     Init(update);
-    AXNodePosition::SetTreeForTesting(tree_.get());
+    AXNodePosition::SetTree(tree_.get());
 
     bool is_search_backward;
     VARIANT is_hidden_attr_val;
@@ -3808,7 +3812,7 @@
     update.nodes = {root_data, text_data1};
 
     Init(update);
-    AXNodePosition::SetTreeForTesting(tree_.get());
+    AXNodePosition::SetTree(tree_.get());
 
     bool is_search_backward;
     VARIANT is_hidden_attr_val;
@@ -3893,7 +3897,7 @@
     update.nodes = {root_data, text_data1, text_data2};
 
     Init(update);
-    AXNodePosition::SetTreeForTesting(tree_.get());
+    AXNodePosition::SetTree(tree_.get());
 
     bool is_search_backward;
     VARIANT is_hidden_attr_val;
@@ -3999,7 +4003,7 @@
                     text_data3, text_data4, text_data5};
 
     Init(update);
-    AXNodePosition::SetTreeForTesting(tree_.get());
+    AXNodePosition::SetTree(tree_.get());
 
     bool is_search_backward;
     VARIANT is_hidden_attr_val;
@@ -4109,7 +4113,7 @@
                     text_data3, text_data4, text_data5};
 
     Init(update);
-    AXNodePosition::SetTreeForTesting(tree_.get());
+    AXNodePosition::SetTree(tree_.get());
 
     bool is_search_backward;
     VARIANT is_hidden_attr_val;
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index 9612041..96516ac 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -1591,19 +1591,21 @@
                                                       LONG* nRanges) {
   COM_OBJECT_VALIDATE_2_ARGS(ranges, nRanges);
   AXPlatformNode::NotifyAddAXModeFlags(kScreenReaderAndHTMLAccessibilityModes);
-  int32_t anchor_id = GetDelegate()->GetTreeData().sel_anchor_object_id;
+  AXTree::Selection unignored_selection =
+      GetDelegate()->GetUnignoredSelection();
+  int32_t anchor_id = unignored_selection.anchor_object_id;
   auto* anchor_node =
       static_cast<AXPlatformNodeWin*>(GetDelegate()->GetFromNodeID(anchor_id));
   if (!anchor_node)
     return E_FAIL;
-  int anchor_offset = int{GetDelegate()->GetTreeData().sel_anchor_offset};
+  int anchor_offset = int{unignored_selection.anchor_offset};
 
-  int32_t focus_id = GetDelegate()->GetTreeData().sel_focus_object_id;
+  int32_t focus_id = unignored_selection.focus_object_id;
   auto* focus_node =
       static_cast<AXPlatformNodeWin*>(GetDelegate()->GetFromNodeID(focus_id));
   if (!focus_node)
     return E_FAIL;
-  int focus_offset = int{GetDelegate()->GetTreeData().sel_focus_offset};
+  int focus_offset = int{unignored_selection.focus_offset};
 
   if (!IsDescendant(anchor_node) || !IsDescendant(focus_node))
     return S_FALSE;  // No selection within this subtree.
@@ -6824,7 +6826,7 @@
     int selection_start, selection_end;
     GetSelectionOffsets(&selection_start, &selection_end);
     // TODO(nektar): Deprecate selection_start and selection_end in favor of
-    // sel_anchor_offset/sel_focus_offset. See https://crbug.com/645596.
+    // anchor_offset/focus_offset. See https://crbug.com/645596.
     if (selection_end < 0)
       *offset = 0;
     else
diff --git a/ui/accessibility/platform/ax_platform_node_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_win_unittest.cc
index 53110c7..12b6d38 100644
--- a/ui/accessibility/platform/ax_platform_node_win_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_win_unittest.cc
@@ -222,7 +222,7 @@
   // Destroy the tree and make sure we're not leaking any objects.
   ax_fragment_root_.reset(nullptr);
   tree_.reset(nullptr);
-  AXNodePosition::SetTreeForTesting(nullptr);
+  AXNodePosition::SetTree(nullptr);
   ASSERT_EQ(0U, AXPlatformNodeBase::GetInstanceCountForTesting());
 }
 
diff --git a/ui/accessibility/platform/test_ax_node_wrapper.cc b/ui/accessibility/platform/test_ax_node_wrapper.cc
index 273b2eb..465ffab 100644
--- a/ui/accessibility/platform/test_ax_node_wrapper.cc
+++ b/ui/accessibility/platform/test_ax_node_wrapper.cc
@@ -99,6 +99,10 @@
   return tree_->data();
 }
 
+const AXTree::Selection TestAXNodeWrapper::GetUnignoredSelection() const {
+  return tree_->GetUnignoredSelection();
+}
+
 AXNodePosition::AXPositionInstance TestAXNodeWrapper::CreateTextPositionAt(
     int offset,
     ax::mojom::TextAffinity affinity) const {
diff --git a/ui/accessibility/platform/test_ax_node_wrapper.h b/ui/accessibility/platform/test_ax_node_wrapper.h
index 9e98cf5..85e39c5 100644
--- a/ui/accessibility/platform/test_ax_node_wrapper.h
+++ b/ui/accessibility/platform/test_ax_node_wrapper.h
@@ -52,6 +52,7 @@
   // AXPlatformNodeDelegate.
   const AXNodeData& GetData() const override;
   const AXTreeData& GetTreeData() const override;
+  const AXTree::Selection GetUnignoredSelection() const override;
   AXNodePosition::AXPositionInstance CreateTextPositionAt(
       int offset,
       ax::mojom::TextAffinity affinity =
diff --git a/ui/events/blink/blink_features.cc b/ui/events/blink/blink_features.cc
index 468ae89b..b173f77 100644
--- a/ui/events/blink/blink_features.cc
+++ b/ui/events/blink/blink_features.cc
@@ -16,7 +16,7 @@
                                           base::FEATURE_ENABLED_BY_DEFAULT};
 
 const base::Feature kUpdateHoverAtBeginFrame{"UpdateHoverAtBeginFrame",
-                                             base::FEATURE_DISABLED_BY_DEFAULT};
+                                             base::FEATURE_ENABLED_BY_DEFAULT};
 
 const base::Feature kCompositorTouchAction{"CompositorTouchAction",
                                            base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/ui/gl/BUILD.gn b/ui/gl/BUILD.gn
index 877db007..fd72f31 100644
--- a/ui/gl/BUILD.gn
+++ b/ui/gl/BUILD.gn
@@ -4,7 +4,6 @@
 
 import("//build/buildflag_header.gni")
 import("//build/config/chrome_build.gni")
-import("//build/config/chromecast_build.gni")
 import("//build/config/jumbo.gni")
 import("//build/config/linux/pkg_config.gni")
 import("//build/config/ui.gni")
@@ -14,7 +13,7 @@
 
 declare_args() {
   enable_swiftshader = (is_win || is_linux || (is_mac && use_egl) ||
-                        is_chromeos || is_fuchsia) && !is_cast_audio_only &&
+                        is_chromeos || is_fuchsia) &&
                        (target_cpu == "x86" || target_cpu == "x64" ||
                         target_cpu == "arm" || target_cpu == "arm64" ||
                         target_cpu == "mipsel" || target_cpu == "mips64el")
diff --git a/ui/gl/direct_composition_child_surface_win.cc b/ui/gl/direct_composition_child_surface_win.cc
index a4ab0d7..df678c1 100644
--- a/ui/gl/direct_composition_child_surface_win.cc
+++ b/ui/gl/direct_composition_child_surface_win.cc
@@ -15,6 +15,7 @@
 #include "base/win/windows_version.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/gl/color_space_utils.h"
+#include "ui/gl/direct_composition_surface_win.h"
 #include "ui/gl/egl_util.h"
 #include "ui/gl/gl_angle_util_win.h"
 #include "ui/gl/gl_context.h"
@@ -40,51 +41,11 @@
 // is made current, then this surface will be suspended.
 IDCompositionSurface* g_current_surface = nullptr;
 
-// Returns true if swap chain tearing is supported.
-bool IsSwapChainTearingSupported() {
-  static const bool supported = [] {
-    // Swap chain tearing is used only if vsync is disabled explicitly.
-    if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
-            switches::kDisableGpuVsync))
-      return false;
-
-    // Swap chain tearing is supported only on Windows 10 Anniversary Edition
-    // (Redstone 1) and above.
-    if (base::win::GetVersion() < base::win::Version::WIN10_RS1)
-      return false;
-
-    Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
-        QueryD3D11DeviceObjectFromANGLE();
-    if (!d3d11_device) {
-      DLOG(ERROR) << "Not using swap chain tearing because failed to retrieve "
-                     "D3D11 device from ANGLE";
-      return false;
-    }
-    Microsoft::WRL::ComPtr<IDXGIDevice> dxgi_device;
-    d3d11_device.As(&dxgi_device);
-    DCHECK(dxgi_device);
-    Microsoft::WRL::ComPtr<IDXGIAdapter> dxgi_adapter;
-    dxgi_device->GetAdapter(&dxgi_adapter);
-    DCHECK(dxgi_adapter);
-    Microsoft::WRL::ComPtr<IDXGIFactory5> dxgi_factory;
-    if (FAILED(dxgi_adapter->GetParent(IID_PPV_ARGS(&dxgi_factory)))) {
-      DLOG(ERROR) << "Not using swap chain tearing because failed to retrieve "
-                     "IDXGIFactory5 interface";
-      return false;
-    }
-
-    BOOL present_allow_tearing = FALSE;
-    DCHECK(dxgi_factory);
-    if (FAILED(dxgi_factory->CheckFeatureSupport(
-            DXGI_FEATURE_PRESENT_ALLOW_TEARING, &present_allow_tearing,
-            sizeof(present_allow_tearing)))) {
-      DLOG(ERROR)
-          << "Not using swap chain tearing because CheckFeatureSupport failed";
-      return false;
-    }
-    return !!present_allow_tearing;
-  }();
-  return supported;
+bool AllowTearing() {
+  // Swap chain tearing is used only if vsync is disabled explicitly.
+  return base::CommandLine::ForCurrentProcess()->HasSwitch(
+             switches::kDisableGpuVsync) &&
+         DirectCompositionSurfaceWin::IsSwapChainTearingSupported();
 }
 }  // namespace
 
@@ -156,9 +117,8 @@
       dcomp_surface_serial_++;
     } else if (!will_discard) {
       TRACE_EVENT0("gpu", "DirectCompositionChildSurfaceWin::PresentSwapChain");
-      bool allow_tearing = IsSwapChainTearingSupported();
-      UINT interval = first_swap_ || !vsync_enabled_ || allow_tearing ? 0 : 1;
-      UINT flags = allow_tearing ? DXGI_PRESENT_ALLOW_TEARING : 0;
+      UINT interval = first_swap_ || !vsync_enabled_ || AllowTearing() ? 0 : 1;
+      UINT flags = AllowTearing() ? DXGI_PRESENT_ALLOW_TEARING : 0;
       DXGI_PRESENT_PARAMETERS params = {};
       RECT dirty_rect = swap_rect_.ToRECT();
       params.DirtyRectsCount = 1;
@@ -336,8 +296,7 @@
     desc.AlphaMode = (has_alpha_ || enable_dc_layers_)
                          ? DXGI_ALPHA_MODE_PREMULTIPLIED
                          : DXGI_ALPHA_MODE_IGNORE;
-    desc.Flags =
-        IsSwapChainTearingSupported() ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0;
+    desc.Flags = AllowTearing() ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0;
     HRESULT hr = dxgi_factory->CreateSwapChainForComposition(
         d3d11_device_.Get(), &desc, nullptr, &swap_chain_);
     first_swap_ = true;
@@ -439,8 +398,7 @@
   // ResizeBuffers can't change alpha blending mode.
   if (swap_chain_ && resize_only) {
     DXGI_FORMAT format = ColorSpaceUtils::GetDXGIFormat(color_space_);
-    UINT flags =
-        IsSwapChainTearingSupported() ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0;
+    UINT flags = AllowTearing() ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0;
     HRESULT hr = swap_chain_->ResizeBuffers(2 /* BufferCount */, size.width(),
                                             size.height(), format, flags);
     UMA_HISTOGRAM_BOOLEAN("GPU.DirectComposition.SwapChainResizeResult",
diff --git a/ui/gl/direct_composition_surface_win.cc b/ui/gl/direct_composition_surface_win.cc
index e5f67db1..7a22240c 100644
--- a/ui/gl/direct_composition_surface_win.cc
+++ b/ui/gl/direct_composition_surface_win.cc
@@ -407,6 +407,43 @@
   return hdr_monitor_found;
 }
 
+// static
+bool DirectCompositionSurfaceWin::IsSwapChainTearingSupported() {
+  static const bool supported = [] {
+    Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
+        QueryD3D11DeviceObjectFromANGLE();
+    if (!d3d11_device) {
+      DLOG(ERROR) << "Not using swap chain tearing because failed to retrieve "
+                     "D3D11 device from ANGLE";
+      return false;
+    }
+    Microsoft::WRL::ComPtr<IDXGIDevice> dxgi_device;
+    d3d11_device.As(&dxgi_device);
+    DCHECK(dxgi_device);
+    Microsoft::WRL::ComPtr<IDXGIAdapter> dxgi_adapter;
+    dxgi_device->GetAdapter(&dxgi_adapter);
+    DCHECK(dxgi_adapter);
+    Microsoft::WRL::ComPtr<IDXGIFactory5> dxgi_factory;
+    if (FAILED(dxgi_adapter->GetParent(IID_PPV_ARGS(&dxgi_factory)))) {
+      DLOG(ERROR) << "Not using swap chain tearing because failed to retrieve "
+                     "IDXGIFactory5 interface";
+      return false;
+    }
+
+    BOOL present_allow_tearing = FALSE;
+    DCHECK(dxgi_factory);
+    if (FAILED(dxgi_factory->CheckFeatureSupport(
+            DXGI_FEATURE_PRESENT_ALLOW_TEARING, &present_allow_tearing,
+            sizeof(present_allow_tearing)))) {
+      DLOG(ERROR)
+          << "Not using swap chain tearing because CheckFeatureSupport failed";
+      return false;
+    }
+    return !!present_allow_tearing;
+  }();
+  return supported;
+}
+
 bool DirectCompositionSurfaceWin::Initialize(GLSurfaceFormat format) {
   d3d11_device_ = QueryD3D11DeviceObjectFromANGLE();
   if (!d3d11_device_) {
diff --git a/ui/gl/direct_composition_surface_win.h b/ui/gl/direct_composition_surface_win.h
index b504372..7111696 100644
--- a/ui/gl/direct_composition_surface_win.h
+++ b/ui/gl/direct_composition_surface_win.h
@@ -77,6 +77,9 @@
   // Returns true if there is an HDR capable display connected.
   static bool IsHDRSupported();
 
+  // Returns true if swap chain tearing is supported.
+  static bool IsSwapChainTearingSupported();
+
   static void SetScaledOverlaysSupportedForTesting(bool value);
 
   static void SetOverlayFormatUsedForTesting(DXGI_FORMAT format);
diff --git a/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.cc b/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.cc
index 2327896..41f63b23 100644
--- a/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.cc
+++ b/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.cc
@@ -169,7 +169,8 @@
     VkImage* vk_image,
     VkImageCreateInfo* vk_image_info,
     VkDeviceMemory* vk_device_memory,
-    VkDeviceSize* mem_allocation_size) {
+    VkDeviceSize* mem_allocation_size,
+    base::Optional<gpu::VulkanYCbCrInfo>* ycbcr_info) {
   NOTIMPLEMENTED();
   return false;
 }
diff --git a/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.h b/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.h
index e787a0e1..cbbbbcc5 100644
--- a/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.h
+++ b/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.h
@@ -46,7 +46,8 @@
       VkImage* vk_image,
       VkImageCreateInfo* vk_image_info,
       VkDeviceMemory* vk_device_memory,
-      VkDeviceSize* mem_allocation_size) override;
+      VkDeviceSize* mem_allocation_size,
+      base::Optional<gpu::VulkanYCbCrInfo>* ycbcr_info) override;
 
  private:
   gpu::VulkanInstance vulkan_instance_;
diff --git a/ui/ozone/platform/headless/BUILD.gn b/ui/ozone/platform/headless/BUILD.gn
index c71628cf..635cc8f 100644
--- a/ui/ozone/platform/headless/BUILD.gn
+++ b/ui/ozone/platform/headless/BUILD.gn
@@ -31,7 +31,6 @@
     "//ui/events/ozone:events_ozone_layout",
     "//ui/events/platform",
     "//ui/gfx/geometry",
-    "//ui/gl:buildflags",
     "//ui/ozone:ozone_base",
     "//ui/ozone/common",
     "//ui/platform_window",
diff --git a/ui/ozone/platform/headless/headless_surface_factory.cc b/ui/ozone/platform/headless/headless_surface_factory.cc
index 7218de3a3..4ec93cec 100644
--- a/ui/ozone/platform/headless/headless_surface_factory.cc
+++ b/ui/ozone/platform/headless/headless_surface_factory.cc
@@ -20,7 +20,6 @@
 #include "ui/gfx/native_pixmap.h"
 #include "ui/gfx/skia_util.h"
 #include "ui/gfx/vsync_provider.h"
-#include "ui/gl/buildflags.h"
 #include "ui/gl/gl_surface_egl.h"
 #include "ui/ozone/common/egl_util.h"
 #include "ui/ozone/common/gl_ozone_egl.h"
@@ -175,11 +174,7 @@
 
 std::vector<gl::GLImplementation>
 HeadlessSurfaceFactory::GetAllowedGLImplementations() {
-  return std::vector<gl::GLImplementation> {
-#if BUILDFLAG(ENABLE_SWIFTSHADER)
-    gl::kGLImplementationSwiftShaderGL,
-#endif
-  };
+  return std::vector<gl::GLImplementation>{gl::kGLImplementationSwiftShaderGL};
 }
 
 GLOzone* HeadlessSurfaceFactory::GetGLOzone(
diff --git a/ui/ozone/platform/scenic/BUILD.gn b/ui/ozone/platform/scenic/BUILD.gn
index 8f7c11e..b630dc5 100644
--- a/ui/ozone/platform/scenic/BUILD.gn
+++ b/ui/ozone/platform/scenic/BUILD.gn
@@ -71,6 +71,7 @@
       "vulkan_implementation_scenic.h",
     ]
     defines += [ "VK_USE_PLATFORM_MAGMA_KHR" ]
+    deps += [ "//gpu/ipc/common:vulkan_ycbcr_info" ]
     data_deps += [
       "//third_party/angle:libEGL",
       "//third_party/angle:libGLESv2",
diff --git a/ui/ozone/platform/scenic/DEPS b/ui/ozone/platform/scenic/DEPS
index 627265fd..3befff0 100644
--- a/ui/ozone/platform/scenic/DEPS
+++ b/ui/ozone/platform/scenic/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
   "+mojo/public",
   "+third_party/skia/include",
+  "+gpu/ipc/common",
 ]
diff --git a/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc b/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc
index 1906792..37470d60 100644
--- a/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc
+++ b/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc
@@ -15,6 +15,7 @@
 #include "base/fuchsia/fuchsia_logging.h"
 #include "base/macros.h"
 #include "base/native_library.h"
+#include "gpu/ipc/common/vulkan_ycbcr_info.h"
 #include "gpu/vulkan/fuchsia/vulkan_fuchsia_ext.h"
 #include "gpu/vulkan/vulkan_function_pointers.h"
 #include "gpu/vulkan/vulkan_instance.h"
@@ -60,6 +61,7 @@
   std::vector<const char*> required_extensions = {
       VK_KHR_SURFACE_EXTENSION_NAME,
       VK_FUCHSIA_IMAGEPIPE_SURFACE_EXTENSION_NAME,
+      VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
   };
   std::vector<const char*> required_layers = {
       "VK_LAYER_FUCHSIA_imagepipe_swapchain",
@@ -124,8 +126,12 @@
       VK_FUCHSIA_BUFFER_COLLECTION_EXTENSION_NAME,
       VK_FUCHSIA_EXTERNAL_MEMORY_EXTENSION_NAME,
       VK_FUCHSIA_EXTERNAL_SEMAPHORE_EXTENSION_NAME,
+      VK_KHR_BIND_MEMORY_2_EXTENSION_NAME,
       VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,
       VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME,
+      VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME,
+      VK_KHR_MAINTENANCE1_EXTENSION_NAME,
+      VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME,
       VK_KHR_SWAPCHAIN_EXTENSION_NAME,
   };
 }
@@ -227,7 +233,8 @@
     VkImage* vk_image,
     VkImageCreateInfo* vk_image_info,
     VkDeviceMemory* vk_device_memory,
-    VkDeviceSize* mem_allocation_size) {
+    VkDeviceSize* mem_allocation_size,
+    base::Optional<gpu::VulkanYCbCrInfo>* ycbcr_info) {
   if (gmb_handle.type != gfx::NATIVE_PIXMAP)
     return false;
 
@@ -251,6 +258,9 @@
     return false;
   }
 
+  // TODO(crbug.com/981022): Initialize VulkanYCbCrInfo from the collection.
+  *ycbcr_info = base::nullopt;
+
   return collection->CreateVkImage(gmb_handle.native_pixmap_handle.buffer_index,
                                    vk_device, vk_image, vk_image_info,
                                    vk_device_memory, mem_allocation_size);
diff --git a/ui/ozone/platform/scenic/vulkan_implementation_scenic.h b/ui/ozone/platform/scenic/vulkan_implementation_scenic.h
index 4b15ee5f..fd22505 100644
--- a/ui/ozone/platform/scenic/vulkan_implementation_scenic.h
+++ b/ui/ozone/platform/scenic/vulkan_implementation_scenic.h
@@ -54,7 +54,8 @@
       VkImage* vk_image,
       VkImageCreateInfo* vk_image_info,
       VkDeviceMemory* vk_device_memory,
-      VkDeviceSize* mem_allocation_size) override;
+      VkDeviceSize* mem_allocation_size,
+      base::Optional<gpu::VulkanYCbCrInfo>* ycbcr_info) override;
 
  private:
   ScenicSurfaceFactory* const scenic_surface_factory_;
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc
index c578a96b..578b841 100644
--- a/ui/views/win/hwnd_message_handler.cc
+++ b/ui/views/win/hwnd_message_handler.cc
@@ -639,7 +639,7 @@
   if (!delegate_->HasFrame() && ui::win::IsAeroGlassEnabled() &&
       !is_translucent_) {
     MARGINS m = {0, 0, 0, 0};
-    if (state == DwmFrameState::ON)
+    if (state == DwmFrameState::kOn)
       m = {0, 0, 1, 0};
     DwmExtendFrameIntoClientArea(hwnd(), &m);
   }
@@ -2808,7 +2808,7 @@
   if (window_pos->flags & SWP_SHOWWINDOW) {
     delegate_->HandleVisibilityChanging(true);
   } else if (window_pos->flags & SWP_HIDEWINDOW) {
-    SetDwmFrameExtension(DwmFrameState::OFF);
+    SetDwmFrameExtension(DwmFrameState::kOff);
     delegate_->HandleVisibilityChanging(false);
   }
 
@@ -2819,10 +2819,10 @@
   if (DidClientAreaSizeChange(window_pos))
     ClientAreaSizeChanged();
   if (window_pos->flags & SWP_FRAMECHANGED)
-    SetDwmFrameExtension(DwmFrameState::ON);
+    SetDwmFrameExtension(DwmFrameState::kOn);
   if (window_pos->flags & SWP_SHOWWINDOW) {
     delegate_->HandleVisibilityChanged(true);
-    SetDwmFrameExtension(DwmFrameState::ON);
+    SetDwmFrameExtension(DwmFrameState::kOn);
   } else if (window_pos->flags & SWP_HIDEWINDOW) {
     delegate_->HandleVisibilityChanged(false);
   }
diff --git a/ui/views/win/hwnd_message_handler.h b/ui/views/win/hwnd_message_handler.h
index 3bccc5c..57bf686 100644
--- a/ui/views/win/hwnd_message_handler.h
+++ b/ui/views/win/hwnd_message_handler.h
@@ -192,7 +192,7 @@
   friend class ::views::test::DesktopWindowTreeHostWinTestApi;
 
   using TouchIDs = std::set<DWORD>;
-  enum class DwmFrameState { OFF, ON };
+  enum class DwmFrameState { kOff, kOn };
 
   // Overridden from WindowImpl:
   HICON GetDefaultWindowIcon() const override;