diff --git a/DEPS b/DEPS
index 197a0f29..036c602 100644
--- a/DEPS
+++ b/DEPS
@@ -142,11 +142,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': 'e192c4ce5a33829325ded5a03587605d892829b6',
+  'skia_revision': 'aee26ea14efc9bcbfa99fd2e3947dd59ca72bdea',
   # 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': 'f77a9153efb855ae59cfb17c3c4bd32f51c34857',
+  'v8_revision': '8bccdcf52f80f1308b967e916fe90fe5a7759699',
   # 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.
@@ -154,11 +154,11 @@
   # 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': 'a1b6761e6e3c55bb058ccd413d962a0a4ccfe12b',
+  'angle_revision': '3ffbaed656aeab3239a75edb69a1ae7ca7fdb458',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': '8900e7c54a223f97ca23c5a7853bcf331ab92b71',
+  'swiftshader_revision': '8c4c9e37bf96db64cbec5b7e26f12fc1af0b3e99',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -197,7 +197,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling HarfBuzz
   # and whatever else without interference from each other.
-  'harfbuzz_revision': '7185bd6ffb4dd8c0efebdab5b930e62c5695e3ab',
+  'harfbuzz_revision': '2e7021da7d1726a37822e6a001b9218f82255bc8',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Emoji Segmenter
   # and whatever else without interference from each other.
@@ -205,7 +205,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': 'dd686e35e94691afce7ca90eb70324ce5ba8bd82',
+  'catapult_revision': '0285f89eed34ed53cdd4f0d550acbbdfd7b3f7eb',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -277,7 +277,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '35716c204d2caebe01417bfec3750f5f63000229',
+  'dawn_revision': '6be313225eaae51e390fcc4db5aed12c4f306f89',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -806,7 +806,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'ca227ecc2bfd7582675b735b8ff81477cce26cac',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'c4ec2639c7ed67f8a2679e8ff478a27c9ac30893',
       'condition': 'checkout_linux',
   },
 
@@ -831,7 +831,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '92afaf53fddb7cb46ef7ee8d752521f6868be7d8',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '55dad64f46e8552be3c3c684b37196a73b3578e5',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1057,7 +1057,7 @@
   },
 
   'src/third_party/libjpeg_turbo':
-    Var('chromium_git') + '/chromium/deps/libjpeg_turbo.git' + '@' + 'e1669e3707c6448a01c8a0dc3e4b20976a4dacf3',
+    Var('chromium_git') + '/chromium/deps/libjpeg_turbo.git' + '@' + '76aabbd351eea8a5988a5672526eda0677f2048d',
 
   'src/third_party/liblouis/src': {
       'url': Var('chromium_git') + '/external/liblouis-github.git' + '@' + '97ce1c67fccbd3668291b7e63c06161c095d49f2',
@@ -1191,7 +1191,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  'c8e169dde402fc9130fd4585da3a4279ba30535c',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  'd8448ae7b07a4ff20e08b93da2954973d2ea35d4',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1359,7 +1359,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '91350f8ecf9ab2922ee062c114e4a759f24bd8d0',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '86f8b3bd5d29e790ae24e0c285fa501805529d62',
+    Var('webrtc_git') + '/src.git' + '@' + 'a0eefc17f7e81bb23cdaed0985136d42d9527e4f',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1400,7 +1400,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@25cf5a641d73fce8890b99b3fd6d4069e497f5bf',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@31aa7d39c69e0bdede9904318bc7ab2649870b3e',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/browser/aw_browser_context.cc b/android_webview/browser/aw_browser_context.cc
index c6a08f1f..d0246a0 100644
--- a/android_webview/browser/aw_browser_context.cc
+++ b/android_webview/browser/aw_browser_context.cc
@@ -264,8 +264,8 @@
                                auth_pref_callback);
   }
 
-  safe_browsing_ui_manager_ = new AwSafeBrowsingUIManager(
-      GetAwURLRequestContext(), user_pref_service_.get());
+  safe_browsing_ui_manager_ =
+      new AwSafeBrowsingUIManager(GetAwURLRequestContext());
   safe_browsing_trigger_manager_ =
       std::make_unique<safe_browsing::TriggerManager>(
           safe_browsing_ui_manager_.get(),
@@ -471,4 +471,9 @@
   enumerator->OnComplete(true);
 }
 
+void AwBrowserContext::SetExtendedReportingAllowed(bool allowed) {
+  user_pref_service_->SetBoolean(
+      ::prefs::kSafeBrowsingExtendedReportingOptInAllowed, allowed);
+}
+
 }  // namespace android_webview
diff --git a/android_webview/browser/aw_browser_context.h b/android_webview/browser/aw_browser_context.h
index 048b0ca..64eb1b5 100644
--- a/android_webview/browser/aw_browser_context.h
+++ b/android_webview/browser/aw_browser_context.h
@@ -143,6 +143,8 @@
 
   PrefService* GetPrefService() const { return user_pref_service_.get(); }
 
+  void SetExtendedReportingAllowed(bool allowed);
+
  private:
   void OnAuthPrefsChanged();
   void CreateUserPrefService();
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index ff5fc10..2e5797d7 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -769,7 +769,8 @@
         navigation_interception::InterceptNavigationDelegate::CreateThrottleFor(
             navigation_handle, navigation_interception::SynchronyMode::kSync));
     throttles.push_back(std::make_unique<PolicyBlacklistNavigationThrottle>(
-        navigation_handle, browser_context_.get()));
+        navigation_handle, AwBrowserContext::FromWebContents(
+                               navigation_handle->GetWebContents())));
   }
   return throttles;
 }
diff --git a/android_webview/browser/aw_contents_client_bridge_unittest.cc b/android_webview/browser/aw_contents_client_bridge_unittest.cc
index 8e6dce2d..0670b62b 100644
--- a/android_webview/browser/aw_contents_client_bridge_unittest.cc
+++ b/android_webview/browser/aw_contents_client_bridge_unittest.cc
@@ -88,7 +88,7 @@
   bridge_.reset(new AwContentsClientBridge(env_, jbridge_));
   selected_cert_ = nullptr;
   cert_selected_callbacks_ = 0;
-  cert_request_info_ = new net::SSLCertRequestInfo;
+  cert_request_info_ = base::MakeRefCounted<net::SSLCertRequestInfo>();
 }
 
 void AwContentsClientBridgeTest::CertSelected(
diff --git a/android_webview/browser/safe_browsing/aw_safe_browsing_blocking_page.cc b/android_webview/browser/safe_browsing/aw_safe_browsing_blocking_page.cc
index a6fbda8..18bb742 100644
--- a/android_webview/browser/safe_browsing/aw_safe_browsing_blocking_page.cc
+++ b/android_webview/browser/safe_browsing/aw_safe_browsing_blocking_page.cc
@@ -78,8 +78,7 @@
 // static
 void AwSafeBrowsingBlockingPage::ShowBlockingPage(
     AwSafeBrowsingUIManager* ui_manager,
-    const UnsafeResource& unsafe_resource,
-    PrefService* pref_service) {
+    const UnsafeResource& unsafe_resource) {
   DVLOG(1) << __func__ << " " << unsafe_resource.url.spec();
   WebContents* web_contents = unsafe_resource.web_contents_getter.Run();
 
@@ -95,11 +94,14 @@
     content::NavigationEntry* entry =
         unsafe_resource.GetNavigationEntryForResource();
     const UnsafeResourceList unsafe_resources{unsafe_resource};
+    AwBrowserContext* browser_context =
+        AwBrowserContext::FromWebContents(web_contents);
+    PrefService* pref_service = browser_context->GetPrefService();
     BaseSafeBrowsingErrorUI::SBErrorDisplayOptions display_options =
         BaseSafeBrowsingErrorUI::SBErrorDisplayOptions(
             IsMainPageLoadBlocked(unsafe_resources),
             safe_browsing::IsExtendedReportingOptInAllowed(*pref_service),
-            false,  // is_off_the_record
+            browser_context->IsOffTheRecord(),
             safe_browsing::IsExtendedReportingEnabled(*pref_service),
             safe_browsing::IsExtendedReportingPolicyManaged(*pref_service),
             pref_service->GetBoolean(
diff --git a/android_webview/browser/safe_browsing/aw_safe_browsing_blocking_page.h b/android_webview/browser/safe_browsing/aw_safe_browsing_blocking_page.h
index 28dae42..696ee44 100644
--- a/android_webview/browser/safe_browsing/aw_safe_browsing_blocking_page.h
+++ b/android_webview/browser/safe_browsing/aw_safe_browsing_blocking_page.h
@@ -8,8 +8,6 @@
 #include "components/safe_browsing/base_blocking_page.h"
 #include "components/security_interstitials/core/base_safe_browsing_error_ui.h"
 
-class PrefService;
-
 namespace security_interstitials {
 struct UnsafeResource;
 }  // namespace security_interstitials
@@ -23,8 +21,7 @@
   typedef security_interstitials::UnsafeResource UnsafeResource;
 
   static void ShowBlockingPage(AwSafeBrowsingUIManager* ui_manager,
-                               const UnsafeResource& unsafe_resource,
-                               PrefService* pref_service);
+                               const UnsafeResource& unsafe_resource);
 
  protected:
   // Used to specify which BaseSafeBrowsingErrorUI to instantiate, and
diff --git a/android_webview/browser/safe_browsing/aw_safe_browsing_ui_manager.cc b/android_webview/browser/safe_browsing/aw_safe_browsing_ui_manager.cc
index 89c8115..eda44e6 100644
--- a/android_webview/browser/safe_browsing/aw_safe_browsing_ui_manager.cc
+++ b/android_webview/browser/safe_browsing/aw_safe_browsing_ui_manager.cc
@@ -13,7 +13,6 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/path_service.h"
 #include "base/task/post_task.h"
-#include "components/prefs/pref_service.h"
 #include "components/safe_browsing/base_ui_manager.h"
 #include "components/safe_browsing/browser/safe_browsing_network_context.h"
 #include "components/safe_browsing/browser/safe_browsing_url_request_context_getter.h"
@@ -52,9 +51,7 @@
 }  // namespace
 
 AwSafeBrowsingUIManager::AwSafeBrowsingUIManager(
-    AwURLRequestContextGetter* browser_url_request_context_getter,
-    PrefService* pref_service)
-    : pref_service_(pref_service) {
+    AwURLRequestContextGetter* browser_url_request_context_getter) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   // TODO(timvolodine): verify this is what we want regarding the directory.
@@ -96,12 +93,7 @@
 
 void AwSafeBrowsingUIManager::ShowBlockingPageForResource(
     const UnsafeResource& resource) {
-  AwSafeBrowsingBlockingPage::ShowBlockingPage(this, resource, pref_service_);
-}
-
-void AwSafeBrowsingUIManager::SetExtendedReportingAllowed(bool allowed) {
-  pref_service_->SetBoolean(::prefs::kSafeBrowsingExtendedReportingOptInAllowed,
-                            allowed);
+  AwSafeBrowsingBlockingPage::ShowBlockingPage(this, resource);
 }
 
 scoped_refptr<network::SharedURLLoaderFactory>
diff --git a/android_webview/browser/safe_browsing/aw_safe_browsing_ui_manager.h b/android_webview/browser/safe_browsing/aw_safe_browsing_ui_manager.h
index b57ff34..7ca75bd 100644
--- a/android_webview/browser/safe_browsing/aw_safe_browsing_ui_manager.h
+++ b/android_webview/browser/safe_browsing/aw_safe_browsing_ui_manager.h
@@ -13,8 +13,6 @@
 #include "content/public/browser/web_contents.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 
-class PrefService;
-
 namespace network {
 class SharedURLLoaderFactory;
 }
@@ -43,8 +41,7 @@
 
   // Construction needs to happen on the UI thread.
   AwSafeBrowsingUIManager(
-      AwURLRequestContextGetter* browser_url_request_context_getter,
-      PrefService* pref_service);
+      AwURLRequestContextGetter* browser_url_request_context_getter);
 
   // Gets the correct ErrorUiType for the web contents
   int GetErrorUiType(const UnsafeResource& resource) const;
@@ -56,8 +53,6 @@
   // protocol buffer, so the service can send it over.
   void SendSerializedThreatDetails(const std::string& serialized) override;
 
-  void SetExtendedReportingAllowed(bool allowed);
-
   // Called on the IO thread to get a SharedURLLoaderFactory that can be used on
   // the IO thread.
   scoped_refptr<network::SharedURLLoaderFactory>
@@ -94,9 +89,6 @@
   scoped_refptr<network::WeakWrapperSharedURLLoaderFactory>
       shared_url_loader_factory_on_io_;
 
-  // non-owning
-  PrefService* pref_service_;
-
   DISALLOW_COPY_AND_ASSIGN(AwSafeBrowsingUIManager);
 };
 
diff --git a/android_webview/browser/safe_browsing/aw_url_checker_delegate_impl.cc b/android_webview/browser/safe_browsing/aw_url_checker_delegate_impl.cc
index dbb21a62..3789984 100644
--- a/android_webview/browser/safe_browsing/aw_url_checker_delegate_impl.cc
+++ b/android_webview/browser/safe_browsing/aw_url_checker_delegate_impl.cc
@@ -4,6 +4,7 @@
 
 #include "android_webview/browser/safe_browsing/aw_url_checker_delegate_impl.h"
 
+#include "android_webview/browser/aw_browser_context.h"
 #include "android_webview/browser/aw_contents_client_bridge.h"
 #include "android_webview/browser/aw_contents_io_thread_client.h"
 #include "android_webview/browser/net/aw_web_resource_request.h"
@@ -124,8 +125,13 @@
     const security_interstitials::UnsafeResource& resource,
     SafeBrowsingAction action,
     bool reporting) {
-  if (!reporting)
-    ui_manager->SetExtendedReportingAllowed(false);
+  content::WebContents* web_contents = resource.web_contents_getter.Run();
+
+  if (!reporting) {
+    AwBrowserContext* browser_context =
+        AwBrowserContext::FromWebContents(web_contents);
+    browser_context->SetExtendedReportingAllowed(false);
+  }
 
   // TODO(ntfschr): fully handle reporting once we add support (crbug/688629)
   bool proceed;
@@ -147,7 +153,6 @@
       NOTREACHED();
   }
 
-  content::WebContents* web_contents = resource.web_contents_getter.Run();
   content::NavigationEntry* entry = resource.GetNavigationEntryForResource();
   GURL main_frame_url = entry ? entry->GetURL() : GURL();
 
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index e03180a..68fe670 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -607,6 +607,8 @@
     "sticky_keys/sticky_keys_overlay.cc",
     "sticky_keys/sticky_keys_overlay.h",
     "sticky_keys/sticky_keys_state.h",
+    "style/ash_color_provider.cc",
+    "style/ash_color_provider.h",
     "system/accessibility/accessibility_feature_disable_dialog.cc",
     "system/accessibility/accessibility_feature_disable_dialog.h",
     "system/accessibility/accessibility_feature_pod_controller.cc",
diff --git a/ash/drag_drop/drag_drop_controller.cc b/ash/drag_drop/drag_drop_controller.cc
index c9bf89f..037ce398 100644
--- a/ash/drag_drop/drag_drop_controller.cc
+++ b/ash/drag_drop/drag_drop_controller.cc
@@ -127,8 +127,7 @@
 // DragDropController, public:
 
 DragDropController::DragDropController()
-    : drag_data_(NULL),
-      drag_operation_(0),
+    : drag_operation_(0),
       drag_window_(NULL),
       drag_source_window_(NULL),
       should_block_during_drag_drop_(true),
@@ -150,7 +149,7 @@
 }
 
 int DragDropController::StartDragAndDrop(
-    const ui::OSExchangeData& data,
+    std::unique_ptr<ui::OSExchangeData> data,
     aura::Window* root_window,
     aura::Window* source_window,
     const gfx::Point& screen_location,
@@ -159,7 +158,7 @@
   if (!enabled_ || IsDragDropInProgress())
     return 0;
 
-  const ui::OSExchangeData::Provider* provider = &data.provider();
+  const ui::OSExchangeData::Provider* provider = &data->provider();
   // We do not support touch drag/drop without a drag image.
   if (source == ui::DragDropTypes::DRAG_EVENT_SOURCE_TOUCH &&
       provider->GetDragImage().size().IsEmpty())
@@ -190,7 +189,7 @@
     drag_source_window_->AddObserver(this);
   pending_long_tap_.reset();
 
-  drag_data_ = &data;
+  drag_data_ = std::move(data);
   drag_operation_ = operation;
 
   float drag_image_scale = 1;
@@ -430,7 +429,7 @@
     aura::client::DragDropDelegate* delegate =
         aura::client::GetDragDropDelegate(drag_window_);
     if (delegate) {
-      ui::DropTargetEvent e(*drag_data_, event.location_f(),
+      ui::DropTargetEvent e(*drag_data_.get(), event.location_f(),
                             event.root_location_f(), drag_operation_);
       e.set_flags(event.flags());
       ui::Event::DispatcherApi(&e).set_target(target);
@@ -440,7 +439,7 @@
     aura::client::DragDropDelegate* delegate =
         aura::client::GetDragDropDelegate(drag_window_);
     if (delegate) {
-      ui::DropTargetEvent e(*drag_data_, event.location_f(),
+      ui::DropTargetEvent e(*drag_data_.get(), event.location_f(),
                             event.root_location_f(), drag_operation_);
       e.set_flags(event.flags());
       ui::Event::DispatcherApi(&e).set_target(target);
@@ -481,11 +480,11 @@
   aura::client::DragDropDelegate* delegate =
       aura::client::GetDragDropDelegate(target);
   if (delegate) {
-    ui::DropTargetEvent e(*drag_data_, event.location_f(),
+    ui::DropTargetEvent e(*drag_data_.get(), event.location_f(),
                           event.root_location_f(), drag_operation_);
     e.set_flags(event.flags());
     ui::Event::DispatcherApi(&e).set_target(target);
-    drag_operation_ = delegate->OnPerformDrop(e);
+    drag_operation_ = delegate->OnPerformDrop(e, std::move(drag_data_));
     if (drag_operation_ == 0)
       StartCanceledAnimation(kCancelAnimationDuration);
     else
@@ -587,7 +586,7 @@
   if (drag_window_)
     drag_window_->RemoveObserver(this);
   drag_window_ = NULL;
-  drag_data_ = NULL;
+  drag_data_.reset();
   // Cleanup can be called again while deleting DragDropTracker, so delete
   // the pointer with a local variable to avoid double free.
   std::unique_ptr<ash::DragDropTracker> holder = std::move(drag_drop_tracker_);
diff --git a/ash/drag_drop/drag_drop_controller.h b/ash/drag_drop/drag_drop_controller.h
index c5a2ee8..021559fb 100644
--- a/ash/drag_drop/drag_drop_controller.h
+++ b/ash/drag_drop/drag_drop_controller.h
@@ -51,7 +51,7 @@
   void set_enabled(bool enabled) { enabled_ = enabled; }
 
   // Overridden from aura::client::DragDropClient:
-  int StartDragAndDrop(const ui::OSExchangeData& data,
+  int StartDragAndDrop(std::unique_ptr<ui::OSExchangeData> data,
                        aura::Window* root_window,
                        aura::Window* source_window,
                        const gfx::Point& screen_location,
@@ -111,7 +111,7 @@
   bool enabled_ = false;
   std::unique_ptr<DragImageView> drag_image_;
   gfx::Vector2d drag_image_offset_;
-  const ui::OSExchangeData* drag_data_;
+  std::unique_ptr<ui::OSExchangeData> drag_data_;
   int drag_operation_;
 
   // Window that is currently under the drag cursor.
diff --git a/ash/drag_drop/drag_drop_controller_unittest.cc b/ash/drag_drop/drag_drop_controller_unittest.cc
index 7da49e70..a50ea9a 100644
--- a/ash/drag_drop/drag_drop_controller_unittest.cc
+++ b/ash/drag_drop/drag_drop_controller_unittest.cc
@@ -145,16 +145,17 @@
     drag_string_.clear();
   }
 
-  int StartDragAndDrop(const ui::OSExchangeData& data,
+  int StartDragAndDrop(std::unique_ptr<ui::OSExchangeData> data,
                        aura::Window* root_window,
                        aura::Window* source_window,
                        const gfx::Point& location,
                        int operation,
                        ui::DragDropTypes::DragEventSource source) override {
     drag_start_received_ = true;
-    data.GetString(&drag_string_);
-    return DragDropController::StartDragAndDrop(
-        data, root_window, source_window, location, operation, source);
+    data->GetString(&drag_string_);
+    return DragDropController::StartDragAndDrop(std::move(data), root_window,
+                                                source_window, location,
+                                                operation, source);
   }
 
   void DragUpdate(aura::Window* target,
@@ -247,7 +248,8 @@
     return ui::DragDropTypes::DRAG_MOVE;
   }
   void OnDragExited() override { ADD_FAILURE(); }
-  int OnPerformDrop(const ui::DropTargetEvent& event) override {
+  int OnPerformDrop(const ui::DropTargetEvent& event,
+                    std::unique_ptr<ui::OSExchangeData> data) override {
     EXPECT_EQ(State::kDragUpdateInvoked, state_);
     EXPECT_EQ(window_, event.target());
     state_ = State::kPerformDropInvoked;
@@ -310,8 +312,10 @@
     AshTestBase::TearDown();
   }
 
-  void UpdateDragData(ui::OSExchangeData* data) {
-    drag_drop_controller_->drag_data_ = data;
+  void UpdateDragData() {
+    drag_drop_controller_->drag_data_ = std::make_unique<ui::OSExchangeData>();
+    drag_drop_controller_->drag_data_->SetString(
+        base::UTF8ToUTF16("I am being dragged"));
   }
 
   aura::Window* GetDragWindow() { return drag_drop_controller_->drag_window_; }
@@ -365,8 +369,6 @@
   std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
   DragTestView* drag_view = new DragTestView;
   AddViewToWidgetAndResize(widget.get(), drag_view);
-  ui::OSExchangeData data;
-  data.SetString(base::UTF8ToUTF16("I am being dragged"));
   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
                                      widget->GetNativeView());
   generator.PressLeftButton();
@@ -376,9 +378,9 @@
     // Because we are not doing a blocking drag and drop, the original
     // OSDragExchangeData object is lost as soon as we return from the drag
     // initiation in DragDropController::StartDragAndDrop(). Hence we set the
-    // drag_data_ to a fake drag data object that we created.
+    // drag_data_ to a fake drag data object that we create.
     if (i > 0)
-      UpdateDragData(&data);
+      UpdateDragData();
     generator.MoveMouseBy(0, 1);
 
     // Execute any scheduled draws to process deferred mouse events.
@@ -406,8 +408,6 @@
   std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
   DragTestView* drag_view = new DragTestView;
   AddViewToWidgetAndResize(widget.get(), drag_view);
-  ui::OSExchangeData data;
-  data.SetString(base::UTF8ToUTF16("I am being dragged"));
   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
                                      widget->GetNativeView());
   generator.PressLeftButton();
@@ -417,13 +417,13 @@
     // Because we are not doing a blocking drag and drop, the original
     // OSDragExchangeData object is lost as soon as we return from the drag
     // initiation in DragDropController::StartDragAndDrop(). Hence we set the
-    // drag_data_ to a fake drag data object that we created.
+    // drag_data_ to a fake drag data object that we create.
     if (i > 0)
-      UpdateDragData(&data);
+      UpdateDragData();
     generator.MoveMouseBy(0, 1);
   }
 
-  UpdateDragData(&data);
+  UpdateDragData();
 
   generator.ReleaseLeftButton();
 
@@ -447,9 +447,6 @@
   DragTestView* drag_view2 = new DragTestView;
   AddViewToWidgetAndResize(widget.get(), drag_view2);
 
-  ui::OSExchangeData data;
-  data.SetString(base::UTF8ToUTF16("I am being dragged"));
-
   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
   generator.MoveMouseRelativeTo(widget->GetNativeView(),
                                 drag_view1->bounds().CenterPoint());
@@ -460,9 +457,9 @@
     // Because we are not doing a blocking drag and drop, the original
     // OSDragExchangeData object is lost as soon as we return from the drag
     // initiation in DragDropController::StartDragAndDrop(). Hence we set the
-    // drag_data_ to a fake drag data object that we created.
+    // drag_data_ to a fake drag data object that we create.
     if (i > 0)
-      UpdateDragData(&data);
+      UpdateDragData();
     generator.MoveMouseBy(1, 0);
 
     // Execute any scheduled draws to process deferred mouse events.
@@ -508,9 +505,6 @@
                                widget2_bounds.width(),
                                widget2_bounds.height()));
 
-  ui::OSExchangeData data;
-  data.SetString(base::UTF8ToUTF16("I am being dragged"));
-
   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
                                      widget1->GetNativeView());
   generator.PressLeftButton();
@@ -520,9 +514,9 @@
     // Because we are not doing a blocking drag and drop, the original
     // OSDragExchangeData object is lost as soon as we return from the drag
     // initiation in DragDropController::StartDragAndDrop(). Hence we set the
-    // drag_data_ to a fake drag data object that we created.
+    // drag_data_ to a fake drag data object that we create.
     if (i > 0)
-      UpdateDragData(&data);
+      UpdateDragData();
     generator.MoveMouseBy(1, 0);
 
     // Execute any scheduled draws to process deferred mouse events.
@@ -559,8 +553,6 @@
   std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
   std::unique_ptr<DragTestView> drag_view(new DragTestView);
   AddViewToWidgetAndResize(widget.get(), drag_view.get());
-  ui::OSExchangeData data;
-  data.SetString(base::UTF8ToUTF16("I am being dragged"));
 
   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
   generator.MoveMouseToCenterOf(widget->GetNativeView());
@@ -571,9 +563,9 @@
     // Because we are not doing a blocking drag and drop, the original
     // OSDragExchangeData object is lost as soon as we return from the drag
     // initiation in DragDropController::StartDragAndDrop(). Hence we set the
-    // drag_data_ to a fake drag data object that we created.
+    // drag_data_ to a fake drag data object that we create.
     if (i > 0)
-      UpdateDragData(&data);
+      UpdateDragData();
     generator.MoveMouseBy(0, 1);
 
     // Execute any scheduled draws to process deferred mouse events.
@@ -584,7 +576,7 @@
   // View has been removed. We will not get any of the following drag updates.
   int num_drags_2 = 23;
   for (int i = 0; i < num_drags_2; ++i) {
-    UpdateDragData(&data);
+    UpdateDragData();
     generator.MoveMouseBy(0, 1);
 
     // Execute any scheduled draws to process deferred mouse events.
@@ -625,10 +617,6 @@
 
   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
                                      widget->GetNativeView());
-  ui::OSExchangeData data;
-  std::string data_str("I am being dragged");
-  data.SetString(base::ASCIIToUTF16(data_str));
-
   generator.PressLeftButton();
   generator.MoveMouseBy(0, drag_view->VerticalDragThreshold() + 1);
 
@@ -652,8 +640,6 @@
   AddViewToWidgetAndResize(widget.get(), drag_view);
   aura::Window* window = widget->GetNativeView();
 
-  ui::OSExchangeData data;
-  data.SetString(base::UTF8ToUTF16("I am being dragged"));
   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
                                      widget->GetNativeView());
   generator.PressLeftButton();
@@ -663,9 +649,9 @@
     // Because we are not doing a blocking drag and drop, the original
     // OSDragExchangeData object is lost as soon as we return from the drag
     // initiation in DragDropController::StartDragAndDrop(). Hence we set the
-    // drag_data_ to a fake drag data object that we created.
+    // drag_data_ to a fake drag data object that we create.
     if (i > 0)
-      UpdateDragData(&data);
+      UpdateDragData();
     generator.MoveMouseBy(0, 1);
 
     // Execute any scheduled draws to process deferred mouse events.
@@ -681,7 +667,7 @@
   num_drags = 23;
   for (int i = 0; i < num_drags; ++i) {
     if (i > 0)
-      UpdateDragData(&data);
+      UpdateDragData();
     generator.MoveMouseBy(0, 1);
     // We should not crash here.
   }
@@ -696,8 +682,6 @@
   std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
   DragTestView* drag_view = new DragTestView;
   AddViewToWidgetAndResize(widget.get(), drag_view);
-  ui::OSExchangeData data;
-  data.SetString(base::UTF8ToUTF16("I am being dragged"));
   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
                                      widget->GetNativeView());
   generator.PressLeftButton();
@@ -707,9 +691,9 @@
     // Because we are not doing a blocking drag and drop, the original
     // OSDragExchangeData object is lost as soon as we return from the drag
     // initiation in DragDropController::StartDragAndDrop(). Hence we set the
-    // drag_data_ to a fake drag data object that we created.
+    // drag_data_ to a fake drag data object that we create.
     if (i > 0)
-      UpdateDragData(&data);
+      UpdateDragData();
     generator.MoveMouseBy(0, 1);
 
     // We send a unexpected mouse move event. Note that we cannot use
@@ -746,8 +730,6 @@
   std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
   DragTestView* drag_view = new DragTestView;
   AddViewToWidgetAndResize(widget.get(), drag_view);
-  ui::OSExchangeData data;
-  data.SetString(base::UTF8ToUTF16("I am being dragged"));
   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
                                      widget->GetNativeView());
   generator.PressLeftButton();
@@ -759,7 +741,7 @@
     // initiation in DragDropController::StartDragAndDrop(). Hence we set the
     // drag_data_ to a fake drag data object that we created.
     if (i > 0)
-      UpdateDragData(&data);
+      UpdateDragData();
     generator.MoveMouseBy(0, 1);
 
     // Execute any scheduled draws to process deferred mouse events.
@@ -788,8 +770,6 @@
   std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
   DragTestView* drag_view = new DragTestView;
   AddViewToWidgetAndResize(widget.get(), drag_view);
-  ui::OSExchangeData data;
-  data.SetString(base::UTF8ToUTF16("I am being dragged"));
   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
                                      widget->GetNativeView());
   generator.PressLeftButton();
@@ -799,9 +779,9 @@
     // Because we are not doing a blocking drag and drop, the original
     // OSDragExchangeData object is lost as soon as we return from the drag
     // initiation in DragDropController::StartDragAndDrop(). Hence we set the
-    // drag_data_ to a fake drag data object that we created.
+    // drag_data_ to a fake drag data object that we create.
     if (i > 0)
-      UpdateDragData(&data);
+      UpdateDragData();
     generator.MoveMouseBy(0, 1);
 
     // Execute any scheduled draws to process deferred mouse events.
@@ -847,9 +827,6 @@
                                widget2_bounds.width(),
                                widget2_bounds.height()));
 
-  ui::OSExchangeData data;
-  data.SetString(base::UTF8ToUTF16("I am being dragged"));
-
   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
                                      widget1->GetNativeView());
   generator.PressTouch();
@@ -858,8 +835,8 @@
   // Because we are not doing a blocking drag and drop, the original
   // OSDragExchangeData object is lost as soon as we return from the drag
   // initiation in DragDropController::StartDragAndDrop(). Hence we set the
-  // drag_data_ to a fake drag data object that we created.
-  UpdateDragData(&data);
+  // drag_data_ to a fake drag data object that we create.
+  UpdateDragData();
   gfx::Point gesture_location = point;
   int num_drags = drag_view1->width();
   for (int i = 0; i < num_drags; ++i) {
@@ -971,13 +948,13 @@
     aura::client::SetDragDropClient(*iter, drag_drop_controller_.get());
   }
 
-  ui::OSExchangeData data;
-  data.SetString(base::UTF8ToUTF16("I am being dragged"));
   {
+    auto data(std::make_unique<ui::OSExchangeData>());
+    data->SetString(base::UTF8ToUTF16("I am being dragged"));
     std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
     aura::Window* window = widget->GetNativeWindow();
     drag_drop_controller_->StartDragAndDrop(
-        data, window->GetRootWindow(), window, gfx::Point(5, 5),
+        std::move(data), window->GetRootWindow(), window, gfx::Point(5, 5),
         ui::DragDropTypes::DRAG_MOVE,
         ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
 
@@ -1005,10 +982,12 @@
   }
 
   {
+    auto data(std::make_unique<ui::OSExchangeData>());
+    data->SetString(base::UTF8ToUTF16("I am being dragged"));
     std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
     aura::Window* window = widget->GetNativeWindow();
     drag_drop_controller_->StartDragAndDrop(
-        data, window->GetRootWindow(), window, gfx::Point(405, 405),
+        std::move(data), window->GetRootWindow(), window, gfx::Point(405, 405),
         ui::DragDropTypes::DRAG_MOVE,
         ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
     DragImageWindowObserver observer;
@@ -1046,12 +1025,12 @@
     aura::client::SetDragDropClient(root, drag_drop_controller_.get());
   }
 
-  ui::OSExchangeData data;
-  data.SetString(base::UTF8ToUTF16("I am being dragged"));
+  auto data(std::make_unique<ui::OSExchangeData>());
+  data->SetString(base::UTF8ToUTF16("I am being dragged"));
   std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
   aura::Window* window = widget->GetNativeWindow();
   drag_drop_controller_->StartDragAndDrop(
-      data, window->GetRootWindow(), window, gfx::Point(5, 5),
+      std::move(data), window->GetRootWindow(), window, gfx::Point(5, 5),
       ui::DragDropTypes::DRAG_MOVE, ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
 
   // Start dragging.
@@ -1085,8 +1064,6 @@
   std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
   DragTestView* drag_view = new DragTestView;
   AddViewToWidgetAndResize(widget.get(), drag_view);
-  ui::OSExchangeData data;
-  data.SetString(base::UTF8ToUTF16("I am being dragged"));
   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
                                      widget->GetNativeView());
 
@@ -1101,7 +1078,7 @@
   generator.Dispatch(&press);
 
   DispatchGesture(ui::ET_GESTURE_LONG_PRESS, start);
-  UpdateDragData(&data);
+  UpdateDragData();
   timestamp += base::TimeDelta::FromMilliseconds(10);
   ui::TouchEvent move1(
       ui::ET_TOUCH_MOVED, mid, timestamp,
@@ -1136,13 +1113,13 @@
   TestObserver observer;
   drag_drop_controller_->AddObserver(&observer);
 
-  ui::OSExchangeData data;
-  data.SetString(base::UTF8ToUTF16("I am being dragged"));
   {
+    auto data(std::make_unique<ui::OSExchangeData>());
+    data->SetString(base::UTF8ToUTF16("I am being dragged"));
     std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
     aura::Window* window = widget->GetNativeWindow();
     drag_drop_controller_->StartDragAndDrop(
-        data, window->GetRootWindow(), window, gfx::Point(5, 5),
+        std::move(data), window->GetRootWindow(), window, gfx::Point(5, 5),
         ui::DragDropTypes::DRAG_MOVE,
         ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
 
@@ -1164,15 +1141,15 @@
   drag_drop_controller_->AddObserver(&observer);
 
   // Data for the drag.
-  ui::OSExchangeData data;
-  data.SetString(base::UTF8ToUTF16("I am being dragged"));
+  auto data(std::make_unique<ui::OSExchangeData>());
+  data->SetString(base::UTF8ToUTF16("I am being dragged"));
   std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
   aura::Window* window = widget->GetNativeWindow();
 
   // Cannot start a drag when the controller is disabled.
   drag_drop_controller_->set_enabled(false);
   drag_drop_controller_->StartDragAndDrop(
-      data, window->GetRootWindow(), window, gfx::Point(5, 5),
+      std::move(data), window->GetRootWindow(), window, gfx::Point(5, 5),
       ui::DragDropTypes::DRAG_MOVE, ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
   EXPECT_EQ(TestObserver::State::kNotInvoked, observer.state());
 
@@ -1203,10 +1180,10 @@
                                 base::Unretained(&generator)));
 
   drag_drop_controller_->set_should_block_during_drag_drop(true);
-  ui::OSExchangeData data;
-  data.SetString(base::UTF8ToUTF16("I am being dragged"));
+  auto data(std::make_unique<ui::OSExchangeData>());
+  data->SetString(base::UTF8ToUTF16("I am being dragged"));
   drag_drop_controller_->StartDragAndDrop(
-      data, window->GetRootWindow(), window.get(), gfx::Point(5, 5),
+      std::move(data), window->GetRootWindow(), window.get(), gfx::Point(5, 5),
       ui::DragDropTypes::DRAG_MOVE, ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
 
   EXPECT_EQ(EventTargetTestDelegate::State::kPerformDropInvoked,
diff --git a/ash/public/cpp/ash_switches.cc b/ash/public/cpp/ash_switches.cc
index 48a7efe..06ddd3a7 100644
--- a/ash/public/cpp/ash_switches.cc
+++ b/ash/public/cpp/ash_switches.cc
@@ -9,6 +9,12 @@
 namespace ash {
 namespace switches {
 
+// Indicates the current color mode of ash.
+const char kAshColorMode[] = "ash-color-mode";
+const char kAshColorModeDark[] = "dark";
+const char kAshColorModeDefault[] = "default";
+const char kAshColorModeLight[] = "light";
+
 // Force the pointer (cursor) position to be kept inside root windows.
 const char kAshConstrainPointerToRoot[] = "ash-constrain-pointer-to-root";
 
diff --git a/ash/public/cpp/ash_switches.h b/ash/public/cpp/ash_switches.h
index dace823..97b0e14 100644
--- a/ash/public/cpp/ash_switches.h
+++ b/ash/public/cpp/ash_switches.h
@@ -16,6 +16,10 @@
 
 // Please keep alphabetized.
 // TODO(sky): fix order!
+ASH_PUBLIC_EXPORT extern const char kAshColorMode[];
+ASH_PUBLIC_EXPORT extern const char kAshColorModeDark[];
+ASH_PUBLIC_EXPORT extern const char kAshColorModeDefault[];
+ASH_PUBLIC_EXPORT extern const char kAshColorModeLight[];
 ASH_PUBLIC_EXPORT extern const char kAshConstrainPointerToRoot[];
 ASH_PUBLIC_EXPORT extern const char kAshDebugShortcuts[];
 ASH_PUBLIC_EXPORT extern const char kAshDeveloperShortcuts[];
diff --git a/ash/shelf/login_shelf_view.cc b/ash/shelf/login_shelf_view.cc
index b5549d9..e899682f 100644
--- a/ash/shelf/login_shelf_view.cc
+++ b/ash/shelf/login_shelf_view.cc
@@ -227,6 +227,16 @@
       true /*can_close*/, EmptyAccountId() /*prefilled_account*/);
 }
 
+bool DialogStateGuestAllowed(OobeDialogState state) {
+  // Temp solution until https://crbug.com/981544 is fixed.
+  if (state == OobeDialogState::HIDDEN)
+    return true;
+
+  return state == OobeDialogState::NONE ||
+         state == OobeDialogState::GAIA_SIGNIN ||
+         state == OobeDialogState::ERROR;
+}
+
 }  // namespace
 
 class KioskAppsButton : public views::MenuButton,
@@ -651,29 +661,7 @@
   bool dialog_visible = dialog_state_ != OobeDialogState::HIDDEN;
   bool is_oobe = (session_state == SessionState::OOBE);
 
-  bool user_session_started =
-      Shell::Get()->session_controller()->NumberOfLoggedInUsers() != 0;
-
-  // Show guest button if:
-  // 1. It's in login screen or OOBE. Note: In OOBE, the guest button visibility
-  // is manually controlled by the WebUI.
-  // 2. Guest login is allowed.
-  // 3. OOBE UI dialog is not currently showing wrong HWID warning screen, SAML
-  // password confirmation screen or login UI provided by an extension.
-  // 4. OOBE UI dialog is not currently showing gaia signin screen, or if there
-  // are no user views available. If there are no user pods (i.e. Gaia is the
-  // only signin option), the guest button should be shown if allowed.
-  // 5. No users sessions have started. Button is hidden from all post login
-  // screens like sync consent, etc.
-  GetViewByID(kBrowseAsGuest)
-      ->SetVisible((is_login_primary || (is_oobe && allow_guest_in_oobe_)) &&
-                   allow_guest_ &&
-                   dialog_state_ != OobeDialogState::WRONG_HWID_WARNING &&
-                   dialog_state_ != OobeDialogState::SAML_PASSWORD_CONFIRM &&
-                   dialog_state_ != OobeDialogState::EXTENSION_LOGIN &&
-                   (dialog_state_ != OobeDialogState::GAIA_SIGNIN ||
-                    !login_screen_has_users_) &&
-                   !user_session_started);
+  GetViewByID(kBrowseAsGuest)->SetVisible(ShouldShowGuestButton());
 
   // Show add user button when it's in login screen and Oobe UI dialog is not
   // visible. The button should not appear if the device is not connected to a
@@ -730,4 +718,42 @@
   }
 }
 
+// Show guest button if:
+// 1. Guest login is allowed.
+// 2. OOBE UI dialog is currently showing the login UI or error.
+// 3. No users sessions have started. Button is hidden from all post login
+// screens like sync consent, etc.
+// 4. It's in login screen or OOBE. Note: In OOBE, the guest button visibility
+// is manually controlled by the WebUI.
+// 5. OOBE UI dialog is not currently showing gaia signin screen, or if there
+// are no user views available. If there are no user pods (i.e. Gaia is the
+// only signin option), the guest button should be shown if allowed by policy
+// and OOBE.
+bool LoginShelfView::ShouldShowGuestButton() const {
+  if (!allow_guest_)
+    return false;
+
+  if (!DialogStateGuestAllowed(dialog_state_))
+    return false;
+
+  const bool user_session_started =
+      Shell::Get()->session_controller()->NumberOfLoggedInUsers() != 0;
+  if (user_session_started)
+    return false;
+
+  const SessionState session_state =
+      Shell::Get()->session_controller()->GetSessionState();
+
+  if (session_state == SessionState::OOBE)
+    return allow_guest_in_oobe_;
+
+  if (session_state != SessionState::LOGIN_PRIMARY)
+    return false;
+
+  if (dialog_state_ == OobeDialogState::GAIA_SIGNIN)
+    return !login_screen_has_users_ && allow_guest_in_oobe_;
+
+  return true;
+}
+
 }  // namespace ash
diff --git a/ash/shelf/login_shelf_view.h b/ash/shelf/login_shelf_view.h
index 26ec6d1..3ed0d1ec 100644
--- a/ash/shelf/login_shelf_view.h
+++ b/ash/shelf/login_shelf_view.h
@@ -158,6 +158,8 @@
   // Updates the total bounds of all buttons.
   void UpdateButtonUnionBounds();
 
+  bool ShouldShowGuestButton() const;
+
   OobeDialogState dialog_state_ = OobeDialogState::HIDDEN;
   bool allow_guest_ = true;
   bool allow_guest_in_oobe_ = false;
diff --git a/ash/shelf/login_shelf_view_unittest.cc b/ash/shelf/login_shelf_view_unittest.cc
index 7dd1fbe..dec8849 100644
--- a/ash/shelf/login_shelf_view_unittest.cc
+++ b/ash/shelf/login_shelf_view_unittest.cc
@@ -371,7 +371,8 @@
 }
 
 TEST_F(LoginShelfViewTest, ShouldShowGuestButtonWhenNoUserPods) {
-  login_shelf_view_->SetAllowLoginAsGuest(true /*allow_guest*/);
+  login_shelf_view_->SetAllowLoginAsGuest(/*allow_guest=*/true);
+  login_shelf_view_->ShowGuestButtonInOobe(/*show=*/true);
   SetUserCount(0);
 
   NotifySessionStateChanged(SessionState::LOGIN_PRIMARY);
diff --git a/ash/shell.cc b/ash/shell.cc
index fbe68e5..a253384c 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -85,6 +85,7 @@
 #include "ash/shell_state.h"
 #include "ash/shutdown_controller_impl.h"
 #include "ash/sticky_keys/sticky_keys_controller.h"
+#include "ash/style/ash_color_provider.h"
 #include "ash/system/audio/display_speaker_controller.h"
 #include "ash/system/bluetooth/bluetooth_notification_controller.h"
 #include "ash/system/bluetooth/bluetooth_power_controller.h"
@@ -844,6 +845,8 @@
   // Destroys the MessageCenter singleton, so must happen late.
   message_center_controller_.reset();
 
+  ash_color_provider_.reset();
+
   shell_delegate_.reset();
 
   // Must be shut down after detachable_base_handler_.
@@ -1138,6 +1141,11 @@
 
   key_accessibility_enabler_ = std::make_unique<KeyAccessibilityEnabler>();
 
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kAshColorMode)) {
+    ash_color_provider_ = std::make_unique<AshColorProvider>();
+  }
+
   // The compositor thread and main message loop have to be running in
   // order to create mirror window. Run it after the main message loop
   // is started.
diff --git a/ash/shell.h b/ash/shell.h
index 9b0b814eb..4bedc0a 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -103,6 +103,7 @@
 class BluetoothNotificationController;
 class BluetoothPowerController;
 class BrightnessControlDelegate;
+class AshColorProvider;
 class CrosDisplayConfig;
 class DesksController;
 class DetachableBaseHandler;
@@ -506,10 +507,10 @@
   WindowTreeHostManager* window_tree_host_manager() {
     return window_tree_host_manager_.get();
   }
-
   ToplevelWindowEventHandler* toplevel_window_event_handler() {
     return toplevel_window_event_handler_.get();
   }
+  AshColorProvider* ash_color_provider() { return ash_color_provider_.get(); }
 
   PrefService* local_state() { return local_state_; }
 
@@ -799,6 +800,9 @@
   // volume keys.
   std::unique_ptr<KeyAccessibilityEnabler> key_accessibility_enabler_;
 
+  // Color provider for ash.
+  std::unique_ptr<AshColorProvider> ash_color_provider_;
+
   // For testing only: simulate that a modal window is open
   bool simulate_modal_window_open_for_test_ = false;
 
diff --git a/ash/style/ash_color_provider.cc b/ash/style/ash_color_provider.cc
new file mode 100644
index 0000000..f207157
--- /dev/null
+++ b/ash/style/ash_color_provider.cc
@@ -0,0 +1,128 @@
+// 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 "ash/style/ash_color_provider.h"
+
+#include "ash/public/cpp/ash_switches.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "ui/gfx/color_palette.h"
+
+namespace ash {
+
+namespace {
+
+// Colors for dark Shield layer with specific opacity.
+constexpr SkColor kDarkShieldAlpha20 = SkColorSetA(gfx::kGoogleGrey900, 0x33);
+constexpr SkColor kDarkShieldAlpha40 = SkColorSetA(gfx::kGoogleGrey900, 0x66);
+constexpr SkColor kDarkShieldAlpha60 = SkColorSetA(gfx::kGoogleGrey900, 0x99);
+
+// Colors for light Shield layer with specific opacity.
+constexpr SkColor kLightShieldAlpha20 = SkColorSetA(SK_ColorWHITE, 0x33);
+constexpr SkColor kLightShieldAlpha40 = SkColorSetA(SK_ColorWHITE, 0x66);
+constexpr SkColor kLightShieldAlpha60 = SkColorSetA(SK_ColorWHITE, 0x99);
+
+// Gets the color mode value from feature flag "--ash-color-mode".
+AshColorProvider::AshColorMode GetColorModeFromCommandLine() {
+  const base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
+
+  if (!cl->HasSwitch(switches::kAshColorMode))
+    return AshColorProvider::AshColorMode::kDefault;
+
+  const std::string switch_value =
+      cl->GetSwitchValueASCII(switches::kAshColorMode);
+  if (switch_value == switches::kAshColorModeDark)
+    return AshColorProvider::AshColorMode::kDark;
+
+  if (switch_value == switches::kAshColorModeLight)
+    return AshColorProvider::AshColorMode::kLight;
+
+  return AshColorProvider::AshColorMode::kDefault;
+}
+
+}  // namespace
+
+AshColorProvider::AshColorProvider()
+    : color_mode_(GetColorModeFromCommandLine()) {}
+
+AshColorProvider::~AshColorProvider() = default;
+
+SkColor AshColorProvider::GetShieldLayerColor(ShieldLayerType type) const {
+  SkColor light_color, dark_color;
+  switch (type) {
+    case ShieldLayerType::kAlpha20WithBlur:
+    case ShieldLayerType::kAlpha20WithoutBlur:
+      light_color = kLightShieldAlpha20;
+      dark_color = kDarkShieldAlpha20;
+      break;
+    case ShieldLayerType::kAlpha40WithBlur:
+    case ShieldLayerType::kAlpha40WithoutBlur:
+      light_color = kLightShieldAlpha40;
+      dark_color = kDarkShieldAlpha40;
+      break;
+    case ShieldLayerType::kAlpha60WithBlur:
+    case ShieldLayerType::kAlpha60WithoutBlur:
+      light_color = kLightShieldAlpha60;
+      dark_color = kDarkShieldAlpha60;
+      break;
+  }
+  return SelectColorOnMode(light_color, dark_color);
+}
+
+SkColor AshColorProvider::GetBaseLayerColor(BaseLayerType type) const {
+  SkColor light_color, dark_color;
+  switch (type) {
+    case BaseLayerType::kTransparentWithBlur:
+      light_color = SkColorSetA(SK_ColorWHITE, 0xC7);
+      dark_color = SkColorSetA(gfx::kGoogleGrey900, 0xC7);
+      break;
+    case BaseLayerType::kTransparentWithoutBlur:
+      light_color = SkColorSetA(SK_ColorWHITE, 0xE6);
+      dark_color = SkColorSetA(gfx::kGoogleGrey900, 0xE6);
+      break;
+    case BaseLayerType::kOpaque:
+      light_color = SK_ColorWHITE;
+      dark_color = gfx::kGoogleGrey900;
+      break;
+  }
+  return SelectColorOnMode(light_color, dark_color);
+}
+
+SkColor AshColorProvider::GetPlusOneLayerColor(PlusOneLayerType type) const {
+  SkColor light_color, dark_color;
+  switch (type) {
+    case PlusOneLayerType::kHairLine:
+      light_color = SkColorSetA(SK_ColorBLACK, 0x24);
+      dark_color = SkColorSetA(SK_ColorWHITE, 0x24);
+      break;
+    case PlusOneLayerType::kSeparator:
+      light_color = SkColorSetA(SK_ColorBLACK, 0x24);
+      dark_color = SkColorSetA(SK_ColorWHITE, 0x24);
+      break;
+    case PlusOneLayerType::kInActive:
+      light_color = SkColorSetA(SK_ColorBLACK, 0x0D);
+      dark_color = SkColorSetA(SK_ColorWHITE, 0x1A);
+      break;
+    case PlusOneLayerType::kActive:
+      light_color = gfx::kGoogleBlue600;
+      dark_color = gfx::kGoogleBlue300;
+      break;
+  }
+  return SelectColorOnMode(light_color, dark_color);
+}
+
+SkColor AshColorProvider::SelectColorOnMode(SkColor light_color,
+                                            SkColor dark_color) const {
+  if (color_mode_ == AshColorMode::kLight)
+    return light_color;
+  if (color_mode_ == AshColorMode::kDark)
+    return dark_color;
+
+  LOG(ERROR) << "Current color mode is AshColorMode::kDefault and should not "
+             << "retrieve color from AshColorProvider.";
+  return SK_ColorTRANSPARENT;
+}
+
+}  // namespace ash
diff --git a/ash/style/ash_color_provider.h b/ash/style/ash_color_provider.h
new file mode 100644
index 0000000..1b697db6
--- /dev/null
+++ b/ash/style/ash_color_provider.h
@@ -0,0 +1,113 @@
+// 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 ASH_STYLE_ASH_COLOR_PROVIDER_H_
+#define ASH_STYLE_ASH_COLOR_PROVIDER_H_
+
+#include "base/macros.h"
+#include "third_party/skia/include/core/SkColor.h"
+
+namespace ash {
+
+// The color provider for system UI. It provides colors for Shield layer, Base
+// layer and +1 layer. Shield layer is a combination of color, opacity and blur
+// which may change depending on the context, it is usually a fullscreen layer.
+// e.g, PowerButtoneMenuScreenView for power button menu. Base layer is the
+// bottom layer of any UI displayed on top of all other UIs. e.g, the ShelfView
+// that contains all the shelf items. +1 layer is where components such as icons
+// and inkdrops lay on, it may also indicate the state of an interactive
+// element (active/inactive states). The color of an element in system UI will
+// be the combination of the colors of the three layers.
+class AshColorProvider {
+ public:
+  // The color mode of system UI. It is controlled by the feature flag
+  // "--ash-color-mode" currently.
+  enum class AshColorMode {
+    // This is the color mode of current system UI, which is a combination of
+    // dark and light mode. e.g, shelf and system tray are dark while many other
+    // elements like notification are light.
+    kDefault = 0,
+    // The text is black while the background is white or light.
+    kLight,
+    // The text is light color while the background is black or dark grey.
+    kDark
+  };
+
+  // TODO(minch): To consider whether we should split this into two enums like
+  // ShieldOpacity and ShieldBlur.
+  // Types of Shield layer.
+  enum class ShieldLayerType {
+    // The layer has blur and opacity is 20%.
+    kAlpha20WithBlur,
+
+    // The layer has blur and opacity is 40%.
+    kAlpha40WithBlur,
+
+    // The layer has blur and opacity is 60%.
+    kAlpha60WithBlur,
+
+    // The layer doesn't have blur and opacity is 20%.
+    kAlpha20WithoutBlur,
+
+    // The layer doesn't have blur and opacity is 40%.
+    kAlpha40WithoutBlur,
+
+    // The layer doesn't have blur and opacity is 60%.
+    kAlpha60WithoutBlur,
+  };
+
+  // TODO(minch): Revise the names of these layers after their usage becomes
+  // clearer or discuss with PM/UX to suggest better names.
+  // Types of Base layer.
+  enum class BaseLayerType {
+    // Base layer is transparent with blur.
+    kTransparentWithBlur = 0,
+
+    // Base layer is transparent without blur.
+    kTransparentWithoutBlur,
+
+    // Base layer is opaque.
+    kOpaque,
+  };
+
+  // TODO(minch): Discuss with UX to check whether the grouping here is
+  // reasonable. e.g, `kSeparator` looks very odd here.
+  // Types of +1 layer.
+  enum class PlusOneLayerType {
+    // The +1 layer has a border with kHairLinePx thickness.
+    kHairLine = 0,
+
+    // The +1 layer is a separator, could be vertical or horizontal.
+    kSeparator,
+
+    // The state of the +1 layer is inactive or active. They will be served as a
+    // base for interactive layers, where ripple will be used as tap/touch
+    // feedback.
+    kInActive,
+    kActive,
+  };
+
+  AshColorProvider();
+  ~AshColorProvider();
+
+  // Gets the color of corresponding layer for specific type.
+  SkColor GetShieldLayerColor(ShieldLayerType type) const;
+  SkColor GetBaseLayerColor(BaseLayerType type) const;
+  SkColor GetPlusOneLayerColor(PlusOneLayerType type) const;
+
+  AshColorMode color_mode() const { return color_mode_; }
+
+ private:
+  // Selects from |light_color| and |dark_color| based on |color_mode_|.
+  SkColor SelectColorOnMode(SkColor light_color, SkColor dark_color) const;
+
+  // Current color mode of system UI.
+  AshColorMode color_mode_ = AshColorMode::kDefault;
+
+  DISALLOW_COPY_AND_ASSIGN(AshColorProvider);
+};
+
+}  // namespace ash
+
+#endif  // ASH_STYLE_ASH_COLOR_PROVIDER_H_
diff --git a/base/BUILD.gn b/base/BUILD.gn
index d76b55d..415fc69 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -622,6 +622,7 @@
     "profiler/native_unwinder_mac.h",
     "profiler/native_unwinder_win.cc",
     "profiler/native_unwinder_win.h",
+    "profiler/profile_builder.cc",
     "profiler/profile_builder.h",
     "profiler/register_context.h",
     "profiler/sample_metadata.cc",
@@ -3223,6 +3224,7 @@
       "android/java/src/org/chromium/base/compat/ApiHelperForO.java",
       "android/java/src/org/chromium/base/compat/ApiHelperForOMR1.java",
       "android/java/src/org/chromium/base/compat/ApiHelperForP.java",
+      "android/java/src/org/chromium/base/library_loader/LegacyLinker.java",
       "android/java/src/org/chromium/base/library_loader/LibraryLoader.java",
       "android/java/src/org/chromium/base/library_loader/LibraryPrefetcher.java",
       "android/java/src/org/chromium/base/library_loader/Linker.java",
diff --git a/base/android/java/src/org/chromium/base/library_loader/LegacyLinker.java b/base/android/java/src/org/chromium/base/library_loader/LegacyLinker.java
new file mode 100644
index 0000000..34e68634
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/library_loader/LegacyLinker.java
@@ -0,0 +1,561 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.library_loader;
+
+import android.annotation.SuppressLint;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.support.annotation.Nullable;
+
+import org.chromium.base.ContextUtils;
+import org.chromium.base.Log;
+import org.chromium.base.SysUtils;
+import org.chromium.base.annotations.JniIgnoreNatives;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.annotation.concurrent.GuardedBy;
+
+/*
+ * For more, see Technical note, Security considerations, and the explanation
+ * of how this class is supposed to be used in Linker.java.
+ */
+
+/**
+ * Provides a concrete implementation of the Chromium Linker.
+ *
+ * This Linker implementation uses the crazy linker to map and then run Chrome
+ * for Android.
+ *
+ * For more on the operations performed by the Linker, see {@link Linker}.
+ */
+@JniIgnoreNatives
+class LegacyLinker extends Linker {
+    // Log tag for this class.
+    private static final String TAG = "LegacyLinker";
+
+    // Becomes true after linker initialization.
+    private boolean mInitialized;
+
+    // Set to true if this runs in the browser process. Disabled by initServiceProcess().
+    private boolean mInBrowserProcess = true;
+
+    // Becomes true to indicate this process needs to wait for a shared RELRO in
+    // finishLibraryLoad().
+    private boolean mWaitForSharedRelros;
+
+    // Becomes true when initialization determines that the browser process can use the
+    // shared RELRO.
+    private boolean mBrowserUsesSharedRelro;
+
+    // The map of all RELRO sections either created or used in this process.
+    private Bundle mSharedRelros;
+
+    // Current common random base load address. A value of -1 indicates not yet initialized.
+    private long mBaseLoadAddress = -1;
+
+    // Current fixed-location load address for the next library called by loadLibrary().
+    // A value of -1 indicates not yet initialized.
+    private long mCurrentLoadAddress = -1;
+
+    // The map of libraries that are currently loaded in this process.
+    private HashMap<String, LibInfo> mLoadedLibraries;
+
+    LegacyLinker() {}
+
+    // Used internally to initialize the linker's data. Assumes lock is held.
+    // Loads JNI, and sets mMemoryDeviceConfig and mBrowserUsesSharedRelro.
+    @GuardedBy("sLock")
+    private void ensureInitializedLocked() {
+        assert Thread.holdsLock(sLock);
+
+        if (mInitialized) return;
+
+        // On first call, load libchromium_android_linker.so. Cannot be done in the
+        // constructor because instantiation occurs on the UI thread.
+        loadLinkerJniLibrary();
+
+        if (mMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_INIT) {
+            if (SysUtils.isLowEndDevice()) {
+                mMemoryDeviceConfig = MEMORY_DEVICE_CONFIG_LOW;
+            } else {
+                mMemoryDeviceConfig = MEMORY_DEVICE_CONFIG_NORMAL;
+            }
+        }
+
+        // Cannot run in the constructor because SysUtils.isLowEndDevice() relies
+        // on CommandLine, which may not be available at instantiation.
+        switch (BROWSER_SHARED_RELRO_CONFIG) {
+            case BROWSER_SHARED_RELRO_CONFIG_NEVER:
+                break;
+            case BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY:
+                if (mMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW) {
+                    mBrowserUsesSharedRelro = true;
+                    Log.w(TAG, "Low-memory device: shared RELROs used in all processes");
+                }
+                break;
+            case BROWSER_SHARED_RELRO_CONFIG_ALWAYS:
+                Log.w(TAG, "Beware: shared RELROs used in all processes!");
+                mBrowserUsesSharedRelro = true;
+                break;
+            default:
+                Log.wtf(TAG, "FATAL: illegal shared RELRO config");
+                throw new AssertionError();
+        }
+
+        mInitialized = true;
+    }
+
+    /**
+     * Call this method to determine if the linker will try to use shared RELROs
+     * for the browser process.
+     */
+    @Override
+    public boolean isUsingBrowserSharedRelros() {
+        synchronized (sLock) {
+            ensureInitializedLocked();
+            return mInBrowserProcess && mBrowserUsesSharedRelro;
+        }
+    }
+
+    /**
+     * Call this method just before loading any native shared libraries in this process.
+     */
+    @Override
+    public void prepareLibraryLoad(@Nullable String apkFilePath) {
+        if (DEBUG) Log.i(TAG, "prepareLibraryLoad() called");
+        synchronized (sLock) {
+            ensureInitializedLocked();
+            if (apkFilePath != null) {
+                nativeAddZipArchivePath(apkFilePath);
+            }
+
+            if (mInBrowserProcess) {
+                // Force generation of random base load address, as well
+                // as creation of shared RELRO sections in this process.
+                setupBaseLoadAddressLocked();
+            }
+        }
+    }
+
+    /**
+     * Call this method just after loading all native shared libraries in this process.
+     * Note that when in a service process, this will block until the RELRO bundle is
+     * received, i.e. when another thread calls useSharedRelros().
+     */
+    @Override
+    public void finishLibraryLoad() {
+        if (DEBUG) Log.i(TAG, "finishLibraryLoad() called");
+
+        synchronized (sLock) {
+            ensureInitializedLocked();
+            if (DEBUG) {
+                String message = String.format(Locale.US,
+                        "mInBrowserProcess=%b mBrowserUsesSharedRelro=%b mWaitForSharedRelros=%b",
+                        mInBrowserProcess, mBrowserUsesSharedRelro, mWaitForSharedRelros);
+                Log.i(TAG, message);
+            }
+
+            if (mLoadedLibraries == null) {
+                if (DEBUG) Log.i(TAG, "No libraries loaded");
+            } else {
+                if (mInBrowserProcess) {
+                    // Create new Bundle containing RELRO section information
+                    // for all loaded libraries. Make it available to getSharedRelros().
+                    mSharedRelros = createBundleFromLibInfoMap(mLoadedLibraries);
+                    if (DEBUG) {
+                        Log.i(TAG, "Shared RELRO created");
+                        dumpBundle(mSharedRelros);
+                    }
+
+                    if (mBrowserUsesSharedRelro) {
+                        useSharedRelrosLocked(mSharedRelros);
+                    }
+                }
+
+                if (mWaitForSharedRelros) {
+                    assert !mInBrowserProcess;
+
+                    // Wait until the shared relro bundle is received from useSharedRelros().
+                    while (mSharedRelros == null) {
+                        try {
+                            sLock.wait();
+                        } catch (InterruptedException ie) {
+                            // Restore the thread's interrupt status.
+                            Thread.currentThread().interrupt();
+                        }
+                    }
+                    useSharedRelrosLocked(mSharedRelros);
+                    // Clear the Bundle to ensure its file descriptor references can't be reused.
+                    mSharedRelros.clear();
+                    mSharedRelros = null;
+                }
+            }
+
+            // If testing, run tests now that all libraries are loaded and initialized.
+            if (NativeLibraries.sEnableLinkerTests) {
+                runTestRunnerClassForTesting(mMemoryDeviceConfig, mInBrowserProcess);
+            }
+        }
+        if (DEBUG) Log.i(TAG, "finishLibraryLoad() exiting");
+    }
+
+    /**
+     * Call this to send a Bundle containing the shared RELRO sections to be
+     * used in this process. If initServiceProcess() was previously called,
+     * finishLibraryLoad() will not exit until this method is called in another
+     * thread with a non-null value.
+     *
+     * @param bundle The Bundle instance containing a map of shared RELRO sections
+     * to use in this process.
+     */
+    @Override
+    public void useSharedRelros(Bundle bundle) {
+        // Ensure the bundle uses the application's class loader, not the framework
+        // one which doesn't know anything about LibInfo.
+        // Also, hold a fresh copy of it so the caller can't recycle it.
+        Bundle clonedBundle = null;
+        if (bundle != null) {
+            bundle.setClassLoader(LibInfo.class.getClassLoader());
+            clonedBundle = new Bundle(LibInfo.class.getClassLoader());
+            Parcel parcel = Parcel.obtain();
+            bundle.writeToParcel(parcel, 0);
+            parcel.setDataPosition(0);
+            clonedBundle.readFromParcel(parcel);
+            parcel.recycle();
+        }
+        if (DEBUG) Log.i(TAG, "useSharedRelros() called with %s, cloned %s", bundle, clonedBundle);
+        synchronized (sLock) {
+            // Note that in certain cases, this can be called before
+            // initServiceProcess() in service processes.
+            mSharedRelros = clonedBundle;
+            // Tell any listener blocked in finishLibraryLoad() about it.
+            sLock.notifyAll();
+        }
+    }
+
+    /**
+     * Call this to retrieve the shared RELRO sections created in this process,
+     * after loading all libraries.
+     *
+     * @return a new Bundle instance, or null if RELRO sharing is disabled on
+     * this system, or if initServiceProcess() was called previously.
+     */
+    @Override
+    public Bundle getSharedRelros() {
+        if (DEBUG) Log.i(TAG, "getSharedRelros() called");
+        synchronized (sLock) {
+            if (!mInBrowserProcess) {
+                if (DEBUG) Log.i(TAG, "... returning null Bundle");
+                return null;
+            }
+
+            // Return the Bundle created in finishLibraryLoad().
+            if (DEBUG) Log.i(TAG, "... returning %s", mSharedRelros);
+            return mSharedRelros;
+        }
+    }
+
+    /**
+     * Call this method before loading any libraries to indicate that this
+     * process shall neither create or reuse shared RELRO sections.
+     */
+    @Override
+    public void disableSharedRelros() {
+        if (DEBUG) Log.i(TAG, "disableSharedRelros() called");
+        synchronized (sLock) {
+            ensureInitializedLocked();
+            mInBrowserProcess = false;
+            mWaitForSharedRelros = false;
+            mBrowserUsesSharedRelro = false;
+        }
+    }
+
+    /**
+     * Call this method before loading any libraries to indicate that this
+     * process is ready to reuse shared RELRO sections from another one.
+     * Typically used when starting service processes.
+     *
+     * @param baseLoadAddress the base library load address to use.
+     */
+    @Override
+    public void initServiceProcess(long baseLoadAddress) {
+        if (DEBUG) {
+            Log.i(TAG,
+                    String.format(Locale.US, "initServiceProcess(0x%x) called", baseLoadAddress));
+        }
+        synchronized (sLock) {
+            ensureInitializedLocked();
+            mInBrowserProcess = false;
+            mBrowserUsesSharedRelro = false;
+            mWaitForSharedRelros = true;
+            mBaseLoadAddress = baseLoadAddress;
+            mCurrentLoadAddress = baseLoadAddress;
+        }
+    }
+
+    /**
+     * Retrieve the base load address of all shared RELRO sections.
+     * This also enforces the creation of shared RELRO sections in
+     * prepareLibraryLoad(), which can later be retrieved with getSharedRelros().
+     *
+     * @return a common, random base load address, or 0 if RELRO sharing is
+     * disabled.
+     */
+    @Override
+    public long getBaseLoadAddress() {
+        synchronized (sLock) {
+            ensureInitializedLocked();
+            if (!mInBrowserProcess) {
+                Log.w(TAG, "Shared RELRO sections are disabled in this process!");
+                return 0;
+            }
+
+            setupBaseLoadAddressLocked();
+            if (DEBUG) {
+                Log.i(TAG,
+                        String.format(
+                                Locale.US, "getBaseLoadAddress() returns 0x%x", mBaseLoadAddress));
+            }
+            return mBaseLoadAddress;
+        }
+    }
+
+    // Used internally to lazily setup the common random base load address.
+    @GuardedBy("sLock")
+    private void setupBaseLoadAddressLocked() {
+        if (mBaseLoadAddress == -1) {
+            mBaseLoadAddress = getRandomBaseLoadAddress();
+            mCurrentLoadAddress = mBaseLoadAddress;
+            if (mBaseLoadAddress == 0) {
+                // If the random address is 0 there are issues with finding enough
+                // free address space, so disable RELRO shared / fixed load addresses.
+                Log.w(TAG, "Disabling shared RELROs due address space pressure");
+                mBrowserUsesSharedRelro = false;
+                mWaitForSharedRelros = false;
+            }
+        }
+    }
+
+    // Used for debugging only.
+    private void dumpBundle(Bundle bundle) {
+        if (DEBUG) Log.i(TAG, "Bundle has " + bundle.size() + " items: " + bundle);
+    }
+
+    /**
+     * Use the shared RELRO section from a Bundle received form another process.
+     * Call this after calling setBaseLoadAddress() then loading all libraries
+     * with loadLibrary().
+     *
+     * @param bundle Bundle instance generated with createSharedRelroBundle() in
+     * another process.
+     */
+    @GuardedBy("sLock")
+    private void useSharedRelrosLocked(Bundle bundle) {
+        assert Thread.holdsLock(sLock);
+        if (DEBUG) Log.i(TAG, "Linker.useSharedRelrosLocked() called");
+
+        if (bundle == null) {
+            if (DEBUG) Log.i(TAG, "null bundle!");
+            return;
+        }
+
+        if (mLoadedLibraries == null) {
+            if (DEBUG) Log.i(TAG, "No libraries loaded!");
+            return;
+        }
+
+        if (DEBUG) dumpBundle(bundle);
+        HashMap<String, LibInfo> relroMap = createLibInfoMapFromBundle(bundle);
+
+        // Apply the RELRO section to all libraries that were already loaded.
+        for (Map.Entry<String, LibInfo> entry : relroMap.entrySet()) {
+            String libName = entry.getKey();
+            LibInfo libInfo = entry.getValue();
+            if (!nativeUseSharedRelro(libName, libInfo)) {
+                Log.w(TAG, "Could not use shared RELRO section for %s", libName);
+            } else {
+                if (DEBUG) Log.i(TAG, "Using shared RELRO section for %s", libName);
+            }
+        }
+
+        // In service processes, close all file descriptors from the map now.
+        if (!mInBrowserProcess) closeLibInfoMap(relroMap);
+
+        if (DEBUG) Log.i(TAG, "Linker.useSharedRelrosLocked() exiting");
+    }
+
+    /**
+     * Load the Linker JNI library. Throws UnsatisfiedLinkError on error.
+     */
+    @SuppressLint({"UnsafeDynamicallyLoadedCode"})
+    protected static void loadLinkerJniLibrary() {
+        LibraryLoader.setEnvForNative();
+        if (DEBUG) {
+            String libName = "lib" + LINKER_JNI_LIBRARY + ".so";
+            Log.i(TAG, "Loading %s", libName);
+        }
+        try {
+            System.loadLibrary(LINKER_JNI_LIBRARY);
+            LibraryLoader.incrementRelinkerCountNotHitHistogram();
+        } catch (UnsatisfiedLinkError e) {
+            if (LibraryLoader.PLATFORM_REQUIRES_NATIVE_FALLBACK_EXTRACTION) {
+                System.load(LibraryLoader.getExtractedLibraryPath(
+                        ContextUtils.getApplicationContext().getApplicationInfo(),
+                        LINKER_JNI_LIBRARY));
+                LibraryLoader.incrementRelinkerCountHitHistogram();
+            }
+        }
+    }
+
+    /**
+     * Implements loading a native shared library with the Chromium linker.
+     *
+     * Load a native shared library with the Chromium linker. If the zip file
+     * is not null, the shared library must be uncompressed and page aligned
+     * inside the zipfile. Note the crazy linker treats libraries and files as
+     * equivalent, so you can only open one library in a given zip file. The
+     * library must not be the Chromium linker library.
+     *
+     * @param libFilePath The path of the library (possibly in the zip file).
+     * @param isFixedAddressPermitted If true, uses a fixed load address if one was
+     * supplied, otherwise ignores the fixed address and loads wherever available.
+     */
+    @Override
+    void loadLibraryImpl(String libFilePath, boolean isFixedAddressPermitted) {
+        if (DEBUG) {
+            Log.i(TAG, "loadLibraryImpl: " + libFilePath + ", " + isFixedAddressPermitted);
+        }
+        synchronized (sLock) {
+            ensureInitializedLocked();
+
+            if (mLoadedLibraries == null) {
+                mLoadedLibraries = new HashMap<String, LibInfo>();
+            }
+
+            if (mLoadedLibraries.containsKey(libFilePath)) {
+                if (DEBUG) {
+                    Log.i(TAG, "Not loading " + libFilePath + " twice");
+                }
+                return;
+            }
+
+            LibInfo libInfo = new LibInfo();
+            long loadAddress = 0;
+            if (isFixedAddressPermitted) {
+                if ((mInBrowserProcess && mBrowserUsesSharedRelro) || mWaitForSharedRelros) {
+                    // Load the library at a fixed address.
+                    loadAddress = mCurrentLoadAddress;
+
+                    // For multiple libraries, ensure we stay within reservation range.
+                    if (loadAddress > mBaseLoadAddress + ADDRESS_SPACE_RESERVATION) {
+                        String errorMessage =
+                                "Load address outside reservation, for: " + libFilePath;
+                        Log.e(TAG, errorMessage);
+                        throw new UnsatisfiedLinkError(errorMessage);
+                    }
+                }
+            }
+
+            final String sharedRelRoName = libFilePath;
+            if (!nativeLoadLibrary(libFilePath, loadAddress, libInfo)) {
+                String errorMessage = "Unable to load library: " + libFilePath;
+                Log.e(TAG, errorMessage);
+                throw new UnsatisfiedLinkError(errorMessage);
+            }
+
+            // Print the load address to the logcat when testing the linker. The format
+            // of the string is expected by the Python test_runner script as one of:
+            //    BROWSER_LIBRARY_ADDRESS: <library-name> <address>
+            //    RENDERER_LIBRARY_ADDRESS: <library-name> <address>
+            // Where <library-name> is the library name, and <address> is the hexadecimal load
+            // address.
+            if (NativeLibraries.sEnableLinkerTests) {
+                String tag =
+                        mInBrowserProcess ? "BROWSER_LIBRARY_ADDRESS" : "RENDERER_LIBRARY_ADDRESS";
+                Log.i(TAG,
+                        String.format(
+                                Locale.US, "%s: %s %x", tag, libFilePath, libInfo.mLoadAddress));
+            }
+
+            if (mInBrowserProcess) {
+                // Create a new shared RELRO section at the 'current' fixed load address.
+                if (!nativeCreateSharedRelro(sharedRelRoName, mCurrentLoadAddress, libInfo)) {
+                    Log.w(TAG,
+                            String.format(Locale.US, "Could not create shared RELRO for %s at %x",
+                                    libFilePath, mCurrentLoadAddress));
+                } else {
+                    if (DEBUG) {
+                        Log.i(TAG,
+                                String.format(Locale.US, "Created shared RELRO for %s at %x: %s",
+                                        sharedRelRoName, mCurrentLoadAddress, libInfo.toString()));
+                    }
+                }
+            }
+
+            if (loadAddress != 0 && mCurrentLoadAddress != 0) {
+                // Compute the next current load address. If mCurrentLoadAddress
+                // is not 0, this is an explicit library load address. Otherwise,
+                // this is an explicit load address for relocated RELRO sections
+                // only.
+                mCurrentLoadAddress = libInfo.mLoadAddress + libInfo.mLoadSize;
+            }
+
+            mLoadedLibraries.put(sharedRelRoName, libInfo);
+            if (DEBUG) {
+                Log.i(TAG, "Library details " + libInfo.toString());
+            }
+        }
+    }
+
+    /**
+     * Native method used to load a library.
+     *
+     * @param library Platform specific library name (e.g. libfoo.so)
+     * @param loadAddress Explicit load address, or 0 for randomized one.
+     * @param libInfo If not null, the mLoadAddress and mLoadSize fields
+     * of this LibInfo instance will set on success.
+     * @return true for success, false otherwise.
+     */
+    private static native boolean nativeLoadLibrary(
+            String library, long loadAddress, LibInfo libInfo);
+
+    /**
+     * Native method used to add a zip archive or APK to the search path
+     * for native libraries. Allows loading directly from it.
+     *
+     * @param zipfilePath Path of the zip file containing the libraries.
+     * @return true for success, false otherwise.
+     */
+    private static native boolean nativeAddZipArchivePath(String zipFilePath);
+
+    /**
+     * Native method used to create a shared RELRO section.
+     * If the library was already loaded at the same address using
+     * nativeLoadLibrary(), this creates the RELRO for it. Otherwise,
+     * this loads a new temporary library at the specified address,
+     * creates and extracts the RELRO section from it, then unloads it.
+     *
+     * @param library Library name.
+     * @param loadAddress load address, which can be different from the one
+     * used to load the library in the current process!
+     * @param libInfo libInfo instance. On success, the mRelroStart, mRelroSize
+     * and mRelroFd will be set.
+     * @return true on success, false otherwise.
+     */
+    private static native boolean nativeCreateSharedRelro(
+            String library, long loadAddress, LibInfo libInfo);
+
+    /**
+     * Native method used to use a shared RELRO section.
+     *
+     * @param library Library name.
+     * @param libInfo A LibInfo instance containing valid RELRO information
+     * @return true on success.
+     */
+    private static native boolean nativeUseSharedRelro(String library, LibInfo libInfo);
+}
diff --git a/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java b/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
index 6f62095..9e5f0b8 100644
--- a/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
+++ b/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
@@ -423,7 +423,7 @@
 
                     // If the libraries are located in the zip file, assert that the device API
                     // level is M or higher. On devices lower than M, the libraries should
-                    // always be loaded by Linker.
+                    // always be loaded by LegacyLinker.
                     assert !isInZipFile() || Build.VERSION.SDK_INT >= VERSION_CODES.M;
 
                     // Load libraries using the system linker.
diff --git a/base/android/java/src/org/chromium/base/library_loader/Linker.java b/base/android/java/src/org/chromium/base/library_loader/Linker.java
index 68c42ef..bef217f 100644
--- a/base/android/java/src/org/chromium/base/library_loader/Linker.java
+++ b/base/android/java/src/org/chromium/base/library_loader/Linker.java
@@ -4,17 +4,14 @@
 
 package org.chromium.base.library_loader;
 
-import android.annotation.SuppressLint;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
 import android.support.annotation.Nullable;
 
-import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.StreamUtil;
-import org.chromium.base.SysUtils;
 import org.chromium.base.annotations.AccessedByNative;
 import org.chromium.base.annotations.JniIgnoreNatives;
 
@@ -148,12 +145,12 @@
  *    This method also ensures the process uses the shared RELROs.
  */
 @JniIgnoreNatives
-public class Linker {
+public abstract class Linker {
     // Log tag for this class.
     private static final String TAG = "LibraryLoader";
 
     // Name of the library that contains our JNI code.
-    private static final String LINKER_JNI_LIBRARY = "chromium_android_linker";
+    protected static final String LINKER_JNI_LIBRARY = "chromium_android_linker";
 
     // Constants used to control the behaviour of the browser process with
     // regards to the shared RELRO section.
@@ -183,7 +180,7 @@
     // Indicates if this is a low-memory device or not. The default is to
     // determine this by probing the system at runtime, but this can be forced
     // for testing by calling setMemoryDeviceConfigForTesting().
-    private int mMemoryDeviceConfig = MEMORY_DEVICE_CONFIG_INIT;
+    protected int mMemoryDeviceConfig = MEMORY_DEVICE_CONFIG_INIT;
 
     // Set to true to enable debug logs.
     protected static final boolean DEBUG = false;
@@ -192,9 +189,6 @@
     public static final String EXTRA_LINKER_SHARED_RELROS =
             "org.chromium.base.android.linker.shared_relros";
 
-    // Guards all access to the linker.
-    protected final Object mLock = new Object();
-
     // The name of a class that implements TestRunner.
     private String mTestRunnerClassName;
 
@@ -202,62 +196,36 @@
     // Should match the value of kAddressSpaceReservationSize on the JNI side.
     // Used when computing the load addresses of multiple loaded libraries to
     // ensure that we don't try to load outside the area originally requested.
-    private static final int ADDRESS_SPACE_RESERVATION = 192 * 1024 * 1024;
-
-    // Becomes true after linker initialization.
-    private boolean mInitialized;
-
-    // Set to true if this runs in the browser process. Disabled by initServiceProcess().
-    private boolean mInBrowserProcess = true;
-
-    // Becomes true to indicate this process needs to wait for a shared RELRO in
-    // finishLibraryLoad().
-    private boolean mWaitForSharedRelros;
-
-    // Becomes true when initialization determines that the browser process can use the
-    // shared RELRO.
-    private boolean mBrowserUsesSharedRelro;
-
-    // The map of all RELRO sections either created or used in this process.
-    private Bundle mSharedRelros;
-
-    // Current common random base load address. A value of -1 indicates not yet initialized.
-    private long mBaseLoadAddress = -1;
-
-    // Current fixed-location load address for the next library called by loadLibrary().
-    // A value of -1 indicates not yet initialized.
-    private long mCurrentLoadAddress = -1;
-
-    // Becomes true once prepareLibraryLoad() has been called.
-    private boolean mPrepareLibraryLoadCalled;
-
-    // The map of libraries that are currently loaded in this process.
-    private HashMap<String, LibInfo> mLoadedLibraries;
+    protected static final int ADDRESS_SPACE_RESERVATION = 192 * 1024 * 1024;
 
     // Singleton.
-    private static final Linker sSingleton = new Linker();
+    protected static final Object sLock = new Object();
+    private static Linker sSingleton;
 
-    // Private singleton constructor.
-    private Linker() {
-        // Ensure this class is not referenced unless it's used.
-        assert LibraryLoader.useCrazyLinker();
-    }
+    // Protected singleton constructor.
+    protected Linker() {}
 
     /**
-     * Get singleton instance. Returns a Linker.
+     * Get singleton instance. Returns a LegacyLinker.
      *
      * On N+ Monochrome is selected by Play Store. With Monochrome this code is not used, instead
      * Chrome asks the WebView to provide the library (and the shared RELRO). If the WebView fails
      * to provide the library, the system linker is used as a fallback.
      *
-     * Linker runs on all Android releases, but is incompatible with GVR library on N+.
-     * Linker is preferred on M- because it does not write the shared RELRO to disk at
+     * LegacyLinker runs on all Android releases, but is incompatible with GVR library on N+.
+     * LegacyLinker is preferred on M- because it does not write the shared RELRO to disk at
      * almost every cold startup.
      *
      * @return the Linker implementation instance.
      */
     public static Linker getInstance() {
-        return sSingleton;
+        synchronized (sLock) {
+            if (sSingleton == null) {
+                sSingleton = new LegacyLinker();
+                Log.i(TAG, "Using linker: LegacyLinker");
+            }
+            return sSingleton;
+        }
     }
 
     /**
@@ -312,7 +280,7 @@
         // Sanity check. This method may only be called during tests.
         assertLinkerTestsAreEnabled();
 
-        synchronized (mLock) {
+        synchronized (sLock) {
             return mTestRunnerClassName;
         }
     }
@@ -331,7 +299,7 @@
         // Sanity check. This method may only be called during tests.
         assertLinkerTestsAreEnabled();
 
-        synchronized (sSingleton) {
+        synchronized (sLock) {
             sSingleton.mTestRunnerClassName = testRunnerClassName;
         }
     }
@@ -341,10 +309,10 @@
      * must be instantiated _after_ all libraries are loaded to ensure that its
      * native methods are properly registered.
      *
-     * @param memoryDeviceConfig Linker memory config, or 0 if unused
+     * @param memoryDeviceConfig LegacyLinker memory config, or 0 if unused
      * @param inBrowserProcess true if in the browser process
      */
-    private final void runTestRunnerClassForTesting(
+    protected final void runTestRunnerClassForTesting(
             int memoryDeviceConfig, boolean inBrowserProcess) {
         if (DEBUG) {
             Log.i(TAG, "runTestRunnerClassForTesting called");
@@ -352,7 +320,7 @@
         // Sanity check. This method may only be called during tests.
         assertLinkerTestsAreEnabled();
 
-        synchronized (mLock) {
+        synchronized (sLock) {
             if (mTestRunnerClassName == null) {
                 Log.wtf(TAG, "Linker runtime tests not set up for this process");
                 assert false;
@@ -394,7 +362,7 @@
         assert memoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW
                 || memoryDeviceConfig == MEMORY_DEVICE_CONFIG_NORMAL;
 
-        synchronized (mLock) {
+        synchronized (sLock) {
             assert mMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_INIT;
 
             mMemoryDeviceConfig = memoryDeviceConfig;
@@ -419,34 +387,11 @@
     }
 
     /**
-     * Load the Linker JNI library. Throws UnsatisfiedLinkError on error.
-     */
-    @SuppressLint({"UnsafeDynamicallyLoadedCode"})
-    private static void loadLinkerJniLibrary() {
-        LibraryLoader.setEnvForNative();
-        if (DEBUG) {
-            String libName = "lib" + LINKER_JNI_LIBRARY + ".so";
-            Log.i(TAG, "Loading " + libName);
-        }
-        try {
-            System.loadLibrary(LINKER_JNI_LIBRARY);
-            LibraryLoader.incrementRelinkerCountNotHitHistogram();
-        } catch (UnsatisfiedLinkError e) {
-            if (LibraryLoader.PLATFORM_REQUIRES_NATIVE_FALLBACK_EXTRACTION) {
-                System.load(LibraryLoader.getExtractedLibraryPath(
-                        ContextUtils.getApplicationContext().getApplicationInfo(),
-                        LINKER_JNI_LIBRARY));
-                LibraryLoader.incrementRelinkerCountHitHistogram();
-            }
-        }
-    }
-
-    /**
      * Obtain a random base load address at which to place loaded libraries.
      *
      * @return new base load address
      */
-    private long getRandomBaseLoadAddress() {
+    protected long getRandomBaseLoadAddress() {
         // nativeGetRandomBaseLoadAddress() returns an address at which it has previously
         // successfully mapped an area larger than the largest library we expect to load,
         // on the basis that we will be able, with high probability, to map our library
@@ -500,154 +445,24 @@
         loadLibraryImpl(libFilePath, isFixedAddressPermitted);
     }
 
-    // Used internally to initialize the linker's data. Assumes lock is held.
-    // Loads JNI, and sets mMemoryDeviceConfig and mBrowserUsesSharedRelro.
-    private void ensureInitializedLocked() {
-        assert Thread.holdsLock(mLock);
-
-        if (mInitialized) {
-            return;
-        }
-
-        // On first call, load libchromium_android_linker.so. Cannot be done in the
-        // constructor because instantiation occurs on the UI thread.
-        loadLinkerJniLibrary();
-
-        if (mMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_INIT) {
-            if (SysUtils.isLowEndDevice()) {
-                mMemoryDeviceConfig = MEMORY_DEVICE_CONFIG_LOW;
-            } else {
-                mMemoryDeviceConfig = MEMORY_DEVICE_CONFIG_NORMAL;
-            }
-        }
-
-        // Cannot run in the constructor because SysUtils.isLowEndDevice() relies
-        // on CommandLine, which may not be available at instantiation.
-        switch (BROWSER_SHARED_RELRO_CONFIG) {
-            case BROWSER_SHARED_RELRO_CONFIG_NEVER:
-                mBrowserUsesSharedRelro = false;
-                break;
-            case BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY:
-                if (mMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW) {
-                    mBrowserUsesSharedRelro = true;
-                    Log.w(TAG, "Low-memory device: shared RELROs used in all processes");
-                } else {
-                    mBrowserUsesSharedRelro = false;
-                }
-                break;
-            case BROWSER_SHARED_RELRO_CONFIG_ALWAYS:
-                Log.w(TAG, "Beware: shared RELROs used in all processes!");
-                mBrowserUsesSharedRelro = true;
-                break;
-            default:
-                Log.wtf(TAG, "FATAL: illegal shared RELRO config");
-                throw new AssertionError();
-        }
-
-        mInitialized = true;
-    }
-
     /**
      * Call this method to determine if the linker will try to use shared RELROs
      * for the browser process.
      */
-    public boolean isUsingBrowserSharedRelros() {
-        synchronized (mLock) {
-            ensureInitializedLocked();
-            return mInBrowserProcess && mBrowserUsesSharedRelro;
-        }
-    }
+    public abstract boolean isUsingBrowserSharedRelros();
 
     /**
      * Call this method just before loading any native shared libraries in this process.
      *
-     * @param apkFilePath Optional current APK file path. If provided, the linker
+     * @param zipFilePath Optional current APK file path. If provided, the linker
      * will try to load libraries directly from it.
      */
-    public void prepareLibraryLoad(@Nullable String apkFilePath) {
-        if (DEBUG) {
-            Log.i(TAG, "prepareLibraryLoad() called");
-        }
-        synchronized (mLock) {
-            ensureInitializedLocked();
-            if (apkFilePath != null) {
-                nativeAddZipArchivePath(apkFilePath);
-            }
-            mPrepareLibraryLoadCalled = true;
-
-            if (mInBrowserProcess) {
-                // Force generation of random base load address, as well
-                // as creation of shared RELRO sections in this process.
-                setupBaseLoadAddressLocked();
-            }
-        }
-    }
+    abstract void prepareLibraryLoad(@Nullable String apkFilePath);
 
     /**
      * Call this method just after loading all native shared libraries in this process.
-     * Note that when in a service process, this will block until the RELRO bundle is
-     * received, i.e. when another thread calls useSharedRelros().
      */
-    void finishLibraryLoad() {
-        if (DEBUG) {
-            Log.i(TAG, "finishLibraryLoad() called");
-        }
-        synchronized (mLock) {
-            ensureInitializedLocked();
-            if (DEBUG) {
-                Log.i(TAG,
-                        String.format(Locale.US,
-                                "mInBrowserProcess=%b mBrowserUsesSharedRelro=%b mWaitForSharedRelros=%b",
-                                mInBrowserProcess, mBrowserUsesSharedRelro, mWaitForSharedRelros));
-            }
-
-            if (mLoadedLibraries == null) {
-                if (DEBUG) {
-                    Log.i(TAG, "No libraries loaded");
-                }
-            } else {
-                if (mInBrowserProcess) {
-                    // Create new Bundle containing RELRO section information
-                    // for all loaded libraries. Make it available to getSharedRelros().
-                    mSharedRelros = createBundleFromLibInfoMap(mLoadedLibraries);
-                    if (DEBUG) {
-                        Log.i(TAG, "Shared RELRO created");
-                        dumpBundle(mSharedRelros);
-                    }
-
-                    if (mBrowserUsesSharedRelro) {
-                        useSharedRelrosLocked(mSharedRelros);
-                    }
-                }
-
-                if (mWaitForSharedRelros) {
-                    assert !mInBrowserProcess;
-
-                    // Wait until the shared relro bundle is received from useSharedRelros().
-                    while (mSharedRelros == null) {
-                        try {
-                            mLock.wait();
-                        } catch (InterruptedException ie) {
-                            // Restore the thread's interrupt status.
-                            Thread.currentThread().interrupt();
-                        }
-                    }
-                    useSharedRelrosLocked(mSharedRelros);
-                    // Clear the Bundle to ensure its file descriptor references can't be reused.
-                    mSharedRelros.clear();
-                    mSharedRelros = null;
-                }
-            }
-
-            // If testing, run tests now that all libraries are loaded and initialized.
-            if (NativeLibraries.sEnableLinkerTests) {
-                runTestRunnerClassForTesting(mMemoryDeviceConfig, mInBrowserProcess);
-            }
-        }
-        if (DEBUG) {
-            Log.i(TAG, "finishLibraryLoad() exiting");
-        }
-    }
+    abstract void finishLibraryLoad();
 
     /**
      * Call this to send a Bundle containing the shared RELRO sections to be
@@ -658,31 +473,7 @@
      * @param bundle The Bundle instance containing a map of shared RELRO sections
      * to use in this process.
      */
-    public void useSharedRelros(Bundle bundle) {
-        // Ensure the bundle uses the application's class loader, not the framework
-        // one which doesn't know anything about LibInfo.
-        // Also, hold a fresh copy of it so the caller can't recycle it.
-        Bundle clonedBundle = null;
-        if (bundle != null) {
-            bundle.setClassLoader(LibInfo.class.getClassLoader());
-            clonedBundle = new Bundle(LibInfo.class.getClassLoader());
-            Parcel parcel = Parcel.obtain();
-            bundle.writeToParcel(parcel, 0);
-            parcel.setDataPosition(0);
-            clonedBundle.readFromParcel(parcel);
-            parcel.recycle();
-        }
-        if (DEBUG) {
-            Log.i(TAG, "useSharedRelros() called with " + bundle + ", cloned " + clonedBundle);
-        }
-        synchronized (mLock) {
-            // Note that in certain cases, this can be called before
-            // initServiceProcess() in service processes.
-            mSharedRelros = clonedBundle;
-            // Tell any listener blocked in finishLibraryLoad() about it.
-            mLock.notifyAll();
-        }
-    }
+    public abstract void useSharedRelros(Bundle bundle);
 
     /**
      * Call this to retrieve the shared RELRO sections created in this process,
@@ -691,41 +482,13 @@
      * @return a new Bundle instance, or null if RELRO sharing is disabled on
      * this system, or if initServiceProcess() was called previously.
      */
-    public Bundle getSharedRelros() {
-        if (DEBUG) {
-            Log.i(TAG, "getSharedRelros() called");
-        }
-        synchronized (mLock) {
-            if (!mInBrowserProcess) {
-                if (DEBUG) {
-                    Log.i(TAG, "... returning null Bundle");
-                }
-                return null;
-            }
-
-            // Return the Bundle created in finishLibraryLoad().
-            if (DEBUG) {
-                Log.i(TAG, "... returning " + mSharedRelros);
-            }
-            return mSharedRelros;
-        }
-    }
+    public abstract Bundle getSharedRelros();
 
     /**
      * Call this method before loading any libraries to indicate that this
      * process shall neither create or reuse shared RELRO sections.
      */
-    public void disableSharedRelros() {
-        if (DEBUG) {
-            Log.i(TAG, "disableSharedRelros() called");
-        }
-        synchronized (mLock) {
-            ensureInitializedLocked();
-            mInBrowserProcess = false;
-            mWaitForSharedRelros = false;
-            mBrowserUsesSharedRelro = false;
-        }
-    }
+    public abstract void disableSharedRelros();
 
     /**
      * Call this method before loading any libraries to indicate that this
@@ -734,20 +497,7 @@
      *
      * @param baseLoadAddress the base library load address to use.
      */
-    public void initServiceProcess(long baseLoadAddress) {
-        if (DEBUG) {
-            Log.i(TAG,
-                    String.format(Locale.US, "initServiceProcess(0x%x) called", baseLoadAddress));
-        }
-        synchronized (mLock) {
-            ensureInitializedLocked();
-            mInBrowserProcess = false;
-            mBrowserUsesSharedRelro = false;
-            mWaitForSharedRelros = true;
-            mBaseLoadAddress = baseLoadAddress;
-            mCurrentLoadAddress = baseLoadAddress;
-        }
-    }
+    public abstract void initServiceProcess(long baseLoadAddress);
 
     /**
      * Retrieve the base load address of all shared RELRO sections.
@@ -757,208 +507,16 @@
      * @return a common, random base load address, or 0 if RELRO sharing is
      * disabled.
      */
-    public long getBaseLoadAddress() {
-        synchronized (mLock) {
-            ensureInitializedLocked();
-            if (!mInBrowserProcess) {
-                Log.w(TAG, "Shared RELRO sections are disabled in this process!");
-                return 0;
-            }
-
-            setupBaseLoadAddressLocked();
-            if (DEBUG) {
-                Log.i(TAG,
-                        String.format(
-                                Locale.US, "getBaseLoadAddress() returns 0x%x", mBaseLoadAddress));
-            }
-            return mBaseLoadAddress;
-        }
-    }
-
-    // Used internally to lazily setup the common random base load address.
-    private void setupBaseLoadAddressLocked() {
-        assert Thread.holdsLock(mLock);
-        if (mBaseLoadAddress == -1) {
-            mBaseLoadAddress = getRandomBaseLoadAddress();
-            mCurrentLoadAddress = mBaseLoadAddress;
-            if (mBaseLoadAddress == 0) {
-                // If the random address is 0 there are issues with finding enough
-                // free address space, so disable RELRO shared / fixed load addresses.
-                Log.w(TAG, "Disabling shared RELROs due address space pressure");
-                mBrowserUsesSharedRelro = false;
-                mWaitForSharedRelros = false;
-            }
-        }
-    }
-
-    // Used for debugging only.
-    private void dumpBundle(Bundle bundle) {
-        if (DEBUG) {
-            Log.i(TAG, "Bundle has " + bundle.size() + " items: " + bundle);
-        }
-    }
-
-    /**
-     * Use the shared RELRO section from a Bundle received form another process.
-     * Call this after calling setBaseLoadAddress() then loading all libraries
-     * with loadLibrary().
-     *
-     * @param bundle Bundle instance generated with createSharedRelroBundle() in
-     * another process.
-     */
-    private void useSharedRelrosLocked(Bundle bundle) {
-        assert Thread.holdsLock(mLock);
-
-        if (DEBUG) {
-            Log.i(TAG, "Linker.useSharedRelrosLocked() called");
-        }
-
-        if (bundle == null) {
-            if (DEBUG) {
-                Log.i(TAG, "null bundle!");
-            }
-            return;
-        }
-
-        if (mLoadedLibraries == null) {
-            if (DEBUG) {
-                Log.i(TAG, "No libraries loaded!");
-            }
-            return;
-        }
-
-        if (DEBUG) {
-            dumpBundle(bundle);
-        }
-        HashMap<String, LibInfo> relroMap = createLibInfoMapFromBundle(bundle);
-
-        // Apply the RELRO section to all libraries that were already loaded.
-        for (Map.Entry<String, LibInfo> entry : relroMap.entrySet()) {
-            String libName = entry.getKey();
-            LibInfo libInfo = entry.getValue();
-            if (!nativeUseSharedRelro(libName, libInfo)) {
-                Log.w(TAG, "Could not use shared RELRO section for " + libName);
-            } else {
-                if (DEBUG) {
-                    Log.i(TAG, "Using shared RELRO section for " + libName);
-                }
-            }
-        }
-
-        // In service processes, close all file descriptors from the map now.
-        if (!mInBrowserProcess) {
-            closeLibInfoMap(relroMap);
-        }
-
-        if (DEBUG) {
-            Log.i(TAG, "Linker.useSharedRelrosLocked() exiting");
-        }
-    }
+    public abstract long getBaseLoadAddress();
 
     /**
      * Implements loading a native shared library with the Chromium linker.
      *
-     * Load a native shared library with the Chromium linker. If the zip file
-     * is not null, the shared library must be uncompressed and page aligned
-     * inside the zipfile. Note the crazy linker treats libraries and files as
-     * equivalent, so you can only open one library in a given zip file. The
-     * library must not be the Chromium linker library.
-     *
      * @param libFilePath The path of the library (possibly in the zip file).
      * @param isFixedAddressPermitted If true, uses a fixed load address if one was
      * supplied, otherwise ignores the fixed address and loads wherever available.
      */
-    void loadLibraryImpl(String libFilePath, boolean isFixedAddressPermitted) {
-        if (DEBUG) {
-            Log.i(TAG, "loadLibraryImpl: " + libFilePath + ", " + isFixedAddressPermitted);
-        }
-        synchronized (mLock) {
-            ensureInitializedLocked();
-
-            // Security: Ensure prepareLibraryLoad() was called before.
-            // In theory, this can be done lazily here, but it's more consistent
-            // to use a pair of functions (i.e. prepareLibraryLoad() + finishLibraryLoad())
-            // that wrap all calls to loadLibrary() in the library loader.
-            assert mPrepareLibraryLoadCalled;
-
-            if (mLoadedLibraries == null) {
-                mLoadedLibraries = new HashMap<String, LibInfo>();
-            }
-
-            if (mLoadedLibraries.containsKey(libFilePath)) {
-                if (DEBUG) {
-                    Log.i(TAG, "Not loading " + libFilePath + " twice");
-                }
-                return;
-            }
-
-            LibInfo libInfo = new LibInfo();
-            long loadAddress = 0;
-            if (isFixedAddressPermitted) {
-                if ((mInBrowserProcess && mBrowserUsesSharedRelro) || mWaitForSharedRelros) {
-                    // Load the library at a fixed address.
-                    loadAddress = mCurrentLoadAddress;
-
-                    // For multiple libraries, ensure we stay within reservation range.
-                    if (loadAddress > mBaseLoadAddress + ADDRESS_SPACE_RESERVATION) {
-                        String errorMessage =
-                                "Load address outside reservation, for: " + libFilePath;
-                        Log.e(TAG, errorMessage);
-                        throw new UnsatisfiedLinkError(errorMessage);
-                    }
-                }
-            }
-
-            final String sharedRelRoName = libFilePath;
-            if (!nativeLoadLibrary(libFilePath, loadAddress, libInfo)) {
-                String errorMessage = "Unable to load library: " + libFilePath;
-                Log.e(TAG, errorMessage);
-                throw new UnsatisfiedLinkError(errorMessage);
-            }
-
-            // Print the load address to the logcat when testing the linker. The format
-            // of the string is expected by the Python test_runner script as one of:
-            //    BROWSER_LIBRARY_ADDRESS: <library-name> <address>
-            //    RENDERER_LIBRARY_ADDRESS: <library-name> <address>
-            // Where <library-name> is the library name, and <address> is the hexadecimal load
-            // address.
-            if (NativeLibraries.sEnableLinkerTests) {
-                String tag =
-                        mInBrowserProcess ? "BROWSER_LIBRARY_ADDRESS" : "RENDERER_LIBRARY_ADDRESS";
-                Log.i(TAG,
-                        String.format(
-                                Locale.US, "%s: %s %x", tag, libFilePath, libInfo.mLoadAddress));
-            }
-
-            if (mInBrowserProcess) {
-                // Create a new shared RELRO section at the 'current' fixed load address.
-                if (!nativeCreateSharedRelro(sharedRelRoName, mCurrentLoadAddress, libInfo)) {
-                    Log.w(TAG,
-                            String.format(Locale.US, "Could not create shared RELRO for %s at %x",
-                                    libFilePath, mCurrentLoadAddress));
-                } else {
-                    if (DEBUG) {
-                        Log.i(TAG,
-                                String.format(Locale.US, "Created shared RELRO for %s at %x: %s",
-                                        sharedRelRoName, mCurrentLoadAddress, libInfo.toString()));
-                    }
-                }
-            }
-
-            if (loadAddress != 0 && mCurrentLoadAddress != 0) {
-                // Compute the next current load address. If mCurrentLoadAddress
-                // is not 0, this is an explicit library load address. Otherwise,
-                // this is an explicit load address for relocated RELRO sections
-                // only.
-                mCurrentLoadAddress = libInfo.mLoadAddress + libInfo.mLoadSize;
-            }
-
-            mLoadedLibraries.put(sharedRelRoName, libInfo);
-            if (DEBUG) {
-                Log.i(TAG, "Library details " + libInfo.toString());
-            }
-        }
-    }
+    abstract void loadLibraryImpl(String libFilePath, boolean isFixedAddressPermitted);
 
     /**
      * Record information for a given library.
@@ -966,7 +524,8 @@
      * don't change them without modifying the corresponding C++ sources.
      * Also, the LibInfo instance owns the shared RELRO file descriptor.
      */
-    private static class LibInfo implements Parcelable {
+    @JniIgnoreNatives
+    protected static class LibInfo implements Parcelable {
         LibInfo() {}
 
         // from Parcelable
@@ -1042,7 +601,7 @@
     }
 
     // Create a Bundle from a map of LibInfo objects.
-    private Bundle createBundleFromLibInfoMap(HashMap<String, LibInfo> map) {
+    protected Bundle createBundleFromLibInfoMap(HashMap<String, LibInfo> map) {
         Bundle bundle = new Bundle(map.size());
         for (Map.Entry<String, LibInfo> entry : map.entrySet()) {
             bundle.putParcelable(entry.getKey(), entry.getValue());
@@ -1051,7 +610,7 @@
     }
 
     // Create a new LibInfo map from a Bundle.
-    private HashMap<String, LibInfo> createLibInfoMapFromBundle(Bundle bundle) {
+    protected HashMap<String, LibInfo> createLibInfoMapFromBundle(Bundle bundle) {
         HashMap<String, LibInfo> map = new HashMap<String, LibInfo>();
         for (String library : bundle.keySet()) {
             LibInfo libInfo = bundle.getParcelable(library);
@@ -1061,60 +620,13 @@
     }
 
     // Call the close() method on all values of a LibInfo map.
-    private void closeLibInfoMap(HashMap<String, LibInfo> map) {
+    protected void closeLibInfoMap(HashMap<String, LibInfo> map) {
         for (Map.Entry<String, LibInfo> entry : map.entrySet()) {
             entry.getValue().close();
         }
     }
 
     /**
-     * Native method used to load a library.
-     *
-     * @param library Platform specific library name (e.g. libfoo.so)
-     * @param loadAddress Explicit load address, or 0 for randomized one.
-     * @param libInfo If not null, the mLoadAddress and mLoadSize fields
-     * of this LibInfo instance will set on success.
-     * @return true for success, false otherwise.
-     */
-    private static native boolean nativeLoadLibrary(
-            String library, long loadAddress, LibInfo libInfo);
-
-    /**
-     * Native method used to add a zip archive or APK to the search path
-     * for native libraries. Allows loading directly from it.
-     *
-     * @param zipfilePath Path of the zip file containing the libraries.
-     * @return true for success, false otherwise.
-     */
-    private static native boolean nativeAddZipArchivePath(String zipFilePath);
-
-    /**
-     * Native method used to create a shared RELRO section.
-     * If the library was already loaded at the same address using
-     * nativeLoadLibrary(), this creates the RELRO for it. Otherwise,
-     * this loads a new temporary library at the specified address,
-     * creates and extracts the RELRO section from it, then unloads it.
-     *
-     * @param library Library name.
-     * @param loadAddress load address, which can be different from the one
-     * used to load the library in the current process!
-     * @param libInfo libInfo instance. On success, the mRelroStart, mRelroSize
-     * and mRelroFd will be set.
-     * @return true on success, false otherwise.
-     */
-    private static native boolean nativeCreateSharedRelro(
-            String library, long loadAddress, LibInfo libInfo);
-
-    /**
-     * Native method used to use a shared RELRO section.
-     *
-     * @param library Library name.
-     * @param libInfo A LibInfo instance containing valid RELRO information
-     * @return true on success.
-     */
-    private static native boolean nativeUseSharedRelro(String library, LibInfo libInfo);
-
-    /**
      * Return a random address that should be free to be mapped with the given size.
      * Maps an area large enough for the largest library we might attempt to load,
      * and if successful then unmaps it and returns the address of the area allocated
diff --git a/base/android/linker/linker_jni.cc b/base/android/linker/linker_jni.cc
index 33a9591..15d2691 100644
--- a/base/android/linker/linker_jni.cc
+++ b/base/android/linker/linker_jni.cc
@@ -298,7 +298,7 @@
 // Add a zip archive file path to the context's current search path
 // list. Making it possible to load libraries directly from it.
 JNI_GENERATOR_EXPORT bool
-Java_org_chromium_base_library_1loader_Linker_nativeAddZipArchivePath(
+Java_org_chromium_base_library_1loader_LegacyLinker_nativeAddZipArchivePath(
     JNIEnv* env,
     jclass clazz,
     jstring apk_path_obj) {
@@ -327,7 +327,7 @@
 // with the Java side.
 // Return true on success.
 JNI_GENERATOR_EXPORT bool
-Java_org_chromium_base_library_1loader_Linker_nativeLoadLibrary(
+Java_org_chromium_base_library_1loader_LegacyLinker_nativeLoadLibrary(
     JNIEnv* env,
     jclass clazz,
     jstring lib_name_obj,
@@ -368,7 +368,7 @@
 }
 
 JNI_GENERATOR_EXPORT jboolean
-Java_org_chromium_base_library_1loader_Linker_nativeCreateSharedRelro(
+Java_org_chromium_base_library_1loader_LegacyLinker_nativeCreateSharedRelro(
     JNIEnv* env,
     jclass clazz,
     jstring library_name,
@@ -409,7 +409,7 @@
 }
 
 JNI_GENERATOR_EXPORT jboolean
-Java_org_chromium_base_library_1loader_Linker_nativeUseSharedRelro(
+Java_org_chromium_base_library_1loader_LegacyLinker_nativeUseSharedRelro(
     JNIEnv* env,
     jclass clazz,
     jstring library_name,
@@ -446,20 +446,19 @@
   return true;
 }
 
+// JNI_OnLoad() initialization hook.
 static bool LinkerJNIInit(JavaVM* vm, JNIEnv* env) {
-  LOG_INFO("Entering");
-
   // Find LibInfo field ids.
   LOG_INFO("Caching field IDs");
   if (!s_lib_info_fields.Init(env)) {
     return false;
   }
 
-  // Register native methods.
-  jclass linker_class;
-  if (!InitClassReference(env, "org/chromium/base/library_loader/Linker",
-                          &linker_class))
-    return false;
+  return true;
+}
+
+static bool LegacyLinkerJNIInit(JavaVM* vm, JNIEnv* env) {
+  LOG_INFO("Entering");
 
   // Save JavaVM* handle into linker, so that it can call JNI_OnLoad()
   // automatically when loading libraries containing JNI entry points.
@@ -481,7 +480,7 @@
   }
 
   // Initialize linker base and implementations.
-  if (!LinkerJNIInit(vm, env)) {
+  if (!LinkerJNIInit(vm, env) || !LegacyLinkerJNIInit(vm, env)) {
     return -1;
   }
 
diff --git a/base/profiler/metadata_recorder.cc b/base/profiler/metadata_recorder.cc
index baca29a..5783da8 100644
--- a/base/profiler/metadata_recorder.cc
+++ b/base/profiler/metadata_recorder.cc
@@ -21,20 +21,33 @@
 void MetadataRecorder::Set(uint64_t name_hash, int64_t value) {
   base::AutoLock lock(write_lock_);
 
-  // Acquiring the |write_lock_| guarantees that two simultaneous writes don't
-  // attempt to create items in the same slot. Use of memory_order_release
-  // guarantees that all writes performed by other threads to the metadata items
-  // will be seen by the time we reach this point.
+  // Acquiring the |write_lock_| ensures that:
+  //
+  //   - We don't try to write into the same new slot at the same time as
+  //     another thread
+  //   - We see all writes by other threads (acquiring a mutex implies acquire
+  //     semantics)
   size_t item_slots_used = item_slots_used_.load(std::memory_order_relaxed);
   for (size_t i = 0; i < item_slots_used; ++i) {
     auto& item = items_[i];
     if (item.name_hash == name_hash) {
       item.value.store(value, std::memory_order_relaxed);
-      item.is_active.store(true, std::memory_order_release);
+
+      const bool was_active =
+          item.is_active.exchange(true, std::memory_order_release);
+      if (!was_active)
+        inactive_item_count_--;
+
       return;
     }
   }
 
+  item_slots_used = TryReclaimInactiveSlots(item_slots_used);
+
+  // TODO(charliea): Add an UMA histogram to track the number of occupied
+  // metadata slots.
+  // See: https://crbug.com/980308
+
   // There should always be room in this data structure because there are more
   // reserved slots than there are unique metadata names in Chromium.
   DCHECK_NE(item_slots_used, items_.size())
@@ -44,7 +57,7 @@
   // Wait until the item is fully created before setting |is_active| to true and
   // incrementing |item_slots_used_|, which will signal to readers that the item
   // is ready.
-  auto& item = items_[item_slots_used_];
+  auto& item = items_[item_slots_used];
   item.name_hash = name_hash;
   item.value.store(value, std::memory_order_relaxed);
   item.is_active.store(true, std::memory_order_release);
@@ -58,16 +71,45 @@
   for (size_t i = 0; i < item_slots_used; ++i) {
     auto& item = items_[i];
     if (item.name_hash == name_hash) {
-      // A removed item will occupy its slot indefinitely.
-      item.is_active.store(false, std::memory_order_release);
+      // A removed item will occupy its slot until that slot is reclaimed.
+      const bool was_active =
+          item.is_active.exchange(false, std::memory_order_relaxed);
+      if (was_active)
+        inactive_item_count_++;
+
+      return;
     }
   }
 }
 
-size_t MetadataRecorder::GetItems(ItemArray* const items) const {
-  // TODO(charliea): Defragment the item array if we can successfully acquire
-  // the write lock here. This will require either making this function
-  // non-const or |items_| mutable.
+MetadataRecorder::ScopedGetItems::ScopedGetItems(
+    MetadataRecorder* metadata_recorder)
+    : metadata_recorder_(metadata_recorder),
+      auto_lock_(std::make_unique<AutoLock>(metadata_recorder->read_lock_)) {}
+
+MetadataRecorder::ScopedGetItems::~ScopedGetItems() {}
+
+size_t MetadataRecorder::ScopedGetItems::GetItems(
+    ProfileBuilder::MetadataItemArray* const items) {
+  if (!auto_lock_) {
+    NOTREACHED()
+        << "GetItems() can only be called once on each ScopedGetItems "
+           "instance because the read lock is released when it is called.";
+  }
+
+  size_t item_count = metadata_recorder_->GetItems(items);
+  auto_lock_.reset();
+  return item_count;
+}
+
+std::unique_ptr<ProfileBuilder::MetadataProvider>
+MetadataRecorder::CreateMetadataProvider() {
+  return std::make_unique<MetadataRecorder::ScopedGetItems>(this);
+}
+
+size_t MetadataRecorder::GetItems(
+    ProfileBuilder::MetadataItemArray* const items) const {
+  read_lock_.AssertAcquired();
 
   // If a writer adds a new item after this load, it will be ignored.  We do
   // this instead of calling item_slots_used_.load() explicitly in the for loop
@@ -87,12 +129,75 @@
     // Because we wait until |is_active| is set to consider an item active and
     // that field is always set last, we ignore half-created items.
     if (item.is_active.load(std::memory_order_acquire)) {
-      (*items)[write_index++] =
-          Item{item.name_hash, item.value.load(std::memory_order_relaxed)};
+      (*items)[write_index++] = ProfileBuilder::MetadataItem{
+          item.name_hash, item.value.load(std::memory_order_relaxed)};
     }
   }
 
   return write_index;
 }
 
+size_t MetadataRecorder::TryReclaimInactiveSlots(size_t item_slots_used) {
+  const size_t remaining_slots =
+      ProfileBuilder::MAX_METADATA_COUNT - item_slots_used;
+
+  if (inactive_item_count_ == 0 || inactive_item_count_ < remaining_slots) {
+    // This reclaiming threshold has a few nice properties:
+    //
+    //   - It avoids reclaiming when no items have been removed
+    //   - It makes doing so more likely as free slots become more scarce
+    //   - It makes doing so less likely when the benefits are lower
+    return item_slots_used;
+  }
+
+  if (read_lock_.Try()) {
+    // The lock isn't already held by a reader or another thread reclaiming
+    // slots.
+    item_slots_used = ReclaimInactiveSlots(item_slots_used);
+    read_lock_.Release();
+  }
+
+  return item_slots_used;
+}
+
+size_t MetadataRecorder::ReclaimInactiveSlots(size_t item_slots_used) {
+  // From here until the end of the reclamation, we can safely use
+  // memory_order_relaxed for all reads and writes. We don't need
+  // memory_order_acquire because acquiring the write mutex gives acquire
+  // semantics and no other threads can write after we hold that mutex. We don't
+  // need memory_order_release because no readers can read until we release the
+  // read mutex, which itself has release semantics.
+  size_t first_inactive_item_idx = 0;
+  size_t last_active_item_idx = item_slots_used - 1;
+  while (first_inactive_item_idx < last_active_item_idx) {
+    ItemInternal& inactive_item = items_[first_inactive_item_idx];
+    ItemInternal& active_item = items_[last_active_item_idx];
+
+    if (inactive_item.is_active.load(std::memory_order_relaxed)) {
+      // Keep seeking forward to an inactive item.
+      ++first_inactive_item_idx;
+      continue;
+    }
+
+    if (!active_item.is_active.load(std::memory_order_relaxed)) {
+      // Keep seeking backward to an active item. Skipping over this item
+      // indicates that we're freeing the slot at this index.
+      --last_active_item_idx;
+      item_slots_used--;
+      continue;
+    }
+
+    inactive_item.name_hash = active_item.name_hash;
+    inactive_item.value.store(active_item.value.load(std::memory_order_relaxed),
+                              std::memory_order_relaxed);
+    inactive_item.is_active.store(true, std::memory_order_relaxed);
+
+    ++first_inactive_item_idx;
+    --last_active_item_idx;
+    item_slots_used--;
+  }
+
+  item_slots_used_.store(item_slots_used, std::memory_order_relaxed);
+  return item_slots_used;
+}
 }  // namespace base
diff --git a/base/profiler/metadata_recorder.h b/base/profiler/metadata_recorder.h
index 346a5a1..5b50786 100644
--- a/base/profiler/metadata_recorder.h
+++ b/base/profiler/metadata_recorder.h
@@ -9,7 +9,9 @@
 #include <atomic>
 #include <utility>
 
+#include "base/profiler/profile_builder.h"
 #include "base/synchronization/lock.h"
+#include "base/thread_annotations.h"
 
 namespace base {
 
@@ -19,6 +21,105 @@
 // with the sample.
 //
 // Methods on this class are safe to call unsynchronized from arbitrary threads.
+//
+// This class was designed to read metadata from a single sampling thread and
+// write metadata from many Chrome threads within the same process. These other
+// threads might be suspended by the sampling thread at any time in order to
+// collect a sample.
+//
+// This class has a few notable constraints:
+//
+// A) If a lock that's required to read the metadata might be held while writing
+//    the metadata, that lock must be acquirable *before* the thread is
+//    suspended. Otherwise, the sampling thread might suspend the target thread
+//    while it is holding the required lock, causing deadlock.
+//
+//      Ramifications:
+//
+//      - When retrieving items, lock acquisition (through
+//        CreateMetadataProvider()) and actual item retrieval (through
+//        MetadataProvider::GetItems()) are separate.
+//
+// B) We can't allocate data on the heap while reading the metadata items. This
+//    is because, on many operating systems, there's a process-wide heap lock
+//    that is held while allocating on the heap. If a thread is suspended while
+//    holding this lock and the sampling thread then tries to allocate on the
+//    heap to read the metadata, it will deadlock trying to acquire the heap
+//    lock.
+//
+//      Ramifications:
+//
+//      - We hold and retrieve the metadata using a fixed-size array, which
+//        allows readers to preallocate the data structure that we pass back
+//        the metadata in.
+//
+// C) We shouldn't guard writes with a lock that also guards reads. It can take
+//    ~30us from the time that the sampling thread requests that a thread be
+//    suspended and the time that it actually happens. If all metadata writes
+//    block their thread during that time, we're very likely to block all Chrome
+//    threads for an additional 30us per sample.
+//
+//      Ramifications:
+//
+//      - We use two locks to guard the metadata: a read lock and a write
+//        lock. Only the write lock is required to write into the metadata, and
+//        only the read lock is required to read the metadata.
+//
+//      - Because we can't guard reads and writes with the same lock, we have to
+//        face the possibility of writes occurring during a read. This is
+//        especially problematic because there's no way to read both the key and
+//        value for an item atomically without using mutexes, which violates
+//        constraint A). If the sampling thread were to see the following
+//        interleaving of reads and writes:
+//
+//          * Reader thread reads key for slot 0
+//          * Writer thread removes item at slot 0
+//          * Writer thread creates new item with different key in slot 0
+//          * Reader thread reads value for slot 0
+//
+//        then the reader would see an invalid value for the given key. Because
+//        of this possibility, we keep slots reserved for a specific key even
+//        after that item has been removed. We reclaim these slots on a
+//        best-effort basis during writes when the metadata recorder has become
+//        sufficiently full and we can acquire the read lock.
+//
+//      - We use state stored in atomic data types to ensure that readers and
+//        writers are synchronized about where data should be written to and
+//        read from. We must use atomic data types to guarantee that there's no
+//        instruction during a write after which the recorder is in an
+//        inconsistent state that might yield garbage data for a reader.
+//
+// Here are a few of the many states the recorder can be in:
+//
+// - No thread is using the recorder.
+//
+// - A single writer is writing into the recorder without a simultaneous
+//   read. The write will succeed.
+//
+// - A reader is reading from the recorder without a simultaneous write. The
+//   read will succeed.
+//
+// - Multiple writers attempt to write into the recorder simultaneously. All
+//   writers but one will block because only one can hold the write lock.
+//
+// - A writer is writing into the recorder, which hasn't reached the threshold
+//   at which it will try to reclaim inactive slots. The writer won't try to
+//   acquire the read lock to reclaim inactive slots. The reader will therefore
+//   be able to immediately acquire the read lock, suspend the target thread,
+//   and read the metadata.
+//
+// - A writer is writing into the recorder, the recorder has reached the
+//   threshold at which it needs to reclaim inactive slots, and the writer
+//   thread is now in the middle of reclaiming those slots when a reader
+//   arrives. The reader will try to acquire the read lock before suspending the
+//   thread but will block until the writer thread finishes reclamation and
+//   releases the read lock. The reader will then be able to acquire the read
+//   lock and suspend the target thread.
+//
+// - A reader is reading the recorder when a writer attempts to write. The write
+//   will be successful. However, if the writer deems it necessary to reclaim
+//   inactive slots, it will skip doing so because it won't be able to acquire
+//   the read lock.
 class BASE_EXPORT MetadataRecorder {
  public:
   MetadataRecorder();
@@ -35,22 +136,62 @@
   // If such an item does not exist, this has no effect.
   void Remove(uint64_t name_hash);
 
-  struct Item {
-    // The hash of the metadata name, as produced by base::HashMetricName().
-    uint64_t name_hash;
-    // The value of the metadata item.
-    int64_t value;
-  };
-
-  static const size_t MAX_METADATA_COUNT = 50;
-  typedef std::array<Item, MAX_METADATA_COUNT> ItemArray;
-  // Retrieves the first |available_slots| items in the metadata recorder and
-  // copies them into |items|, returning the number of metadata items that were
-  // copied. To ensure that all items can be copied, |available slots| should be
-  // greater than or equal to |MAX_METADATA_COUNT|.
-  size_t GetItems(ItemArray* const items) const;
+  // Creates a MetadataProvider object for the recorder, which acquires the
+  // necessary exclusive read lock and provides access to the recorder's items
+  // via its GetItems() function. Reclaiming of inactive slots in the recorder
+  // can't occur while this object lives, so it should be created as soon before
+  // it's needed as possible. Calling GetItems() releases the lock held by the
+  // object and can therefore only be called once during the object's lifetime.
+  //
+  // This object should be created *before* suspending the target
+  // thread. Otherwise, that thread might be suspended while reclaiming inactive
+  // slots and holding the read lock, which would cause the sampling thread to
+  // deadlock.
+  //
+  // Example usage:
+  //
+  //   MetadataRecorder r;
+  //   base::ProfileBuilder::MetadataItemArray arr;
+  //   size_t item_count;
+  //   ...
+  //   {
+  //     auto get_items = r.CreateMetadataProvider();
+  //     item_count = get_items.GetItems(arr);
+  //   }
+  std::unique_ptr<ProfileBuilder::MetadataProvider> CreateMetadataProvider();
 
  private:
+  // An object that provides access to a MetadataRecorder's items and holds the
+  // necessary exclusive read lock until either GetItems() is called or the
+  // object is destroyed.
+  //
+  // For usage and more details, see CreateMetadataProvider().
+  class SCOPED_LOCKABLE ScopedGetItems
+      : public ProfileBuilder::MetadataProvider {
+   public:
+    // Acquires an exclusive read lock on the metadata recorder which is held
+    // until either GetItems() is called or the object is destroyed.
+    ScopedGetItems(MetadataRecorder* metadata_recorder)
+        EXCLUSIVE_LOCK_FUNCTION(metadata_recorder->read_lock_);
+    ~ScopedGetItems() override UNLOCK_FUNCTION(metadata_recorder_->read_lock_);
+    ScopedGetItems(const ScopedGetItems&) = delete;
+    ScopedGetItems& operator=(const ScopedGetItems&) = delete;
+
+    // Retrieves the first |available_slots| items in the metadata recorder and
+    // copies them into |items|, returning the number of metadata items that
+    // were copied. To ensure that all items can be copied, |available slots|
+    // should be greater than or equal to |MAX_METADATA_COUNT|.
+    //
+    // This function releases the lock held by the object and can therefore only
+    // be called once during the object's lifetime.
+    size_t GetItems(ProfileBuilder::MetadataItemArray* const items) override
+        EXCLUSIVE_LOCKS_REQUIRED(metadata_recorder_->read_lock_);
+
+   private:
+    const MetadataRecorder* const metadata_recorder_;
+    std::unique_ptr<base::AutoLock> auto_lock_;
+  };
+
   // TODO(charliea): Support large quantities of metadata efficiently.
   struct ItemInternal {
     ItemInternal();
@@ -77,6 +218,24 @@
     std::atomic<int64_t> value;
   };
 
+  // Attempts to free slots in the metadata map that are currently allocated to
+  // inactive items. May fail silently if the read lock is already held, in
+  // which case no slots will be freed. Returns the number of item slots used
+  // after the reclamation.
+  size_t TryReclaimInactiveSlots(size_t item_slots_used)
+      EXCLUSIVE_LOCKS_REQUIRED(write_lock_) LOCKS_EXCLUDED(read_lock_);
+  // Also protected by read_lock_, but current thread annotation limitations
+  // prevent us from using thread annotations with locks acquired through
+  // Lock::Try(). Updates item_slots_used_ to reflect the new item count and
+  // returns the number of item slots used after the reclamation.
+  size_t ReclaimInactiveSlots(size_t item_slots_used)
+      EXCLUSIVE_LOCKS_REQUIRED(write_lock_);
+
+  // Protected by read_lock_, but current thread annotation limitations
+  // prevent us from using thread annotations with locks acquired through
+  // Lock::Try().
+  size_t GetItems(ProfileBuilder::MetadataItemArray* const items) const;
+
   // Metadata items that the recorder has seen. Rather than implementing the
   // metadata recorder as a dense array, we implement it as a sparse array where
   // removed metadata items keep their slot with their |is_active| bit set to
@@ -85,7 +244,7 @@
   //
   // For the rationale behind this design (along with others considered), see
   // https://docs.google.com/document/d/18shLhVwuFbLl_jKZxCmOfRB98FmNHdKl0yZZZ3aEO4U/edit#.
-  std::array<ItemInternal, MAX_METADATA_COUNT> items_;
+  std::array<ItemInternal, ProfileBuilder::MAX_METADATA_COUNT> items_;
 
   // The number of item slots used in the metadata map.
   //
@@ -95,9 +254,21 @@
   // of its existence.
   std::atomic<size_t> item_slots_used_{0};
 
-  // A lock that guards against multiple threads trying to modify the same item
-  // at once.
+  // The number of item slots occupied by inactive items.
+  size_t inactive_item_count_ GUARDED_BY(write_lock_) = 0;
+
+  // A lock that guards against multiple threads trying to manipulate items_,
+  // item_slots_used_, or inactive_item_count_ at the same time.
   base::Lock write_lock_;
+
+  // A lock that guards against a reader trying to read items_ while inactive
+  // slots are being reclaimed.
+  //
+  // Note that we can't enforce that this lock is properly acquired through
+  // thread annotations because thread annotations doesn't understand that
+  // ScopedGetItems::GetItems() can only be called between ScopedGetItems's
+  // constructor and destructor.
+  base::Lock read_lock_;
 };
 
 }  // namespace base
diff --git a/base/profiler/metadata_recorder_unittest.cc b/base/profiler/metadata_recorder_unittest.cc
index 8155687..7228ec9 100644
--- a/base/profiler/metadata_recorder_unittest.cc
+++ b/base/profiler/metadata_recorder_unittest.cc
@@ -10,15 +10,21 @@
 
 namespace base {
 
-bool operator==(const MetadataRecorder::Item& lhs,
-                const MetadataRecorder::Item& rhs) {
+bool operator==(const base::ProfileBuilder::MetadataItem& lhs,
+                const base::ProfileBuilder::MetadataItem& rhs) {
   return lhs.name_hash == rhs.name_hash && lhs.value == rhs.value;
 }
 
+bool operator<(const base::ProfileBuilder::MetadataItem& lhs,
+               const base::ProfileBuilder::MetadataItem& rhs) {
+  return lhs.name_hash < rhs.name_hash;
+}
+
 TEST(MetadataRecorderTest, GetItems_Empty) {
   MetadataRecorder recorder;
-  MetadataRecorder::ItemArray items;
-  size_t item_count = recorder.GetItems(&items);
+  base::ProfileBuilder::MetadataItemArray items;
+
+  size_t item_count = recorder.CreateMetadataProvider()->GetItems(&items);
 
   ASSERT_EQ(0u, item_count);
 }
@@ -28,18 +34,23 @@
 
   recorder.Set(10, 20);
 
-  MetadataRecorder::ItemArray items;
-  size_t item_count = recorder.GetItems(&items);
-  ASSERT_EQ(1u, item_count);
-  ASSERT_EQ(10u, items[0].name_hash);
-  ASSERT_EQ(20, items[0].value);
+  base::ProfileBuilder::MetadataItemArray items;
+  size_t item_count;
+  {
+    item_count = recorder.CreateMetadataProvider()->GetItems(&items);
+    ASSERT_EQ(1u, item_count);
+    ASSERT_EQ(10u, items[0].name_hash);
+    ASSERT_EQ(20, items[0].value);
+  }
 
   recorder.Set(20, 30);
 
-  item_count = recorder.GetItems(&items);
-  ASSERT_EQ(2u, item_count);
-  ASSERT_EQ(20u, items[1].name_hash);
-  ASSERT_EQ(30, items[1].value);
+  {
+    item_count = recorder.CreateMetadataProvider()->GetItems(&items);
+    ASSERT_EQ(2u, item_count);
+    ASSERT_EQ(20u, items[1].name_hash);
+    ASSERT_EQ(30, items[1].value);
+  }
 }
 
 TEST(MetadataRecorderTest, Set_ExistingNameNash) {
@@ -47,8 +58,8 @@
   recorder.Set(10, 20);
   recorder.Set(10, 30);
 
-  MetadataRecorder::ItemArray items;
-  size_t item_count = recorder.GetItems(&items);
+  base::ProfileBuilder::MetadataItemArray items;
+  size_t item_count = recorder.CreateMetadataProvider()->GetItems(&items);
   ASSERT_EQ(1u, item_count);
   ASSERT_EQ(10u, items[0].name_hash);
   ASSERT_EQ(30, items[0].value);
@@ -56,10 +67,10 @@
 
 TEST(MetadataRecorderTest, Set_ReAddRemovedNameNash) {
   MetadataRecorder recorder;
-  MetadataRecorder::ItemArray items;
-  std::vector<MetadataRecorder::Item> expected;
+  base::ProfileBuilder::MetadataItemArray items;
+  std::vector<base::ProfileBuilder::MetadataItem> expected;
   for (size_t i = 0; i < items.size(); ++i) {
-    expected.push_back(MetadataRecorder::Item{i, 0});
+    expected.push_back(base::ProfileBuilder::MetadataItem{i, 0});
     recorder.Set(i, 0);
   }
 
@@ -70,14 +81,14 @@
   recorder.Remove(3);
   recorder.Set(3, 0);
 
-  size_t item_count = recorder.GetItems(&items);
+  size_t item_count = recorder.CreateMetadataProvider()->GetItems(&items);
   EXPECT_EQ(items.size(), item_count);
-  ASSERT_THAT(expected, ::testing::ElementsAreArray(items));
+  ASSERT_THAT(expected, ::testing::UnorderedElementsAreArray(items));
 }
 
 TEST(MetadataRecorderTest, Set_AddPastMaxCount) {
   MetadataRecorder recorder;
-  MetadataRecorder::ItemArray items;
+  base::ProfileBuilder::MetadataItemArray items;
   for (size_t i = 0; i < items.size(); ++i) {
     recorder.Set(i, 0);
   }
@@ -92,8 +103,8 @@
   recorder.Set(50, 60);
   recorder.Remove(30);
 
-  MetadataRecorder::ItemArray items;
-  size_t item_count = recorder.GetItems(&items);
+  base::ProfileBuilder::MetadataItemArray items;
+  size_t item_count = recorder.CreateMetadataProvider()->GetItems(&items);
   ASSERT_EQ(2u, item_count);
   ASSERT_EQ(10u, items[0].name_hash);
   ASSERT_EQ(20, items[0].value);
@@ -106,11 +117,45 @@
   recorder.Set(10, 20);
   recorder.Remove(20);
 
-  MetadataRecorder::ItemArray items;
-  size_t item_count = recorder.GetItems(&items);
+  base::ProfileBuilder::MetadataItemArray items;
+  size_t item_count = recorder.CreateMetadataProvider()->GetItems(&items);
   ASSERT_EQ(1u, item_count);
   ASSERT_EQ(10u, items[0].name_hash);
   ASSERT_EQ(20, items[0].value);
 }
 
+TEST(MetadataRecorderTest, ReclaimInactiveSlots) {
+  MetadataRecorder recorder;
+
+  std::set<base::ProfileBuilder::MetadataItem> items_set;
+  // Fill up the metadata map.
+  for (size_t i = 0; i < base::ProfileBuilder::MAX_METADATA_COUNT; ++i) {
+    recorder.Set(i, i);
+    items_set.insert(base::ProfileBuilder::MetadataItem{i, i});
+  }
+
+  // Remove every fourth entry to fragment the data.
+  size_t entries_removed = 0;
+  for (size_t i = 3; i < base::ProfileBuilder::MAX_METADATA_COUNT; i += 4) {
+    recorder.Remove(i);
+    ++entries_removed;
+    items_set.erase(base::ProfileBuilder::MetadataItem{i, i});
+  }
+
+  // Ensure that the inactive slots are reclaimed to make room for more entries.
+  for (size_t i = 1; i <= entries_removed; ++i) {
+    recorder.Set(i * 100, i * 100);
+    items_set.insert(base::ProfileBuilder::MetadataItem{i * 100, i * 100});
+  }
+
+  base::ProfileBuilder::MetadataItemArray items_arr;
+  std::copy(items_set.begin(), items_set.end(), items_arr.begin());
+
+  base::ProfileBuilder::MetadataItemArray recorder_items;
+  size_t recorder_item_count =
+      recorder.CreateMetadataProvider()->GetItems(&recorder_items);
+  ASSERT_EQ(recorder_item_count, base::ProfileBuilder::MAX_METADATA_COUNT);
+  ASSERT_THAT(recorder_items, ::testing::UnorderedElementsAreArray(items_arr));
+}
+
 }  // namespace base
diff --git a/base/profiler/profile_builder.cc b/base/profiler/profile_builder.cc
new file mode 100644
index 0000000..ca3db2a
--- /dev/null
+++ b/base/profiler/profile_builder.cc
@@ -0,0 +1,7 @@
+// 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 "base/profiler/profile_builder.h"
+
+const size_t base::ProfileBuilder::MAX_METADATA_COUNT;
diff --git a/base/profiler/profile_builder.h b/base/profiler/profile_builder.h
index 0202c21..49355ef 100644
--- a/base/profiler/profile_builder.h
+++ b/base/profiler/profile_builder.h
@@ -26,13 +26,31 @@
   // up modules from addresses.
   virtual ModuleCache* GetModuleCache() = 0;
 
+  struct MetadataItem {
+    // The hash of the metadata name, as produced by base::HashMetricName().
+    uint64_t name_hash;
+    // The value of the metadata item.
+    int64_t value;
+  };
+
+  static constexpr size_t MAX_METADATA_COUNT = 50;
+  typedef std::array<MetadataItem, MAX_METADATA_COUNT> MetadataItemArray;
+
+  class MetadataProvider {
+   public:
+    MetadataProvider() = default;
+    virtual ~MetadataProvider() = default;
+
+    virtual size_t GetItems(ProfileBuilder::MetadataItemArray* const items) = 0;
+  };
+
   // Records metadata to be associated with the current sample. To avoid
   // deadlock on locks taken by the suspended profiled thread, implementations
   // of this method must not execute any code that could take a lock, including
   // heap allocation or use of CHECK/DCHECK/LOG statements. Generally
   // implementations should simply atomically copy metadata state to be
   // associated with the sample.
-  virtual void RecordMetadata() {}
+  virtual void RecordMetadata(MetadataProvider* metadata_provider) {}
 
   // Records a new set of frames. Invoked when sampling a sample completes.
   virtual void OnSampleCompleted(std::vector<Frame> frames) = 0;
diff --git a/base/profiler/sample_metadata_unittest.cc b/base/profiler/sample_metadata_unittest.cc
index 27e177b..e38052f 100644
--- a/base/profiler/sample_metadata_unittest.cc
+++ b/base/profiler/sample_metadata_unittest.cc
@@ -10,19 +10,29 @@
 namespace base {
 
 TEST(SampleMetadataTest, ScopedSampleMetadata) {
-  MetadataRecorder::ItemArray items;
-
-  ASSERT_EQ(0u, GetSampleMetadataRecorder()->GetItems(&items));
+  base::ProfileBuilder::MetadataItemArray items;
+  {
+    auto get_items = GetSampleMetadataRecorder()->CreateMetadataProvider();
+    ASSERT_EQ(0u, get_items->GetItems(&items));
+  }
 
   {
     ScopedSampleMetadata m("myname", 100);
 
-    ASSERT_EQ(1u, GetSampleMetadataRecorder()->GetItems(&items));
-    EXPECT_EQ(base::HashMetricName("myname"), items[0].name_hash);
-    EXPECT_EQ(100, items[0].value);
+    {
+      ASSERT_EQ(1u,
+                GetSampleMetadataRecorder()->CreateMetadataProvider()->GetItems(
+                    &items));
+      EXPECT_EQ(base::HashMetricName("myname"), items[0].name_hash);
+      EXPECT_EQ(100, items[0].value);
+    }
   }
 
-  ASSERT_EQ(0u, GetSampleMetadataRecorder()->GetItems(&items));
+  {
+    ASSERT_EQ(0u,
+              GetSampleMetadataRecorder()->CreateMetadataProvider()->GetItems(
+                  &items));
+  }
 }
 
 }  // namespace base
diff --git a/base/profiler/stack_sampler_impl.cc b/base/profiler/stack_sampler_impl.cc
index 2c70cc8..6993664 100644
--- a/base/profiler/stack_sampler_impl.cc
+++ b/base/profiler/stack_sampler_impl.cc
@@ -8,6 +8,7 @@
 
 #include "base/logging.h"
 #include "base/profiler/profile_builder.h"
+#include "base/profiler/sample_metadata.h"
 #include "base/profiler/thread_delegate.h"
 #include "base/profiler/unwinder.h"
 
@@ -79,6 +80,12 @@
   uintptr_t bottom = 0;
   const uint8_t* stack_copy_bottom = nullptr;
   {
+    // The MetadataProvider must be created before the ScopedSuspendThread
+    // because it acquires a lock in its constructor that might otherwise be
+    // held by the target thread, resulting in deadlock.
+    std::unique_ptr<base::ProfileBuilder::MetadataProvider> get_metadata_items =
+        base::GetSampleMetadataRecorder()->CreateMetadataProvider();
+
     // Allocation of the ScopedSuspendThread object itself is OK since it
     // necessarily occurs before the thread is suspended by the object.
     std::unique_ptr<ThreadDelegate::ScopedSuspendThread> suspend_thread =
@@ -102,7 +109,7 @@
     if (!thread_delegate_->CanCopyStack(bottom))
       return false;
 
-    profile_builder->RecordMetadata();
+    profile_builder->RecordMetadata(get_metadata_items.get());
 
     stack_copy_bottom = CopyStackContentsAndRewritePointers(
         reinterpret_cast<uint8_t*>(bottom), reinterpret_cast<uintptr_t*>(top),
diff --git a/base/profiler/stack_sampler_impl_unittest.cc b/base/profiler/stack_sampler_impl_unittest.cc
index 9884e59c..f86d433 100644
--- a/base/profiler/stack_sampler_impl_unittest.cc
+++ b/base/profiler/stack_sampler_impl_unittest.cc
@@ -33,7 +33,8 @@
 
   // ProfileBuilder
   ModuleCache* GetModuleCache() override { return module_cache_; }
-  void RecordMetadata() override {}
+  void RecordMetadata(
+      base::ProfileBuilder::MetadataProvider* metadata_provider) override {}
   void OnSampleCompleted(std::vector<Frame> frames) override {}
   void OnProfileCompleted(TimeDelta profile_duration,
                           TimeDelta sampling_period) override {}
@@ -60,8 +61,7 @@
                      // The register context will be initialized to
                      // *|thread_context| if non-null.
                      RegisterContext* thread_context = nullptr)
-      : fake_stack_(fake_stack),
-        thread_context_(thread_context) {}
+      : fake_stack_(fake_stack), thread_context_(thread_context) {}
 
   TestThreadDelegate(const TestThreadDelegate&) = delete;
   TestThreadDelegate& operator=(const TestThreadDelegate&) = delete;
diff --git a/base/profiler/stack_sampling_profiler_test_util.cc b/base/profiler/stack_sampling_profiler_test_util.cc
index e560e0c..b96bbeb 100644
--- a/base/profiler/stack_sampling_profiler_test_util.cc
+++ b/base/profiler/stack_sampling_profiler_test_util.cc
@@ -35,7 +35,7 @@
 
   // ProfileBuilder:
   ModuleCache* GetModuleCache() override { return module_cache_; }
-  void RecordMetadata() override {}
+  void RecordMetadata(MetadataProvider* metadata_provider) override {}
 
   void OnSampleCompleted(std::vector<Frame> sample) override {
     EXPECT_TRUE(sample_.empty());
diff --git a/base/profiler/stack_sampling_profiler_unittest.cc b/base/profiler/stack_sampling_profiler_unittest.cc
index c52fcc2d..d3035b93 100644
--- a/base/profiler/stack_sampling_profiler_unittest.cc
+++ b/base/profiler/stack_sampling_profiler_unittest.cc
@@ -172,7 +172,8 @@
 
   // ProfileBuilder:
   ModuleCache* GetModuleCache() override;
-  void RecordMetadata() override;
+  void RecordMetadata(
+      base::ProfileBuilder::MetadataProvider* metadata_provider) override;
   void OnSampleCompleted(std::vector<Frame> sample) override;
   void OnProfileCompleted(TimeDelta profile_duration,
                           TimeDelta sampling_period) override;
@@ -202,7 +203,8 @@
   return module_cache_;
 }
 
-void TestProfileBuilder::RecordMetadata() {
+void TestProfileBuilder::RecordMetadata(
+    base::ProfileBuilder::MetadataProvider* metadata_provider) {
   ++metadata_count_;
 }
 
diff --git a/base/test/scoped_task_environment.h b/base/test/scoped_task_environment.h
index 90583a7..c094d87 100644
--- a/base/test/scoped_task_environment.h
+++ b/base/test/scoped_task_environment.h
@@ -113,9 +113,6 @@
     DEFAULT = ASYNC
   };
 
-  // TODO(carlscab): Deprecated. Migrate all uses and remove.
-  using ExecutionMode = ThreadPoolExecutionMode;
-
   enum class NowSource {
     // base::Time::Now() and base::TimeTicks::Now() are real time.
     REAL_TIME,
diff --git a/build/android/pylib/linker/test_case.py b/build/android/pylib/linker/test_case.py
index ee1b998..2afba5c 100644
--- a/build/android/pylib/linker/test_case.py
+++ b/build/android/pylib/linker/test_case.py
@@ -131,7 +131,7 @@
     Args:
       is_low_memory: True to simulate a low-memory device, False otherwise.
     """
-    test_suffix = 'ForLinker'
+    test_suffix = 'ForLegacyLinker'
     self.is_low_memory = is_low_memory
     if is_low_memory:
       test_suffix += 'LowMemoryDevice'
diff --git a/build/chromeos/OWNERS b/build/chromeos/OWNERS
new file mode 100644
index 0000000..6ba0eaa
--- /dev/null
+++ b/build/chromeos/OWNERS
@@ -0,0 +1,4 @@
+bpastene@chromium.org
+
+# TEAM: infra-dev@chromium.org
+# COMPONENT: Build
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index c6c0e415..f8c0ef0 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8908519668143306512
\ No newline at end of file
+8908493396578343696
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 6655c00b..c728ee0 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-8908521448671558320
\ No newline at end of file
+8908494036510635456
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
index ef2e053..8dffae63 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
@@ -46,9 +46,14 @@
     public static final String BROWSER_ACTIONS_NAMESPACE = "browser_actions";
     public static final String LIVE_PAGE_SHARING_NAMESPACE = "live_page_sharing";
 
+    private long mNativeOfflinePageBridge;
+    private boolean mIsNativeOfflinePageModelLoaded;
+    private final ObserverList<OfflinePageModelObserver> mObservers = new ObserverList<>();
+
     /**
      * Retrieves the OfflinePageBridge for the given profile, creating it the first time
-     * getForProfile is called for the profile.  Must be called on the UI thread.
+     * getForProfile or getForProfileKey is called for the profile.  Must be called on the UI
+     * thread.
      *
      * @param profile The profile associated with the OfflinePageBridge to get.
      */
@@ -58,13 +63,21 @@
         if (profile == null)
             return null;
 
-        return nativeGetOfflinePageBridgeForProfileKey(profile.getProfileKey());
+        return getForProfileKey(profile.getProfileKey());
     }
 
-    private long mNativeOfflinePageBridge;
-    private boolean mIsNativeOfflinePageModelLoaded;
-    private final ObserverList<OfflinePageModelObserver> mObservers =
-            new ObserverList<OfflinePageModelObserver>();
+    /**
+     * Retrieves the OfflinePageBridge for the profile with the given key, creating it the first
+     * time getForProfile or getForProfileKey is called for the profile.  Must be called on the UI
+     * thread.
+     *
+     * @param profileKey Key of the profile associated with the OfflinePageBridge to get.
+     */
+    public static OfflinePageBridge getForProfileKey(ProfileKey profileKey) {
+        ThreadUtils.assertOnUiThread();
+
+        return nativeGetOfflinePageBridgeForProfileKey(profileKey);
+    }
 
     /**
      * Callback used when saving an offline page.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderServiceHost.java b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderServiceHost.java
index 6ec07b7..2b023d4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderServiceHost.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderServiceHost.java
@@ -112,12 +112,6 @@
         // The URI for the file containing the bitmap to decode.
         public Uri mUri;
 
-        // Whether this is a high priority request. All decoding request start out high priority,
-        // and those that contain requests to decode a video, will be broken up into two requests
-        // each (a high priority one to decode the first frame and a low-priority one to decode the
-        // rest of the frames).
-        boolean mHighPriorityRequest;
-
         // The requested size (width and height) of the bitmap, once decoded.
         public int mSize;
 
@@ -132,17 +126,21 @@
         long mTimestamp;
 
         public DecoderServiceParams(Uri uri, int size, @PickerBitmap.TileTypes int fileType,
-                boolean highPriorityRequest, ImagesDecodedCallback callback) {
+                ImagesDecodedCallback callback) {
             mUri = uri;
             mSize = size;
             mFileType = fileType;
-            mHighPriorityRequest = highPriorityRequest;
             mCallback = callback;
         }
     }
 
-    // Map of file paths to pending decoding requests.
-    private LinkedHashMap<String, DecoderServiceParams> mPendingRequests = new LinkedHashMap<>();
+    // Map of file paths to pending decoding requests of high priority.
+    private LinkedHashMap<String, DecoderServiceParams> mHighPriorityRequests =
+            new LinkedHashMap<>();
+
+    // Map of file paths to pending decoding requests of low priority.
+    private LinkedHashMap<String, DecoderServiceParams> mLowPriorityRequests =
+            new LinkedHashMap<>();
 
     // Map of file paths to processing decoding requests.
     private LinkedHashMap<String, DecoderServiceParams> mProcessingRequests = new LinkedHashMap<>();
@@ -199,61 +197,62 @@
      */
     public void decodeImage(Uri uri, @PickerBitmap.TileTypes int fileType, int size,
             ImagesDecodedCallback callback) {
-        DecoderServiceParams params = new DecoderServiceParams(
-                uri, size, fileType, /*highPriorityRequest*/ true, callback);
-        mPendingRequests.put(uri.getPath(), params);
-        if (mPendingRequests.size() == 1) dispatchNextDecodeRequest();
+        DecoderServiceParams params = new DecoderServiceParams(uri, size, fileType, callback);
+        mHighPriorityRequests.put(uri.getPath(), params);
+        if (mHighPriorityRequests.size() == 1) dispatchNextDecodeRequest();
     }
 
     /**
-     * Fetches the next decoding request from the queue. High-priority requests are returned first,
-     * then low-priority ones that have had their high-priority counterpart processed already.
-     * @return The highest priority request pending, or null. Null can be returned in two scenarios:
+     * Fetches the next high-priority decoding request from the queue and removes it from the queue.
+     * If that request is a video decoding request, a request for decoding additional frames is
+     * added to the low-priority queue.
+     * @return Next high-priority request pending.
+     */
+    private DecoderServiceParams getNextHighPriority() {
+        assert mHighPriorityRequests.size() > 0;
+        DecoderServiceParams params = mHighPriorityRequests.entrySet().iterator().next().getValue();
+        mHighPriorityRequests.remove(params.mUri.getPath());
+        if (params.mFileType == PickerBitmap.TileTypes.VIDEO) {
+            // High-priority decoding requests for videos are requests for first frames (see
+            // dispatchDecodeVideoRequest). Adding another low-priority request is a request for
+            // decoding the rest of the frames.
+            DecoderServiceParams lowPriorityRequest = new DecoderServiceParams(
+                    params.mUri, params.mSize, params.mFileType, params.mCallback);
+            mLowPriorityRequests.put(params.mUri.getPath(), lowPriorityRequest);
+        }
+        return params;
+    }
+
+    /**
+     * Fetches the next low-priority decoding request from the queue and removes it from the queue.
+     * @return Next low-priority request pending, or null. Null can be returned in two scenarios:
      *         If no requests remain or if the only request remaining is a low-priority request
      *         where it's high-priority counterpart is still being processed.
      */
-    private DecoderServiceParams getNextRequestByPriority() {
-        DecoderServiceParams firstNonPriority = null;
-        for (DecoderServiceParams request : mPendingRequests.values()) {
-            if (request.mHighPriorityRequest) return request;
-            if (firstNonPriority == null) {
-                boolean foundAlreadyProcessing = false;
-                for (DecoderServiceParams processing : mProcessingRequests.values()) {
-                    if (request.mUri.getPath().equals(processing.mUri.getPath())) {
-                        foundAlreadyProcessing = true;
-                        break;
-                    }
-                }
-                if (!foundAlreadyProcessing) firstNonPriority = request;
-            }
+    private DecoderServiceParams getNextLowPriority() {
+        for (DecoderServiceParams request : mLowPriorityRequests.values()) {
+            String filePath = request.mUri.getPath();
+            if (mProcessingRequests.get(filePath) != null) continue;
+            mLowPriorityRequests.remove(filePath);
+            return request;
         }
-        return firstNonPriority;
+        return null;
     }
 
     /**
      * Dispatches the next image/video for decoding (from the queue).
      */
     private void dispatchNextDecodeRequest() {
-        DecoderServiceParams params = getNextRequestByPriority();
+        boolean highPriority = mHighPriorityRequests.entrySet().iterator().hasNext();
+        DecoderServiceParams params = highPriority ? getNextHighPriority() : getNextLowPriority();
         if (params != null) {
-            mPendingRequests.remove(params.mUri.getPath());
             mProcessingRequests.put(params.mUri.getPath(), params);
 
             params.mTimestamp = SystemClock.elapsedRealtime();
             if (params.mFileType != PickerBitmap.TileTypes.VIDEO) {
                 dispatchDecodeImageRequest(params);
             } else {
-                dispatchDecodeVideoRequest(params);
-
-                // High-priority decoding requests for videos are requests for first frames (see
-                // dispatchDecodeVideoRequest). Add another low-priority request for decoding the
-                // rest of the frames.
-                if (params.mHighPriorityRequest) {
-                    DecoderServiceParams lowPriorityRequest =
-                            new DecoderServiceParams(params.mUri, params.mSize, params.mFileType,
-                                    /*highPriorityRequest=*/false, params.mCallback);
-                    mPendingRequests.put(params.mUri.getPath(), lowPriorityRequest);
-                }
+                dispatchDecodeVideoRequest(params, highPriority);
             }
             return;
         }
@@ -352,13 +351,14 @@
     /**
      * Communicates with the utility process to decode a single video.
      * @param params The information about the decoding request.
+     * @param highPriority True if the decoding request is a high-priority request.
      */
-    private void dispatchDecodeVideoRequest(DecoderServiceParams params) {
+    private void dispatchDecodeVideoRequest(DecoderServiceParams params, boolean highPriority) {
         // Videos are decoded by the system (on N+) using a restricted helper process, so
         // there's no need to use our custom sandboxed process.
         assert Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;
 
-        int frames = params.mHighPriorityRequest ? 1 : 20;
+        int frames = highPriority ? 1 : 20;
         int intervalMs = 500;
         mWorkerTask = new DecodeVideoTask(
                 this, mContentResolver, params.mUri, params.mSize, frames, intervalMs);
@@ -416,7 +416,8 @@
      * @param filePath The path to the image to cancel decoding.
      */
     public void cancelDecodeImage(String filePath) {
-        mPendingRequests.remove(filePath);
+        mHighPriorityRequests.remove(filePath);
+        mLowPriorityRequests.remove(filePath);
         mProcessingRequests.remove(filePath);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandler.java
index 95e235f..232901b9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandler.java
@@ -65,7 +65,7 @@
                 new Intent(context, TapReceiver.class).putExtra(EXTRA_PHONE_NUMBER, phoneNumber),
                 PendingIntent.FLAG_UPDATE_CURRENT);
         Resources resources = context.getResources();
-        String text = resources.getString(R.string.click_to_call_notification_text, phoneNumber);
+        String text = resources.getString(R.string.click_to_call_notification_text);
         ChromeNotificationBuilder builder =
                 NotificationBuilderFactory
                         .createChromeNotificationBuilder(/*preferCompat=*/true,
@@ -76,6 +76,7 @@
                                         NotificationConstants.GROUP_CLICK_TO_CALL,
                                         NotificationConstants.NOTIFICATION_ID_CLICK_TO_CALL))
                         .setContentIntent(contentIntent)
+                        .setContentTitle(phoneNumber)
                         .setContentText(text)
                         .setGroup(NotificationConstants.GROUP_CLICK_TO_CALL)
                         .setPriorityBeforeO(NotificationCompat.PRIORITY_HIGH)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/ProfileSyncService.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/ProfileSyncService.java
index 4add6579..f105055c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/ProfileSyncService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/ProfileSyncService.java
@@ -387,9 +387,9 @@
     }
 
     /**
-     * Checks whether syncing is "requested" by the user, i.e. the user has not disabled syncing
-     * in settings. Note that even if this is true, other reasons might prevent Sync from actually
-     * starting up.
+     * Checks whether syncing is requested by the user, i.e. the user has at least started a Sync
+     * setup flow, and has not disabled syncing in settings. Note that even if this is true, other
+     * reasons might prevent Sync from actually starting up.
      *
      * @return true if the user wants to sync, false otherwise.
      */
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index d4e9cba..2730fae91 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -1591,7 +1591,7 @@
         Your bookmarks, history, passwords, and other Chrome data will no longer be synced to your Google Account
       </message>
       <message name="IDS_REMOVE_LOCAL_DATA" desc="Checkbox to delete all existing data in local device storage">
-        Also clear this Chrome data from this device
+        Also clear your Chrome data from this device
       </message>
       <message name="IDS_SIGNOUT_MANAGED_ACCOUNT_MESSAGE" desc="Message to display for sign out of Chrome dialog when the account has enterprise management, and all user data will be erased">
         You are signing out of an account managed by <ph name="DOMAIN_NAME">%1$s<ex>google.com</ex></ph>. This will delete the Chrome data stored on this device, but the data will remain in your Google Account.
@@ -3904,7 +3904,7 @@
 
       <!-- ClickToCall -->
       <message name="IDS_CLICK_TO_CALL_NOTIFICATION_TEXT" desc="Text displayed in a click to call notification.">
-        Call <ph name="PHONE_NUMBER">%1$s<ex>+1234567890</ex></ph>
+        Tap to make call
       </message>
 
       <!-- Chrome Duet -->
diff --git a/chrome/android/java/strings/android_chrome_strings_grd/IDS_REMOVE_LOCAL_DATA.png.sha1 b/chrome/android/java/strings/android_chrome_strings_grd/IDS_REMOVE_LOCAL_DATA.png.sha1
new file mode 100644
index 0000000..e925d54
--- /dev/null
+++ b/chrome/android/java/strings/android_chrome_strings_grd/IDS_REMOVE_LOCAL_DATA.png.sha1
@@ -0,0 +1 @@
+52ec60c38256bd198a2fca7310ad7245379811b0
\ No newline at end of file
diff --git a/chrome/android/java/strings/android_chrome_strings_grd/IDS_SIGNOUT_MESSAGE.png.sha1 b/chrome/android/java/strings/android_chrome_strings_grd/IDS_SIGNOUT_MESSAGE.png.sha1
index bdb61d0..e925d54 100644
--- a/chrome/android/java/strings/android_chrome_strings_grd/IDS_SIGNOUT_MESSAGE.png.sha1
+++ b/chrome/android/java/strings/android_chrome_strings_grd/IDS_SIGNOUT_MESSAGE.png.sha1
@@ -1 +1 @@
-3b785f5a55c656ee3fa36a40178aea0a35ae6360
\ No newline at end of file
+52ec60c38256bd198a2fca7310ad7245379811b0
\ No newline at end of file
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java
index b4d82e3..962d1a7e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java
@@ -30,6 +30,7 @@
 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge.SavePageCallback;
 import org.chromium.chrome.browser.offlinepages.downloads.OfflinePageDownloadBridge;
 import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.profiles.ProfileKey;
 import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.components.offlinepages.DeletePageResult;
@@ -99,6 +100,31 @@
         if (!incognitoProfile) Assert.assertNotNull(mOfflinePageBridge);
     }
 
+    private OfflinePageBridge getBridgeForProfileKey() throws InterruptedException {
+        final Semaphore semaphore = new Semaphore(0);
+        AtomicReference<OfflinePageBridge> offlinePageBridgeRef = new AtomicReference<>();
+        PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> {
+            ProfileKey profileKey = ProfileKey.getLastUsedProfileKey();
+            // Ensure we start in an offline state.
+            OfflinePageBridge offlinePageBridge = OfflinePageBridge.getForProfileKey(profileKey);
+            offlinePageBridgeRef.set(offlinePageBridge);
+            if (offlinePageBridge == null || offlinePageBridge.isOfflinePageModelLoaded()) {
+                semaphore.release();
+                return;
+            }
+            offlinePageBridge.addObserver(new OfflinePageModelObserver() {
+                @Override
+                public void offlinePageModelLoaded() {
+                    semaphore.release();
+                    offlinePageBridge.removeObserver(this);
+                }
+            });
+        });
+        Assert.assertTrue(semaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        Assert.assertNotNull(offlinePageBridgeRef.get());
+        return offlinePageBridgeRef.get();
+    }
+
     @Before
     public void setUp() throws Exception {
         mActivityTestRule.startMainActivityOnBlankPage();
@@ -124,6 +150,13 @@
 
     @Test
     @MediumTest
+    public void testProfileAndKeyMapToSameOfflinePageBridge() throws Exception {
+        OfflinePageBridge offlinePageBridgeRetrievedByKey = getBridgeForProfileKey();
+        Assert.assertSame(mOfflinePageBridge, offlinePageBridgeRetrievedByKey);
+    }
+
+    @Test
+    @MediumTest
     @RetryOnFailure
     public void testLoadOfflinePagesWhenEmpty() throws Exception {
         List<OfflinePageItem> offlinePages = OfflineTestUtil.getAllPages();
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index 0276344ac..524966f 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-77.0.3846.0_rc-r1-merged.afdo.bz2
\ No newline at end of file
+chromeos-chrome-amd64-77.0.3847.0_rc-r1-merged.afdo.bz2
\ No newline at end of file
diff --git a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/ui/progressbar/ProgressBarMediator.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/ui/progressbar/ProgressBarMediator.java
index 29322243..66c09cf 100644
--- a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/ui/progressbar/ProgressBarMediator.java
+++ b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/ui/progressbar/ProgressBarMediator.java
@@ -9,6 +9,7 @@
 import org.chromium.chrome.browser.native_page.NativePageFactory;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.util.UrlUtilities;
+import org.chromium.content_public.browser.NavigationHandle;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
 import org.chromium.ui.modelutil.PropertyModel;
 
@@ -54,7 +55,15 @@
         mModel.set(ProgressBarProperties.IS_VISIBLE, false);
     }
 
-    private void onLoadingStopped() {
+    private void startLoadProgress() {
+        mWasDisplayedForMinimumDuration = false;
+        mCanHideProgressBar = false;
+
+        mModel.set(ProgressBarProperties.PROGRESS_FRACTION, 0f);
+        show();
+    }
+
+    private void stopLoadProgress() {
         mCanHideProgressBar = true;
         hide();
     }
@@ -64,22 +73,42 @@
         mProgressBarTabObserver.destroy();
     }
 
+    // This class follows the same logic used in ToolbarManager#mTabObserver for updating the shown
+    // URL as well as updating the progress bar.
     private class ProgressBarTabObserver extends ActivityTabProvider.ActivityTabTabObserver {
         ProgressBarTabObserver(ActivityTabProvider tabProvider) {
             super(tabProvider);
         }
 
         @Override
-        public void onPageLoadStarted(Tab tab, String url) {
-            if (NativePageFactory.isNativePageUrl(url, tab.isIncognito())) {
+        public void onDidStartNavigation(Tab tab, NavigationHandle navigation) {
+            if (!navigation.isInMainFrame()) return;
+
+            if (NativePageFactory.isNativePageUrl(navigation.getUrl(), tab.isIncognito())) {
                 mModel.set(ProgressBarProperties.IS_ENABLED, false);
-            } else {
-                mModel.set(ProgressBarProperties.IS_ENABLED, true);
-                mWasDisplayedForMinimumDuration = false;
-                mCanHideProgressBar = false;
-                show();
-                mModel.set(ProgressBarProperties.PROGRESS_FRACTION, 0f);
+                stopLoadProgress();
+                return;
             }
+
+            mModel.set(ProgressBarProperties.IS_ENABLED, true);
+            updateUrl(tab);
+            startLoadProgress();
+        }
+
+        @Override
+        public void onUrlUpdated(Tab tab) {
+            updateUrl(tab);
+        }
+
+        @Override
+        public void onLoadStarted(Tab tab, boolean toDifferentDocument) {
+            updateUrl(tab);
+        }
+
+        @Override
+        public void onLoadStopped(Tab tab, boolean toDifferentDocument) {
+            updateUrl(tab);
+            stopLoadProgress();
         }
 
         @Override
@@ -87,23 +116,24 @@
             if (NativePageFactory.isNativePageUrl(tab.getUrl(), tab.isIncognito())) return;
 
             mModel.set(ProgressBarProperties.PROGRESS_FRACTION, progress / 100f);
-            mModel.set(ProgressBarProperties.URL,
-                    UrlUtilities.getDomainAndRegistry(tab.getUrl(), false));
+        }
+
+        @Override
+        public void onWebContentsSwapped(Tab tab, boolean didStartLoad, boolean didFinishLoad) {
+            if (!didStartLoad) return;
+
+            updateUrl(tab);
+            if (didFinishLoad) stopLoadProgress();
         }
 
         @Override
         public void onCrash(Tab tab) {
-            onLoadingStopped();
+            stopLoadProgress();
         }
 
-        @Override
-        public void onPageLoadFailed(Tab tab, int errorCode) {
-            onLoadingStopped();
-        }
-
-        @Override
-        public void onPageLoadFinished(Tab tab, String url) {
-            onLoadingStopped();
+        private void updateUrl(Tab tab) {
+            mModel.set(ProgressBarProperties.URL,
+                    UrlUtilities.getDomainAndRegistry(tab.getUrl(), false));
         }
     }
 }
\ No newline at end of file
diff --git a/chrome/android/touchless/junit/DEPS b/chrome/android/touchless/junit/DEPS
index 2e2fc77..81c3f45e 100644
--- a/chrome/android/touchless/junit/DEPS
+++ b/chrome/android/touchless/junit/DEPS
@@ -1,3 +1,4 @@
 include_rules = [
   "+components/feature_engagement/public",
+  "+content/public/android/java/src/org/chromium/content_public",
 ]
diff --git a/chrome/android/touchless/junit/src/org/chromium/chrome/browser/touchless/ui/progressbar/ProgressBarMediatorTest.java b/chrome/android/touchless/junit/src/org/chromium/chrome/browser/touchless/ui/progressbar/ProgressBarMediatorTest.java
index 5db6699..53c4811a 100644
--- a/chrome/android/touchless/junit/src/org/chromium/chrome/browser/touchless/ui/progressbar/ProgressBarMediatorTest.java
+++ b/chrome/android/touchless/junit/src/org/chromium/chrome/browser/touchless/ui/progressbar/ProgressBarMediatorTest.java
@@ -25,6 +25,7 @@
 import org.chromium.chrome.browser.tab.TabObserver;
 import org.chromium.chrome.browser.util.UrlConstants;
 import org.chromium.chrome.browser.util.test.ShadowUrlUtilities;
+import org.chromium.content_public.browser.NavigationHandle;
 import org.chromium.ui.modelutil.PropertyModel;
 
 /**
@@ -36,6 +37,7 @@
     private static final String SAMPLE_URL = "https://www.google.com/chrome";
     private static final String SAMPLE_URL_SHORT = "google.com";
 
+    private ProgressBarMediator mProgressBarMediator;
     private PropertyModel mModel;
     private ArgumentCaptor<TabObserver> mTabObserver;
     private Tab mTab;
@@ -48,32 +50,29 @@
                 return SAMPLE_URL_SHORT;
             }
         });
-    }
-
-    private ProgressBarMediator initProgressBarMediator() {
-        mModel = spy(new PropertyModel.Builder(ProgressBarProperties.ALL_KEYS).build());
+        mModel = new PropertyModel.Builder(ProgressBarProperties.ALL_KEYS).build();
         mTabObserver = ArgumentCaptor.forClass(TabObserver.class);
         mTab = mock(Tab.class);
         ActivityTabProvider activityTabProvider = spy(ActivityTabProvider.class);
         when(activityTabProvider.get()).thenReturn(mTab);
-        ProgressBarMediator progressBarMediator =
-                new ProgressBarMediator(mModel, activityTabProvider);
+        mProgressBarMediator = new ProgressBarMediator(mModel, activityTabProvider);
         verify(mTab).addObserver(mTabObserver.capture());
-        return progressBarMediator;
     }
 
     @Test
     public void visibilityTest() {
-        ProgressBarMediator progressBarMediator = initProgressBarMediator();
+        NavigationHandle navigationHandle = mock(NavigationHandle.class);
         Assert.assertEquals(mModel.get(ProgressBarProperties.IS_ENABLED), false);
         Assert.assertEquals(mModel.get(ProgressBarProperties.IS_VISIBLE), false);
 
-        mTabObserver.getValue().onPageLoadStarted(mTab, SAMPLE_URL);
+        when(navigationHandle.isInMainFrame()).thenReturn(true);
+        when(navigationHandle.getUrl()).thenReturn(SAMPLE_URL);
+        mTabObserver.getValue().onDidStartNavigation(mTab, navigationHandle);
         Assert.assertEquals(mModel.get(ProgressBarProperties.IS_ENABLED), true);
         Assert.assertEquals(mModel.get(ProgressBarProperties.IS_VISIBLE), true);
 
         // Mock page load finish, but not display timeout. The progress bar should still be visible.
-        mTabObserver.getValue().onPageLoadFinished(mTab, SAMPLE_URL);
+        mTabObserver.getValue().onLoadStopped(mTab, true);
         Assert.assertEquals(mModel.get(ProgressBarProperties.IS_ENABLED), true);
         Assert.assertEquals(mModel.get(ProgressBarProperties.IS_VISIBLE), true);
 
@@ -83,7 +82,7 @@
         Assert.assertEquals(mModel.get(ProgressBarProperties.IS_VISIBLE), false);
 
         // The progress bar should be shown on activity resume.
-        progressBarMediator.onActivityResume();
+        mProgressBarMediator.onActivityResume();
         Assert.assertEquals(mModel.get(ProgressBarProperties.IS_ENABLED), true);
         Assert.assertEquals(mModel.get(ProgressBarProperties.IS_VISIBLE), true);
 
@@ -93,12 +92,14 @@
         Assert.assertEquals(mModel.get(ProgressBarProperties.IS_VISIBLE), false);
 
         // The progress bar should be disabled for native pages.
-        mTabObserver.getValue().onPageLoadStarted(mTab, UrlConstants.NTP_URL);
+        when(navigationHandle.getUrl()).thenReturn(UrlConstants.NTP_URL);
+        mTabObserver.getValue().onDidStartNavigation(mTab, navigationHandle);
         Assert.assertEquals(mModel.get(ProgressBarProperties.IS_ENABLED), false);
         Assert.assertEquals(mModel.get(ProgressBarProperties.IS_VISIBLE), false);
 
         // Mock display timeout before page load finish.
-        mTabObserver.getValue().onPageLoadStarted(mTab, SAMPLE_URL);
+        when(navigationHandle.getUrl()).thenReturn(SAMPLE_URL);
+        mTabObserver.getValue().onDidStartNavigation(mTab, navigationHandle);
         ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
         Assert.assertEquals(mModel.get(ProgressBarProperties.IS_ENABLED), true);
         Assert.assertEquals(mModel.get(ProgressBarProperties.IS_VISIBLE), true);
@@ -106,9 +107,14 @@
 
     @Test
     public void progressAndUrlTest() {
-        initProgressBarMediator();
         Assert.assertNull(mModel.get(ProgressBarProperties.URL));
 
+        NavigationHandle navigationHandle = mock(NavigationHandle.class);
+        when(navigationHandle.isInMainFrame()).thenReturn(true);
+        when(navigationHandle.getUrl()).thenReturn(SAMPLE_URL);
+
+        mTabObserver.getValue().onDidStartNavigation(mTab, navigationHandle);
+
         when(mTab.getUrl()).thenReturn(SAMPLE_URL);
         mTabObserver.getValue().onLoadProgressChanged(mTab, 10);
         Assert.assertEquals(mModel.get(ProgressBarProperties.PROGRESS_FRACTION), .1, .001);
diff --git a/chrome/app/chrome_exe_main_win.cc b/chrome/app/chrome_exe_main_win.cc
index 2fdad636..3ea9acc 100644
--- a/chrome/app/chrome_exe_main_win.cc
+++ b/chrome/app/chrome_exe_main_win.cc
@@ -15,6 +15,7 @@
 #include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/path_service.h"
+#include "base/process/memory.h"
 #include "base/stl_util.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_split.h"
@@ -177,6 +178,10 @@
   install_static::InitializeFromPrimaryModule();
   SignalInitializeCrashReporting();
 
+  // Done here to ensure that OOMs that happen early in process initialization
+  // are correctly signaled to the OS.
+  base::EnableTerminationOnOutOfMemory();
+
   // Initialize the CommandLine singleton from the environment.
   base::CommandLine::Init(0, nullptr);
   const base::CommandLine* command_line =
diff --git a/chrome/browser/android/autofill_assistant/client_android.cc b/chrome/browser/android/autofill_assistant/client_android.cc
index 472c45b4..bbbe7a2 100644
--- a/chrome/browser/android/autofill_assistant/client_android.cc
+++ b/chrome/browser/android/autofill_assistant/client_android.cc
@@ -124,7 +124,7 @@
   GURL initial_url(base::android::ConvertJavaStringToUTF8(env, jinitial_url));
   std::map<std::string, std::string> parameters;
   FillParametersFromJava(env, parameterNames, parameterValues, &parameters);
-  controller_->Start(initial_url, std::make_unique<TriggerContext>(
+  controller_->Start(initial_url, TriggerContext::Create(
                                       std::move(parameters),
                                       base::android::ConvertJavaStringToUTF8(
                                           env, jexperiment_ids)));
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.cc b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
index b246f963..99cf812 100644
--- a/chrome/browser/android/autofill_assistant/ui_controller_android.cc
+++ b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
@@ -403,13 +403,13 @@
   int user_action_count = static_cast<int>(user_actions.size());
   for (int i = 0; i < user_action_count; i++) {
     const auto& user_action = user_actions[i];
-    if (user_action.chip.type != SUGGESTION)
+    if (user_action.chip().type != SUGGESTION)
       continue;
 
     Java_AutofillAssistantUiController_addSuggestion(
         env, java_object_, chips,
-        base::android::ConvertUTF8ToJavaString(env, user_action.chip.text), i,
-        user_action.chip.icon, !user_action.enabled);
+        base::android::ConvertUTF8ToJavaString(env, user_action.chip().text), i,
+        user_action.chip().icon, !user_action.enabled());
   }
   Java_AutofillAssistantUiController_setSuggestions(env, java_object_, chips);
 }
@@ -425,7 +425,7 @@
   int user_action_count = static_cast<int>(user_actions.size());
   for (int i = 0; i < user_action_count; i++) {
     const auto& action = user_actions[i];
-    const Chip& chip = action.chip;
+    const Chip& chip = action.chip();
     switch (chip.type) {
       default:  // Ignore actions with other chip types or with no chips.
         break;
@@ -434,14 +434,14 @@
         Java_AutofillAssistantUiController_addHighlightedActionButton(
             env, java_object_, chips, chip.icon,
             base::android::ConvertUTF8ToJavaString(env, chip.text), i,
-            !action.enabled, chip.sticky);
+            !action.enabled(), chip.sticky);
         break;
 
       case NORMAL_ACTION:
         Java_AutofillAssistantUiController_addActionButton(
             env, java_object_, chips, chip.icon,
             base::android::ConvertUTF8ToJavaString(env, chip.text), i,
-            !action.enabled, chip.sticky);
+            !action.enabled(), chip.sticky);
         break;
 
       case CANCEL_ACTION:
@@ -450,7 +450,7 @@
         Java_AutofillAssistantUiController_addCancelButton(
             env, java_object_, chips, chip.icon,
             base::android::ConvertUTF8ToJavaString(env, chip.text), i,
-            !action.enabled, chip.sticky);
+            !action.enabled(), chip.sticky);
         has_close_or_cancel = true;
         break;
 
@@ -458,7 +458,7 @@
         Java_AutofillAssistantUiController_addActionButton(
             env, java_object_, chips, chip.icon,
             base::android::ConvertUTF8ToJavaString(env, chip.text), i,
-            !action.enabled, chip.sticky);
+            !action.enabled(), chip.sticky);
         has_close_or_cancel = true;
         break;
 
@@ -466,7 +466,7 @@
         Java_AutofillAssistantUiController_addHighlightedActionButton(
             env, java_object_, chips, chip.icon,
             base::android::ConvertUTF8ToJavaString(env, chip.text), i,
-            !action.enabled, chip.sticky);
+            !action.enabled(), chip.sticky);
         has_close_or_cancel = true;
         break;
     }
diff --git a/chrome/browser/android/chrome_backup_agent.cc b/chrome/browser/android/chrome_backup_agent.cc
index 524cffa..adef943 100644
--- a/chrome/browser/android/chrome_backup_agent.cc
+++ b/chrome/browser/android/chrome_backup_agent.cc
@@ -33,13 +33,13 @@
     syncer::prefs::kSyncPasswords,
     syncer::prefs::kSyncPreferences,
     syncer::prefs::kSyncPriorityPreferences,
+    syncer::prefs::kSyncRequested,
     syncer::prefs::kSyncSessions,
     syncer::prefs::kSyncSupervisedUserSettings,
     syncer::prefs::kSyncSupervisedUserSharedSettings,
     syncer::prefs::kSyncSupervisedUserWhitelists,
     syncer::prefs::kSyncTabs,
     syncer::prefs::kSyncTypedUrls,
-    syncer::prefs::kSyncSuppressStart,
 };
 
 }  // namespace
diff --git a/chrome/browser/autofill/manual_filling_controller_impl.cc b/chrome/browser/autofill/manual_filling_controller_impl.cc
index 27c52609..627b3a74 100644
--- a/chrome/browser/autofill/manual_filling_controller_impl.cc
+++ b/chrome/browser/autofill/manual_filling_controller_impl.cc
@@ -10,12 +10,14 @@
 #include "base/metrics/histogram_macros.h"
 #include "chrome/browser/autofill/address_accessory_controller.h"
 #include "chrome/browser/autofill/credit_card_accessory_controller.h"
+#include "chrome/browser/password_manager/chrome_password_manager_client.h"
 #include "chrome/browser/password_manager/password_accessory_controller.h"
 #include "chrome/browser/password_manager/password_accessory_metrics_util.h"
 #include "chrome/browser/password_manager/touch_to_fill_controller.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/autofill/core/common/autofill_features.h"
 #include "components/autofill/core/common/autofill_util.h"
+#include "components/password_manager/core/browser/credential_cache.h"
 #include "content/public/browser/web_contents.h"
 
 using autofill::AccessoryAction;
@@ -150,21 +152,30 @@
 void ManualFillingControllerImpl::OnFillingTriggered(
     AccessoryTabType type,
     const autofill::UserInfo::Field& selection) {
-  GetControllerForTab(type)->OnFillingTriggered(selection);
+  AccessoryController* controller = GetControllerForTab(type);
+  if (!controller)
+    return;  // Controller not available anymore.
+  controller->OnFillingTriggered(selection);
 }
 
 void ManualFillingControllerImpl::OnOptionSelected(
     AccessoryAction selected_action) const {
   UMA_HISTOGRAM_ENUMERATION("KeyboardAccessory.AccessoryActionSelected",
                             selected_action, AccessoryAction::COUNT);
-  GetControllerForAction(selected_action)->OnOptionSelected(selected_action);
+  AccessoryController* controller = GetControllerForAction(selected_action);
+  if (!controller)
+    return;  // Controller not available anymore.
+  controller->OnOptionSelected(selected_action);
 }
 
 void ManualFillingControllerImpl::GetFavicon(
     int desired_size_in_pixel,
     base::OnceCallback<void(const gfx::Image&)> icon_callback) {
-  DCHECK(pwd_controller_);
-  pwd_controller_->GetFavicon(desired_size_in_pixel, std::move(icon_callback));
+  // TODO(crbug.com/945300): This should request favicons directly.
+  PasswordAccessoryController* controller = GetPasswordController();
+  if (!controller)
+    return;  // Controller not available anymore.
+  controller->GetFavicon(desired_size_in_pixel, std::move(icon_callback));
 }
 
 gfx::NativeView ManualFillingControllerImpl::container_view() const {
@@ -188,11 +199,6 @@
 ManualFillingControllerImpl::ManualFillingControllerImpl(
     content::WebContents* web_contents)
     : web_contents_(web_contents) {
-  if (PasswordAccessoryController::AllowedForWebContents(web_contents)) {
-    pwd_controller_ =
-        PasswordAccessoryController::GetOrCreate(web_contents)->AsWeakPtr();
-    DCHECK(pwd_controller_);
-  }
   if (AddressAccessoryController::AllowedForWebContents(web_contents)) {
     address_controller_ =
         AddressAccessoryController::GetOrCreate(web_contents)->AsWeakPtr();
@@ -217,7 +223,7 @@
     base::WeakPtr<CreditCardAccessoryController> cc_controller,
     std::unique_ptr<ManualFillingViewInterface> view)
     : web_contents_(web_contents),
-      pwd_controller_(std::move(pwd_controller)),
+      pwd_controller_for_testing_(std::move(pwd_controller)),
       address_controller_(std::move(address_controller)),
       cc_controller_(std::move(cc_controller)),
       view_(std::move(view)) {}
@@ -274,7 +280,7 @@
     case AccessoryTabType::ADDRESSES:
       return address_controller_.get();
     case AccessoryTabType::PASSWORDS:
-      return pwd_controller_.get();
+      return GetPasswordController();
     case AccessoryTabType::CREDIT_CARDS:
       return cc_controller_.get();
     case AccessoryTabType::TOUCH_TO_FILL:
@@ -293,7 +299,7 @@
     case AccessoryAction::GENERATE_PASSWORD_MANUAL:
     case AccessoryAction::MANAGE_PASSWORDS:
     case AccessoryAction::GENERATE_PASSWORD_AUTOMATIC:
-      return pwd_controller_.get();
+      return GetPasswordController();
     case AccessoryAction::MANAGE_ADDRESSES:
       return address_controller_.get();
     case AccessoryAction::MANAGE_CREDIT_CARDS:
@@ -307,4 +313,15 @@
   return nullptr;
 }
 
+PasswordAccessoryController*
+ManualFillingControllerImpl::GetPasswordController() const {
+  if (pwd_controller_for_testing_)
+    return pwd_controller_for_testing_.get();
+
+  return PasswordAccessoryController::AllowedForWebContents(web_contents_)
+             ? ChromePasswordManagerClient::FromWebContents(web_contents_)
+                   ->GetOrCreatePasswordAccessory()
+             : nullptr;
+}
+
 WEB_CONTENTS_USER_DATA_KEY_IMPL(ManualFillingControllerImpl)
diff --git a/chrome/browser/autofill/manual_filling_controller_impl.h b/chrome/browser/autofill/manual_filling_controller_impl.h
index 435facf..2624aa1b 100644
--- a/chrome/browser/autofill/manual_filling_controller_impl.h
+++ b/chrome/browser/autofill/manual_filling_controller_impl.h
@@ -67,10 +67,6 @@
   // Returns the held view for testing.
   ManualFillingViewInterface* view() const { return view_.get(); }
 #endif  // defined(UNIT_TEST)
-  // Returns the connected password accessory controller for testing.
-  PasswordAccessoryController* password_controller_for_testing() const {
-    return pwd_controller_.get();
-  }
 
  protected:
   friend class ManualFillingController;  // Allow protected access in factories.
@@ -108,6 +104,9 @@
   AccessoryController* GetControllerForAction(
       autofill::AccessoryAction action) const;
 
+  // Returns the controller that is responsible for a given |action|.
+  PasswordAccessoryController* GetPasswordController() const;
+
   // The tab for which this class is scoped.
   content::WebContents* web_contents_;
 
@@ -120,11 +119,9 @@
 
   // Controllers which handle events relating to a specific tab and the
   // associated data.
-  base::WeakPtr<PasswordAccessoryController> pwd_controller_;
+  base::WeakPtr<PasswordAccessoryController> pwd_controller_for_testing_;
   base::WeakPtr<autofill::AddressAccessoryController> address_controller_;
   base::WeakPtr<autofill::CreditCardAccessoryController> cc_controller_;
-
-  // The touch to fill controller object to forward view requests to.
   base::WeakPtr<TouchToFillController> touch_to_fill_controller_;
 
   // Hold the native instance of the view. Must be last declared and initialized
diff --git a/chrome/browser/bookmarks/chrome_bookmark_client.cc b/chrome/browser/bookmarks/chrome_bookmark_client.cc
index 1bad4d8..97b04c2b 100644
--- a/chrome/browser/bookmarks/chrome_bookmark_client.cc
+++ b/chrome/browser/bookmarks/chrome_bookmark_client.cc
@@ -105,11 +105,11 @@
   base::RecordAction(action);
 }
 
-bookmarks::LoadExtraCallback ChromeBookmarkClient::GetLoadExtraNodesCallback() {
+bookmarks::LoadExtraCallback ChromeBookmarkClient::GetLoadExtraNodeCallback() {
   if (!managed_bookmark_service_)
     return bookmarks::LoadExtraCallback();
 
-  return managed_bookmark_service_->GetLoadExtraNodesCallback();
+  return managed_bookmark_service_->GetLoadExtraNodeCallback();
 }
 
 bool ChromeBookmarkClient::CanSetPermanentNodeTitle(
diff --git a/chrome/browser/bookmarks/chrome_bookmark_client.h b/chrome/browser/bookmarks/chrome_bookmark_client.h
index 705c118b..59226530 100644
--- a/chrome/browser/bookmarks/chrome_bookmark_client.h
+++ b/chrome/browser/bookmarks/chrome_bookmark_client.h
@@ -54,7 +54,7 @@
   bool IsPermanentNodeVisible(
       const bookmarks::BookmarkPermanentNode* node) override;
   void RecordAction(const base::UserMetricsAction& action) override;
-  bookmarks::LoadExtraCallback GetLoadExtraNodesCallback() override;
+  bookmarks::LoadExtraCallback GetLoadExtraNodeCallback() override;
   bool CanSetPermanentNodeTitle(
       const bookmarks::BookmarkNode* permanent_node) override;
   bool CanSyncNode(const bookmarks::BookmarkNode* node) override;
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index b9a6f50..ee9702c 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -3463,6 +3463,9 @@
             ? content::AutoplayPolicy::kDocumentUserActivationRequired
             : content::AutoplayPolicy::kNoUserGestureRequired;
   }
+  web_prefs->forced_colors = native_theme->UsesHighContrastColors()
+                                 ? blink::ForcedColors::kActive
+                                 : blink::ForcedColors::kNone;
   web_prefs->preferred_color_scheme = native_theme->SystemDarkModeEnabled()
                                           ? blink::PreferredColorScheme::kDark
                                           : blink::PreferredColorScheme::kLight;
diff --git a/chrome/browser/chrome_content_browser_client_browsertest.cc b/chrome/browser/chrome_content_browser_client_browsertest.cc
index 389323c..f1da002c 100644
--- a/chrome/browser/chrome_content_browser_client_browsertest.cc
+++ b/chrome/browser/chrome_content_browser_client_browsertest.cc
@@ -666,6 +666,71 @@
 
 INSTANTIATE_TEST_SUITE_P(All, PrefersColorSchemeTest, testing::Bool());
 
+class ForcedColorsTest : public testing::WithParamInterface<bool>,
+                         public InProcessBrowserTest {
+ protected:
+  ForcedColorsTest() : theme_client_(&test_theme_) {}
+
+  ~ForcedColorsTest() {
+    CHECK_EQ(&theme_client_, SetBrowserClientForTesting(original_client_));
+  }
+
+  const char* ExpectedForcedColors() const {
+    return GetParam() ? "active" : "none";
+  }
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    InProcessBrowserTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitchASCII(switches::kEnableBlinkFeatures,
+                                    "ForcedColors");
+  }
+
+  void SetUpOnMainThread() override {
+    InProcessBrowserTest::SetUpOnMainThread();
+    original_client_ = SetBrowserClientForTesting(&theme_client_);
+  }
+
+ protected:
+  ui::TestNativeTheme test_theme_;
+
+ private:
+  content::ContentBrowserClient* original_client_ = nullptr;
+
+  class ChromeContentBrowserClientWithWebTheme
+      : public ChromeContentBrowserClient {
+   public:
+    explicit ChromeContentBrowserClientWithWebTheme(
+        const ui::NativeTheme* theme)
+        : theme_(theme) {}
+
+   protected:
+    const ui::NativeTheme* GetWebTheme() const override { return theme_; }
+
+   private:
+    const ui::NativeTheme* const theme_;
+  };
+
+  ChromeContentBrowserClientWithWebTheme theme_client_;
+};
+
+IN_PROC_BROWSER_TEST_P(ForcedColorsTest, ForcedColors) {
+  test_theme_.SetUsesHighContrastColors(GetParam());
+  browser()
+      ->tab_strip_model()
+      ->GetActiveWebContents()
+      ->GetRenderViewHost()
+      ->OnWebkitPreferencesChanged();
+  ui_test_utils::NavigateToURL(
+      browser(), ui_test_utils::GetTestUrl(
+                     base::FilePath(base::FilePath::kCurrentDirectory),
+                     base::FilePath(FILE_PATH_LITERAL("forced-colors.html"))));
+  base::string16 tab_title;
+  ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(), &tab_title));
+  EXPECT_EQ(base::ASCIIToUTF16(ExpectedForcedColors()), tab_title);
+}
+
+INSTANTIATE_TEST_SUITE_P(All, ForcedColorsTest, testing::Bool());
+
 class ProtocolHandlerTest : public InProcessBrowserTest {
  public:
   ProtocolHandlerTest() = default;
diff --git a/chrome/browser/chrome_notification_types.h b/chrome/browser/chrome_notification_types.h
index 33fe370..9176955 100644
--- a/chrome/browser/chrome_notification_types.h
+++ b/chrome/browser/chrome_notification_types.h
@@ -191,12 +191,6 @@
   // Source is the WebContents that holds the print job.
   NOTIFICATION_PRINT_JOB_RELEASED,
 
-  // Content Settings --------------------------------------------------------
-
-  // Sent when content settings change for a tab. The source is a
-  // content::WebContents object, the details are None.
-  NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
-
   // Cookies -----------------------------------------------------------------
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
diff --git a/chrome/browser/chromeos/login/enrollment/enrollment_local_policy_server_browsertest.cc b/chrome/browser/chromeos/login/enrollment/enrollment_local_policy_server_browsertest.cc
index c00f5fa..ef992b12 100644
--- a/chrome/browser/chromeos/login/enrollment/enrollment_local_policy_server_browsertest.cc
+++ b/chrome/browser/chromeos/login/enrollment/enrollment_local_policy_server_browsertest.cc
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "ash/public/cpp/login_screen_test_api.h"
 #include "base/bind.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.h"
 #include "chrome/browser/chromeos/login/enrollment/enrollment_screen.h"
 #include "chrome/browser/chromeos/login/enrollment/enrollment_screen_view.h"
@@ -38,6 +40,7 @@
 #include "components/policy/core/common/policy_switches.h"
 #include "components/policy/test_support/local_policy_test_server.h"
 #include "components/strings/grit/components_strings.h"
+#include "content/public/test/test_utils.h"
 
 namespace chromeos {
 
@@ -757,4 +760,41 @@
   EXPECT_TRUE(InstallAttributes::Get()->IsCloudManaged());
 }
 
+class OobeGuestButtonPolicy : public testing::WithParamInterface<bool>,
+                              public EnrollmentLocalPolicyServerBase {
+ public:
+  OobeGuestButtonPolicy() = default;
+
+  void SetUpOnMainThread() override {
+    enterprise_management::ChromeDeviceSettingsProto proto;
+    proto.mutable_guest_mode_enabled()->set_guest_mode_enabled(GetParam());
+    policy_server_.UpdateDevicePolicy(proto);
+    EnrollmentLocalPolicyServerBase::SetUpOnMainThread();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(OobeGuestButtonPolicy);
+};
+
+IN_PROC_BROWSER_TEST_P(OobeGuestButtonPolicy, VisibilityAfterEnrollment) {
+  TriggerEnrollmentAndSignInSuccessfully();
+  enrollment_ui_.WaitForStep(test::ui::kEnrollmentStepSuccess);
+  enrollment_screen()->OnConfirmationClosed();
+  OobeScreenWaiter(GaiaView::kScreenId).Wait();
+
+  ASSERT_EQ(GetParam(),
+            user_manager::UserManager::Get()->IsGuestSessionAllowed());
+  EXPECT_EQ(GetParam(), ash::LoginScreenTestApi::IsGuestButtonShown());
+
+  test::ExecuteOobeJS("chrome.send('showGuestInOobe', [false]);");
+  EXPECT_FALSE(ash::LoginScreenTestApi::IsGuestButtonShown());
+
+  test::ExecuteOobeJS("chrome.send('showGuestInOobe', [true]);");
+  EXPECT_EQ(GetParam(), ash::LoginScreenTestApi::IsGuestButtonShown());
+}
+
+INSTANTIATE_TEST_SUITE_P(/* no prefix */,
+                         OobeGuestButtonPolicy,
+                         ::testing::Bool());
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/login_screen_policy_browsertest.cc b/chrome/browser/chromeos/login/login_screen_policy_browsertest.cc
index 3b2a2e6..e5337851 100644
--- a/chrome/browser/chromeos/login/login_screen_policy_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_screen_policy_browsertest.cc
@@ -2,6 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "ash/public/cpp/login_screen.h"
+#include "ash/public/cpp/login_screen_model.h"
+#include "ash/public/cpp/login_screen_test_api.h"
+#include "ash/public/cpp/login_types.h"
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/memory/ref_counted.h"
@@ -10,9 +14,11 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/login/startup_utils.h"
+#include "chrome/browser/chromeos/login/test/js_checker.h"
 #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
+#include "chrome/browser/ui/ash/login_screen_client.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "chromeos/constants/chromeos_switches.h"
@@ -32,11 +38,21 @@
 
 class LoginScreenPolicyTest : public policy::DevicePolicyCrosBrowserTest {
  public:
+  LoginScreenPolicyTest() = default;
+
   void RefreshDevicePolicyAndWaitForSettingChange(
       const char* cros_setting_name);
 
  protected:
+  void WaitForLoginScreen() {
+    content::WindowedNotificationObserver(
+        chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
+        content::NotificationService::AllSources())
+        .Wait();
+  }
+
   void SetUpCommandLine(base::CommandLine* command_line) override {
+    policy::DevicePolicyCrosBrowserTest::SetUpCommandLine(command_line);
     command_line->AppendSwitch(switches::kLoginManager);
     command_line->AppendSwitch(switches::kForceLoginManagerInTests);
   }
@@ -46,7 +62,11 @@
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(&chrome::AttemptExit));
     base::RunLoop().RunUntilIdle();
+    policy::DevicePolicyCrosBrowserTest::TearDownOnMainThread();
   }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LoginScreenPolicyTest);
 };
 
 void LoginScreenPolicyTest::RefreshDevicePolicyAndWaitForSettingChange(
@@ -62,10 +82,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(LoginScreenPolicyTest, RestrictInputMethods) {
-  content::WindowedNotificationObserver(
-      chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
-      content::NotificationService::AllSources())
-      .Wait();
+  WaitForLoginScreen();
 
   input_method::InputMethodManager* imm =
       input_method::InputMethodManager::Get();
@@ -91,10 +108,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(LoginScreenPolicyTest, PolicyInputMethodsListEmpty) {
-  content::WindowedNotificationObserver(
-      chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
-      content::NotificationService::AllSources())
-      .Wait();
+  WaitForLoginScreen();
 
   input_method::InputMethodManager* imm =
       input_method::InputMethodManager::Get();
@@ -113,6 +127,71 @@
   ASSERT_EQ(0U, imm->GetActiveIMEState()->GetAllowedInputMethods().size());
 }
 
+class LoginScreenGuestButtonPolicy : public LoginScreenPolicyTest {
+ public:
+  LoginScreenGuestButtonPolicy() {
+    device_state_.SetState(
+        DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LoginScreenGuestButtonPolicy);
+};
+
+IN_PROC_BROWSER_TEST_F(LoginScreenGuestButtonPolicy, NoUsers) {
+  WaitForLoginScreen();
+
+  // Default.
+  EXPECT_TRUE(ash::LoginScreenTestApi::IsGuestButtonShown());
+
+  // When there are no users - should be the same as OOBE.
+  test::ExecuteOobeJS("chrome.send('showGuestInOobe', [false]);");
+  EXPECT_FALSE(ash::LoginScreenTestApi::IsGuestButtonShown());
+
+  test::ExecuteOobeJS("chrome.send('showGuestInOobe', [true]);");
+  EXPECT_TRUE(ash::LoginScreenTestApi::IsGuestButtonShown());
+
+  {
+    em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
+    proto.mutable_guest_mode_enabled()->set_guest_mode_enabled(false);
+    RefreshDevicePolicyAndWaitForSettingChange(
+        chromeos::kAccountsPrefAllowGuest);
+
+    EXPECT_FALSE(ash::LoginScreenTestApi::IsGuestButtonShown());
+
+    test::ExecuteOobeJS("chrome.send('showGuestInOobe', [true]);");
+    // Should not affect.
+    EXPECT_FALSE(ash::LoginScreenTestApi::IsGuestButtonShown());
+  }
+
+  {
+    em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
+    proto.mutable_guest_mode_enabled()->set_guest_mode_enabled(true);
+    RefreshDevicePolicyAndWaitForSettingChange(
+        chromeos::kAccountsPrefAllowGuest);
+
+    EXPECT_TRUE(ash::LoginScreenTestApi::IsGuestButtonShown());
+  }
+}
+
+IN_PROC_BROWSER_TEST_F(LoginScreenGuestButtonPolicy, HasUsers) {
+  WaitForLoginScreen();
+  EXPECT_TRUE(ash::LoginScreenTestApi::IsGuestButtonShown());
+
+  ash::LoginScreen::Get()->GetModel()->SetUserList({{}});
+  EXPECT_FALSE(ash::LoginScreenTestApi::IsGuestButtonShown());
+
+  // Should not affect.
+  test::ExecuteOobeJS("chrome.send('showGuestInOobe', [true]);");
+  EXPECT_FALSE(ash::LoginScreenTestApi::IsGuestButtonShown());
+
+  ash::LoginScreen::Get()->GetModel()->SetUserList({});
+  EXPECT_TRUE(ash::LoginScreenTestApi::IsGuestButtonShown());
+
+  test::ExecuteOobeJS("chrome.send('showGuestInOobe', [false]);");
+  EXPECT_FALSE(ash::LoginScreenTestApi::IsGuestButtonShown());
+}
+
 class LoginScreenLocalePolicyTest : public LoginScreenPolicyTest {
  protected:
   LoginScreenLocalePolicyTest() {}
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index 72383a3e..e90abd2a 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -1493,7 +1493,7 @@
 }
 
 void WizardController::OnGuestModePolicyUpdated() {
-  ash::LoginScreen::Get()->ShowGuestButtonInOobe(
+  ash::LoginScreen::Get()->SetAllowLoginAsGuest(
       user_manager::UserManager::Get()->IsGuestSessionAllowed());
 }
 
diff --git a/chrome/browser/chromeos/net/client_cert_store_chromeos_unittest.cc b/chrome/browser/chromeos/net/client_cert_store_chromeos_unittest.cc
index 954d7b1c..01b55771 100644
--- a/chrome/browser/chromeos/net/client_cert_store_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/net/client_cert_store_chromeos_unittest.cc
@@ -124,8 +124,7 @@
   ASSERT_TRUE(cert_1.get());
 
   // Request any client certificate, which is expected to match client_1.
-  scoped_refptr<net::SSLCertRequestInfo> request_all(
-      new net::SSLCertRequestInfo());
+  auto request_all = base::MakeRefCounted<net::SSLCertRequestInfo>();
 
   net::ClientCertIdentityList selected_identities;
   base::RunLoop run_loop;
@@ -163,8 +162,7 @@
       "client_1.pem", "client_1.pk8", test_db.slot(), &nss_cert_1));
   ASSERT_TRUE(cert_1.get());
 
-  scoped_refptr<net::SSLCertRequestInfo> request_all(
-      new net::SSLCertRequestInfo());
+  auto request_all = base::MakeRefCounted<net::SSLCertRequestInfo>();
 
   base::RunLoop run_loop;
   net::ClientCertIdentityList selected_identities;
@@ -195,8 +193,7 @@
       "client_2.pem", "client_2.pk8", test_db.slot(), &nss_cert_2));
   ASSERT_TRUE(cert_2.get());
 
-  scoped_refptr<net::SSLCertRequestInfo> request_all(
-      new net::SSLCertRequestInfo());
+  auto request_all = base::MakeRefCounted<net::SSLCertRequestInfo>();
 
   {
     base::RunLoop run_loop;
@@ -254,7 +251,7 @@
   std::vector<std::string> authority_1(
       1, std::string(reinterpret_cast<const char*>(kAuthority1DN),
                      sizeof(kAuthority1DN)));
-  scoped_refptr<net::SSLCertRequestInfo> request(new net::SSLCertRequestInfo());
+  auto request = base::MakeRefCounted<net::SSLCertRequestInfo>();
   request->cert_authorities = authority_1;
 
   base::RunLoop run_loop;
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc b/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc
index 75ad099b..7762043 100644
--- a/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc
+++ b/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc
@@ -873,8 +873,7 @@
     content::BrowserContext* browser_context) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  scoped_refptr<net::SSLCertRequestInfo> cert_request_info(
-      new net::SSLCertRequestInfo);
+  auto cert_request_info = base::MakeRefCounted<net::SSLCertRequestInfo>();
 
   // Currently we do not pass down the requested certificate type to the net
   // layer, as it does not support filtering certificates by type. Rather, we
diff --git a/chrome/browser/content_settings/chrome_content_settings_utils.cc b/chrome/browser/content_settings/chrome_content_settings_utils.cc
index 663e7c1..12037091 100644
--- a/chrome/browser/content_settings/chrome_content_settings_utils.cc
+++ b/chrome/browser/content_settings/chrome_content_settings_utils.cc
@@ -6,6 +6,15 @@
 
 #include "base/metrics/histogram_macros.h"
 
+#if !defined(OS_ANDROID)
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/location_bar/location_bar.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "content/public/browser/web_contents.h"
+#endif
+
 namespace content_settings {
 
 void RecordMixedScriptAction(MixedScriptAction action) {
@@ -23,4 +32,19 @@
                             POPUPS_ACTION_COUNT);
 }
 
+void UpdateLocationBarUiForWebContents(content::WebContents* web_contents) {
+#if !defined(OS_ANDROID)
+  Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
+  if (!browser)
+    return;
+
+  if (browser->tab_strip_model()->GetActiveWebContents() != web_contents)
+    return;
+
+  LocationBar* location_bar = browser->window()->GetLocationBar();
+  if (location_bar)
+    location_bar->UpdateContentSettingsIcons();
+#endif
+}
+
 }  // namespace content_settings
diff --git a/chrome/browser/content_settings/chrome_content_settings_utils.h b/chrome/browser/content_settings/chrome_content_settings_utils.h
index 50429a6..de33fa2 100644
--- a/chrome/browser/content_settings/chrome_content_settings_utils.h
+++ b/chrome/browser/content_settings/chrome_content_settings_utils.h
@@ -5,10 +5,16 @@
 #ifndef CHROME_BROWSER_CONTENT_SETTINGS_CHROME_CONTENT_SETTINGS_UTILS_H_
 #define CHROME_BROWSER_CONTENT_SETTINGS_CHROME_CONTENT_SETTINGS_UTILS_H_
 
+#include "build/build_config.h"
+
 // Put utility functions only used by //chrome code here. If a function declared
 // here would be meaningfully shared with other platforms, consider moving it to
 // components/content_settings/core/browser/content_settings_utils.h.
 
+namespace content {
+class WebContents;
+}  // namespace content
+
 namespace content_settings {
 
 // UMA histogram for the mixed script shield. The enum values correspond to
@@ -54,6 +60,9 @@
 
 void RecordPopupsAction(PopupsAction action);
 
+// Calls UpdateContentSettingsIcons on the |LocationBar| for |web_contents|.
+void UpdateLocationBarUiForWebContents(content::WebContents* web_contents);
+
 }  // namespace content_settings
 
 #endif  // CHROME_BROWSER_CONTENT_SETTINGS_CHROME_CONTENT_SETTINGS_UTILS_H_
diff --git a/chrome/browser/content_settings/content_settings_browsertest.cc b/chrome/browser/content_settings/content_settings_browsertest.cc
index bc32d78..35f8704 100644
--- a/chrome/browser/content_settings/content_settings_browsertest.cc
+++ b/chrome/browser/content_settings/content_settings_browsertest.cc
@@ -12,7 +12,6 @@
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "chrome/browser/browsing_data/browsing_data_cookie_helper.h"
-#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/content_settings/cookie_settings_factory.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
@@ -21,10 +20,12 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/view_ids.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/interactive_test_utils.h"
 #include "chrome/test/base/test_launcher_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/content_settings/core/browser/cookie_settings.h"
@@ -33,8 +34,6 @@
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_handle.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_service.h"
 #include "content/public/browser/plugin_service.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
@@ -746,12 +745,6 @@
   TabSpecificContentSettings* tab_settings =
       TabSpecificContentSettings::FromWebContents(web_contents);
 
-  content::WindowedNotificationObserver javascript_content_blocked_observer(
-      chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
-      base::BindRepeating(&TabSpecificContentSettings::IsContentBlocked,
-                          base::Unretained(tab_settings),
-                          CONTENT_SETTINGS_TYPE_JAVASCRIPT));
-
   base::string16 expected_title(base::ASCIIToUTF16("Failed"));
   content::TitleWatcher title_watcher(web_contents, expected_title);
   title_watcher.AlsoWaitForTitle(base::ASCIIToUTF16("Imported"));
@@ -759,7 +752,8 @@
   ui_test_utils::NavigateToURL(browser(), http_url);
 
   // The import must be blocked.
-  javascript_content_blocked_observer.Wait();
+  ui_test_utils::WaitForViewVisibility(
+      browser(), VIEW_ID_CONTENT_SETTING_JAVASCRIPT, true);
   EXPECT_TRUE(tab_settings->IsContentBlocked(CONTENT_SETTINGS_TYPE_JAVASCRIPT));
   EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
 }
@@ -925,24 +919,16 @@
     // before the blocked content can be reported to the browser process.
     // See http://crbug.com/306702.
     // Therefore, when expecting blocked content, we must wait until it has been
-    // reported by checking IsContentBlocked() when notified that
-    // NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED. (It is not sufficient to wait
-    // for just the notification because the same notification is reported for
-    // other reasons and the notification contains no indication of what
-    // caused it.)
-    content::WindowedNotificationObserver javascript_content_blocked_observer(
-              chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
-              base::Bind(&TabSpecificContentSettings::IsContentBlocked,
-                                   base::Unretained(tab_settings),
-                                   CONTENT_SETTINGS_TYPE_JAVASCRIPT));
-
+    // reported by waiting for the appropriate icon to appear in the location
+    // bar, and checking IsContentBlocked().
     ui_test_utils::NavigateToURL(browser(), https_server_.GetURL(path));
 
     // Always wait for the page to load.
     EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
 
     if (expect_is_javascript_content_blocked) {
-      javascript_content_blocked_observer.Wait();
+      ui_test_utils::WaitForViewVisibility(
+          browser(), VIEW_ID_CONTENT_SETTING_JAVASCRIPT, true);
     } else {
       // Since there is no notification that content is not blocked and no
       // content is blocked when |expect_is_javascript_content_blocked| is
diff --git a/chrome/browser/content_settings/tab_specific_content_settings.cc b/chrome/browser/content_settings/tab_specific_content_settings.cc
index f521d5f78..604bf66d 100644
--- a/chrome/browser/content_settings/tab_specific_content_settings.cc
+++ b/chrome/browser/content_settings/tab_specific_content_settings.cc
@@ -20,7 +20,6 @@
 #include "chrome/browser/browsing_data/browsing_data_indexed_db_helper.h"
 #include "chrome/browser/browsing_data/browsing_data_local_storage_helper.h"
 #include "chrome/browser/browsing_data/cookies_tree_model.h"
-#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/content_settings/chrome_content_settings_utils.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
@@ -42,8 +41,6 @@
 #include "content/public/browser/navigation_details.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/navigation_handle.h"
-#include "content/public/browser/notification_registrar.h"
-#include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
@@ -335,11 +332,7 @@
 
   if (!status.blocked) {
     status.blocked = true;
-    // TODO: it would be nice to have a way of mocking this in tests.
-    content::NotificationService::current()->Notify(
-        chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
-        content::Source<WebContents>(web_contents()),
-        content::NotificationService::NoDetails());
+    content_settings::UpdateLocationBarUiForWebContents(web_contents());
 
     if (type == CONTENT_SETTINGS_TYPE_MIXEDSCRIPT) {
       content_settings::RecordMixedScriptAction(
@@ -394,12 +387,8 @@
     access_changed = true;
   }
 
-  if (access_changed) {
-    content::NotificationService::current()->Notify(
-        chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
-        content::Source<WebContents>(web_contents()),
-        content::NotificationService::NoDetails());
-  }
+  if (access_changed)
+    content_settings::UpdateLocationBarUiForWebContents(web_contents());
 }
 
 void TabSpecificContentSettings::OnCookiesRead(
@@ -564,10 +553,7 @@
     const GURL& requesting_origin,
     bool allowed) {
   geolocation_usages_state_.OnPermissionSet(requesting_origin, allowed);
-  content::NotificationService::current()->Notify(
-      chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
-      content::Source<WebContents>(web_contents()),
-      content::NotificationService::NoDetails());
+  content_settings::UpdateLocationBarUiForWebContents(web_contents());
 }
 
 #if defined(OS_ANDROID) || defined(OS_CHROMEOS)
@@ -665,10 +651,7 @@
 
   if (microphone_camera_state_ != new_microphone_camera_state) {
     microphone_camera_state_ = new_microphone_camera_state;
-    content::NotificationService::current()->Notify(
-        chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
-        content::Source<WebContents>(web_contents()),
-        content::NotificationService::NoDetails());
+    content_settings::UpdateLocationBarUiForWebContents(web_contents());
   }
 }
 
@@ -695,10 +678,7 @@
   }
   microphone_camera_state_ = MICROPHONE_CAMERA_NOT_ACCESSED;
   load_plugins_link_enabled_ = true;
-  content::NotificationService::current()->Notify(
-      chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
-      content::Source<WebContents>(web_contents()),
-      content::NotificationService::NoDetails());
+  content_settings::UpdateLocationBarUiForWebContents(web_contents());
 }
 
 void TabSpecificContentSettings::ClearNavigationRelatedContentSettings() {
@@ -711,10 +691,7 @@
     status.blocked = false;
     status.allowed = false;
   }
-  content::NotificationService::current()->Notify(
-      chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
-      content::Source<WebContents>(web_contents()),
-      content::NotificationService::NoDetails());
+  content_settings::UpdateLocationBarUiForWebContents(web_contents());
 }
 
 void TabSpecificContentSettings::FlashDownloadBlocked() {
@@ -726,10 +703,7 @@
   ContentSettingsStatus& status =
       content_settings_status_[CONTENT_SETTINGS_TYPE_POPUPS];
   status.blocked = false;
-  content::NotificationService::current()->Notify(
-      chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
-      content::Source<WebContents>(web_contents()),
-      content::NotificationService::NoDetails());
+  content_settings::UpdateLocationBarUiForWebContents(web_contents());
 }
 
 void TabSpecificContentSettings::OnAudioBlocked() {
diff --git a/chrome/browser/download/download_request_limiter.cc b/chrome/browser/download/download_request_limiter.cc
index 1cf321f..9b375961 100644
--- a/chrome/browser/download/download_request_limiter.cc
+++ b/chrome/browser/download/download_request_limiter.cc
@@ -11,7 +11,7 @@
 #include "base/stl_util.h"
 #include "base/task/post_task.h"
 #include "build/build_config.h"
-#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/content_settings/chrome_content_settings_utils.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/download/download_permission_request.h"
 #include "chrome/browser/permissions/permission_request_manager.h"
@@ -25,7 +25,6 @@
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/navigation_handle.h"
-#include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/resource_dispatcher_host.h"
 #include "content/public/browser/web_contents.h"
@@ -433,10 +432,7 @@
     return;
   }
 
-  content::NotificationService::current()->Notify(
-      chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
-      content::Source<content::WebContents>(web_contents()),
-      content::NotificationService::NoDetails());
+  content_settings::UpdateLocationBarUiForWebContents(web_contents());
 }
 
 bool DownloadRequestLimiter::TabDownloadState::IsNavigationRestricted(
diff --git a/chrome/browser/download/drag_download_item_aura.cc b/chrome/browser/download/drag_download_item_aura.cc
index b801206..d88c068 100644
--- a/chrome/browser/download/drag_download_item_aura.cc
+++ b/chrome/browser/download/drag_download_item_aura.cc
@@ -40,12 +40,12 @@
     return;
 
   // Set up our OLE machinery
-  ui::OSExchangeData data;
+  auto data = std::make_unique<ui::OSExchangeData>();
 
   button_drag_utils::SetDragImage(
       GURL(), download->GetFileNameToReportUser().BaseName().LossyDisplayName(),
       icon ? icon->AsImageSkia() : gfx::ImageSkia(), nullptr,
-      *views::Widget::GetTopLevelWidgetForNativeView(view), &data);
+      *views::Widget::GetTopLevelWidgetForNativeView(view), data.get());
 
   base::FilePath full_path = download->GetTargetFilePath();
 #if defined(OS_CHROMEOS)
@@ -61,13 +61,13 @@
   std::vector<ui::FileInfo> file_infos;
   file_infos.push_back(
       ui::FileInfo(full_path, download->GetFileNameToReportUser()));
-  data.SetFilenames(file_infos);
+  data->SetFilenames(file_infos);
 
   gfx::Point location = display::Screen::GetScreen()->GetCursorScreenPoint();
   // TODO(varunjain): Properly determine and send DRAG_EVENT_SOURCE below.
   aura::client::GetDragDropClient(root_window)
       ->StartDragAndDrop(
-          data, root_window, view, location,
+          std::move(data), root_window, view, location,
           ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_LINK,
           ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
 }
diff --git a/chrome/browser/enterprise_reporting/profile_report_generator.cc b/chrome/browser/enterprise_reporting/profile_report_generator.cc
index a45a697..91065a7 100644
--- a/chrome/browser/enterprise_reporting/profile_report_generator.cc
+++ b/chrome/browser/enterprise_reporting/profile_report_generator.cc
@@ -5,6 +5,8 @@
 #include "chrome/browser/enterprise_reporting/profile_report_generator.h"
 
 #include "base/files/file_path.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/enterprise_reporting/extension_info.h"
 #include "chrome/browser/profiles/profile.h"
@@ -12,10 +14,12 @@
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "components/signin/core/browser/account_info.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
+#include "content/public/browser/plugin_service.h"
+#include "content/public/common/webplugininfo.h"
 
 namespace enterprise_reporting {
 
-ProfileReportGenerator::ProfileReportGenerator() = default;
+ProfileReportGenerator::ProfileReportGenerator() : weak_ptr_factory_(this) {}
 
 ProfileReportGenerator::~ProfileReportGenerator() = default;
 
@@ -27,21 +31,31 @@
   policies_enabled_ = enabled;
 }
 
-std::unique_ptr<em::ChromeUserProfileInfo>
-ProfileReportGenerator::MaybeGenerate(const base::FilePath& path,
-                                      const std::string& name) {
+void ProfileReportGenerator::MaybeGenerate(const base::FilePath& path,
+                                           const std::string& name,
+                                           ReportCallback callback) {
+  callback_ = std::move(callback);
+
   profile_ = g_browser_process->profile_manager()->GetProfileByPath(path);
-  if (!profile_)
-    return nullptr;
+
+  if (!profile_) {
+    CheckReportStatusAsync();
+    return;
+  }
 
   report_ = std::make_unique<em::ChromeUserProfileInfo>();
   report_->set_id(path.AsUTF8Unsafe());
   report_->set_name(name);
   report_->set_is_full_report(true);
 
-  GetSigninUserInfo();
+  is_plugin_info_ready_ = false;
 
-  return std::move(report_);
+  GetSigninUserInfo();
+  GetExtensionInfo();
+  GetPluginInfo();
+
+  CheckReportStatusAsync();
+  return;
 }
 
 void ProfileReportGenerator::GetSigninUserInfo() {
@@ -60,4 +74,49 @@
   AppendExtensionInfoIntoProfileReport(profile_, report_.get());
 }
 
+void ProfileReportGenerator::GetPluginInfo() {
+  if (!extensions_and_plugins_enabled_) {
+    is_plugin_info_ready_ = true;
+    return;
+  }
+
+  content::PluginService::GetInstance()->GetPlugins(
+      base::BindOnce(&ProfileReportGenerator::OnPluginsLoaded,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+void ProfileReportGenerator::OnPluginsLoaded(
+    const std::vector<content::WebPluginInfo>& plugins) {
+  for (auto plugin : plugins) {
+    auto* plugin_info = report_->add_plugins();
+    plugin_info->set_name(base::UTF16ToUTF8(plugin.name));
+    plugin_info->set_version(base::UTF16ToUTF8(plugin.version));
+    plugin_info->set_filename(plugin.path.BaseName().AsUTF8Unsafe());
+    plugin_info->set_description(base::UTF16ToUTF8(plugin.desc));
+  }
+
+  is_plugin_info_ready_ = true;
+  CheckReportStatus();
+}
+
+void ProfileReportGenerator::CheckReportStatus() {
+  // Report is not generated, return nullptr.
+  if (!report_) {
+    std::move(callback_).Run(nullptr);
+    return;
+  }
+
+  // Report is not ready, quit and wait.
+  if (!is_plugin_info_ready_)
+    return;
+
+  std::move(callback_).Run(std::move(report_));
+}
+
+void ProfileReportGenerator::CheckReportStatusAsync() {
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(&ProfileReportGenerator::CheckReportStatus,
+                                weak_ptr_factory_.GetWeakPtr()));
+}
+
 }  // namespace enterprise_reporting
diff --git a/chrome/browser/enterprise_reporting/profile_report_generator.h b/chrome/browser/enterprise_reporting/profile_report_generator.h
index bdc8ebd..1e209f7 100644
--- a/chrome/browser/enterprise_reporting/profile_report_generator.h
+++ b/chrome/browser/enterprise_reporting/profile_report_generator.h
@@ -5,7 +5,9 @@
 #ifndef CHROME_BROWSER_ENTERPRISE_REPORTING_PROFILE_REPORT_GENERATOR_H_
 #define CHROME_BROWSER_ENTERPRISE_REPORTING_PROFILE_REPORT_GENERATOR_H_
 
+#include "base/callback.h"
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "components/policy/proto/device_management_backend.pb.h"
 
 namespace em = enterprise_management;
@@ -14,6 +16,10 @@
 class FilePath;
 }
 
+namespace content {
+struct WebPluginInfo;
+}
+
 class Profile;
 
 namespace enterprise_reporting {
@@ -24,34 +30,47 @@
  */
 class ProfileReportGenerator {
  public:
+  using ReportCallback =
+      base::OnceCallback<void(std::unique_ptr<em::ChromeUserProfileInfo>)>;
+
   ProfileReportGenerator();
   ~ProfileReportGenerator();
 
   void set_extensions_and_plugins_enabled(bool enabled);
   void set_policies_enabled(bool enabled);
 
-  // Generates report for Profile if it's activated. Otherwise, returns null.
-  std::unique_ptr<em::ChromeUserProfileInfo> MaybeGenerate(
-      const base::FilePath& path,
-      const std::string& name);
+  // Generates report for Profile if it's activated. Returns the report with
+  // |callback| once it's ready. The report is null if it can't be generated.
+  void MaybeGenerate(const base::FilePath& path,
+                     const std::string& name,
+                     ReportCallback callback);
 
  protected:
   // Get Signin information includes email and gaia id.
   virtual void GetSigninUserInfo();
 
   void GetExtensionInfo();
-  // TODO(zmin): void GetPluginInfo();
+  void GetPluginInfo();
   // TODO(zmin): void GetChromePolicyInfo();
   // TODO(zmin): void GetExtensionPolicyInfo();
   // TODO(zmin): void GetPolicyFetchTimestampInfo();
 
  private:
+  void OnPluginsLoaded(const std::vector<content::WebPluginInfo>& plugins);
+
+  void CheckReportStatus();
+  void CheckReportStatusAsync();
+
   Profile* profile_;
 
   bool extensions_and_plugins_enabled_ = true;
   bool policies_enabled_ = true;
+  bool is_plugin_info_ready_ = false;
+  ReportCallback callback_;
 
-  std::unique_ptr<em::ChromeUserProfileInfo> report_;
+  std::unique_ptr<em::ChromeUserProfileInfo> report_ = nullptr;
+
+  base::WeakPtrFactory<ProfileReportGenerator> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ProfileReportGenerator);
 };
diff --git a/chrome/browser/enterprise_reporting/profile_report_generator_unittest.cc b/chrome/browser/enterprise_reporting/profile_report_generator_unittest.cc
index c5c79cc..191290b 100644
--- a/chrome/browser/enterprise_reporting/profile_report_generator_unittest.cc
+++ b/chrome/browser/enterprise_reporting/profile_report_generator_unittest.cc
@@ -5,22 +5,34 @@
 #include "chrome/browser/enterprise_reporting/profile_report_generator.h"
 
 #include "base/logging.h"
+#include "base/run_loop.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/bind_test_util.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile_manager.h"
 #include "components/account_id/account_id.h"
 #include "components/signin/public/identity_manager/identity_test_environment.h"
+#include "content/public/browser/plugin_service.h"
+#include "content/public/common/webplugininfo.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace enterprise_reporting {
 namespace {
+
 const char kProfile[] = "Profile";
 const char kIdleProfile[] = "IdleProfile";
+
+const char kPluginName[] = "plugin";
+const char kPluginVersion[] = "1.0";
+const char kPluginDescription[] = "This is a plugin.";
+const char kPluginFileName[] = "file_name";
+
 }  // namespace
+
 class ProfileReportGeneratorTest : public ::testing::Test {
  public:
   ProfileReportGeneratorTest()
@@ -30,12 +42,31 @@
   void SetUp() override {
     ASSERT_TRUE(profile_manager_.SetUp());
     profile_ = profile_manager_.CreateTestingProfile(kProfile);
+    content::PluginService::GetInstance()->Init();
+  }
+
+  std::unique_ptr<em::ChromeUserProfileInfo> GenerateReport(
+      const base::FilePath& path,
+      const std::string& name) {
+    base::RunLoop run_loop;
+    std::unique_ptr<em::ChromeUserProfileInfo> report =
+        std::make_unique<em::ChromeUserProfileInfo>();
+    generator_.MaybeGenerate(
+        path, name,
+        base::BindLambdaForTesting(
+            [&run_loop, report = report.get()](
+                std::unique_ptr<em::ChromeUserProfileInfo> response) {
+              DCHECK(response);
+              report->Swap(response.get());
+              run_loop.Quit();
+            }));
+    run_loop.Run();
+    return report;
   }
 
   std::unique_ptr<em::ChromeUserProfileInfo> GenerateReport() {
-    auto report = generator_.MaybeGenerate(profile()->GetPath(),
-                                           profile()->GetProfileUserName());
-
+    auto report =
+        GenerateReport(profile()->GetPath(), profile()->GetProfileUserName());
     EXPECT_TRUE(report);
     EXPECT_EQ(profile()->GetProfileUserName(), report->name());
     EXPECT_EQ(profile()->GetPath().AsUTF8Unsafe(), report->id());
@@ -44,6 +75,19 @@
     return report;
   }
 
+  void CreatePlugin() {
+    content::WebPluginInfo info;
+    info.name = base::ASCIIToUTF16(kPluginName);
+    info.version = base::ASCIIToUTF16(kPluginVersion);
+    info.desc = base::ASCIIToUTF16(kPluginDescription);
+    info.path =
+        base::FilePath().AppendASCII("path").AppendASCII(kPluginFileName);
+    content::PluginService* plugin_service =
+        content::PluginService::GetInstance();
+    plugin_service->RegisterInternalPlugin(info, true);
+    plugin_service->RefreshPlugins();
+  }
+
   TestingProfile* profile() { return profile_; }
   TestingProfileManager* profile_manager() { return &profile_manager_; }
 
@@ -63,7 +107,15 @@
   profile_manager()->profile_attributes_storage()->AddProfile(
       profile_path, base::ASCIIToUTF16(kIdleProfile), std::string(),
       base::string16(), 0, std::string(), EmptyAccountId());
-  EXPECT_FALSE(generator_.MaybeGenerate(profile_path, kIdleProfile));
+  base::RunLoop run_loop;
+  generator_.MaybeGenerate(
+      profile_path, kIdleProfile,
+      base::BindLambdaForTesting(
+          [&run_loop](std::unique_ptr<em::ChromeUserProfileInfo> response) {
+            EXPECT_FALSE(response);
+            run_loop.Quit();
+          }));
+  run_loop.Run();
 }
 
 TEST_F(ProfileReportGeneratorTest, UnsignedInProfile) {
@@ -83,4 +135,23 @@
             report->chrome_signed_in_user().obfudscated_gaiaid());
 }
 
+TEST_F(ProfileReportGeneratorTest, PluginIsDisabled) {
+  CreatePlugin();
+  generator_.set_extensions_and_plugins_enabled(false);
+  auto report = GenerateReport();
+  EXPECT_EQ(0, report->plugins_size());
+}
+
+TEST_F(ProfileReportGeneratorTest, PluginIsEnabled) {
+  CreatePlugin();
+  auto report = GenerateReport();
+  // There might be other plugins like PDF plugin, however, our fake plugin
+  // should be the first one in the report.
+  EXPECT_LE(1, report->plugins_size());
+  EXPECT_EQ(kPluginName, report->plugins(0).name());
+  EXPECT_EQ(kPluginVersion, report->plugins(0).version());
+  EXPECT_EQ(kPluginDescription, report->plugins(0).description());
+  EXPECT_EQ(kPluginFileName, report->plugins(0).filename());
+}
+
 }  // namespace enterprise_reporting
diff --git a/chrome/browser/extensions/app_process_apitest.cc b/chrome/browser/extensions/app_process_apitest.cc
index fd1b73d..242b95c 100644
--- a/chrome/browser/extensions/app_process_apitest.cc
+++ b/chrome/browser/extensions/app_process_apitest.cc
@@ -16,7 +16,9 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/view_ids.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/test/base/interactive_test_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/sync/model/string_ordinal.h"
 #include "content/public/browser/navigation_entry.h"
@@ -643,17 +645,12 @@
 
   ui_test_utils::NavigateToURL(
       browser(), GetTestBaseURL("app_process").Resolve("path3/container.html"));
+  ui_test_utils::WaitForViewVisibility(browser(), VIEW_ID_CONTENT_SETTING_POPUP,
+                                       true);
 
   WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
   PopupBlockerTabHelper* popup_blocker_tab_helper =
       PopupBlockerTabHelper::FromWebContents(tab);
-  if (!popup_blocker_tab_helper->GetBlockedPopupsCount()) {
-    content::WindowedNotificationObserver observer(
-        chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
-        content::NotificationService::AllSources());
-    observer.Wait();
-  }
-
   EXPECT_EQ(1u, popup_blocker_tab_helper->GetBlockedPopupsCount());
 }
 
diff --git a/chrome/browser/extensions/extension_functional_browsertest.cc b/chrome/browser/extensions/extension_functional_browsertest.cc
index 9674a0f..c1d9f3a 100644
--- a/chrome/browser/extensions/extension_functional_browsertest.cc
+++ b/chrome/browser/extensions/extension_functional_browsertest.cc
@@ -144,13 +144,6 @@
 
   // Verify that |tab1_popup| can find unrelated frames from the same extension
   // (i.e. that it can find |tab2|.
-  // TODO(lukasza): https://crbug.com/786411: The verification below is helpful
-  // to 1) verify about:blank-handling, parent-hopping done by
-  // GetExtensionFromFrame in extension_frame_helper.cc and 2) verify the old
-  // behavior.  We want to change the old behavior - this would expectedly make
-  // the assestion below fail and in this case we would need to tweak the test
-  // to look-up another window (most likely a background page).
-  base::HistogramTester histogram_tester;
   std::string location_of_opened_window;
   EXPECT_TRUE(ExecuteScriptAndExtractString(
       tab1_popup,
@@ -158,24 +151,6 @@
       "window.domAutomationController.send(w.location.href);",
       &location_of_opened_window));
   EXPECT_EQ(tab2->GetLastCommittedURL(), location_of_opened_window);
-
-  // Verify UMA got recorded as expected.
-  SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
-  EXPECT_THAT(histogram_tester.GetAllSamples(
-                  "Extensions.BrowsingInstanceViolation.ExtensionType"),
-              testing::ElementsAre(base::Bucket(Manifest::TYPE_EXTENSION, 1)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples(
-          "Extensions.BrowsingInstanceViolation.SourceExtensionViewType"),
-      testing::ElementsAre(base::Bucket(VIEW_TYPE_TAB_CONTENTS, 1)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples(
-          "Extensions.BrowsingInstanceViolation.TargetExtensionViewType"),
-      testing::ElementsAre(base::Bucket(VIEW_TYPE_TAB_CONTENTS, 1)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples(
-          "Extensions.BrowsingInstanceViolation.IsBackgroundSourceOrTarget"),
-      testing::ElementsAre(base::Bucket(false, 1)));
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionFunctionalTest, DownloadExtensionResource) {
diff --git a/chrome/browser/favicon/history_ui_favicon_request_handler_factory.cc b/chrome/browser/favicon/history_ui_favicon_request_handler_factory.cc
index 3212bfe..2c09a117a 100644
--- a/chrome/browser/favicon/history_ui_favicon_request_handler_factory.cc
+++ b/chrome/browser/favicon/history_ui_favicon_request_handler_factory.cc
@@ -33,8 +33,8 @@
 }
 
 bool CanSendHistoryData(syncer::SyncService* sync_service) {
-  return syncer::GetUploadToGoogleState(
-             sync_service, syncer::ModelType::HISTORY_DELETE_DIRECTIVES) ==
+  return syncer::GetUploadToGoogleState(sync_service,
+                                        syncer::ModelType::SESSIONS) ==
          syncer::UploadState::ACTIVE;
 }
 
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index e8aedf9..8746bab3 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -2129,7 +2129,7 @@
   {
     "name": "grid-layout-for-ntp-shortcuts",
     "owners": [ "kristipark", "ramyan" ],
-    "expiry_milestone": 77
+    "expiry_milestone": 78
   },
   {
     "name": "handwriting-gesture",
diff --git a/chrome/browser/media/webrtc/media_stream_capture_indicator.cc b/chrome/browser/media/webrtc/media_stream_capture_indicator.cc
index ec0bf473..25f9bb09 100644
--- a/chrome/browser/media/webrtc/media_stream_capture_indicator.cc
+++ b/chrome/browser/media/webrtc/media_stream_capture_indicator.cc
@@ -15,14 +15,13 @@
 #include "build/build_config.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/content_settings/chrome_content_settings_utils.h"
 #include "chrome/browser/status_icons/status_icon.h"
 #include "chrome/browser/status_icons/status_tray.h"
 #include "chrome/browser/tab_contents/tab_util.h"
 #include "components/url_formatter/elide_url.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
-#include "content/public/browser/notification_service.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/browser/web_contents_observer.h"
@@ -216,10 +215,7 @@
 
   if (web_contents()) {
     web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB);
-    content::NotificationService::current()->Notify(
-        chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
-        content::Source<WebContents>(web_contents()),
-        content::NotificationService::NoDetails());
+    content_settings::UpdateLocationBarUiForWebContents(web_contents());
   }
 
   indicator_->UpdateNotificationUserInterface();
diff --git a/chrome/browser/offline_pages/android/offline_page_auto_fetcher.cc b/chrome/browser/offline_pages/android/offline_page_auto_fetcher.cc
index 7242d52..0dfd12c 100644
--- a/chrome/browser/offline_pages/android/offline_page_auto_fetcher.cc
+++ b/chrome/browser/offline_pages/android/offline_page_auto_fetcher.cc
@@ -40,38 +40,45 @@
 
 OfflinePageAutoFetcher::OfflinePageAutoFetcher(
     content::RenderFrameHost* render_frame_host)
-    : render_frame_host_(render_frame_host) {}
+    : last_committed_url_(render_frame_host->GetLastCommittedURL()) {
+  TabAndroid* tab = FindTab(render_frame_host);
+  if (!tab) {
+    return;
+  }
+  auto_fetcher_service_ =
+      OfflinePageAutoFetcherServiceFactory::GetForBrowserContext(
+          render_frame_host->GetProcess()->GetBrowserContext());
+  android_tab_id_ = tab->GetAndroidId();
+}
 
 OfflinePageAutoFetcher::~OfflinePageAutoFetcher() = default;
 
 void OfflinePageAutoFetcher::TrySchedule(bool user_requested,
                                          TryScheduleCallback callback) {
-  TabAndroid* tab = FindTab(render_frame_host_);
-  if (!tab) {
+  if (!auto_fetcher_service_) {
     std::move(callback).Run(OfflinePageAutoFetcherScheduleResult::kOtherError);
     return;
   }
-  GetService()->TrySchedule(user_requested,
-                            render_frame_host_->GetLastCommittedURL(),
-                            tab->GetAndroidId(), std::move(callback));
+
+  auto_fetcher_service_->TrySchedule(user_requested, last_committed_url_,
+                                     android_tab_id_, std::move(callback));
 }
 
 void OfflinePageAutoFetcher::CancelSchedule() {
-  GetService()->CancelSchedule(render_frame_host_->GetLastCommittedURL());
+  if (!auto_fetcher_service_)
+    return;
+  auto_fetcher_service_->CancelSchedule(last_committed_url_);
 }
 
 // static
 void OfflinePageAutoFetcher::Create(
     chrome::mojom::OfflinePageAutoFetcherRequest request,
     content::RenderFrameHost* render_frame_host) {
+  // Lifetime of the strong binding can exceed the render frame host, so
+  // OfflinePageAutoFetcher does not retain a reference.
   mojo::MakeStrongBinding(
       std::make_unique<OfflinePageAutoFetcher>(render_frame_host),
       std::move(request));
 }
 
-OfflinePageAutoFetcherService* OfflinePageAutoFetcher::GetService() {
-  return OfflinePageAutoFetcherServiceFactory::GetForBrowserContext(
-      render_frame_host_->GetProcess()->GetBrowserContext());
-}
-
 }  // namespace offline_pages
diff --git a/chrome/browser/offline_pages/android/offline_page_auto_fetcher.h b/chrome/browser/offline_pages/android/offline_page_auto_fetcher.h
index e39387a..a7ca7c4 100644
--- a/chrome/browser/offline_pages/android/offline_page_auto_fetcher.h
+++ b/chrome/browser/offline_pages/android/offline_page_auto_fetcher.h
@@ -38,7 +38,9 @@
   using OfflinePageAutoFetcherScheduleResult =
       chrome::mojom::OfflinePageAutoFetcherScheduleResult;
 
-  content::RenderFrameHost* render_frame_host_;
+  GURL last_committed_url_;
+  int android_tab_id_;
+  OfflinePageAutoFetcherService* auto_fetcher_service_ = nullptr;
 };
 
 }  // namespace offline_pages
diff --git a/chrome/browser/offline_pages/background_loader_offliner.cc b/chrome/browser/offline_pages/background_loader_offliner.cc
index de53bb8..b8844d08 100644
--- a/chrome/browser/offline_pages/background_loader_offliner.cc
+++ b/chrome/browser/offline_pages/background_loader_offliner.cc
@@ -83,17 +83,6 @@
       is_previews_enabled);
 }
 
-void RecordResourceCompletionUMA(bool image_complete,
-                                 bool css_complete,
-                                 bool xhr_complete) {
-  base::UmaHistogramBoolean("OfflinePages.Background.ResourceCompletion.Image",
-                            image_complete);
-  base::UmaHistogramBoolean("OfflinePages.Background.ResourceCompletion.Css",
-                            css_complete);
-  base::UmaHistogramBoolean("OfflinePages.Background.ResourceCompletion.Xhr",
-                            xhr_complete);
-}
-
 void HandleLoadTerminationCancel(
     Offliner::CompletionCallback completion_callback,
     const SavePageRequest& canceled_request) {
@@ -166,41 +155,9 @@
        IsNetworkPredictionDisabled(browser_context_))) {
     DVLOG(1) << "WARNING: Unable to load when 3rd party cookies blocked or "
              << "prediction disabled";
-    // Record user metrics for third party cookies being disabled or network
-    // prediction being disabled.
-    if (AreThirdPartyCookiesBlocked(browser_context_)) {
-      UMA_HISTOGRAM_ENUMERATION(
-          "OfflinePages.Background.CctApiDisableStatus",
-          static_cast<int>(OfflinePagesCctApiPrerenderAllowedStatus::
-                               THIRD_PARTY_COOKIES_DISABLED),
-          static_cast<int>(OfflinePagesCctApiPrerenderAllowedStatus::
-                               NETWORK_PREDICTION_DISABLED) +
-              1);
-    }
-    if (IsNetworkPredictionDisabled(browser_context_)) {
-      UMA_HISTOGRAM_ENUMERATION(
-          "OfflinePages.Background.CctApiDisableStatus",
-          static_cast<int>(OfflinePagesCctApiPrerenderAllowedStatus::
-                               NETWORK_PREDICTION_DISABLED),
-          static_cast<int>(OfflinePagesCctApiPrerenderAllowedStatus::
-                               NETWORK_PREDICTION_DISABLED) +
-              1);
-    }
-
     return false;
   }
 
-  // Record UMA that the load was allowed to proceed.
-  if (request.client_id().name_space == kCCTNamespace) {
-    UMA_HISTOGRAM_ENUMERATION(
-        "OfflinePages.Background.CctApiDisableStatus",
-        static_cast<int>(
-            OfflinePagesCctApiPrerenderAllowedStatus::PRERENDER_ALLOWED),
-        static_cast<int>(OfflinePagesCctApiPrerenderAllowedStatus::
-                             NETWORK_PREDICTION_DISABLED) +
-            1);
-  }
-
   if (!OfflinePageModel::CanSaveURL(request.url())) {
     DVLOG(1) << "Not able to save page for requested url: " << request.url();
     return false;
@@ -294,6 +251,7 @@
     base::OnceCallback<void(bool)> callback) {
   if (!pending_request_.get()) {
     std::move(callback).Run(false);  // Shouldn't happen though...
+    return;
   }
 
   bool should_allow_downloads = false;
@@ -486,10 +444,6 @@
   RequestStats& image_stats = stats_[ResourceDataType::IMAGE];
   RequestStats& css_stats = stats_[ResourceDataType::TEXT_CSS];
   RequestStats& xhr_stats = stats_[ResourceDataType::XHR];
-  bool image_complete = (image_stats.requested == image_stats.completed);
-  bool css_complete = (css_stats.requested == css_stats.completed);
-  bool xhr_complete = (xhr_stats.requested == xhr_stats.completed);
-  RecordResourceCompletionUMA(image_complete, css_complete, xhr_complete);
 
   // Add loading signal into the MHTML that will be generated if the command
   // line flag is set for it.
diff --git a/chrome/browser/offline_pages/background_loader_offliner_unittest.cc b/chrome/browser/offline_pages/background_loader_offliner_unittest.cc
index 2b0213c..8b6f3cf 100644
--- a/chrome/browser/offline_pages/background_loader_offliner_unittest.cc
+++ b/chrome/browser/offline_pages/background_loader_offliner_unittest.cc
@@ -367,13 +367,6 @@
   profile()->GetPrefs()->SetBoolean(prefs::kBlockThirdPartyCookies, true);
   EXPECT_FALSE(offliner()->LoadAndSave(request, completion_callback(),
                                        progress_callback()));
-  histograms().ExpectBucketCount(
-      "OfflinePages.Background.CctApiDisableStatus",
-      static_cast<int>(OfflinePagesCctApiPrerenderAllowedStatus::
-                           THIRD_PARTY_COOKIES_DISABLED),
-      1);
-  histograms().ExpectBucketCount("OfflinePages.Background.CctApiDisableStatus",
-                                 0 /* PRERENDER_ALLOWED */, 0);
 }
 
 TEST_F(BackgroundLoaderOfflinerTest,
@@ -388,16 +381,6 @@
       chrome_browser_net::NETWORK_PREDICTION_NEVER);
   EXPECT_FALSE(offliner()->LoadAndSave(request, completion_callback(),
                                        progress_callback()));
-  histograms().ExpectBucketCount(
-      "OfflinePages.Background.CctApiDisableStatus",
-      static_cast<int>(OfflinePagesCctApiPrerenderAllowedStatus::
-                           NETWORK_PREDICTION_DISABLED),
-      1);
-  histograms().ExpectBucketCount(
-      "OfflinePages.Background.CctApiDisableStatus",
-      static_cast<int>(
-          OfflinePagesCctApiPrerenderAllowedStatus::PRERENDER_ALLOWED),
-      0);
 }
 
 TEST_F(BackgroundLoaderOfflinerTest, LoadAndSaveStartsLoading) {
@@ -587,6 +570,13 @@
   EXPECT_EQ(Offliner::RequestStatus::LOADING_FAILED_DOWNLOAD, request_status());
 }
 
+TEST_F(BackgroundLoaderOfflinerTest, CanDownloadReturnsIfNoPendingRequest) {
+  offliner()->CanDownload(can_download_callback());
+  PumpLoop();
+  EXPECT_TRUE(can_download_callback_called());
+  EXPECT_FALSE(can_download());
+}
+
 TEST_F(BackgroundLoaderOfflinerTest, FailsOnInvalidURL) {
   base::Time creation_time = base::Time::Now();
   SavePageRequest request(kRequestId, kFileUrl, kClientId, creation_time,
diff --git a/chrome/browser/page_load_metrics/OWNERS b/chrome/browser/page_load_metrics/OWNERS
index d31b3bf..68b74bc 100644
--- a/chrome/browser/page_load_metrics/OWNERS
+++ b/chrome/browser/page_load_metrics/OWNERS
@@ -2,6 +2,7 @@
 bmcquade@chromium.org
 jkarlin@chromium.org
 ryansturm@chromium.org
+johnidel@chromium.org
 
 # For straightforward addition/removal to existing observers only (for
 # APAC).
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc
index 96f674a..750a80c 100644
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc
@@ -106,7 +106,7 @@
     resource->received_data_length = 10 * 1024;
     resource->delta_bytes = 10 * 1024;
     resource->encoded_body_length = 10 * 1024;
-    resource->was_fetched_via_cache = false;
+    resource->cache_type = page_load_metrics::mojom::CacheType::kNotCached;
     resource->is_complete = true;
     resource->is_primary_frame_resource = true;
     resources.push_back(std::move(resource));
@@ -338,7 +338,9 @@
     resource->encoded_body_length = resource_size_in_kbyte << 10;
     resource->reported_as_ad_resource = is_ad_resource;
     resource->is_complete = true;
-    resource->was_fetched_via_cache = static_cast<bool>(resource_cached);
+    resource->cache_type = (resource_cached == ResourceCached::NOT_CACHED)
+                               ? page_load_metrics::mojom::CacheType::kNotCached
+                               : page_load_metrics::mojom::CacheType::kHttp;
     resource->mime_type = mime_type;
     resource->is_primary_frame_resource = true;
     resource->is_main_frame_resource =
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.cc
index 43ad0bb2..d5eab50 100644
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.cc
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.cc
@@ -96,6 +96,10 @@
     const page_load_metrics::mojom::ResourceDataUpdatePtr& resource,
     int process_id,
     const page_load_metrics::ResourceTracker& resource_tracker) {
+  // TODO(968141): Update these metrics to include resources loaded by the
+  // memory cache.
+  if (resource->cache_type == page_load_metrics::mojom::CacheType::kMemory)
+    return;
   bool is_same_origin = origin_.IsSameOriginWith(resource->origin);
   bytes_ += resource->delta_bytes;
   network_bytes_ += resource->delta_bytes;
@@ -107,7 +111,8 @@
     num_resources_++;
 
   // Report cached resource body bytes to overall frame bytes.
-  if (resource->is_complete && resource->was_fetched_via_cache) {
+  if (resource->is_complete &&
+      resource->cache_type != page_load_metrics::mojom::CacheType::kNotCached) {
     bytes_ += resource->encoded_body_length;
     if (is_same_origin)
       same_origin_bytes_ += resource->encoded_body_length;
@@ -122,7 +127,8 @@
     ad_network_bytes_ += resource->delta_bytes;
     ad_bytes_ += resource->delta_bytes;
     // Report cached resource body bytes to overall frame bytes.
-    if (resource->is_complete && resource->was_fetched_via_cache)
+    if (resource->is_complete &&
+        resource->cache_type != page_load_metrics::mojom::CacheType::kNotCached)
       ad_bytes_ += resource->encoded_body_length;
 
     ResourceMimeType mime_type = GetResourceMimeType(resource);
diff --git a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc
index 2f7da13..7cee9c41 100644
--- a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc
@@ -220,42 +220,44 @@
 const char kHistogramFirstScrollInputAfterFirstPaint[] =
     "PageLoad.InputTiming.NavigationToFirstScroll.AfterPaint";
 
-const char kHistogramPageLoadTotalBytes[] = "PageLoad.Experimental.Bytes.Total";
+const char kHistogramPageLoadTotalBytes[] =
+    "PageLoad.Experimental.Bytes.Total2";
 const char kHistogramPageLoadNetworkBytes[] =
     "PageLoad.Experimental.Bytes.Network";
-const char kHistogramPageLoadCacheBytes[] = "PageLoad.Experimental.Bytes.Cache";
+const char kHistogramPageLoadCacheBytes[] =
+    "PageLoad.Experimental.Bytes.Cache2";
 const char kHistogramPageLoadNetworkBytesIncludingHeaders[] =
     "PageLoad.Experimental.Bytes.NetworkIncludingHeaders";
 const char kHistogramPageLoadUnfinishedBytes[] =
     "PageLoad.Experimental.Bytes.Unfinished";
 
 const char kHistogramLoadTypeTotalBytesForwardBack[] =
-    "PageLoad.Experimental.Bytes.Total.LoadType.ForwardBackNavigation";
+    "PageLoad.Experimental.Bytes.Total2.LoadType.ForwardBackNavigation";
 const char kHistogramLoadTypeNetworkBytesForwardBack[] =
     "PageLoad.Experimental.Bytes.Network.LoadType.ForwardBackNavigation";
 const char kHistogramLoadTypeCacheBytesForwardBack[] =
-    "PageLoad.Experimental.Bytes.Cache.LoadType.ForwardBackNavigation";
+    "PageLoad.Experimental.Bytes.Cache2.LoadType.ForwardBackNavigation";
 
 const char kHistogramLoadTypeTotalBytesReload[] =
-    "PageLoad.Experimental.Bytes.Total.LoadType.Reload";
+    "PageLoad.Experimental.Bytes.Total2.LoadType.Reload";
 const char kHistogramLoadTypeNetworkBytesReload[] =
     "PageLoad.Experimental.Bytes.Network.LoadType.Reload";
 const char kHistogramLoadTypeCacheBytesReload[] =
-    "PageLoad.Experimental.Bytes.Cache.LoadType.Reload";
+    "PageLoad.Experimental.Bytes.Cache2.LoadType.Reload";
 
 const char kHistogramLoadTypeTotalBytesNewNavigation[] =
-    "PageLoad.Experimental.Bytes.Total.LoadType.NewNavigation";
+    "PageLoad.Experimental.Bytes.Total2.LoadType.NewNavigation";
 const char kHistogramLoadTypeNetworkBytesNewNavigation[] =
     "PageLoad.Experimental.Bytes.Network.LoadType.NewNavigation";
 const char kHistogramLoadTypeCacheBytesNewNavigation[] =
-    "PageLoad.Experimental.Bytes.Cache.LoadType.NewNavigation";
+    "PageLoad.Experimental.Bytes.Cache2.LoadType.NewNavigation";
 
 const char kHistogramTotalCompletedResources[] =
-    "PageLoad.Experimental.CompletedResources.Total";
+    "PageLoad.Experimental.CompletedResources.Total2";
 const char kHistogramNetworkCompletedResources[] =
     "PageLoad.Experimental.CompletedResources.Network";
 const char kHistogramCacheCompletedResources[] =
-    "PageLoad.Experimental.CompletedResources.Cache";
+    "PageLoad.Experimental.CompletedResources.Cache2";
 
 const char kHistogramInputToNavigation[] =
     "PageLoad.Experimental.InputTiming.InputToNavigationStart";
@@ -769,7 +771,8 @@
         resources) {
   for (auto const& resource : resources) {
     if (resource->is_complete) {
-      if (!resource->was_fetched_via_cache) {
+      if (resource->cache_type ==
+          page_load_metrics::mojom::CacheType::kNotCached) {
         network_bytes_ += resource->encoded_body_length;
         num_network_resources_++;
       } else {
diff --git a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc
index 35a6f513..c55d71a 100644
--- a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc
@@ -378,7 +378,8 @@
   int64_t cache_bytes = 0;
   for (const auto& resource : resources) {
     if (resource->is_complete) {
-      if (!resource->was_fetched_via_cache)
+      if (resource->cache_type ==
+          page_load_metrics::mojom::CacheType::kNotCached)
         network_bytes += resource->encoded_body_length;
       else
         cache_bytes += resource->encoded_body_length;
@@ -457,7 +458,8 @@
   int64_t cache_bytes = 0;
   for (const auto& resource : resources) {
     if (resource->is_complete) {
-      if (!resource->was_fetched_via_cache)
+      if (resource->cache_type ==
+          page_load_metrics::mojom::CacheType::kNotCached)
         network_bytes += resource->encoded_body_length;
       else
         cache_bytes += resource->encoded_body_length;
@@ -530,7 +532,8 @@
   int64_t cache_bytes = 0;
   for (const auto& resource : resources) {
     if (resource->is_complete) {
-      if (!resource->was_fetched_via_cache)
+      if (resource->cache_type ==
+          page_load_metrics::mojom::CacheType::kNotCached)
         network_bytes += resource->encoded_body_length;
       else
         cache_bytes += resource->encoded_body_length;
diff --git a/chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer_base.cc b/chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer_base.cc
index 809db81..0cd0d55 100644
--- a/chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer_base.cc
+++ b/chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer_base.cc
@@ -402,7 +402,10 @@
         resources) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   for (auto const& resource : resources) {
-    if (resource->was_fetched_via_cache) {
+    if (resource->cache_type == page_load_metrics::mojom::CacheType::kMemory)
+      continue;
+    if (resource->cache_type !=
+        page_load_metrics::mojom::CacheType::kNotCached) {
       if (resource->is_complete) {
         if (resource->is_secure_scheme) {
           secure_cached_bytes_ += resource->encoded_body_length;
diff --git a/chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer_test_utils.cc b/chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer_test_utils.cc
index f04642e5..188c885 100644
--- a/chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer_test_utils.cc
+++ b/chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer_test_utils.cc
@@ -32,7 +32,9 @@
                                  double compression_ratio) {
   auto resource_data_update =
       page_load_metrics::mojom::ResourceDataUpdate::New();
-  resource_data_update->was_fetched_via_cache = was_cached;
+  resource_data_update->cache_type =
+      was_cached ? page_load_metrics::mojom::CacheType::kHttp
+                 : page_load_metrics::mojom::CacheType::kNotCached;
   resource_data_update->delta_bytes = was_cached ? 0 : delta_bytes;
   resource_data_update->encoded_body_length = delta_bytes;
   resource_data_update->is_complete = is_complete;
diff --git a/chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer_unittest.cc
index 9b75b6a..610ccc8 100644
--- a/chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer_unittest.cc
@@ -305,7 +305,8 @@
   int64_t insecure_ocl_bytes = 0;
   int64_t secure_ocl_bytes = 0;
   for (const auto& request : resources) {
-    if (!request->was_fetched_via_cache) {
+    if (request->cache_type ==
+        page_load_metrics::mojom::CacheType::kNotCached) {
       if (request->is_secure_scheme) {
         secure_network_bytes += request->delta_bytes;
         secure_ocl_bytes +=
@@ -322,7 +323,9 @@
     }
     if (request->proxy_used) {
       drp_bytes += request->delta_bytes;
-      if (!request->was_fetched_via_cache && request->is_complete)
+      if (request->cache_type ==
+              page_load_metrics::mojom::CacheType::kNotCached &&
+          request->is_complete)
         ++drp_resources;
     }
   }
@@ -368,7 +371,8 @@
   int64_t insecure_ocl_bytes = 0;
   int64_t secure_ocl_bytes = 0;
   for (const auto& request : resources) {
-    if (!request->was_fetched_via_cache) {
+    if (request->cache_type ==
+        page_load_metrics::mojom::CacheType::kNotCached) {
       if (request->is_secure_scheme) {
         secure_network_bytes += request->delta_bytes;
         secure_ocl_bytes +=
@@ -388,7 +392,9 @@
         secure_drp_bytes += request->delta_bytes;
       else
         drp_bytes += request->delta_bytes;
-      if (!request->was_fetched_via_cache && request->is_complete)
+      if (request->cache_type ==
+              page_load_metrics::mojom::CacheType::kNotCached &&
+          request->is_complete)
         ++drp_resources;
     }
   }
diff --git a/chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer.cc
index 67a4c3c8..2ea45b9 100644
--- a/chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer.cc
@@ -29,7 +29,8 @@
         resources) {
   for (auto const& resource : resources) {
     if (resource->is_complete) {
-      if (!resource->was_fetched_via_cache)
+      if (resource->cache_type ==
+          page_load_metrics::mojom::CacheType::kNotCached)
         network_bytes_ += resource->encoded_body_length;
       else
         cache_bytes_ += resource->encoded_body_length;
diff --git a/chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer_unittest.cc
index 4bf8bda..1390686 100644
--- a/chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer_unittest.cc
@@ -60,7 +60,8 @@
     SimulateResourceDataUseUpdate(resources);
     for (const auto& resource : resources) {
       if (resource->is_complete) {
-        if (!resource->was_fetched_via_cache)
+        if (resource->cache_type ==
+            page_load_metrics::mojom::CacheType::kNotCached)
           network_bytes_ += resource->encoded_body_length;
         else
           cache_bytes_ += resource->encoded_body_length;
diff --git a/chrome/browser/page_load_metrics/observers/previews_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/previews_page_load_metrics_observer.cc
index 9f36663..60eb2335 100644
--- a/chrome/browser/page_load_metrics/observers/previews_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/previews_page_load_metrics_observer.cc
@@ -219,7 +219,9 @@
     const std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr>&
         resources) {
   for (auto const& resource : resources) {
-    if (!resource->was_fetched_via_cache && resource->is_complete) {
+    if (resource->cache_type ==
+            page_load_metrics::mojom::CacheType::kNotCached &&
+        resource->is_complete) {
       num_network_resources_++;
     }
     total_network_bytes_ += resource->delta_bytes;
diff --git a/chrome/browser/page_load_metrics/observers/resource_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/resource_metrics_observer.cc
index c0333e85..ba588a2e 100644
--- a/chrome/browser/page_load_metrics/observers/resource_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/resource_metrics_observer.cc
@@ -56,48 +56,46 @@
 
 void ResourceMetricsObserver::RecordResourceMimeHistograms(
     const page_load_metrics::mojom::ResourceDataUpdatePtr& resource) {
-  int64_t data_length = resource->was_fetched_via_cache
-                            ? resource->encoded_body_length
-                            : resource->received_data_length;
+  bool was_cached =
+      resource->cache_type != page_load_metrics::mojom::CacheType::kNotCached;
+  int64_t data_length = was_cached ? resource->encoded_body_length
+                                   : resource->received_data_length;
   ResourceMimeType mime_type = FrameData::GetResourceMimeType(resource);
   if (mime_type == ResourceMimeType::kImage) {
-    RESOURCE_BYTES_HISTOGRAM("Mime.Image", resource->was_fetched_via_cache,
-                             data_length);
+    RESOURCE_BYTES_HISTOGRAM("Mime.Image", was_cached, data_length);
   } else if (mime_type == ResourceMimeType::kJavascript) {
-    RESOURCE_BYTES_HISTOGRAM("Mime.JS", resource->was_fetched_via_cache,
-                             data_length);
+    RESOURCE_BYTES_HISTOGRAM("Mime.JS", was_cached, data_length);
   } else if (mime_type == ResourceMimeType::kVideo) {
-    RESOURCE_BYTES_HISTOGRAM("Mime.Video", resource->was_fetched_via_cache,
-                             data_length);
+    RESOURCE_BYTES_HISTOGRAM("Mime.Video", was_cached, data_length);
   } else if (mime_type == ResourceMimeType::kCss) {
-    RESOURCE_BYTES_HISTOGRAM("Mime.CSS", resource->was_fetched_via_cache,
-                             data_length);
+    RESOURCE_BYTES_HISTOGRAM("Mime.CSS", was_cached, data_length);
   } else if (mime_type == ResourceMimeType::kHtml) {
-    RESOURCE_BYTES_HISTOGRAM("Mime.HTML", resource->was_fetched_via_cache,
-                             data_length);
+    RESOURCE_BYTES_HISTOGRAM("Mime.HTML", was_cached, data_length);
   } else if (mime_type == ResourceMimeType::kOther) {
-    RESOURCE_BYTES_HISTOGRAM("Mime.Other", resource->was_fetched_via_cache,
-                             data_length);
+    RESOURCE_BYTES_HISTOGRAM("Mime.Other", was_cached, data_length);
   }
 }
 
 void ResourceMetricsObserver::RecordResourceHistograms(
     const page_load_metrics::mojom::ResourceDataUpdatePtr& resource) {
-  int64_t data_length = resource->was_fetched_via_cache
-                            ? resource->encoded_body_length
-                            : resource->received_data_length;
+  // TODO(968141): Update these metrics to include resources loaded by the
+  // memory cache.
+  if (resource->cache_type == page_load_metrics::mojom::CacheType::kMemory)
+    return;
+  bool was_cached =
+      resource->cache_type != page_load_metrics::mojom::CacheType::kNotCached;
+  int64_t data_length = was_cached ? resource->encoded_body_length
+                                   : resource->received_data_length;
   if (resource->is_main_frame_resource && resource->reported_as_ad_resource) {
-    RESOURCE_BYTES_HISTOGRAM("Mainframe.AdResource",
-                             resource->was_fetched_via_cache, data_length);
+    RESOURCE_BYTES_HISTOGRAM("Mainframe.AdResource", was_cached, data_length);
   } else if (resource->is_main_frame_resource) {
-    RESOURCE_BYTES_HISTOGRAM("Mainframe.VanillaResource",
-                             resource->was_fetched_via_cache, data_length);
+    RESOURCE_BYTES_HISTOGRAM("Mainframe.VanillaResource", was_cached,
+                             data_length);
   } else if (resource->reported_as_ad_resource) {
-    RESOURCE_BYTES_HISTOGRAM("Subframe.AdResource",
-                             resource->was_fetched_via_cache, data_length);
+    RESOURCE_BYTES_HISTOGRAM("Subframe.AdResource", was_cached, data_length);
   } else {
-    RESOURCE_BYTES_HISTOGRAM("Subframe.VanillaResource",
-                             resource->was_fetched_via_cache, data_length);
+    RESOURCE_BYTES_HISTOGRAM("Subframe.VanillaResource", was_cached,
+                             data_length);
   }
 
   // Only report sizes by mime type for ad resources.
diff --git a/chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer.cc
index 3514c4ee..0ce6cc7 100644
--- a/chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer.cc
@@ -45,7 +45,8 @@
         resources) {
   for (auto const& resource : resources) {
     if (resource->is_complete) {
-      if (!resource->was_fetched_via_cache)
+      if (resource->cache_type ==
+          page_load_metrics::mojom::CacheType::kNotCached)
         network_bytes_ += resource->encoded_body_length;
       else
         cache_bytes_ += resource->encoded_body_length;
diff --git a/chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer_unittest.cc
index 03c6830c..cb20637 100644
--- a/chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer_unittest.cc
@@ -75,7 +75,8 @@
     SimulateResourceDataUseUpdate(resources);
     for (const auto& resource : resources) {
       if (resource->is_complete) {
-        if (!resource->was_fetched_via_cache)
+        if (resource->cache_type ==
+            page_load_metrics::mojom::CacheType::kNotCached)
           network_bytes_ += resource->encoded_body_length;
         else
           cache_bytes_ += resource->encoded_body_length;
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc
index 43ceab7..b3c0d3b 100644
--- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc
@@ -231,7 +231,9 @@
     return;
   for (auto const& resource : resources) {
     network_bytes_ += resource->delta_bytes;
-    if (resource->is_complete && resource->was_fetched_via_cache) {
+    if (resource->is_complete &&
+        resource->cache_type !=
+            page_load_metrics::mojom::CacheType::kNotCached) {
       cache_bytes_ += resource->encoded_body_length;
     }
   }
@@ -392,7 +394,7 @@
   builder.SetCpuTime(total_foreground_cpu_time_.InMilliseconds());
 
   // Use a bucket spacing factor of 1.3 for bytes.
-  builder.SetNet_CacheBytes(ukm::GetExponentialBucketMin(cache_bytes_, 1.3));
+  builder.SetNet_CacheBytes2(ukm::GetExponentialBucketMin(cache_bytes_, 1.3));
   builder.SetNet_NetworkBytes2(
       ukm::GetExponentialBucketMin(network_bytes_, 1.3));
 
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
index eb9f63d..01fccd6 100644
--- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
@@ -1017,7 +1017,8 @@
   int64_t network_bytes = 0;
   int64_t cache_bytes = 0;
   for (const auto& request : resources) {
-    if (!request->was_fetched_via_cache) {
+    if (request->cache_type ==
+        page_load_metrics::mojom::CacheType::kNotCached) {
       network_bytes += request->delta_bytes;
     } else {
       cache_bytes += request->encoded_body_length;
@@ -1040,7 +1041,7 @@
                                                 GURL(kTestUrl1));
     test_ukm_recorder().ExpectEntryMetric(kv.second.get(), "Net.NetworkBytes2",
                                           bucketed_network_bytes);
-    test_ukm_recorder().ExpectEntryMetric(kv.second.get(), "Net.CacheBytes",
+    test_ukm_recorder().ExpectEntryMetric(kv.second.get(), "Net.CacheBytes2",
                                           bucketed_cache_bytes);
   }
 }
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
index 78fd90ba..fe9409f 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
@@ -2113,6 +2113,91 @@
   waiter->Wait();
 }
 
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTest,
+                       MemoryCacheResource_Recorded) {
+  const char kHttpResponseHeader[] =
+      "HTTP/1.1 200 OK\r\n"
+      "Content-Type: text/html; charset=utf-8\r\n"
+      "Cache-Control: max-age=60\r\n"
+      "\r\n";
+  embedded_test_server()->ServeFilesFromSourceDirectory("content/test/data");
+  content::SetupCrossSiteRedirector(embedded_test_server());
+  auto cached_response =
+      std::make_unique<net::test_server::ControllableHttpResponse>(
+          embedded_test_server(), "/cachetime",
+          true /*relative_url_is_prefix*/);
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  auto waiter = CreatePageLoadMetricsTestWaiter();
+  browser()->OpenURL(content::OpenURLParams(
+      embedded_test_server()->GetURL("/page_with_cached_subresource.html"),
+      content::Referrer(), WindowOpenDisposition::CURRENT_TAB,
+      ui::PAGE_TRANSITION_TYPED, false));
+
+  // Load a resource large enough to record a nonzero number of kilobytes.
+  cached_response->WaitForRequest();
+  cached_response->Send(kHttpResponseHeader);
+  cached_response->Send(std::string(10 * 1024, ' '));
+  cached_response->Done();
+
+  waiter->AddMinimumCompleteResourcesExpectation(3);
+  waiter->Wait();
+
+  // Re-navigate the page to the same url with a different query string so the
+  // main resource is not loaded from the disk cache. The subresource will be
+  // loaded from the memory cache.
+  waiter = CreatePageLoadMetricsTestWaiter();
+  browser()->OpenURL(content::OpenURLParams(
+      embedded_test_server()->GetURL("/page_with_cached_subresource.html?xyz"),
+      content::Referrer(), WindowOpenDisposition::CURRENT_TAB,
+      ui::PAGE_TRANSITION_TYPED, false));
+
+  // Favicon is not fetched this time.
+  waiter->AddMinimumCompleteResourcesExpectation(2);
+  waiter->Wait();
+
+  // Verify no resources were cached for the first load.
+  histogram_tester_.ExpectBucketCount(
+      internal::kHistogramCacheCompletedResources, 0, 1);
+  histogram_tester_.ExpectBucketCount(internal::kHistogramPageLoadCacheBytes, 0,
+                                      1);
+
+  // Force histograms to record.
+  NavigateToUntrackedUrl();
+
+  // Verify that the cached resource from the memory cache is recorded
+  // correctly.
+  histogram_tester_.ExpectBucketCount(
+      internal::kHistogramCacheCompletedResources, 1, 1);
+  histogram_tester_.ExpectBucketCount(internal::kHistogramPageLoadCacheBytes,
+                                      10, 1);
+}
+
+// Verifies that css image resources shared across document do not cause a
+// crash, and are only counted once per context. https://crbug.com/979459.
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTest,
+                       MemoryCacheResources_RecordedOncePerContext) {
+  embedded_test_server()->ServeFilesFromSourceDirectory("chrome/test/data");
+  content::SetupCrossSiteRedirector(embedded_test_server());
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  auto waiter = CreatePageLoadMetricsTestWaiter();
+  ui_test_utils::NavigateToURL(
+      browser(),
+      embedded_test_server()->GetURL(
+          "/page_load_metrics/document_with_css_image_sharing.html"));
+
+  waiter->AddMinimumCompleteResourcesExpectation(7);
+  waiter->Wait();
+
+  // Force histograms to record.
+  NavigateToUntrackedUrl();
+
+  // Verify that cached resources are only reported once per context.
+  histogram_tester_.ExpectBucketCount(
+      internal::kHistogramCacheCompletedResources, 2, 1);
+}
+
 IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTest, InputEventsForClick) {
   embedded_test_server()->ServeFilesFromSourceDirectory("content/test/data");
   content::SetupCrossSiteRedirector(embedded_test_server());
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_observer.h b/chrome/browser/page_load_metrics/page_load_metrics_observer.h
index 2df1a213..5bfd1ed 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/page_load_metrics_observer.h
@@ -499,7 +499,9 @@
 
   // Invoked when there is data use for loading a resource on the page
   // for a given render frame host. This only contains resources that have had
-  // new data use since the last callback.
+  // new data use since the last callback. Resources loaded from the cache only
+  // receive a single update. Multiple updates can be received for the same
+  // resource if it is loaded in multiple documents.
   virtual void OnResourceDataUseObserved(
       content::RenderFrameHost* rfh,
       const std::vector<mojom::ResourceDataUpdatePtr>& resources) {}
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_test_waiter.cc b/chrome/browser/page_load_metrics/page_load_metrics_test_waiter.cc
index 3f3d75b..69ca6f1 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_test_waiter.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_test_waiter.cc
@@ -153,7 +153,8 @@
     HandleResourceUpdate(resource);
     if (resource->is_complete) {
       current_complete_resources_++;
-      if (!resource->was_fetched_via_cache)
+      if (resource->cache_type ==
+          page_load_metrics::mojom::CacheType::kNotCached)
         current_network_body_bytes_ += resource->encoded_body_length;
     }
     current_network_bytes_ += resource->delta_bytes;
diff --git a/chrome/browser/page_load_metrics/resource_tracker.cc b/chrome/browser/page_load_metrics/resource_tracker.cc
index f7ffd3e..fe5a26aa 100644
--- a/chrome/browser/page_load_metrics/resource_tracker.cc
+++ b/chrome/browser/page_load_metrics/resource_tracker.cc
@@ -28,6 +28,11 @@
 void ResourceTracker::ProcessResourceUpdate(
     int process_id,
     const page_load_metrics::mojom::ResourceDataUpdatePtr& resource) {
+  // Do not store resources loaded from the memory cache as we can receive
+  // duplicate loads of resources across documents.
+  if (resource->cache_type == page_load_metrics::mojom::CacheType::kMemory)
+    return;
+
   content::GlobalRequestID global_id(process_id, resource->request_id);
   auto it = unfinished_resources_.find(global_id);
 
diff --git a/chrome/browser/page_load_metrics/resource_tracker.h b/chrome/browser/page_load_metrics/resource_tracker.h
index e1476b46..d73e70d 100644
--- a/chrome/browser/page_load_metrics/resource_tracker.h
+++ b/chrome/browser/page_load_metrics/resource_tracker.h
@@ -14,7 +14,8 @@
 
 namespace page_load_metrics {
 
-// Tracks individual resource loads on the page.
+// Tracks individual resource loads on the page. Only tracks resources loaded
+// by the network stack (including HTTP cache).
 class ResourceTracker {
  public:
   // Maps a request id for a blink resource to the metadata for the resource
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc
index e065484..b6b48be 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -110,6 +110,7 @@
 #include "chrome/browser/password_manager/save_password_infobar_delegate_android.h"
 #include "chrome/browser/password_manager/update_password_infobar_delegate_android.h"
 #include "chrome/browser/ui/android/snackbars/auto_signin_prompt_controller.h"
+#include "components/password_manager/core/browser/credential_cache.h"
 #include "ui/base/ui_base_features.h"
 #else
 #include "chrome/browser/ui/browser_finder.h"
@@ -449,14 +450,13 @@
 void ChromePasswordManagerClient::PasswordWasAutofilled(
     const std::map<base::string16, const PasswordForm*>& best_matches,
     const GURL& origin,
-    const std::vector<const PasswordForm*>* federated_matches) const {
+    const std::vector<const PasswordForm*>* federated_matches) {
 #if defined(OS_ANDROID)
   if (!PasswordAccessoryController::AllowedForWebContents(web_contents())) {
     return;  // No need to even create the bridge if it's not going to be used.
   }
-
-  PasswordAccessoryController::GetOrCreate(web_contents())
-      ->SavePasswordsForOrigin(best_matches, url::Origin::Create(origin));
+  credential_cache_.SaveCredentialsForOrigin(best_matches,
+                                             url::Origin::Create(origin));
 #else  // !defined(OS_ANDROID)
   PasswordsClientUIDelegate* manage_passwords_ui_controller =
       PasswordsClientUIDelegateFromWebContents(web_contents());
@@ -467,7 +467,7 @@
 
 void ChromePasswordManagerClient::AutofillHttpAuth(
     const PasswordForm& preferred_match,
-    const password_manager::PasswordFormManagerForUI* form_manager) const {
+    const password_manager::PasswordFormManagerForUI* form_manager) {
   httpauth_manager_.Autofill(preferred_match, form_manager);
   DCHECK(!form_manager->GetBestMatches().empty());
   PasswordWasAutofilled(form_manager->GetBestMatches(),
@@ -542,6 +542,14 @@
   return base::OptionalOrNullptr(metrics_recorder_);
 }
 
+#if defined(OS_ANDROID)
+PasswordAccessoryController*
+ChromePasswordManagerClient::GetOrCreatePasswordAccessory() {
+  return PasswordAccessoryController::GetOrCreate(web_contents(),
+                                                  &credential_cache_);
+}
+#endif  // defined(OS_ANDROID)
+
 void ChromePasswordManagerClient::DidFinishNavigation(
     content::NavigationHandle* navigation_handle) {
   if (!navigation_handle->IsInMainFrame() || !navigation_handle->HasCommitted())
@@ -567,6 +575,7 @@
   AddToWidgetInputEventObservers(
       web_contents()->GetRenderViewHost()->GetWidget(), this);
 #else   // defined(OS_ANDROID)
+  credential_cache_.ClearCredentials();
   PasswordAccessoryController* accessory =
       PasswordAccessoryController::GetIfExisting(web_contents());
   if (accessory)
@@ -1078,10 +1087,9 @@
     return;
 
   if (web_contents()->GetFocusedFrame()) {
-    PasswordAccessoryController::GetOrCreate(web_contents())
-        ->RefreshSuggestionsForField(
-            focused_field_type,
-            password_manager_util::ManualPasswordGenerationEnabled(driver));
+    GetOrCreatePasswordAccessory()->RefreshSuggestionsForField(
+        focused_field_type,
+        password_manager_util::ManualPasswordGenerationEnabled(driver));
   }
 
   PasswordGenerationController::GetOrCreate(web_contents())
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.h b/chrome/browser/password_manager/chrome_password_manager_client.h
index 022a2058..5dcfcea 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.h
+++ b/chrome/browser/password_manager/chrome_password_manager_client.h
@@ -35,6 +35,12 @@
 #include "content/public/browser/web_contents_user_data.h"
 #include "ui/gfx/geometry/rect.h"
 
+#if defined(OS_ANDROID)
+#include "components/password_manager/core/browser/credential_cache.h"
+
+class PasswordAccessoryController;
+#endif
+
 class PasswordGenerationPopupObserver;
 class PasswordGenerationPopupControllerImpl;
 class Profile;
@@ -100,10 +106,10 @@
           best_matches,
       const GURL& origin,
       const std::vector<const autofill::PasswordForm*>* federated_matches)
-      const override;
-  void AutofillHttpAuth(const autofill::PasswordForm& preferred_match,
-                        const password_manager::PasswordFormManagerForUI*
-                            form_manager) const override;
+      override;
+  void AutofillHttpAuth(
+      const autofill::PasswordForm& preferred_match,
+      const password_manager::PasswordFormManagerForUI* form_manager) override;
   bool IsIsolationForPasswordSitesEnabled() const override;
 
   PrefService* GetPrefs() const override;
@@ -187,6 +193,13 @@
     return content_credential_manager_.HasBinding();
   }
 #endif
+#if defined(OS_ANDROID)
+  PasswordAccessoryController* GetOrCreatePasswordAccessory();
+
+  password_manager::CredentialCache* GetCredentialCacheForTesting() {
+    return &credential_cache_;
+  }
+#endif
 
  protected:
   // Callable for tests.
@@ -258,6 +271,11 @@
       password_reuse_detection_manager_;
 #endif
 
+#if defined(OS_ANDROID)
+  // Holds and facilitates a credential store for each origin in this tab.
+  password_manager::CredentialCache credential_cache_;
+#endif
+
   password_manager::ContentPasswordManagerDriverFactory* driver_factory_;
 
   // As a mojo service, will be registered into service registry
diff --git a/chrome/browser/password_manager/password_accessory_controller.h b/chrome/browser/password_manager/password_accessory_controller.h
index 376dae5..f97de60 100644
--- a/chrome/browser/password_manager/password_accessory_controller.h
+++ b/chrome/browser/password_manager/password_accessory_controller.h
@@ -16,14 +16,11 @@
 #include "chrome/browser/autofill/accessory_controller.h"
 #include "components/autofill/core/common/mojom/autofill_types.mojom.h"
 #include "components/autofill/core/common/password_generation_util.h"
+#include "components/password_manager/core/browser/credential_cache.h"
 #include "content/public/browser/web_contents_user_data.h"
 #include "ui/gfx/image/image.h"
 #include "url/gurl.h"
 
-namespace autofill {
-struct PasswordForm;
-}  // namespace autofill
-
 // Interface for password-specific keyboard accessory controller between the
 // ManualFillingController and PasswordManagerClient.
 //
@@ -47,7 +44,8 @@
   // function is called. Only valid to be called if
   // |PasswordAccessoryController::AllowedForWebContents(web_contents)|.
   static PasswordAccessoryController* GetOrCreate(
-      content::WebContents* web_contents);
+      content::WebContents* web_contents,
+      password_manager::CredentialCache* credential_cache);
 
   // Returns a reference to the unique PasswordAccessoryController associated
   // with |web_contents|. Returns null if no such instance exists.
@@ -58,13 +56,6 @@
   // Methods called by the client:
   // -----------------------------
 
-  // Saves credentials for an origin so that they can be used in the sheet.
-  virtual void SavePasswordsForOrigin(
-      const std::map<base::string16, const autofill::PasswordForm*>&
-          best_matches,
-      const url::Origin& origin) = 0;
-
-
   // Completes a filling attempt by recording metrics, giving feedback to the
   // user and dismissing the accessory sheet.
   virtual void OnFilledIntoFocusedField(
diff --git a/chrome/browser/password_manager/password_accessory_controller_impl.cc b/chrome/browser/password_manager/password_accessory_controller_impl.cc
index 1f6bfa5..625771af 100644
--- a/chrome/browser/password_manager/password_accessory_controller_impl.cc
+++ b/chrome/browser/password_manager/password_accessory_controller_impl.cc
@@ -9,6 +9,7 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/containers/span.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/android/preferences/preferences_launcher.h"
@@ -24,7 +25,6 @@
 #include "components/autofill/core/browser/ui/accessory_sheet_enums.h"
 #include "components/autofill/core/common/autofill_features.h"
 #include "components/autofill/core/common/autofill_util.h"
-#include "components/autofill/core/common/password_form.h"
 #include "components/autofill/core/common/password_generation_util.h"
 #include "components/favicon/core/favicon_service.h"
 #include "components/favicon_base/favicon_types.h"
@@ -33,32 +33,34 @@
 #include "components/password_manager/core/browser/password_manager_driver.h"
 #include "components/password_manager/core/browser/password_manager_util.h"
 #include "components/password_manager/core/common/password_manager_features.h"
+#include "components/strings/grit/components_strings.h"
 #include "components/url_formatter/elide_url.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/base/l10n/l10n_util.h"
 
 using autofill::AccessorySheetData;
 using autofill::FooterCommand;
-using autofill::PasswordForm;
 using autofill::UserInfo;
 using autofill::mojom::FocusedFieldType;
+using password_manager::CredentialCache;
+using password_manager::CredentialPair;
 using FillingSource = ManualFillingController::FillingSource;
 
 namespace {
 
-autofill::UserInfo TranslateCredentials(
-    bool current_field_is_password,
-    const PasswordAccessorySuggestion& data) {
+autofill::UserInfo TranslateCredentials(bool current_field_is_password,
+                                        const CredentialPair& data) {
   UserInfo user_info;
 
+  base::string16 username = GetDisplayUsername(data);
   user_info.add_field(UserInfo::Field(
-      data.username, data.username, /*is_password=*/false,
-      /*selectable=*/data.username_selectable && !current_field_is_password));
+      username, username, /*is_password=*/false,
+      /*selectable=*/!data.username.empty() && !current_field_is_password));
 
   user_info.add_field(UserInfo::Field(
       data.password,
       l10n_util::GetStringFUTF16(
-          IDS_PASSWORD_MANAGER_ACCESSORY_PASSWORD_DESCRIPTION, data.username),
+          IDS_PASSWORD_MANAGER_ACCESSORY_PASSWORD_DESCRIPTION, username),
       /*is_password=*/true, /*selectable=*/current_field_is_password));
 
   return user_info;
@@ -113,10 +115,12 @@
 
 // static
 PasswordAccessoryController* PasswordAccessoryController::GetOrCreate(
-    content::WebContents* web_contents) {
+    content::WebContents* web_contents,
+    password_manager::CredentialCache* credential_cache) {
   DCHECK(PasswordAccessoryController::AllowedForWebContents(web_contents));
 
-  PasswordAccessoryControllerImpl::CreateForWebContents(web_contents);
+  PasswordAccessoryControllerImpl::CreateForWebContents(web_contents,
+                                                        credential_cache);
   return PasswordAccessoryControllerImpl::FromWebContents(web_contents);
 }
 
@@ -135,8 +139,23 @@
 };
 
 // static
+void PasswordAccessoryControllerImpl::CreateForWebContents(
+    content::WebContents* web_contents,
+    password_manager::CredentialCache* credential_cache) {
+  DCHECK(web_contents) << "Need valid WebContents to attach controller to!";
+  DCHECK(credential_cache);
+
+  if (!FromWebContents(web_contents)) {
+    web_contents->SetUserData(
+        UserDataKey(), base::WrapUnique(new PasswordAccessoryControllerImpl(
+                           web_contents, credential_cache)));
+  }
+}
+
+// static
 void PasswordAccessoryControllerImpl::CreateForWebContentsForTesting(
     content::WebContents* web_contents,
+    password_manager::CredentialCache* credential_cache,
     base::WeakPtr<ManualFillingController> mf_controller,
     favicon::FaviconService* favicon_service) {
   DCHECK(web_contents) << "Need valid WebContents to attach controller to!";
@@ -144,9 +163,9 @@
   DCHECK(mf_controller);
 
   web_contents->SetUserData(
-      UserDataKey(),
-      base::WrapUnique(new PasswordAccessoryControllerImpl(
-          web_contents, std::move(mf_controller), favicon_service)));
+      UserDataKey(), base::WrapUnique(new PasswordAccessoryControllerImpl(
+                         web_contents, credential_cache,
+                         std::move(mf_controller), favicon_service)));
 }
 
 // static
@@ -172,23 +191,6 @@
   return false;
 }
 
-void PasswordAccessoryControllerImpl::SavePasswordsForOrigin(
-    const std::map<base::string16, const PasswordForm*>& best_matches,
-    const url::Origin& origin) {
-  std::vector<PasswordAccessorySuggestion>* suggestions =
-      &origin_suggestions_[origin];
-  suggestions->clear();
-  for (const auto& pair : best_matches) {
-    const PasswordForm* form = pair.second;
-    if (!url::IsSameOriginWith(origin.GetURL(), form->origin) &&
-        !base::FeatureList::IsEnabled(
-            autofill::features::kAutofillKeyboardAccessory))
-      continue;  // Skip matches for PSL origins in V1 which has no UI for that.
-    suggestions->emplace_back(form->password_value, GetDisplayUsername(*form),
-                              /*selectable=*/!form->username_value.empty());
-  }
-}
-
 void PasswordAccessoryControllerImpl::OnFilledIntoFocusedField(
     autofill::mojom::FillingStatus status) {
   GetManualFillingController()->OnFilledIntoFocusedField(status);
@@ -235,13 +237,17 @@
       focused_field_type == FocusedFieldType::kFillablePasswordField;
 
   if (autofill::IsFillable(focused_field_type)) {
-    const std::vector<PasswordAccessorySuggestion> suggestions =
-        GetSuggestions();
-    info_to_add.resize(suggestions.size());
-    std::transform(suggestions.begin(), suggestions.end(), info_to_add.begin(),
-                   [is_password_field](const auto& x) {
-                     return TranslateCredentials(is_password_field, x);
-                   });
+    base::span<const CredentialPair> suggestions =
+        credential_cache_->GetCredentialStore(origin)->GetCredentials();
+    info_to_add.reserve(suggestions.size());
+    for (const auto& pair : suggestions) {
+      if (pair.is_public_suffix_match &&
+          !base::FeatureList::IsEnabled(
+              autofill::features::kAutofillKeyboardAccessory))
+        continue;  // PSL origins have no representation in V1. Don't show them!
+      // TODO(crbug.com/976761): Mark PSL-matches with their origin.
+      info_to_add.push_back(TranslateCredentials(is_password_field, pair));
+    }
   }
 
   if (is_password_field && is_manual_generation_available) {
@@ -277,7 +283,6 @@
 void PasswordAccessoryControllerImpl::DidNavigateMainFrame() {
   favicon_tracker_.TryCancelAll();  // If there is a request pending, cancel it.
   icons_request_data_.clear();
-  origin_suggestions_.clear();
 }
 
 void PasswordAccessoryControllerImpl::GetFavicon(
@@ -318,19 +323,22 @@
 }
 
 PasswordAccessoryControllerImpl::PasswordAccessoryControllerImpl(
-    content::WebContents* web_contents)
+    content::WebContents* web_contents,
+    password_manager::CredentialCache* credential_cache)
     : web_contents_(web_contents),
+      credential_cache_(credential_cache),
       favicon_service_(FaviconServiceFactory::GetForProfile(
           Profile::FromBrowserContext(web_contents->GetBrowserContext()),
-          ServiceAccessType::EXPLICIT_ACCESS)) {
-}
+          ServiceAccessType::EXPLICIT_ACCESS)) {}
 
 // Additional creation functions in unit tests only:
 PasswordAccessoryControllerImpl::PasswordAccessoryControllerImpl(
     content::WebContents* web_contents,
+    password_manager::CredentialCache* credential_cache,
     base::WeakPtr<ManualFillingController> mf_controller,
     favicon::FaviconService* favicon_service)
     : web_contents_(web_contents),
+      credential_cache_(credential_cache),
       mf_controller_(std::move(mf_controller)),
       favicon_service_(favicon_service) {}
 
@@ -359,11 +367,11 @@
     bool is_password,
     const url::Origin& origin) const {
   if (origin.opaque())
-    return false;  // Don't proceed for invalid origins.
-  for (const PasswordAccessorySuggestion& element :
-       origin_suggestions_.at(origin)) {
+    return false;  // Don't proceed for invalid origins.;
+  for (const CredentialPair& pair :
+       credential_cache_->GetCredentialStore(origin)->GetCredentials()) {
     const base::string16& candidate =
-        is_password ? element.password : element.username;
+        is_password ? pair.password : pair.username;
     if (candidate == suggestion)
       return true;
   }
@@ -387,12 +395,4 @@
   return web_contents_->GetFocusedFrame()->GetLastCommittedOrigin();
 }
 
-std::vector<PasswordAccessorySuggestion>
-PasswordAccessoryControllerImpl::GetSuggestions() const {
-  auto it = origin_suggestions_.find(GetFocusedFrameOrigin());
-  return it == origin_suggestions_.end()
-             ? std::vector<PasswordAccessorySuggestion>()
-             : it->second;
-}
-
 WEB_CONTENTS_USER_DATA_KEY_IMPL(PasswordAccessoryControllerImpl)
diff --git a/chrome/browser/password_manager/password_accessory_controller_impl.h b/chrome/browser/password_manager/password_accessory_controller_impl.h
index 35e1629..d39ae13 100644
--- a/chrome/browser/password_manager/password_accessory_controller_impl.h
+++ b/chrome/browser/password_manager/password_accessory_controller_impl.h
@@ -7,6 +7,7 @@
 
 #include <map>
 #include <memory>
+#include <utility>
 #include <vector>
 
 #include "base/callback_forward.h"
@@ -17,13 +18,10 @@
 #include "components/autofill/core/browser/ui/accessory_sheet_data.h"
 #include "components/autofill/core/common/mojom/autofill_types.mojom.h"
 #include "components/favicon_base/favicon_types.h"
+#include "components/password_manager/core/browser/credential_cache.h"
 #include "content/public/browser/web_contents_user_data.h"
 #include "url/gurl.h"
 
-namespace autofill {
-struct PasswordForm;
-}  // namespace autofill
-
 namespace favicon {
 class FaviconService;
 }  // namespace favicon
@@ -34,24 +32,6 @@
 
 class ManualFillingController;
 
-// Encapsulates the data needed from the password manager backend to
-// eventually render a username/password in the manual filling frontend.
-// TODO(crbug.com/941654): It's probably cleanest to use PasswordForm directly
-// instead of PasswordAccessorySuggestion as the type for the
-// AccessoryController.
-struct PasswordAccessorySuggestion {
-  PasswordAccessorySuggestion(base::string16 password,
-                              base::string16 username,
-                              bool username_selectable)
-      : password(std::move(password)),
-        username(std::move(username)),
-        username_selectable(username_selectable) {}
-
-  base::string16 password;
-  base::string16 username;
-  bool username_selectable;
-};
-
 // Use either PasswordAccessoryController::GetOrCreate or
 // PasswordAccessoryController::GetIfExisting to obtain instances of this class.
 // This class exists for every tab and should never store state based on the
@@ -67,10 +47,6 @@
   void OnOptionSelected(autofill::AccessoryAction selected_action) override;
 
   // PasswordAccessoryController:
-  void SavePasswordsForOrigin(
-      const std::map<base::string16, const autofill::PasswordForm*>&
-          best_matches,
-      const url::Origin& origin) override;
   void OnFilledIntoFocusedField(autofill::mojom::FillingStatus status) override;
   void RefreshSuggestionsForField(
       autofill::mojom::FocusedFieldType focused_field_type,
@@ -82,10 +58,18 @@
       base::OnceCallback<void(const gfx::Image&)> icon_callback) override;
 
   // Like |CreateForWebContents|, it creates the controller and attaches it to
+  // the given |web_contents|. Upon creation, a |credential_cache| is required
+  // that will be queried for credentials.
+  static void CreateForWebContents(
+      content::WebContents* web_contents,
+      password_manager::CredentialCache* credential_cache);
+
+  // Like |CreateForWebContents|, it creates the controller and attaches it to
   // the given |web_contents|. Additionally, it allows inject a manual filling
-  // controller.
+  // controller and a favicon service.
   static void CreateForWebContentsForTesting(
       content::WebContents* web_contents,
+      password_manager::CredentialCache* credential_cache,
       base::WeakPtr<ManualFillingController> mf_controller,
       favicon::FaviconService* favicon_service);
 
@@ -106,11 +90,14 @@
   friend class content::WebContentsUserData<PasswordAccessoryControllerImpl>;
 
   // Required for construction via |CreateForWebContents|:
-  explicit PasswordAccessoryControllerImpl(content::WebContents* contents);
+  PasswordAccessoryControllerImpl(
+      content::WebContents* contents,
+      password_manager::CredentialCache* credential_cache);
 
   // Constructor that allows to inject a mock or fake view.
   PasswordAccessoryControllerImpl(
       content::WebContents* web_contents,
+      password_manager::CredentialCache* credential_cache,
       base::WeakPtr<ManualFillingController> mf_controller,
       favicon::FaviconService* favicon_service);
 
@@ -130,19 +117,18 @@
   base::WeakPtr<ManualFillingController> GetManualFillingController();
 
   url::Origin GetFocusedFrameOrigin() const;
-  std::vector<PasswordAccessorySuggestion> GetSuggestions() const;
+  std::vector<password_manager::CredentialPair> GetSuggestions() const;
 
   // ------------------------------------------------------------------------
   // Members - Make sure to NEVER store state related to a single frame here!
   // ------------------------------------------------------------------------
 
-  // Contains the last set of credentials by origin.
-  std::map<url::Origin, std::vector<PasswordAccessorySuggestion>>
-      origin_suggestions_;
-
   // The tab for which this class is scoped.
   content::WebContents* web_contents_;
 
+  // Keeps track of credentials which are stored for all origins in this tab.
+  password_manager::CredentialCache* credential_cache_;
+
   // TODO(fhorschig): Find a way to use unordered_map with origin keys.
   // A cache for all favicons that were requested. This includes all iframes
   // for which the accessory was displayed.
diff --git a/chrome/browser/password_manager/password_accessory_controller_impl_unittest.cc b/chrome/browser/password_manager/password_accessory_controller_impl_unittest.cc
index 9166387..bc9f003 100644
--- a/chrome/browser/password_manager/password_accessory_controller_impl_unittest.cc
+++ b/chrome/browser/password_manager/password_accessory_controller_impl_unittest.cc
@@ -23,6 +23,7 @@
 #include "components/autofill/core/common/password_form.h"
 #include "components/autofill/core/common/signatures_util.h"
 #include "components/favicon/core/test/mock_favicon_service.h"
+#include "components/password_manager/core/browser/password_manager_test_utils.h"
 #include "components/password_manager/core/browser/stub_password_manager_driver.h"
 #include "components/strings/grit/components_strings.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -41,6 +42,7 @@
 using autofill::mojom::FillingStatus;
 using autofill::mojom::FocusedFieldType;
 using base::ASCIIToUTF16;
+using password_manager::CreateEntry;
 using testing::_;
 using testing::ByMove;
 using testing::Mock;
@@ -76,23 +78,6 @@
     content::WebContents* web_contents)
     : PasswordGenerationControllerImpl(web_contents) {}
 
-// Creates a new map entry in the |first| element of the returned pair. The
-// |second| element holds the PasswordForm that the |first| element points to.
-// That way, the pointer only points to a valid address in the called scope.
-std::pair<std::pair<base::string16, const PasswordForm*>,
-          std::unique_ptr<const PasswordForm>>
-CreateEntry(const std::string& username, const std::string& password) {
-  PasswordForm form;
-  form.username_value = ASCIIToUTF16(username);
-  form.password_value = ASCIIToUTF16(password);
-  form.origin = GURL(kExampleSite);
-  std::unique_ptr<const PasswordForm> form_ptr(
-      new PasswordForm(std::move(form)));
-  auto username_form_pair =
-      std::make_pair(ASCIIToUTF16(username), form_ptr.get());
-  return {std::move(username_form_pair), std::move(form_ptr)};
-}
-
 base::string16 password_for_str(const base::string16& user) {
   return l10n_util::GetStringFUTF16(
       IDS_PASSWORD_MANAGER_ACCESSORY_PASSWORD_DESCRIPTION, user);
@@ -155,7 +140,7 @@
 
     MockPasswordGenerationController::CreateForWebContents(web_contents());
     PasswordAccessoryControllerImpl::CreateForWebContentsForTesting(
-        web_contents(), mock_manual_filling_controller_.AsWeakPtr(),
+        web_contents(), cache(), mock_manual_filling_controller_.AsWeakPtr(),
         favicon_service());
     NavigateAndCommit(GURL(kExampleSite));
   }
@@ -168,10 +153,13 @@
     return mock_favicon_service_.get();
   }
 
+  password_manager::CredentialCache* cache() { return &credential_cache_; }
+
  protected:
   StrictMock<MockManualFillingController> mock_manual_filling_controller_;
 
  private:
+  password_manager::CredentialCache credential_cache_;
   std::unique_ptr<StrictMock<favicon::MockFaviconService>>
       mock_favicon_service_;
 };
@@ -180,14 +168,16 @@
   PasswordAccessoryControllerImpl* initial_controller =
       PasswordAccessoryControllerImpl::FromWebContents(web_contents());
   EXPECT_NE(nullptr, initial_controller);
-  PasswordAccessoryControllerImpl::CreateForWebContents(web_contents());
+  PasswordAccessoryControllerImpl::CreateForWebContents(web_contents(),
+                                                        cache());
   EXPECT_EQ(PasswordAccessoryControllerImpl::FromWebContents(web_contents()),
             initial_controller);
 }
 
 TEST_F(PasswordAccessoryControllerTest, TransformsMatchesToSuggestions) {
-  controller()->SavePasswordsForOrigin({CreateEntry("Ben", "S3cur3").first},
-                                       url::Origin::Create(GURL(kExampleSite)));
+  cache()->SaveCredentialsForOrigin(
+      {CreateEntry("Ben", "S3cur3", GURL(kExampleDomain), false).first},
+      url::Origin::Create(GURL(kExampleSite)));
   EXPECT_CALL(
       mock_manual_filling_controller_,
       RefreshSuggestions(
@@ -204,8 +194,9 @@
 }
 
 TEST_F(PasswordAccessoryControllerTest, HintsToEmptyUserNames) {
-  controller()->SavePasswordsForOrigin({CreateEntry("", "S3cur3").first},
-                                       url::Origin::Create(GURL(kExampleSite)));
+  cache()->SaveCredentialsForOrigin(
+      {CreateEntry("", "S3cur3", GURL(kExampleDomain), false).first},
+      url::Origin::Create(GURL(kExampleSite)));
 
   EXPECT_CALL(
       mock_manual_filling_controller_,
@@ -222,9 +213,11 @@
 }
 
 TEST_F(PasswordAccessoryControllerTest, SortsAlphabeticalDuringTransform) {
-  controller()->SavePasswordsForOrigin(
-      {CreateEntry("Ben", "S3cur3").first, CreateEntry("Zebra", "M3h").first,
-       CreateEntry("Alf", "PWD").first, CreateEntry("Cat", "M1@u").first},
+  cache()->SaveCredentialsForOrigin(
+      {CreateEntry("Ben", "S3cur3", GURL(kExampleDomain), false).first,
+       CreateEntry("Zebra", "M3h", GURL(kExampleDomain), false).first,
+       CreateEntry("Alf", "PWD", GURL(kExampleDomain), false).first,
+       CreateEntry("Cat", "M1@u", GURL(kExampleDomain), false).first},
       url::Origin::Create(GURL(kExampleSite)));
 
   EXPECT_CALL(
@@ -258,8 +251,9 @@
 }
 
 TEST_F(PasswordAccessoryControllerTest, RepeatsSuggestionsForSameFrame) {
-  controller()->SavePasswordsForOrigin({CreateEntry("Ben", "S3cur3").first},
-                                       url::Origin::Create(GURL(kExampleSite)));
+  cache()->SaveCredentialsForOrigin(
+      {CreateEntry("Ben", "S3cur3", GURL(kExampleDomain), false).first},
+      url::Origin::Create(GURL(kExampleSite)));
 
   // Pretend that any input in the same frame was focused.
   EXPECT_CALL(
@@ -278,8 +272,8 @@
 }
 
 TEST_F(PasswordAccessoryControllerTest, ProvidesEmptySuggestionsMessage) {
-  controller()->SavePasswordsForOrigin({},
-                                       url::Origin::Create(GURL(kExampleSite)));
+  cache()->SaveCredentialsForOrigin({},
+                                    url::Origin::Create(GURL(kExampleSite)));
 
   EXPECT_CALL(mock_manual_filling_controller_,
               RefreshSuggestions(PasswordAccessorySheetDataBuilder(
@@ -305,8 +299,9 @@
 }
 
 TEST_F(PasswordAccessoryControllerTest, PasswordFieldChangesSuggestionType) {
-  controller()->SavePasswordsForOrigin({CreateEntry("Ben", "S3cur3").first},
-                                       url::Origin::Create(GURL(kExampleSite)));
+  cache()->SaveCredentialsForOrigin(
+      {CreateEntry("Ben", "S3cur3", GURL(kExampleDomain), false).first},
+      url::Origin::Create(GURL(kExampleSite)));
   // Pretend a username field was focused. This should result in non-interactive
   // suggestion.
   EXPECT_CALL(
@@ -341,8 +336,9 @@
 }
 
 TEST_F(PasswordAccessoryControllerTest, CachesIsReplacedByNewPasswords) {
-  controller()->SavePasswordsForOrigin({CreateEntry("Ben", "S3cur3").first},
-                                       url::Origin::Create(GURL(kExampleSite)));
+  cache()->SaveCredentialsForOrigin(
+      {CreateEntry("Ben", "S3cur3", GURL(kExampleDomain), false).first},
+      url::Origin::Create(GURL(kExampleSite)));
   EXPECT_CALL(
       mock_manual_filling_controller_,
       RefreshSuggestions(
@@ -357,8 +353,9 @@
       FocusedFieldType::kFillableUsernameField,
       /*is_manual_generation_available=*/false);
 
-  controller()->SavePasswordsForOrigin({CreateEntry("Alf", "M3lm4k").first},
-                                       url::Origin::Create(GURL(kExampleSite)));
+  cache()->SaveCredentialsForOrigin(
+      {CreateEntry("Alf", "M3lm4k", GURL(kExampleDomain), false).first},
+      url::Origin::Create(GURL(kExampleSite)));
   EXPECT_CALL(
       mock_manual_filling_controller_,
       RefreshSuggestions(
@@ -375,8 +372,9 @@
 }
 
 TEST_F(PasswordAccessoryControllerTest, UnfillableFieldClearsSuggestions) {
-  controller()->SavePasswordsForOrigin({CreateEntry("Ben", "S3cur3").first},
-                                       url::Origin::Create(GURL(kExampleSite)));
+  cache()->SaveCredentialsForOrigin(
+      {CreateEntry("Ben", "S3cur3", GURL(kExampleDomain), false).first},
+      url::Origin::Create(GURL(kExampleSite)));
   // Pretend a username field was focused. This should result in non-emtpy
   // suggestions.
   EXPECT_CALL(
@@ -407,8 +405,9 @@
 TEST_F(PasswordAccessoryControllerTest, NavigatingMainFrameClearsSuggestions) {
   // Set any, non-empty password list and pretend a username field was focused.
   // This should result in non-emtpy suggestions.
-  controller()->SavePasswordsForOrigin({CreateEntry("Ben", "S3cur3").first},
-                                       url::Origin::Create(GURL(kExampleSite)));
+  cache()->SaveCredentialsForOrigin(
+      {CreateEntry("Ben", "S3cur3", GURL(kExampleDomain), false).first},
+      url::Origin::Create(GURL(kExampleSite)));
   EXPECT_CALL(
       mock_manual_filling_controller_,
       RefreshSuggestions(
@@ -601,8 +600,8 @@
 }
 
 TEST_F(PasswordAccessoryControllerTest, AddsGenerationCommandWhenAvailable) {
-  controller()->SavePasswordsForOrigin({},
-                                       url::Origin::Create(GURL(kExampleSite)));
+  cache()->SaveCredentialsForOrigin({},
+                                    url::Origin::Create(GURL(kExampleSite)));
   AccessorySheetData::Builder data_builder(AccessoryTabType::PASSWORDS,
                                            passwords_empty_str(kExampleDomain));
   data_builder
@@ -618,8 +617,8 @@
 }
 
 TEST_F(PasswordAccessoryControllerTest, NoGenerationCommandIfNotPasswordField) {
-  controller()->SavePasswordsForOrigin({},
-                                       url::Origin::Create(GURL(kExampleSite)));
+  cache()->SaveCredentialsForOrigin({},
+                                    url::Origin::Create(GURL(kExampleSite)));
   EXPECT_CALL(mock_manual_filling_controller_,
               RefreshSuggestions(PasswordAccessorySheetDataBuilder(
                                      passwords_empty_str(kExampleDomain))
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
index 094be70..5197bd8 100644
--- a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
+++ b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
@@ -3137,3 +3137,33 @@
   // Video should no longer be in Picture-in-Picture.
   ExpectLeavePictureInPicture(active_web_contents);
 }
+
+IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest,
+                       UpdateMaxSize) {
+  LoadTabAndEnterPictureInPicture(
+      browser(), base::FilePath(kPictureInPictureWindowSizePage));
+
+  content::WebContents* active_web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  ASSERT_NE(nullptr, active_web_contents);
+
+  OverlayWindowViews* overlay_window = static_cast<OverlayWindowViews*>(
+      window_controller()->GetWindowForTesting());
+  ASSERT_TRUE(overlay_window);
+
+  // Size should be half the work area.
+  gfx::Size window_size(100, 100);
+  window_size = overlay_window->UpdateMaxSize(gfx::Rect(100, 100), window_size);
+  EXPECT_EQ(gfx::Size(50, 50), window_size);
+  EXPECT_EQ(gfx::Size(50, 50), overlay_window->GetMaximumSize());
+
+  // If the max size increases then we should keep the existing window size.
+  window_size = overlay_window->UpdateMaxSize(gfx::Rect(200, 200), window_size);
+  EXPECT_EQ(gfx::Size(50, 50), window_size);
+  EXPECT_EQ(gfx::Size(100, 100), overlay_window->GetMaximumSize());
+
+  // If the max size decreases then we should shrink to fit.
+  window_size = overlay_window->UpdateMaxSize(gfx::Rect(50, 50), window_size);
+  EXPECT_EQ(gfx::Size(25, 25), window_size);
+  EXPECT_EQ(gfx::Size(25, 25), overlay_window->GetMaximumSize());
+}
diff --git a/chrome/browser/policy/e2e_test/.vpython b/chrome/browser/policy/e2e_test/.vpython
index c7bd7004..262de132 100644
--- a/chrome/browser/policy/e2e_test/.vpython
+++ b/chrome/browser/policy/e2e_test/.vpython
@@ -11,7 +11,7 @@
 
 wheel: <
   name: "infra/celab/celab/windows-amd64"
-  version: "jgh6G7OL6nIJ2-lKS916XK0jDcIP7cCc0FdONt9AwVwC"
+  version: "ewVkoqiGDczXj334qRCQ8uSvGl6dd6XQGAcdbmgwpbsC"
 >
 
 # googleapiclient
@@ -96,4 +96,4 @@
 wheel: <
   name: "infra/python/wheels/wheel-py2_py3"
   version: "version:0.33.1"
->
\ No newline at end of file
+>
diff --git a/chrome/browser/policy/e2e_test/run_tests.py b/chrome/browser/policy/e2e_test/run_tests.py
index 2542c4c..f74071c 100644
--- a/chrome/browser/policy/e2e_test/run_tests.py
+++ b/chrome/browser/policy/e2e_test/run_tests.py
@@ -39,7 +39,7 @@
   parser.add_argument(
       '--test_py',
       dest='test_py',
-      default=os.path.join('test', 'test.py'),
+      default=os.path.join('test.py'),
       help='Path to the script to use to launch a single test')
   parser.add_argument(
       '--test_py_args',
diff --git a/chrome/browser/policy/e2e_test/tests/__init__.py b/chrome/browser/policy/e2e_test/tests/__init__.py
index 98057ef..26eadb6 100644
--- a/chrome/browser/policy/e2e_test/tests/__init__.py
+++ b/chrome/browser/policy/e2e_test/tests/__init__.py
@@ -3,3 +3,14 @@
 # found in the LICENSE file.
 
 from force_google_safe_search.force_google_safe_search import *
+from homepage.homepage import *
+# TODO(feiling): Fix RestoreOnStartupTest on LUCI bots.
+# from restore_on_startup.restore_on_startup import *
+from popups_allowed.popups_allowed import *
+from url_blacklist.url_blacklist import *
+from url_whitelist.url_whitelist import *
+from extension_blacklist.extension_blacklist import *
+from extension_whitelist.extension_whitelist import *
+# TODO(mbinette): Fix TranslateEnabledTest on LUCI bots.
+# from translate_enabled.translate_enabled import *
+from youtube_restrict.youtube_restrict import *
diff --git a/chrome/browser/policy/e2e_test/tests/extension_blacklist/__init__.py b/chrome/browser/policy/e2e_test/tests/extension_blacklist/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/chrome/browser/policy/e2e_test/tests/extension_blacklist/__init__.py
diff --git a/chrome/browser/policy/e2e_test/tests/extension_blacklist/extension_blacklist.py b/chrome/browser/policy/e2e_test/tests/extension_blacklist/extension_blacklist.py
new file mode 100644
index 0000000..67a1ce0
--- /dev/null
+++ b/chrome/browser/policy/e2e_test/tests/extension_blacklist/extension_blacklist.py
@@ -0,0 +1,57 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import logging
+import os
+from chrome_ent_test.ent_tests import ChromeEnterpriseTestCase
+from chrome_ent_test.infra.core import environment, before_all, test
+
+
+@environment(file="../policy_test.asset.textpb")
+class ExtensionInstallBlacklistTest(ChromeEnterpriseTestCase):
+  """Test the ExtensionInstallBlacklist policy.
+    https://www.chromium.org/administrators/policy-list-3#ExtensionInstallBlacklist"""
+
+  @before_all
+  def setup(self):
+    self.InstallChrome('client2012')
+    self.InstallWebDriver('client2012')
+
+  def installExtension(self, url):
+    args = ['--url', url, '--text_only', '--wait', '5']
+
+    dir = os.path.dirname(os.path.abspath(__file__))
+    logging.info('Opening page: %s' % url)
+    output = self.RunWebDriverTest('client2012',
+                                   os.path.join(dir, '../install_extension.py'),
+                                   args)
+    return output
+
+  @test
+  def test_ExtensionBlacklist_all(self):
+    extension = '*'
+    self.SetPolicy('win2012-dc', r'ExtensionInstallBlacklist\1', extension,
+                   'String')
+    self.RunCommand('client2012', 'gpupdate /force')
+    logging.info('Disabled extension install for ' + extension)
+
+    test_url = 'https://chrome.google.com/webstore/detail/google-hangouts/nckgahadagoaajjgafhacjanaoiihapd'
+    output = self.installExtension(test_url)
+    self.assertIn('blocked', output)
+
+  @test
+  def test_ExtensionBlacklist_hangout(self):
+    extension = 'nckgahadagoaajjgafhacjanaoiihapd'
+    self.SetPolicy('win2012-dc', r'ExtensionInstallBlacklist\1', extension,
+                   'String')
+    self.RunCommand('client2012', 'gpupdate /force')
+    logging.info('Disabled extension install for ' + extension)
+
+    test_url = 'https://chrome.google.com/webstore/detail/google-hangouts/nckgahadagoaajjgafhacjanaoiihapd'
+    output = self.installExtension(test_url)
+    self.assertIn('blocked', output)
+
+    positive_test_url = 'https://chrome.google.com/webstore/detail/grammarly-for-chrome/kbfnbcaeplbcioakkpcpgfkobkghlhen'
+    output = self.installExtension(positive_test_url)
+    self.assertNotIn('blocked', output)
diff --git a/chrome/browser/policy/e2e_test/tests/extension_whitelist/__init__.py b/chrome/browser/policy/e2e_test/tests/extension_whitelist/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/chrome/browser/policy/e2e_test/tests/extension_whitelist/__init__.py
diff --git a/chrome/browser/policy/e2e_test/tests/extension_whitelist/extension_whitelist.py b/chrome/browser/policy/e2e_test/tests/extension_whitelist/extension_whitelist.py
new file mode 100644
index 0000000..510ec67
--- /dev/null
+++ b/chrome/browser/policy/e2e_test/tests/extension_whitelist/extension_whitelist.py
@@ -0,0 +1,47 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import logging
+import os
+from chrome_ent_test.ent_tests import ChromeEnterpriseTestCase
+from chrome_ent_test.infra.core import environment, before_all, test
+
+
+@environment(file="../policy_test.asset.textpb")
+class ExtensionInstallWhitelistTest(ChromeEnterpriseTestCase):
+  """Test the ExtensionInstallBlacklist policy.
+    https://www.chromium.org/administrators/policy-list-3#ExtensionInstallWhitelist"""
+
+  @before_all
+  def setup(self):
+    self.InstallChrome('client2012')
+    self.InstallWebDriver('client2012')
+
+  def installExtension(self, url):
+    args = ['--url', url, '--text_only', '--wait', '5']
+
+    dir = os.path.dirname(os.path.abspath(__file__))
+    logging.info('Opening page: %s' % url)
+    output = self.RunWebDriverTest('client2012',
+                                   os.path.join(dir, '../install_extension.py'),
+                                   args)
+    return output
+
+  @test
+  def test_ExtensionWhitelist_hangout(self):
+    extension = 'nckgahadagoaajjgafhacjanaoiihapd'
+    self.SetPolicy('win2012-dc', r'ExtensionInstallBlacklist\1', '*', 'String')
+    self.SetPolicy('win2012-dc', r'ExtensionInstallWhitelist\1', extension,
+                   'String')
+    self.RunCommand('client2012', 'gpupdate /force')
+    logging.info('Whitelist extension install for ' + extension +
+                 ' while disabling others')
+
+    test_url = 'https://chrome.google.com/webstore/detail/google-hangouts/nckgahadagoaajjgafhacjanaoiihapd'
+    output = self.installExtension(test_url)
+    self.assertNotIn('blocked', output)
+
+    negative_test_url = 'https://chrome.google.com/webstore/detail/grammarly-for-chrome/kbfnbcaeplbcioakkpcpgfkobkghlhen'
+    output = self.installExtension(negative_test_url)
+    self.assertIn('blocked', output)
\ No newline at end of file
diff --git a/chrome/browser/policy/e2e_test/tests/homepage/__init__.py b/chrome/browser/policy/e2e_test/tests/homepage/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/chrome/browser/policy/e2e_test/tests/homepage/__init__.py
diff --git a/chrome/browser/policy/e2e_test/tests/homepage/get_homepage_url.py b/chrome/browser/policy/e2e_test/tests/homepage/get_homepage_url.py
new file mode 100644
index 0000000..7bb3f5e
--- /dev/null
+++ b/chrome/browser/policy/e2e_test/tests/homepage/get_homepage_url.py
@@ -0,0 +1,21 @@
+# 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.
+
+from selenium import webdriver
+import os
+from pywinauto.application import Application
+
+driver = webdriver.Chrome(
+    "C:/ProgramData/chocolatey/lib/chromedriver/tools/chromedriver.exe")
+
+try:
+  app = Application(backend="uia")
+  app.connect(title_re='.*Chrome|.*Chromium')
+
+  # Use shortcut Alt+HOME to go to the home page
+  app.top_window().type_keys("%{HOME}")
+
+  print 'homepage:%s' % driver.current_url
+finally:
+  driver.quit()
diff --git a/chrome/browser/policy/e2e_test/tests/homepage/homepage.py b/chrome/browser/policy/e2e_test/tests/homepage/homepage.py
new file mode 100644
index 0000000..632c74b
--- /dev/null
+++ b/chrome/browser/policy/e2e_test/tests/homepage/homepage.py
@@ -0,0 +1,71 @@
+# 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.
+
+import os
+import logging
+import re
+from chrome_ent_test.infra.core import environment, before_all, test
+from chrome_ent_test.ent_tests import ChromeEnterpriseTestCase
+from absl import flags
+
+FLAGS = flags.FLAGS
+
+
+@environment(file="../policy_test.asset.textpb")
+class HomepageTest(ChromeEnterpriseTestCase):
+  """Test HomepageIsNewTabPage and HomepageLocation policies.
+
+  See:
+     https://www.chromium.org/administrators/policy-list-3#HomepageLocation
+     https://www.chromium.org/administrators/policy-list-3#HomepageIsNewTabPage
+  """
+
+  @before_all
+  def setup(self):
+    self.InstallChrome('client2012')
+    self.EnableUITest('client2012')
+
+  def _getHomepageLocation(self, instance_name):
+    dir = os.path.dirname(os.path.abspath(__file__))
+    output = self.RunUITest(instance_name,
+                            os.path.join(dir, 'get_homepage_url.py'))
+    m = re.search(r"homepage:([^ \r\n]+)", output)
+    return m.group(1)
+
+  @test
+  def test_HomepageLocation(self):
+    # Test the case where
+    # -  HomepageIsNewTabPage is false
+    # -  HomepageLocation is set
+    # In this case, when a home page is opened, the HomepageLocation is used
+    self.SetPolicy('win2012-dc', 'HomepageIsNewTabPage', 0, 'DWORD')
+    self.SetPolicy('win2012-dc', 'HomepageLocation',
+                   '"http://www.example.com/"', 'String')
+    self.RunCommand('client2012', 'gpupdate /force')
+
+    # verify the home page is the value of HomepageLocation
+    homepage = self._getHomepageLocation('client2012')
+    self.assertEqual(homepage, 'http://www.example.com/')
+
+  @test
+  def test_HomepageIsNewTab(self):
+    # Test the case when HomepageIsNewTabPage is true
+    # In this case, when a home page is opened, the new tab page will be used.
+    self.SetPolicy('win2012-dc', 'HomepageIsNewTabPage', 1, 'DWORD')
+    self.SetPolicy('win2012-dc', 'HomepageLocation',
+                   '"http://www.example.com/"', 'String')
+    self.RunCommand('client2012', 'gpupdate /force')
+
+    # verify that the home page is the new tab page.
+    homepage = self._getHomepageLocation('client2012')
+
+    # The URL of the new tab can be one of the following:
+    # - https://www.google.com/_/chrome/newtab?ie=UTF-8
+    # - chrome://newtab
+    # - chrome-search://local-ntp/local-ntp.html
+    if ('newtab' in homepage
+       ) or homepage == 'chrome-search://local-ntp/local-ntp.html':
+      pass
+    else:
+      self.fail('homepage url is not new tab: %s' % homepage)
diff --git a/chrome/browser/policy/e2e_test/tests/install_extension.py b/chrome/browser/policy/e2e_test/tests/install_extension.py
new file mode 100644
index 0000000..4188ddc
--- /dev/null
+++ b/chrome/browser/policy/e2e_test/tests/install_extension.py
@@ -0,0 +1,60 @@
+# 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.
+
+from selenium import webdriver
+import os
+import time
+from absl import app, flags
+
+FLAGS = flags.FLAGS
+
+flags.DEFINE_string('url', None, 'The url to open in Chrome.')
+flags.mark_flag_as_required('url')
+
+flags.DEFINE_integer(
+    'wait', 0,
+    'How many seconds to wait between loading the page and printing the source.'
+)
+
+flags.DEFINE_bool('incognito', False,
+                  'Set flag to open Chrome in incognito mode.')
+
+flags.DEFINE_bool(
+    'text_only', False,
+    'Set flag to print only page text (defaults to full source).')
+
+
+def main(argv):
+  chrome_options = webdriver.ChromeOptions()
+
+  if FLAGS.incognito:
+    chrome_options.add_argument('incognito')
+
+  #Always set useAutomationExtension as false to avoid failing launch Chrome
+  #https://bugs.chromium.org/p/chromedriver/issues/detail?id=2930
+  chrome_options.add_experimental_option("useAutomationExtension", False)
+
+  os.environ["CHROME_LOG_FILE"] = r"c:\temp\chrome_log.txt"
+
+  driver = webdriver.Chrome(
+      "C:/ProgramData/chocolatey/lib/chromedriver/tools/chromedriver.exe",
+      service_args=["--verbose", r"--log-path=c:\temp\chromedriver.log"],
+      chrome_options=chrome_options)
+  driver.implicitly_wait(FLAGS.wait)
+  driver.get(FLAGS.url)
+
+  driver.find_element_by_xpath("//div[@aria-label='Add to Chrome']").click()
+  if FLAGS.wait > 0:
+    time.sleep(FLAGS.wait)
+
+  if FLAGS.text_only:
+    print driver.find_element_by_css_selector('html').text.encode('utf-8')
+  else:
+    print driver.page_source.encode('utf-8')
+
+  driver.quit()
+
+
+if __name__ == '__main__':
+  app.run(main)
diff --git a/chrome/browser/policy/e2e_test/tests/open_page.py b/chrome/browser/policy/e2e_test/tests/open_page.py
new file mode 100644
index 0000000..d54237a
--- /dev/null
+++ b/chrome/browser/policy/e2e_test/tests/open_page.py
@@ -0,0 +1,43 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import test_util
+import time
+from absl import app, flags
+
+FLAGS = flags.FLAGS
+
+flags.DEFINE_string('url', None, 'The url to open in Chrome.')
+flags.mark_flag_as_required('url')
+
+flags.DEFINE_integer(
+    'wait', 0,
+    'How many seconds to wait between loading the page and printing the source.'
+)
+
+flags.DEFINE_bool('incognito', False,
+                  'Set flag to open Chrome in incognito mode.')
+
+flags.DEFINE_bool(
+    'text_only', False,
+    'Set flag to print only page text (defaults to full source).')
+
+
+def main(argv):
+  driver = test_util.create_chrome_webdriver(incognito=FLAGS.incognito)
+  driver.get(FLAGS.url)
+
+  if FLAGS.wait > 0:
+    time.sleep(FLAGS.wait)
+
+  if FLAGS.text_only:
+    print driver.find_element_by_css_selector('html').text.encode('utf-8')
+  else:
+    print driver.page_source.encode('utf-8')
+
+  driver.quit()
+
+
+if __name__ == '__main__':
+  app.run(main)
diff --git a/chrome/browser/policy/e2e_test/tests/popups_allowed/__init__.py b/chrome/browser/policy/e2e_test/tests/popups_allowed/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/chrome/browser/policy/e2e_test/tests/popups_allowed/__init__.py
diff --git a/chrome/browser/policy/e2e_test/tests/popups_allowed/popup_allowed_webdriver_test.py b/chrome/browser/policy/e2e_test/tests/popups_allowed/popup_allowed_webdriver_test.py
new file mode 100644
index 0000000..5029678
--- /dev/null
+++ b/chrome/browser/policy/e2e_test/tests/popups_allowed/popup_allowed_webdriver_test.py
@@ -0,0 +1,19 @@
+# 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.
+
+from selenium import webdriver
+
+testSite = "http://www.popuptest.com/popuptest1.html"
+options = webdriver.ChromeOptions()
+options.add_experimental_option('excludeSwitches', ['disable-popup-blocking'])
+exe_path = "C:/ProgramData/chocolatey/lib/chromedriver/tools/chromedriver.exe"
+driver = webdriver.Chrome(
+    exe_path,
+    chrome_options=options,
+    service_args=["--verbose", r"--log-path=c:\temp\chromedriver.log"])
+driver.implicitly_wait(5)
+driver.get(testSite)
+handles = driver.window_handles
+print len(handles)
+driver.quit()
diff --git a/chrome/browser/policy/e2e_test/tests/popups_allowed/popups_allowed.py b/chrome/browser/policy/e2e_test/tests/popups_allowed/popups_allowed.py
new file mode 100644
index 0000000..ae7e0f9
--- /dev/null
+++ b/chrome/browser/policy/e2e_test/tests/popups_allowed/popups_allowed.py
@@ -0,0 +1,57 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import logging
+import os
+from absl import flags
+
+from chrome_ent_test.ent_tests import ChromeEnterpriseTestCase
+from chrome_ent_test.infra.core import environment, before_all, test
+
+FLAGS = flags.FLAGS
+
+
+@environment(file="../policy_test.asset.textpb")
+class PopupsAllowedForUrlsTest(ChromeEnterpriseTestCase):
+  """Test the PopupsAllowedForUrls
+
+    https://www.chromium.org/administrators/policy-list-3#PopupsAllowedForUrls.
+    """
+
+  @before_all
+  def setup(self):
+    self.InstallChrome('client2012')
+    self.InstallWebDriver('client2012')
+
+  @test
+  def test_popup_allow_for_url(self):
+    # Enable "Allow popups on these sites" with testing URL
+    test_site = 'www.popuptest.com'
+    self.SetPolicy('win2012-dc', r'PopupsAllowedForUrls\1', test_site, 'String')
+    self.RunCommand('client2012', 'gpupdate /force')
+    logging.info('Enabled Allow pop-ups on' + test_site)
+
+    # Run webdriver test
+    local_dir = os.path.dirname(os.path.abspath(__file__))
+    output = self.RunWebDriverTest(
+        'client2012', os.path.join(local_dir,
+                                   'popup_allowed_webdriver_test.py'))
+    # Check if new pop up window comes up
+    self.assertTrue(int(output) > 1)
+
+  @test
+  def test_allow_for_other_url(self):
+    # Set the allow popup site using google.com, so popuptest.com is disabled
+    test_site = 'www.google.com'
+    self.SetPolicy('win2012-dc', r'PopupsAllowedForUrls\1', test_site, 'String')
+    self.RunCommand('client2012', 'gpupdate /force')
+    logging.info('Enabled Allow pop-ups on' + test_site)
+
+    # Run webdriver test
+    local_dir = os.path.dirname(os.path.abspath(__file__))
+    output = self.RunWebDriverTest(
+        'client2012', os.path.join(local_dir,
+                                   'popup_allowed_webdriver_test.py'))
+    # Check if the 6 new pop-up windows are blocked
+    self.assertEquals(int(output), 1)
diff --git a/chrome/browser/policy/e2e_test/tests/restore_on_startup/__init__.py b/chrome/browser/policy/e2e_test/tests/restore_on_startup/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/chrome/browser/policy/e2e_test/tests/restore_on_startup/__init__.py
diff --git a/chrome/browser/policy/e2e_test/tests/restore_on_startup/restore_on_startup.py b/chrome/browser/policy/e2e_test/tests/restore_on_startup/restore_on_startup.py
new file mode 100644
index 0000000..a696649
--- /dev/null
+++ b/chrome/browser/policy/e2e_test/tests/restore_on_startup/restore_on_startup.py
@@ -0,0 +1,131 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import json
+import logging
+import os
+
+from absl import flags
+
+from chrome_ent_test.ent_tests import ChromeEnterpriseTestCase
+from chrome_ent_test.infra.core import environment, before_all, test
+
+FLAGS = flags.FLAGS
+
+
+@environment(file="../policy_test.asset.textpb")
+class RestoreOnStartupTest(ChromeEnterpriseTestCase):
+  """Test the RestoreOnStartup policy.
+
+  See https://www.chromium.org/administrators/policy-list-3#RestoreOnStartup."""
+
+  @before_all
+  def setup(self):
+    self.InstallChrome('client2012')
+    self.InstallWebDriver('client2012')
+
+  @test
+  def test_RestoreTheLastSession(self):
+    logging.info('RestoreOnStartup is set to RestoreTheLastSession')
+
+    self.SetPolicy('win2012-dc', 'RestoreOnStartup', 1, 'DWORD')
+    self.RunCommand('client2012', 'gpupdate /force')
+
+    # delete the user data directory to make sure we start from a clean slate.
+    user_data_dir = r'c:\temp\user1'
+    self.RunCommand(
+        'client2012',
+        'if exist %s rmdir /s /q %s' % (user_data_dir, user_data_dir))
+    dir = os.path.dirname(os.path.abspath(__file__))
+    user_data_dir_arg = '--user_data_dir=%s' % user_data_dir
+    urls = ['https://www.cnn.com/', 'https://www.youtube.com/']
+    list.sort(urls)
+
+    # create a session: start Chrome and open several URLs.
+    output = self.RunWebDriverTest(
+        'client2012', os.path.join(dir, 'restore_on_startup_webdriver_test.py'),
+        [
+            '--action=open_urls',
+            user_data_dir_arg,
+        ] + ['--urls=%s' % url for url in urls])
+    output_urls = json.loads(output)
+    self.assertEqual(urls, output_urls)
+
+    # start Chrome. The last session should be restored.
+    output = self.RunWebDriverTest(
+        'client2012', os.path.join(dir, 'restore_on_startup_webdriver_test.py'),
+        [
+            '--action=start_chrome',
+            user_data_dir_arg,
+        ])
+    output_urls = json.loads(output)
+    self.assertEqual(urls, output_urls)
+
+  @test
+  def test_OpenNewTabPage(self):
+    logging.info('RestoreOnStartup is set to Open New Tab Page')
+
+    self.SetPolicy('win2012-dc', 'RestoreOnStartup', 5, 'DWORD')
+    self.RunCommand('client2012', 'gpupdate /force')
+    dir = os.path.dirname(os.path.abspath(__file__))
+    user_data_dir_arg = r'--user_data_dir=c:\temp\user2'
+    urls = ['https://www.cnn.com/', 'https://www.youtube.com/']
+    list.sort(urls)
+
+    # create a session: start Chrome and open several URLs.
+    output = self.RunWebDriverTest(
+        'client2012', os.path.join(dir, 'restore_on_startup_webdriver_test.py'),
+        [
+            '--action=open_urls',
+            user_data_dir_arg,
+        ] + ['--urls=%s' % url for url in urls])
+    output_urls = json.loads(output)
+    self.assertEqual(urls, output_urls)
+
+    # start Chrome. There should be just one New Tab page.
+    output = self.RunWebDriverTest(
+        'client2012', os.path.join(dir, 'restore_on_startup_webdriver_test.py'),
+        [
+            '--action=start_chrome',
+            user_data_dir_arg,
+        ])
+    output_urls = json.loads(output)
+    self.assertEqual(len(output_urls), 1)
+    self.assertTrue('/_/chrome/newtab' in output_urls[0])
+
+  @test
+  def test_OpenListOfUrls(self):
+    logging.info('RestoreOnStartup is set to Open a list of URLs')
+
+    self.SetPolicy('win2012-dc', 'RestoreOnStartup', 4, 'DWORD')
+    urls_to_open = ['https://www.wikipedia.org/']
+    for i in range(len(urls_to_open)):
+      self.SetPolicy('win2012-dc', r'RestoreOnStartupURLs\%s' % (i + 1),
+                     '"%s"' % urls_to_open[i], 'String')
+
+    self.RunCommand('client2012', 'gpupdate /force')
+    dir = os.path.dirname(os.path.abspath(__file__))
+    user_data_dir_arg = r'--user_data_dir=c:\temp\user3'
+    urls = ['https://www.cnn.com/', 'https://www.youtube.com/']
+    list.sort(urls)
+
+    # start Chrome and open several URLs.
+    output = self.RunWebDriverTest(
+        'client2012', os.path.join(dir, 'restore_on_startup_webdriver_test.py'),
+        [
+            '--action=open_urls',
+            user_data_dir_arg,
+        ] + ['--urls=%s' % url for url in urls])
+    output_urls = json.loads(output)
+    self.assertEqual(urls, output_urls)
+
+    # start Chrome. Urls specified by RestoreOnStartupURLs should be opened
+    output = self.RunWebDriverTest(
+        'client2012', os.path.join(dir, 'restore_on_startup_webdriver_test.py'),
+        [
+            '--action=start_chrome',
+            user_data_dir_arg,
+        ])
+    output_urls = json.loads(output)
+    self.assertEqual(urls_to_open, output_urls)
diff --git a/chrome/browser/policy/e2e_test/tests/restore_on_startup/restore_on_startup_webdriver_test.py b/chrome/browser/policy/e2e_test/tests/restore_on_startup/restore_on_startup_webdriver_test.py
new file mode 100644
index 0000000..76a78d3
--- /dev/null
+++ b/chrome/browser/policy/e2e_test/tests/restore_on_startup/restore_on_startup_webdriver_test.py
@@ -0,0 +1,87 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import time
+import test_util
+import json
+from absl import app, flags
+from selenium import webdriver
+from selenium.webdriver.chrome.options import Options
+
+FLAGS = flags.FLAGS
+
+flags.DEFINE_enum(
+    'action', None, ['open_urls', 'start_chrome'], """The action to take.
+
+    - open_urls: start chrome, then open urls passed through --urls in tabs.
+    - start_chrome: start chrome.
+    """)
+
+flags.DEFINE_multi_string('urls', None, "List of urls to open")
+flags.DEFINE_string('user_data_dir', None,
+                    "The user data directory used by chrome")
+
+
+def _create_driver():
+  chrome_options = Options()
+  chrome_options.add_argument(r'user-data-dir=%s' % FLAGS.user_data_dir)
+  driver = webdriver.Chrome(
+      executable_path=
+      "C:/ProgramData/chocolatey/lib/chromedriver/tools/chromedriver.exe",
+      chrome_options=chrome_options,
+      service_args=["--verbose", r"--log-path=c:\temp\chromedriver.log"])
+  return driver
+
+
+def _get_urls(driver):
+  """Returns the list of URLs in tabs."""
+  urls = []
+  for w in driver.window_handles:
+    driver.switch_to.window(w)
+    urls.append(driver.current_url)
+  list.sort(urls)
+  return urls
+
+
+def open_urls():
+  driver = _create_driver()
+
+  # open the first url in the current New Tab tab
+  driver.get(FLAGS.urls[0])
+
+  # open the rest of urls in new tabs
+  for url in FLAGS.urls[1:]:
+    driver.execute_script("window.open('%s');" % url)
+
+  # give chrome some time to load everything
+  time.sleep(2)
+
+  print json.dumps(_get_urls(driver))
+  test_util.shutdown_chrome()
+
+
+def start_chrome():
+  """Start chrome.
+
+  Write the list of URLs in tabs to stdout.
+  """
+  driver = _create_driver()
+
+  # give chrome some time to load everything. This is less than ideal, but
+  # currently there's no statisfactory solution.
+  time.sleep(10)
+
+  print json.dumps(_get_urls(driver))
+  test_util.shutdown_chrome()
+
+
+def main(argv):
+  if FLAGS.action == 'open_urls':
+    open_urls()
+  elif FLAGS.action == 'start_chrome':
+    start_chrome()
+
+
+if __name__ == '__main__':
+  app.run(main)
diff --git a/chrome/browser/policy/e2e_test/tests/translate_enabled/__init__.py b/chrome/browser/policy/e2e_test/tests/translate_enabled/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/chrome/browser/policy/e2e_test/tests/translate_enabled/__init__.py
diff --git a/chrome/browser/policy/e2e_test/tests/translate_enabled/translate_enabled.py b/chrome/browser/policy/e2e_test/tests/translate_enabled/translate_enabled.py
new file mode 100644
index 0000000..1083717
--- /dev/null
+++ b/chrome/browser/policy/e2e_test/tests/translate_enabled/translate_enabled.py
@@ -0,0 +1,51 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import logging
+import os
+from chrome_ent_test.ent_tests import ChromeEnterpriseTestCase
+from chrome_ent_test.infra.core import environment, before_all, test
+
+
+@environment(file="../policy_test.asset.textpb")
+class TranslateEnabledTest(ChromeEnterpriseTestCase):
+  """Test the TranslateEnabled policy.
+
+  See https://www.chromium.org/administrators/policy-list-3#TranslateEnabled"""
+
+  @before_all
+  def setup(self):
+    self.InstallChrome('client2012')
+    self.InstallWebDriver('client2012')
+
+  def isChromeTranslateEnabled(self, incognito=False):
+    dir = os.path.dirname(os.path.abspath(__file__))
+    output = self.RunWebDriverTest(
+        'client2012', os.path.join(dir, 'translate_enabled_webdriver_test.py'),
+        ['--incognito'] if incognito else [])
+    return "TRUE" in output
+
+  @test
+  def test_TranslatedDisabled(self, incognito=False):
+    self.SetPolicy('win2012-dc', 'TranslateEnabled', 0, 'DWORD')
+    self.RunCommand('client2012', 'gpupdate /force')
+
+    enabled = self.isChromeTranslateEnabled()
+    self.assertFalse(enabled)
+
+  @test
+  def test_TranslatedEnabled(self, incognito=False):
+    self.SetPolicy('win2012-dc', 'TranslateEnabled', 1, 'DWORD')
+    self.RunCommand('client2012', 'gpupdate /force')
+
+    enabled = self.isChromeTranslateEnabled()
+    self.assertTrue(enabled)
+
+  @test
+  def test_TranslatedDisabledIncognito(self):
+    self.test_TranslatedDisabled(incognito=True)
+
+  @test
+  def test_TranslatedEnabledIncognito(self):
+    self.test_TranslatedEnabled(incognito=True)
diff --git a/chrome/browser/policy/e2e_test/tests/translate_enabled/translate_enabled_webdriver_test.py b/chrome/browser/policy/e2e_test/tests/translate_enabled/translate_enabled_webdriver_test.py
new file mode 100644
index 0000000..a31e780
--- /dev/null
+++ b/chrome/browser/policy/e2e_test/tests/translate_enabled/translate_enabled_webdriver_test.py
@@ -0,0 +1,49 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import time
+import test_util
+from absl import app, flags
+from selenium import webdriver
+from selenium.webdriver.chrome.options import Options
+
+# A URL that is in a different language than our Chrome language. It should be
+# a site stable enough for us to rely on for our tests, and have a somewhat
+# static string we can use to tell if translate worked (see below).
+URL = "https://zh.wikipedia.org/wiki/Chromium"
+
+# The magic string to look for on the translated page.
+# This string must NOT be on the original page.
+MAGIC_STRING_ENGLISH = "Wikipedia, the free encyclopedia"
+
+# We automatically accept Translate prompts from Chinese (Simpl.) to English.
+# Ideally we would detect the Translate prompt and return TRUE/FALSE based on
+# that, but webdriver doesn't support this AFAIK.
+PREFS = {"translate_whitelists": {"zh-CN": "en"}}
+
+FLAGS = flags.FLAGS
+
+flags.DEFINE_bool('incognito', False,
+                  'Set flag to open Chrome in incognito mode.')
+
+
+def main(argv):
+  driver = test_util.create_chrome_webdriver(
+      incognito=FLAGS.incognito, prefs=PREFS)
+  driver.get(URL)
+
+  time.sleep(10)
+
+  output = driver.find_element_by_css_selector('html').text.encode('utf-8')
+
+  if MAGIC_STRING_ENGLISH in output:
+    print "TRUE"
+  else:
+    print "FALSE"
+
+  driver.quit()
+
+
+if __name__ == '__main__':
+  app.run(main)
diff --git a/chrome/browser/policy/e2e_test/tests/url_blacklist/__init__.py b/chrome/browser/policy/e2e_test/tests/url_blacklist/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/chrome/browser/policy/e2e_test/tests/url_blacklist/__init__.py
diff --git a/chrome/browser/policy/e2e_test/tests/url_blacklist/url_blacklist.py b/chrome/browser/policy/e2e_test/tests/url_blacklist/url_blacklist.py
new file mode 100644
index 0000000..ccb435c
--- /dev/null
+++ b/chrome/browser/policy/e2e_test/tests/url_blacklist/url_blacklist.py
@@ -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.
+
+import logging
+import os
+from chrome_ent_test.ent_tests import ChromeEnterpriseTestCase
+from chrome_ent_test.infra.core import environment, before_all, test
+
+
+@environment(file="../policy_test.asset.textpb")
+class UrlBlacklistTest(ChromeEnterpriseTestCase):
+  """Test the URLBlacklist policy.
+
+  See https://www.chromium.org/administrators/policy-list-3#URLBlacklist"""
+
+  @before_all
+  def setup(self):
+    self.InstallChrome('client2012')
+    self.InstallWebDriver('client2012')
+
+  def openPage(self, url, incognito=False):
+    args = ['--url', url, '--text_only']
+    if incognito:
+      args += ['--incognito']
+
+    dir = os.path.dirname(os.path.abspath(__file__))
+    logging.info('Opening page: %s' % url)
+    output = self.RunWebDriverTest('client2012',
+                                   os.path.join(dir, '../open_page.py'), args)
+    return output
+
+  @test
+  def test_BlacklistAllCantVisit(self, incognito=False):
+    self.SetPolicy('win2012-dc', r'URLBlacklist\1', '*', 'String')
+    self.RunCommand('client2012', 'gpupdate /force')
+
+    # Verify that we can't visit any site.
+    output = self.openPage('https://youtube.com/yt/about/', incognito=incognito)
+    self.assertIn("ERR_BLOCKED_BY_ADMINISTRATOR", output)
+
+    output = self.openPage('https://google.com', incognito=incognito)
+    self.assertIn("ERR_BLOCKED_BY_ADMINISTRATOR", output)
+
+  @test
+  def test_BlacklistYouTubeCantVisit(self, incognito=False):
+    self.SetPolicy('win2012-dc', r'URLBlacklist\1', 'https://youtube.com',
+                   'String')
+    self.RunCommand('client2012', 'gpupdate /force')
+
+    # Verify that we can't visit YouTube, but can still visit other sites.
+    output = self.openPage('https://youtube.com/yt/about/', incognito=incognito)
+    self.assertIn("ERR_BLOCKED_BY_ADMINISTRATOR", output)
+
+    output = self.openPage('https://google.com', incognito=incognito)
+    self.assertNotIn("ERR_BLOCKED_BY_ADMINISTRATOR", output)
+
+  @test
+  def test_BlacklistAllCantVisitIncognito(self):
+    self.test_BlacklistAllCantVisit(incognito=True)
+
+  @test
+  def test_BlacklistYouTubeCantVisitIncognito(self):
+    self.test_BlacklistYouTubeCantVisit(incognito=True)
diff --git a/chrome/browser/policy/e2e_test/tests/url_whitelist/__init__.py b/chrome/browser/policy/e2e_test/tests/url_whitelist/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/chrome/browser/policy/e2e_test/tests/url_whitelist/__init__.py
diff --git a/chrome/browser/policy/e2e_test/tests/url_whitelist/url_whitelist.py b/chrome/browser/policy/e2e_test/tests/url_whitelist/url_whitelist.py
new file mode 100644
index 0000000..4176554
--- /dev/null
+++ b/chrome/browser/policy/e2e_test/tests/url_whitelist/url_whitelist.py
@@ -0,0 +1,61 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import logging
+import os
+from chrome_ent_test.ent_tests import ChromeEnterpriseTestCase
+from chrome_ent_test.infra.core import environment, before_all, test
+
+
+@environment(file="../policy_test.asset.textpb")
+class UrlWhitelistTest(ChromeEnterpriseTestCase):
+  """Test the URLWhitelist policy.
+
+  This policy provides exceptions to the URLBlacklist policy.
+
+  See https://www.chromium.org/administrators/policy-list-3#URLBlacklist
+  and https://www.chromium.org/administrators/policy-list-3#URLWhitelist"""
+
+  @before_all
+  def setup(self):
+    client = 'client2012'
+    dc = 'win2012-dc'
+    self.InstallChrome(client)
+    self.InstallWebDriver(client)
+
+    # Blacklist all sites and add an exception with URLWhitelist.
+    self.SetPolicy(dc, r'URLBlacklist\1', '*', 'String')
+    self.SetPolicy(dc, r'URLWhitelist\1', 'https://youtube.com', 'String')
+    self.RunCommand(client, 'gpupdate /force')
+
+  def openPage(self, url, incognito=False):
+    args = ['--url', url, '--text_only']
+    if incognito:
+      args += ['--incognito']
+
+    dir = os.path.dirname(os.path.abspath(__file__))
+    logging.info('Opening page: %s' % url)
+    output = self.RunWebDriverTest('client2012',
+                                   os.path.join(dir, '../open_page.py'), args)
+    return output
+
+  @test
+  def test_AllowedUrlCanVisit(self):
+    output = self.openPage('https://youtube.com/yt/about/')
+    self.assertNotIn("ERR_BLOCKED_BY_ADMINISTRATOR", output)
+
+  @test
+  def test_NotAllowedUrlCantVisit(self):
+    output = self.openPage('https://google.com')
+    self.assertIn("ERR_BLOCKED_BY_ADMINISTRATOR", output)
+
+  @test
+  def test_AllowedUrlCanVisitIncognito(self):
+    output = self.openPage('https://youtube.com/yt/about/', incognito=True)
+    self.assertNotIn("ERR_BLOCKED_BY_ADMINISTRATOR", output)
+
+  @test
+  def test_NotAllowedUrlCantVisitIncognito(self):
+    output = self.openPage('https://google.com', incognito=True)
+    self.assertIn("ERR_BLOCKED_BY_ADMINISTRATOR", output)
diff --git a/chrome/browser/policy/e2e_test/tests/youtube_restrict/__init__.py b/chrome/browser/policy/e2e_test/tests/youtube_restrict/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/chrome/browser/policy/e2e_test/tests/youtube_restrict/__init__.py
diff --git a/chrome/browser/policy/e2e_test/tests/youtube_restrict/youtube_restrict.py b/chrome/browser/policy/e2e_test/tests/youtube_restrict/youtube_restrict.py
new file mode 100644
index 0000000..03651956
--- /dev/null
+++ b/chrome/browser/policy/e2e_test/tests/youtube_restrict/youtube_restrict.py
@@ -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.
+
+import logging
+import os
+from chrome_ent_test.ent_tests import ChromeEnterpriseTestCase
+from chrome_ent_test.infra.core import environment, before_all, test
+
+
+@environment(file="../policy_test.asset.textpb")
+class YouTubeRestrictTest(ChromeEnterpriseTestCase):
+  """Test the ForceYouTubeRestrict policy.
+
+  See https://www.chromium.org/administrators/policy-list-3#ForceYouTubeRestrict"""
+
+  RestrictedText = "This video is restricted. " \
+      + "Try signing in with a Google Apps account."
+
+  @before_all
+  def setup(self):
+    self.InstallChrome('client2012')
+    self.InstallWebDriver('client2012')
+
+  def openRestrictedVideo(self):
+    url = "https://www.youtube.com/watch?v=JtvhQ6klunk"
+    dir = os.path.dirname(os.path.abspath(__file__))
+    logging.info('Opening page: %s' % url)
+    output = self.RunWebDriverTest('client2012',
+                                   os.path.join(dir, '../open_page.py'),
+                                   ['--url', url, '--wait=5', '--text_only'])
+    return output
+
+  @test
+  def test_UnrestrictedYouTubeCanWatchVideo(self):
+    self.SetPolicy('win2012-dc', 'ForceYouTubeRestrict', 0, 'DWORD')
+    self.RunCommand('client2012', 'gpupdate /force')
+
+    output = self.openRestrictedVideo()
+    self.assertNotIn(YouTubeRestrictTest.RestrictedText, output)
+
+  @test
+  def test_StrictRestrictedYouTubeCantWatchVideo(self):
+    self.SetPolicy('win2012-dc', 'ForceYouTubeRestrict', 2, 'DWORD')
+    self.RunCommand('client2012', 'gpupdate /force')
+
+    output = self.openRestrictedVideo()
+    self.assertIn(YouTubeRestrictTest.RestrictedText, output)
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 718e84d..b4c24cf 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -1129,4 +1129,7 @@
 #if defined(OS_MACOSX)
   profile_prefs->ClearPref(password_manager::prefs::kKeychainMigrationStatus);
 #endif  // defined(OS_MACOSX)
+
+  // Added 7/2019.
+  syncer::MigrateSyncSuppressedPref(profile_prefs);
 }
diff --git a/chrome/browser/previews/previews_prober.cc b/chrome/browser/previews/previews_prober.cc
index 66aef53..4f2205fa 100644
--- a/chrome/browser/previews/previews_prober.cc
+++ b/chrome/browser/previews/previews_prober.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "base/guid.h"
 #include "base/time/default_tick_clock.h"
+#include "build/build_config.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/network_service_instance.h"
 #include "net/base/load_flags.h"
@@ -50,6 +51,20 @@
   }
 }
 
+#if defined(OS_ANDROID)
+bool IsInForeground(base::android::ApplicationState state) {
+  switch (state) {
+    case base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES:
+      return true;
+    case base::android::APPLICATION_STATE_UNKNOWN:
+    case base::android::APPLICATION_STATE_HAS_PAUSED_ACTIVITIES:
+    case base::android::APPLICATION_STATE_HAS_STOPPED_ACTIVITIES:
+    case base::android::APPLICATION_STATE_HAS_DESTROYED_ACTIVITIES:
+      return false;
+  }
+}
+#endif
+
 }  // namespace
 
 PreviewsProber::RetryPolicy::RetryPolicy() = default;
@@ -139,17 +154,45 @@
   retry_timer_.reset();
   timeout_timer_.reset();
   url_loader_.reset();
+#if defined(OS_ANDROID)
+  application_status_listener_.reset();
+#endif
 }
 
-void PreviewsProber::SendNowIfInactive() {
+void PreviewsProber::SendNowIfInactive(bool send_only_in_foreground) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (is_active_)
     return;
 
+#if defined(OS_ANDROID)
+  if (send_only_in_foreground &&
+      !IsInForeground(base::android::ApplicationStatusListener::GetState())) {
+    // base::Unretained is safe here because the callback is owned by
+    // |application_status_listener_| which is owned by |this|.
+    application_status_listener_ =
+        base::android::ApplicationStatusListener::New(base::BindRepeating(
+            &PreviewsProber::OnApplicationStateChange, base::Unretained(this)));
+    return;
+  }
+#endif
+
   CreateAndStartURLLoader();
 }
 
+#if defined(OS_ANDROID)
+void PreviewsProber::OnApplicationStateChange(
+    base::android::ApplicationState new_state) {
+  DCHECK(application_status_listener_);
+
+  if (!IsInForeground(new_state))
+    return;
+
+  SendNowIfInactive(false);
+  application_status_listener_.reset();
+}
+#endif
+
 void PreviewsProber::OnConnectionChanged(network::mojom::ConnectionType type) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
diff --git a/chrome/browser/previews/previews_prober.h b/chrome/browser/previews/previews_prober.h
index 6476e45..af057e9 100644
--- a/chrome/browser/previews/previews_prober.h
+++ b/chrome/browser/previews/previews_prober.h
@@ -15,12 +15,17 @@
 #include "base/sequence_checker.h"
 #include "base/time/tick_clock.h"
 #include "base/timer/timer.h"
+#include "build/build_config.h"
 #include "net/base/net_errors.h"
 #include "net/http/http_request_headers.h"
 #include "services/network/public/cpp/network_connection_tracker.h"
 #include "services/network/public/cpp/resource_response.h"
 #include "url/gurl.h"
 
+#if defined(OS_ANDROID)
+#include "base/android/application_status_listener.h"
+#endif
+
 namespace network {
 class NetworkConnectionTracker;
 class SimpleURLLoader;
@@ -125,8 +130,10 @@
   ~PreviewsProber() override;
 
   // Sends a probe now if the prober is currently inactive. If the probe is
-  // active (i.e.: there are probes in flight), this is a no-op.
-  void SendNowIfInactive();
+  // active (i.e.: there are probes in flight), this is a no-op. If
+  // |send_only_in_foreground| is set, the probe will only be sent when the app
+  // is in the foreground (work on Android only).
+  void SendNowIfInactive(bool send_only_in_foreground);
 
   // Returns the successfulness of the last probe, if there was one.
   base::Optional<bool> LastProbeWasSuccessful() const;
@@ -159,6 +166,9 @@
   void ProcessProbeSuccess();
   void AddSelfAsNetworkConnectionObserver(
       network::NetworkConnectionTracker* network_connection_tracker);
+#if defined(OS_ANDROID)
+  void OnApplicationStateChange(base::android::ApplicationState new_state);
+#endif
 
   // Must outlive |this|.
   Delegate* delegate_;
@@ -215,6 +225,13 @@
   // The URLLoader used for the probe. Expected to be non-null iff |is_active_|.
   std::unique_ptr<network::SimpleURLLoader> url_loader_;
 
+#if defined(OS_ANDROID)
+  // Set if |SendInForegroundIfInactive| is called while app is in the
+  // background and listens until app comes to the foreground, then resets.
+  std::unique_ptr<base::android::ApplicationStatusListener>
+      application_status_listener_;
+#endif
+
   SEQUENCE_CHECKER(sequence_checker_);
 
   base::WeakPtrFactory<PreviewsProber> weak_factory_;
diff --git a/chrome/browser/previews/previews_prober_browsertest.cc b/chrome/browser/previews/previews_prober_browsertest.cc
index d962b40..c3954a1 100644
--- a/chrome/browser/previews/previews_prober_browsertest.cc
+++ b/chrome/browser/previews/previews_prober_browsertest.cc
@@ -132,7 +132,7 @@
                         PreviewsProber::ClientName::kLitepages, url,
                         PreviewsProber::HttpMethod::kGet, headers, retry_policy,
                         timeout_policy);
-  prober.SendNowIfInactive();
+  prober.SendNowIfInactive(false);
   WaitForCompletedProbe(&prober);
 
   EXPECT_TRUE(prober.LastProbeWasSuccessful().value());
@@ -153,7 +153,7 @@
                         PreviewsProber::ClientName::kLitepages, url,
                         PreviewsProber::HttpMethod::kGet, headers, retry_policy,
                         timeout_policy);
-  prober.SendNowIfInactive();
+  prober.SendNowIfInactive(false);
   WaitForCompletedProbe(&prober);
 
   EXPECT_FALSE(prober.LastProbeWasSuccessful().value());
diff --git a/chrome/browser/previews/previews_prober_unittest.cc b/chrome/browser/previews/previews_prober_unittest.cc
index ce36be51..fed276b6 100644
--- a/chrome/browser/previews/previews_prober_unittest.cc
+++ b/chrome/browser/previews/previews_prober_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/previews/previews_prober.h"
 
+#include "build/build_config.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "net/base/load_flags.h"
 #include "net/base/net_errors.h"
@@ -172,7 +173,7 @@
   std::unique_ptr<PreviewsProber> prober = NewProber();
   EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt);
 
-  prober->SendNowIfInactive();
+  prober->SendNowIfInactive(false);
   VerifyRequest();
 
   MakeResponseAndWait(net::HTTP_OK, net::OK);
@@ -186,9 +187,9 @@
 
   // Calling |SendNowIfInactive| many times should result in only one url
   // request, which is verified in |VerifyRequest|.
-  prober->SendNowIfInactive();
-  prober->SendNowIfInactive();
-  prober->SendNowIfInactive();
+  prober->SendNowIfInactive(false);
+  prober->SendNowIfInactive(false);
+  prober->SendNowIfInactive(false);
   VerifyRequest();
 }
 
@@ -204,11 +205,32 @@
   EXPECT_TRUE(prober->is_active());
 }
 
+#if defined(OS_ANDROID)
+TEST_F(PreviewsProberTest, StartInForeground) {
+  std::unique_ptr<PreviewsProber> prober = NewProber();
+  EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt);
+  EXPECT_FALSE(prober->is_active());
+
+  prober->SendNowIfInactive(true);
+  EXPECT_TRUE(prober->is_active());
+}
+
+TEST_F(PreviewsProberTest, DoesntCallSendInForegroundIfInactive) {
+  std::unique_ptr<PreviewsProber> prober = NewProber();
+  EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt);
+  EXPECT_FALSE(prober->is_active());
+
+  base::android::ApplicationStatusListener::NotifyApplicationStateChange(
+      base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES);
+  EXPECT_FALSE(prober->is_active());
+}
+#endif
+
 TEST_F(PreviewsProberTest, NetError) {
   std::unique_ptr<PreviewsProber> prober = NewProber();
   EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt);
 
-  prober->SendNowIfInactive();
+  prober->SendNowIfInactive(false);
   VerifyRequest();
 
   MakeResponseAndWait(net::HTTP_OK, net::ERR_FAILED);
@@ -220,7 +242,7 @@
   std::unique_ptr<PreviewsProber> prober = NewProber();
   EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt);
 
-  prober->SendNowIfInactive();
+  prober->SendNowIfInactive(false);
   VerifyRequest();
 
   MakeResponseAndWait(net::HTTP_NOT_FOUND, net::OK);
@@ -237,7 +259,7 @@
       NewProberWithRetryPolicy(retry_policy);
   EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt);
 
-  prober->SendNowIfInactive();
+  prober->SendNowIfInactive(false);
   VerifyRequest(true /* expect_random_guid */);
 
   MakeResponseAndWait(net::HTTP_OK, net::ERR_FAILED);
@@ -255,7 +277,7 @@
       NewProberWithRetryPolicy(retry_policy);
   EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt);
 
-  prober->SendNowIfInactive();
+  prober->SendNowIfInactive(false);
   VerifyRequest();
   MakeResponseAndWait(net::HTTP_OK, net::ERR_FAILED);
   EXPECT_FALSE(prober->LastProbeWasSuccessful().value());
@@ -290,7 +312,7 @@
       NewProberWithRetryPolicy(retry_policy);
   EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt);
 
-  prober->SendNowIfInactive();
+  prober->SendNowIfInactive(false);
   VerifyRequest();
   MakeResponseAndWait(net::HTTP_OK, net::ERR_FAILED);
   EXPECT_FALSE(prober->LastProbeWasSuccessful().value());
@@ -329,7 +351,7 @@
   EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt);
 
   // First attempt.
-  prober->SendNowIfInactive();
+  prober->SendNowIfInactive(false);
   VerifyRequest();
   FastForward(base::TimeDelta::FromMilliseconds(999));
   VerifyRequest();
@@ -365,7 +387,7 @@
   EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt);
 
   // First attempt.
-  prober->SendNowIfInactive();
+  prober->SendNowIfInactive(false);
   VerifyRequest();
   FastForward(base::TimeDelta::FromMilliseconds(999));
   VerifyRequest();
@@ -400,7 +422,7 @@
       &delegate, retry_policy, PreviewsProber::TimeoutPolicy());
   EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt);
 
-  prober->SendNowIfInactive();
+  prober->SendNowIfInactive(false);
   EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt);
   EXPECT_FALSE(prober->is_active());
   VerifyNoRequests();
@@ -418,7 +440,7 @@
       &delegate, retry_policy, PreviewsProber::TimeoutPolicy());
   EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt);
 
-  prober->SendNowIfInactive();
+  prober->SendNowIfInactive(false);
   VerifyRequest();
   MakeResponseAndWait(net::HTTP_OK, net::ERR_FAILED);
   EXPECT_FALSE(prober->LastProbeWasSuccessful().value());
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index 720c38bc..74e8591 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -343,8 +343,8 @@
     google_services_user_account_id_.Init(prefs::kGoogleServicesUserAccountId,
                                           pref_service);
     google_services_user_account_id_.MoveToSequence(io_task_runner);
-    sync_suppress_start_.Init(syncer::prefs::kSyncSuppressStart, pref_service);
-    sync_suppress_start_.MoveToSequence(io_task_runner);
+    sync_requested_.Init(syncer::prefs::kSyncRequested, pref_service);
+    sync_requested_.MoveToSequence(io_task_runner);
     sync_first_setup_complete_.Init(syncer::prefs::kSyncFirstSetupComplete,
                                     pref_service);
     sync_first_setup_complete_.MoveToSequence(io_task_runner);
@@ -475,8 +475,7 @@
 }
 
 bool ProfileIOData::IsSyncEnabled() const {
-  return sync_first_setup_complete_.GetValue() &&
-         !sync_suppress_start_.GetValue();
+  return sync_first_setup_complete_.GetValue() && sync_requested_.GetValue();
 }
 
 #if !defined(OS_CHROMEOS)
@@ -579,7 +578,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   google_services_user_account_id_.Destroy();
-  sync_suppress_start_.Destroy();
+  sync_requested_.Destroy();
   sync_first_setup_complete_.Destroy();
 #if !defined(OS_CHROMEOS)
   signin_scoped_device_id_.Destroy();
diff --git a/chrome/browser/profiles/profile_io_data.h b/chrome/browser/profiles/profile_io_data.h
index f5f1545..bb2f81a 100644
--- a/chrome/browser/profiles/profile_io_data.h
+++ b/chrome/browser/profiles/profile_io_data.h
@@ -293,7 +293,7 @@
       client_cert_store_factory_;
 
   mutable StringPrefMember google_services_user_account_id_;
-  mutable BooleanPrefMember sync_suppress_start_;
+  mutable BooleanPrefMember sync_requested_;
   mutable BooleanPrefMember sync_first_setup_complete_;
   mutable signin::AccountConsistencyMethod account_consistency_;
 
diff --git a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
index ee806bd..10a553a 100644
--- a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
+++ b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
@@ -353,6 +353,7 @@
    */
   updateGuestButtonVisibility_: function() {
     let showGuestInOobe = !this.isClosable_() && this.isAtTheBeginning_();
+    // TODO(rsorokin): Rename message string to reflect the meaning.
     chrome.send('showGuestInOobe', [showGuestInOobe]);
   },
 
diff --git a/chrome/browser/resources/local_ntp/customize.js b/chrome/browser/resources/local_ntp/customize.js
index 6b6b9e8..92ad17b6 100644
--- a/chrome/browser/resources/local_ntp/customize.js
+++ b/chrome/browser/resources/local_ntp/customize.js
@@ -1357,6 +1357,12 @@
   $(customize.IDS.EDIT_BG_ICON)
       .setAttribute('title', configData.translatedStrings.customizeBackground);
 
+  // Selecting a local image for the background should close the picker.
+  if (configData.richerPicker) {
+    ntpApiHandle.onlocalbackgroundselected =
+        customize.richerPicker_applyCustomization;
+  }
+
   // Edit gear icon interaction events.
   const editBackgroundInteraction = function() {
     if (configData.richerPicker) {
diff --git a/chrome/browser/resources/local_ntp/local_ntp.js b/chrome/browser/resources/local_ntp/local_ntp.js
index ea0c76a..a4619d78 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.js
+++ b/chrome/browser/resources/local_ntp/local_ntp.js
@@ -405,7 +405,8 @@
       // should close the customization menu. Closing the menu before the image
       // is selected doesn't look good.
       const localImageFileName = 'background.jpg';
-      if (imageWithOverlay.includes(localImageFileName) &&
+      if (!configData.richerPicker &&
+          imageWithOverlay.includes(localImageFileName) &&
           !$(IDS.CUSTOM_BG)
                .style.backgroundImage.includes(localImageFileName)) {
         customize.closeCustomizationDialog();
diff --git a/chrome/browser/resources/policy/policy.html b/chrome/browser/resources/policy/policy.html
index 0cbdeba..b059bc46 100644
--- a/chrome/browser/resources/policy/policy.html
+++ b/chrome/browser/resources/policy/policy.html
@@ -113,6 +113,10 @@
         <div class="label">$i18n{labelIsAffiliated}</div>
         <div class="is-affiliated"></div>
       </div>
+      <div class="status-entry" hidden>
+        <div class="label">$i18n{labelIsOffHoursActive}</div>
+        <div class="is-offhours-active"></div>
+      </div>
     </fieldset>
 
     <div class="policy-table" id="policy-table-template">
diff --git a/chrome/browser/resources/policy/policy_base.js b/chrome/browser/resources/policy/policy_base.js
index 848318b9..47e5f49d 100644
--- a/chrome/browser/resources/policy/policy_base.js
+++ b/chrome/browser/resources/policy/policy_base.js
@@ -124,6 +124,13 @@
         this.setLabelAndShow_(
             '.directory-api-id', status.directoryApiId || notSpecifiedString);
         this.setLabelAndShow_('.client-id', status.clientId);
+        //For off-hours policy, indicate if it's active or not.
+        if (status.isOffHoursActive != null) {
+          this.setLabelAndShow_(
+              '.is-offhours-active',
+              loadTimeData.getString(
+                  status.isOffHoursActive ? 'offHoursActive' : 'offHoursNotActive'));
+        }
       } else if (scope == 'machine') {
         // For machine policy, set the appropriate title and populate
         // machine enrollment status with the information that applies
diff --git a/chrome/browser/ssl/ssl_client_certificate_selector_test.cc b/chrome/browser/ssl/ssl_client_certificate_selector_test.cc
index ac897571..fd1d508 100644
--- a/chrome/browser/ssl/ssl_client_certificate_selector_test.cc
+++ b/chrome/browser/ssl/ssl_client_certificate_selector_test.cc
@@ -33,7 +33,7 @@
 }
 
 void SSLClientCertificateSelectorTestBase::SetUpInProcessBrowserTestFixture() {
-  cert_request_info_ = new net::SSLCertRequestInfo;
+  cert_request_info_ = base::MakeRefCounted<net::SSLCertRequestInfo>();
   cert_request_info_->host_and_port = net::HostPortPair("foo", 123);
 }
 
diff --git a/chrome/browser/ui/android/passwords/manual_filling_view_android.cc b/chrome/browser/ui/android/passwords/manual_filling_view_android.cc
index 5ee2501..329bf916 100644
--- a/chrome/browser/ui/android/passwords/manual_filling_view_android.cc
+++ b/chrome/browser/ui/android/passwords/manual_filling_view_android.cc
@@ -22,11 +22,11 @@
 #include "chrome/android/features/keyboard_accessory/jni_headers/UserInfoField_jni.h"
 #include "chrome/browser/autofill/manual_filling_controller.h"
 #include "chrome/browser/autofill/manual_filling_controller_impl.h"
-#include "chrome/browser/password_manager/password_accessory_controller.h"
+#include "chrome/browser/password_manager/chrome_password_manager_client.h"
 #include "chrome/browser/password_manager/password_accessory_metrics_util.h"
-#include "chrome/browser/password_manager/password_generation_controller.h"
 #include "components/autofill/core/browser/ui/accessory_sheet_data.h"
 #include "components/autofill/core/common/password_form.h"
+#include "components/password_manager/core/browser/credential_cache.h"
 #include "ui/android/view_android.h"
 #include "ui/android/window_android.h"
 #include "ui/gfx/android/java_bitmap.h"
@@ -201,17 +201,6 @@
     const base::android::JavaParamRef<jobjectArray>& j_passwords) {
   content::WebContents* web_contents =
       content::WebContents::FromJavaWebContents(j_web_contents);
-  PasswordAccessoryController* pwd_controller =
-      static_cast<ManualFillingControllerImpl*>(
-          ManualFillingControllerImpl::GetOrCreate(web_contents).get())
-          ->password_controller_for_testing();
-
-  if (!pwd_controller) {
-    // If the controller isn't initialized (e.g. because the flags are not set),
-    // fail silently so tests can use shared setup methods for old and new UI.
-    LOG(ERROR) << "Tried to fill cache of non-existent accessory controller.";
-    return;
-  }
 
   url::Origin origin = url::Origin::Create(web_contents->GetLastCommittedURL());
   std::vector<std::string> usernames;
@@ -228,7 +217,9 @@
     password_forms[i].password_value = base::ASCIIToUTF16(passwords[i]);
     credentials[password_forms[i].username_value] = &password_forms[i];
   }
-  pwd_controller->SavePasswordsForOrigin(credentials, origin);
+  return ChromePasswordManagerClient::FromWebContents(web_contents)
+      ->GetCredentialCacheForTesting()
+      ->SaveCredentialsForOrigin(credentials, origin);
 }
 
 // static
diff --git a/chrome/browser/ui/blocked_content/framebust_block_tab_helper.cc b/chrome/browser/ui/blocked_content/framebust_block_tab_helper.cc
index f9ced124..7782b403 100644
--- a/chrome/browser/ui/blocked_content/framebust_block_tab_helper.cc
+++ b/chrome/browser/ui/blocked_content/framebust_block_tab_helper.cc
@@ -5,20 +5,8 @@
 #include "chrome/browser/ui/blocked_content/framebust_block_tab_helper.h"
 
 #include "base/logging.h"
-#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/content_settings/chrome_content_settings_utils.h"
 #include "content/public/browser/navigation_handle.h"
-#include "content/public/browser/notification_service.h"
-
-namespace {
-
-void UpdateLocationBarUI(content::WebContents* contents) {
-  content::NotificationService::current()->Notify(
-      chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
-      content::Source<content::WebContents>(contents),
-      content::NotificationService::NoDetails());
-}
-
-}  // namespace
 
 FramebustBlockTabHelper::~FramebustBlockTabHelper() = default;
 
@@ -29,7 +17,7 @@
   DCHECK_EQ(blocked_urls_.size(), callbacks_.size());
 
   manager_.NotifyObservers(0 /* id */, blocked_url);
-  UpdateLocationBarUI(web_contents());
+  content_settings::UpdateLocationBarUiForWebContents(web_contents());
 }
 
 bool FramebustBlockTabHelper::HasBlockedUrls() const {
@@ -61,7 +49,7 @@
   blocked_urls_.clear();
   callbacks_.clear();
 
-  UpdateLocationBarUI(web_contents());
+  content_settings::UpdateLocationBarUiForWebContents(web_contents());
 }
 
 WEB_CONTENTS_USER_DATA_KEY_IMPL(FramebustBlockTabHelper)
diff --git a/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc b/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc
index 7df5f3b..7f43575 100644
--- a/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc
+++ b/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc
@@ -30,6 +30,7 @@
 #include "chrome/browser/ui/login/login_handler.h"
 #include "chrome/browser/ui/login/login_handler_test_utils.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/view_ids.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
@@ -221,12 +222,8 @@
     // Launch the blocked popup.
     PopupBlockerTabHelper* popup_blocker_helper =
         PopupBlockerTabHelper::FromWebContents(web_contents);
-    if (!popup_blocker_helper->GetBlockedPopupsCount()) {
-      content::WindowedNotificationObserver observer(
-          chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
-          content::NotificationService::AllSources());
-      observer.Wait();
-    }
+    ui_test_utils::WaitForViewVisibility(browser, VIEW_ID_CONTENT_SETTING_POPUP,
+                                         true);
     EXPECT_EQ(1u, popup_blocker_helper->GetBlockedPopupsCount());
     std::map<int32_t, GURL> blocked_requests =
         popup_blocker_helper->GetBlockedPopupRequests();
diff --git a/chrome/browser/ui/bookmarks/bookmark_browsertest.cc b/chrome/browser/ui/bookmarks/bookmark_browsertest.cc
index c265dce..bf39292b 100644
--- a/chrome/browser/ui/bookmarks/bookmark_browsertest.cc
+++ b/chrome/browser/ui/bookmarks/bookmark_browsertest.cc
@@ -231,12 +231,13 @@
 
   chrome::DoBookmarkDragCallback cb = base::BindLambdaForTesting(
       [&run_loop, page_title, page_url, expected_point](
-          const ui::OSExchangeData& drag_data, gfx::NativeView native_view,
+          std::unique_ptr<ui::OSExchangeData> drag_data,
+          gfx::NativeView native_view,
           ui::DragDropTypes::DragEventSource source, gfx::Point point,
           int operation) {
         GURL url;
         base::string16 title;
-        EXPECT_TRUE(drag_data.provider().GetURLAndTitle(
+        EXPECT_TRUE(drag_data->provider().GetURLAndTitle(
             ui::OSExchangeData::FilenameToURLPolicy::DO_NOT_CONVERT_FILENAMES,
             &url, &title));
         EXPECT_EQ(page_url, url);
@@ -246,7 +247,7 @@
         // implementation of OSExchangeData just sets the drag image on the OS
         // API.
         // See https://crbug.com/893388.
-        EXPECT_FALSE(drag_data.provider().GetDragImage().isNull());
+        EXPECT_FALSE(drag_data->provider().GetDragImage().isNull());
 #endif
         EXPECT_EQ(expected_point, point);
         run_loop->Quit();
@@ -279,7 +280,7 @@
   auto run_loop = std::make_unique<base::RunLoop>();
 
   chrome::DoBookmarkDragCallback cb = base::BindLambdaForTesting(
-      [&run_loop, expected_point](const ui::OSExchangeData& drag_data,
+      [&run_loop, expected_point](std::unique_ptr<ui::OSExchangeData> drag_data,
                                   gfx::NativeView native_view,
                                   ui::DragDropTypes::DragEventSource source,
                                   gfx::Point point, int operation) {
@@ -288,7 +289,7 @@
         base::string16 title;
         // On Mac 10.11 and 10.12, this returns true, even though we set no url.
         // See https://crbug.com/893432.
-        EXPECT_FALSE(drag_data.provider().GetURLAndTitle(
+        EXPECT_FALSE(drag_data->provider().GetURLAndTitle(
             ui::OSExchangeData::FilenameToURLPolicy::DO_NOT_CONVERT_FILENAMES,
             &url, &title));
 #endif
@@ -297,7 +298,7 @@
         // implementation of OSExchangeData just sets the drag image on the OS
         // API.
         // See https://crbug.com/893388.
-        EXPECT_FALSE(drag_data.provider().GetDragImage().isNull());
+        EXPECT_FALSE(drag_data->provider().GetDragImage().isNull());
 #endif
         EXPECT_EQ(expected_point, point);
         run_loop->Quit();
diff --git a/chrome/browser/ui/bookmarks/bookmark_drag_drop.h b/chrome/browser/ui/bookmarks/bookmark_drag_drop.h
index 71c1f94..fcf9b05 100644
--- a/chrome/browser/ui/bookmarks/bookmark_drag_drop.h
+++ b/chrome/browser/ui/bookmarks/bookmark_drag_drop.h
@@ -28,7 +28,7 @@
 // Callback for implementing a system drag based on gathered bookmark drag data.
 // Used in testing.
 using DoBookmarkDragCallback =
-    base::OnceCallback<void(const ui::OSExchangeData& drag_data,
+    base::OnceCallback<void(std::unique_ptr<ui::OSExchangeData> drag_data,
                             gfx::NativeView native_view,
                             ui::DragDropTypes::DragEventSource source,
                             gfx::Point start_point,
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 95dbd565..b08b03ac 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -448,8 +448,6 @@
   registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
                  content::Source<ThemeService>(
                      ThemeServiceFactory::GetForProfile(profile_)));
-  registrar_.Add(this, chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
-                 content::NotificationService::AllSources());
 
   profile_pref_registrar_.Init(profile_->GetPrefs());
   profile_pref_registrar_.Add(
@@ -2001,24 +1999,8 @@
 void Browser::Observe(int type,
                       const content::NotificationSource& source,
                       const content::NotificationDetails& details) {
-  switch (type) {
-    case chrome::NOTIFICATION_BROWSER_THEME_CHANGED:
-      window()->UserChangedTheme(BrowserThemeChangeType::kBrowserTheme);
-      break;
-
-    case chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED: {
-      WebContents* web_contents = content::Source<WebContents>(source).ptr();
-      if (web_contents == tab_strip_model_->GetActiveWebContents()) {
-        LocationBar* location_bar = window()->GetLocationBar();
-        if (location_bar)
-          location_bar->UpdateContentSettingsIcons();
-      }
-      break;
-    }
-
-    default:
-      NOTREACHED() << "Got a notification we didn't register for.";
-  }
+  DCHECK_EQ(chrome::NOTIFICATION_BROWSER_THEME_CHANGED, type);
+  window()->UserChangedTheme(BrowserThemeChangeType::kBrowserTheme);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc
index eed68f27..dee922d 100644
--- a/chrome/browser/ui/browser_commands.cc
+++ b/chrome/browser/ui/browser_commands.cc
@@ -479,15 +479,14 @@
   }
 }
 
-bool NavigateToIndexWithDisposition(Browser* browser,
+void NavigateToIndexWithDisposition(Browser* browser,
                                     int index,
                                     WindowOpenDisposition disposition) {
   NavigationController* controller =
       &GetTabAndRevertIfNecessary(browser, disposition)->GetController();
-  if (index < 0 || index >= controller->GetEntryCount())
-    return false;
+  DCHECK_GE(index, 0);
+  DCHECK_LT(index, controller->GetEntryCount());
   controller->GoToIndex(index);
-  return true;
 }
 
 void Reload(Browser* browser, WindowOpenDisposition disposition) {
diff --git a/chrome/browser/ui/browser_commands.h b/chrome/browser/ui/browser_commands.h
index cd872bc..1fba14c4 100644
--- a/chrome/browser/ui/browser_commands.h
+++ b/chrome/browser/ui/browser_commands.h
@@ -64,7 +64,7 @@
 void GoBack(Browser* browser, WindowOpenDisposition disposition);
 bool CanGoForward(const Browser* browser);
 void GoForward(Browser* browser, WindowOpenDisposition disposition);
-bool NavigateToIndexWithDisposition(Browser* browser,
+void NavigateToIndexWithDisposition(Browser* browser,
                                     int index,
                                     WindowOpenDisposition disposition);
 void Reload(Browser* browser, WindowOpenDisposition disposition);
diff --git a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
index 75690a38..794d8a9 100644
--- a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
+++ b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
@@ -16,7 +16,6 @@
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/content_settings/chrome_content_settings_utils.h"
 #include "chrome/browser/content_settings/cookie_settings_factory.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
@@ -54,7 +53,6 @@
 #include "components/subresource_filter/core/browser/subresource_filter_constants.h"
 #include "components/subresource_filter/core/browser/subresource_filter_features.h"
 #include "components/url_formatter/elide_url.h"
-#include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
@@ -423,10 +421,7 @@
   // then we remove it.
   auto* settings = TabSpecificContentSettings::FromWebContents(web_contents());
   settings->ClearPendingProtocolHandler();
-  content::NotificationService::current()->Notify(
-      chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
-      content::Source<WebContents>(web_contents()),
-      content::NotificationService::NoDetails());
+  content_settings::UpdateLocationBarUiForWebContents(web_contents());
 }
 
 void ContentSettingRPHBubbleModel::RegisterProtocolHandler() {
diff --git a/chrome/browser/ui/content_settings/content_setting_image_model_unittest.cc b/chrome/browser/ui/content_settings/content_setting_image_model_unittest.cc
index 072b0422..b297539 100644
--- a/chrome/browser/ui/content_settings/content_setting_image_model_unittest.cc
+++ b/chrome/browser/ui/content_settings/content_setting_image_model_unittest.cc
@@ -33,39 +33,7 @@
   return !model.GetIcon(gfx::kPlaceholderColor).IsEmpty();
 }
 
-// Forward all NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED to the specified
-// ContentSettingImageModel.
-class NotificationForwarder : public content::NotificationObserver {
- public:
-  explicit NotificationForwarder(ContentSettingImageModel* model)
-      : model_(model) {
-    registrar_.Add(this,
-                   chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
-                   content::NotificationService::AllSources());
-  }
-  ~NotificationForwarder() override {}
-
-  void clear() {
-    registrar_.RemoveAll();
-  }
-
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override {
-    if (type == chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED) {
-      model_->Update(content::Source<content::WebContents>(source).ptr());
-    }
-  }
-
- private:
-  content::NotificationRegistrar registrar_;
-  ContentSettingImageModel* model_;
-
-  DISALLOW_COPY_AND_ASSIGN(NotificationForwarder);
-};
-
-class ContentSettingImageModelTest : public ChromeRenderViewHostTestHarness {
-};
+using ContentSettingImageModelTest = ChromeRenderViewHostTestHarness;
 
 TEST_F(ContentSettingImageModelTest, Update) {
   TabSpecificContentSettings::CreateForWebContents(web_contents());
@@ -325,13 +293,12 @@
 
 // Regression test for http://crbug.com/161854.
 TEST_F(ContentSettingImageModelTest, NULLTabSpecificContentSettings) {
-  auto content_setting_image_model =
-      ContentSettingImageModel::CreateForContentType(
-          ContentSettingImageModel::ImageType::IMAGES);
-  NotificationForwarder forwarder(content_setting_image_model.get());
+  EXPECT_EQ(nullptr,
+            TabSpecificContentSettings::FromWebContents(web_contents()));
   // Should not crash.
-  TabSpecificContentSettings::CreateForWebContents(web_contents());
-  forwarder.clear();
+  ContentSettingImageModel::CreateForContentType(
+      ContentSettingImageModel::ImageType::IMAGES)
+      ->Update(web_contents());
 }
 
 TEST_F(ContentSettingImageModelTest, SubresourceFilter) {
diff --git a/chrome/browser/ui/passwords/manage_passwords_view_utils.cc b/chrome/browser/ui/passwords/manage_passwords_view_utils.cc
index 2d4d4a7..f0a3c22 100644
--- a/chrome/browser/ui/passwords/manage_passwords_view_utils.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_view_utils.cc
@@ -166,6 +166,13 @@
              : form.username_value;
 }
 
+base::string16 GetDisplayUsername(
+    const password_manager::CredentialPair& credential_pair) {
+  return credential_pair.username.empty()
+             ? l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_EMPTY_LOGIN)
+             : credential_pair.username;
+}
+
 base::string16 GetDisplayFederation(const autofill::PasswordForm& form) {
   return url_formatter::FormatOriginForSecurityDisplay(
       form.federation_origin, url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC);
diff --git a/chrome/browser/ui/passwords/manage_passwords_view_utils.h b/chrome/browser/ui/passwords/manage_passwords_view_utils.h
index 5c5dd2b..14a4e2de 100644
--- a/chrome/browser/ui/passwords/manage_passwords_view_utils.h
+++ b/chrome/browser/ui/passwords/manage_passwords_view_utils.h
@@ -5,8 +5,11 @@
 #ifndef CHROME_BROWSER_UI_PASSWORDS_MANAGE_PASSWORDS_VIEW_UTILS_H_
 #define CHROME_BROWSER_UI_PASSWORDS_MANAGE_PASSWORDS_VIEW_UTILS_H_
 
+#include <utility>
+
 #include "base/strings/string16.h"
 #include "components/password_manager/core/browser/manage_passwords_referrer.h"
+#include "components/password_manager/core/browser/origin_credential_store.h"
 
 namespace autofill {
 struct PasswordForm;
@@ -70,6 +73,11 @@
 // Returns an username in the form that should be shown in the bubble.
 base::string16 GetDisplayUsername(const autofill::PasswordForm& form);
 
+// Returns either the username or the |IDS_PASSWORD_MANAGER_EMPTY_LOGIN| in case
+// it is empty.
+base::string16 GetDisplayUsername(
+    const password_manager::CredentialPair& credential_pair);
+
 // Returns |federation_origin| in a human-readable format.
 base::string16 GetDisplayFederation(const autofill::PasswordForm& form);
 
diff --git a/chrome/browser/ui/search/search_ipc_router.cc b/chrome/browser/ui/search/search_ipc_router.cc
index 98ebd92..ebb13f0 100644
--- a/chrome/browser/ui/search/search_ipc_router.cc
+++ b/chrome/browser/ui/search/search_ipc_router.cc
@@ -139,6 +139,13 @@
   embedded_search_client()->ThemeChanged(theme_info);
 }
 
+void SearchIPCRouter::SendLocalBackgroundSelected() {
+  if (!policy_->ShouldSendLocalBackgroundSelected())
+    return;
+
+  embedded_search_client()->LocalBackgroundSelected();
+}
+
 void SearchIPCRouter::OnTabActivated() {
   is_active_tab_ = true;
 }
diff --git a/chrome/browser/ui/search/search_ipc_router.h b/chrome/browser/ui/search/search_ipc_router.h
index 1b4c0014..d4deaae 100644
--- a/chrome/browser/ui/search/search_ipc_router.h
+++ b/chrome/browser/ui/search/search_ipc_router.h
@@ -183,6 +183,7 @@
     virtual bool ShouldSendOmniboxFocusChanged() = 0;
     virtual bool ShouldSendMostVisitedInfo() = 0;
     virtual bool ShouldSendThemeBackgroundInfo() = 0;
+    virtual bool ShouldSendLocalBackgroundSelected() = 0;
     virtual bool ShouldProcessSetCustomBackgroundURLWithAttributions() = 0;
     virtual bool ShouldProcessSelectLocalBackgroundImage() = 0;
     virtual bool ShouldProcessBlocklistSearchSuggestion() = 0;
@@ -226,6 +227,10 @@
   // Tells the renderer about the current theme background.
   void SendThemeBackgroundInfo(const ThemeBackgroundInfo& theme_info);
 
+  // Tells the renderer that "Done" was clicked on the file selection dialog for
+  // uploading a image to use as the NTP background.
+  void SendLocalBackgroundSelected();
+
   // Called when the tab corresponding to |this| instance is activated.
   void OnTabActivated();
 
diff --git a/chrome/browser/ui/search/search_ipc_router_policy_impl.cc b/chrome/browser/ui/search/search_ipc_router_policy_impl.cc
index 643cfff2..0dcc143 100644
--- a/chrome/browser/ui/search/search_ipc_router_policy_impl.cc
+++ b/chrome/browser/ui/search/search_ipc_router_policy_impl.cc
@@ -99,6 +99,10 @@
   return !is_incognito_ && search::IsInstantNTP(web_contents_);
 }
 
+bool SearchIPCRouterPolicyImpl::ShouldSendLocalBackgroundSelected() {
+  return !is_incognito_ && search::IsInstantNTP(web_contents_);
+}
+
 bool SearchIPCRouterPolicyImpl::ShouldProcessSelectLocalBackgroundImage() {
   return !is_incognito_ && search::IsInstantNTP(web_contents_);
 }
diff --git a/chrome/browser/ui/search/search_ipc_router_policy_impl.h b/chrome/browser/ui/search/search_ipc_router_policy_impl.h
index d99f7a4..e01fe99 100644
--- a/chrome/browser/ui/search/search_ipc_router_policy_impl.h
+++ b/chrome/browser/ui/search/search_ipc_router_policy_impl.h
@@ -46,6 +46,7 @@
   bool ShouldSendOmniboxFocusChanged() override;
   bool ShouldSendMostVisitedInfo() override;
   bool ShouldSendThemeBackgroundInfo() override;
+  bool ShouldSendLocalBackgroundSelected() override;
   bool ShouldProcessSetCustomBackgroundURLWithAttributions() override;
   bool ShouldProcessSelectLocalBackgroundImage() override;
   bool ShouldProcessBlocklistSearchSuggestion() override;
diff --git a/chrome/browser/ui/search/search_ipc_router_unittest.cc b/chrome/browser/ui/search/search_ipc_router_unittest.cc
index 674b12a..1e32dbf 100644
--- a/chrome/browser/ui/search/search_ipc_router_unittest.cc
+++ b/chrome/browser/ui/search/search_ipc_router_unittest.cc
@@ -134,6 +134,7 @@
   MOCK_METHOD0(ShouldSendOmniboxFocusChanged, bool());
   MOCK_METHOD0(ShouldSendMostVisitedInfo, bool());
   MOCK_METHOD0(ShouldSendThemeBackgroundInfo, bool());
+  MOCK_METHOD0(ShouldSendLocalBackgroundSelected, bool());
   MOCK_METHOD0(ShouldProcessThemeChangeMessages, bool());
 };
 
@@ -843,6 +844,31 @@
   GetSearchIPCRouter().SendThemeBackgroundInfo(ThemeBackgroundInfo());
 }
 
+TEST_F(SearchIPCRouterTest, SendLocalBackgroundSelectedMsg) {
+  NavigateAndCommitActiveTab(GURL(chrome::kChromeSearchLocalNtpUrl));
+  SetupMockDelegateAndPolicy();
+  MockSearchIPCRouterPolicy* policy = GetSearchIPCRouterPolicy();
+  EXPECT_CALL(*policy, ShouldSendLocalBackgroundSelected())
+      .Times(1)
+      .WillOnce(Return(true));
+
+  EXPECT_CALL(*mock_embedded_search_client(), LocalBackgroundSelected());
+  GetSearchIPCRouter().SendLocalBackgroundSelected();
+}
+
+TEST_F(SearchIPCRouterTest, DoNotSendLocalBackgroundSelectedMsg) {
+  NavigateAndCommitActiveTab(GURL(chrome::kChromeSearchLocalNtpUrl));
+  SetupMockDelegateAndPolicy();
+  MockSearchIPCRouterPolicy* policy = GetSearchIPCRouterPolicy();
+  EXPECT_CALL(*policy, ShouldSendLocalBackgroundSelected())
+      .Times(1)
+      .WillOnce(Return(false));
+
+  EXPECT_CALL(*mock_embedded_search_client(), LocalBackgroundSelected())
+      .Times(0);
+  GetSearchIPCRouter().SendLocalBackgroundSelected();
+}
+
 TEST_F(SearchIPCRouterTest, ProcessSetCustomBackgroundURLWithAttributionsMsg) {
   NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
   SetupMockDelegateAndPolicy();
diff --git a/chrome/browser/ui/search/search_tab_helper.cc b/chrome/browser/ui/search/search_tab_helper.cc
index 70317af6..c60eda49 100644
--- a/chrome/browser/ui/search/search_tab_helper.cc
+++ b/chrome/browser/ui/search/search_tab_helper.cc
@@ -403,6 +403,8 @@
   NTPUserDataLogger::GetOrCreateFromWebContents(web_contents())
       ->LogEvent(NTP_CUSTOMIZE_LOCAL_IMAGE_DONE,
                  base::TimeDelta::FromSeconds(0));
+
+  ipc_router_.SendLocalBackgroundSelected();
 }
 
 void SearchTabHelper::FileSelectionCanceled(void* params) {
diff --git a/chrome/browser/ui/tab_sharing/tab_sharing_infobar_delegate.cc b/chrome/browser/ui/tab_sharing/tab_sharing_infobar_delegate.cc
index 1457ec3..da6be7a 100644
--- a/chrome/browser/ui/tab_sharing/tab_sharing_infobar_delegate.cc
+++ b/chrome/browser/ui/tab_sharing/tab_sharing_infobar_delegate.cc
@@ -21,11 +21,9 @@
     bool is_sharing_allowed,
     TabSharingUI* ui) {
   DCHECK(infobar_service);
-  return infobar_service->AddInfoBar(
-      infobar_service->CreateConfirmInfoBar(
-          base::WrapUnique(new TabSharingInfoBarDelegate(
-              shared_tab_name, app_name, is_sharing_allowed, ui))),
-      true /*replace_existing*/);
+  return infobar_service->AddInfoBar(infobar_service->CreateConfirmInfoBar(
+      base::WrapUnique(new TabSharingInfoBarDelegate(shared_tab_name, app_name,
+                                                     is_sharing_allowed, ui))));
 }
 
 TabSharingInfoBarDelegate::TabSharingInfoBarDelegate(
@@ -40,7 +38,7 @@
 
 bool TabSharingInfoBarDelegate::EqualsDelegate(
     InfoBarDelegate* delegate) const {
-  return delegate && delegate->GetIdentifier() == GetIdentifier();
+  return false;
 }
 
 bool TabSharingInfoBarDelegate::ShouldExpire(
diff --git a/chrome/browser/ui/tab_sharing/tab_sharing_ui.cc b/chrome/browser/ui/tab_sharing/tab_sharing_ui.cc
index f146fe7..435f09a 100644
--- a/chrome/browser/ui/tab_sharing/tab_sharing_ui.cc
+++ b/chrome/browser/ui/tab_sharing/tab_sharing_ui.cc
@@ -77,13 +77,13 @@
     const TabStripSelectionChange& selection) {
   if (change.type() == TabStripModelChange::kInserted) {
     for (const auto& contents : change.GetInsert()->contents) {
-      auto* info_bar = TabSharingInfoBarDelegate::Create(
+      if (infobars_.find(contents.contents) != infobars_.end())
+        continue;
+      infobars_[contents.contents] = TabSharingInfoBarDelegate::Create(
           InfoBarService::FromWebContents(contents.contents),
           shared_tab_ == contents.contents ? base::string16()
                                            : shared_tab_name_,
           app_name_, !source_callback_.is_null() /*is_sharing_allowed*/, this);
-      info_bar->owner()->AddObserver(this);
-      infobars_[contents.contents] = info_bar;
     }
   } else if (change.type() == TabStripModelChange::kRemoved &&
              change.GetRemove()->will_be_deleted) {
@@ -99,21 +99,6 @@
   }
 }
 
-void TabSharingUI::OnInfoBarRemoved(infobars::InfoBar* info_bar, bool animate) {
-  base::EraseIf(infobars_, [info_bar, this](const auto& infobars_entry) {
-    if (infobars_entry.second == info_bar) {
-      info_bar->owner()->RemoveObserver(this);
-      return true;
-    }
-    return false;
-  });
-}
-
-void TabSharingUI::OnInfoBarReplaced(infobars::InfoBar* old_infobar,
-                                     infobars::InfoBar* new_infobar) {
-  OnInfoBarRemoved(old_infobar, false);
-}
-
 void TabSharingUI::StartSharing(infobars::InfoBar* infobar) {
   if (source_callback_.is_null())
     return;
@@ -150,12 +135,10 @@
     TabStripModel* tab_strip_model = browser->tab_strip_model();
     for (int i = 0; i < tab_strip_model->count(); i++) {
       content::WebContents* contents = tab_strip_model->GetWebContentsAt(i);
-      auto* info_bar = TabSharingInfoBarDelegate::Create(
+      infobars_[contents] = TabSharingInfoBarDelegate::Create(
           InfoBarService::FromWebContents(contents),
           shared_tab_ == contents ? base::string16() : shared_tab_name_,
           app_name_, !source_callback_.is_null() /*is_sharing_allowed*/, this);
-      info_bar->owner()->AddObserver(this);
-      infobars_[contents] = info_bar;
     }
   }
   browser_list->AddObserver(this);
@@ -165,9 +148,8 @@
   BrowserList::GetInstance()->RemoveObserver(this);
   tab_strip_models_observer_.RemoveAll();
 
-  for (const auto& infobars_entry : infobars_) {
-    infobars_entry.second->owner()->RemoveObserver(this);
+  for (const auto& infobars_entry : infobars_)
     infobars_entry.second->RemoveSelf();
-  }
+
   infobars_.clear();
 }
diff --git a/chrome/browser/ui/tab_sharing/tab_sharing_ui.h b/chrome/browser/ui/tab_sharing/tab_sharing_ui.h
index 65d0f8b..6d931129 100644
--- a/chrome/browser/ui/tab_sharing/tab_sharing_ui.h
+++ b/chrome/browser/ui/tab_sharing/tab_sharing_ui.h
@@ -29,8 +29,7 @@
 
 class TabSharingUI : public MediaStreamUI,
                      public TabStripModelObserver,
-                     public BrowserListObserver,
-                     public infobars::InfoBarManager::Observer {
+                     public BrowserListObserver {
  public:
   TabSharingUI(const content::DesktopMediaID& media_id,
                base::string16 app_name);
@@ -52,11 +51,6 @@
   void OnBrowserAdded(Browser* browser) override;
   void OnBrowserRemoved(Browser* browser) override;
 
-  // infobars::InfoBarManager::Observer:
-  void OnInfoBarRemoved(infobars::InfoBar* info_bar, bool animate) override;
-  void OnInfoBarReplaced(infobars::InfoBar* old_infobar,
-                         infobars::InfoBar* new_infobar) override;
-
   // Runs |source_callback_| to start sharing the tab containing |infobar|.
   // Removes infobars on all tabs; OnStarted() will recreate the infobars with
   // updated title and buttons.
diff --git a/chrome/browser/ui/toolbar/back_forward_menu_model.cc b/chrome/browser/ui/toolbar/back_forward_menu_model.cc
index 6b645b61..e52e2e7 100644
--- a/chrome/browser/ui/toolbar/back_forward_menu_model.cc
+++ b/chrome/browser/ui/toolbar/back_forward_menu_model.cc
@@ -192,11 +192,8 @@
 
   WindowOpenDisposition disposition =
       ui::DispositionFromEventFlags(event_flags);
-  if (!chrome::NavigateToIndexWithDisposition(browser_,
-                                              controller_index,
-                                              disposition)) {
-    NOTREACHED();
-  }
+  chrome::NavigateToIndexWithDisposition(browser_, controller_index,
+                                         disposition);
 }
 
 void BackForwardMenuModel::MenuWillShow() {
diff --git a/chrome/browser/ui/view_ids.h b/chrome/browser/ui/view_ids.h
index 234cb55..8af18a9f 100644
--- a/chrome/browser/ui/view_ids.h
+++ b/chrome/browser/ui/view_ids.h
@@ -62,6 +62,10 @@
   VIEW_ID_MIGRATE_LOCAL_CREDIT_CARD_BUTTON,
   VIEW_ID_TRANSLATE_BUTTON,
 
+  // Location bar content settings icons.
+  VIEW_ID_CONTENT_SETTING_JAVASCRIPT,
+  VIEW_ID_CONTENT_SETTING_POPUP,
+
   // The Bookmark Bar.
   VIEW_ID_BOOKMARK_BAR,
   VIEW_ID_OTHER_BOOKMARKS,
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_drag_drop_views.cc b/chrome/browser/ui/views/bookmarks/bookmark_drag_drop_views.cc
index 912bb51..d1027b5 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_drag_drop_views.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_drag_drop_views.cc
@@ -176,13 +176,14 @@
         source_(params.source),
         start_point_(params.start_point),
         do_drag_callback_(std::move(do_drag_callback)),
+        drag_data_(std::make_unique<ui::OSExchangeData>()),
         observer_(this),
         weak_factory_(this) {
     observer_.Add(model_);
 
     // Set up our OLE machinery.
     bookmarks::BookmarkNodeData bookmark_drag_data(params.nodes);
-    bookmark_drag_data.Write(profile->GetPath(), &drag_data_);
+    bookmark_drag_data.Write(profile->GetPath(), drag_data_.get());
 
     operation_ = ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_LINK;
     if (bookmarks::CanAllBeEditedByUser(model_->client(), params.nodes))
@@ -225,12 +226,13 @@
             count_),
         BookmarkDragImageSource::kBookmarkDragImageSize);
 
-    drag_data_.provider().SetDragImage(
+    drag_data_->provider().SetDragImage(
         drag_image, gfx::Vector2d(BookmarkDragImageSource::kDragImageOffsetX,
                                   BookmarkDragImageSource::kDragImageOffsetY));
 
     std::move(do_drag_callback_)
-        .Run(drag_data_, native_view_, source_, start_point_, operation_);
+        .Run(std::move(drag_data_), native_view_, source_, start_point_,
+             operation_);
 
     delete this;
   }
@@ -266,7 +268,7 @@
 
   DoBookmarkDragCallback do_drag_callback_;
 
-  ui::OSExchangeData drag_data_;
+  std::unique_ptr<ui::OSExchangeData> drag_data_;
 
   ScopedObserver<bookmarks::BookmarkModel, bookmarks::BookmarkModelObserver>
       observer_;
@@ -276,7 +278,7 @@
   DISALLOW_COPY_AND_ASSIGN(BookmarkDragHelper);
 };
 
-void DoDragImpl(const ui::OSExchangeData& drag_data,
+void DoDragImpl(std::unique_ptr<ui::OSExchangeData> drag_data,
                 gfx::NativeView native_view,
                 ui::DragDropTypes::DragEventSource source,
                 gfx::Point point,
@@ -286,9 +288,11 @@
 
   views::Widget* widget = views::Widget::GetWidgetForNativeView(native_view);
   if (widget) {
-    widget->RunShellDrag(nullptr, drag_data, gfx::Point(), operation, source);
+    widget->RunShellDrag(nullptr, std::move(drag_data), gfx::Point(), operation,
+                         source);
   } else {
-    views::RunShellDrag(native_view, drag_data, point, operation, source);
+    views::RunShellDrag(native_view, std::move(drag_data), point, operation,
+                        source);
   }
 }
 
diff --git a/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc b/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc
index 5d56b24..0017280 100644
--- a/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc
+++ b/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc
@@ -114,7 +114,7 @@
     active_drag_event_->set_root_location_f(event_root_location);
 
     delegate->OnDragUpdated(*active_drag_event_);
-    delegate->OnPerformDrop(*active_drag_event_);
+    delegate->OnPerformDrop(*active_drag_event_, std::move(os_exchange_data_));
     return true;
   }
 
@@ -242,7 +242,7 @@
   }
 
   // aura::client::DragDropClient overrides:
-  int StartDragAndDrop(const ui::OSExchangeData& data,
+  int StartDragAndDrop(std::unique_ptr<ui::OSExchangeData> data,
                        aura::Window* root_window,
                        aura::Window* source_window,
                        const gfx::Point& screen_location,
@@ -254,14 +254,14 @@
       message_loop_runner_->Quit();
 
       base::string16 text;
-      if (data.GetString(&text))
+      if (data->GetString(&text))
         text_ = base::UTF16ToUTF8(text);
       else
         text_ = "<no text>";
 
       GURL base_url;
       base::string16 html;
-      if (data.GetHtml(&html, &base_url))
+      if (data->GetHtml(&html, &base_url))
         html_ = base::UTF16ToUTF8(html);
       else
         html_ = "<no html>";
@@ -285,8 +285,9 @@
       return 0;
 
     // Start a nested drag-and-drop loop (might not return for a long time).
-    return old_client_->StartDragAndDrop(data, root_window, source_window,
-                                         screen_location, operation, source);
+    return old_client_->StartDragAndDrop(std::move(data), root_window,
+                                         source_window, screen_location,
+                                         operation, source);
   }
 
   void DragCancel() override {
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc b/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc
index ca5b4343..04cca2a 100644
--- a/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc
+++ b/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc
@@ -33,6 +33,9 @@
 
 void ExtensionsToolbarContainer::UpdateAllIcons() {
   extensions_button_->UpdateIcon();
+
+  for (const auto& action : actions_)
+    action->UpdateState();
 }
 
 ToolbarActionViewController* ExtensionsToolbarContainer::GetActionForId(
diff --git a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.cc b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.cc
index e9b60dbc..a927228 100644
--- a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.cc
+++ b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.cc
@@ -199,6 +199,11 @@
 }
 
 void BrowserDesktopWindowTreeHostWin::HandleDestroying() {
+  // TODO(crbug/976176): Move all access to |virtual_desktop_manager_| off of
+  // the ui thread to prevent reentrancy bugs due to COM objects pumping
+  // messages. For now, Reset() so COM object destructor is called before
+  // |this| is in the process of being deleted.
+  virtual_desktop_manager_.Reset();
   browser_window_property_manager_.reset();
   DesktopWindowTreeHostWin::HandleDestroying();
 }
diff --git a/chrome/browser/ui/views/location_bar/content_setting_image_view.cc b/chrome/browser/ui/views/location_bar/content_setting_image_view.cc
index cfcbea2..91c90fd 100644
--- a/chrome/browser/ui/views/location_bar/content_setting_image_view.cc
+++ b/chrome/browser/ui/views/location_bar/content_setting_image_view.cc
@@ -6,10 +6,12 @@
 
 #include <utility>
 
+#include "base/optional.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/ui/content_settings/content_setting_bubble_model.h"
 #include "chrome/browser/ui/content_settings/content_setting_image_model.h"
+#include "chrome/browser/ui/view_ids.h"
 #include "chrome/browser/ui/views/content_setting_bubble_contents.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/theme_provider.h"
@@ -22,6 +24,44 @@
 #include "ui/views/controls/label.h"
 #include "ui/views/widget/widget.h"
 
+namespace {
+
+base::Optional<ViewID> GetViewID(
+    ContentSettingImageModel::ImageType image_type) {
+  using ImageType = ContentSettingImageModel::ImageType;
+  switch (image_type) {
+    case ImageType::JAVASCRIPT:
+      return ViewID::VIEW_ID_CONTENT_SETTING_JAVASCRIPT;
+
+    case ImageType::POPUPS:
+      return ViewID::VIEW_ID_CONTENT_SETTING_POPUP;
+
+    case ImageType::COOKIES:
+    case ImageType::IMAGES:
+    case ImageType::PPAPI_BROKER:
+    case ImageType::PLUGINS:
+    case ImageType::GEOLOCATION:
+    case ImageType::MIXEDSCRIPT:
+    case ImageType::PROTOCOL_HANDLERS:
+    case ImageType::MEDIASTREAM:
+    case ImageType::ADS:
+    case ImageType::AUTOMATIC_DOWNLOADS:
+    case ImageType::MIDI_SYSEX:
+    case ImageType::SOUND:
+    case ImageType::FRAMEBUST:
+    case ImageType::CLIPBOARD_READ:
+    case ImageType::SENSORS:
+      return base::nullopt;
+
+    case ImageType::NUM_IMAGE_TYPES:
+      break;
+  }
+  NOTREACHED();
+  return base::nullopt;
+}
+
+}  // namespace
+
 ContentSettingImageView::ContentSettingImageView(
     std::unique_ptr<ContentSettingImageModel> image_model,
     Delegate* delegate,
@@ -33,6 +73,11 @@
   DCHECK(delegate_);
   SetUpForInOutAnimation();
   image()->EnableCanvasFlippingForRTLUI(true);
+
+  base::Optional<ViewID> view_id =
+      GetViewID(content_setting_image_model_->image_type());
+  if (view_id)
+    SetID(*view_id);
 }
 
 ContentSettingImageView::~ContentSettingImageView() {
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.cc b/chrome/browser/ui/views/overlay/overlay_window_views.cc
index cf4e45a2..f5bae7b 100644
--- a/chrome/browser/ui/views/overlay/overlay_window_views.cc
+++ b/chrome/browser/ui/views/overlay/overlay_window_views.cc
@@ -264,16 +264,9 @@
 OverlayWindowViews::~OverlayWindowViews() = default;
 
 gfx::Rect OverlayWindowViews::CalculateAndUpdateWindowBounds() {
-  gfx::Rect work_area =
-      display::Screen::GetScreen()
-          ->GetDisplayNearestWindow(IsVisible()
-                                        ? GetNativeWindow()
-                                        : controller_->GetInitiatorWebContents()
-                                              ->GetTopLevelNativeWindow())
-          .work_area();
+  gfx::Rect work_area = GetWorkAreaForWindow();
 
-  // Upper bound size of the window is 50% of the display width and height.
-  max_size_ = gfx::Size(work_area.width() / 2, work_area.height() / 2);
+  UpdateMaxSize(work_area, window_bounds_.size());
 
   // Lower bound size of the window is a fixed value to allow for minimal sizes
   // on UI affordances, such as buttons.
@@ -840,6 +833,10 @@
   // shown.
   window_bounds_ = GetBounds();
 
+  // Update the maximum size of the widget in case we have moved to another
+  // window.
+  UpdateMaxSize(GetWorkAreaForWindow(), window_bounds_.size());
+
 #if defined(OS_CHROMEOS)
   // Update the positioning of some icons when the window is moved.
   WindowQuadrant quadrant = GetCurrentWindowQuadrant(GetBounds(), controller_);
@@ -1088,6 +1085,31 @@
   return resize_handle_view_->layer();
 }
 
+gfx::Rect OverlayWindowViews::GetWorkAreaForWindow() const {
+  return display::Screen::GetScreen()
+      ->GetDisplayNearestWindow(IsVisible()
+                                    ? GetNativeWindow()
+                                    : controller_->GetInitiatorWebContents()
+                                          ->GetTopLevelNativeWindow())
+      .work_area();
+}
+
+gfx::Size OverlayWindowViews::UpdateMaxSize(const gfx::Rect& work_area,
+                                            const gfx::Size& window_size) {
+  max_size_ = gfx::Size(work_area.width() / 2, work_area.height() / 2);
+
+  if (!IsVisible())
+    return window_size;
+
+  if (window_size.width() <= max_size_.width() &&
+      window_size.height() <= max_size_.height()) {
+    return window_size;
+  }
+
+  SetSize(max_size_);
+  return gfx::Size(max_size_);
+}
+
 void OverlayWindowViews::TogglePlayPause() {
   // Retrieve expected active state based on what command was sent in
   // TogglePlayPause() since the IPC message may not have been propagated
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.h b/chrome/browser/ui/views/overlay/overlay_window_views.h
index 7d7ccdf..51c3ecd 100644
--- a/chrome/browser/ui/views/overlay/overlay_window_views.h
+++ b/chrome/browser/ui/views/overlay/overlay_window_views.h
@@ -103,7 +103,16 @@
   ui::Layer* video_layer_for_testing() const;
   cc::Layer* GetLayerForTesting() override;
 
+  // Update the max size of the widget based on |work_area| and |window_size|.
+  // The return value is the new size of the window if it was resized and is
+  // only used for testing.
+  gfx::Size UpdateMaxSize(const gfx::Rect& work_area,
+                          const gfx::Size& window_size);
+
  private:
+  // Return the work area for the nearest display the widget is on.
+  gfx::Rect GetWorkAreaForWindow() const;
+
   // Determine the intended bounds of |this|. This should be called when there
   // is reason for the bounds to change, such as switching primary displays or
   // playing a new video (i.e. different aspect ratio). This also updates
diff --git a/chrome/browser/ui/views/ssl_client_certificate_selector_browsertest.cc b/chrome/browser/ui/views/ssl_client_certificate_selector_browsertest.cc
index bc64443..d57a0a3 100644
--- a/chrome/browser/ui/views/ssl_client_certificate_selector_browsertest.cc
+++ b/chrome/browser/ui/views/ssl_client_certificate_selector_browsertest.cc
@@ -60,7 +60,7 @@
         certs_dir, "client_2.pem", "client_2.pk8");
     ASSERT_TRUE(cert_identity_2_);
 
-    cert_request_info_ = new net::SSLCertRequestInfo;
+    cert_request_info_ = base::MakeRefCounted<net::SSLCertRequestInfo>();
     cert_request_info_->host_and_port = net::HostPortPair("foo", 123);
   }
 
@@ -130,10 +130,10 @@
   void SetUpInProcessBrowserTestFixture() override {
     SSLClientCertificateSelectorTest::SetUpInProcessBrowserTestFixture();
 
-    cert_request_info_1_ = new net::SSLCertRequestInfo;
+    cert_request_info_1_ = base::MakeRefCounted<net::SSLCertRequestInfo>();
     cert_request_info_1_->host_and_port = net::HostPortPair("bar", 123);
 
-    cert_request_info_2_ = new net::SSLCertRequestInfo;
+    cert_request_info_2_ = base::MakeRefCounted<net::SSLCertRequestInfo>();
     cert_request_info_2_->host_and_port = net::HostPortPair("bar", 123);
   }
 
@@ -215,7 +215,7 @@
   void SetUpInProcessBrowserTestFixture() override {
     SSLClientCertificateSelectorTest::SetUpInProcessBrowserTestFixture();
 
-    cert_request_info_1_ = new net::SSLCertRequestInfo;
+    cert_request_info_1_ = base::MakeRefCounted<net::SSLCertRequestInfo>();
     cert_request_info_1_->host_and_port = net::HostPortPair("foo", 123);
   }
 
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index d59b4b5..a36900a 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -130,13 +130,13 @@
 
  private:
   void OnViewFocused(views::View* observed_view) override {
-    controller_->UpdateHoverCard(tab_, /* should_show */ true);
+    controller_->UpdateHoverCard(tab_);
   }
 
   void OnViewBlurred(views::View* observed_view) override {
     // Only hide hover card if not keyboard navigating.
     if (!controller_->IsFocusInTabs())
-      controller_->UpdateHoverCard(nullptr, /* should_show */ false);
+      controller_->UpdateHoverCard(nullptr);
   }
 
   ScopedObserver<views::View, views::ViewObserver> tab_close_button_observer_{
@@ -209,7 +209,7 @@
 Tab::~Tab() {
   // Observer must be unregistered before child views are destroyed.
   tab_close_button_observer_.reset();
-  controller_->UpdateHoverCard(this, /* should_show */ false);
+  controller_->UpdateHoverCard(nullptr);
 }
 
 void Tab::AnimationEnded(const gfx::Animation* animation) {
@@ -436,7 +436,7 @@
 }  // namespace
 
 bool Tab::OnMousePressed(const ui::MouseEvent& event) {
-  controller_->UpdateHoverCard(this, /* should_show */ false);
+  controller_->UpdateHoverCard(nullptr);
   controller_->OnMouseEventInTab(this, event);
 
   // Allow a right click from touch to drag, which corresponds to a long click.
@@ -548,7 +548,7 @@
   tab_style_->ShowHover(TabStyle::ShowHoverStyle::kSubtle);
   UpdateForegroundColors();
   Layout();
-  controller_->UpdateHoverCard(this, /* should_show */ true);
+  controller_->UpdateHoverCard(this);
 }
 
 void Tab::OnMouseExited(const ui::MouseEvent& event) {
@@ -559,7 +559,7 @@
 }
 
 void Tab::OnGestureEvent(ui::GestureEvent* event) {
-  controller_->UpdateHoverCard(this, /* should_show */ false);
+  controller_->UpdateHoverCard(nullptr);
   switch (event->type()) {
     case ui::ET_GESTURE_TAP_DOWN: {
       // TAP_DOWN is only dispatched for the first touch point.
@@ -655,12 +655,12 @@
 
 void Tab::OnFocus() {
   View::OnFocus();
-  controller_->UpdateHoverCard(this, /* should_show */ true);
+  controller_->UpdateHoverCard(this);
 }
 
 void Tab::OnBlur() {
   View::OnBlur();
-  controller_->UpdateHoverCard(nullptr, /* should_show */ false);
+  controller_->UpdateHoverCard(nullptr);
 }
 
 void Tab::OnThemeChanged() {
diff --git a/chrome/browser/ui/views/tabs/tab_controller.h b/chrome/browser/ui/views/tabs/tab_controller.h
index 900ecfa0..dac07175 100644
--- a/chrome/browser/ui/views/tabs/tab_controller.h
+++ b/chrome/browser/ui/views/tabs/tab_controller.h
@@ -105,8 +105,9 @@
                                  const ui::MouseEvent& event) = 0;
 
   // Updates hover-card content, anchoring and visibility based on what tab is
-  // hovered and whether the card should be shown.
-  virtual void UpdateHoverCard(Tab* tab, bool should_show) = 0;
+  // hovered and whether the card should be shown. Providing a nullptr for |tab|
+  // will cause the tab hover card to be hidden.
+  virtual void UpdateHoverCard(Tab* tab) = 0;
 
   // Returns whether |tab| needs to be painted. When this returns true, |clip|
   // is set to the path which should be clipped out of the current tab's region
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index 3277ca9..b9566df 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -149,7 +149,7 @@
   // ui::EventTarget:
   void OnKeyEvent(ui::KeyEvent* event) override {
     if (!tab_strip_->IsFocusInTabs())
-      tab_strip_->UpdateHoverCard(nullptr, false);
+      tab_strip_->UpdateHoverCard(nullptr);
   }
 
   void OnMouseEvent(ui::MouseEvent* event) override {
@@ -1181,7 +1181,7 @@
 
   UpdateAccessibleTabIndices();
 
-  UpdateHoverCard(nullptr, /* should_show */ false);
+  UpdateHoverCard(nullptr);
 
   for (TabStripObserver& observer : observers_)
     observer.OnTabRemoved(model_index);
@@ -1206,7 +1206,7 @@
   tab->SetData(std::move(data));
 
   if (HoverCardIsShowingForTab(tab))
-    UpdateHoverCard(tab, /* should_show */ true);
+    UpdateHoverCard(tab);
 
   if (pinned_state_changed) {
     if (touch_layout_) {
@@ -1365,7 +1365,7 @@
       ->NotifyAccessibilityEvent(ax::mojom::Event::kSelection, true);
   selected_tabs_ = new_selection;
 
-  UpdateHoverCard(nullptr, /* should_show */ false);
+  UpdateHoverCard(nullptr);
   // The hover cards seen count is reset when the active tab is changed by any
   // event. Note TabStrip::SelectTab does not capture tab changes triggered by
   // the keyboard.
@@ -1512,7 +1512,7 @@
       AddMessageLoopObserver();
   }
 
-  UpdateHoverCard(nullptr, /* should_show */ false);
+  UpdateHoverCard(nullptr);
   controller_->CloseTab(model_index, source);
 }
 
@@ -1612,18 +1612,18 @@
   UpdateStackedLayoutFromMouseEvent(source, event);
 }
 
-void TabStrip::UpdateHoverCard(Tab* tab, bool should_show) {
+void TabStrip::UpdateHoverCard(Tab* tab) {
   if (!base::FeatureList::IsEnabled(features::kTabHoverCards))
     return;
   // We don't want to show a hover card for a tab while it is animating.
-  if (bounds_animator_.IsAnimating(tab) && should_show) {
+  if (tab && bounds_animator_.IsAnimating(tab)) {
     return;
   }
 
   if (!hover_card_) {
     // There is nothing to be done if the hover card doesn't exist and we are
     // not trying to show it.
-    if (!should_show)
+    if (!tab)
       return;
     hover_card_ = new TabHoverCardBubbleView(tab);
     hover_card_->views::View::AddObserver(this);
@@ -1632,7 +1632,7 @@
           std::make_unique<TabHoverCardEventSniffer>(hover_card_, this);
     }
   }
-  if (should_show)
+  if (tab)
     hover_card_->UpdateAndShow(tab);
   else
     hover_card_->FadeOutToHide();
@@ -2186,7 +2186,7 @@
 }
 
 void TabStrip::AnimateToIdealBounds() {
-  UpdateHoverCard(nullptr, /* should_show */ false);
+  UpdateHoverCard(nullptr);
   // bounds_animator_ and TabStripLayoutHelper::animator_ should not run
   // concurrently. bounds_animator_ takes precedence, and can finish what the
   // other started.
@@ -2350,7 +2350,7 @@
   Tab* closing_tab = tab_at(index);
   bool closing_tab_was_active = closing_tab->IsActive();
 
-  UpdateHoverCard(closing_tab, /* should_show */ false);
+  UpdateHoverCard(nullptr);
 
   // We still need to paint the tab until we actually remove it. Put it
   // in tabs_closing_map_ so we can find it.
@@ -2999,7 +2999,7 @@
 void TabStrip::OnMouseExited(const ui::MouseEvent& event) {
   if (base::FeatureList::IsEnabled(features::kTabHoverCards) && hover_card_)
     hover_card_->set_last_mouse_exit_timestamp(base::TimeTicks::Now());
-  UpdateHoverCard(nullptr, /* should_show */ false);
+  UpdateHoverCard(nullptr);
 }
 
 void TabStrip::AddedToWidget() {
@@ -3105,7 +3105,7 @@
 
 void TabStrip::OnViewFocused(views::View* observed_view) {
   if (observed_view == new_tab_button_)
-    UpdateHoverCard(nullptr, false);
+    UpdateHoverCard(nullptr);
 }
 
 void TabStrip::OnTouchUiChanged() {
diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h
index bc8a80d..20ea2fc 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.h
+++ b/chrome/browser/ui/views/tabs/tab_strip.h
@@ -251,7 +251,7 @@
   const Tab* GetAdjacentTab(const Tab* tab, int offset) override;
   void OnMouseEventInTab(views::View* source,
                          const ui::MouseEvent& event) override;
-  void UpdateHoverCard(Tab* tab, bool should_show) override;
+  void UpdateHoverCard(Tab* tab) override;
   bool ShouldPaintTab(const Tab* tab, float scale, SkPath* clip) override;
   int GetStrokeThickness() const override;
   bool CanPaintThrobberToLayer() const override;
diff --git a/chrome/browser/ui/views/tabs/tab_unittest.cc b/chrome/browser/ui/views/tabs/tab_unittest.cc
index 7897fed..ed448526 100644
--- a/chrome/browser/ui/views/tabs/tab_unittest.cc
+++ b/chrome/browser/ui/views/tabs/tab_unittest.cc
@@ -78,7 +78,7 @@
   }
   void OnMouseEventInTab(views::View* source,
                          const ui::MouseEvent& event) override {}
-  void UpdateHoverCard(Tab* tab, bool hovered) override {}
+  void UpdateHoverCard(Tab* tab) override {}
   bool ShouldPaintTab(const Tab* tab, float scale, SkPath* clip) override {
     return true;
   }
diff --git a/chrome/browser/ui/webui/policy_ui.cc b/chrome/browser/ui/webui/policy_ui.cc
index ced53b8..81efd814 100644
--- a/chrome/browser/ui/webui/policy_ui.cc
+++ b/chrome/browser/ui/webui/policy_ui.cc
@@ -47,12 +47,15 @@
        IDS_POLICY_LABEL_MACHINE_ENROLLMENT_TOKEN},
       {"labelMachineEntrollmentDeviceId",
        IDS_POLICY_LABEL_MACHINE_ENROLLMENT_DEVICE_ID},
+      {"labelIsOffHoursActive", IDS_POLICY_LABEL_IS_OFFHOURS_ACTIVE},
       {"labelPoliciesPush", IDS_POLICY_LABEL_PUSH_POLICIES},
       {"labelRefreshInterval", IDS_POLICY_LABEL_REFRESH_INTERVAL},
       {"labelStatus", IDS_POLICY_LABEL_STATUS},
       {"labelTimeSinceLastRefresh", IDS_POLICY_LABEL_TIME_SINCE_LAST_REFRESH},
       {"labelUsername", IDS_POLICY_LABEL_USERNAME},
       {"noPoliciesSet", IDS_POLICY_NO_POLICIES_SET},
+      {"offHoursActive", IDS_POLICY_OFFHOURS_ACTIVE},
+      {"offHoursNotActive", IDS_POLICY_OFFHOURS_NOT_ACTIVE},
       {"policiesPushOff", IDS_POLICY_PUSH_POLICIES_OFF},
       {"policiesPushOn", IDS_POLICY_PUSH_POLICIES_ON},
       {"policyLearnMore", IDS_POLICY_LEARN_MORE},
diff --git a/chrome/browser/ui/webui/policy_ui_handler.cc b/chrome/browser/ui/webui/policy_ui_handler.cc
index 84e05a7..afe6d33 100644
--- a/chrome/browser/ui/webui/policy_ui_handler.cc
+++ b/chrome/browser/ui/webui/policy_ui_handler.cc
@@ -76,6 +76,7 @@
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h"
 #include "chrome/browser/chromeos/policy/device_local_account_policy_service.h"
+#include "chrome/browser/chromeos/policy/off_hours/device_off_hours_controller.h"
 #include "chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chromeos/dbus/util/version_loader.h"
@@ -205,6 +206,13 @@
     return;
   dict->SetBoolean("isAffiliated", user->IsAffiliated());
 }
+
+void GetOffHoursStatus(base::DictionaryValue* dict) {
+  policy::off_hours::DeviceOffHoursController* off_hours_controller =
+      chromeos::DeviceSettingsService::Get()->device_off_hours_controller();
+  if (off_hours_controller)
+    dict->SetBoolean("isOffHoursActive", off_hours_controller->is_off_hours_mode());
+}
 #endif  // defined(OS_CHROMEOS)
 
 void ExtractDomainFromUsername(base::DictionaryValue* dict) {
@@ -566,6 +574,7 @@
   GetStatusFromCore(core_, dict);
   dict->SetString("enterpriseEnrollmentDomain", enterprise_enrollment_domain_);
   dict->SetString("enterpriseDisplayDomain", enterprise_display_domain_);
+  GetOffHoursStatus(dict);
 }
 
 DeviceLocalAccountPolicyStatusProvider::DeviceLocalAccountPolicyStatusProvider(
diff --git a/chrome/browser/ui/webui/sync_internals_browsertest.js b/chrome/browser/ui/webui/sync_internals_browsertest.js
index 9a179ff..ede5673 100644
--- a/chrome/browser/ui/webui/sync_internals_browsertest.js
+++ b/chrome/browser/ui/webui/sync_internals_browsertest.js
@@ -260,9 +260,8 @@
 // set.
 TEST_F('SyncInternalsWebUITest', 'SyncDisabledByDefault', function() {
   expectTrue(this.hasInDetails(true, 'Transport State', 'Disabled'));
-  // TODO(crbug.com/906034,crbug.com/973770): Sort out the proper default value
-  // for IsSyncRequested() and possibly add the "User choice" disable reason.
-  expectTrue(this.hasInDetails(true, 'Disable Reasons', 'Not signed in'));
+  expectTrue(
+      this.hasInDetails(true, 'Disable Reasons', 'Not signed in, User choice'));
   expectTrue(this.hasInDetails(true, 'Username', ''));
 });
 
diff --git a/chrome/common/page_load_metrics/page_load_metrics.mojom b/chrome/common/page_load_metrics/page_load_metrics.mojom
index baf6813..c305e3f2 100644
--- a/chrome/common/page_load_metrics/page_load_metrics.mojom
+++ b/chrome/common/page_load_metrics/page_load_metrics.mojom
@@ -167,6 +167,13 @@
   array<int32> animated_css_properties;
 };
 
+// Enumeration of distinct cache types.
+enum CacheType {
+  kNotCached, // Resource came from network.
+  kHttp, // Resource was serviced by the http cache.
+  kMemory, // Resource was serviced by the Renderer's MemoryCache.
+};
+
 struct ResourceDataUpdate {
   // The id for the resource request.
   int32 request_id = 0;
@@ -199,8 +206,8 @@
   // Whether this resource was loaded in the top-level frame.
   bool is_main_frame_resource;
 
-  // Whether this resource was fetched from the http cache.
-  bool was_fetched_via_cache;
+  // Which cache this resource originated from, if any.
+  CacheType cache_type;
 
   // Whether this resource is the primary resource for a frame.
   bool is_primary_frame_resource;
diff --git a/chrome/common/page_load_metrics/test/page_load_metrics_test_util.cc b/chrome/common/page_load_metrics/test/page_load_metrics_test_util.cc
index 737a19fc..7d4fa45 100644
--- a/chrome/common/page_load_metrics/test/page_load_metrics_test_util.cc
+++ b/chrome/common/page_load_metrics/test/page_load_metrics_test_util.cc
@@ -92,7 +92,9 @@
     bool is_complete) {
   auto resource_data_update =
       page_load_metrics::mojom::ResourceDataUpdate::New();
-  resource_data_update->was_fetched_via_cache = was_cached;
+  resource_data_update->cache_type =
+      was_cached ? page_load_metrics::mojom::CacheType::kHttp
+                 : page_load_metrics::mojom::CacheType::kNotCached;
   resource_data_update->delta_bytes = delta_bytes;
   resource_data_update->received_data_length = delta_bytes;
   resource_data_update->encoded_body_length = encoded_body_length;
diff --git a/chrome/common/search.mojom b/chrome/common/search.mojom
index 0812afc..65621de 100644
--- a/chrome/common/search.mojom
+++ b/chrome/common/search.mojom
@@ -155,16 +155,26 @@
 // Renderer interface used by the browser to push updates to the client. For
 // example, the browser will tell the frame if the omnibox got focus.
 interface EmbeddedSearchClient {
+  // Update the page sequence number for the page.
   SetPageSequenceNumber(int32 page_seq_no);
 
+  // Focus on the Omnibox has changed, the fakebox focus state may need to
+  // be updated.
   FocusChanged(OmniboxFocusState new_focus_state,
                OmniboxFocusChangeReason reason);
 
+  // The data for the NTP shortcuts has changed and shortcuts should be
+  // reloaded.
   MostVisitedInfoChanged(InstantMostVisitedInfo most_visited_info);
 
+  // Input into the Omnibox has started/stopped.
   SetInputInProgress(bool input_in_progress);
 
+  // The browser theme has changed, the NTP should be updated accordingly.
   ThemeChanged(ThemeBackgroundInfo value);
+
+  // A background image was selected from the file upload dialog.
+  LocalBackgroundSelected();
 };
 
 // SearchBouncer tracks the NTP URL specified by the default search provider,
diff --git a/chrome/common/search/mock_embedded_search_client.h b/chrome/common/search/mock_embedded_search_client.h
index 5a8ab75..f5008ea9 100644
--- a/chrome/common/search/mock_embedded_search_client.h
+++ b/chrome/common/search/mock_embedded_search_client.h
@@ -18,7 +18,7 @@
   MOCK_METHOD1(MostVisitedInfoChanged, void(const InstantMostVisitedInfo&));
   MOCK_METHOD1(SetInputInProgress, void(bool));
   MOCK_METHOD1(ThemeChanged, void(const ThemeBackgroundInfo&));
-  MOCK_METHOD0(SelectLocalImageSuccess, void());
+  MOCK_METHOD0(LocalBackgroundSelected, void());
 };
 
 #endif  // CHROME_COMMON_SEARCH_MOCK_EMBEDDED_SEARCH_CLIENT_H_
diff --git a/chrome/common/thread_profiler.cc b/chrome/common/thread_profiler.cc
index bfdb6c4..b8333d3a 100644
--- a/chrome/common/thread_profiler.cc
+++ b/chrome/common/thread_profiler.cc
@@ -245,7 +245,7 @@
       std::make_unique<CallStackProfileBuilder>(
           CallStackProfileParams(GetProcess(), thread,
                                  CallStackProfileParams::PROCESS_STARTUP),
-          work_id_recorder_.get(), base::GetSampleMetadataRecorder()));
+          work_id_recorder_.get()));
 
   startup_profiler_->Start();
 
@@ -305,7 +305,7 @@
       std::make_unique<CallStackProfileBuilder>(
           CallStackProfileParams(GetProcess(), thread_,
                                  CallStackProfileParams::PERIODIC_COLLECTION),
-          work_id_recorder_.get(), base::GetSampleMetadataRecorder(),
+          work_id_recorder_.get(),
           base::BindOnce(&ThreadProfiler::OnPeriodicCollectionCompleted,
                          owning_thread_task_runner_,
                          weak_factory_.GetWeakPtr())));
diff --git a/chrome/renderer/net/net_error_helper_core.cc b/chrome/renderer/net/net_error_helper_core.cc
index cb2ad2d..9dff86e4 100644
--- a/chrome/renderer/net/net_error_helper_core.cc
+++ b/chrome/renderer/net/net_error_helper_core.cc
@@ -572,6 +572,7 @@
   // Don't need this state. It will be refreshed if another error page is
   // loaded.
   available_content_helper_.Reset();
+  page_auto_fetcher_helper_->OnCommitLoad();
 #endif
 
   // Track if an error occurred due to a page button press.
diff --git a/chrome/renderer/net/net_error_helper_core_unittest.cc b/chrome/renderer/net/net_error_helper_core_unittest.cc
index 3885911..87742721 100644
--- a/chrome/renderer/net/net_error_helper_core_unittest.cc
+++ b/chrome/renderer/net/net_error_helper_core_unittest.cc
@@ -21,6 +21,7 @@
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/test/bind_test_util.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/timer/mock_timer.h"
@@ -2762,11 +2763,17 @@
 class TestPageAutoFetcherHelper : public PageAutoFetcherHelper {
  public:
   explicit TestPageAutoFetcherHelper(
-      chrome::mojom::OfflinePageAutoFetcherPtr fetcher)
-      : PageAutoFetcherHelper(nullptr) {
-    fetcher_ = std::move(fetcher);
+      base::RepeatingCallback<chrome::mojom::OfflinePageAutoFetcherPtr()>
+          binder)
+      : PageAutoFetcherHelper(nullptr), binder_(binder) {}
+  bool Bind() override {
+    if (!fetcher_)
+      fetcher_ = binder_.Run();
+    return true;
   }
-  bool Bind() override { return true; }
+
+ private:
+  base::RepeatingCallback<chrome::mojom::OfflinePageAutoFetcherPtr()> binder_;
 };
 
 // Provides set up for testing the 'auto fetch on dino' feature.
@@ -2783,12 +2790,16 @@
         chrome::mojom::OfflinePageAutoFetcher::Name_,
         base::BindRepeating(&FakeOfflinePageAutoFetcher::AddBinding,
                             base::Unretained(&fake_fetcher_)));
-    chrome::mojom::OfflinePageAutoFetcherPtr fetcher_ptr;
-    render_thread()->GetConnector()->BindInterface(
-        content::mojom::kBrowserServiceName, &fetcher_ptr);
-    ASSERT_TRUE(fetcher_ptr);
+
+    auto binder = base::BindLambdaForTesting([&]() {
+      chrome::mojom::OfflinePageAutoFetcherPtr fetcher_ptr;
+      render_thread()->GetConnector()->BindInterface(
+          content::mojom::kBrowserServiceName, &fetcher_ptr);
+      return fetcher_ptr;
+    });
+
     core()->SetPageAutoFetcherHelperForTesting(
-        std::make_unique<TestPageAutoFetcherHelper>(std::move(fetcher_ptr)));
+        std::make_unique<TestPageAutoFetcherHelper>(binder));
   }
 
  protected:
diff --git a/chrome/renderer/net/page_auto_fetcher_helper_android.cc b/chrome/renderer/net/page_auto_fetcher_helper_android.cc
index 7705c0d..e36ec01 100644
--- a/chrome/renderer/net/page_auto_fetcher_helper_android.cc
+++ b/chrome/renderer/net/page_auto_fetcher_helper_android.cc
@@ -18,6 +18,12 @@
     : render_frame_(render_frame) {}
 PageAutoFetcherHelper::~PageAutoFetcherHelper() = default;
 
+void PageAutoFetcherHelper::OnCommitLoad() {
+  // Make sure we don't try to re-use the same mojo interface for more than one
+  // page. Otherwise, the browser side will use the old page's URL.
+  fetcher_.reset();
+}
+
 void PageAutoFetcherHelper::TrySchedule(
     bool user_requested,
     base::OnceCallback<void(FetcherScheduleResult)> complete_callback) {
diff --git a/chrome/renderer/net/page_auto_fetcher_helper_android.h b/chrome/renderer/net/page_auto_fetcher_helper_android.h
index 0d76567..f250510 100644
--- a/chrome/renderer/net/page_auto_fetcher_helper_android.h
+++ b/chrome/renderer/net/page_auto_fetcher_helper_android.h
@@ -22,6 +22,8 @@
       chrome::mojom::OfflinePageAutoFetcherScheduleResult;
   explicit PageAutoFetcherHelper(content::RenderFrame* render_frame);
   virtual ~PageAutoFetcherHelper();
+  // Should be called for each page load.
+  void OnCommitLoad();
   void TrySchedule(
       bool user_requested,
       base::OnceCallback<void(FetcherScheduleResult)> complete_callback);
diff --git a/chrome/renderer/page_load_metrics/metrics_render_frame_observer.cc b/chrome/renderer/page_load_metrics/metrics_render_frame_observer.cc
index b575917..f7d6156e 100644
--- a/chrome/renderer/page_load_metrics/metrics_render_frame_observer.cc
+++ b/chrome/renderer/page_load_metrics/metrics_render_frame_observer.cc
@@ -178,6 +178,25 @@
   }
 }
 
+void MetricsRenderFrameObserver::DidLoadResourceFromMemoryCache(
+    const GURL& response_url,
+    int request_id,
+    int64_t encoded_body_length,
+    const std::string& mime_type,
+    bool from_archive) {
+  // Resources from archives, such as subresources from a MHTML archive, do not
+  // have valid request ids and should not be reported to PLM.
+  if (from_archive)
+    return;
+
+  // A provisional frame resource cannot be serviced from the memory cache, so
+  // we do not need to check |provisional_frame_resource_data_use_|.
+  if (page_timing_metrics_sender_) {
+    page_timing_metrics_sender_->DidLoadResourceFromMemoryCache(
+        response_url, request_id, encoded_body_length, mime_type);
+  }
+}
+
 void MetricsRenderFrameObserver::FrameDetached() {
   page_timing_metrics_sender_.reset();
 }
diff --git a/chrome/renderer/page_load_metrics/metrics_render_frame_observer.h b/chrome/renderer/page_load_metrics/metrics_render_frame_observer.h
index 5e80942..3ecc1a7 100644
--- a/chrome/renderer/page_load_metrics/metrics_render_frame_observer.h
+++ b/chrome/renderer/page_load_metrics/metrics_render_frame_observer.h
@@ -63,6 +63,11 @@
       int request_id,
       const network::URLLoaderCompletionStatus& status) override;
   void DidCancelResponse(int request_id) override;
+  void DidLoadResourceFromMemoryCache(const GURL& response_url,
+                                      int request_id,
+                                      int64_t encoded_body_length,
+                                      const std::string& mime_type,
+                                      bool from_archive) override;
   void ReadyToCommitNavigation(
       blink::WebDocumentLoader* document_loader) override;
   void DidFailProvisionalLoad(const blink::WebURLError& error) override;
diff --git a/chrome/renderer/page_load_metrics/page_resource_data_use.cc b/chrome/renderer/page_load_metrics/page_resource_data_use.cc
index fb6f326..395fb07 100644
--- a/chrome/renderer/page_load_metrics/page_resource_data_use.cc
+++ b/chrome/renderer/page_load_metrics/page_resource_data_use.cc
@@ -8,6 +8,7 @@
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
 #include "services/network/public/cpp/resource_response.h"
 #include "services/network/public/cpp/url_loader_completion_status.h"
+#include "third_party/blink/public/platform/web_url.h"
 #include "url/gurl.h"
 
 namespace page_load_metrics {
@@ -75,9 +76,9 @@
       is_canceled_(false),
       reported_as_ad_resource_(false),
       is_main_frame_resource_(false),
-      was_fetched_via_cache_(false),
       is_secure_scheme_(false),
-      proxy_used_(false) {}
+      proxy_used_(false),
+      cache_type_(mojom::CacheType::kNotCached) {}
 
 PageResourceDataUse::PageResourceDataUse(const PageResourceDataUse& other) =
     default;
@@ -105,7 +106,8 @@
 
   proxy_used_ = !response_head.proxy_server.is_direct();
   mime_type_ = response_head.mime_type;
-  was_fetched_via_cache_ = response_head.was_fetched_via_cache;
+  if (response_head.was_fetched_via_cache)
+    cache_type_ = mojom::CacheType::kHttp;
   is_secure_scheme_ = response_url.SchemeIsCryptographic();
   is_primary_frame_resource_ =
       resource_type == content::ResourceType::kMainFrame ||
@@ -133,6 +135,23 @@
   is_canceled_ = true;
 }
 
+void PageResourceDataUse::DidLoadFromMemoryCache(const GURL& response_url,
+                                                 int request_id,
+                                                 int64_t encoded_body_length,
+                                                 const std::string& mime_type) {
+  origin_ = url::Origin::Create(response_url);
+  resource_id_ = request_id;
+  mime_type_ = mime_type;
+  is_secure_scheme_ = response_url.SchemeIsCryptographic();
+  cache_type_ = mojom::CacheType::kMemory;
+
+  // Resources from the memory cache cannot be a primary frame resource.
+  is_primary_frame_resource_ = false;
+
+  is_complete_ = true;
+  encoded_body_length_ = encoded_body_length;
+}
+
 bool PageResourceDataUse::IsFinishedLoading() {
   return is_complete_ || is_canceled_;
 }
@@ -154,6 +173,7 @@
 }
 
 mojom::ResourceDataUpdatePtr PageResourceDataUse::GetResourceDataUpdate() {
+  DCHECK(cache_type_ == mojom::CacheType::kMemory ? is_complete_ : true);
   mojom::ResourceDataUpdatePtr resource_data_update =
       mojom::ResourceDataUpdate::New();
   resource_data_update->request_id = resource_id();
@@ -166,7 +186,7 @@
   resource_data_update->is_main_frame_resource = is_main_frame_resource_;
   resource_data_update->mime_type = mime_type_;
   resource_data_update->encoded_body_length = encoded_body_length_;
-  resource_data_update->was_fetched_via_cache = was_fetched_via_cache_;
+  resource_data_update->cache_type = cache_type_;
   resource_data_update->is_secure_scheme = is_secure_scheme_;
   resource_data_update->proxy_used = proxy_used_;
   resource_data_update->is_primary_frame_resource = is_primary_frame_resource_;
diff --git a/chrome/renderer/page_load_metrics/page_resource_data_use.h b/chrome/renderer/page_load_metrics/page_resource_data_use.h
index e11e7c9..5cc47a6 100644
--- a/chrome/renderer/page_load_metrics/page_resource_data_use.h
+++ b/chrome/renderer/page_load_metrics/page_resource_data_use.h
@@ -43,6 +43,13 @@
   // Flags the resource as canceled.
   void DidCancelResponse();
 
+  // Called when this resource was loaded from the memory cache. Resources
+  // loaded from the memory cache only receive a single update.
+  void DidLoadFromMemoryCache(const GURL& response_url,
+                              int request_id,
+                              int64_t encoded_body_length,
+                              const std::string& mime_type);
+
   // Checks if the resource has completed loading or if the response was
   // cancelled.
   bool IsFinishedLoading();
@@ -76,11 +83,12 @@
   bool is_canceled_;
   bool reported_as_ad_resource_;
   bool is_main_frame_resource_;
-  bool was_fetched_via_cache_;
   bool is_secure_scheme_;
   bool proxy_used_;
   bool is_primary_frame_resource_ = false;
 
+  mojom::CacheType cache_type_;
+
   url::Origin origin_;
 
   std::string mime_type_;
diff --git a/chrome/renderer/page_load_metrics/page_timing_metrics_sender.cc b/chrome/renderer/page_load_metrics/page_timing_metrics_sender.cc
index 8a1a692..8462cdc 100644
--- a/chrome/renderer/page_load_metrics/page_timing_metrics_sender.cc
+++ b/chrome/renderer/page_load_metrics/page_timing_metrics_sender.cc
@@ -181,6 +181,27 @@
   resource_it->second->DidCancelResponse();
 }
 
+void PageTimingMetricsSender::DidLoadResourceFromMemoryCache(
+    const GURL& response_url,
+    int request_id,
+    int64_t encoded_body_length,
+    const std::string& mime_type) {
+  // In general, we should not observe the same resource being loaded twice in
+  // the frame. This is possible due to an existing workaround in
+  // ResourceFetcher::EmulateLoadStartedForInspector(). In this case, ignore
+  // multiple resources being loaded in the document, as memory cache resources
+  // are only reported once per context by design in all other cases.
+  if (base::Contains(page_resource_data_use_, request_id))
+    return;
+
+  auto resource_it = page_resource_data_use_.emplace(
+      std::piecewise_construct, std::forward_as_tuple(request_id),
+      std::forward_as_tuple(std::make_unique<PageResourceDataUse>()));
+  resource_it.first->second->DidLoadFromMemoryCache(
+      response_url, request_id, encoded_body_length, mime_type);
+  modified_resources_.insert(resource_it.first->second.get());
+}
+
 void PageTimingMetricsSender::UpdateResourceMetadata(
     int resource_id,
     bool reported_as_ad_resource,
diff --git a/chrome/renderer/page_load_metrics/page_timing_metrics_sender.h b/chrome/renderer/page_load_metrics/page_timing_metrics_sender.h
index eefacfa..e75d48c 100644
--- a/chrome/renderer/page_load_metrics/page_timing_metrics_sender.h
+++ b/chrome/renderer/page_load_metrics/page_timing_metrics_sender.h
@@ -61,6 +61,10 @@
   void DidCompleteResponse(int resource_id,
                            const network::URLLoaderCompletionStatus& status);
   void DidCancelResponse(int resource_id);
+  void DidLoadResourceFromMemoryCache(const GURL& response_url,
+                                      int request_id,
+                                      int64_t encoded_body_length,
+                                      const std::string& mime_type);
 
   // TODO(ericrobinson): There should probably be a name change here:
   // * Send: Sends immediately, functions as SendNow.
diff --git a/chrome/renderer/searchbox/searchbox.cc b/chrome/renderer/searchbox/searchbox.cc
index d9511411..0ab67daa 100644
--- a/chrome/renderer/searchbox/searchbox.cc
+++ b/chrome/renderer/searchbox/searchbox.cc
@@ -535,6 +535,13 @@
     SearchBoxExtension::DispatchThemeChange(render_frame()->GetWebFrame());
 }
 
+void SearchBox::LocalBackgroundSelected() {
+  if (can_run_js_in_renderframe_) {
+    SearchBoxExtension::DispatchLocalBackgroundSelected(
+        render_frame()->GetWebFrame());
+  }
+}
+
 GURL SearchBox::GetURLForMostVisitedItem(InstantRestrictedID item_id) const {
   InstantMostVisitedItem item;
   return GetMostVisitedItemWithID(item_id, &item) ? item.url : GURL();
diff --git a/chrome/renderer/searchbox/searchbox.h b/chrome/renderer/searchbox/searchbox.h
index 396bc447..c99f06cc 100644
--- a/chrome/renderer/searchbox/searchbox.h
+++ b/chrome/renderer/searchbox/searchbox.h
@@ -205,6 +205,7 @@
       const InstantMostVisitedInfo& most_visited_info) override;
   void SetInputInProgress(bool input_in_progress) override;
   void ThemeChanged(const ThemeBackgroundInfo& theme_info) override;
+  void LocalBackgroundSelected() override;
 
   void AddCustomLinkResult(bool success);
   void UpdateCustomLinkResult(bool success);
diff --git a/chrome/renderer/searchbox/searchbox_extension.cc b/chrome/renderer/searchbox/searchbox_extension.cc
index 6990408..5a78397 100644
--- a/chrome/renderer/searchbox/searchbox_extension.cc
+++ b/chrome/renderer/searchbox/searchbox_extension.cc
@@ -535,6 +535,19 @@
     "  true;"
     "}";
 
+static const char kDispatchLocalBackgroundSelectedScript[] =
+    "if (window.chrome &&"
+    "    window.chrome.embeddedSearch &&"
+    "    window.chrome.embeddedSearch.newTabPage &&"
+    "    window.chrome.embeddedSearch.newTabPage.onthemechange &&"
+    "    typeof window.chrome.embeddedSearch.newTabPage.onthemechange =="
+    "        'function') {"
+    "  "
+    "window.chrome.embeddedSearch.newTabPage."
+    "onlocalbackgroundselected();"
+    "  true;"
+    "}";
+
 // ----------------------------------------------------------------------------
 
 class SearchBoxBindings : public gin::Wrappable<SearchBoxBindings> {
@@ -1331,3 +1344,9 @@
 void SearchBoxExtension::DispatchThemeChange(blink::WebLocalFrame* frame) {
   Dispatch(frame, kDispatchThemeChangeEventScript);
 }
+
+// static
+void SearchBoxExtension::DispatchLocalBackgroundSelected(
+    blink::WebLocalFrame* frame) {
+  Dispatch(frame, kDispatchLocalBackgroundSelectedScript);
+}
diff --git a/chrome/renderer/searchbox/searchbox_extension.h b/chrome/renderer/searchbox/searchbox_extension.h
index f8b208e4..95072487 100644
--- a/chrome/renderer/searchbox/searchbox_extension.h
+++ b/chrome/renderer/searchbox/searchbox_extension.h
@@ -34,6 +34,7 @@
   static void DispatchKeyCaptureChange(blink::WebLocalFrame* frame);
   static void DispatchMostVisitedChanged(blink::WebLocalFrame* frame);
   static void DispatchThemeChange(blink::WebLocalFrame* frame);
+  static void DispatchLocalBackgroundSelected(blink::WebLocalFrame* frame);
 
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(SearchBoxExtension);
diff --git a/chrome/test/base/interactive_test_utils_views.cc b/chrome/test/base/interactive_test_utils_views.cc
index 3723adbe..680e864 100644
--- a/chrome/test/base/interactive_test_utils_views.cc
+++ b/chrome/test/base/interactive_test_utils_views.cc
@@ -36,12 +36,12 @@
 
   // views::ViewObserver:
   void OnViewFocused(views::View* observed_view) override {
-    if (target_focused_ && run_loop_.running())
+    if (run_loop_.running() && target_focused_)
       run_loop_.Quit();
   }
 
   void OnViewBlurred(views::View* observed_view) override {
-    if (!target_focused_ && run_loop_.running())
+    if (run_loop_.running() && !target_focused_)
       run_loop_.Quit();
   }
 
diff --git a/chrome/test/base/ui_test_utils.cc b/chrome/test/base/ui_test_utils.cc
index 09b8418f..196d219 100644
--- a/chrome/test/base/ui_test_utils.cc
+++ b/chrome/test/base/ui_test_utils.cc
@@ -81,6 +81,12 @@
 #include <windows.h>
 #endif
 
+#if defined(TOOLKIT_VIEWS)
+#include "chrome/browser/ui/browser_window.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+#endif
+
 using content::NavigationController;
 using content::NavigationEntry;
 using content::OpenURLParams;
@@ -371,6 +377,23 @@
   return waiter.Wait();
 }
 
+#if defined(TOOLKIT_VIEWS)
+void WaitForViewVisibility(Browser* browser, ViewID vid, bool visible) {
+  views::View* view = views::Widget::GetWidgetForNativeWindow(
+                          browser->window()->GetNativeWindow())
+                          ->GetContentsView()
+                          ->GetViewByID(vid);
+  ASSERT_TRUE(view);
+  if (view->GetVisible() == visible)
+    return;
+
+  base::RunLoop run_loop;
+  auto subscription = view->AddVisibleChangedCallback(run_loop.QuitClosure());
+  run_loop.Run();
+  EXPECT_EQ(visible, view->GetVisible());
+}
+#endif
+
 int FindInPage(WebContents* tab,
                const base::string16& search_string,
                bool forward,
diff --git a/chrome/test/base/ui_test_utils.h b/chrome/test/base/ui_test_utils.h
index 2556432..09902e1a 100644
--- a/chrome/test/base/ui_test_utils.h
+++ b/chrome/test/base/ui_test_utils.h
@@ -13,6 +13,7 @@
 
 #include "base/macros.h"
 #include "base/strings/string16.h"
+#include "chrome/browser/ui/view_ids.h"
 #include "components/history/core/browser/history_service.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_observer.h"
@@ -164,6 +165,11 @@
 // Blocks until an application modal dialog is shown and returns it.
 app_modal::JavaScriptAppModalDialog* WaitForAppModalDialog();
 
+#if defined(TOOLKIT_VIEWS)
+// Blocks until the given view attains the given visibility state.
+void WaitForViewVisibility(Browser* browser, ViewID vid, bool visible);
+#endif
+
 // Performs a find in the page of the specified tab. Returns the number of
 // matches found.  |ordinal| is an optional parameter which is set to the index
 // of the current match. |selection_rect| is an optional parameter which is set
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index 3b0145b..b54ea75 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -113,9 +113,6 @@
 _OS_SPECIFIC_FILTER['mac'] = [
     # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1927
     'MobileEmulationCapabilityTest.testTapElement',
-    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2579
-    'ChromeDriverTest.testTakeElementScreenshot',
-    'ChromeDriverTest.testTakeElementScreenshotInIframe',
     # https://bugs.chromium.org/p/chromium/issues/detail?id=946023
     'ChromeDriverTest.testWindowFullScreen',
     'ChromeDownloadDirTest.testFileDownloadAfterTabHeadless',
@@ -1982,8 +1979,18 @@
   def testTakeElementScreenshot(self):
     self._driver.Load(self.GetHttpUrlForFile(
                       '/chromedriver/page_with_redbox.html'))
+    analysisResult = 'FAIL'
+    i = 0
     redElement = self._driver.FindElement('css selector', '#box')
-    analysisResult = self.takeScreenshotAndVerifyCorrect(redElement)
+    # In some cases (particularly on Mac),
+    # scrollbars are displayed briefly after scrolling,
+    # causing failures in verifying the screenshot.
+    # Retries until the scrollbars disappear.
+    while analysisResult != 'PASS' and i < 3:
+      analysisResult = self.takeScreenshotAndVerifyCorrect(redElement)
+      i += 1
+      if analysisResult != 'PASS':
+        time.sleep(0.5)
     self.assertEquals('PASS', analysisResult)
 
   def testTakeElementScreenshotInIframe(self):
@@ -1991,8 +1998,18 @@
                       '/chromedriver/page_with_iframe_redbox.html'))
     frame = self._driver.FindElement('css selector', '#frm')
     self._driver.SwitchToFrame(frame)
+    analysisResult = 'FAIL'
+    i = 0
     redElement = self._driver.FindElement('css selector', '#box')
-    analysisResult = self.takeScreenshotAndVerifyCorrect(redElement)
+    # In some cases (particularly on Mac),
+    # scrollbars are displayed briefly after scrolling,
+    # causing failures in verifying the screenshot.
+    # Retries until the scrollbars disappear.
+    while analysisResult != 'PASS' and i < 3:
+      analysisResult = self.takeScreenshotAndVerifyCorrect(redElement)
+      i += 1
+      if analysisResult != 'PASS':
+        time.sleep(0.5)
     self.assertEquals('PASS', analysisResult)
 
   def testTakeLargeElementScreenshot(self):
diff --git a/chrome/test/chromedriver/test/test_expectations b/chrome/test/chromedriver/test/test_expectations
index cd0dc41..0cc3ae1c 100644
--- a/chrome/test/chromedriver/test/test_expectations
+++ b/chrome/test/chromedriver/test/test_expectations
@@ -35,13 +35,6 @@
 
     #https://bugs.chromium.org/p/chromedriver/issues/detail?id=2971
     'ChromeDevToolsProfilerTest.sampleProfileEvents',
-
-    #https://bugs.chromium.org/p/chromedriver/issues/detail?id=2978
-    'TypingTest.testChordControlHomeShiftEndDelete',
-    'TypingTest.testChordReveseShiftHomeSelectionDeletes',
-    'TypingTest.testChordControlCutAndPaste',
-    'TypingTest.testDeleteAndBackspaceKeys',
-    'TypingTest.testShiftSelectionDeletes',
 ]
 
 _READY_TO_RUN_FILTER = [
diff --git a/chrome/test/data/forced-colors.html b/chrome/test/data/forced-colors.html
new file mode 100644
index 0000000..5923392
--- /dev/null
+++ b/chrome/test/data/forced-colors.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<title>FAIL</title>
+<script>
+  if (window.matchMedia("(forced-colors: none)").matches) {
+    document.title = "none";
+  } else if (window.matchMedia("(forced-colors: active)").matches) {
+    document.title = "active";
+  }
+</script>
diff --git a/chrome/test/data/page_load_metrics/background_image.css b/chrome/test/data/page_load_metrics/background_image.css
new file mode 100644
index 0000000..f91e16f
--- /dev/null
+++ b/chrome/test/data/page_load_metrics/background_image.css
@@ -0,0 +1,7 @@
+/* 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. */
+
+body {
+  background-image: url("pixel.png");
+}
diff --git a/chrome/test/data/page_load_metrics/background_image.css.mock-http-headers b/chrome/test/data/page_load_metrics/background_image.css.mock-http-headers
new file mode 100644
index 0000000..0e97a23
--- /dev/null
+++ b/chrome/test/data/page_load_metrics/background_image.css.mock-http-headers
@@ -0,0 +1,3 @@
+HTTP/1.1 200 OK
+Content-Type: text/html
+Cache-Control: max-age=31536000
\ No newline at end of file
diff --git a/chrome/test/data/page_load_metrics/document_with_css_image_sharing.html b/chrome/test/data/page_load_metrics/document_with_css_image_sharing.html
new file mode 100644
index 0000000..c5e87f9
--- /dev/null
+++ b/chrome/test/data/page_load_metrics/document_with_css_image_sharing.html
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="background_image.css">
+  </head>
+  <body>
+    <iframe src="document_with_duplicate_css.html"></iframe>
+  </body>
+</html>
diff --git a/chrome/test/data/page_load_metrics/document_with_duplicate_css.html b/chrome/test/data/page_load_metrics/document_with_duplicate_css.html
new file mode 100644
index 0000000..b41fe2b
--- /dev/null
+++ b/chrome/test/data/page_load_metrics/document_with_duplicate_css.html
@@ -0,0 +1,9 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="background_image.css">
+    <link rel="stylesheet" type="text/css" href="background_image.css">
+  </head>
+  <body>
+   The page loads the same css file.
+  </body>
+</html>
diff --git a/chrome/test/data/page_load_metrics/pixel.png b/chrome/test/data/page_load_metrics/pixel.png
new file mode 100644
index 0000000..c5916f2
--- /dev/null
+++ b/chrome/test/data/page_load_metrics/pixel.png
Binary files differ
diff --git a/chrome/test/data/page_load_metrics/pixel.png.mock-http-headers b/chrome/test/data/page_load_metrics/pixel.png.mock-http-headers
new file mode 100644
index 0000000..0e97a23
--- /dev/null
+++ b/chrome/test/data/page_load_metrics/pixel.png.mock-http-headers
@@ -0,0 +1,3 @@
+HTTP/1.1 200 OK
+Content-Type: text/html
+Cache-Control: max-age=31536000
\ No newline at end of file
diff --git a/chromecast/media/cma/backend/post_processing_pipeline_impl.cc b/chromecast/media/cma/backend/post_processing_pipeline_impl.cc
index 01dffc0..3aabc58 100644
--- a/chromecast/media/cma/backend/post_processing_pipeline_impl.cc
+++ b/chromecast/media/cma/backend/post_processing_pipeline_impl.cc
@@ -4,6 +4,7 @@
 
 #include "chromecast/media/cma/backend/post_processing_pipeline_impl.h"
 
+#include <algorithm>
 #include <cmath>
 #include <string>
 
@@ -129,7 +130,16 @@
 
   if (is_silence) {
     if (!IsRinging()) {
-      return delay_s_;  // Output will be silence.
+      // If the input sample rate differs from the output sample rate, then the
+      // input data will be the incorrect size without any resampling. Output a
+      // zeroed buffer of correct size.
+      if (input_sample_rate_ != output_sample_rate_) {
+        // We cannot guarantee that the consumer of the output buffer will not
+        // mutate it, so set it back to zero.
+        std::fill_n(silence_buffer_.data(), silence_buffer_.size(), 0.0);
+        output_buffer_ = silence_buffer_.data();
+      }
+      return delay_s_;
     }
     silence_frames_processed_ += num_input_frames;
   } else {
@@ -185,6 +195,14 @@
   input_sample_rate_ = processor_config.output_sample_rate;
   ringing_time_in_frames_ = GetRingingTimeInFrames();
   silence_frames_processed_ = 0;
+
+  if (input_sample_rate_ != output_sample_rate_) {
+    size_t silence_size = num_output_channels_ *
+                          processors_[0].input_frames_per_write *
+                          output_sample_rate_ / input_sample_rate_;
+    silence_buffer_.resize(silence_size);
+  }
+
   return true;
 }
 
diff --git a/chromecast/media/cma/backend/post_processing_pipeline_impl.h b/chromecast/media/cma/backend/post_processing_pipeline_impl.h
index 7babae6..f604acf9 100644
--- a/chromecast/media/cma/backend/post_processing_pipeline_impl.h
+++ b/chromecast/media/cma/backend/post_processing_pipeline_impl.h
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "chromecast/media/base/aligned_buffer.h"
 #include "chromecast/media/cma/backend/post_processing_pipeline.h"
 #include "chromecast/media/cma/backend/post_processor_factory.h"
 #include "chromecast/public/volume_control.h"
@@ -73,6 +74,7 @@
   float current_dbfs_ = 0.0;
   int num_output_channels_ = 0;
   float* output_buffer_ = nullptr;
+  AlignedBuffer<float> silence_buffer_;
 
   // factory_ keeps shared libraries open, so it must outlive processors_.
   PostProcessorFactory factory_;
diff --git a/chromeos/components/multidevice/debug_webui/BUILD.gn b/chromeos/components/multidevice/debug_webui/BUILD.gn
index 79b3465d..92077a4 100644
--- a/chromeos/components/multidevice/debug_webui/BUILD.gn
+++ b/chromeos/components/multidevice/debug_webui/BUILD.gn
@@ -32,6 +32,7 @@
     "//components/resources",
     "//content/public/browser",
     "//device/bluetooth",
+    "//device/bluetooth/public/cpp",
     "//ui/resources",
     "//ui/webui",
   ]
diff --git a/chromeos/components/multidevice/debug_webui/proximity_auth_webui_handler.cc b/chromeos/components/multidevice/debug_webui/proximity_auth_webui_handler.cc
index eb1a490..3d04392d 100644
--- a/chromeos/components/multidevice/debug_webui/proximity_auth_webui_handler.cc
+++ b/chromeos/components/multidevice/debug_webui/proximity_auth_webui_handler.cc
@@ -26,7 +26,7 @@
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_ui.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace chromeos {
 
diff --git a/chromeos/services/assistant/platform/audio_input_impl.cc b/chromeos/services/assistant/platform/audio_input_impl.cc
index 529616ab..5546547 100644
--- a/chromeos/services/assistant/platform/audio_input_impl.cc
+++ b/chromeos/services/assistant/platform/audio_input_impl.cc
@@ -10,6 +10,7 @@
 #include "base/stl_util.h"
 #include "base/timer/timer.h"
 #include "chromeos/audio/cras_audio_handler.h"
+#include "chromeos/dbus/power/power_manager_client.h"
 #include "chromeos/services/assistant/public/features.h"
 #include "chromeos/services/assistant/utils.h"
 #include "libassistant/shared/public/platform_audio_buffer.h"
@@ -70,14 +71,23 @@
       input_->RecreateAudioInputStream(false /* use_dsp */);
     }
     stream_state_ = StreamState::NORMAL;
+
+    // Inform power manager of the user activity happened every time
+    // Libassistant recognized hotword and started a conversation.
+    chromeos::PowerManagerClient::Get()->NotifyUserActivity(
+        power_manager::USER_ACTIVITY_OTHER);
   }
 
   // Runs on main thread.
   void OnConversationTurnFinished() override {
     DCHECK(task_runner_->RunsTasksInCurrentSequence());
     input_->RecreateAudioInputStream(true /* use_dsp */);
+    if (stream_state_ == StreamState::HOTWORD) {
+      // If |stream_state_| remains unchanged, that indicates the first stage
+      // DSP hotword detection was rejected by Libassistant.
+      RecordDspHotwordDetection(DspHotwordDetectionStatus::SOFTWARE_REJECTED);
+    }
     stream_state_ = StreamState::HOTWORD;
-    RecordDspHotwordDetection(DspHotwordDetectionStatus::SOFTWARE_REJECTED);
   }
 
   // Runs on audio service thread
diff --git a/chromeos/services/secure_channel/BUILD.gn b/chromeos/services/secure_channel/BUILD.gn
index 1aa62e7..f9a6dfc 100644
--- a/chromeos/services/secure_channel/BUILD.gn
+++ b/chromeos/services/secure_channel/BUILD.gn
@@ -161,6 +161,7 @@
     "//chromeos/services/secure_channel/public/mojom",
     "//crypto",
     "//device/bluetooth",
+    "//device/bluetooth/public/cpp",
     "//services/service_manager/public/cpp",
     "//services/service_manager/public/mojom",
   ]
diff --git a/chromeos/services/secure_channel/ble_characteristics_finder.cc b/chromeos/services/secure_channel/ble_characteristics_finder.cc
index c4e2a8d..d02dc9f 100644
--- a/chromeos/services/secure_channel/ble_characteristics_finder.cc
+++ b/chromeos/services/secure_channel/ble_characteristics_finder.cc
@@ -8,7 +8,7 @@
 #include "device/bluetooth/bluetooth_adapter.h"
 #include "device/bluetooth/bluetooth_device.h"
 #include "device/bluetooth/bluetooth_remote_gatt_characteristic.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 using device::BluetoothAdapter;
 using device::BluetoothDevice;
diff --git a/chromeos/services/secure_channel/ble_characteristics_finder.h b/chromeos/services/secure_channel/ble_characteristics_finder.h
index f784876..615bf7a 100644
--- a/chromeos/services/secure_channel/ble_characteristics_finder.h
+++ b/chromeos/services/secure_channel/ble_characteristics_finder.h
@@ -13,7 +13,7 @@
 #include "device/bluetooth/bluetooth_device.h"
 #include "device/bluetooth/bluetooth_remote_gatt_characteristic.h"
 #include "device/bluetooth/bluetooth_remote_gatt_service.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace chromeos {
 
diff --git a/chromeos/services/secure_channel/ble_characteristics_finder_unittest.cc b/chromeos/services/secure_channel/ble_characteristics_finder_unittest.cc
index d71eea9..7b6aa516 100644
--- a/chromeos/services/secure_channel/ble_characteristics_finder_unittest.cc
+++ b/chromeos/services/secure_channel/ble_characteristics_finder_unittest.cc
@@ -10,7 +10,7 @@
 #include "base/memory/ref_counted.h"
 #include "chromeos/services/secure_channel/remote_attribute.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
 #include "device/bluetooth/test/mock_bluetooth_device.h"
 #include "device/bluetooth/test/mock_bluetooth_gatt_characteristic.h"
diff --git a/chromeos/services/secure_channel/ble_connection_manager_impl.cc b/chromeos/services/secure_channel/ble_connection_manager_impl.cc
index 0d4df396..3be6868 100644
--- a/chromeos/services/secure_channel/ble_connection_manager_impl.cc
+++ b/chromeos/services/secure_channel/ble_connection_manager_impl.cc
@@ -22,7 +22,7 @@
 #include "chromeos/services/secure_channel/latency_metrics_logger.h"
 #include "chromeos/services/secure_channel/public/mojom/secure_channel.mojom.h"
 #include "chromeos/services/secure_channel/secure_channel_disconnector_impl.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace chromeos {
 
diff --git a/chromeos/services/secure_channel/ble_connection_manager_impl_unittest.cc b/chromeos/services/secure_channel/ble_connection_manager_impl_unittest.cc
index a22cc15f..afb1fd6 100644
--- a/chromeos/services/secure_channel/ble_connection_manager_impl_unittest.cc
+++ b/chromeos/services/secure_channel/ble_connection_manager_impl_unittest.cc
@@ -36,7 +36,7 @@
 #include "chromeos/services/secure_channel/fake_timer_factory.h"
 #include "chromeos/services/secure_channel/secure_channel.h"
 #include "chromeos/services/secure_channel/secure_channel_disconnector_impl.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromeos/services/secure_channel/ble_scanner_impl.cc b/chromeos/services/secure_channel/ble_scanner_impl.cc
index 665fb39f..6734f3e 100644
--- a/chromeos/services/secure_channel/ble_scanner_impl.cc
+++ b/chromeos/services/secure_channel/ble_scanner_impl.cc
@@ -18,7 +18,7 @@
 #include "chromeos/services/secure_channel/ble_synchronizer_base.h"
 #include "device/bluetooth/bluetooth_device.h"
 #include "device/bluetooth/bluetooth_discovery_session.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace chromeos {
 
diff --git a/chromeos/services/secure_channel/ble_weave_client_connection.h b/chromeos/services/secure_channel/ble_weave_client_connection.h
index e6fef2e0..39398db 100644
--- a/chromeos/services/secure_channel/ble_weave_client_connection.h
+++ b/chromeos/services/secure_channel/ble_weave_client_connection.h
@@ -27,7 +27,7 @@
 #include "device/bluetooth/bluetooth_device.h"
 #include "device/bluetooth/bluetooth_gatt_notify_session.h"
 #include "device/bluetooth/bluetooth_remote_gatt_characteristic.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace base {
 class TaskRunner;
diff --git a/chromeos/services/secure_channel/remote_attribute.h b/chromeos/services/secure_channel/remote_attribute.h
index 292faeb..e7e0824 100644
--- a/chromeos/services/secure_channel/remote_attribute.h
+++ b/chromeos/services/secure_channel/remote_attribute.h
@@ -7,7 +7,7 @@
 
 #include <string>
 
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace chromeos {
 
diff --git a/components/arc/bluetooth/bluetooth_struct_traits.cc b/components/arc/bluetooth/bluetooth_struct_traits.cc
index dfb7423..e10d42f 100644
--- a/components/arc/bluetooth/bluetooth_struct_traits.cc
+++ b/components/arc/bluetooth/bluetooth_struct_traits.cc
@@ -14,7 +14,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "device/bluetooth/bluetooth_advertisement.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace {
 
diff --git a/components/arc/bluetooth/bluetooth_struct_traits.h b/components/arc/bluetooth/bluetooth_struct_traits.h
index aa60fe6..5ae85d1 100644
--- a/components/arc/bluetooth/bluetooth_struct_traits.h
+++ b/components/arc/bluetooth/bluetooth_struct_traits.h
@@ -11,8 +11,8 @@
 #include "components/arc/common/bluetooth.mojom.h"
 #include "device/bluetooth/bluetooth_advertisement.h"
 #include "device/bluetooth/bluetooth_common.h"
-#include "device/bluetooth/bluetooth_uuid.h"
 #include "device/bluetooth/bluez/bluetooth_service_attribute_value_bluez.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace mojo {
 
diff --git a/components/arc/bluetooth/bluetooth_struct_traits_unittest.cc b/components/arc/bluetooth/bluetooth_struct_traits_unittest.cc
index 243245f5..b6ddaae7 100644
--- a/components/arc/bluetooth/bluetooth_struct_traits_unittest.cc
+++ b/components/arc/bluetooth/bluetooth_struct_traits_unittest.cc
@@ -8,7 +8,7 @@
 #include <utility>
 
 #include "base/stl_util.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
diff --git a/components/arc/bluetooth/bluetooth_type_converters.cc b/components/arc/bluetooth/bluetooth_type_converters.cc
index 1bcda4b8..cba30eb 100644
--- a/components/arc/bluetooth/bluetooth_type_converters.cc
+++ b/components/arc/bluetooth/bluetooth_type_converters.cc
@@ -17,7 +17,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "components/arc/bluetooth/bluetooth_type_converters.h"
 #include "device/bluetooth/bluetooth_gatt_service.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace {
 
diff --git a/components/arc/bluetooth/bluetooth_type_converters_unittest.cc b/components/arc/bluetooth/bluetooth_type_converters_unittest.cc
index 1cdbe259..c4f9e8b 100644
--- a/components/arc/bluetooth/bluetooth_type_converters_unittest.cc
+++ b/components/arc/bluetooth/bluetooth_type_converters_unittest.cc
@@ -11,8 +11,8 @@
 
 #include "base/values.h"
 #include "device/bluetooth/bluetooth_gatt_service.h"
-#include "device/bluetooth/bluetooth_uuid.h"
 #include "device/bluetooth/bluez/bluetooth_service_attribute_value_bluez.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
diff --git a/components/arc/common/bluetooth.typemap b/components/arc/common/bluetooth.typemap
index b59c8707..d620ccc 100644
--- a/components/arc/common/bluetooth.typemap
+++ b/components/arc/common/bluetooth.typemap
@@ -2,7 +2,7 @@
 public_headers = [
   "//device/bluetooth/bluetooth_advertisement.h",
   "//device/bluetooth/bluetooth_common.h",
-  "//device/bluetooth/bluetooth_uuid.h",
+  "//device/bluetooth/public/cpp/bluetooth_uuid.h",
   "//device/bluetooth/bluez/bluetooth_service_attribute_value_bluez.h",
 ]
 traits_headers = [ "//components/arc/bluetooth/bluetooth_struct_traits.h" ]
@@ -11,6 +11,7 @@
 ]
 deps = [
   "//device/bluetooth",
+  "//device/bluetooth/public/cpp",
 ]
 type_mappings = [
   "arc.mojom.BluetoothDeviceType=device::BluetoothTransport",
diff --git a/components/arc/common/power.mojom b/components/arc/common/power.mojom
index 048f8c6..b3304bf 100644
--- a/components/arc/common/power.mojom
+++ b/components/arc/common/power.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Next MinVersion: 5
+// Next MinVersion: 6
 
 module arc.mojom;
 
@@ -33,7 +33,7 @@
   [MinVersion=3] OnScreenBrightnessUpdateRequest@3(double percent);
 };
 
-// Next method ID: 6
+// Next method ID: 7
 interface PowerInstance {
   // DEPRECATED: Please use Init@5 instead.
   InitDeprecated@0(PowerHost host_ptr);
@@ -54,4 +54,9 @@
   // Update Android brightness settings.
   // |percent| is of the range [0, 100]
   [MinVersion=3] UpdateScreenBrightnessSettings@4(double percent);
+
+  // Called when the power supply information is updated.
+  // TODO(b/136427446): Rearchitect ARC power info management with more
+  // explicit data / event passing.
+  [MinVersion=5] PowerSupplyInfoChanged@6();
 };
diff --git a/components/arc/power/arc_power_bridge.cc b/components/arc/power/arc_power_bridge.cc
index 897e2f0..4985b116 100644
--- a/components/arc/power/arc_power_bridge.cc
+++ b/components/arc/power/arc_power_bridge.cc
@@ -208,6 +208,16 @@
   last_brightness_changed_time_ = now;
 }
 
+void ArcPowerBridge::PowerChanged(
+    const power_manager::PowerSupplyProperties& proto) {
+  mojom::PowerInstance* power_instance = ARC_GET_INSTANCE_FOR_METHOD(
+      arc_bridge_service_->power(), PowerSupplyInfoChanged);
+  if (!power_instance)
+    return;
+
+  power_instance->PowerSupplyInfoChanged();
+}
+
 void ArcPowerBridge::OnPowerStateChanged(
     chromeos::DisplayPowerState power_state) {
   mojom::PowerInstance* power_instance =
diff --git a/components/arc/power/arc_power_bridge.h b/components/arc/power/arc_power_bridge.h
index 2de26f0..94fc7dbc 100644
--- a/components/arc/power/arc_power_bridge.h
+++ b/components/arc/power/arc_power_bridge.h
@@ -67,6 +67,7 @@
   void SuspendDone(const base::TimeDelta& sleep_duration) override;
   void ScreenBrightnessChanged(
       const power_manager::BacklightBrightnessChange& change) override;
+  void PowerChanged(const power_manager::PowerSupplyProperties& proto) override;
 
   // DisplayConfigurator::Observer overrides.
   void OnPowerStateChanged(chromeos::DisplayPowerState power_state) override;
diff --git a/components/arc/power/arc_power_bridge_unittest.cc b/components/arc/power/arc_power_bridge_unittest.cc
index a4d479e..427ea574 100644
--- a/components/arc/power/arc_power_bridge_unittest.cc
+++ b/components/arc/power/arc_power_bridge_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/run_loop.h"
 #include "base/test/scoped_task_environment.h"
 #include "chromeos/dbus/power/fake_power_manager_client.h"
+#include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
 #include "chromeos/dbus/power_manager/suspend.pb.h"
 #include "components/arc/common/power.mojom.h"
 #include "components/arc/session/arc_bridge_service.h"
@@ -190,6 +191,20 @@
   EXPECT_DOUBLE_EQ(kAndroidBrightness, power_instance_->screen_brightness());
 }
 
+TEST_F(ArcPowerBridgeTest, PowerSupplyInfoChanged) {
+  base::Optional<power_manager::PowerSupplyProperties> prop =
+      power_manager_client()->GetLastStatus();
+  ASSERT_TRUE(prop.has_value());
+  prop->set_battery_state(power_manager::PowerSupplyProperties::FULL);
+  power_manager_client()->UpdatePowerProperties(prop.value());
+
+  // Check that Chrome OS power changes are passed to Android.
+  const int prev_call_count = power_instance_->num_power_supply_info();
+  prop->set_battery_state(power_manager::PowerSupplyProperties::DISCHARGING);
+  power_manager_client()->UpdatePowerProperties(prop.value());
+  EXPECT_EQ(1 + prev_call_count, power_instance_->num_power_supply_info());
+}
+
 TEST_F(ArcPowerBridgeTest, DifferentWakeLocks) {
   AcquireDisplayWakeLock(mojom::DisplayWakeLockType::BRIGHT);
   EXPECT_EQ(1, GetActiveWakeLocks(WakeLockType::kPreventDisplaySleep));
diff --git a/components/arc/test/fake_power_instance.cc b/components/arc/test/fake_power_instance.cc
index 7b17755..f5620df 100644
--- a/components/arc/test/fake_power_instance.cc
+++ b/components/arc/test/fake_power_instance.cc
@@ -46,4 +46,8 @@
   screen_brightness_ = percent;
 }
 
+void FakePowerInstance::PowerSupplyInfoChanged() {
+  num_power_supply_info_++;
+}
+
 }  // namespace arc
diff --git a/components/arc/test/fake_power_instance.h b/components/arc/test/fake_power_instance.h
index 28dfc3c..c2e3240 100644
--- a/components/arc/test/fake_power_instance.h
+++ b/components/arc/test/fake_power_instance.h
@@ -19,6 +19,7 @@
   int num_suspend() const { return num_suspend_; }
   int num_resume() const { return num_resume_; }
   double screen_brightness() const { return screen_brightness_; }
+  int num_power_supply_info() const { return num_power_supply_info_; }
 
   // Returns |suspend_callback_| and resets the member.
   SuspendCallback GetSuspendCallback();
@@ -30,6 +31,7 @@
   void Suspend(SuspendCallback callback) override;
   void Resume() override;
   void UpdateScreenBrightnessSettings(double percent) override;
+  void PowerSupplyInfoChanged() override;
 
  private:
   mojom::PowerHostPtr host_ptr_;
@@ -47,6 +49,9 @@
   // Last value passed to UpdateScreenBrightnessSettings().
   double screen_brightness_ = 0.0;
 
+  // Number of calls to PowerSupplyInfoChanged().
+  int num_power_supply_info_ = 0;
+
   DISALLOW_COPY_AND_ASSIGN(FakePowerInstance);
 };
 
diff --git a/components/autofill/core/browser/autofill_manager_unittest.cc b/components/autofill/core/browser/autofill_manager_unittest.cc
index c6217b9..60a277e 100644
--- a/components/autofill/core/browser/autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -665,8 +665,9 @@
   }
 };
 
-class SuggestionMatchingTest : public AutofillManagerTest,
-                               public testing::WithParamInterface<bool> {
+class SuggestionMatchingTest
+    : public AutofillManagerTest,
+      public testing::WithParamInterface<std::tuple<bool, std::string>> {
  protected:
   void SetUp() override {
     AutofillManagerTest::SetUp();
@@ -680,26 +681,45 @@
 #endif  // defined(OS_ANDROID) || defined(OS_IOS)
 
   std::string MakeLabel(const std::vector<std::string>& parts);
+  std::string MakeMobileLabel(const std::vector<std::string>& parts);
 
-  enum class EnabledFeature { kNone, kDesktop, kMobile };
+  enum class EnabledFeature { kNone, kDesktop, kMobileShowAll, kMobileShowOne };
   EnabledFeature enabled_feature_;
   base::test::ScopedFeatureList features_;
 };
 
-// TODO(crbug.com/963630): Implement tests for mobile label experiment.
 #if defined(OS_ANDROID) || defined(OS_IOS)
 void SuggestionMatchingTest::InitializeFeatures() {
-  enabled_feature_ =
-      GetParam() ? EnabledFeature::kMobile : EnabledFeature::kNone;
-  features_.InitWithFeatureState(
-      features::kAutofillUseMobileLabelDisambiguation, false);
+  if (std::get<0>(GetParam())) {
+    std::string variant = std::get<1>(GetParam());
+
+    if (variant ==
+        features::kAutofillUseMobileLabelDisambiguationParameterShowAll) {
+      enabled_feature_ = EnabledFeature::kMobileShowAll;
+    } else if (variant ==
+               features::
+                   kAutofillUseMobileLabelDisambiguationParameterShowOne) {
+      enabled_feature_ = EnabledFeature::kMobileShowOne;
+    } else {
+      NOTREACHED();
+    }
+
+    std::map<std::string, std::string> parameters;
+    parameters[features::kAutofillUseMobileLabelDisambiguationParameterName] =
+        variant;
+    features_.InitAndEnableFeatureWithParameters(
+        features::kAutofillUseMobileLabelDisambiguation, parameters);
+  } else {
+    enabled_feature_ = EnabledFeature::kNone;
+  }
 }
 #else
 void SuggestionMatchingTest::InitializeFeatures() {
-  enabled_feature_ =
-      GetParam() ? EnabledFeature::kDesktop : EnabledFeature::kNone;
+  enabled_feature_ = std::get<0>(GetParam()) ? EnabledFeature::kDesktop
+                                             : EnabledFeature::kNone;
   features_.InitWithFeatureState(
-      features::kAutofillUseImprovedLabelDisambiguation, GetParam());
+      features::kAutofillUseImprovedLabelDisambiguation,
+      std::get<0>(GetParam()));
 }
 #endif  // defined(OS_ANDROID) || defined(OS_IOS)
 
@@ -709,6 +729,12 @@
       parts, l10n_util::GetStringUTF8(IDS_AUTOFILL_SUGGESTION_LABEL_SEPARATOR));
 }
 
+std::string SuggestionMatchingTest::MakeMobileLabel(
+    const std::vector<std::string>& parts) {
+  return base::JoinString(
+      parts, l10n_util::GetStringUTF8(IDS_AUTOFILL_ADDRESS_SUMMARY_SEPARATOR));
+}
+
 class CreditCardSuggestionMatchingTest
     : public AutofillManagerTest,
       public testing::WithParamInterface<bool> {
@@ -1047,15 +1073,24 @@
   std::string label2;
 
   switch (enabled_feature_) {
+      // 23456789012 is not formatted because it is invalid for the app locale.
+      // It has an extra digit.
     case EnabledFeature::kDesktop:
       label1 = MakeLabel(
           {"123 Apple St., unit 6", "23456789012", "buddy@gmail.com"});
       label2 = MakeLabel({"3734 Elvis Presley Blvd., Apt. 10", "(234) 567-8901",
                           "theking@gmail.com"});
       break;
-    case EnabledFeature::kMobile:
-      // TODO(crbug.com/963630)
-      return;
+    case EnabledFeature::kMobileShowAll:
+      label1 = MakeMobileLabel(
+          {"123 Apple St., unit 6", "23456789012", "buddy@gmail.com"});
+      label2 = MakeMobileLabel({"3734 Elvis Presley Blvd., Apt. 10",
+                                "(234) 567-8901", "theking@gmail.com"});
+      break;
+    case EnabledFeature::kMobileShowOne:
+      label1 = "123 Apple St., unit 6";
+      label2 = "3734 Elvis Presley Blvd., Apt. 10";
+      break;
     case EnabledFeature::kNone:
       label1 = "123 Apple St.";
       label2 = "3734 Elvis Presley Blvd.";
@@ -1082,11 +1117,10 @@
 
   switch (enabled_feature_) {
     case EnabledFeature::kDesktop:
+    case EnabledFeature::kMobileShowAll:
+    case EnabledFeature::kMobileShowOne:
       label = "3734 Elvis Presley Blvd., Apt. 10";
       break;
-    case EnabledFeature::kMobile:
-      // TODO(crbug.com/963630)
-      return;
     case EnabledFeature::kNone:
       label = "3734 Elvis Presley Blvd.";
   }
@@ -1140,13 +1174,12 @@
 
   switch (enabled_feature_) {
     case EnabledFeature::kDesktop:
+    case EnabledFeature::kMobileShowAll:
+    case EnabledFeature::kMobileShowOne:
       CheckSuggestions(kDefaultPageID,
                        Suggestion("Googler", "1600 Amphitheater pkwy", "", 1),
                        Suggestion("Grimes", "1234 Smith Blvd.", "", 2));
       break;
-    case EnabledFeature::kMobile:
-      // TODO(crbug.com/963630)
-      return;
     case EnabledFeature::kNone:
       // Test that we sent the right values to the external delegate. No labels
       // with duplicate values "Grimes" merged.
@@ -1180,11 +1213,10 @@
 
   switch (enabled_feature_) {
     case EnabledFeature::kDesktop:
+    case EnabledFeature::kMobileShowAll:
+    case EnabledFeature::kMobileShowOne:
       label = "3734 Elvis Presley Blvd., Apt. 10";
       break;
-    case EnabledFeature::kMobile:
-      // TODO(crbug.com/963630)
-      return;
     case EnabledFeature::kNone:
       label = "3734 Elvis Presley Blvd.";
   }
@@ -1237,15 +1269,24 @@
   std::string label2;
 
   switch (enabled_feature_) {
+      // 23456789012 is not formatted because it is invalid for the app locale.
+      // It has an extra digit.
     case EnabledFeature::kDesktop:
       label1 = MakeLabel(
           {"123 Apple St., unit 6", "23456789012", "buddy@gmail.com"});
       label2 = MakeLabel({"3734 Elvis Presley Blvd., Apt. 10", "(234) 567-8901",
                           "theking@gmail.com"});
       break;
-    case EnabledFeature::kMobile:
-      // TODO(crbug.com/963630)
-      return;
+    case EnabledFeature::kMobileShowAll:
+      label1 = MakeMobileLabel(
+          {"123 Apple St., unit 6", "23456789012", "buddy@gmail.com"});
+      label2 = MakeMobileLabel({"3734 Elvis Presley Blvd., Apt. 10",
+                                "(234) 567-8901", "theking@gmail.com"});
+      break;
+    case EnabledFeature::kMobileShowOne:
+      label1 = "123 Apple St., unit 6";
+      label2 = "3734 Elvis Presley Blvd., Apt. 10";
+      break;
     case EnabledFeature::kNone:
       label1 = "123 Apple St.";
       label2 = "3734 Elvis Presley Blvd.";
@@ -1729,16 +1770,23 @@
 
   switch (enabled_feature_) {
     case EnabledFeature::kDesktop:
-      // The first phone number is not formatted because it is invalid for the
-      // app locale.
+      // 23456789012 is not formatted because it is invalid for the app locale.
+      // It has an extra digit.
       label1 = MakeLabel(
           {"123 Apple St., unit 6", "23456789012", "buddy@gmail.com"});
       label2 = MakeLabel({"3734 Elvis Presley Blvd., Apt. 10", "(234) 567-8901",
                           "theking@gmail.com"});
       break;
-    case EnabledFeature::kMobile:
-      // TODO(crbug.com/963630)
-      return;
+    case EnabledFeature::kMobileShowAll:
+      label1 = MakeMobileLabel(
+          {"123 Apple St., unit 6", "23456789012", "buddy@gmail.com"});
+      label2 = MakeMobileLabel({"3734 Elvis Presley Blvd., Apt. 10",
+                                "(234) 567-8901", "theking@gmail.com"});
+      break;
+    case EnabledFeature::kMobileShowOne:
+      label1 = "123 Apple St., unit 6";
+      label2 = "3734 Elvis Presley Blvd., Apt. 10";
+      break;
     case EnabledFeature::kNone:
       label1 = "123 Apple St.";
       label2 = "3734 Elvis Presley Blvd.";
@@ -1775,7 +1823,7 @@
 // only return address suggestions. Instead of credit card suggestions, we
 // should return a warning explaining that credit card profile suggestions are
 // unavailable when the form is not https.
-TEST_P(SuggestionMatchingTest, GetAddressAndCreditCardSuggestionsNonHttps) {
+TEST_F(AutofillManagerTest, GetAddressAndCreditCardSuggestionsNonHttps) {
   // Set up our form data.
   FormData form;
   test::CreateTestAddressFormData(&form);
@@ -1786,26 +1834,8 @@
   FormFieldData field = form.fields[0];
   GetAutofillSuggestions(form, field);
 
-  std::string label1;
-  std::string label2;
-
-  switch (enabled_feature_) {
-    case EnabledFeature::kDesktop:
-      label1 = MakeLabel(
-          {"123 Apple St., unit 6", "23456789012", "buddy@gmail.com"});
-      label2 = MakeLabel({"3734 Elvis Presley Blvd., Apt. 10", "(234) 567-8901",
-                          "theking@gmail.com"});
-      break;
-    case EnabledFeature::kMobile:
-      // TODO(crbug.com/963630)
-      return;
-    case EnabledFeature::kNone:
-      label1 = "123 Apple St.";
-      label2 = "3734 Elvis Presley Blvd.";
-  }
-  // Test that we sent the right values to the external delegate.
-  CheckSuggestions(kDefaultPageID, Suggestion("Charles", label1, "", 1),
-                   Suggestion("Elvis", label2, "", 2));
+  // Verify that suggestions are returned.
+  EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
 
   test::CreateTestFormField("Card Number", "cardnumber", "", "text", &field);
   const int kPageID2 = 2;
@@ -1823,7 +1853,7 @@
   external_delegate_->CheckNoSuggestions(kDefaultPageID);
 }
 
-TEST_P(SuggestionMatchingTest,
+TEST_F(AutofillManagerTest,
        ShouldShowAddressSuggestionsIfCreditCardAutofillDisabled) {
   base::test::ScopedFeatureList features;
   features.InitAndEnableFeature(
@@ -1834,30 +1864,11 @@
   test::CreateTestAddressFormData(&form);
   std::vector<FormData> forms(1, form);
   FormsSeen(forms);
-
   FormFieldData field = form.fields[0];
+
   GetAutofillSuggestions(form, field);
-
-  std::string label1;
-  std::string label2;
-
-  switch (enabled_feature_) {
-    case EnabledFeature::kDesktop:
-      label1 = MakeLabel(
-          {"123 Apple St., unit 6", "23456789012", "buddy@gmail.com"});
-      label2 = MakeLabel({"3734 Elvis Presley Blvd., Apt. 10", "(234) 567-8901",
-                          "theking@gmail.com"});
-      break;
-    case EnabledFeature::kMobile:
-      // TODO(crbug.com/963630)
-      return;
-    case EnabledFeature::kNone:
-      label1 = "123 Apple St.";
-      label2 = "3734 Elvis Presley Blvd.";
-  }
-  // Test that we sent the right values to the external delegate.
-  CheckSuggestions(kDefaultPageID, Suggestion("Charles", label1, "", 1),
-                   Suggestion("Elvis", label2, "", 2));
+  // Verify that suggestions are returned.
+  EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
 }
 
 TEST_F(AutofillManagerTest,
@@ -1897,7 +1908,7 @@
                                      1);
 }
 
-// Test that we return normal autofill suggestions when trying to autofill
+// Test that we return normal Autofill suggestions when trying to autofill
 // already filled forms.
 TEST_P(SuggestionMatchingTest, GetFieldSuggestionsWhenFormIsAutofilled) {
   // Set up our form data.
@@ -1915,17 +1926,24 @@
   std::string label2;
 
   switch (enabled_feature_) {
+      // 23456789012 is not formatted because it is invalid for the app locale.
+      // It has an extra digit.
     case EnabledFeature::kDesktop:
-      // The below phone number is not formatted because it is not valid for the
-      // app locale. It has an extra digit.
       label1 = MakeLabel(
           {"123 Apple St., unit 6", "23456789012", "buddy@gmail.com"});
       label2 = MakeLabel({"3734 Elvis Presley Blvd., Apt. 10", "(234) 567-8901",
                           "theking@gmail.com"});
       break;
-    case EnabledFeature::kMobile:
-      // TODO(crbug.com/963630)
-      return;
+    case EnabledFeature::kMobileShowAll:
+      label1 = MakeMobileLabel(
+          {"123 Apple St., unit 6", "23456789012", "buddy@gmail.com"});
+      label2 = MakeMobileLabel({"3734 Elvis Presley Blvd., Apt. 10",
+                                "(234) 567-8901", "theking@gmail.com"});
+      break;
+    case EnabledFeature::kMobileShowOne:
+      label1 = "123 Apple St., unit 6";
+      label2 = "3734 Elvis Presley Blvd., Apt. 10";
+      break;
     case EnabledFeature::kNone:
       label1 = "123 Apple St.";
       label2 = "3734 Elvis Presley Blvd.";
@@ -1986,11 +2004,10 @@
 
   switch (enabled_feature_) {
     case EnabledFeature::kDesktop:
+    case EnabledFeature::kMobileShowAll:
+    case EnabledFeature::kMobileShowOne:
       label = "3734 Elvis Presley Blvd., Apt. 10";
       break;
-    case EnabledFeature::kMobile:
-      // TODO(crbug.com/963630)
-      return;
     case EnabledFeature::kNone:
       label = "3734 Elvis Presley Blvd.";
   }
@@ -2022,10 +2039,10 @@
   std::string label3;
 
   switch (enabled_feature_) {
+      // 23456789012 is not formatted because it is invalid for the app locale.
+      // It has an extra digit.
     case EnabledFeature::kDesktop:
       value1 = "(800) 772-4743";
-      // The below phone number is not formatted because it is not valid for the
-      // app locale. It has an extra digit.
       value2 = "23456789012";
       value3 = "(234) 567-8901";
       label1 = "Natty Bumppo";
@@ -2034,9 +2051,24 @@
       label3 = MakeLabel({"Elvis Presley", "3734 Elvis Presley Blvd., Apt. 10",
                           "theking@gmail.com"});
       break;
-    case EnabledFeature::kMobile:
-      // TODO(crbug.com/963630)
-      return;
+    case EnabledFeature::kMobileShowAll:
+      value1 = "(800) 772-4743";
+      value2 = "23456789012";
+      value3 = "(234) 567-8901";
+      label1 = "Natty";
+      label2 = MakeMobileLabel(
+          {"Charles", "123 Apple St., unit 6", "buddy@gmail.com"});
+      label3 = MakeMobileLabel(
+          {"Elvis", "3734 Elvis Presley Blvd., Apt. 10", "theking@gmail.com"});
+      break;
+    case EnabledFeature::kMobileShowOne:
+      value1 = "(800) 772-4743";
+      value2 = "23456789012";
+      value3 = "(234) 567-8901";
+      label1 = "";
+      label2 = "123 Apple St., unit 6";
+      label3 = "3734 Elvis Presley Blvd., Apt. 10";
+      break;
     case EnabledFeature::kNone:
       value1 = "18007724743";  // 1800PRAIRIE
       value2 = "23456789012";
@@ -4209,42 +4241,22 @@
 
 // Test that we do not query for Autocomplete suggestions when there are
 // Autofill suggestions available.
-TEST_P(SuggestionMatchingTest,
-       AutocompleteSuggestions_NoneWhenAutofillPresent) {
+TEST_F(AutofillManagerTest, AutocompleteSuggestions_NoneWhenAutofillPresent) {
   // Set up our form data.
   FormData form;
   test::CreateTestAddressFormData(&form);
   std::vector<FormData> forms(1, form);
   FormsSeen(forms);
-
   const FormFieldData& field = form.fields[0];
 
-  // Autocomplete manager is not called for suggestions.
+  // AutocompleteManager is not called for suggestions.
   EXPECT_CALL(*(autocomplete_history_manager_.get()),
               OnGetAutocompleteSuggestions)
       .Times(0);
 
   GetAutofillSuggestions(form, field);
-
-  if (enabled_feature_ == EnabledFeature::kDesktop) {
-    CheckSuggestions(
-        kDefaultPageID,
-        Suggestion("Charles",
-                   MakeLabel({"123 Apple St., unit 6", "23456789012",
-                              "buddy@gmail.com"}),
-                   "", 1),
-        Suggestion("Elvis",
-                   MakeLabel({"3734 Elvis Presley Blvd., Apt. 10",
-                              "(234) 567-8901", "theking@gmail.com"}),
-                   "", 2));
-  } else {
-    // Test that we sent the right values to the external delegate. Inferred
-    // labels include full first relevant field, which in this case is the
-    // address line 1.
-    CheckSuggestions(kDefaultPageID,
-                     Suggestion("Charles", "123 Apple St.", "", 1),
-                     Suggestion("Elvis", "3734 Elvis Presley Blvd.", "", 2));
-  }
+  // Verify that suggestions are returned.
+  EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
 }
 
 // Test that we query for Autocomplete suggestions when there are no Autofill
@@ -4925,8 +4937,8 @@
     {"TN", ADDRESS_HOME_STATE},     // Saved as "Tennessee" in profile.
     {"Texas", ADDRESS_HOME_STATE},  // Saved as "TX" in profile.
 
-    // Special phone number case. A profile with no country code should only
-    // match PHONE_HOME_CITY_AND_NUMBER.
+    // Special phone number case. A profile with no country code should
+    // only match PHONE_HOME_CITY_AND_NUMBER.
     {"5142821292", PHONE_HOME_CITY_AND_NUMBER},
 
     // Make sure unsupported variants do not match.
@@ -4939,8 +4951,8 @@
     {"901", UNKNOWN_TYPE},
 };
 
-// Tests that DeterminePossibleFieldTypesForUpload finds accurate possible types
-// and validities.
+// Tests that DeterminePossibleFieldTypesForUpload finds accurate possible
+// types and validities.
 TEST_P(ProfileMatchingTypesTest, DeterminePossibleFieldTypesForUpload) {
   // Unpack the test paramters
   const auto& test_case = std::get<0>(GetParam());
@@ -4986,8 +4998,8 @@
         // An UNKNOWN type is always UNVALIDATED
         validity_state = AutofillDataModel::UNVALIDATED;
       } else if (profile.IsAnInvalidPhoneNumber(test_case.field_type)) {
-        // a phone field is a compound field, an invalid part would make it
-        // invalid.
+        // A phone field is a compound field, and an invalid part makes
+        // the phone number invalid.
         validity_state = AutofillDataModel::INVALID;
       }
       profile.SetValidityState(test_case.field_type, validity_state,
@@ -5836,15 +5848,27 @@
   std::string label2;
 
   switch (enabled_feature_) {
+      // 23456789012 is not formatted because it is invalid for the app locale.
+      // It has an extra digit.
     case EnabledFeature::kDesktop:
       label1 =
           MakeLabel({"Charles Holley", "123 Apple St., unit 6", "23456789012"});
       label2 = MakeLabel({"Elvis Presley", "3734 Elvis Presley Blvd., Apt. 10",
                           "(234) 567-8901"});
       break;
-    case EnabledFeature::kMobile:
-      // TODO(crbug.com/963630)
-      return;
+    case EnabledFeature::kMobileShowAll:
+      // 23456789012 is not formatted because it is invalid for the app locale.
+      // It
+      // has an extra digit.
+      label1 =
+          MakeMobileLabel({"Charles", "123 Apple St., unit 6", "23456789012"});
+      label2 = MakeMobileLabel(
+          {"Elvis", "3734 Elvis Presley Blvd., Apt. 10", "(234) 567-8901"});
+      break;
+    case EnabledFeature::kMobileShowOne:
+      label1 = "123 Apple St., unit 6";
+      label2 = "3734 Elvis Presley Blvd., Apt. 10";
+      break;
     case EnabledFeature::kNone:
       label1 = "123 Apple St.";
       label2 = "3734 Elvis Presley Blvd.";
@@ -5871,23 +5895,24 @@
   test::CreateTestFormField("Address Line 2", "addr2", "apple", "text", &field);
   GetAutofillSuggestions(form, field);
 
-  std::string value;
   std::string label;
 
   switch (enabled_feature_) {
     case EnabledFeature::kDesktop:
-      value = "123 Apple St., unit 6";
       label = "Charles Holley";
       break;
-    case EnabledFeature::kMobile:
-      // TODO(crbug.com/963630)
-      return;
+    case EnabledFeature::kMobileShowAll:
+    case EnabledFeature::kMobileShowOne:
+      // 23456789012 is not formatted because it is invalid for the app locale.
+      // It has an extra digit.
+      label = "23456789012";
+      break;
     case EnabledFeature::kNone:
-      value = "123 Apple St., unit 6";
       label = "123 Apple St.";
   }
   // Test that we sent the right values to the external delegate.
-  CheckSuggestions(kDefaultPageID, Suggestion(value, label, "", 1));
+  CheckSuggestions(kDefaultPageID,
+                   Suggestion("123 Apple St., unit 6", label, "", 1));
 }
 
 // Verify that typing "mail" will not match any of the "@gmail.com" email
@@ -6197,18 +6222,22 @@
   test::CreateTestFormField("Middle Name", "middlename", "S", "text", &field);
   GetAutofillSuggestions(form, field);
 
-  if (enabled_feature_ == EnabledFeature::kDesktop) {
-    CheckSuggestions(kDefaultPageID,
-                     Suggestion("Shawn Smith", "1234 Smith Blvd.", "", 1),
-                     Suggestion("Adam Smith", "1234 Smith Blvd.", "", 2));
-  } else {
-    CheckSuggestions(
-        kDefaultPageID,
-        Suggestion("Shawn Smith", "1234 Smith Blvd., Carl Shawn Smith Grimes",
-                   "", 1),
-        Suggestion("Adam Smith", "1234 Smith Blvd., Robin Adam Smith Grimes",
-                   "", 2));
+  std::string label1;
+  std::string label2;
+
+  switch (enabled_feature_) {
+    case EnabledFeature::kDesktop:
+    case EnabledFeature::kMobileShowAll:
+    case EnabledFeature::kMobileShowOne:
+      label1 = "1234 Smith Blvd.";
+      label2 = "1234 Smith Blvd.";
+      break;
+    case EnabledFeature::kNone:
+      label1 = "1234 Smith Blvd., Carl Shawn Smith Grimes";
+      label2 = "1234 Smith Blvd., Robin Adam Smith Grimes";
   }
+  CheckSuggestions(kDefaultPageID, Suggestion("Shawn Smith", label1, "", 1),
+                   Suggestion("Adam Smith", label2, "", 2));
 }
 
 TEST_F(AutofillManagerTest, ShouldUploadForm) {
@@ -7478,7 +7507,18 @@
 
 INSTANTIATE_TEST_SUITE_P(All, OnFocusOnFormFieldTest, testing::Bool());
 
-INSTANTIATE_TEST_SUITE_P(, SuggestionMatchingTest, testing::Bool());
+#if defined(OS_IOS) || defined(OS_ANDROID)
+INSTANTIATE_TEST_SUITE_P(,
+                         SuggestionMatchingTest,
+                         testing::Values(std::make_tuple(0, ""),
+                                         std::make_tuple(1, "show-all"),
+                                         std::make_tuple(1, "show-one")));
+#else
+INSTANTIATE_TEST_SUITE_P(,
+                         SuggestionMatchingTest,
+                         testing::Values(std::make_tuple(0, ""),
+                                         std::make_tuple(1, "")));
+#endif  // defined(OS_IOS) || defined(OS_ANDROID)
 
 INSTANTIATE_TEST_SUITE_P(, CreditCardSuggestionMatchingTest, testing::Bool());
 
diff --git a/components/autofill_assistant/browser/BUILD.gn b/components/autofill_assistant/browser/BUILD.gn
index a3d1133..f8856d5 100644
--- a/components/autofill_assistant/browser/BUILD.gn
+++ b/components/autofill_assistant/browser/BUILD.gn
@@ -96,6 +96,8 @@
     "controller.h",
     "details.cc",
     "details.h",
+    "direct_action.cc",
+    "direct_action.h",
     "element_area.cc",
     "element_area.h",
     "element_precondition.cc",
@@ -192,6 +194,7 @@
     "script_tracker_unittest.cc",
     "selector_unittest.cc",
     "string_conversions_util_unittest.cc",
+    "trigger_context_unittest.cc",
   ]
 
   deps = [
diff --git a/components/autofill_assistant/browser/actions/prompt_action.cc b/components/autofill_assistant/browser/actions/prompt_action.cc
index 36544dd5..e48091c 100644
--- a/components/autofill_assistant/browser/actions/prompt_action.cc
+++ b/components/autofill_assistant/browser/actions/prompt_action.cc
@@ -113,9 +113,9 @@
     if (!precondition_results_[i] && !choice_proto.allow_disabling())
       continue;
 
-    user_action.enabled = precondition_results_[i];
-    user_action.callback = base::BindOnce(&PromptAction::OnSuggestionChosen,
-                                          weak_ptr_factory_.GetWeakPtr(), i);
+    user_action.SetEnabled(precondition_results_[i]);
+    user_action.SetCallback(base::BindOnce(&PromptAction::OnSuggestionChosen,
+                                           weak_ptr_factory_.GetWeakPtr(), i));
     user_actions->emplace_back(std::move(user_action));
   }
   delegate_->Prompt(std::move(user_actions));
diff --git a/components/autofill_assistant/browser/actions/prompt_action_unittest.cc b/components/autofill_assistant/browser/actions/prompt_action_unittest.cc
index bbfb42b..a4761f51 100644
--- a/components/autofill_assistant/browser/actions/prompt_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/prompt_action_unittest.cc
@@ -91,11 +91,11 @@
 
   ASSERT_THAT(user_actions_, Pointee(SizeIs(2)));
 
-  EXPECT_EQ("Ok", (*user_actions_)[0].chip.text);
-  EXPECT_EQ(HIGHLIGHTED_ACTION, (*user_actions_)[0].chip.type);
+  EXPECT_EQ("Ok", (*user_actions_)[0].chip().text);
+  EXPECT_EQ(HIGHLIGHTED_ACTION, (*user_actions_)[0].chip().type);
 
-  EXPECT_EQ("Cancel", (*user_actions_)[1].chip.text);
-  EXPECT_EQ(NORMAL_ACTION, (*user_actions_)[1].chip.type);
+  EXPECT_EQ("Cancel", (*user_actions_)[1].chip().text);
+  EXPECT_EQ(NORMAL_ACTION, (*user_actions_)[1].chip().type);
 
   EXPECT_CALL(
       callback_,
@@ -103,8 +103,8 @@
           Property(&ProcessedActionProto::status, ACTION_APPLIED),
           Property(&ProcessedActionProto::prompt_choice,
                    Property(&PromptProto::Choice::server_payload, "ok"))))));
-  DCHECK((*user_actions_)[0].callback);
-  std::move((*user_actions_)[0].callback).Run();
+  EXPECT_TRUE((*user_actions_)[0].HasCallback());
+  (*user_actions_)[0].Call(TriggerContext::CreateEmpty());
 }
 
 TEST_F(PromptActionTest, ReportDirectAction) {
@@ -125,11 +125,11 @@
 
   ASSERT_THAT(user_actions_, Pointee(SizeIs(2)));
 
-  EXPECT_THAT((*user_actions_)[0].direct_action_names, ElementsAre("ok"));
-  EXPECT_FALSE((*user_actions_)[0].chip.empty());
-  EXPECT_THAT((*user_actions_)[1].direct_action_names,
+  EXPECT_THAT((*user_actions_)[0].direct_action().names, ElementsAre("ok"));
+  EXPECT_FALSE((*user_actions_)[0].chip().empty());
+  EXPECT_THAT((*user_actions_)[1].direct_action().names,
               ElementsAre("maybe", "I_guess"));
-  EXPECT_TRUE((*user_actions_)[1].chip.empty());
+  EXPECT_TRUE((*user_actions_)[1].chip().empty());
 }
 
 TEST_F(PromptActionTest, ShowOnlyIfElementExists) {
@@ -173,14 +173,15 @@
       .WillRepeatedly(RunOnceCallback<1>(true));
   task_env_.FastForwardBy(base::TimeDelta::FromSeconds(1));
   ASSERT_THAT(user_actions_, Pointee(SizeIs(1)));
-  EXPECT_TRUE((*user_actions_)[0].enabled);
+  EXPECT_TRUE((*user_actions_)[0].enabled());
 
   EXPECT_CALL(mock_web_controller_,
               OnElementCheck(Eq(Selector({"element"})), _))
       .WillRepeatedly(RunOnceCallback<1>(false));
   task_env_.FastForwardBy(base::TimeDelta::FromSeconds(1));
   ASSERT_THAT(user_actions_, Pointee(SizeIs(1)));
-  EXPECT_FALSE((*user_actions_)[0].enabled);
+  EXPECT_FALSE((*user_actions_)[0].enabled());
+  EXPECT_TRUE((*user_actions_)[0].HasCallback());
 }
 
 TEST_F(PromptActionTest, AutoSelect) {
@@ -247,7 +248,8 @@
 
   // Chips pointing to a deleted action do nothing.
   ASSERT_THAT(user_actions_, Pointee(SizeIs(1)));
-  std::move((*user_actions_)[0].callback).Run();
+  EXPECT_TRUE((*user_actions_)[0].HasCallback());
+  (*user_actions_)[0].Call(TriggerContext::CreateEmpty());
 }
 
 }  // namespace
diff --git a/components/autofill_assistant/browser/actions/show_form_action.cc b/components/autofill_assistant/browser/actions/show_form_action.cc
index 4a3402a..6b1f85e 100644
--- a/components/autofill_assistant/browser/actions/show_form_action.cc
+++ b/components/autofill_assistant/browser/actions/show_form_action.cc
@@ -45,14 +45,14 @@
   // Show "Continue" chip.
   UserAction user_action =
       UserAction(proto_.show_form().chip(), proto_.show_form().direct_action());
-  if (user_action.chip.empty()) {
-    user_action.chip.text =
+  if (user_action.chip().empty()) {
+    user_action.chip().text =
         l10n_util::GetStringUTF8(IDS_AUTOFILL_ASSISTANT_PAYMENT_INFO_CONFIRM);
-    user_action.chip.type = HIGHLIGHTED_ACTION;
+    user_action.chip().type = HIGHLIGHTED_ACTION;
   }
-  user_action.enabled = IsFormValid(proto_.show_form().form(), *form_result);
-  user_action.callback = base::BindOnce(&ShowFormAction::OnButtonClicked,
-                                        weak_ptr_factory_.GetWeakPtr());
+  user_action.SetEnabled(IsFormValid(proto_.show_form().form(), *form_result));
+  user_action.SetCallback(base::BindOnce(&ShowFormAction::OnButtonClicked,
+                                         weak_ptr_factory_.GetWeakPtr()));
 
   auto user_actions = std::make_unique<std::vector<UserAction>>();
   user_actions->emplace_back(std::move(user_action));
diff --git a/components/autofill_assistant/browser/actions/show_form_action.h b/components/autofill_assistant/browser/actions/show_form_action.h
index f6cadb9..34bfb01 100644
--- a/components/autofill_assistant/browser/actions/show_form_action.h
+++ b/components/autofill_assistant/browser/actions/show_form_action.h
@@ -13,6 +13,7 @@
 #include "components/autofill_assistant/browser/actions/action.h"
 
 namespace autofill_assistant {
+
 // An action to show a form than can be filled by the user.
 class ShowFormAction : public Action {
  public:
diff --git a/components/autofill_assistant/browser/chip.cc b/components/autofill_assistant/browser/chip.cc
index d6ba436d..903ee34 100644
--- a/components/autofill_assistant/browser/chip.cc
+++ b/components/autofill_assistant/browser/chip.cc
@@ -22,10 +22,10 @@
 void SetDefaultChipType(std::vector<UserAction>* user_actions) {
   ChipType default_type = SUGGESTION;
   for (const UserAction& user_action : *user_actions) {
-    if (user_action.chip.empty())
+    if (user_action.chip().empty())
       continue;
 
-    ChipType type = user_action.chip.type;
+    ChipType type = user_action.chip().type;
     if (type != UNKNOWN_CHIP_TYPE && type != SUGGESTION) {
       // If there's an action chip, assume chips with unknown type are also
       // actions.
@@ -34,11 +34,11 @@
     }
   }
   for (UserAction& user_action : *user_actions) {
-    if (user_action.chip.empty())
+    if (user_action.chip().empty())
       continue;
 
-    if (user_action.chip.type == UNKNOWN_CHIP_TYPE) {
-      user_action.chip.type = default_type;
+    if (user_action.chip().type == UNKNOWN_CHIP_TYPE) {
+      user_action.chip().type = default_type;
     }
   }
 }
diff --git a/components/autofill_assistant/browser/chip.h b/components/autofill_assistant/browser/chip.h
index 4d669aa7..650935d 100644
--- a/components/autofill_assistant/browser/chip.h
+++ b/components/autofill_assistant/browser/chip.h
@@ -12,7 +12,7 @@
 #include "components/autofill_assistant/browser/service.pb.h"
 
 namespace autofill_assistant {
-struct UserAction;  // For SetDefaultChipType
+class UserAction;  // For SetDefaultChipType
 
 // A structure to represent a Chip shown in the carousel.
 //
diff --git a/components/autofill_assistant/browser/controller.cc b/components/autofill_assistant/browser/controller.cc
index 75bbc3e..361ae15 100644
--- a/components/autofill_assistant/browser/controller.cc
+++ b/components/autofill_assistant/browser/controller.cc
@@ -17,6 +17,7 @@
 #include "components/autofill_assistant/browser/features.h"
 #include "components/autofill_assistant/browser/metrics.h"
 #include "components/autofill_assistant/browser/protocol_utils.h"
+#include "components/autofill_assistant/browser/trigger_context.h"
 #include "components/autofill_assistant/browser/ui_controller.h"
 #include "components/strings/grit/components_strings.h"
 #include "content/public/browser/browser_task_traits.h"
@@ -35,19 +36,9 @@
 // message.
 static constexpr int kAutostartInitialProgress = 5;
 
-// Cookie experiment name.
-// TODO(crbug.com/806868): Introduce a dedicated experiment extra parameter to
-// pass allow passing more than one experiment.
-static const char* const kCookieExperimentName = "EXP_COOKIE";
-// Website visited before parameter.
-// Note: This parameter goes with the previous experiment name. I.e. it is only
-// set when the cookie experiment is active.
-static const char* const kWebsiteVisitedBeforeParameterName =
-    "WEBSITE_VISITED_BEFORE";
 // Parameter that allows setting the color of the overlay.
 static const char* const kOverlayColorParameterName = "OVERLAY_COLORS";
 
-static const char* const kTrueValue = "true";
 }  // namespace
 
 Controller::Controller(content::WebContents* web_contents,
@@ -234,21 +225,23 @@
     listeners_.erase(found);
 }
 
-bool Controller::PerformUserAction(int index) {
+bool Controller::PerformUserActionWithContext(
+    int index,
+    std::unique_ptr<TriggerContext> context) {
   if (!user_actions_ || index < 0 ||
       static_cast<size_t>(index) >= user_actions_->size()) {
     NOTREACHED() << "Invalid user action index: " << index;
     return false;
   }
 
-  UserAction* user_action = &(*user_actions_)[index];
-  if (!user_action->enabled || !user_action->callback) {
+  if (!(*user_actions_)[index].enabled()) {
+    NOTREACHED() << "Action at index " << index << " is disabled.";
     return false;
   }
 
-  auto callback = std::move(user_action->callback);
+  UserAction user_action = std::move((*user_actions_)[index]);
   SetUserActions(nullptr);
-  std::move(callback).Run();
+  user_action.Call(std::move(context));
   return true;
 }
 
@@ -445,7 +438,7 @@
     script_domain_ = url.host();
     DVLOG(2) << "GetScripts for " << script_domain_;
     GetService()->GetScriptsForUrl(
-        url, trigger_context_.get(),
+        url, *trigger_context_,
         base::BindOnce(&Controller::OnGetScripts, base::Unretained(this), url));
   } else {
     script_tracker()->CheckScripts();
@@ -488,7 +481,7 @@
     std::string script_path = autostart_timeout_script_path_;
     autostart_timeout_script_path_.clear();
     periodic_script_check_scheduled_ = false;
-    ExecuteScript(script_path, state_);
+    ExecuteScript(script_path, TriggerContext::CreateEmpty(), state_);
     return;
   }
 
@@ -565,6 +558,7 @@
 }
 
 void Controller::ExecuteScript(const std::string& script_path,
+                               std::unique_ptr<TriggerContext> context,
                                AutofillAssistantState end_state) {
   DCHECK(!script_tracker()->running());
   EnterState(AutofillAssistantState::RUNNING);
@@ -579,7 +573,7 @@
   // TODO(crbug.com/806868): Consider making ClearRunnableScripts part of
   // ExecuteScripts to simplify the controller.
   script_tracker()->ExecuteScript(
-      script_path,
+      script_path, std::move(context),
       base::BindOnce(&Controller::OnScriptExecuted,
                      // script_tracker_ is owned by Controller.
                      base::Unretained(this), script_path, end_state));
@@ -605,7 +599,6 @@
       return;
 
     case ScriptExecutor::SHUTDOWN_GRACEFULLY:
-      GetWebController()->ClearCookie();
       EnterStoppedState();
       client_->Shutdown(Metrics::SCRIPT_SHUTDOWN);
       return;
@@ -650,7 +643,8 @@
   }
   if (autostart_count == 1) {
     DisableAutostart();
-    ExecuteScript(autostart_path, AutofillAssistantState::PROMPT);
+    ExecuteScript(autostart_path, TriggerContext::CreateEmpty(),
+                  AutofillAssistantState::PROMPT);
     return true;
   }
   return false;
@@ -661,49 +655,18 @@
   autostart_timeout_script_path_.clear();
 }
 
-void Controller::OnGetCookie(bool has_cookie) {
-  if (has_cookie) {
-    // This code is only active with the experiment parameter.
-    // TODO(crbug.com/806868): Remove the cookie experiment.
-    trigger_context_->script_parameters.insert(
-        std::make_pair(kWebsiteVisitedBeforeParameterName, kTrueValue));
-    OnSetCookie(has_cookie);
-    return;
-  }
-  GetWebController()->SetCookie(
-      deeplink_url_.host(),
-      base::BindOnce(&Controller::OnSetCookie,
-                     // WebController is owned by Controller.
-                     base::Unretained(this)));
-}
-
-void Controller::OnSetCookie(bool result) {
-  DCHECK(result) << "Setting cookie failed";
-  FinishStart();
-}
-
-void Controller::FinishStart() {
-  started_ = true;
-  if (allow_autostart_) {
-    SetStatusMessage(
-        l10n_util::GetStringFUTF8(IDS_AUTOFILL_ASSISTANT_LOADING,
-                                  base::UTF8ToUTF16(deeplink_url_.host())));
-    SetProgress(kAutostartInitialProgress);
-  }
-  GetOrCheckScripts();
-}
-
 void Controller::InitFromParameters() {
   auto details = std::make_unique<Details>();
-  if (details->UpdateFromParameters(trigger_context_->script_parameters))
+  if (details->UpdateFromParameters(*trigger_context_))
     SetDetails(std::move(details));
 
-  const auto iter =
-      trigger_context_->script_parameters.find(kOverlayColorParameterName);
-  if (iter != trigger_context_->script_parameters.end()) {
+  const base::Optional<std::string> overlay_color =
+      trigger_context_->GetParameter(kOverlayColorParameterName);
+  if (overlay_color) {
     std::unique_ptr<OverlayColors> colors = std::make_unique<OverlayColors>();
-    std::vector<std::string> color_strings = base::SplitString(
-        iter->second, ":", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
+    std::vector<std::string> color_strings =
+        base::SplitString(overlay_color.value(), ":", base::KEEP_WHITESPACE,
+                          base::SPLIT_WANT_ALL);
     if (color_strings.size() > 0) {
       colors->background = color_strings[0];
     }
@@ -733,14 +696,14 @@
   deeplink_url_ = deeplink_url;
   EnterState(AutofillAssistantState::STARTING);
   client_->ShowUI();
-  if (IsCookieExperimentEnabled()) {
-    GetWebController()->HasCookie(
-        base::BindOnce(&Controller::OnGetCookie,
-                       // WebController is owned by Controller.
-                       base::Unretained(this)));
-  } else {
-    FinishStart();
+  started_ = true;
+  if (allow_autostart_) {
+    SetStatusMessage(
+        l10n_util::GetStringFUTF8(IDS_AUTOFILL_ASSISTANT_LOADING,
+                                  base::UTF8ToUTF16(deeplink_url_.host())));
+    SetProgress(kAutostartInitialProgress);
   }
+  GetOrCheckScripts();
 }
 
 AutofillAssistantState Controller::GetState() {
@@ -756,9 +719,11 @@
   }
 }
 
-void Controller::OnScriptSelected(const std::string& script_path) {
+void Controller::OnScriptSelected(const std::string& script_path,
+                                  std::unique_ptr<TriggerContext> context) {
   DCHECK(!script_path.empty());
-  ExecuteScript(script_path, AutofillAssistantState::PROMPT);
+  ExecuteScript(script_path, std::move(context),
+                AutofillAssistantState::PROMPT);
 }
 
 void Controller::UpdateTouchableArea() {
@@ -775,10 +740,13 @@
 
   dict.SetKey("status", base::Value(status_message_));
   if (trigger_context_) {
+    google::protobuf::RepeatedPtrField<ScriptParameterProto> parameters_proto;
+    trigger_context_->AddParameters(&parameters_proto);
     std::vector<base::Value> parameters_js;
-    for (const auto& entry : trigger_context_->script_parameters) {
+    for (const auto& parameter_proto : parameters_proto) {
       base::Value parameter_js = base::Value(base::Value::Type::DICTIONARY);
-      parameter_js.SetKey(entry.first, base::Value(entry.second));
+      parameter_js.SetKey(parameter_proto.name(),
+                          base::Value(parameter_proto.value()));
       parameters_js.push_back(std::move(parameter_js));
     }
     dict.SetKey("parameters", base::Value(parameters_js));
@@ -904,11 +872,11 @@
 
   UserAction confirm(payment_request_options_->confirm_chip,
                      payment_request_options_->confirm_direct_action);
-  confirm.enabled = confirm_button_enabled;
+  confirm.SetEnabled(confirm_button_enabled);
   if (confirm_button_enabled) {
-    confirm.callback =
+    confirm.SetCallback(
         base::BindOnce(&Controller::OnPaymentRequestContinueButtonClicked,
-                       weak_ptr_factory_.GetWeakPtr());
+                       weak_ptr_factory_.GetWeakPtr()));
   }
 
   auto user_actions = std::make_unique<std::vector<UserAction>>();
@@ -988,14 +956,14 @@
   auto user_actions = std::make_unique<std::vector<UserAction>>();
   for (const auto& script : runnable_scripts) {
     UserAction user_action;
-    user_action.chip = script.chip;
-    user_action.direct_action_names = script.direct_action_names;
+    user_action.chip() = script.chip;
+    user_action.direct_action() = script.direct_action;
     if (!user_action.has_triggers())
       continue;
 
-    user_action.callback =
-        base::BindOnce(&Controller::OnScriptSelected,
-                       weak_ptr_factory_.GetWeakPtr(), script.path);
+    user_action.SetCallback(base::BindOnce(&Controller::OnScriptSelected,
+                                           weak_ptr_factory_.GetWeakPtr(),
+                                           script.path));
     user_actions->emplace_back(std::move(user_action));
   }
 
@@ -1100,12 +1068,6 @@
   }
 }
 
-bool Controller::IsCookieExperimentEnabled() const {
-  auto iter = trigger_context_->script_parameters.find(kCookieExperimentName);
-  return iter != trigger_context_->script_parameters.end() &&
-         iter->second == "1";
-}
-
 void Controller::OnTouchableAreaChanged(
     const RectF& visual_viewport,
     const std::vector<RectF>& touchable_areas,
diff --git a/components/autofill_assistant/browser/controller.h b/components/autofill_assistant/browser/controller.h
index b59cf091..eb43b7b 100644
--- a/components/autofill_assistant/browser/controller.h
+++ b/components/autofill_assistant/browser/controller.h
@@ -101,7 +101,6 @@
   void RemoveListener(ScriptExecutorDelegate::Listener* listener) override;
 
   void EnterState(AutofillAssistantState state) override;
-  bool IsCookieExperimentEnabled() const;
   void SetPaymentRequestOptions(
       std::unique_ptr<PaymentRequestOptions> options) override;
 
@@ -114,7 +113,9 @@
   int GetProgress() const override;
   bool GetProgressVisible() const override;
   const std::vector<UserAction>& GetUserActions() const override;
-  bool PerformUserAction(int index) override;
+  bool PerformUserActionWithContext(
+      int index,
+      std::unique_ptr<TriggerContext> context) override;
   std::string GetDebugContext() override;
   const PaymentRequestOptions* GetPaymentRequestOptions() const override;
   const PaymentInformation* GetPaymentRequestInformation() const override;
@@ -155,6 +156,7 @@
   // Execute |script_path| and, if execution succeeds, enter |end_state| and
   // call |on_success|.
   void ExecuteScript(const std::string& script_path,
+                     std::unique_ptr<TriggerContext> context,
                      AutofillAssistantState end_state);
   void OnScriptExecuted(const std::string& script_path,
                         AutofillAssistantState end_state,
@@ -175,19 +177,11 @@
 
   void DisableAutostart();
 
-  // Autofill Assistant cookie logic.
-  //
-  // On startup of the controller we set a cookie. If a cookie already existed
-  // for the intial URL, we show a warning that the website has already been
-  // visited and could contain old data. The cookie is cleared (or expires) when
-  // a script terminated with a Stop action.
-  void OnGetCookie(bool has_cookie);
-  void OnSetCookie(bool result);
-  void FinishStart();
   void InitFromParameters();
 
   // Called when a script is selected.
-  void OnScriptSelected(const std::string& script_path);
+  void OnScriptSelected(const std::string& script_path,
+                        std::unique_ptr<TriggerContext> context);
 
   void UpdatePaymentRequestActions();
   void OnPaymentRequestContinueButtonClicked();
diff --git a/components/autofill_assistant/browser/controller_unittest.cc b/components/autofill_assistant/browser/controller_unittest.cc
index 2bce1c8c6..57c6bec 100644
--- a/components/autofill_assistant/browser/controller_unittest.cc
+++ b/components/autofill_assistant/browser/controller_unittest.cc
@@ -158,7 +158,7 @@
   void Start() { Start("http://initialurl.com"); }
 
   void Start(const std::string& url) {
-    controller_->Start(GURL(url), std::make_unique<TriggerContext>());
+    controller_->Start(GURL(url), TriggerContext::CreateEmpty());
   }
 
   void SetLastCommittedUrl(const GURL& url) {
@@ -261,11 +261,12 @@
             controller_->GetState());
   EXPECT_THAT(
       controller_->GetUserActions(),
-      UnorderedElementsAre(
-          Field(&UserAction::chip, AllOf(Field(&Chip::text, StrEq("script1")),
-                                         Field(&Chip::type, SUGGESTION))),
-          Field(&UserAction::chip, AllOf(Field(&Chip::text, StrEq("script2")),
-                                         Field(&Chip::type, SUGGESTION)))));
+      UnorderedElementsAre(Property(&UserAction::chip,
+                                    AllOf(Field(&Chip::text, StrEq("script1")),
+                                          Field(&Chip::type, SUGGESTION))),
+                           Property(&UserAction::chip,
+                                    AllOf(Field(&Chip::text, StrEq("script2")),
+                                          Field(&Chip::type, SUGGESTION)))));
 
   // Choose script2 and run it successfully.
   EXPECT_CALL(*mock_service_, OnGetActions(StrEq("script2"), _, _, _, _, _))
@@ -275,8 +276,8 @@
   // Offering the remaining choice: script1 as script2 can only run once.
   EXPECT_EQ(AutofillAssistantState::PROMPT, controller_->GetState());
   EXPECT_THAT(controller_->GetUserActions(),
-              ElementsAre(Field(&UserAction::chip,
-                                Field(&Chip::text, StrEq("script1")))));
+              ElementsAre(Property(&UserAction::chip,
+                                   Field(&Chip::text, StrEq("script1")))));
 }
 
 TEST_F(ControllerTest, ReportDirectActions) {
@@ -302,14 +303,65 @@
   // Offering the choices: script1 and script2
   EXPECT_EQ(AutofillAssistantState::AUTOSTART_FALLBACK_PROMPT,
             controller_->GetState());
+  EXPECT_THAT(
+      controller_->GetUserActions(),
+      UnorderedElementsAre(
+          AllOf(Property(&UserAction::chip, Field(&Chip::text, "script1")),
+                Property(&UserAction::direct_action,
+                         Field(&DirectAction::names, ElementsAre("action_1")))),
+          AllOf(
+              Property(&UserAction::chip, Property(&Chip::empty, true)),
+              Property(&UserAction::direct_action,
+                       Field(&DirectAction::names, ElementsAre("action_2"))))));
+}
+
+TEST_F(ControllerTest, RunDirectActionWithArguments) {
+  SupportsScriptResponseProto script_response;
+
+  // script is available as a chip and a direct action.
+  auto* script1 = AddRunnableScript(&script_response, "script");
+  auto* action = script1->mutable_presentation()->mutable_direct_action();
+  action->add_names("action");
+  action->add_required_arguments("required");
+  action->add_optional_arguments("arg0");
+  action->add_optional_arguments("arg1");
+
+  SetNextScriptResponse(script_response);
+
+  testing::InSequence seq;
+
+  Start("http://a.example.com/path");
+
+  EXPECT_EQ(AutofillAssistantState::AUTOSTART_FALLBACK_PROMPT,
+            controller_->GetState());
   EXPECT_THAT(controller_->GetUserActions(),
-              UnorderedElementsAre(
-                  AllOf(Field(&UserAction::chip, Field(&Chip::text, "script1")),
-                        Field(&UserAction::direct_action_names,
-                              ElementsAre("action_1"))),
-                  AllOf(Field(&UserAction::chip, Property(&Chip::empty, true)),
-                        Field(&UserAction::direct_action_names,
-                              ElementsAre("action_2")))));
+              ElementsAre(Property(
+                  &UserAction::direct_action,
+                  AllOf(Field(&DirectAction::names, ElementsAre("action")),
+                        Field(&DirectAction::required_arguments,
+                              ElementsAre("required")),
+                        Field(&DirectAction::optional_arguments,
+                              ElementsAre("arg0", "arg1"))))));
+
+  EXPECT_CALL(*mock_service_, OnGetActions("script", _, _, _, _, _))
+      .WillOnce(Invoke([](const std::string& script_path, const GURL& url,
+                          const TriggerContext& trigger_context,
+                          const std::string& global_payload,
+                          const std::string& script_payload,
+                          Service::ResponseCallback& callback) {
+        EXPECT_THAT("value",
+                    trigger_context.GetParameter("required").value_or(""));
+        EXPECT_THAT("value0",
+                    trigger_context.GetParameter("arg0").value_or(""));
+
+        std::move(callback).Run(true, "");
+      }));
+
+  std::map<std::string, std::string> parameters;
+  parameters["required"] = "value";
+  parameters["arg0"] = "value0";
+  EXPECT_TRUE(controller_->PerformUserActionWithContext(
+      0, TriggerContext::Create(parameters, "")));
 }
 
 TEST_F(ControllerTest, NoScripts) {
@@ -443,8 +495,8 @@
 
     Start("http://a.example.com/path");
     EXPECT_THAT(controller_->GetUserActions(),
-                ElementsAre(Field(&UserAction::chip,
-                                  Field(&Chip::text, StrEq("reset")))));
+                ElementsAre(Property(&UserAction::chip,
+                                     Field(&Chip::text, StrEq("reset")))));
 
     // 2. Execute the "reset" script, which contains a reset action.
     ActionsResponseProto actions_response;
@@ -466,8 +518,8 @@
     // The reset script should be available again, even though it's marked
     // RunOnce, as the script state should have been cleared as well.
     EXPECT_THAT(controller_->GetUserActions(),
-                ElementsAre(Field(&UserAction::chip,
-                                  Field(&Chip::text, StrEq("reset")))));
+                ElementsAre(Property(&UserAction::chip,
+                                     Field(&Chip::text, StrEq("reset")))));
 }
 
 TEST_F(ControllerTest, RefreshScriptWhenDomainChanges) {
@@ -484,20 +536,6 @@
   SimulateNavigateToUrl(GURL("http://b.example.com/path2"));
 }
 
-TEST_F(ControllerTest, ForwardParameters) {
-  EXPECT_CALL(*mock_service_,
-              OnGetScriptsForUrl(_,
-                                 Field(&TriggerContext::script_parameters,
-                                       Contains(Pair("a", "b"))),
-                                 _))
-      .WillOnce(RunOnceCallback<2>(true, ""));
-
-  GURL initialUrl("http://example.com/");
-  std::unique_ptr<TriggerContext> context(new TriggerContext);
-  context->script_parameters["a"] = "b";
-  controller_->Start(initialUrl, std::move(context));
-}
-
 TEST_F(ControllerTest, Autostart) {
   SupportsScriptResponseProto script_response;
   AddRunnableScript(&script_response, "runnable");
@@ -534,26 +572,7 @@
   EXPECT_CALL(*mock_service_, OnGetScriptsForUrl(Eq(initialUrl), _, _))
       .WillOnce(RunOnceCallback<2>(true, ""));
 
-  controller_->Start(initialUrl, std::make_unique<TriggerContext>());
-}
-
-TEST_F(ControllerTest, CookieExperimentEnabled) {
-  GURL initialUrl("http://a.example.com/path");
-
-  // TODO(crbug.com/806868): Extend this test once the cookie information is
-  // passed to the initial request. Currently the public controller API does not
-  // yet allow proper testing.
-  EXPECT_CALL(*mock_service_, OnGetScriptsForUrl(Eq(initialUrl), _, _))
-      .WillOnce(RunOnceCallback<2>(true, ""));
-
-  std::unique_ptr<TriggerContext> trigger_context(new TriggerContext);
-  trigger_context->script_parameters.insert(std::make_pair("EXP_COOKIE", "1"));
-  controller_->Start(initialUrl, std::move(trigger_context));
-
-  // TODO(crbug.com): Make IsCookieExperimentEnabled private and remove this
-  // test when we pass the cookie data along in the initial request so that it
-  // can be tested.
-  EXPECT_TRUE(controller_->IsCookieExperimentEnabled());
+  controller_->Start(initialUrl, TriggerContext::CreateEmpty());
 }
 
 TEST_F(ControllerTest, ProgressIncreasesAtStart) {
diff --git a/components/autofill_assistant/browser/details.cc b/components/autofill_assistant/browser/details.cc
index b88c10b..ac72c77 100644
--- a/components/autofill_assistant/browser/details.cc
+++ b/components/autofill_assistant/browser/details.cc
@@ -11,6 +11,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/autofill/core/browser/geo/country_names.h"
+#include "components/autofill_assistant/browser/trigger_context.h"
 #include "components/strings/grit/components_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -173,103 +174,106 @@
   return dict;
 }
 
-bool Details::UpdateFromParameters(
-    const std::map<std::string, std::string>& parameters) {
-  const auto iter = parameters.find("DETAILS_SHOW_INITIAL");
-  if (iter != parameters.end() && iter->second.compare("false") == 0) {
+bool Details::UpdateFromParameters(const TriggerContext& context) {
+  base::Optional<std::string> show_initial =
+      context.GetParameter("DETAILS_SHOW_INITIAL");
+  if (show_initial.value_or("true") == "false") {
     return false;
   }
   // Whenever details are updated from parameters we want to animate missing
   // data.
   proto_.set_animate_placeholders(true);
   proto_.set_show_image_placeholder(true);
-  if (MaybeUpdateFromDetailsParameters(parameters)) {
+  if (MaybeUpdateFromDetailsParameters(context)) {
     return true;
   }
 
   // NOTE: The logic below is only needed for backward compatibility.
   // Remove once we always pass detail parameters.
   bool is_updated = false;
-  for (const auto& iter : parameters) {
-    std::string key = iter.first;
-    if (key == "MOVIES_MOVIE_NAME") {
-      proto_.set_title(iter.second);
-      is_updated = true;
-      continue;
-    }
+  base::Optional<std::string> movie_name =
+      context.GetParameter("MOVIES_MOVIE_NAME");
+  if (movie_name) {
+    proto_.set_title(movie_name.value());
+    is_updated = true;
+  }
 
-    if (key == "MOVIES_THEATER_NAME") {
-      proto_.set_description_line_2(iter.second);
-      is_updated = true;
-      continue;
-    }
+  base::Optional<std::string> theater_name =
+      context.GetParameter("MOVIES_THEATER_NAME");
+  if (theater_name) {
+    proto_.set_description_line_2(theater_name.value());
+    is_updated = true;
+  }
 
-    if (iter.first.compare("MOVIES_SCREENING_DATETIME") == 0) {
-      // TODO(crbug.com/806868): Parse the string here and fill
-      // proto.description_line_1, then get rid of datetime_ in Details.
-      datetime_ = iter.second;
-      is_updated = true;
-      continue;
-    }
+  base::Optional<std::string> screening_datetime =
+      context.GetParameter("MOVIES_SCREENING_DATETIME");
+  if (screening_datetime) {
+    datetime_ = screening_datetime.value();
+    is_updated = true;
   }
   return is_updated;
 }
 
-bool Details::MaybeUpdateFromDetailsParameters(
-    const std::map<std::string, std::string>& parameters) {
+bool Details::MaybeUpdateFromDetailsParameters(const TriggerContext& context) {
   bool details_updated = false;
-  for (const auto& iter : parameters) {
-    std::string key = iter.first;
-    if (key == "DETAILS_TITLE") {
-      proto_.set_title(iter.second);
-      details_updated = true;
-      continue;
-    }
 
-    if (key == "DETAILS_DESCRIPTION_LINE_1") {
-      proto_.set_description_line_1(iter.second);
-      details_updated = true;
-      continue;
-    }
-
-    if (key == "DETAILS_DESCRIPTION_LINE_2") {
-      proto_.set_description_line_2(iter.second);
-      details_updated = true;
-      continue;
-    }
-
-    if (key == "DETAILS_DESCRIPTION_LINE_3") {
-      proto_.set_description_line_3(iter.second);
-      details_updated = true;
-      continue;
-    }
-
-    if (key == "DETAILS_IMAGE_URL") {
-      proto_.set_image_url(iter.second);
-      details_updated = true;
-      continue;
-    }
-
-    if (key == "DETAILS_IMAGE_CLICKTHROUGH_URL") {
-      proto_.mutable_image_clickthrough_data()->set_allow_clickthrough(true);
-      proto_.mutable_image_clickthrough_data()->set_clickthrough_url(
-          iter.second);
-      details_updated = true;
-      continue;
-    }
-
-    if (key == "DETAILS_TOTAL_PRICE_LABEL") {
-      proto_.set_total_price_label(iter.second);
-      details_updated = true;
-      continue;
-    }
-
-    if (key == "DETAILS_TOTAL_PRICE") {
-      proto_.set_total_price(iter.second);
-      details_updated = true;
-      continue;
-    }
+  base::Optional<std::string> title = context.GetParameter("DETAILS_TITLE");
+  if (title) {
+    proto_.set_title(title.value());
+    details_updated = true;
   }
+
+  base::Optional<std::string> description_line_1 =
+      context.GetParameter("DETAILS_DESCRIPTION_LINE_1");
+  if (description_line_1) {
+    proto_.set_description_line_1(description_line_1.value());
+    details_updated = true;
+  }
+
+  base::Optional<std::string> description_line_2 =
+      context.GetParameter("DETAILS_DESCRIPTION_LINE_2");
+  if (description_line_2) {
+    proto_.set_description_line_2(description_line_2.value());
+    details_updated = true;
+  }
+
+  base::Optional<std::string> description_line_3 =
+      context.GetParameter("DETAILS_DESCRIPTION_LINE_3");
+  if (description_line_3) {
+    proto_.set_description_line_3(description_line_3.value());
+    details_updated = true;
+  }
+
+  base::Optional<std::string> image_url =
+      context.GetParameter("DETAILS_IMAGE_URL");
+  if (image_url) {
+    proto_.set_image_url(image_url.value());
+    details_updated = true;
+  }
+
+  base::Optional<std::string> image_clickthrough_url =
+      context.GetParameter("DETAILS_IMAGE_CLICKTHROUGH_URL");
+  if (image_clickthrough_url) {
+    proto_.mutable_image_clickthrough_data()->set_allow_clickthrough(true);
+    proto_.mutable_image_clickthrough_data()->set_clickthrough_url(
+        image_clickthrough_url.value());
+    details_updated = true;
+  }
+
+  base::Optional<std::string> total_price_label =
+      context.GetParameter("DETAILS_TOTAL_PRICE_LABEL");
+  if (total_price_label) {
+    proto_.set_total_price_label(total_price_label.value());
+    details_updated = true;
+  }
+
+  base::Optional<std::string> total_price =
+      context.GetParameter("DETAILS_TOTAL_PRICE");
+  if (total_price) {
+    proto_.set_total_price(total_price.value());
+    details_updated = true;
+  }
+
   return details_updated;
 }
 
diff --git a/components/autofill_assistant/browser/details.h b/components/autofill_assistant/browser/details.h
index 310cc71..f19a1eb5 100644
--- a/components/autofill_assistant/browser/details.h
+++ b/components/autofill_assistant/browser/details.h
@@ -13,6 +13,7 @@
 #include "components/autofill_assistant/browser/service.pb.h"
 
 namespace autofill_assistant {
+class TriggerContext;
 
 class Details {
  public:
@@ -29,8 +30,7 @@
   // made.
   // If one of the generic detail parameter is present then vertical specific
   // parameters are not used for Details creation.
-  bool UpdateFromParameters(
-      const std::map<std::string, std::string>& parameters);
+  bool UpdateFromParameters(const TriggerContext& context);
 
   // Updates the details to show data directly from proto. Returns true if
   // |details| were successfully updated.
@@ -64,8 +64,7 @@
  private:
   // Tries updating the details using generic detail parameters. Returns true
   // if at least one generic detail parameter was found and used.
-  bool MaybeUpdateFromDetailsParameters(
-      const std::map<std::string, std::string>& parameters);
+  bool MaybeUpdateFromDetailsParameters(const TriggerContext& context);
 
   DetailsProto proto_;
   DetailsChangesProto change_flags_;
diff --git a/components/autofill_assistant/browser/direct_action.cc b/components/autofill_assistant/browser/direct_action.cc
new file mode 100644
index 0000000..2ee6ec3
--- /dev/null
+++ b/components/autofill_assistant/browser/direct_action.cc
@@ -0,0 +1,27 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill_assistant/browser/direct_action.h"
+
+#include "components/autofill_assistant/browser/service.pb.h"
+
+namespace autofill_assistant {
+
+DirectAction::DirectAction() = default;
+DirectAction::DirectAction(const DirectAction&) = default;
+DirectAction::~DirectAction() = default;
+
+DirectAction::DirectAction(const DirectActionProto& proto) {
+  for (const std::string& name : proto.names()) {
+    names.emplace_back(name);
+  }
+  for (const std::string& argument : proto.required_arguments()) {
+    required_arguments.emplace_back(argument);
+  }
+  for (const std::string& argument : proto.optional_arguments()) {
+    optional_arguments.emplace_back(argument);
+  }
+}
+
+}  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/direct_action.h b/components/autofill_assistant/browser/direct_action.h
new file mode 100644
index 0000000..8a9a332
--- /dev/null
+++ b/components/autofill_assistant/browser/direct_action.h
@@ -0,0 +1,41 @@
+// 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_AUTOFILL_ASSISTANT_BROWSER_DIRECT_ACTION_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_DIRECT_ACTION_H_
+
+#include <string>
+#include <vector>
+
+namespace autofill_assistant {
+
+class DirectActionProto;
+
+// Definition of a direct action to which a UserAction can be mapped.
+//
+// A direct action is an user action that originates not from the UI but instead
+// from some other app or tool. This corresponds to Android's direct actions,
+// first introduced in Android Q.
+struct DirectAction {
+  DirectAction();
+  DirectAction(const DirectAction&);
+  ~DirectAction();
+
+  explicit DirectAction(const DirectActionProto& proto);
+
+  bool empty() const { return names.empty(); }
+
+  // Names of the direct action under which this action is available. Optional.
+  std::vector<std::string> names;
+
+  // Arguments that must be set to run the direct action.
+  std::vector<std::string> required_arguments;
+
+  // Arguments that might be set to run the direct action.
+  std::vector<std::string> optional_arguments;
+};
+
+}  // namespace autofill_assistant
+
+#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_DIRECT_ACTION_H_
diff --git a/components/autofill_assistant/browser/fake_script_executor_delegate.cc b/components/autofill_assistant/browser/fake_script_executor_delegate.cc
index 81f0603..4e914d1f 100644
--- a/components/autofill_assistant/browser/fake_script_executor_delegate.cc
+++ b/components/autofill_assistant/browser/fake_script_executor_delegate.cc
@@ -8,7 +8,9 @@
 
 namespace autofill_assistant {
 
-FakeScriptExecutorDelegate::FakeScriptExecutorDelegate() = default;
+FakeScriptExecutorDelegate::FakeScriptExecutorDelegate()
+    : trigger_context_(TriggerContext::CreateEmpty()) {}
+
 FakeScriptExecutorDelegate::~FakeScriptExecutorDelegate() = default;
 
 const ClientSettings& FakeScriptExecutorDelegate::GetSettings() {
@@ -40,7 +42,7 @@
 }
 
 TriggerContext* FakeScriptExecutorDelegate::GetTriggerContext() {
-  return &trigger_context_;
+  return trigger_context_.get();
 }
 
 autofill::PersonalDataManager*
diff --git a/components/autofill_assistant/browser/fake_script_executor_delegate.h b/components/autofill_assistant/browser/fake_script_executor_delegate.h
index 398a9e4..362c580 100644
--- a/components/autofill_assistant/browser/fake_script_executor_delegate.h
+++ b/components/autofill_assistant/browser/fake_script_executor_delegate.h
@@ -76,8 +76,8 @@
     web_controller_ = web_controller;
   }
 
-  std::map<std::string, std::string>* GetMutableParameters() {
-    return &trigger_context_.script_parameters;
+  void SetTriggerContext(std::unique_ptr<TriggerContext> trigger_context) {
+    trigger_context_ = std::move(trigger_context);
   }
 
   AutofillAssistantState GetState() { return state_; }
@@ -108,7 +108,7 @@
   UiController* ui_controller_ = nullptr;
   WebController* web_controller_ = nullptr;
   ClientMemory memory_;
-  TriggerContext trigger_context_;
+  std::unique_ptr<TriggerContext> trigger_context_;
   AutofillAssistantState state_ = AutofillAssistantState::INACTIVE;
   std::string status_message_;
   std::unique_ptr<Details> details_;
diff --git a/components/autofill_assistant/browser/mock_service.cc b/components/autofill_assistant/browser/mock_service.cc
index db67dd8..2804c96 100644
--- a/components/autofill_assistant/browser/mock_service.cc
+++ b/components/autofill_assistant/browser/mock_service.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "components/autofill_assistant/browser/mock_service.h"
+#include "components/autofill_assistant/browser/trigger_context.h"
 
 #include "url/gurl.h"
 
diff --git a/components/autofill_assistant/browser/mock_service.h b/components/autofill_assistant/browser/mock_service.h
index 23ed84e..1872c2e 100644
--- a/components/autofill_assistant/browser/mock_service.h
+++ b/components/autofill_assistant/browser/mock_service.h
@@ -20,7 +20,7 @@
   ~MockService() override;
 
   void GetScriptsForUrl(const GURL& url,
-                        const TriggerContext* trigger_context,
+                        const TriggerContext& trigger_context,
                         ResponseCallback callback) override {
     // Transforming callback into a references allows using RunOnceCallback on
     // the argument.
@@ -28,12 +28,12 @@
   }
   MOCK_METHOD3(OnGetScriptsForUrl,
                void(const GURL& url,
-                    const TriggerContext* trigger_context,
+                    const TriggerContext& trigger_context,
                     ResponseCallback& callback));
 
   void GetActions(const std::string& script_path,
                   const GURL& url,
-                  const TriggerContext* trigger_context,
+                  const TriggerContext& trigger_context,
                   const std::string& global_payload,
                   const std::string& script_payload,
                   ResponseCallback callback) override {
@@ -43,13 +43,13 @@
   MOCK_METHOD6(OnGetActions,
                void(const std::string& script_path,
                     const GURL& url,
-                    const TriggerContext* trigger_context,
+                    const TriggerContext& trigger_contexts,
                     const std::string& global_payload,
                     const std::string& script_payload,
                     ResponseCallback& callback));
 
   void GetNextActions(
-      const TriggerContext* trigger_context,
+      const TriggerContext& trigger_context,
       const std::string& previous_global_payload,
       const std::string& previous_script_payload,
       const std::vector<ProcessedActionProto>& processed_actions,
@@ -58,7 +58,7 @@
                      previous_script_payload, processed_actions, callback);
   }
   MOCK_METHOD5(OnGetNextActions,
-               void(const TriggerContext* trigger_context,
+               void(const TriggerContext& trigger_contexts,
                     const std::string& previous_global_payload,
                     const std::string& previous_script_payload,
                     const std::vector<ProcessedActionProto>& processed_actions,
diff --git a/components/autofill_assistant/browser/mock_web_controller.h b/components/autofill_assistant/browser/mock_web_controller.h
index e96b8e73..e1558f2 100644
--- a/components/autofill_assistant/browser/mock_web_controller.h
+++ b/components/autofill_assistant/browser/mock_web_controller.h
@@ -82,17 +82,6 @@
                void(const Selector& selector,
                     base::OnceCallback<void(bool, const RectF&)>& callback));
 
-  void HasCookie(base::OnceCallback<void(bool)> callback) override {
-    std::move(callback).Run(false);
-  }
-
-  void SetCookie(const std::string& domain,
-                 base::OnceCallback<void(bool)> callback) override {
-    std::move(callback).Run(true);
-  }
-
-  MOCK_METHOD0(ClearCookie, void());
-
   void WaitForWindowHeightChange(
       base::OnceCallback<void(const ClientStatus&)> callback) {
     OnWaitForWindowHeightChange(callback);
diff --git a/components/autofill_assistant/browser/protocol_utils.cc b/components/autofill_assistant/browser/protocol_utils.cc
index 8e1617e4..2223653 100644
--- a/components/autofill_assistant/browser/protocol_utils.cc
+++ b/components/autofill_assistant/browser/protocol_utils.cc
@@ -39,24 +39,13 @@
 
 namespace {
 
-// Fills the destination proto field with script parameters from the given
-// parameter map.
-void AddScriptParametersToProto(
-    const std::map<std::string, std::string>& source,
-    ::google::protobuf::RepeatedPtrField<ScriptParameterProto>* destination) {
-  for (const auto& param_entry : source) {
-    ScriptParameterProto* parameter = destination->Add();
-    parameter->set_name(param_entry.first);
-    parameter->set_value(param_entry.second);
-  }
-}
-
 void FillClientContext(const ClientContextProto& client_context,
                        const TriggerContext& trigger_context,
                        ClientContextProto* proto) {
   proto->CopyFrom(client_context);
-  if (!trigger_context.experiment_ids.empty()) {
-    proto->set_experiment_ids(trigger_context.experiment_ids);
+  std::string experiment_ids = trigger_context.experiment_ids();
+  if (!experiment_ids.empty()) {
+    proto->set_experiment_ids(experiment_ids);
   }
 }
 
@@ -73,8 +62,7 @@
   script_proto.set_url(url.spec());
   FillClientContext(client_context, trigger_context,
                     script_proto.mutable_client_context());
-  AddScriptParametersToProto(trigger_context.script_parameters,
-                             script_proto.mutable_script_parameters());
+  trigger_context.AddParameters(script_proto.mutable_script_parameters());
   std::string serialized_script_proto;
   bool success = script_proto.SerializeToString(&serialized_script_proto);
   DCHECK(success);
@@ -111,9 +99,7 @@
     script->handle.initial_prompt = presentation.initial_prompt();
     script->handle.chip = Chip(presentation.chip());
   }
-  for (const auto& name : presentation.direct_action().names()) {
-    script->handle.direct_action_names.emplace_back(name);
-  }
+  script->handle.direct_action = DirectAction(presentation.direct_action());
   scripts->emplace_back(std::move(script));
 }
 
@@ -135,10 +121,8 @@
   query->set_policy(PolicyType::SCRIPT);
   FillClientContext(client_context, trigger_context,
                     request_proto.mutable_client_context());
-  AddScriptParametersToProto(
-      trigger_context.script_parameters,
+  trigger_context.AddParameters(
       initial_request_proto->mutable_script_parameters());
-
   if (!global_payload.empty()) {
     request_proto.set_global_payload(global_payload);
   }
diff --git a/components/autofill_assistant/browser/protocol_utils_unittest.cc b/components/autofill_assistant/browser/protocol_utils_unittest.cc
index 7694e04..b7bd456 100644
--- a/components/autofill_assistant/browser/protocol_utils_unittest.cc
+++ b/components/autofill_assistant/browser/protocol_utils_unittest.cc
@@ -83,10 +83,10 @@
 }
 
 TEST(ProtocolUtilsTest, CreateInitialScriptActionsRequest) {
-  TriggerContext trigger_context;
-  trigger_context.script_parameters["a"] = "b";
-  trigger_context.script_parameters["c"] = "d";
-  trigger_context.experiment_ids = "1,2,3";
+  std::map<std::string, std::string> parameters;
+  parameters["a"] = "b";
+  parameters["c"] = "d";
+  TriggerContextImpl trigger_context(parameters, "1,2,3");
 
   ScriptActionRequestProto request;
   EXPECT_TRUE(
@@ -110,10 +110,10 @@
 }
 
 TEST(ProtocolUtilsTest, CreateNextScriptActionsRequest) {
-  TriggerContext trigger_context;
-  trigger_context.script_parameters["a"] = "b";
-  trigger_context.script_parameters["c"] = "d";
-  trigger_context.experiment_ids = "1,2,3";
+  std::map<std::string, std::string> parameters;
+  parameters["a"] = "b";
+  parameters["c"] = "d";
+  TriggerContextImpl trigger_context(parameters, "1,2,3");
 
   ScriptActionRequestProto request;
   std::vector<ProcessedActionProto> processed_actions;
@@ -129,10 +129,10 @@
 }
 
 TEST(ProtocolUtilsTest, CreateGetScriptsRequest) {
-  TriggerContext trigger_context;
-  trigger_context.script_parameters["a"] = "b";
-  trigger_context.script_parameters["c"] = "d";
-  trigger_context.experiment_ids = "1,2,3";
+  std::map<std::string, std::string> parameters;
+  parameters["a"] = "b";
+  parameters["c"] = "d";
+  TriggerContextImpl trigger_context(parameters, "1,2,3");
 
   SupportsScriptRequestProto request;
   EXPECT_TRUE(request.ParseFromString(ProtocolUtils::CreateGetScriptsRequest(
@@ -190,7 +190,7 @@
 
   EXPECT_NE(nullptr, script);
   EXPECT_EQ("path", script->handle.path);
-  EXPECT_THAT(script->handle.direct_action_names, ElementsAre("action_name"));
+  EXPECT_THAT(script->handle.direct_action.names, ElementsAre("action_name"));
   EXPECT_TRUE(script->handle.chip.empty());
   EXPECT_FALSE(script->handle.autostart);
   EXPECT_NE(nullptr, script->precondition);
diff --git a/components/autofill_assistant/browser/script.h b/components/autofill_assistant/browser/script.h
index 0d07145..78b3345 100644
--- a/components/autofill_assistant/browser/script.h
+++ b/components/autofill_assistant/browser/script.h
@@ -9,6 +9,7 @@
 #include <string>
 
 #include "components/autofill_assistant/browser/chip.h"
+#include "components/autofill_assistant/browser/direct_action.h"
 #include "components/autofill_assistant/browser/script_precondition.h"
 #include "components/autofill_assistant/browser/service.pb.h"
 
@@ -21,7 +22,7 @@
   ~ScriptHandle();
 
   Chip chip;
-  std::vector<std::string> direct_action_names;
+  DirectAction direct_action;
   std::string path;
   std::string initial_prompt;
 
diff --git a/components/autofill_assistant/browser/script_executor.cc b/components/autofill_assistant/browser/script_executor.cc
index 0d966ece..fa84e3d 100644
--- a/components/autofill_assistant/browser/script_executor.cc
+++ b/components/autofill_assistant/browser/script_executor.cc
@@ -22,6 +22,7 @@
 #include "components/autofill_assistant/browser/protocol_utils.h"
 #include "components/autofill_assistant/browser/self_delete_full_card_requester.h"
 #include "components/autofill_assistant/browser/service.h"
+#include "components/autofill_assistant/browser/trigger_context.h"
 #include "components/autofill_assistant/browser/ui_controller.h"
 #include "components/autofill_assistant/browser/web_controller.h"
 #include "components/strings/grit/components_strings.h"
@@ -63,6 +64,7 @@
 
 ScriptExecutor::ScriptExecutor(
     const std::string& script_path,
+    std::unique_ptr<TriggerContext> additional_context,
     const std::string& global_payload,
     const std::string& script_payload,
     ScriptExecutor::Listener* listener,
@@ -70,6 +72,7 @@
     const std::vector<Script*>* ordered_interrupts,
     ScriptExecutorDelegate* delegate)
     : script_path_(script_path),
+      additional_context_(std::move(additional_context)),
       last_global_payload_(global_payload),
       initial_script_payload_(script_payload),
       last_script_payload_(script_payload),
@@ -104,7 +107,9 @@
 
   DVLOG(2) << "GetActions for " << delegate_->GetCurrentURL().host();
   delegate_->GetService()->GetActions(
-      script_path_, delegate_->GetDeeplinkURL(), delegate_->GetTriggerContext(),
+      script_path_, delegate_->GetDeeplinkURL(),
+      MergedTriggerContext(
+          {delegate_->GetTriggerContext(), additional_context_.get()}),
       last_global_payload_, last_script_payload_,
       base::BindOnce(&ScriptExecutor::OnGetActions,
                      weak_ptr_factory_.GetWeakPtr()));
@@ -261,12 +266,11 @@
   // We change the chips callback with a callback that cleans up the state
   // before calling the initial callback.
   for (auto& user_action : *user_actions) {
-    if (!user_action.callback)
+    if (!user_action.HasCallback())
       continue;
 
-    user_action.callback = base::BindOnce(&ScriptExecutor::OnChosen,
-                                          weak_ptr_factory_.GetWeakPtr(),
-                                          std::move(user_action.callback));
+    user_action.AddInterceptor(base::BindOnce(&ScriptExecutor::OnChosen,
+                                              weak_ptr_factory_.GetWeakPtr()));
   }
 
   delegate_->EnterState(AutofillAssistantState::PROMPT);
@@ -287,9 +291,10 @@
   delegate_->EnterState(AutofillAssistantState::RUNNING);
 }
 
-void ScriptExecutor::OnChosen(base::OnceClosure callback) {
+void ScriptExecutor::OnChosen(UserAction::Callback callback,
+                              std::unique_ptr<TriggerContext> context) {
   CleanUpAfterPrompt();
-  std::move(callback).Run();
+  std::move(callback).Run(std::move(context));
 }
 
 void ScriptExecutor::FillAddressForm(
@@ -618,8 +623,9 @@
 
 void ScriptExecutor::GetNextActions() {
   delegate_->GetService()->GetNextActions(
-      delegate_->GetTriggerContext(), last_global_payload_,
-      last_script_payload_, processed_actions_,
+      MergedTriggerContext(
+          {delegate_->GetTriggerContext(), additional_context_.get()}),
+      last_global_payload_, last_script_payload_, processed_actions_,
       base::BindOnce(&ScriptExecutor::OnGetActions,
                      weak_ptr_factory_.GetWeakPtr()));
 }
@@ -789,8 +795,7 @@
 
       interrupt->precondition->Check(
           delegate_->GetCurrentURL(), batch_element_checker_.get(),
-          delegate_->GetTriggerContext()->script_parameters,
-          *main_script_->scripts_state_,
+          *delegate_->GetTriggerContext(), *main_script_->scripts_state_,
           base::BindOnce(&WaitForDomOperation::OnPreconditionCheckDone,
                          weak_ptr_factory_.GetWeakPtr(),
                          base::Unretained(interrupt)));
@@ -838,8 +843,9 @@
   SavePreInterruptState();
   ran_interrupts_.insert(interrupt->handle.path);
   interrupt_executor_ = std::make_unique<ScriptExecutor>(
-      interrupt->handle.path, main_script_->last_global_payload_,
-      main_script_->initial_script_payload_,
+      interrupt->handle.path,
+      TriggerContext::Merge({main_script_->additional_context_.get()}),
+      main_script_->last_global_payload_, main_script_->initial_script_payload_,
       /* listener= */ this, main_script_->scripts_state_, &no_interrupts_,
       delegate_);
   interrupt_executor_->Run(
diff --git a/components/autofill_assistant/browser/script_executor.h b/components/autofill_assistant/browser/script_executor.h
index 1578fba..b0ca8ccd 100644
--- a/components/autofill_assistant/browser/script_executor.h
+++ b/components/autofill_assistant/browser/script_executor.h
@@ -54,6 +54,7 @@
   // |delegate|, |listener|, |script_state| and |ordered_interrupts| should
   // outlive this object and should not be nullptr.
   ScriptExecutor(const std::string& script_path,
+                 std::unique_ptr<TriggerContext> additional_context,
                  const std::string& global_payload,
                  const std::string& script_payload,
                  ScriptExecutor::Listener* listener,
@@ -329,9 +330,11 @@
                      std::unique_ptr<autofill::CreditCard> card,
                      const base::string16& cvc);
   void CleanUpAfterPrompt();
-  void OnChosen(base::OnceClosure callback);
+  void OnChosen(UserAction::Callback callback,
+                std::unique_ptr<TriggerContext> context);
 
   std::string script_path_;
+  std::unique_ptr<TriggerContext> additional_context_;
   std::string last_global_payload_;
   const std::string initial_script_payload_;
   std::string last_script_payload_;
diff --git a/components/autofill_assistant/browser/script_executor_delegate.h b/components/autofill_assistant/browser/script_executor_delegate.h
index e1ef336..d0985a4c 100644
--- a/components/autofill_assistant/browser/script_executor_delegate.h
+++ b/components/autofill_assistant/browser/script_executor_delegate.h
@@ -32,7 +32,7 @@
 class WebController;
 class ClientMemory;
 struct ClientSettings;
-struct TriggerContext;
+class TriggerContext;
 
 class ScriptExecutorDelegate {
  public:
diff --git a/components/autofill_assistant/browser/script_executor_unittest.cc b/components/autofill_assistant/browser/script_executor_unittest.cc
index b22ed20c..1109f217 100644
--- a/components/autofill_assistant/browser/script_executor_unittest.cc
+++ b/components/autofill_assistant/browser/script_executor_unittest.cc
@@ -31,6 +31,7 @@
 using ::testing::ElementsAre;
 using ::testing::Eq;
 using ::testing::Field;
+using ::testing::Invoke;
 using ::testing::InvokeWithoutArgs;
 using ::testing::IsEmpty;
 using ::testing::NiceMock;
@@ -54,8 +55,11 @@
     delegate_.SetWebController(&mock_web_controller_);
     delegate_.SetCurrentURL(GURL("http://example.com/"));
 
+    std::map<std::string, std::string> script_parameters;
+    script_parameters["additional_param"] = "additional_param_value";
     executor_ = std::make_unique<ScriptExecutor>(
         kScriptPath,
+        TriggerContext::Create(script_parameters, "additional_exp"),
         /* global_payload= */ "initial global payload",
         /* script_payload= */ "initial payload",
         /* listener= */ this, &scripts_state_, &ordered_interrupts_,
@@ -177,16 +181,27 @@
 }
 
 TEST_F(ScriptExecutorTest, ForwardParameters) {
-  auto* parameters = delegate_.GetMutableParameters();
-  (*parameters)["param1"] = "value1";
-  (*parameters)["param2"] = "value2";
-  EXPECT_CALL(mock_service_,
-              OnGetActions(StrEq(kScriptPath), _,
-                           Field(&TriggerContext::script_parameters,
-                                 AllOf(Contains(Pair("param1", "value1")),
-                                       Contains(Pair("param2", "value2")))),
-                           _, _, _))
-      .WillOnce(RunOnceCallback<5>(true, ""));
+  std::map<std::string, std::string> parameters;
+  parameters["param"] = "value";
+  delegate_.SetTriggerContext(TriggerContext::Create(parameters, "exp"));
+  EXPECT_CALL(mock_service_, OnGetActions(StrEq(kScriptPath), _, _, _, _, _))
+      .WillOnce(Invoke([](const std::string& script_path, const GURL& url,
+                          const TriggerContext& trigger_context,
+                          const std::string& global_payload,
+                          const std::string& script_payload,
+                          Service::ResponseCallback& callback) {
+        // |trigger_context| includes data passed to
+        // ScriptExecutor constructor as well as data from the
+        // delegate's TriggerContext.
+        EXPECT_THAT("exp,additional_exp", trigger_context.experiment_ids());
+        EXPECT_THAT(
+            "additional_param_value",
+            trigger_context.GetParameter("additional_param").value_or(""));
+        EXPECT_THAT("value",
+                    trigger_context.GetParameter("param").value_or(""));
+
+        std::move(callback).Run(true, "");
+      }));
 
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
diff --git a/components/autofill_assistant/browser/script_precondition.cc b/components/autofill_assistant/browser/script_precondition.cc
index bab669f..ff4a061 100644
--- a/components/autofill_assistant/browser/script_precondition.cc
+++ b/components/autofill_assistant/browser/script_precondition.cc
@@ -11,6 +11,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/autofill_assistant/browser/batch_element_checker.h"
 #include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/trigger_context.h"
 #include "third_party/re2/src/re2/re2.h"
 #include "url/gurl.h"
 
@@ -46,10 +47,10 @@
 void ScriptPrecondition::Check(
     const GURL& url,
     BatchElementChecker* batch_checks,
-    const std::map<std::string, std::string>& parameters,
+    const TriggerContext& context,
     const std::map<std::string, ScriptStatusProto>& executed_scripts,
     base::OnceCallback<void(bool)> callback) {
-  if (!MatchDomain(url) || !MatchPath(url) || !MatchParameters(parameters) ||
+  if (!MatchDomain(url) || !MatchPath(url) || !MatchParameters(context) ||
       !MatchScriptStatus(executed_scripts)) {
     std::move(callback).Run(false);
     return;
@@ -100,21 +101,21 @@
   return false;
 }
 
-bool ScriptPrecondition::MatchParameters(
-    const std::map<std::string, std::string>& parameters) const {
+bool ScriptPrecondition::MatchParameters(const TriggerContext& context) const {
   for (const auto& match : parameter_match_) {
-    auto iter = parameters.find(match.name());
+    auto opt_value = context.GetParameter(match.name());
     if (match.exists()) {
       // parameter must exist and optionally have a specific value
-      if (iter == parameters.end())
+      if (!opt_value)
         return false;
 
-      if (!match.value_equals().empty() && iter->second != match.value_equals())
+      if (!match.value_equals().empty() &&
+          opt_value.value() != match.value_equals())
         return false;
 
     } else {
       // parameter must not exist
-      if (iter != parameters.end())
+      if (opt_value)
         return false;
     }
   }
diff --git a/components/autofill_assistant/browser/script_precondition.h b/components/autofill_assistant/browser/script_precondition.h
index 88ff96a..a3fc996 100644
--- a/components/autofill_assistant/browser/script_precondition.h
+++ b/components/autofill_assistant/browser/script_precondition.h
@@ -24,6 +24,7 @@
 
 namespace autofill_assistant {
 class BatchElementChecker;
+class TriggerContext;
 
 // Class represents a set of preconditions for a script to be executed.
 class ScriptPrecondition {
@@ -58,15 +59,14 @@
   // running check.
   void Check(const GURL& url,
              BatchElementChecker* batch_checks,
-             const std::map<std::string, std::string>& parameters,
+             const TriggerContext& context,
              const std::map<std::string, ScriptStatusProto>& executed_scripts,
              base::OnceCallback<void(bool)> callback);
 
  private:
   bool MatchDomain(const GURL& url) const;
   bool MatchPath(const GURL& url) const;
-  bool MatchParameters(
-      const std::map<std::string, std::string>& parameters) const;
+  bool MatchParameters(const TriggerContext& context) const;
   bool MatchScriptStatus(
       const std::map<std::string, ScriptStatusProto>& executed_scripts) const;
 
diff --git a/components/autofill_assistant/browser/script_precondition_unittest.cc b/components/autofill_assistant/browser/script_precondition_unittest.cc
index 3ccf22d..1212019 100644
--- a/components/autofill_assistant/browser/script_precondition_unittest.cc
+++ b/components/autofill_assistant/browser/script_precondition_unittest.cc
@@ -13,6 +13,7 @@
 #include "components/autofill_assistant/browser/batch_element_checker.h"
 #include "components/autofill_assistant/browser/mock_web_controller.h"
 #include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/trigger_context.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/re2/src/re2/re2.h"
 
@@ -63,6 +64,8 @@
         .WillByDefault(RunOnceCallback<1>(false));
 
     SetUrl("http://www.example.com/path");
+
+    trigger_context_ = TriggerContext::CreateEmpty();
   }
 
  protected:
@@ -76,15 +79,15 @@
 
     DirectCallback callback;
     BatchElementChecker batch_checks;
-    precondition->Check(url_, &batch_checks, parameters_, executed_scripts_,
-                        callback.Get());
+    precondition->Check(url_, &batch_checks, *trigger_context_,
+                        executed_scripts_, callback.Get());
     batch_checks.Run(&mock_web_controller_);
     return callback.GetResultOrDie();
   }
 
   GURL url_;
   MockWebController mock_web_controller_;
-  std::map<std::string, std::string> parameters_;
+  std::unique_ptr<TriggerContext> trigger_context_;
   std::map<std::string, ScriptStatusProto> executed_scripts_;
 };
 
@@ -257,7 +260,9 @@
 
   EXPECT_FALSE(Check(proto));
 
-  parameters_["param"] = "exists";
+  std::map<std::string, std::string> parameters;
+  parameters["param"] = "exists";
+  trigger_context_ = TriggerContext::Create(parameters, "");
 
   EXPECT_TRUE(Check(proto));
 }
@@ -270,7 +275,9 @@
 
   EXPECT_TRUE(Check(proto));
 
-  parameters_["param"] = "exists";
+  std::map<std::string, std::string> parameters;
+  parameters["param"] = "exists";
+  trigger_context_ = TriggerContext::Create(parameters, "");
 
   EXPECT_FALSE(Check(proto));
 }
@@ -283,11 +290,15 @@
 
   EXPECT_FALSE(Check(proto));
 
-  parameters_["param"] = "another value";
+  std::map<std::string, std::string> parameters;
+  parameters["param"] = "another value";
+  trigger_context_ = TriggerContext::Create(parameters, "");
 
   EXPECT_FALSE(Check(proto));
 
-  parameters_["param"] = "value";
+  parameters["param"] = "value";
+  trigger_context_ = TriggerContext::Create(parameters, "");
+
   EXPECT_TRUE(Check(proto));
 }
 
diff --git a/components/autofill_assistant/browser/script_tracker.cc b/components/autofill_assistant/browser/script_tracker.cc
index f3b256a..74ae284 100644
--- a/components/autofill_assistant/browser/script_tracker.cc
+++ b/components/autofill_assistant/browser/script_tracker.cc
@@ -32,6 +32,15 @@
             });
 }
 
+// Creates a value containing a vector of strings.
+base::Value StringVectorToValue(const std::vector<std::string>& v) {
+  std::vector<base::Value> values;
+  for (const auto& s : v) {
+    values.emplace_back(base::Value(s));
+  }
+  return base::Value(values);
+}
+
 }  // namespace
 
 ScriptTracker::ScriptTracker(ScriptExecutorDelegate* delegate,
@@ -78,13 +87,13 @@
   batch_element_checker_ = std::make_unique<BatchElementChecker>();
   for (const auto& entry : available_scripts_) {
     Script* script = entry.first;
-    if (script->handle.chip.empty() &&
-        script->handle.direct_action_names.empty() && !script->handle.autostart)
+    if (script->handle.chip.empty() && script->handle.direct_action.empty() &&
+        !script->handle.autostart)
       continue;
 
     script->precondition->Check(
-        url, batch_element_checker_.get(),
-        delegate_->GetTriggerContext()->script_parameters, scripts_state_,
+        url, batch_element_checker_.get(), *delegate_->GetTriggerContext(),
+        scripts_state_,
         base::BindOnce(&ScriptTracker::OnPreconditionCheck,
                        weak_ptr_factory_.GetWeakPtr(), script));
   }
@@ -105,6 +114,7 @@
 }
 
 void ScriptTracker::ExecuteScript(const std::string& script_path,
+                                  std::unique_ptr<TriggerContext> context,
                                   ScriptExecutor::RunScriptCallback callback) {
   if (running()) {
     DVLOG(1) << "Do not expect executing the script (" << script_path
@@ -116,7 +126,8 @@
   }
 
   executor_ = std::make_unique<ScriptExecutor>(
-      script_path, last_global_payload_, last_script_payload_,
+      script_path, std::move(context), last_global_payload_,
+      last_script_payload_,
       /* listener= */ this, &scripts_state_, &interrupts_, delegate_);
   ScriptExecutor::RunScriptCallback run_script_callback = base::BindOnce(
       &ScriptTracker::OnScriptRun, weak_ptr_factory_.GetWeakPtr(), script_path,
@@ -161,11 +172,18 @@
     script_js.SetKey("initial_prompt", base::Value(entry.initial_prompt));
     script_js.SetKey("autostart", base::Value(entry.autostart));
     script_js.SetKey("chip_type", base::Value(entry.chip.type));
-    std::vector<base::Value> direct_action_names;
-    for (const auto& name : entry.direct_action_names) {
-      direct_action_names.emplace_back(base::Value(name));
-    }
-    script_js.SetKey("direct_action_names", base::Value(direct_action_names));
+
+    base::Value direct_action_js = base::Value(base::Value::Type::DICTIONARY);
+    direct_action_js.SetKey("names",
+                            StringVectorToValue(entry.direct_action.names));
+    direct_action_js.SetKey(
+        "required_arguments",
+        StringVectorToValue(entry.direct_action.required_arguments));
+    direct_action_js.SetKey(
+        "optional_arguments",
+        StringVectorToValue(entry.direct_action.optional_arguments));
+    script_js.SetKey("direct_action", std::move(direct_action_js));
+
     runnable_scripts_js.push_back(std::move(script_js));
   }
   dict.SetKey("runnable-scripts", base::Value(runnable_scripts_js));
diff --git a/components/autofill_assistant/browser/script_tracker.h b/components/autofill_assistant/browser/script_tracker.h
index bd50e050..a983e84 100644
--- a/components/autofill_assistant/browser/script_tracker.h
+++ b/components/autofill_assistant/browser/script_tracker.h
@@ -74,7 +74,12 @@
   // Scripts that are already executed won't be considered runnable anymore.
   // Call CheckScripts to refresh the set of runnable script after script
   // execution.
+  //
+  // The given context allows specifying additional parameters and experiments,
+  // on top of what's available in the context returned by
+  // ScriptExecutorDelegate.
   void ExecuteScript(const std::string& path,
+                     std::unique_ptr<TriggerContext> context,
                      ScriptExecutor::RunScriptCallback callback);
 
   // Clears the set of scripts that could be run.
diff --git a/components/autofill_assistant/browser/script_tracker_unittest.cc b/components/autofill_assistant/browser/script_tracker_unittest.cc
index 1df47dc..09b641c 100644
--- a/components/autofill_assistant/browser/script_tracker_unittest.cc
+++ b/components/autofill_assistant/browser/script_tracker_unittest.cc
@@ -254,7 +254,8 @@
   EXPECT_CALL(execute_callback,
               Run(Field(&ScriptExecutor::Result::success, true)));
 
-  tracker_.ExecuteScript("script1", execute_callback.Get());
+  tracker_.ExecuteScript("script1", TriggerContext::CreateEmpty(),
+                         execute_callback.Get());
   tracker_.CheckScripts();
 
   // The 2nd time the scripts are checked, automatically after the script runs,
@@ -312,7 +313,8 @@
   base::MockCallback<ScriptExecutor::RunScriptCallback> execute_callback;
   EXPECT_CALL(execute_callback,
               Run(Field(&ScriptExecutor::Result::success, true)));
-  tracker_.ExecuteScript("runnable name", execute_callback.Get());
+  tracker_.ExecuteScript("runnable name", TriggerContext::CreateEmpty(),
+                         execute_callback.Get());
   tracker_.CheckScripts();
 
   // 3. Verify that the runnable scripts have changed to the updated list.
@@ -354,7 +356,8 @@
   base::MockCallback<ScriptExecutor::RunScriptCallback> execute_callback;
   EXPECT_CALL(execute_callback,
               Run(Field(&ScriptExecutor::Result::success, true)));
-  tracker_.ExecuteScript("runnable name", execute_callback.Get());
+  tracker_.ExecuteScript("runnable name", TriggerContext::CreateEmpty(),
+                         execute_callback.Get());
   tracker_.CheckScripts();
 
   // 3. Verify that the runnable scripts have changed to the updated list.
diff --git a/components/autofill_assistant/browser/service.cc b/components/autofill_assistant/browser/service.cc
index cbe0051..28522d8 100644
--- a/components/autofill_assistant/browser/service.cc
+++ b/components/autofill_assistant/browser/service.cc
@@ -98,19 +98,19 @@
 Service::~Service() {}
 
 void Service::GetScriptsForUrl(const GURL& url,
-                               const TriggerContext* trigger_context,
+                               const TriggerContext& trigger_context,
                                ResponseCallback callback) {
   DCHECK(url.is_valid());
 
   SendRequest(AddLoader(script_server_url_,
                         ProtocolUtils::CreateGetScriptsRequest(
-                            url, *trigger_context, client_context_),
+                            url, trigger_context, client_context_),
                         std::move(callback)));
 }
 
 void Service::GetActions(const std::string& script_path,
                          const GURL& url,
-                         const TriggerContext* trigger_context,
+                         const TriggerContext& trigger_context,
                          const std::string& global_payload,
                          const std::string& script_payload,
                          ResponseCallback callback) {
@@ -118,13 +118,13 @@
 
   SendRequest(AddLoader(script_action_server_url_,
                         ProtocolUtils::CreateInitialScriptActionsRequest(
-                            script_path, url, *trigger_context, global_payload,
+                            script_path, url, trigger_context, global_payload,
                             script_payload, client_context_),
                         std::move(callback)));
 }
 
 void Service::GetNextActions(
-    const TriggerContext* trigger_context,
+    const TriggerContext& trigger_context,
     const std::string& previous_global_payload,
     const std::string& previous_script_payload,
     const std::vector<ProcessedActionProto>& processed_actions,
@@ -132,7 +132,7 @@
   SendRequest(AddLoader(
       script_action_server_url_,
       ProtocolUtils::CreateNextScriptActionsRequest(
-          *trigger_context, previous_global_payload, previous_script_payload,
+          trigger_context, previous_global_payload, previous_script_payload,
           processed_actions, client_context_),
       std::move(callback)));
 }
diff --git a/components/autofill_assistant/browser/service.h b/components/autofill_assistant/browser/service.h
index 84666700..5d0e7de 100644
--- a/components/autofill_assistant/browser/service.h
+++ b/components/autofill_assistant/browser/service.h
@@ -25,7 +25,7 @@
 
 namespace autofill_assistant {
 class Client;
-struct TriggerContext;
+class TriggerContext;
 
 // Autofill assistant service to communicate with the server to get scripts and
 // client actions.
@@ -50,13 +50,13 @@
       base::OnceCallback<void(bool result, const std::string&)>;
   // Get scripts for a given |url|, which should be a valid URL.
   virtual void GetScriptsForUrl(const GURL& url,
-                                const TriggerContext* trigger_context,
+                                const TriggerContext& trigger_context,
                                 ResponseCallback callback);
 
   // Get actions.
   virtual void GetActions(const std::string& script_path,
                           const GURL& url,
-                          const TriggerContext* trigger_context,
+                          const TriggerContext& trigger_context,
                           const std::string& global_payload,
                           const std::string& script_payload,
                           ResponseCallback callback);
@@ -64,7 +64,7 @@
   // Get next sequence of actions according to server payloads in previous
   // response.
   virtual void GetNextActions(
-      const TriggerContext* trigger_context,
+      const TriggerContext& trigger_context,
       const std::string& previous_global_payload,
       const std::string& previous_script_payload,
       const std::vector<ProcessedActionProto>& processed_actions,
diff --git a/components/autofill_assistant/browser/service.proto b/components/autofill_assistant/browser/service.proto
index 0172f79..4071adf9 100644
--- a/components/autofill_assistant/browser/service.proto
+++ b/components/autofill_assistant/browser/service.proto
@@ -1455,7 +1455,19 @@
 // Defines a mapping to an Android Q direct action.
 message DirectActionProto {
   // Map to direct actions with the given names.
-  repeated string names = 12;
+  repeated string names = 1;
+
+  // Arguments to report as required for the direct action.
+  //
+  // This is included into the definition reported to the caller without being
+  // interpreted. Requirement is not enforced.
+  repeated string required_arguments = 2;
+
+  // Arguments to report as optional for the direct action.
+  //
+  // This is included into the definition reported to the caller without being
+  // interpreted.
+  repeated string optional_arguments = 3;
 }
 
 // Action to show a popup bubble on top of the bottom sheet, anchored at the
diff --git a/components/autofill_assistant/browser/trigger_context.cc b/components/autofill_assistant/browser/trigger_context.cc
index 961d56f..6f0a96a 100644
--- a/components/autofill_assistant/browser/trigger_context.cc
+++ b/components/autofill_assistant/browser/trigger_context.cc
@@ -6,12 +6,94 @@
 
 namespace autofill_assistant {
 
-TriggerContext::TriggerContext(std::map<std::string, std::string> params,
-                               std::string exp)
-    : script_parameters(std::move(params)), experiment_ids(std::move(exp)) {}
+// static
+std::unique_ptr<TriggerContext> TriggerContext::CreateEmpty() {
+  return std::make_unique<TriggerContextImpl>();
+}
 
-TriggerContext::TriggerContext() = default;
-TriggerContext::TriggerContext(const TriggerContext& context) = default;
-TriggerContext::~TriggerContext() = default;
+// static
+std::unique_ptr<TriggerContext> TriggerContext::Create(
+    std::map<std::string, std::string> params,
+    const std::string& exp) {
+  return std::make_unique<TriggerContextImpl>(params, exp);
+}
+
+// static
+std::unique_ptr<TriggerContext> TriggerContext::Merge(
+    std::vector<const TriggerContext*> contexts) {
+  return std::make_unique<MergedTriggerContext>(contexts);
+}
+
+TriggerContext::TriggerContext() {}
+TriggerContext::~TriggerContext() {}
+
+TriggerContextImpl::TriggerContextImpl() {}
+
+TriggerContextImpl::TriggerContextImpl(
+    std::map<std::string, std::string> parameters,
+    const std::string& experiment_ids)
+    : parameters_(std::move(parameters)),
+      experiment_ids_(std::move(experiment_ids)) {}
+TriggerContextImpl::~TriggerContextImpl() = default;
+
+void TriggerContextImpl::AddParameters(
+    google::protobuf::RepeatedPtrField<ScriptParameterProto>* dest) const {
+  for (const auto& param_entry : parameters_) {
+    ScriptParameterProto* parameter = dest->Add();
+    parameter->set_name(param_entry.first);
+    parameter->set_value(param_entry.second);
+  }
+}
+
+base::Optional<std::string> TriggerContextImpl::GetParameter(
+    const std::string& name) const {
+  auto iter = parameters_.find(name);
+  if (iter == parameters_.end())
+    return base::nullopt;
+
+  return iter->second;
+}
+
+std::string TriggerContextImpl::experiment_ids() const {
+  return experiment_ids_;
+}
+
+MergedTriggerContext::MergedTriggerContext(
+    std::vector<const TriggerContext*> contexts)
+    : contexts_(contexts) {}
+
+MergedTriggerContext::~MergedTriggerContext() {}
+
+void MergedTriggerContext::AddParameters(
+    google::protobuf::RepeatedPtrField<ScriptParameterProto>* dest) const {
+  for (const TriggerContext* context : contexts_) {
+    context->AddParameters(dest);
+  }
+}
+
+base::Optional<std::string> MergedTriggerContext::GetParameter(
+    const std::string& name) const {
+  for (const TriggerContext* context : contexts_) {
+    auto opt_value = context->GetParameter(name);
+    if (opt_value)
+      return opt_value;
+  }
+  return base::nullopt;
+}
+
+std::string MergedTriggerContext::experiment_ids() const {
+  std::string experiment_ids;
+  for (const TriggerContext* context : contexts_) {
+    std::string context_experiment_ids = context->experiment_ids();
+    if (context_experiment_ids.empty())
+      continue;
+
+    if (!experiment_ids.empty())
+      experiment_ids.append(1, ',');
+
+    experiment_ids.append(context->experiment_ids());
+  }
+  return experiment_ids;
+}
 
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/trigger_context.h b/components/autofill_assistant/browser/trigger_context.h
index fb0697e..7bb87a7 100644
--- a/components/autofill_assistant/browser/trigger_context.h
+++ b/components/autofill_assistant/browser/trigger_context.h
@@ -10,22 +10,90 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "base/optional.h"
+#include "components/autofill_assistant/browser/service.pb.h"
 
 namespace autofill_assistant {
 
-// A trigger context for data provided by callers.
-struct TriggerContext {
+// Abstract base class for trigger context, providing data provided by callers.
+class TriggerContext {
+ public:
+  // Returns an empty trigger context
+  static std::unique_ptr<TriggerContext> CreateEmpty();
+
+  // Creates a trigger context with the given values.
+  //
+  // Takes ownership (through std:move) of the content |params|.
+  static std::unique_ptr<TriggerContext> Create(
+      std::map<std::string, std::string> params,
+      const std::string& exp);
+
+  // Creates a trigger context that references one or more other contexts.
+  //
+  // The pointers must remain valid for the lifetime of the returned instance.
+  static std::unique_ptr<TriggerContext> Merge(
+      std::vector<const TriggerContext*> contexts);
+
+  TriggerContext();
+  virtual ~TriggerContext();
+
+  // Adds all parameters to the given proto field.
+  virtual void AddParameters(
+      google::protobuf::RepeatedPtrField<ScriptParameterProto>* dest) const = 0;
+
+  // Returns the value of a specific parameter, if present.
+  virtual base::Optional<std::string> GetParameter(
+      const std::string& name) const = 0;
+
+  // Returns a comma-separated set of experiment ids.
+  virtual std::string experiment_ids() const = 0;
+};
+
+// Straightforward implementation of TriggerContext.
+class TriggerContextImpl : public TriggerContext {
+ public:
+  // An empty context
+  TriggerContextImpl();
+
+  // Takes ownership (through std:move) of the content |params| and |exp|.
+  TriggerContextImpl(std::map<std::string, std::string> params,
+                     const std::string& exp);
+
+  ~TriggerContextImpl() override;
+
+  // Implements TriggerContext:
+  void AddParameters(google::protobuf::RepeatedPtrField<ScriptParameterProto>*
+                         dest) const override;
+  base::Optional<std::string> GetParameter(
+      const std::string& name) const override;
+  std::string experiment_ids() const override;
+
+ private:
   // Script parameters provided by the caller.
-  std::map<std::string, std::string> script_parameters;
+  std::map<std::string, std::string> parameters_;
 
   // Experiment ids to be passed to the backend in requests. They may also be
   // used to change client behavior.
-  std::string experiment_ids;
+  std::string experiment_ids_;
+};
 
-  TriggerContext();
-  TriggerContext(std::map<std::string, std::string> params, std::string exp);
-  TriggerContext(const TriggerContext& context);
-  ~TriggerContext();
+// Merges several TriggerContexts together.
+class MergedTriggerContext : public TriggerContext {
+ public:
+  // The pointers in |contexts| must remain valid for the lifetime of the
+  // instances. The vector can be empty.
+  MergedTriggerContext(std::vector<const TriggerContext*> contexts);
+  ~MergedTriggerContext() override;
+
+  // Implements TriggerContext:
+  void AddParameters(google::protobuf::RepeatedPtrField<ScriptParameterProto>*
+                         dest) const override;
+  base::Optional<std::string> GetParameter(
+      const std::string& name) const override;
+  std::string experiment_ids() const override;
+
+ private:
+  std::vector<const TriggerContext*> contexts_;
 };
 
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/trigger_context_unittest.cc b/components/autofill_assistant/browser/trigger_context_unittest.cc
new file mode 100644
index 0000000..08c047f
--- /dev/null
+++ b/components/autofill_assistant/browser/trigger_context_unittest.cc
@@ -0,0 +1,84 @@
+// 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/autofill_assistant/browser/trigger_context.h"
+
+#include "components/autofill_assistant/browser/service.pb.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+namespace {
+
+using ::testing::IsEmpty;
+using ::testing::SizeIs;
+
+TEST(TriggerContextTest, Empty) {
+  auto empty = TriggerContext::CreateEmpty();
+  ASSERT_TRUE(empty);
+
+  google::protobuf::RepeatedPtrField<ScriptParameterProto> parameters_proto;
+  empty->AddParameters(&parameters_proto);
+  EXPECT_THAT(parameters_proto, IsEmpty());
+
+  EXPECT_EQ("", empty->experiment_ids());
+}
+
+TEST(TriggerContextTest, Create) {
+  std::map<std::string, std::string> parameters;
+  parameters["a"] = "b";
+  parameters["c"] = "d";
+  auto context = TriggerContext::Create(parameters, "exps");
+  ASSERT_TRUE(context);
+
+  google::protobuf::RepeatedPtrField<ScriptParameterProto> parameters_proto;
+  context->AddParameters(&parameters_proto);
+  EXPECT_THAT(parameters_proto, SizeIs(2));
+
+  EXPECT_EQ("a", parameters_proto.Get(0).name());
+  EXPECT_EQ("b", parameters_proto.Get(0).value());
+  EXPECT_EQ("c", parameters_proto.Get(1).name());
+  EXPECT_EQ("d", parameters_proto.Get(1).value());
+
+  EXPECT_EQ("b", context->GetParameter("a").value_or(""));
+  EXPECT_EQ("d", context->GetParameter("c").value_or(""));
+  EXPECT_FALSE(context->GetParameter("not_found"));
+
+  EXPECT_EQ("exps", context->experiment_ids());
+}
+
+TEST(TriggerContextTest, Merge) {
+  std::map<std::string, std::string> parameters;
+  parameters["a"] = "b";
+  auto context1 = TriggerContext::Create(parameters, "exp1");
+
+  parameters.clear();
+  parameters["c"] = "d";
+  auto context2 = TriggerContext::Create(parameters, "exp2");
+
+  // Adding empty to make sure empty contexts are properly skipped
+  auto empty = TriggerContext::CreateEmpty();
+
+  auto merged = TriggerContext::Merge(
+      {empty.get(), context1.get(), context2.get(), empty.get()});
+
+  ASSERT_TRUE(merged);
+
+  google::protobuf::RepeatedPtrField<ScriptParameterProto> parameters_proto;
+  merged->AddParameters(&parameters_proto);
+  EXPECT_THAT(parameters_proto, SizeIs(2));
+
+  EXPECT_EQ("a", parameters_proto.Get(0).name());
+  EXPECT_EQ("b", parameters_proto.Get(0).value());
+  EXPECT_EQ("c", parameters_proto.Get(1).name());
+  EXPECT_EQ("d", parameters_proto.Get(1).value());
+
+  EXPECT_EQ("b", merged->GetParameter("a").value_or(""));
+  EXPECT_EQ("d", merged->GetParameter("c").value_or(""));
+  EXPECT_FALSE(merged->GetParameter("not_found"));
+
+  EXPECT_EQ("exp1,exp2", merged->experiment_ids());
+}
+
+}  // namespace
+}  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/ui_delegate.h b/components/autofill_assistant/browser/ui_delegate.h
index 4502d5ef..8f0021e4 100644
--- a/components/autofill_assistant/browser/ui_delegate.h
+++ b/components/autofill_assistant/browser/ui_delegate.h
@@ -71,9 +71,22 @@
 
   // Performs an action, from the set of actions returned by GetUserAction().
   //
+  // If non-empty, |context| is added to the global trigger context when
+  // executing scripts. Ignored if no scripts are executed by the action.
+  //
   // Returns true if the action was triggered, false if the index did not
   // correspond to any enabled actions.
-  virtual bool PerformUserAction(int index) = 0;
+  virtual bool PerformUserActionWithContext(
+      int index,
+      std::unique_ptr<TriggerContext> context) = 0;
+
+  // Performs an action with no additional trigger context set.
+  //
+  // Returns true if the action was triggered, false if the index did not
+  // correspond to any enabled actions.
+  bool PerformUserAction(int index) {
+    return PerformUserActionWithContext(index, TriggerContext::CreateEmpty());
+  }
 
   // If the controller is waiting for payment request information, this
   // field contains a non-null options describing the request.
diff --git a/components/autofill_assistant/browser/user_action.cc b/components/autofill_assistant/browser/user_action.cc
index 3ea6fb0b..be4f79c2 100644
--- a/components/autofill_assistant/browser/user_action.cc
+++ b/components/autofill_assistant/browser/user_action.cc
@@ -4,8 +4,25 @@
 
 #include "components/autofill_assistant/browser/user_action.h"
 
+#include "base/bind.h"
+
 namespace autofill_assistant {
 
+namespace {
+
+void CallIgnoringContext(base::OnceCallback<void()> callback,
+                         std::unique_ptr<TriggerContext> context) {
+  std::move(callback).Run();
+}
+
+// void Intercept(base::OnceCallback<void(UserAction::Callback, const
+// TriggerContext&)> interceptor, UserAction::Callback original,
+// std::unique_ptr<TriggerContext>) {
+//   std::move(interceptor).Run(std::move(original), context);
+// }
+
+}  // namespace
+
 UserAction::UserAction(UserAction&& other) = default;
 UserAction::UserAction() = default;
 UserAction::~UserAction() = default;
@@ -13,15 +30,20 @@
 
 // Initializes user action from proto.
 UserAction::UserAction(const ChipProto& chip_proto,
-                       const DirectActionProto& direct_action)
-    : chip(chip_proto) {
-  for (const std::string& name : direct_action.names()) {
-    direct_action_names.emplace_back(name);
-  }
+                       const DirectActionProto& direct_action_proto)
+    : chip_(chip_proto), direct_action_(direct_action_proto) {}
+
+void UserAction::SetCallback(base::OnceCallback<void()> callback) {
+  callback_ = base::BindOnce(&CallIgnoringContext, std::move(callback));
 }
 
-bool UserAction::has_triggers() const {
-  return !chip.empty() || !direct_action_names.empty();
+void UserAction::AddInterceptor(
+    base::OnceCallback<void(UserAction::Callback,
+                            std::unique_ptr<TriggerContext>)> interceptor) {
+  if (!callback_)
+    return;
+
+  callback_ = base::BindOnce(std::move(interceptor), std::move(callback_));
 }
 
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/user_action.h b/components/autofill_assistant/browser/user_action.h
index 6ff74df..b26f0ff1 100644
--- a/components/autofill_assistant/browser/user_action.h
+++ b/components/autofill_assistant/browser/user_action.h
@@ -9,14 +9,23 @@
 #include <vector>
 
 #include "base/callback.h"
+#include "base/macros.h"
 #include "components/autofill_assistant/browser/chip.h"
+#include "components/autofill_assistant/browser/direct_action.h"
 #include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/trigger_context.h"
 
 namespace autofill_assistant {
 
 // An action that the user can perform, through the UI or, on Android Q, through
 // a direct action.
-struct UserAction {
+class UserAction {
+ public:
+  // Executes a user action with the given additional trigger context.
+  //
+  // The context is relevant only for actions that execute a script.
+  using Callback = base::OnceCallback<void(std::unique_ptr<TriggerContext>)>;
+
   UserAction(UserAction&&);
   UserAction();
   ~UserAction();
@@ -27,21 +36,63 @@
 
   // Returns true if the action has no trigger, that is, there is no chip and no
   // direct action.
-  bool has_triggers() const;
+  bool has_triggers() const {
+    return !chip_.empty() || !direct_action_.empty();
+  }
 
+  const Chip& chip() const { return chip_; }
+  Chip& chip() { return chip_; }
+
+  const DirectAction& direct_action() const { return direct_action_; }
+  DirectAction& direct_action() { return direct_action_; }
+
+  void SetEnabled(bool enabled) { enabled_ = enabled; }
+
+  bool enabled() const { return enabled_; }
+
+  // Checks whether a callback is assigned to the action. Actions without
+  // callbacks do nothing.
+  bool HasCallback() const { return callback_ ? true : false; }
+
+  // Specifies a callback that accepts no context.
+  void SetCallback(base::OnceCallback<void()> callback);
+
+  // Specifies a callback that accepts a context.
+  void SetCallback(
+      base::OnceCallback<void(std::unique_ptr<TriggerContext>)> callback) {
+    callback_ = std::move(callback);
+  }
+
+  // Intercept calls to this action.
+  void AddInterceptor(
+      base::OnceCallback<void(UserAction::Callback,
+                              std::unique_ptr<TriggerContext>)> interceptor);
+
+  // Call this action within the specific context, if a callback is set.
+  void Call(std::unique_ptr<TriggerContext> context) {
+    if (!callback_)
+      return;
+
+    std::move(callback_).Run(std::move(context));
+  }
+
+ private:
   // Specifies how the user can perform the action through the UI. Might be
   // empty.
-  Chip chip;
+  Chip chip_;
 
-  // Names of the direct action under which this action is available. Optional.
-  std::vector<std::string> direct_action_names;
+  // Specifies how the user can perform the action as a direct action. Might be
+  // empty.
+  DirectAction direct_action_;
 
   // Whether the action is enabled. The chip for a disabled action might still
   // be shown.
-  bool enabled = true;
+  bool enabled_ = true;
 
   // Callback triggered to trigger the action.
-  base::OnceClosure callback;
+  Callback callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(UserAction);
 };
 
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/web_controller.cc b/components/autofill_assistant/browser/web_controller.cc
index fd54c95..02336ab 100644
--- a/components/autofill_assistant/browser/web_controller.cc
+++ b/components/autofill_assistant/browser/web_controller.cc
@@ -37,13 +37,6 @@
 using autofill::ContentAutofillDriver;
 
 namespace {
-// Expiration time for the Autofill Assistant cookie.
-constexpr int kCookieExpiresSeconds = 600;
-
-// Name and value used for the static cookie.
-const char* const kAutofillAssistantCookieName = "autofill_assistant_cookie";
-const char* const kAutofillAssistantCookieValue = "true";
-
 const char* const kGetBoundingClientRectAsList =
     R"(function(node) {
       const r = node.getBoundingClientRect();
@@ -1932,61 +1925,6 @@
   std::move(callback).Run(OkClientStatus(), value);
 }
 
-void WebController::SetCookie(const std::string& domain,
-                              base::OnceCallback<void(bool)> callback) {
-  DVLOG(3) << __func__ << " domain=" << domain;
-  DCHECK(!domain.empty());
-  auto expires_seconds =
-      std::chrono::seconds(std::time(nullptr)).count() + kCookieExpiresSeconds;
-  devtools_client_->GetNetwork()->SetCookie(
-      network::SetCookieParams::Builder()
-          .SetName(kAutofillAssistantCookieName)
-          .SetValue(kAutofillAssistantCookieValue)
-          .SetDomain(domain)
-          .SetExpires(expires_seconds)
-          .Build(),
-      base::BindOnce(&WebController::OnSetCookie,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void WebController::OnSetCookie(
-    base::OnceCallback<void(bool)> callback,
-    std::unique_ptr<network::SetCookieResult> result) {
-  std::move(callback).Run(result && result->GetSuccess());
-}
-
-void WebController::HasCookie(base::OnceCallback<void(bool)> callback) {
-  DVLOG(3) << __func__;
-  devtools_client_->GetNetwork()->GetCookies(
-      base::BindOnce(&WebController::OnHasCookie,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void WebController::OnHasCookie(
-    base::OnceCallback<void(bool)> callback,
-    std::unique_ptr<network::GetCookiesResult> result) {
-  if (!result) {
-    std::move(callback).Run(false);
-    return;
-  }
-
-  const auto& cookies = *result->GetCookies();
-  for (const auto& cookie : cookies) {
-    if (cookie->GetName() == kAutofillAssistantCookieName &&
-        cookie->GetValue() == kAutofillAssistantCookieValue) {
-      std::move(callback).Run(true);
-      return;
-    }
-  }
-  std::move(callback).Run(false);
-}
-
-void WebController::ClearCookie() {
-  DVLOG(3) << __func__;
-  devtools_client_->GetNetwork()->DeleteCookies(kAutofillAssistantCookieName,
-                                                base::DoNothing());
-}
-
 void WebController::WaitForDocumentToBecomeInteractive(
     int remaining_rounds,
     std::string object_id,
diff --git a/components/autofill_assistant/browser/web_controller.h b/components/autofill_assistant/browser/web_controller.h
index 8ea31c7..51035732 100644
--- a/components/autofill_assistant/browser/web_controller.h
+++ b/components/autofill_assistant/browser/web_controller.h
@@ -172,13 +172,6 @@
       const Selector& selector,
       base::OnceCallback<void(bool, const RectF&)> callback);
 
-  // Functions to set, get and expire the Autofill Assistant cookie used to
-  // detect when Autofill Assistant has been used on a domain before.
-  virtual void SetCookie(const std::string& domain,
-                         base::OnceCallback<void(bool)> callback);
-  virtual void HasCookie(base::OnceCallback<void(bool)> callback);
-  virtual void ClearCookie();
-
   // Checks whether an element matches the given selector.
   //
   // If strict, there must be exactly one matching element for the check to
@@ -432,11 +425,6 @@
       autofill_assistant::input::DispatchKeyEventType type,
       const UChar32 codepoint);
 
-  void OnSetCookie(base::OnceCallback<void(bool)> callback,
-                   std::unique_ptr<network::SetCookieResult> result);
-  void OnHasCookie(base::OnceCallback<void(bool)> callback,
-                   std::unique_ptr<network::GetCookiesResult> result);
-
   // Waits for the document.readyState to be 'interactive' or 'complete'.
   void WaitForDocumentToBecomeInteractive(
       int remaining_rounds,
diff --git a/components/autofill_assistant/browser/web_controller_browsertest.cc b/components/autofill_assistant/browser/web_controller_browsertest.cc
index 32c479a..c43b056 100644
--- a/components/autofill_assistant/browser/web_controller_browsertest.cc
+++ b/components/autofill_assistant/browser/web_controller_browsertest.cc
@@ -378,35 +378,6 @@
     std::move(done_callback).Run();
   }
 
-  bool HasCookie() {
-    base::RunLoop run_loop;
-    bool result;
-    web_controller_->HasCookie(base::BindOnce(
-        &WebControllerBrowserTest::OnCookieResult, base::Unretained(this),
-        run_loop.QuitClosure(), &result));
-    run_loop.Run();
-    return result;
-  }
-
-  bool SetCookie() {
-    base::RunLoop run_loop;
-    bool result;
-    web_controller_->SetCookie(
-        "http://example.com",
-        base::BindOnce(&WebControllerBrowserTest::OnCookieResult,
-                       base::Unretained(this), run_loop.QuitClosure(),
-                       &result));
-    run_loop.Run();
-    return result;
-  }
-
-  void OnCookieResult(const base::Closure& done_callback,
-                      bool* result_output,
-                      bool result) {
-    *result_output = result;
-    std::move(done_callback).Run();
-  }
-
   // Scroll an element into view that's within a container element. This
   // requires scrolling the container, then the window, to get the element to
   // the desired y position.
@@ -1151,11 +1122,6 @@
   EXPECT_NE("", content::EvalJs(shell(), javascript));
 }
 
-IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, GetAndSetCookie) {
-  EXPECT_FALSE(HasCookie());
-  EXPECT_TRUE(SetCookie());
-}
-
 IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, WaitForHeightChange) {
   base::RunLoop run_loop;
   ClientStatus result;
diff --git a/components/bookmarks/browser/bookmark_client.h b/components/bookmarks/browser/bookmark_client.h
index a537bc5..dc346dd 100644
--- a/components/bookmarks/browser/bookmark_client.h
+++ b/components/bookmarks/browser/bookmark_client.h
@@ -74,9 +74,9 @@
   // that ensure that the action is posted from the correct thread.
   virtual void RecordAction(const base::UserMetricsAction& action) = 0;
 
-  // Returns a task that will be used to load any additional root nodes. This
+  // Returns a task that will be used to load an additional root node. This
   // task will be invoked in the Profile's IO task runner.
-  virtual LoadExtraCallback GetLoadExtraNodesCallback() = 0;
+  virtual LoadExtraCallback GetLoadExtraNodeCallback() = 0;
 
   // Returns true if the |permanent_node| can have its title updated.
   virtual bool CanSetPermanentNodeTitle(const BookmarkNode* permanent_node) = 0;
diff --git a/components/bookmarks/browser/bookmark_model_unittest.cc b/components/bookmarks/browser/bookmark_model_unittest.cc
index 123d0a2..b6dbf0c 100644
--- a/components/bookmarks/browser/bookmark_model_unittest.cc
+++ b/components/bookmarks/browser/bookmark_model_unittest.cc
@@ -431,12 +431,11 @@
   BookmarkPermanentNode* ReloadModelWithExtraNode() {
     model_->RemoveObserver(this);
 
-    BookmarkPermanentNodeList extra_nodes;
-    extra_nodes.push_back(std::make_unique<BookmarkPermanentNode>(100));
-    BookmarkPermanentNode* extra_node = extra_nodes.back().get();
+    auto owned_extra_node = std::make_unique<BookmarkPermanentNode>(100);
+    BookmarkPermanentNode* extra_node = owned_extra_node.get();
 
     std::unique_ptr<TestBookmarkClient> client(new TestBookmarkClient);
-    client->SetExtraNodesToLoad(std::move(extra_nodes));
+    client->SetExtraNodeToLoad(std::move(owned_extra_node));
 
     model_ = TestBookmarkClient::CreateModelWithClient(std::move(client));
     model_->AddObserver(this);
diff --git a/components/bookmarks/browser/bookmark_storage.cc b/components/bookmarks/browser/bookmark_storage.cc
index 4d946ac..a6f7cdc0 100644
--- a/components/bookmarks/browser/bookmark_storage.cc
+++ b/components/bookmarks/browser/bookmark_storage.cc
@@ -157,7 +157,7 @@
     }
   }
 
-  if (details->LoadExtraNodes())
+  if (details->LoadExtraNode())
     load_index = true;
 
   // Load any extra root nodes now, after the IDs have been potentially
@@ -199,7 +199,7 @@
 // BookmarkLoadDetails ---------------------------------------------------------
 
 BookmarkLoadDetails::BookmarkLoadDetails(BookmarkClient* client)
-    : load_extra_callback_(client->GetLoadExtraNodesCallback()),
+    : load_extra_callback_(client->GetLoadExtraNodeCallback()),
       index_(std::make_unique<TitledUrlIndex>()),
       model_sync_transaction_version_(
           BookmarkNode::kInvalidSyncTransactionVersion) {
@@ -219,18 +219,17 @@
 BookmarkLoadDetails::~BookmarkLoadDetails() {
 }
 
-bool BookmarkLoadDetails::LoadExtraNodes() {
+bool BookmarkLoadDetails::LoadExtraNode() {
   if (!load_extra_callback_)
     return false;
 
-  BookmarkPermanentNodeList extra_nodes =
+  std::unique_ptr<BookmarkPermanentNode> extra_node =
       std::move(load_extra_callback_).Run(&max_id_);
-  bool has_non_empty_node = false;
-  for (auto& node : extra_nodes) {
-    has_non_empty_node |= !node->children().empty();
-    root_node_->Add(std::move(node));
-  }
-  return has_non_empty_node;
+  if (!extra_node)
+    return false;
+  bool has_children = !extra_node->children().empty();
+  root_node_->Add(std::move(extra_node));
+  return has_children;
 }
 
 void BookmarkLoadDetails::CreateUrlIndex() {
diff --git a/components/bookmarks/browser/bookmark_storage.h b/components/bookmarks/browser/bookmark_storage.h
index c611e5f..2d0835c 100644
--- a/components/bookmarks/browser/bookmark_storage.h
+++ b/components/bookmarks/browser/bookmark_storage.h
@@ -32,15 +32,11 @@
 class BookmarkNode;
 class UrlIndex;
 
-// A list of BookmarkPermanentNodes that owns them.
-using BookmarkPermanentNodeList =
-    std::vector<std::unique_ptr<BookmarkPermanentNode>>;
-
-// A callback that generates a BookmarkPermanentNodeList, given a max ID to
-// use. The max ID argument will be updated after any new nodes have been
-// created and assigned IDs.
+// A callback that generates a std::unique_ptr<BookmarkPermanentNode>, given a
+// max ID to use. The max ID argument will be updated after if a new node has
+// been created and assigned an ID.
 using LoadExtraCallback =
-    base::OnceCallback<BookmarkPermanentNodeList(int64_t*)>;
+    base::OnceCallback<std::unique_ptr<BookmarkPermanentNode>(int64_t*)>;
 
 // BookmarkLoadDetails is used by BookmarkStorage when loading bookmarks.
 // BookmarkModel creates a BookmarkLoadDetails and passes it (including
@@ -55,9 +51,9 @@
   explicit BookmarkLoadDetails(BookmarkClient* client);
   ~BookmarkLoadDetails();
 
-  // Loads the extra nodes and adds them to |root_|. Returns true if at least
-  // one node was added that has children.
-  bool LoadExtraNodes();
+  // Loads the extra node and adds it to |root_|. Returns true if the added node
+  // has children.
+  bool LoadExtraNode();
 
   BookmarkNode* root_node() { return root_node_ptr_; }
   BookmarkPermanentNode* bb_node() { return bb_node_; }
diff --git a/components/bookmarks/browser/bookmark_utils_unittest.cc b/components/bookmarks/browser/bookmark_utils_unittest.cc
index d12b90d65..e48049a 100644
--- a/components/bookmarks/browser/bookmark_utils_unittest.cc
+++ b/components/bookmarks/browser/bookmark_utils_unittest.cc
@@ -422,10 +422,9 @@
 TEST_F(BookmarkUtilsTest, PasteNonEditableNodes) {
   // Load a model with an extra node that is not editable.
   std::unique_ptr<TestBookmarkClient> client(new TestBookmarkClient());
-  BookmarkPermanentNodeList extra_nodes;
-  extra_nodes.push_back(std::make_unique<BookmarkPermanentNode>(100));
-  BookmarkPermanentNode* extra_node = extra_nodes.back().get();
-  client->SetExtraNodesToLoad(std::move(extra_nodes));
+  auto owned_extra_node = std::make_unique<BookmarkPermanentNode>(100);
+  BookmarkPermanentNode* extra_node = owned_extra_node.get();
+  client->SetExtraNodeToLoad(std::move(owned_extra_node));
 
   std::unique_ptr<BookmarkModel> model(
       TestBookmarkClient::CreateModelWithClient(std::move(client)));
@@ -573,10 +572,9 @@
 TEST_F(BookmarkUtilsTest, RemoveAllBookmarks) {
   // Load a model with an extra node that is not editable.
   std::unique_ptr<TestBookmarkClient> client(new TestBookmarkClient());
-  BookmarkPermanentNodeList extra_nodes;
-  extra_nodes.push_back(std::make_unique<BookmarkPermanentNode>(100));
-  BookmarkPermanentNode* extra_node = extra_nodes.back().get();
-  client->SetExtraNodesToLoad(std::move(extra_nodes));
+  auto owned_extra_node = std::make_unique<BookmarkPermanentNode>(100);
+  BookmarkPermanentNode* extra_node = owned_extra_node.get();
+  client->SetExtraNodeToLoad(std::move(owned_extra_node));
 
   std::unique_ptr<BookmarkModel> model(
       TestBookmarkClient::CreateModelWithClient(std::move(client)));
diff --git a/components/bookmarks/managed/managed_bookmark_service.cc b/components/bookmarks/managed/managed_bookmark_service.cc
index 96f1db3..1e0a27e 100644
--- a/components/bookmarks/managed/managed_bookmark_service.cc
+++ b/components/bookmarks/managed/managed_bookmark_service.cc
@@ -62,15 +62,13 @@
   DISALLOW_COPY_AND_ASSIGN(BookmarkPermanentNodeLoader);
 };
 
-// Returns a list of initialized BookmarkPermanentNodes using |next_node_id| to
-// start assigning id. |next_node_id| is updated as a side effect of calling
-// this method.
-BookmarkPermanentNodeList LoadExtraNodes(
+// Returns a std::unique_ptr<BookmarkPermanentNode> using |next_node_id| for
+// assigning an id. |next_node_id| is updated as a side effect of calling this
+// method.
+std::unique_ptr<BookmarkPermanentNode> LoadExtraNode(
     std::unique_ptr<BookmarkPermanentNodeLoader> loader,
     int64_t* next_node_id) {
-  BookmarkPermanentNodeList extra_nodes;
-  extra_nodes.push_back(loader->Load(next_node_id));
-  return extra_nodes;
+  return loader->Load(next_node_id);
 }
 
 }  // namespace
@@ -98,9 +96,9 @@
       bookmark_model_, prefs_, managed_domain_callback_));
 }
 
-LoadExtraCallback ManagedBookmarkService::GetLoadExtraNodesCallback() {
+LoadExtraCallback ManagedBookmarkService::GetLoadExtraNodeCallback() {
   // Create a BookmarkPermanentNode with a temporary id of 0. It will be
-  // populated and assigned a proper id in the LoadExtraNodes callback. Until
+  // populated and assigned a proper id in the LoadExtraNode callback. Until
   // then, it is owned by the returned closure.
   std::unique_ptr<BookmarkPermanentNode> managed(new BookmarkPermanentNode(0));
 
@@ -111,7 +109,7 @@
       managed_bookmarks_tracker_->GetInitialManagedBookmarks(),
       IDS_BOOKMARK_BAR_MANAGED_FOLDER_DEFAULT_NAME);
 
-  return base::BindOnce(&LoadExtraNodes, std::move(loader));
+  return base::BindOnce(&LoadExtraNode, std::move(loader));
 }
 
 bool ManagedBookmarkService::CanSetPermanentNodeTitle(
diff --git a/components/bookmarks/managed/managed_bookmark_service.h b/components/bookmarks/managed/managed_bookmark_service.h
index 89cc8b2d..fd86386 100644
--- a/components/bookmarks/managed/managed_bookmark_service.h
+++ b/components/bookmarks/managed/managed_bookmark_service.h
@@ -36,9 +36,9 @@
   // Called upon creation of the BookmarkModel.
   void BookmarkModelCreated(BookmarkModel* bookmark_model);
 
-  // Returns a task that will be used to load any additional root nodes. This
-  // task will be invoked in the Profile's IO task runner.
-  LoadExtraCallback GetLoadExtraNodesCallback();
+  // Returns a task that will be used to load an additional root node. This task
+  // will be invoked in the Profile's IO task runner.
+  LoadExtraCallback GetLoadExtraNodeCallback();
 
   // Returns true if the |node| can have its title updated.
   bool CanSetPermanentNodeTitle(const BookmarkNode* node);
diff --git a/components/bookmarks/managed/managed_bookmarks_tracker_unittest.cc b/components/bookmarks/managed/managed_bookmarks_tracker_unittest.cc
index 87ab22c..6c0627d 100644
--- a/components/bookmarks/managed/managed_bookmarks_tracker_unittest.cc
+++ b/components/bookmarks/managed/managed_bookmarks_tracker_unittest.cc
@@ -54,18 +54,16 @@
 
   void CreateModel() {
     // Simulate the creation of the managed node by the BookmarkClient.
-    BookmarkPermanentNode* managed_node = new BookmarkPermanentNode(100);
+    auto owned_managed_node = std::make_unique<BookmarkPermanentNode>(100);
+    BookmarkPermanentNode* managed_node = owned_managed_node.get();
     ManagedBookmarksTracker::LoadInitial(
         managed_node, prefs_.GetList(prefs::kManagedBookmarks), 101);
     managed_node->set_visible(!managed_node->children().empty());
     managed_node->SetTitle(l10n_util::GetStringUTF16(
         IDS_BOOKMARK_BAR_MANAGED_FOLDER_DEFAULT_NAME));
 
-    BookmarkPermanentNodeList extra_nodes;
-    extra_nodes.push_back(base::WrapUnique(managed_node));
-
     std::unique_ptr<TestBookmarkClient> client(new TestBookmarkClient);
-    client->SetExtraNodesToLoad(std::move(extra_nodes));
+    client->SetExtraNodeToLoad(std::move(owned_managed_node));
     model_.reset(new BookmarkModel(std::move(client)));
 
     model_->AddObserver(&observer_);
@@ -78,9 +76,7 @@
 
     TestBookmarkClient* client_ptr =
         static_cast<TestBookmarkClient*>(model_->client());
-    ASSERT_EQ(1u, client_ptr->extra_nodes().size());
-    managed_node_ = client_ptr->extra_nodes()[0];
-    ASSERT_EQ(managed_node, managed_node_);
+    managed_node_ = client_ptr->extra_node();
 
     managed_bookmarks_tracker_.reset(new ManagedBookmarksTracker(
         model_.get(),
diff --git a/components/bookmarks/test/test_bookmark_client.cc b/components/bookmarks/test/test_bookmark_client.cc
index 51a4db0..241b440 100644
--- a/components/bookmarks/test/test_bookmark_client.cc
+++ b/components/bookmarks/test/test_bookmark_client.cc
@@ -36,33 +36,26 @@
       new BookmarkModel(std::move(client)));
   std::unique_ptr<BookmarkLoadDetails> details =
       std::make_unique<BookmarkLoadDetails>(client_ptr);
-  details->LoadExtraNodes();
+  details->LoadExtraNode();
   details->CreateUrlIndex();
   bookmark_model->DoneLoading(std::move(details));
   return bookmark_model;
 }
 
-void TestBookmarkClient::SetExtraNodesToLoad(
-    BookmarkPermanentNodeList extra_nodes) {
-  extra_nodes_ = std::move(extra_nodes);
-  // Keep a copy of the nodes in |unowned_extra_nodes_| for the accessor
+void TestBookmarkClient::SetExtraNodeToLoad(
+    std::unique_ptr<BookmarkPermanentNode> extra_node) {
+  extra_node_ = std::move(extra_node);
+  // Keep a copy of the node in |unowned_extra_node_| for the accessor
   // functions.
-  for (const auto& node : extra_nodes_)
-    unowned_extra_nodes_.push_back(node.get());
+  unowned_extra_node_ = extra_node_.get();
 }
 
 bool TestBookmarkClient::IsExtraNodeRoot(const BookmarkNode* node) {
-  return base::Contains(unowned_extra_nodes_, node);
+  return unowned_extra_node_ == node;
 }
 
 bool TestBookmarkClient::IsAnExtraNode(const BookmarkNode* node) {
-  if (!node)
-    return false;
-  for (const auto* extra_node : unowned_extra_nodes_) {
-    if (node->HasAncestor(extra_node))
-      return true;
-  }
-  return false;
+  return node && node->HasAncestor(unowned_extra_node_);
 }
 
 bool TestBookmarkClient::IsPermanentNodeVisible(
@@ -77,9 +70,9 @@
 void TestBookmarkClient::RecordAction(const base::UserMetricsAction& action) {
 }
 
-LoadExtraCallback TestBookmarkClient::GetLoadExtraNodesCallback() {
-  return base::BindOnce(&TestBookmarkClient::LoadExtraNodes,
-                        std::move(extra_nodes_));
+LoadExtraCallback TestBookmarkClient::GetLoadExtraNodeCallback() {
+  return base::BindOnce(&TestBookmarkClient::LoadExtraNode,
+                        std::move(extra_node_));
 }
 
 bool TestBookmarkClient::CanSetPermanentNodeTitle(
@@ -104,10 +97,10 @@
     const base::RepeatingClosure& schedule_save_closure) {}
 
 // static
-BookmarkPermanentNodeList TestBookmarkClient::LoadExtraNodes(
-    BookmarkPermanentNodeList extra_nodes,
+std::unique_ptr<BookmarkPermanentNode> TestBookmarkClient::LoadExtraNode(
+    std::unique_ptr<BookmarkPermanentNode> extra_node,
     int64_t* next_id) {
-  return extra_nodes;
+  return extra_node;
 }
 
 }  // namespace bookmarks
diff --git a/components/bookmarks/test/test_bookmark_client.h b/components/bookmarks/test/test_bookmark_client.h
index 40f8e9e..6f2a138 100644
--- a/components/bookmarks/test/test_bookmark_client.h
+++ b/components/bookmarks/test/test_bookmark_client.h
@@ -28,26 +28,24 @@
   static std::unique_ptr<BookmarkModel> CreateModelWithClient(
       std::unique_ptr<BookmarkClient> client);
 
-  // Sets the list of extra nodes to be returned by the next call to
-  // CreateModel() or GetLoadExtraNodesCallback().
-  void SetExtraNodesToLoad(BookmarkPermanentNodeList extra_nodes);
+  // Sets the extra node to be returned by the next call to CreateModel() or
+  // GetLoadExtraNodeCallback().
+  void SetExtraNodeToLoad(std::unique_ptr<BookmarkPermanentNode> extra_node);
 
-  // Returns the current extra_nodes, set via SetExtraNodesToLoad().
-  const std::vector<BookmarkPermanentNode*> extra_nodes() {
-    return unowned_extra_nodes_;
-  }
+  // Returns the current extra_node, set via SetExtraNodeToLoad().
+  BookmarkPermanentNode* extra_node() { return unowned_extra_node_; }
 
-  // Returns true if |node| is one of the |extra_nodes_|.
+  // Returns true if |node| is the |extra_node_|.
   bool IsExtraNodeRoot(const BookmarkNode* node);
 
-  // Returns true if |node| belongs to the tree of one of the |extra_nodes_|.
+  // Returns true if |node| belongs to the tree of the |extra_node_|.
   bool IsAnExtraNode(const BookmarkNode* node);
 
  private:
   // BookmarkClient:
   bool IsPermanentNodeVisible(const BookmarkPermanentNode* node) override;
   void RecordAction(const base::UserMetricsAction& action) override;
-  LoadExtraCallback GetLoadExtraNodesCallback() override;
+  LoadExtraCallback GetLoadExtraNodeCallback() override;
   bool CanSetPermanentNodeTitle(const BookmarkNode* permanent_node) override;
   bool CanSyncNode(const BookmarkNode* node) override;
   bool CanBeEditedByUser(const BookmarkNode* node) override;
@@ -56,13 +54,15 @@
       const std::string& metadata_str,
       const base::RepeatingClosure& schedule_save_closure) override;
 
-  // Helpers for GetLoadExtraNodesCallback().
-  static BookmarkPermanentNodeList LoadExtraNodes(
-      BookmarkPermanentNodeList extra_nodes,
+  // Helpers for GetLoadExtraNodeCallback().
+  static std::unique_ptr<BookmarkPermanentNode> LoadExtraNode(
+      std::unique_ptr<BookmarkPermanentNode> extra_node,
       int64_t* next_id);
 
-  BookmarkPermanentNodeList extra_nodes_;
-  std::vector<BookmarkPermanentNode*> unowned_extra_nodes_;
+  // extra_node_ exists only until GetLoadExtraNodeCallback gets called, but
+  // unowned_extra_node_ stays around after that.
+  std::unique_ptr<BookmarkPermanentNode> extra_node_;
+  BookmarkPermanentNode* unowned_extra_node_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(TestBookmarkClient);
 };
diff --git a/components/browser_sync/profile_sync_service_bookmark_unittest.cc b/components/browser_sync/profile_sync_service_bookmark_unittest.cc
index fe01b50..a37ce95 100644
--- a/components/browser_sync/profile_sync_service_bookmark_unittest.cc
+++ b/components/browser_sync/profile_sync_service_bookmark_unittest.cc
@@ -441,8 +441,8 @@
     managed_bookmark_service_->BookmarkModelCreated(model.get());
     int64_t next_id = 0;
     static_cast<bookmarks::TestBookmarkClient*>(model->client())
-        ->SetExtraNodesToLoad(
-            managed_bookmark_service_->GetLoadExtraNodesCallback().Run(
+        ->SetExtraNodeToLoad(
+            managed_bookmark_service_->GetLoadExtraNodeCallback().Run(
                 &next_id));
     if (delete_bookmarks) {
       base::DeleteFile(data_path.Append(FILE_PATH_LITERAL("dummy_bookmarks")),
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn
index 369127589..7299250 100644
--- a/components/cronet/android/BUILD.gn
+++ b/components/cronet/android/BUILD.gn
@@ -335,6 +335,33 @@
   ]
 }
 
+# cronet_impl_fake_base_java.jar - Fake implementation of Cronet.
+android_library("cronet_impl_fake_base_java") {
+  java_files = [ "fake/java/org/chromium/net/test/FakeUrlResponse.java" ]
+
+  deps = [
+    ":cronet_api_java",
+    ":cronet_impl_common_base_java",
+  ]
+}
+
+# cronet_fake_javatests.jar - Java tests for the fake implementation of Cronet.
+android_library("cronet_fake_javatests") {
+  testonly = true
+  java_files =
+      [ "fake/javatests/org/chromium/net/test/FakeUrlResponseTest.java" ]
+
+  deps = [
+    ":cronet_api_java",
+    ":cronet_impl_common_base_java",
+    ":cronet_impl_fake_base_java",
+    "//base:base_java_test_support",
+    "//third_party/android_sdk:android_test_base_java",
+    "//third_party/android_support_test_runner:runner_java",
+    "//third_party/junit",
+  ]
+}
+
 cronet_impl_native_java_srcjar_deps = [
   ":net_request_priority_java",
   ":network_quality_observation_source_java",
@@ -515,6 +542,15 @@
   ]
 }
 
+android_java_prebuilt("package_impl_fake_java") {
+  jar_path = "$_package_dir/cronet_impl_fake_java.jar"
+  deps = [
+    ":package_api_java",
+    ":package_impl_common_java",
+    ":repackage_fake",
+  ]
+}
+
 template("jar_src") {
   action(target_name) {
     _rebased_src_search_dirs =
@@ -612,6 +648,12 @@
   jar_path = "$_package_dir/cronet_impl_platform_java-src.jar"
 }
 
+jar_src("jar_cronet_impl_fake_java_source") {
+  src_search_dirs = [ "fake/java" ]
+  source_deps = [ ":cronet_impl_fake_base_java" ]
+  jar_path = "$_package_dir/cronet_impl_fake_java-src.jar"
+}
+
 # List of patterns of .class files to exclude from the jar.
 _jar_excluded_patterns = [
   # Excludes Android support libraries crbug.com/832770.
@@ -648,6 +690,13 @@
   ]
 }
 
+repackage_jars("repackage_fake") {
+  output = "$_package_dir/cronet_impl_fake_java.jar"
+  deps = [
+    ":cronet_impl_fake_base_java",
+  ]
+}
+
 repackage_jars("repackage_native") {
   output = "$_package_dir/cronet_impl_native_java.jar"
   deps = cronet_impl_native_java_deps_to_package + [
@@ -814,6 +863,7 @@
     "//net/android:net_java_test_support",
     "//url:url_java",
     "//third_party/junit",
+    ":cronet_fake_javatests",
   ]
 
   android_library("cronet_javatests") {
@@ -1220,6 +1270,7 @@
       ":cronet_api_java",
       ":cronet_combine_proguard_flags",
       ":cronet_impl_common_base_java",
+      ":cronet_impl_fake_base_java",
       ":cronet_impl_platform_base_java",
     ]
   }
@@ -1417,11 +1468,13 @@
         ":generate_licenses",
         ":jar_cronet_api_source",
         ":jar_cronet_impl_common_java_source",
+        ":jar_cronet_impl_fake_java_source",
         ":jar_cronet_impl_native_java_source",
         ":jar_cronet_impl_platform_java_source",
         ":jar_cronet_sample_source",
         ":repackage_api",
         ":repackage_common",
+        ":repackage_fake",
         ":repackage_native",
         ":repackage_platform",
       ]
diff --git a/components/cronet/android/api/src/org/chromium/net/UrlResponseInfo.java b/components/cronet/android/api/src/org/chromium/net/UrlResponseInfo.java
index 5dbcbe2..5c59950 100644
--- a/components/cronet/android/api/src/org/chromium/net/UrlResponseInfo.java
+++ b/components/cronet/android/api/src/org/chromium/net/UrlResponseInfo.java
@@ -16,6 +16,7 @@
 public abstract class UrlResponseInfo {
     /**
      * Unmodifiable container of response headers or trailers.
+     * {@hide}.
      */
     public abstract static class HeaderBlock {
         /**
diff --git a/components/cronet/android/fake/java/org/chromium/net/test/FakeUrlResponse.java b/components/cronet/android/fake/java/org/chromium/net/test/FakeUrlResponse.java
new file mode 100644
index 0000000..28412310
--- /dev/null
+++ b/components/cronet/android/fake/java/org/chromium/net/test/FakeUrlResponse.java
@@ -0,0 +1,275 @@
+// 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.net.test;
+
+import org.chromium.net.UrlResponseInfo;
+
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+// TODO(kirchman): Update this to explain inter-class usage once other classes land.
+/**
+ *
+ * Fake response model for UrlRequest used by Fake Cronet.
+ */
+public class FakeUrlResponse {
+    private final int mHttpStatusCode;
+    // Entries to mAllHeadersList should never be mutated.
+    private final List<Map.Entry<String, String>> mAllHeadersList;
+    private final boolean mWasCached;
+    private final String mNegotiatedProtocol;
+    private final String mProxyServer;
+    private final String mResponseBody;
+
+    private static <T extends Object> T getNullableOrDefault(T nullableObject, T defaultObject) {
+        if (nullableObject != null) {
+            return nullableObject;
+        }
+        return defaultObject;
+    }
+
+    /**
+     * Constructs a {@link FakeUrlResponse} from a {@link FakeUrlResponse.Builder}.
+     * @param builder the {@link FakeUrlResponse.Builder} to create the response from
+     */
+    private FakeUrlResponse(Builder builder) {
+        mHttpStatusCode = builder.mHttpStatusCode;
+        mAllHeadersList = Collections.unmodifiableList(new ArrayList<>(builder.mAllHeadersList));
+        mWasCached = builder.mWasCached;
+        mNegotiatedProtocol = builder.mNegotiatedProtocol;
+        mProxyServer = builder.mProxyServer;
+        mResponseBody = builder.mResponseBody;
+    }
+
+    /**
+     * Constructs a {@link FakeUrlResponse} from a {@link UrlResponseInfo}. All nullable fields in
+     * the {@link UrlResponseInfo} are initialized to the default value if the provided value is
+     * null.
+     *
+     * @param info the {@link UrlResponseInfo} used to initialize this object's fields
+     */
+    public FakeUrlResponse(UrlResponseInfo info) {
+        mHttpStatusCode = info.getHttpStatusCode();
+        mAllHeadersList = Collections.unmodifiableList(new ArrayList<>(info.getAllHeadersAsList()));
+        mWasCached = info.wasCached();
+        mNegotiatedProtocol = getNullableOrDefault(
+                info.getNegotiatedProtocol(), Builder.DEFAULT_NEGOTIATED_PROTOCOL);
+        mProxyServer = getNullableOrDefault(info.getProxyServer(), Builder.DEFAULT_PROXY_SERVER);
+        mResponseBody = Builder.DEFAULT_RESPONSE_BODY;
+    }
+
+    /**
+     * Builds a {@link FakeUrlResponse}.
+     */
+    public static class Builder {
+        private static final int DEFAULT_HTTP_STATUS_CODE = 200;
+        private static final List<Map.Entry<String, String>> INTERNAL_INITIAL_HEADERS_LIST =
+                new ArrayList<>();
+        private static final boolean DEFAULT_WAS_CACHED = false;
+        private static final String DEFAULT_NEGOTIATED_PROTOCOL = "";
+        private static final String DEFAULT_PROXY_SERVER = "";
+        private static final String DEFAULT_RESPONSE_BODY = "";
+
+        private int mHttpStatusCode = DEFAULT_HTTP_STATUS_CODE;
+        // Entries to mAllHeadersList should never be mutated.
+        private List<Map.Entry<String, String>> mAllHeadersList =
+                new ArrayList<>(INTERNAL_INITIAL_HEADERS_LIST);
+        private boolean mWasCached = DEFAULT_WAS_CACHED;
+        private String mNegotiatedProtocol = DEFAULT_NEGOTIATED_PROTOCOL;
+        private String mProxyServer = DEFAULT_PROXY_SERVER;
+        private String mResponseBody = DEFAULT_RESPONSE_BODY;
+
+        /**
+         * Constructs a {@link FakeUrlResponse.Builder} with the default parameters.
+         */
+        public Builder() {}
+
+        /**
+         * Constructs a {@link FakeUrlResponse.Builder} from a source {@link FakeUrlResponse}.
+         *
+         * @param source a {@link FakeUrlResponse} to copy into this {@link FakeUrlResponse.Builder}
+         */
+        private Builder(FakeUrlResponse source) {
+            mHttpStatusCode = source.getHttpStatusCode();
+            mAllHeadersList = new ArrayList<>(source.getAllHeadersList());
+            mWasCached = source.getWasCached();
+            mNegotiatedProtocol = source.getNegotiatedProtocol();
+            mProxyServer = source.getProxyServer();
+            mResponseBody = source.getResponseBody();
+        }
+
+        /**
+         * Sets the HTTP status code. The default value is 200.
+         *
+         * @param httpStatusCode for {@link UrlResponseInfo.getHttpStatusCode()}
+         * @return a builder with the corresponding HTTP status code set
+         */
+        public Builder setHttpStatusCode(int httpStatusCode) {
+            mHttpStatusCode = httpStatusCode;
+            return this;
+        }
+
+        /**
+         * Adds a response header to built {@link FakeUrlResponse}s.
+         *
+         * @param name  the name of the header key, for example, "location" for a redirect header
+         * @param value the header value
+         * @return a builder with the corresponding header set
+         */
+        public Builder addHeader(String name, String value) {
+            mAllHeadersList.add(new AbstractMap.SimpleEntry<>(name, value));
+            return this;
+        }
+
+        /**
+         * Sets result of {@link UrlResponseInfo.wasCached()}. The default wasCached value is false.
+         *
+         * @param wasCached for {@link UrlResponseInfo.wasCached()}
+         * @return a builder with the corresponding wasCached field set
+         */
+        public Builder setWasCached(boolean wasCached) {
+            mWasCached = wasCached;
+            return this;
+        }
+
+        /**
+         * Sets result of {@link UrlResponseInfo.getNegotiatedProtocol()}. The default negotiated
+         * protocol is an empty string.
+         *
+         * @param negotiatedProtocol for {@link UrlResponseInfo.getNegotiatedProtocol()}
+         * @return a builder with the corresponding negotiatedProtocol field set
+         */
+        public Builder setNegotiatedProtocol(String negotiatedProtocol) {
+            mNegotiatedProtocol = negotiatedProtocol;
+            return this;
+        }
+
+        /**
+         * Sets result of {@link UrlResponseInfo.getProxyServer()}. The default proxy server is an
+         * empty string.
+         *
+         * @param proxyServer for {@link UrlResponseInfo.getProxyServer()}
+         * @return a builder with the corresponding proxyServer field set
+         */
+        public Builder setProxyServer(String proxyServer) {
+            mProxyServer = proxyServer;
+            return this;
+        }
+
+        /**
+         * Sets the response body for a response. The default response body is an empty string.
+         *
+         * @param responseBody all the information the server returns
+         * @return a builder with the corresponding responseBody field set
+         */
+        public Builder setResponseBody(String responseBody) {
+            mResponseBody = responseBody;
+            return this;
+        }
+
+        /**
+         * Constructs a {@link FakeUrlResponse} from this {@link FakeUrlResponse.Builder}.
+         *
+         * @return a FakeUrlResponse with all fields set according to this builder
+         */
+        public FakeUrlResponse build() {
+            return new FakeUrlResponse(this);
+        }
+    }
+
+    /**
+     * Returns the HTTP status code.
+     *
+     * @return the HTTP status code.
+     */
+    int getHttpStatusCode() {
+        return mHttpStatusCode;
+    }
+
+    /**
+     * Returns an unmodifiable list of the response header key and value pairs.
+     *
+     * @return an unmodifiable list of response header key and value pairs
+     */
+    List<Map.Entry<String, String>> getAllHeadersList() {
+        return mAllHeadersList;
+    }
+
+    /**
+     * Returns the wasCached value for this response.
+     *
+     * @return the wasCached value for this response
+     */
+    boolean getWasCached() {
+        return mWasCached;
+    }
+
+    /**
+     * Returns the protocol (for example 'quic/1+spdy/3') negotiated with the server.
+     *
+     * @return the protocol negotiated with the server
+     */
+    String getNegotiatedProtocol() {
+        return mNegotiatedProtocol;
+    }
+
+    /**
+     * Returns the proxy server that was used for the request.
+     *
+     * @return the proxy server that was used for the request
+     */
+    String getProxyServer() {
+        return mProxyServer;
+    }
+
+    /**
+     * Returns the body of the response as a String. Used for {@link UrlRequest.Callback}
+     * {@code read()} callback.
+     *
+     * @return the response body
+     */
+    String getResponseBody() {
+        return mResponseBody;
+    }
+
+    /**
+     * Returns a mutable builder representation of this {@link FakeUrlResponse}
+     *
+     * @return a {@link FakeUrlResponse.Builder} with all fields copied from this instance.
+     */
+    public Builder toBuilder() {
+        return new Builder(this);
+    }
+
+    @Override
+    public boolean equals(Object otherObj) {
+        if (!(otherObj instanceof FakeUrlResponse)) {
+            return false;
+        }
+        FakeUrlResponse other = (FakeUrlResponse) otherObj;
+        return (mHttpStatusCode == other.mHttpStatusCode
+                && mAllHeadersList.equals(other.mAllHeadersList) && mWasCached == other.mWasCached
+                && mNegotiatedProtocol.equals(other.mNegotiatedProtocol)
+                && mProxyServer.equals(other.mProxyServer)
+                && mResponseBody.equals(other.mResponseBody));
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mHttpStatusCode, mAllHeadersList, mWasCached, mNegotiatedProtocol,
+                mProxyServer, mResponseBody);
+    }
+
+    @Override
+    public String toString() {
+        return "HTTP Status Code: " + mHttpStatusCode + " Headers: " + mAllHeadersList.toString()
+                + " Was Cached: " + mWasCached + " Negotiated Protocol: " + mNegotiatedProtocol
+                + " Proxy Server: " + mProxyServer + " Response Body: " + mResponseBody;
+    }
+}
diff --git a/components/cronet/android/fake/javatests/org/chromium/net/test/FakeUrlResponseTest.java b/components/cronet/android/fake/javatests/org/chromium/net/test/FakeUrlResponseTest.java
new file mode 100644
index 0000000..71c164a6
--- /dev/null
+++ b/components/cronet/android/fake/javatests/org/chromium/net/test/FakeUrlResponseTest.java
@@ -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.
+
+package org.chromium.net.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.BaseJUnit4ClassRunner;
+import org.chromium.net.UrlResponseInfo;
+import org.chromium.net.impl.UrlResponseInfoImpl;
+
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Test functionality of FakeUrlResponse.
+ */
+@RunWith(BaseJUnit4ClassRunner.class)
+public class FakeUrlResponseTest {
+    private static final int TEST_HTTP_STATUS_CODE = 201;
+    private static final String TEST_HEADER_NAME = "name";
+    private static final String TEST_HEADER_VALUE = "value";
+    private static final boolean TEST_WAS_CACHED = true;
+    private static final String TEST_NEGOTIATED_PROTOCOL = "test_negotiated_protocol";
+    private static final String TEST_PROXY_SERVER = "test_proxy_server";
+    private static final String TEST_BODY = "test_body";
+
+    List<Map.Entry<String, String>> mTestHeaders;
+    AbstractMap.SimpleEntry<String, String> mTestHeaderEntry;
+    FakeUrlResponse mTestResponse;
+
+    @Before
+    public void setUp() {
+        mTestHeaders = new ArrayList<>();
+        mTestHeaderEntry = new AbstractMap.SimpleEntry<>(TEST_HEADER_NAME, TEST_HEADER_VALUE);
+        mTestHeaders.add(mTestHeaderEntry);
+        mTestResponse = new FakeUrlResponse.Builder()
+                                .setHttpStatusCode(TEST_HTTP_STATUS_CODE)
+                                .setWasCached(TEST_WAS_CACHED)
+                                .addHeader(TEST_HEADER_NAME, TEST_HEADER_VALUE)
+                                .setNegotiatedProtocol(TEST_NEGOTIATED_PROTOCOL)
+                                .setProxyServer(TEST_PROXY_SERVER)
+                                .setResponseBody(TEST_BODY)
+                                .build();
+    }
+
+    @Test
+    @SmallTest
+    public void testAddHeader() {
+        FakeUrlResponse response = new FakeUrlResponse.Builder()
+                                           .addHeader(TEST_HEADER_NAME, TEST_HEADER_VALUE)
+                                           .build();
+
+        List<Map.Entry<String, String>> responseHeadersList = response.getAllHeadersList();
+
+        // mTestHeaderEntry is header entry of TEST_HEADER_NAME, TEST_HEADER_VALUE.
+        assertTrue(responseHeadersList.contains(mTestHeaderEntry));
+    }
+
+    @Test
+    @SmallTest
+    public void testEquals() {
+        FakeUrlResponse responseEqualToTestResponse = mTestResponse.toBuilder().build();
+        FakeUrlResponse responseNotEqualToTestResponse =
+                mTestResponse.toBuilder().setResponseBody("").build();
+
+        assertEquals(mTestResponse, mTestResponse);
+        assertEquals(mTestResponse, responseEqualToTestResponse);
+        assertNotEquals(mTestResponse, responseNotEqualToTestResponse);
+    }
+
+    @Test
+    @SmallTest
+    public void testHeadersNotShared() {
+        FakeUrlResponse.Builder responseBuilder = new FakeUrlResponse.Builder();
+        FakeUrlResponse response = responseBuilder.build();
+        FakeUrlResponse responseWithHeader =
+                responseBuilder.addHeader(TEST_HEADER_NAME, TEST_HEADER_VALUE).build();
+        List<Map.Entry<String, String>> responseHeadersList = response.getAllHeadersList();
+        List<Map.Entry<String, String>> responseHeadersListWithHeader =
+                responseWithHeader.getAllHeadersList();
+
+        assertNotEquals(responseHeadersListWithHeader, responseHeadersList);
+    }
+
+    @Test
+    @SmallTest
+    public void testSettingAllHeadersCopiesHeaderList() {
+        String nameNotInOriginalList = "nameNotInOriginalList";
+        String valueNotInOriginalList = "valueNotInOriginalList";
+        AbstractMap.SimpleEntry<String, String> entryNotInOriginalList =
+                new AbstractMap.SimpleEntry<>(nameNotInOriginalList, valueNotInOriginalList);
+
+        FakeUrlResponse testResponseWithHeader =
+                mTestResponse.toBuilder()
+                        .addHeader(nameNotInOriginalList, valueNotInOriginalList)
+                        .build();
+
+        assertFalse(mTestHeaders.contains(entryNotInOriginalList));
+        assertTrue(testResponseWithHeader.getAllHeadersList().contains(entryNotInOriginalList));
+    }
+
+    @Test
+    @SmallTest
+    public void testHashCodeReturnsSameIntForEqualObjects() {
+        FakeUrlResponse responseEqualToTest = mTestResponse.toBuilder().build();
+
+        assertEquals(mTestResponse.hashCode(), mTestResponse.hashCode());
+        assertEquals(mTestResponse.hashCode(), responseEqualToTest.hashCode());
+        // Two non-equivalent values can map to the same hashCode.
+    }
+
+    @Test
+    @SmallTest
+    public void testToString() {
+        String expectedString = "HTTP Status Code: " + TEST_HTTP_STATUS_CODE
+                + " Headers: " + mTestHeaders.toString() + " Was Cached: " + TEST_WAS_CACHED
+                + " Negotiated Protocol: " + TEST_NEGOTIATED_PROTOCOL
+                + " Proxy Server: " + TEST_PROXY_SERVER + " Response Body: " + TEST_BODY;
+        String responseToString = mTestResponse.toString();
+
+        assertEquals(expectedString, responseToString);
+    }
+
+    @Test
+    @SmallTest
+    public void testGetResponseWithUrlResponseInfo() {
+        UrlResponseInfo info = new UrlResponseInfoImpl(new ArrayList<>(), TEST_HTTP_STATUS_CODE, "",
+                mTestHeaders, TEST_WAS_CACHED, TEST_NEGOTIATED_PROTOCOL, TEST_PROXY_SERVER, 0);
+        FakeUrlResponse expectedResponse = new FakeUrlResponse.Builder()
+                                                   .setHttpStatusCode(TEST_HTTP_STATUS_CODE)
+                                                   .addHeader(TEST_HEADER_NAME, TEST_HEADER_VALUE)
+                                                   .setWasCached(TEST_WAS_CACHED)
+                                                   .setNegotiatedProtocol(TEST_NEGOTIATED_PROTOCOL)
+                                                   .setProxyServer(TEST_PROXY_SERVER)
+                                                   .build();
+
+        FakeUrlResponse constructedResponse = new FakeUrlResponse(info);
+
+        assertEquals(expectedResponse, constructedResponse);
+    }
+
+    @Test
+    @SmallTest
+    public void testGetResponesWithNullUrlResponseInfoGetsDefault() {
+        // Set params that cannot be null in UrlResponseInfo in the expected response so that the
+        // parameters found in the constructed response from UrlResponseInfo are the same
+        // as the expected.
+        FakeUrlResponse expectedResponse = new FakeUrlResponse.Builder()
+                                                   .setHttpStatusCode(TEST_HTTP_STATUS_CODE)
+                                                   .setWasCached(TEST_WAS_CACHED)
+                                                   .addHeader(TEST_HEADER_NAME, TEST_HEADER_VALUE)
+                                                   .build();
+        // UnmodifiableList cannot be null.
+        UrlResponseInfo info = new UrlResponseInfoImpl(/* UrlChain */ new ArrayList<>(),
+                TEST_HTTP_STATUS_CODE, null, mTestHeaders, TEST_WAS_CACHED, null, null, 0);
+
+        FakeUrlResponse constructedResponse = new FakeUrlResponse(info);
+
+        assertEquals(expectedResponse, constructedResponse);
+    }
+
+    @Test
+    @SmallTest
+    public void testInternalInitialHeadersListCantBeModified() {
+        FakeUrlResponse defaultResponseWithHeader =
+                new FakeUrlResponse.Builder()
+                        .addHeader(TEST_HEADER_NAME, TEST_HEADER_VALUE)
+                        .build();
+        FakeUrlResponse defaultResponse = new FakeUrlResponse.Builder().build();
+
+        assertNotEquals(
+                defaultResponse.getAllHeadersList(), defaultResponseWithHeader.getAllHeadersList());
+    }
+}
diff --git a/components/exo/BUILD.gn b/components/exo/BUILD.gn
index f8ecb57..e7c7799 100644
--- a/components/exo/BUILD.gn
+++ b/components/exo/BUILD.gn
@@ -147,6 +147,7 @@
     ":exo",
     "//base",
     "//base/test:test_support",
+    "//components/viz/service:service",
     "//gpu",
     "//skia",
     "//testing/gtest",
diff --git a/components/exo/pointer_unittest.cc b/components/exo/pointer_unittest.cc
index 623fdbe..70224cd0 100644
--- a/components/exo/pointer_unittest.cc
+++ b/components/exo/pointer_unittest.cc
@@ -18,11 +18,10 @@
 #include "components/exo/test/exo_test_base.h"
 #include "components/exo/test/exo_test_helper.h"
 #include "components/viz/common/quads/compositor_frame.h"
-#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
 #include "components/viz/service/surfaces/surface.h"
+#include "components/viz/service/surfaces/surface_manager.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "ui/aura/client/cursor_client.h"
-#include "ui/aura/env.h"
 #include "ui/events/event_utils.h"
 #include "ui/events/test/event_generator.h"
 #include "ui/views/widget/widget.h"
@@ -30,13 +29,6 @@
 namespace exo {
 namespace {
 
-viz::SurfaceManager* GetSurfaceManager() {
-  return aura::Env::GetInstance()
-      ->context_factory_private()
-      ->GetFrameSinkManager()
-      ->surface_manager();
-}
-
 class MockPointerDelegate : public PointerDelegate {
  public:
   MockPointerDelegate() {}
diff --git a/components/exo/surface_unittest.cc b/components/exo/surface_unittest.cc
index a54bc4a..871ddef 100644
--- a/components/exo/surface_unittest.cc
+++ b/components/exo/surface_unittest.cc
@@ -14,13 +14,12 @@
 #include "components/exo/test/exo_test_helper.h"
 #include "components/viz/common/quads/compositor_frame.h"
 #include "components/viz/common/quads/texture_draw_quad.h"
-#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
 #include "components/viz/service/surfaces/surface.h"
+#include "components/viz/service/surfaces/surface_manager.h"
 #include "components/viz/test/begin_frame_args_test.h"
 #include "components/viz/test/fake_external_begin_frame_source.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/khronos/GLES2/gl2.h"
-#include "ui/aura/env.h"
 #include "ui/compositor/layer_tree_owner.h"
 #include "ui/display/display.h"
 #include "ui/display/display_switches.h"
@@ -68,6 +67,13 @@
     return gfx::ConvertRectToPixel(device_scale_factor(), rect);
   }
 
+  const viz::CompositorFrame& GetFrameFromSurface(ShellSurface* shell_surface) {
+    viz::SurfaceId surface_id = shell_surface->host_window()->GetSurfaceId();
+    const viz::CompositorFrame& frame =
+        GetSurfaceManager()->GetSurfaceForId(surface_id)->GetActiveFrame();
+    return frame;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(SurfaceTest);
 };
@@ -114,17 +120,6 @@
   ASSERT_EQ(1, release_buffer_call_count);
 }
 
-const viz::CompositorFrame& GetFrameFromSurface(ShellSurface* shell_surface) {
-  viz::SurfaceId surface_id = shell_surface->host_window()->GetSurfaceId();
-  viz::SurfaceManager* surface_manager = aura::Env::GetInstance()
-                                             ->context_factory_private()
-                                             ->GetFrameSinkManager()
-                                             ->surface_manager();
-  const viz::CompositorFrame& frame =
-      surface_manager->GetSurfaceForId(surface_id)->GetActiveFrame();
-  return frame;
-}
-
 TEST_P(SurfaceTest, Damage) {
   gfx::Size buffer_size(256, 256);
   std::unique_ptr<Buffer> buffer(
diff --git a/components/exo/test/exo_test_base.cc b/components/exo/test/exo_test_base.cc
index 035d956..734b51f2 100644
--- a/components/exo/test/exo_test_base.cc
+++ b/components/exo/test/exo_test_base.cc
@@ -8,8 +8,11 @@
 #include "components/exo/test/exo_test_helper.h"
 #include "components/exo/wm_helper.h"
 #include "components/exo/wm_helper_chromeos.h"
+#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+#include "components/viz/service/surfaces/surface_manager.h"
 #include "ui/aura/env.h"
 #include "ui/base/ime/init/input_method_factory.h"
+#include "ui/compositor/test/in_process_context_factory.h"
 #include "ui/wm/core/wm_core_switches.h"
 
 namespace exo {
@@ -36,5 +39,12 @@
   AshTestBase::TearDown();
 }
 
+viz::SurfaceManager* ExoTestBase::GetSurfaceManager() {
+  return static_cast<ui::InProcessContextFactory*>(
+             aura::Env::GetInstance()->context_factory_private())
+      ->GetFrameSinkManager()
+      ->surface_manager();
+}
+
 }  // namespace test
 }  // namespace exo
diff --git a/components/exo/test/exo_test_base.h b/components/exo/test/exo_test_base.h
index ac2c1932..2507c3b6 100644
--- a/components/exo/test/exo_test_base.h
+++ b/components/exo/test/exo_test_base.h
@@ -11,6 +11,10 @@
 #include "base/macros.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
 
+namespace viz {
+class SurfaceManager;
+}
+
 namespace exo {
 class WMHelper;
 
@@ -26,6 +30,8 @@
   void SetUp() override;
   void TearDown() override;
 
+  viz::SurfaceManager* GetSurfaceManager();
+
   ExoTestHelper* exo_test_helper() { return exo_test_helper_.get(); }
 
  private:
diff --git a/components/exo/test/exo_test_base_views.cc b/components/exo/test/exo_test_base_views.cc
index 4fdd3fa..09f25a3 100644
--- a/components/exo/test/exo_test_base_views.cc
+++ b/components/exo/test/exo_test_base_views.cc
@@ -79,7 +79,10 @@
   void OnDragEntered(const ui::DropTargetEvent& event) override {}
   int OnDragUpdated(const ui::DropTargetEvent& event) override { return 0; }
   void OnDragExited() override {}
-  int OnPerformDrop(const ui::DropTargetEvent& event) override { return 0; }
+  int OnPerformDrop(const ui::DropTargetEvent& event,
+                    std::unique_ptr<ui::OSExchangeData> data) override {
+    return 0;
+  }
 
   // Overridden from VSyncTimingManager::Delegate:
   void AddVSyncParameterObserver(
diff --git a/components/exo/wm_helper.h b/components/exo/wm_helper.h
index 3a65d52..83f0b24 100644
--- a/components/exo/wm_helper.h
+++ b/components/exo/wm_helper.h
@@ -133,7 +133,8 @@
   void OnDragEntered(const ui::DropTargetEvent& event) override = 0;
   int OnDragUpdated(const ui::DropTargetEvent& event) override = 0;
   void OnDragExited() override = 0;
-  int OnPerformDrop(const ui::DropTargetEvent& event) override = 0;
+  int OnPerformDrop(const ui::DropTargetEvent& event,
+                    std::unique_ptr<ui::OSExchangeData> data) override = 0;
 
  protected:
   DISALLOW_COPY_AND_ASSIGN(WMHelper);
diff --git a/components/exo/wm_helper_chromeos.cc b/components/exo/wm_helper_chromeos.cc
index cc470fa..e53f60f 100644
--- a/components/exo/wm_helper_chromeos.cc
+++ b/components/exo/wm_helper_chromeos.cc
@@ -118,7 +118,8 @@
     observer.OnDragExited();
 }
 
-int WMHelperChromeOS::OnPerformDrop(const ui::DropTargetEvent& event) {
+int WMHelperChromeOS::OnPerformDrop(const ui::DropTargetEvent& event,
+                                    std::unique_ptr<ui::OSExchangeData> data) {
   for (DragDropObserver& observer : drag_drop_observers_)
     observer.OnPerformDrop(event);
   // TODO(hirono): Return the correct result instead of always returning
diff --git a/components/exo/wm_helper_chromeos.h b/components/exo/wm_helper_chromeos.h
index 8ce2a99..b628ee6c 100644
--- a/components/exo/wm_helper_chromeos.h
+++ b/components/exo/wm_helper_chromeos.h
@@ -103,7 +103,8 @@
   void OnDragEntered(const ui::DropTargetEvent& event) override;
   int OnDragUpdated(const ui::DropTargetEvent& event) override;
   void OnDragExited() override;
-  int OnPerformDrop(const ui::DropTargetEvent& event) override;
+  int OnPerformDrop(const ui::DropTargetEvent& event,
+                    std::unique_ptr<ui::OSExchangeData> data) override;
 
   // Overridden from VSyncTimingManager::Delegate:
   void AddVSyncParameterObserver(
diff --git a/components/feed/core/feed_logging_metrics.cc b/components/feed/core/feed_logging_metrics.cc
index 71b8d90..4f1ebcb4 100644
--- a/components/feed/core/feed_logging_metrics.cc
+++ b/components/feed/core/feed_logging_metrics.cc
@@ -691,7 +691,7 @@
   // TODO(https://crbug.com/935602): The max value here is fragile, figure out
   // some way to test the @IntDef size.
   UMA_HISTOGRAM_ENUMERATION("ContentSuggestions.Feed.InternalError",
-                            internal_error, 10);
+                            internal_error, 13);
 }
 
 void FeedLoggingMetrics::OnTokenCompleted(bool was_synthetic,
diff --git a/components/metrics/call_stack_profile_builder.cc b/components/metrics/call_stack_profile_builder.cc
index b35165d..0b40e5b0 100644
--- a/components/metrics/call_stack_profile_builder.cc
+++ b/components/metrics/call_stack_profile_builder.cc
@@ -48,7 +48,7 @@
 }
 
 std::map<uint64_t, int64_t> CreateMetadataMap(
-    base::MetadataRecorder::ItemArray items,
+    base::ProfileBuilder::MetadataItemArray items,
     size_t item_count) {
   std::map<uint64_t, int64_t> item_map;
   for (size_t i = 0; i < item_count; ++i) {
@@ -102,10 +102,8 @@
 CallStackProfileBuilder::CallStackProfileBuilder(
     const CallStackProfileParams& profile_params,
     const WorkIdRecorder* work_id_recorder,
-    const base::MetadataRecorder* metadata_recorder,
     base::OnceClosure completed_callback)
     : work_id_recorder_(work_id_recorder),
-      metadata_recorder_(metadata_recorder),
       profile_start_time_(base::TimeTicks::Now()) {
   completed_callback_ = std::move(completed_callback);
   sampled_profile_.set_process(
@@ -124,7 +122,8 @@
 // This function is invoked on the profiler thread while the target thread is
 // suspended so must not take any locks, including indirectly through use of
 // heap allocation, LOG, CHECK, or DCHECK.
-void CallStackProfileBuilder::RecordMetadata() {
+void CallStackProfileBuilder::RecordMetadata(
+    base::ProfileBuilder::MetadataProvider* metadata_provider) {
   if (work_id_recorder_) {
     unsigned int work_id = work_id_recorder_->RecordWorkId();
     // A work id of 0 indicates that the message loop has not yet started.
@@ -134,8 +133,8 @@
     }
   }
 
-  if (metadata_recorder_)
-    metadata_item_count_ = metadata_recorder_->GetItems(&metadata_items_);
+  if (metadata_provider)
+    metadata_item_count_ = metadata_provider->GetItems(&metadata_items_);
 }
 
 void CallStackProfileBuilder::OnSampleCompleted(
diff --git a/components/metrics/call_stack_profile_builder.h b/components/metrics/call_stack_profile_builder.h
index d141670..9de8401 100644
--- a/components/metrics/call_stack_profile_builder.h
+++ b/components/metrics/call_stack_profile_builder.h
@@ -57,7 +57,6 @@
   explicit CallStackProfileBuilder(
       const CallStackProfileParams& profile_params,
       const WorkIdRecorder* work_id_recorder = nullptr,
-      const base::MetadataRecorder* metadata_recorder = nullptr,
       base::OnceClosure completed_callback = base::OnceClosure());
 
   ~CallStackProfileBuilder() override;
@@ -69,7 +68,8 @@
 
   // base::ProfileBuilder:
   base::ModuleCache* GetModuleCache() override;
-  void RecordMetadata() override;
+  void RecordMetadata(base::ProfileBuilder::MetadataProvider*
+                          metadata_provider = nullptr) override;
   void OnSampleCompleted(std::vector<base::Frame> frames) override;
   void OnProfileCompleted(base::TimeDelta profile_duration,
                           base::TimeDelta sampling_period) override;
@@ -113,7 +113,6 @@
   unsigned int last_work_id_ = std::numeric_limits<unsigned int>::max();
   bool is_continued_work_ = false;
   const WorkIdRecorder* const work_id_recorder_;
-  const base::MetadataRecorder* const metadata_recorder_;
 
   // The SampledProfile protobuf message which contains the collected stack
   // samples.
@@ -135,7 +134,7 @@
   const base::TimeTicks profile_start_time_;
 
   // The data fetched from the MetadataRecorder for the next sample.
-  base::MetadataRecorder::ItemArray metadata_items_;
+  base::ProfileBuilder::MetadataItemArray metadata_items_;
   size_t metadata_item_count_ = 0;
   // The data fetched from the MetadataRecorder for the previous sample.
   std::map<uint64_t, int64_t> previous_items_;
diff --git a/components/metrics/call_stack_profile_builder_unittest.cc b/components/metrics/call_stack_profile_builder_unittest.cc
index 2d4900bb..c3788bf 100644
--- a/components/metrics/call_stack_profile_builder_unittest.cc
+++ b/components/metrics/call_stack_profile_builder_unittest.cc
@@ -53,7 +53,6 @@
   TestingCallStackProfileBuilder(
       const CallStackProfileParams& profile_params,
       const WorkIdRecorder* work_id_recorder = nullptr,
-      const base::MetadataRecorder* metadata_recorder = nullptr,
       base::OnceClosure completed_callback = base::OnceClosure());
 
   ~TestingCallStackProfileBuilder() override;
@@ -72,11 +71,9 @@
 TestingCallStackProfileBuilder::TestingCallStackProfileBuilder(
     const CallStackProfileParams& profile_params,
     const WorkIdRecorder* work_id_recorder,
-    const base::MetadataRecorder* metadata_recorder,
     base::OnceClosure completed_callback)
     : CallStackProfileBuilder(profile_params,
                               work_id_recorder,
-                              metadata_recorder,
                               std::move(completed_callback)) {}
 
 TestingCallStackProfileBuilder::~TestingCallStackProfileBuilder() = default;
@@ -94,7 +91,7 @@
   EXPECT_CALL(mock_closure, Run()).Times(1);
 
   auto profile_builder = std::make_unique<TestingCallStackProfileBuilder>(
-      kProfileParams, nullptr, nullptr, mock_closure.Get());
+      kProfileParams, nullptr, mock_closure.Get());
 
 #if defined(OS_WIN)
   uint64_t module_md5 = 0x46C3E4166659AC02ULL;
@@ -436,8 +433,8 @@
 
 TEST(CallStackProfileBuilderTest, MetadataRecorder_NoItems) {
   base::MetadataRecorder metadata_recorder;
-  auto profile_builder = std::make_unique<TestingCallStackProfileBuilder>(
-      kProfileParams, nullptr, &metadata_recorder);
+  auto profile_builder =
+      std::make_unique<TestingCallStackProfileBuilder>(kProfileParams, nullptr);
 
   TestModule module;
   base::Frame frame = {0x10, &module};
@@ -460,16 +457,22 @@
 
 TEST(CallStackProfileBuilderTest, MetadataRecorder_RepeatItem) {
   base::MetadataRecorder metadata_recorder;
-  auto profile_builder = std::make_unique<TestingCallStackProfileBuilder>(
-      kProfileParams, nullptr, &metadata_recorder);
+  auto profile_builder =
+      std::make_unique<TestingCallStackProfileBuilder>(kProfileParams, nullptr);
 
   TestModule module;
   base::Frame frame = {0x10, &module};
 
   metadata_recorder.Set(100, 10);
-  profile_builder->RecordMetadata();
+  {
+    auto get_items = metadata_recorder.CreateMetadataProvider();
+    profile_builder->RecordMetadata(get_items.get());
+  }
   profile_builder->OnSampleCompleted({frame});
-  profile_builder->RecordMetadata();
+  {
+    auto get_items = metadata_recorder.CreateMetadataProvider();
+    profile_builder->RecordMetadata(get_items.get());
+  }
   profile_builder->OnSampleCompleted({frame});
 
   profile_builder->OnProfileCompleted(base::TimeDelta::FromMilliseconds(500),
@@ -496,17 +499,23 @@
 
 TEST(CallStackProfileBuilderTest, MetadataRecorder_ModifiedItem) {
   base::MetadataRecorder metadata_recorder;
-  auto profile_builder = std::make_unique<TestingCallStackProfileBuilder>(
-      kProfileParams, nullptr, &metadata_recorder);
+  auto profile_builder =
+      std::make_unique<TestingCallStackProfileBuilder>(kProfileParams, nullptr);
 
   TestModule module;
   base::Frame frame = {0x10, &module};
 
   metadata_recorder.Set(100, 10);
-  profile_builder->RecordMetadata();
+  {
+    auto get_items = metadata_recorder.CreateMetadataProvider();
+    profile_builder->RecordMetadata(get_items.get());
+  }
   profile_builder->OnSampleCompleted({frame});
   metadata_recorder.Set(100, 11);
-  profile_builder->RecordMetadata();
+  {
+    auto get_items = metadata_recorder.CreateMetadataProvider();
+    profile_builder->RecordMetadata(get_items.get());
+  }
   profile_builder->OnSampleCompleted({frame});
 
   profile_builder->OnProfileCompleted(base::TimeDelta::FromMilliseconds(500),
@@ -536,19 +545,25 @@
 
 TEST(CallStackProfileBuilderTest, MetadataRecorder_NewItem) {
   base::MetadataRecorder metadata_recorder;
-  auto profile_builder = std::make_unique<TestingCallStackProfileBuilder>(
-      kProfileParams, nullptr, &metadata_recorder);
+  auto profile_builder =
+      std::make_unique<TestingCallStackProfileBuilder>(kProfileParams, nullptr);
 
   TestModule module;
   base::Frame frame = {0x10, &module};
 
   metadata_recorder.Set(100, 10);
-  profile_builder->RecordMetadata();
+  {
+    auto get_items = metadata_recorder.CreateMetadataProvider();
+    profile_builder->RecordMetadata(get_items.get());
+  }
   profile_builder->OnSampleCompleted({frame});
 
   metadata_recorder.Set(100, 11);
   metadata_recorder.Set(200, 20);
-  profile_builder->RecordMetadata();
+  {
+    auto get_items = metadata_recorder.CreateMetadataProvider();
+    profile_builder->RecordMetadata(get_items.get());
+  }
   profile_builder->OnSampleCompleted({frame});
 
   profile_builder->OnProfileCompleted(base::TimeDelta::FromMilliseconds(500),
@@ -582,17 +597,23 @@
 
 TEST(CallStackProfileBuilderTest, MetadataRecorder_RemovedItem) {
   base::MetadataRecorder metadata_recorder;
-  auto profile_builder = std::make_unique<TestingCallStackProfileBuilder>(
-      kProfileParams, nullptr, &metadata_recorder);
+  auto profile_builder =
+      std::make_unique<TestingCallStackProfileBuilder>(kProfileParams, nullptr);
 
   TestModule module;
   base::Frame frame = {0x10, &module};
 
   metadata_recorder.Set(100, 10);
-  profile_builder->RecordMetadata();
+  {
+    auto get_items = metadata_recorder.CreateMetadataProvider();
+    profile_builder->RecordMetadata(get_items.get());
+  }
   profile_builder->OnSampleCompleted({frame});
   metadata_recorder.Remove(100);
-  profile_builder->RecordMetadata();
+  {
+    auto get_items = metadata_recorder.CreateMetadataProvider();
+    profile_builder->RecordMetadata(get_items.get());
+  }
   profile_builder->OnSampleCompleted({frame});
 
   profile_builder->OnProfileCompleted(base::TimeDelta::FromMilliseconds(500),
diff --git a/components/omnibox/browser/document_provider.cc b/components/omnibox/browser/document_provider.cc
index 4782b32..98ae801 100644
--- a/components/omnibox/browser/document_provider.cc
+++ b/components/omnibox/browser/document_provider.cc
@@ -551,7 +551,7 @@
   // https://docs.google.com/[a/domain.tld/]document/d/(id)/[...]
   // https://docs.google.com/[a/domain.tld/]spreadsheets/d/(id)/edit#gid=12345
   // https://docs.google.com/[a/domain.tld/]presentation/d/(id)/edit#slide=id.g12345a_0_26
-  // https://www.google.com/url?[...]url=https://drive.google.com/a/domain.tld/open?id%3D(id)[&...]
+  // https://www.google.com/url?[...]url=https://drive.google.com/a/domain.tld/open?id%3D(id)[%26D...][&...]
   // where id is comprised of characters in [0-9A-Za-z\-_] = [\w\-]
   std::string id;
 
@@ -568,7 +568,7 @@
     // Redirect links wrapping a drive.google.com/open?id= link.
     static re2::LazyRE2 redirect_link_regex = {
         "^[^#]*url=https://drive\\.google\\.com/(?:a/[\\w\\.]+/"
-        ")?open\\?id%3D([^#&]*)"};
+        ")?open\\?id%3D(.*?)(?:%26|#|&|$)"};
     RE2::PartialMatch(url.query(), *redirect_link_regex, &id);
   }
 
diff --git a/components/omnibox/browser/document_provider_unittest.cc b/components/omnibox/browser/document_provider_unittest.cc
index 5f6b5eacf..9ad43e22 100644
--- a/components/omnibox/browser/document_provider_unittest.cc
+++ b/components/omnibox/browser/document_provider_unittest.cc
@@ -673,6 +673,10 @@
       "https://www.google.com/url?url=https://drive.google.com/"
       "open?id%3Dthe_doc_id",
       "the_doc_id");
+  CheckDeduper(
+      "https://www.google.com/url?url=https://drive.google.com/"
+      "open?id%3Dthe_doc_id%26Dusp%3Dchrome_omnibox",
+      "the_doc_id");
 
   // URLs that do not represent documents:
   CheckDeduper("https://drive.google.com/b/domain.com/open?id=the_doc-id", "");
diff --git a/components/password_manager/core/browser/BUILD.gn b/components/password_manager/core/browser/BUILD.gn
index 5678327..6734e40af 100644
--- a/components/password_manager/core/browser/BUILD.gn
+++ b/components/password_manager/core/browser/BUILD.gn
@@ -47,6 +47,8 @@
     "blacklisted_credentials_cleaner.h",
     "browser_save_password_progress_logger.cc",
     "browser_save_password_progress_logger.h",
+    "credential_cache.cc",
+    "credential_cache.h",
     "credential_manager_impl.cc",
     "credential_manager_impl.h",
     "credential_manager_logger.cc",
@@ -105,6 +107,8 @@
     "manage_passwords_referrer.h",
     "new_password_form_manager.cc",
     "new_password_form_manager.h",
+    "origin_credential_store.cc",
+    "origin_credential_store.h",
     "password_autofill_manager.cc",
     "password_autofill_manager.h",
     "password_bubble_experiment.cc",
@@ -457,6 +461,7 @@
     "android_affiliation/facet_manager_unittest.cc",
     "blacklisted_credentials_cleaner_unittest.cc",
     "browser_save_password_progress_logger_unittest.cc",
+    "credential_cache_unittest.cc",
     "credential_manager_impl_unittest.cc",
     "credential_manager_logger_unittest.cc",
     "credential_manager_password_form_manager_unittest.cc",
@@ -478,6 +483,7 @@
     "log_router_unittest.cc",
     "login_database_unittest.cc",
     "new_password_form_manager_unittest.cc",
+    "origin_credential_store_unittest.cc",
     "password_autofill_manager_unittest.cc",
     "password_bubble_experiment_unittest.cc",
     "password_form_filling_unittest.cc",
diff --git a/components/password_manager/core/browser/credential_cache.cc b/components/password_manager/core/browser/credential_cache.cc
new file mode 100644
index 0000000..f84e6076
--- /dev/null
+++ b/components/password_manager/core/browser/credential_cache.cc
@@ -0,0 +1,65 @@
+// 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/password_manager/core/browser/credential_cache.h"
+
+#include <algorithm>
+#include <iterator>
+#include <map>
+#include <utility>
+#include <vector>
+
+#include "components/autofill/core/common/autofill_features.h"
+#include "components/autofill/core/common/password_form.h"
+
+namespace password_manager {
+
+CredentialCache::CredentialCache() = default;
+CredentialCache::~CredentialCache() = default;
+
+void CredentialCache::SaveCredentialsForOrigin(
+    const std::map<base::string16, const autofill::PasswordForm*>& best_matches,
+    const url::Origin& origin) {
+  std::vector<CredentialPair> credentials;
+  std::transform(best_matches.begin(), best_matches.end(),
+                 std::back_inserter(credentials), [](const auto& pair) {
+                   return CredentialPair(pair.second->username_value,
+                                         pair.second->password_value,
+                                         pair.second->origin,
+                                         pair.second->is_public_suffix_match);
+                 });
+  // Sort by origin (but keep the existing username order).
+  std::stable_sort(credentials.begin(), credentials.end(),
+                   [](const CredentialPair& lhs, const CredentialPair& rhs) {
+                     return lhs.origin_url < rhs.origin_url;
+                   });
+  // Move credentials with exactly matching origins to the top.
+  std::stable_partition(credentials.begin(), credentials.end(),
+                        [o = origin.GetURL()](const CredentialPair& pair) {
+                          return pair.origin_url == o;
+                        });
+  GetOrCreateCredentialStore(origin)->SaveCredentials(std::move(credentials));
+}
+
+const OriginCredentialStore* CredentialCache::GetCredentialStore(
+    const url::Origin& origin) {
+  return GetOrCreateCredentialStore(origin);
+}
+
+void CredentialCache::ClearCredentials() {
+  origin_credentials_.clear();
+}
+
+OriginCredentialStore* CredentialCache::GetOrCreateCredentialStore(
+    const url::Origin& origin) {
+  auto it = origin_credentials_.find(origin);
+  if (it != origin_credentials_.end())
+    return it->second.get();
+  auto iter =
+      origin_credentials_
+          .insert({origin, std::make_unique<OriginCredentialStore>(origin)})
+          .first;
+  return iter->second.get();
+}
+}  // namespace password_manager
diff --git a/components/password_manager/core/browser/credential_cache.h b/components/password_manager/core/browser/credential_cache.h
new file mode 100644
index 0000000..0fc25c0
--- /dev/null
+++ b/components/password_manager/core/browser/credential_cache.h
@@ -0,0 +1,54 @@
+// 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_PASSWORD_MANAGER_CORE_BROWSER_CREDENTIAL_CACHE_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_CREDENTIAL_CACHE_H_
+
+#include <map>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "components/password_manager/core/browser/origin_credential_store.h"
+#include "url/origin.h"
+
+namespace autofill {
+struct PasswordForm;
+}  // namespace autofill
+
+namespace password_manager {
+
+// This class caches and provides credential stores for different origins.
+class CredentialCache {
+ public:
+  CredentialCache();
+  ~CredentialCache();
+  CredentialCache(const CredentialCache&) = delete;
+  CredentialCache& operator=(const CredentialCache&) = delete;
+
+  // Saves credentials for an origin so that they can be used in the sheet.
+  void SaveCredentialsForOrigin(
+      const std::map<base::string16, const autofill::PasswordForm*>& matches,
+      const url::Origin& origin);
+
+  // Returns the credential store for a given origin. If it does not exist, an
+  // empty store will be created.
+  const OriginCredentialStore* GetCredentialStore(const url::Origin& origin);
+
+  // Removes all credentials for all origins.
+  void ClearCredentials();
+
+ private:
+  OriginCredentialStore* GetOrCreateCredentialStore(const url::Origin& origin);
+
+  // Contains the store for credential of each requested origin.
+  std::map<url::Origin, std::unique_ptr<OriginCredentialStore>>
+      origin_credentials_;
+};
+
+}  // namespace password_manager
+
+#endif  // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_CREDENTIAL_CACHE_H_
diff --git a/components/password_manager/core/browser/credential_cache_unittest.cc b/components/password_manager/core/browser/credential_cache_unittest.cc
new file mode 100644
index 0000000..998865d
--- /dev/null
+++ b/components/password_manager/core/browser/credential_cache_unittest.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 "components/password_manager/core/browser/credential_cache.h"
+
+#include <memory>
+#include <string>
+
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/common/password_form.h"
+#include "components/password_manager/core/browser/password_manager_test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace password_manager {
+
+using autofill::PasswordForm;
+using base::ASCIIToUTF16;
+using url::Origin;
+
+constexpr char kExampleSiteAndroidApp[] = "android://3x4mpl3@com.example.app/";
+constexpr char kExampleSite[] = "https://example.com";
+constexpr char kExampleSite2[] = "https://example.two.com";
+constexpr char kExampleSiteMobile[] = "https://m.example.com";
+constexpr char kExampleSiteSubdomain[] = "https://accounts.example.com";
+
+class CredentialCacheTest : public testing::Test {
+ public:
+  CredentialCache* cache() { return &cache_; }
+
+ private:
+  CredentialCache cache_;
+};
+
+TEST_F(CredentialCacheTest, ReturnsSameStoreForSameOriginOnly) {
+  EXPECT_EQ(cache()->GetCredentialStore(Origin::Create(GURL(kExampleSite))),
+            cache()->GetCredentialStore(Origin::Create(GURL(kExampleSite))));
+
+  EXPECT_NE(cache()->GetCredentialStore(Origin::Create(GURL(kExampleSite))),
+            cache()->GetCredentialStore(Origin::Create(GURL(kExampleSite2))));
+}
+
+TEST_F(CredentialCacheTest, StoresCredentialsSortedByAplhabetAndOrigins) {
+  Origin origin = Origin::Create(GURL(kExampleSite));
+  cache()->SaveCredentialsForOrigin(
+      {CreateEntry("Berta", "30948", GURL(kExampleSite), false).first,
+       CreateEntry("Adam", "Pas83B", GURL(kExampleSite), false).first,
+       CreateEntry("Dora", "PakudC", GURL(kExampleSite), false).first,
+       CreateEntry("Carl", "P1238C", GURL(kExampleSite), false).first,
+       // These entries need to be ordered but come after the examples above.
+       CreateEntry("Cesar", "V3V1V", GURL(kExampleSiteAndroidApp), false).first,
+       CreateEntry("Rolf", "A4nd0m", GURL(kExampleSiteMobile), true).first,
+       CreateEntry("Greg", "5fnd1m", GURL(kExampleSiteSubdomain), true).first,
+       CreateEntry("Elfi", "a65ddm", GURL(kExampleSiteSubdomain), true).first,
+       CreateEntry("Alf", "R4nd50m", GURL(kExampleSiteMobile), true).first},
+      origin);
+
+  EXPECT_THAT(
+      cache()->GetCredentialStore(origin)->GetCredentials(),
+      testing::ElementsAre(
+
+          // Alphabetical entries of the exactly matching https://example.com:
+          CredentialPair(ASCIIToUTF16("Adam"), ASCIIToUTF16("Pas83B"),
+                         GURL(kExampleSite), /*is_psl_match*/ false),
+          CredentialPair(ASCIIToUTF16("Berta"), ASCIIToUTF16("30948"),
+                         GURL(kExampleSite), /*is_psl_match*/ false),
+          CredentialPair(ASCIIToUTF16("Carl"), ASCIIToUTF16("P1238C"),
+                         GURL(kExampleSite), /*is_psl_match*/ false),
+          CredentialPair(ASCIIToUTF16("Dora"), ASCIIToUTF16("PakudC"),
+                         GURL(kExampleSite), /*is_psl_match*/ false),
+
+          // Entry for PSL-match android://3x4mpl3@com.example.app:
+          CredentialPair(ASCIIToUTF16("Cesar"), ASCIIToUTF16("V3V1V"),
+                         GURL(kExampleSiteAndroidApp), /*is_psl_match*/ false),
+
+          // Alphabetical entries of PSL-match https://accounts.example.com:
+          CredentialPair(ASCIIToUTF16("Elfi"), ASCIIToUTF16("a65ddm"),
+                         GURL(kExampleSiteSubdomain), /*is_psl_match*/ true),
+          CredentialPair(ASCIIToUTF16("Greg"), ASCIIToUTF16("5fnd1m"),
+                         GURL(kExampleSiteSubdomain), /*is_psl_match*/ true),
+
+          // Alphabetical entries of PSL-match https://m.example.com:
+          CredentialPair(ASCIIToUTF16("Alf"), ASCIIToUTF16("R4nd50m"),
+                         GURL(kExampleSiteMobile), /*is_psl_match*/ true),
+          CredentialPair(ASCIIToUTF16("Rolf"), ASCIIToUTF16("A4nd0m"),
+                         GURL(kExampleSiteMobile), /*is_psl_match*/ true)));
+}
+
+TEST_F(CredentialCacheTest, StoredCredentialsForIndependentOrigins) {
+  Origin origin = Origin::Create(GURL(kExampleSite));
+  Origin origin2 = Origin::Create(GURL(kExampleSite2));
+
+  cache()->SaveCredentialsForOrigin(
+      {CreateEntry("Ben", "S3cur3", GURL(kExampleSite), false).first}, origin);
+  cache()->SaveCredentialsForOrigin(
+      {CreateEntry("Abe", "B4dPW", GURL(kExampleSite2), false).first}, origin2);
+
+  EXPECT_THAT(cache()->GetCredentialStore(origin)->GetCredentials(),
+              testing::ElementsAre(
+                  CredentialPair(ASCIIToUTF16("Ben"), ASCIIToUTF16("S3cur3"),
+                                 GURL(kExampleSite), /*is_psl_match*/ false)));
+  EXPECT_THAT(cache()->GetCredentialStore(origin2)->GetCredentials(),
+              testing::ElementsAre(
+                  CredentialPair(ASCIIToUTF16("Abe"), ASCIIToUTF16("B4dPW"),
+                                 GURL(kExampleSite2), /*is_psl_match*/ false)));
+}
+
+TEST_F(CredentialCacheTest, ClearsCredentials) {
+  Origin origin = Origin::Create(GURL(kExampleSite));
+  cache()->SaveCredentialsForOrigin(
+      {CreateEntry("Ben", "S3cur3", GURL(kExampleSite), false).first},
+      Origin::Create(GURL(kExampleSite)));
+  ASSERT_THAT(cache()->GetCredentialStore(origin)->GetCredentials(),
+              testing::ElementsAre(
+                  CredentialPair(ASCIIToUTF16("Ben"), ASCIIToUTF16("S3cur3"),
+                                 GURL(kExampleSite), /*is_psl_match*/ false)));
+
+  cache()->ClearCredentials();
+  EXPECT_EQ(cache()->GetCredentialStore(origin)->GetCredentials().size(), 0u);
+}
+
+}  // namespace password_manager
diff --git a/components/password_manager/core/browser/http_auth_manager_unittest.cc b/components/password_manager/core/browser/http_auth_manager_unittest.cc
index ba08e4fe..af68ae9 100644
--- a/components/password_manager/core/browser/http_auth_manager_unittest.cc
+++ b/components/password_manager/core/browser/http_auth_manager_unittest.cc
@@ -53,9 +53,9 @@
 
   MOCK_CONST_METHOD1(IsSavingAndFillingEnabled, bool(const GURL&));
   MOCK_CONST_METHOD1(IsFillingEnabled, bool(const GURL&));
-  MOCK_CONST_METHOD2(AutofillHttpAuth,
-                     void(const autofill::PasswordForm&,
-                          const PasswordFormManagerForUI*));
+  MOCK_METHOD2(AutofillHttpAuth,
+               void(const autofill::PasswordForm&,
+                    const PasswordFormManagerForUI*));
   MOCK_CONST_METHOD0(GetPasswordStore, PasswordStore*());
   MOCK_METHOD0(PromptUserToSaveOrUpdatePasswordPtr, void());
 
diff --git a/components/password_manager/core/browser/new_password_form_manager.cc b/components/password_manager/core/browser/new_password_form_manager.cc
index f9a1a02..ceda1d6 100644
--- a/components/password_manager/core/browser/new_password_form_manager.cc
+++ b/components/password_manager/core/browser/new_password_form_manager.cc
@@ -712,7 +712,7 @@
   // TODO(https://crbug.com/831123): Implement correct treating of federated
   // matches.
   std::vector<const PasswordForm*> federated_matches;
-  SendFillInformationToRenderer(*client_, driver_.get(), IsBlacklisted(),
+  SendFillInformationToRenderer(client_, driver_.get(), IsBlacklisted(),
                                 *observed_password_form.get(), best_matches_,
                                 federated_matches, preferred_match_,
                                 metrics_recorder_.get());
diff --git a/components/password_manager/core/browser/new_password_form_manager_unittest.cc b/components/password_manager/core/browser/new_password_form_manager_unittest.cc
index 8b7aaf1..86e4129 100644
--- a/components/password_manager/core/browser/new_password_form_manager_unittest.cc
+++ b/components/password_manager/core/browser/new_password_form_manager_unittest.cc
@@ -117,9 +117,8 @@
 
   MOCK_METHOD0(UpdateFormManagers, void());
 
-  MOCK_CONST_METHOD2(AutofillHttpAuth,
-                     void(const PasswordForm&,
-                          const PasswordFormManagerForUI*));
+  MOCK_METHOD2(AutofillHttpAuth,
+               void(const PasswordForm&, const PasswordFormManagerForUI*));
 };
 
 void CheckPendingCredentials(const PasswordForm& expected,
diff --git a/components/password_manager/core/browser/origin_credential_store.cc b/components/password_manager/core/browser/origin_credential_store.cc
new file mode 100644
index 0000000..87937ff3
--- /dev/null
+++ b/components/password_manager/core/browser/origin_credential_store.cc
@@ -0,0 +1,68 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/password_manager/core/browser/origin_credential_store.h"
+
+#include <utility>
+#include <vector>
+
+#include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h"
+#include "url/gurl.h"
+
+namespace password_manager {
+namespace {
+
+GURL GetAndroidOrOriginURL(const GURL& url) {
+  if (IsValidAndroidFacetURI(url.spec()))
+    return url;  // Pass android origins as they are.
+  return url.GetOrigin();
+}
+
+}  // namespace
+
+CredentialPair::CredentialPair(base::string16 username,
+                               base::string16 password,
+                               const GURL& origin_url,
+                               bool is_public_suffix_match)
+    : username(std::move(username)),
+      password(std::move(password)),
+      origin_url(GetAndroidOrOriginURL(origin_url)),
+      is_public_suffix_match(is_public_suffix_match) {}
+CredentialPair::CredentialPair(CredentialPair&&) = default;
+CredentialPair::CredentialPair(const CredentialPair&) = default;
+CredentialPair& CredentialPair::operator=(CredentialPair&&) = default;
+CredentialPair& CredentialPair::operator=(const CredentialPair&) = default;
+
+bool CredentialPair::operator==(const CredentialPair& rhs) const {
+  return username == rhs.username && password == rhs.password &&
+         origin_url == rhs.origin_url &&
+         is_public_suffix_match == rhs.is_public_suffix_match;
+}
+
+std::ostream& operator<<(std::ostream& os, const CredentialPair& pair) {
+  os << "(user: \"" << pair.username << "\", "
+     << "pwd: \"" << pair.password << "\", "
+     << "origin: \"" << pair.origin_url << "\", "
+     << (pair.is_public_suffix_match ? "PSL-" : "exact origin ") << "match)";
+  return os;
+}
+
+OriginCredentialStore::OriginCredentialStore(url::Origin origin)
+    : origin_(origin) {}
+OriginCredentialStore::~OriginCredentialStore() = default;
+
+void OriginCredentialStore::SaveCredentials(
+    std::vector<CredentialPair> credentials) {
+  credentials_ = std::move(credentials);
+}
+
+base::span<const CredentialPair> OriginCredentialStore::GetCredentials() const {
+  return base::make_span<>(credentials_);
+}
+
+void OriginCredentialStore::ClearCredentials() {
+  credentials_.clear();
+}
+
+}  // namespace password_manager
diff --git a/components/password_manager/core/browser/origin_credential_store.h b/components/password_manager/core/browser/origin_credential_store.h
new file mode 100644
index 0000000..8c838ed
--- /dev/null
+++ b/components/password_manager/core/browser/origin_credential_store.h
@@ -0,0 +1,72 @@
+// 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_PASSWORD_MANAGER_CORE_BROWSER_ORIGIN_CREDENTIAL_STORE_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_ORIGIN_CREDENTIAL_STORE_H_
+
+#include <map>
+#include <utility>
+#include <vector>
+
+#include "base/containers/span.h"
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace password_manager {
+
+// Encapsulates the data from the password manager backend as used by the UI.
+struct CredentialPair {
+  CredentialPair(base::string16 username,
+                 base::string16 password,
+                 const GURL& origin_url,
+                 bool is_public_suffix_match);
+  CredentialPair(CredentialPair&&);
+  CredentialPair(const CredentialPair&);
+  CredentialPair& operator=(CredentialPair&&);
+  CredentialPair& operator=(const CredentialPair&);
+  bool operator==(const CredentialPair& rhs) const;
+
+  base::string16 username;
+  base::string16 password;
+  GURL origin_url;  // Could be android:// which url::Origin doesn't support.
+  bool is_public_suffix_match;
+};
+
+std::ostream& operator<<(std::ostream& os, const CredentialPair& pair);
+
+// This class stores credential pairs originating from the same origin. The
+// store is supposed to be unique per origin per tab. It is designed to share
+// credentials without creating unnecessary copies.
+class OriginCredentialStore {
+ public:
+  explicit OriginCredentialStore(url::Origin origin);
+  ~OriginCredentialStore();
+  OriginCredentialStore(const OriginCredentialStore&) = delete;
+  OriginCredentialStore& operator=(const OriginCredentialStore&) = delete;
+
+  // Saves credentials so that they can be used in the UI.
+  void SaveCredentials(std::vector<CredentialPair> credentials);
+
+  // Returns references to the held credentials (or an empty set if aren't any).
+  base::span<const CredentialPair> GetCredentials() const;
+
+  // Removes all credentials from the store.
+  void ClearCredentials();
+
+  // Returns the origin that this store keeps credentials for.
+  const url::Origin& origin() const { return origin_; }
+
+ private:
+  // Contains all previously stored of credentials.
+  std::vector<CredentialPair> credentials_;
+
+  // The origin which all stored passwords are related to.
+  const url::Origin origin_;
+};
+
+}  // namespace password_manager
+
+#endif  // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_ORIGIN_CREDENTIAL_STORE_H_
diff --git a/components/password_manager/core/browser/origin_credential_store_unittest.cc b/components/password_manager/core/browser/origin_credential_store_unittest.cc
new file mode 100644
index 0000000..99aba3a
--- /dev/null
+++ b/components/password_manager/core/browser/origin_credential_store_unittest.cc
@@ -0,0 +1,101 @@
+// 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/password_manager/core/browser/origin_credential_store.h"
+
+#include <memory>
+#include <string>
+
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace password_manager {
+namespace {
+
+using base::ASCIIToUTF16;
+using testing::ElementsAre;
+
+constexpr char kExampleSite[] = "https://example.com";
+constexpr char kExampleSiteAndroidApp[] = "android://3x4mpl3@com.example.app/";
+
+CredentialPair CreateCredentials(std::string username, std::string password) {
+  return CredentialPair(base::ASCIIToUTF16(std::move(username)),
+                        base::ASCIIToUTF16(std::move(password)),
+                        GURL(kExampleSite), /*is_psl_match=*/false);
+}
+
+}  // namespace
+
+class OriginCredentialStoreTest : public testing::Test {
+ public:
+  OriginCredentialStore* store() { return &store_; }
+
+ private:
+  OriginCredentialStore store_{url::Origin::Create(GURL(kExampleSite))};
+};
+
+TEST_F(OriginCredentialStoreTest, StoresCredentials) {
+  store()->SaveCredentials({CreateCredentials("Berta", "30948"),
+                            CreateCredentials("Adam", "Pas83B"),
+                            CreateCredentials("Dora", "PakudC"),
+                            CreateCredentials("Carl", "P1238C")});
+
+  EXPECT_THAT(store()->GetCredentials(),
+              ElementsAre(CreateCredentials("Berta", "30948"),
+                          CreateCredentials("Adam", "Pas83B"),
+                          CreateCredentials("Dora", "PakudC"),
+                          CreateCredentials("Carl", "P1238C")));
+}
+
+TEST_F(OriginCredentialStoreTest, StoresOnlyNormalizedOrigins) {
+  store()->SaveCredentials(
+      {CredentialPair(base::ASCIIToUTF16("Berta"), base::ASCIIToUTF16("30948"),
+                      GURL(kExampleSite), /*is_psl_match=*/false),
+       CredentialPair(base::ASCIIToUTF16("Adam"), base::ASCIIToUTF16("Pas83B"),
+                      GURL(kExampleSite).Resolve("/agbs"),
+                      /*is_psl_match=*/false),
+       CredentialPair(base::ASCIIToUTF16("Dora"), base::ASCIIToUTF16("PakudC"),
+                      GURL(kExampleSiteAndroidApp), /*is_psl_match=*/false)});
+
+  EXPECT_THAT(store()->GetCredentials(),
+              ElementsAre(
+
+                  // The URL that equals an origin stays untouched.
+                  CredentialPair(base::ASCIIToUTF16("Berta"),
+                                 base::ASCIIToUTF16("30948"),
+                                 GURL(kExampleSite), /*is_psl_match=*/false),
+
+                  // The longer URL is reduced to an origin.
+                  CredentialPair(base::ASCIIToUTF16("Adam"),
+                                 base::ASCIIToUTF16("Pas83B"),
+                                 GURL(kExampleSite), /*is_psl_match=*/false),
+
+                  // The android origin stays untouched.
+                  CredentialPair(
+                      base::ASCIIToUTF16("Dora"), base::ASCIIToUTF16("PakudC"),
+                      GURL(kExampleSiteAndroidApp), /*is_psl_match=*/false)));
+}
+
+TEST_F(OriginCredentialStoreTest, ReplacesCredentials) {
+  store()->SaveCredentials({CreateCredentials("Ben", "S3cur3")});
+  ASSERT_THAT(store()->GetCredentials(),
+              ElementsAre(CreateCredentials("Ben", "S3cur3")));
+
+  store()->SaveCredentials({CreateCredentials(std::string(), "M1@u")});
+  EXPECT_THAT(store()->GetCredentials(),
+              ElementsAre(CreateCredentials(std::string(), "M1@u")));
+}
+
+TEST_F(OriginCredentialStoreTest, ClearsCredentials) {
+  store()->SaveCredentials({CreateCredentials("Ben", "S3cur3")});
+  ASSERT_THAT(store()->GetCredentials(),
+              ElementsAre(CreateCredentials("Ben", "S3cur3")));
+
+  store()->ClearCredentials();
+  EXPECT_EQ(store()->GetCredentials().size(), 0u);
+}
+
+}  // namespace password_manager
diff --git a/components/password_manager/core/browser/password_form_filling.cc b/components/password_manager/core/browser/password_form_filling.cc
index 680d821..19269a8 100644
--- a/components/password_manager/core/browser/password_form_filling.cc
+++ b/components/password_manager/core/browser/password_form_filling.cc
@@ -45,7 +45,7 @@
       password_manager::features::kFillOnAccountSelect);
 }
 
-void Autofill(const PasswordManagerClient& client,
+void Autofill(PasswordManagerClient* client,
               PasswordManagerDriver* driver,
               const PasswordForm& form_for_autofill,
               const std::map<base::string16, const PasswordForm*>& best_matches,
@@ -55,8 +55,9 @@
   DCHECK_EQ(PasswordForm::Scheme::kHtml, preferred_match.scheme);
 
   std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
-  if (password_manager_util::IsLoggingActive(&client)) {
-    logger.reset(new BrowserSavePasswordProgressLogger(client.GetLogManager()));
+  if (password_manager_util::IsLoggingActive(client)) {
+    logger.reset(
+        new BrowserSavePasswordProgressLogger(client->GetLogManager()));
     logger->LogMessage(Logger::STRING_PASSWORDMANAGER_AUTOFILL);
   }
 
@@ -71,8 +72,8 @@
       PreferredRealmIsFromAndroid(fill_data));
   driver->FillPasswordForm(fill_data);
 
-  client.PasswordWasAutofilled(best_matches, form_for_autofill.origin,
-                               &federated_matches);
+  client->PasswordWasAutofilled(best_matches, form_for_autofill.origin,
+                                &federated_matches);
 }
 
 void ShowInitialPasswordAccountSuggestions(
@@ -101,7 +102,7 @@
 }  // namespace
 
 LikelyFormFilling SendFillInformationToRenderer(
-    const PasswordManagerClient& client,
+    PasswordManagerClient* client,
     PasswordManagerDriver* driver,
     bool is_blacklisted,
     const PasswordForm& observed_form,
@@ -146,7 +147,7 @@
   // insecure.
   const bool enable_foas_on_http =
       base::FeatureList::IsEnabled(features::kFillOnAccountSelectHttp) &&
-      !client.IsMainFrameSecure();
+      !client->IsMainFrameSecure();
 
   // Suppress autofilling on Android in case the Touch To Fill feature is
   // enabled.
@@ -165,7 +166,7 @@
       PasswordFormMetricsRecorder::WaitForUsernameReason;
   WaitForUsernameReason wait_for_username_reason =
       WaitForUsernameReason::kDontWait;
-  if (client.IsIncognito()) {
+  if (client->IsIncognito()) {
     wait_for_username_reason = WaitForUsernameReason::kIncognitoMode;
   } else if (preferred_match->is_public_suffix_match) {
     wait_for_username_reason = WaitForUsernameReason::kPublicSuffixMatch;
@@ -207,7 +208,7 @@
     // found usernames and passwords on load, this instructs the renderer to
     // return with any found password forms so a list of password account
     // suggestions can be drawn.
-    ShowInitialPasswordAccountSuggestions(client, driver, observed_form,
+    ShowInitialPasswordAccountSuggestions(*client, driver, observed_form,
                                           best_matches, *preferred_match,
                                           wait_for_username);
     return LikelyFormFilling::kShowInitialAccountSuggestions;
diff --git a/components/password_manager/core/browser/password_form_filling.h b/components/password_manager/core/browser/password_form_filling.h
index ac03bd4..87647eb 100644
--- a/components/password_manager/core/browser/password_form_filling.h
+++ b/components/password_manager/core/browser/password_form_filling.h
@@ -40,7 +40,7 @@
 };
 
 LikelyFormFilling SendFillInformationToRenderer(
-    const PasswordManagerClient& client,
+    PasswordManagerClient* client,
     PasswordManagerDriver* driver,
     bool is_blacklisted,
     const autofill::PasswordForm& observed_form,
diff --git a/components/password_manager/core/browser/password_form_filling_unittest.cc b/components/password_manager/core/browser/password_form_filling_unittest.cc
index 147d3b4..42fa14e 100644
--- a/components/password_manager/core/browser/password_form_filling_unittest.cc
+++ b/components/password_manager/core/browser/password_form_filling_unittest.cc
@@ -47,10 +47,10 @@
  public:
   MockPasswordManagerClient() {}
 
-  MOCK_CONST_METHOD3(PasswordWasAutofilled,
-                     void(const std::map<base::string16, const PasswordForm*>&,
-                          const GURL&,
-                          const std::vector<const PasswordForm*>*));
+  MOCK_METHOD3(PasswordWasAutofilled,
+               void(const std::map<base::string16, const PasswordForm*>&,
+                    const GURL&,
+                    const std::vector<const PasswordForm*>*));
 };
 
 }  // namespace
@@ -102,7 +102,7 @@
   EXPECT_CALL(driver_, ShowInitialPasswordAccountSuggestions(_)).Times(0);
 
   LikelyFormFilling likely_form_filling = SendFillInformationToRenderer(
-      client_, &driver_, false /* is_blacklisted */, observed_form_,
+      &client_, &driver_, false /* is_blacklisted */, observed_form_,
       best_matches, federated_matches_, nullptr, metrics_recorder_.get());
   EXPECT_EQ(LikelyFormFilling::kNoFilling, likely_form_filling);
 }
@@ -123,7 +123,7 @@
     EXPECT_CALL(client_, PasswordWasAutofilled(_, _, _));
 
     LikelyFormFilling likely_form_filling = SendFillInformationToRenderer(
-        client_, &driver_, is_blacklisted, observed_form_, best_matches,
+        &client_, &driver_, is_blacklisted, observed_form_, best_matches,
         federated_matches_, &saved_match_, metrics_recorder_.get());
     EXPECT_EQ(LikelyFormFilling::kFillOnPageLoad, likely_form_filling);
 
@@ -192,7 +192,7 @@
     EXPECT_CALL(client_, PasswordWasAutofilled(_, _, _));
 
     LikelyFormFilling likely_form_filling = SendFillInformationToRenderer(
-        client_, &driver_, false, observed_form, best_matches,
+        &client_, &driver_, false, observed_form, best_matches,
         federated_matches_, &saved_match_, metrics_recorder_.get());
 
     // In all cases where a current password exists, fill on load should be
@@ -216,7 +216,7 @@
   EXPECT_CALL(client_, PasswordWasAutofilled(_, _, _));
 
   LikelyFormFilling likely_form_filling = SendFillInformationToRenderer(
-      client_, &driver_, false /* is_blacklisted */, observed_form_,
+      &client_, &driver_, false /* is_blacklisted */, observed_form_,
       best_matches, federated_matches_, &psl_saved_match_,
       metrics_recorder_.get());
   EXPECT_EQ(LikelyFormFilling::kFillOnAccountSelect, likely_form_filling);
@@ -245,7 +245,7 @@
                                   enable_foas_http);
 
     LikelyFormFilling likely_form_filling = SendFillInformationToRenderer(
-        client_, &driver_, false /* is_blacklisted */, observed_form_,
+        &client_, &driver_, false /* is_blacklisted */, observed_form_,
         best_matches, federated_matches_, &saved_match_,
         metrics_recorder_.get());
     EXPECT_EQ(enable_foas_http ? LikelyFormFilling::kFillOnAccountSelect
@@ -266,7 +266,7 @@
                                   enable_touch_to_fill);
 
     LikelyFormFilling likely_form_filling = SendFillInformationToRenderer(
-        client_, &driver_, false /* is_blacklisted */, observed_form_,
+        &client_, &driver_, false /* is_blacklisted */, observed_form_,
         best_matches, federated_matches_, &saved_match_,
         metrics_recorder_.get());
     EXPECT_EQ(enable_touch_to_fill ? LikelyFormFilling::kFillOnAccountSelect
diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc
index 9524e00..81a50d01 100644
--- a/components/password_manager/core/browser/password_form_manager.cc
+++ b/components/password_manager/core/browser/password_form_manager.cc
@@ -556,7 +556,7 @@
     return;
   if (!driver)
     return;
-  SendFillInformationToRenderer(*client_, driver.get(), IsBlacklisted(),
+  SendFillInformationToRenderer(client_, driver.get(), IsBlacklisted(),
                                 observed_form_, best_matches_,
                                 form_fetcher_->GetFederatedMatches(),
                                 preferred_match_, GetMetricsRecorder());
diff --git a/components/password_manager/core/browser/password_manager_client.cc b/components/password_manager/core/browser/password_manager_client.cc
index 493fa60..e3b40e4 100644
--- a/components/password_manager/core/browser/password_manager_client.cc
+++ b/components/password_manager/core/browser/password_manager_client.cc
@@ -37,12 +37,11 @@
 void PasswordManagerClient::PasswordWasAutofilled(
     const std::map<base::string16, const autofill::PasswordForm*>& best_matches,
     const GURL& origin,
-    const std::vector<const autofill::PasswordForm*>* federated_matches) const {
-}
+    const std::vector<const autofill::PasswordForm*>* federated_matches) {}
 
 void PasswordManagerClient::AutofillHttpAuth(
     const autofill::PasswordForm& preferred_match,
-    const PasswordFormManagerForUI* form_manager) const {}
+    const PasswordFormManagerForUI* form_manager) {}
 
 SyncState PasswordManagerClient::GetPasswordSyncState() const {
   return NOT_SYNCING;
diff --git a/components/password_manager/core/browser/password_manager_client.h b/components/password_manager/core/browser/password_manager_client.h
index d888cca..33eb7698 100644
--- a/components/password_manager/core/browser/password_manager_client.h
+++ b/components/password_manager/core/browser/password_manager_client.h
@@ -187,14 +187,12 @@
       const std::map<base::string16, const autofill::PasswordForm*>&
           best_matches,
       const GURL& origin,
-      const std::vector<const autofill::PasswordForm*>* federated_matches)
-      const;
+      const std::vector<const autofill::PasswordForm*>* federated_matches);
 
   // Sends username/password from |preferred_match| for filling in the http auth
   // prompt.
-  virtual void AutofillHttpAuth(
-      const autofill::PasswordForm& preferred_match,
-      const PasswordFormManagerForUI* form_manager) const;
+  virtual void AutofillHttpAuth(const autofill::PasswordForm& preferred_match,
+                                const PasswordFormManagerForUI* form_manager);
 
   // Gets prefs associated with this embedder.
   virtual PrefService* GetPrefs() const = 0;
diff --git a/components/password_manager/core/browser/password_manager_test_utils.cc b/components/password_manager/core/browser/password_manager_test_utils.cc
index 9557530e..20ee9ab 100644
--- a/components/password_manager/core/browser/password_manager_test_utils.cc
+++ b/components/password_manager/core/browser/password_manager_test_utils.cc
@@ -8,6 +8,7 @@
 #include <memory>
 #include <ostream>
 #include <string>
+#include <utility>
 
 #include "base/feature_list.h"
 #include "base/strings/string_util.h"
@@ -61,6 +62,22 @@
   return form;
 }
 
+std::pair<std::pair<base::string16, const autofill::PasswordForm*>,
+          std::unique_ptr<const autofill::PasswordForm>>
+CreateEntry(const std::string& username,
+            const std::string& password,
+            const GURL& origin_url,
+            bool is_psl_match) {
+  auto form = std::make_unique<autofill::PasswordForm>();
+  form->username_value = base::ASCIIToUTF16(username);
+  form->password_value = base::ASCIIToUTF16(password);
+  form->origin = origin_url;
+  form->is_public_suffix_match = is_psl_match;
+  auto username_form_pair =
+      std::make_pair(base::ASCIIToUTF16(username), form.get());
+  return {std::move(username_form_pair), std::move(form)};
+}
+
 bool ContainsEqualPasswordFormsUnordered(
     const std::vector<std::unique_ptr<PasswordForm>>& expectations,
     const std::vector<std::unique_ptr<PasswordForm>>& actual_values,
diff --git a/components/password_manager/core/browser/password_manager_test_utils.h b/components/password_manager/core/browser/password_manager_test_utils.h
index 889d835..6f40e9f 100644
--- a/components/password_manager/core/browser/password_manager_test_utils.h
+++ b/components/password_manager/core/browser/password_manager_test_utils.h
@@ -11,8 +11,10 @@
 #include "base/feature_list.h"
 #include "base/memory/ref_counted.h"
 #include "components/autofill/core/common/password_form.h"
+#include "components/password_manager/core/browser/origin_credential_store.h"
 #include "components/password_manager/core/browser/password_store.h"
 #include "testing/gmock/include/gmock/gmock.h"
+#include "url/gurl.h"
 
 #if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
 #include "components/password_manager/core/browser/password_hash_data.h"  // nogncheck
@@ -61,6 +63,16 @@
     const PasswordFormData& form_data,
     bool use_federated_login = false);
 
+// Creates a new map entry in the |first| element of the returned pair. The
+// |second| element holds the PasswordForm that the |first| element points to.
+// That way, the pointer only points to a valid address in the called scope.
+std::pair<std::pair<base::string16, const autofill::PasswordForm*>,
+          std::unique_ptr<const autofill::PasswordForm>>
+CreateEntry(const std::string& username,
+            const std::string& password,
+            const GURL& origin_url,
+            bool is_psl_match);
+
 // Checks whether the PasswordForms pointed to in |actual_values| are in some
 // permutation pairwise equal to those in |expectations|. Returns true in case
 // of a perfect match; otherwise returns false and writes details of mismatches
diff --git a/components/password_manager/core/browser/password_manager_unittest.cc b/components/password_manager/core/browser/password_manager_unittest.cc
index 01d57a9..0cd65c2 100644
--- a/components/password_manager/core/browser/password_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_manager_unittest.cc
@@ -104,9 +104,9 @@
 
   MOCK_CONST_METHOD1(IsSavingAndFillingEnabled, bool(const GURL&));
   MOCK_CONST_METHOD0(GetMainFrameCertStatus, net::CertStatus());
-  MOCK_CONST_METHOD2(AutofillHttpAuth,
-                     void(const autofill::PasswordForm&,
-                          const PasswordFormManagerForUI*));
+  MOCK_METHOD2(AutofillHttpAuth,
+               void(const autofill::PasswordForm&,
+                    const PasswordFormManagerForUI*));
   MOCK_CONST_METHOD0(GetPasswordStore, PasswordStore*());
   // The code inside EXPECT_CALL for PromptUserToSaveOrUpdatePasswordPtr and
   // ShowManualFallbackForSavingPtr owns the PasswordFormManager* argument.
diff --git a/components/policy_strings.grdp b/components/policy_strings.grdp
index 706b3a9..619ce16f 100644
--- a/components/policy_strings.grdp
+++ b/components/policy_strings.grdp
@@ -492,4 +492,13 @@
   <message name="IDS_POLICY_IS_AFFILIATED_NO" desc="Indicates the user is not affiliated.">
     No
   </message>
+  <message name="IDS_POLICY_LABEL_IS_OFFHOURS_ACTIVE" desc="Label to indicate if the off-hours policy is active or not.">
+    Off-Hours Policy:
+  </message>
+  <message name="IDS_POLICY_OFFHOURS_ACTIVE" desc="Indicates the off-hours policy is active.">
+    Active
+  </message>
+  <message name="IDS_POLICY_OFFHOURS_NOT_ACTIVE" desc="Indicates the off-hours policy is not active.">
+    Not active
+  </message>
 </grit-part>
diff --git a/components/safe_browsing/triggers/ad_popup_trigger.cc b/components/safe_browsing/triggers/ad_popup_trigger.cc
index a3b134bb..e67f3fe 100644
--- a/components/safe_browsing/triggers/ad_popup_trigger.cc
+++ b/components/safe_browsing/triggers/ad_popup_trigger.cc
@@ -30,6 +30,8 @@
 
 namespace safe_browsing {
 
+namespace {
+
 // Number of milliseconds to allow data collection to run before sending a
 // report (since this trigger runs in the background).
 const int64_t kAdPopupCollectionPeriodMilliseconds = 5000;
@@ -39,6 +41,12 @@
 const int64_t kMaxAdPopupCollectionStartDelayMilliseconds = 5000;
 const int64_t kMinAdPopupCollectionStartDelayMilliseconds = 500;
 
+void RecordAdPopupTriggerAction(AdPopupTriggerAction action) {
+  UMA_HISTOGRAM_ENUMERATION(kAdPopupTriggerActionMetricName, action);
+}
+
+}  // namespace
+
 // Metric for tracking what the Ad Popup trigger does on each navigation.
 const char kAdPopupTriggerActionMetricName[] =
     "SafeBrowsing.Triggers.AdPopup.Action";
@@ -94,12 +102,10 @@
           TriggerType::AD_POPUP, web_contents_, resource, url_loader_factory_,
           history_service_, error_options, &reason)) {
     if (reason == TriggerManagerReason::DAILY_QUOTA_EXCEEDED) {
-      UMA_HISTOGRAM_ENUMERATION(
-          kAdPopupTriggerActionMetricName,
+      RecordAdPopupTriggerAction(
           AdPopupTriggerAction::POPUP_DAILY_QUOTA_EXCEEDED);
     } else {
-      UMA_HISTOGRAM_ENUMERATION(
-          kAdPopupTriggerActionMetricName,
+      RecordAdPopupTriggerAction(
           AdPopupTriggerAction::POPUP_COULD_NOT_START_REPORT);
     }
     return;
@@ -117,16 +123,13 @@
           /*did_proceed=*/false, /*num_visits=*/0, error_options),
       base::TimeDelta::FromMilliseconds(finish_report_delay_ms_));
 
-  UMA_HISTOGRAM_ENUMERATION(kAdPopupTriggerActionMetricName,
-                            AdPopupTriggerAction::POPUP_REPORTED);
+  RecordAdPopupTriggerAction(AdPopupTriggerAction::POPUP_REPORTED);
 }
 
 void AdPopupTrigger::PopupWasBlocked(content::RenderFrameHost* render_frame) {
-  UMA_HISTOGRAM_ENUMERATION(kAdPopupTriggerActionMetricName,
-                            AdPopupTriggerAction::POPUP_CHECK);
+  RecordAdPopupTriggerAction(AdPopupTriggerAction::POPUP_CHECK);
   if (!DetectGoogleAd(render_frame, web_contents_->GetURL())) {
-    UMA_HISTOGRAM_ENUMERATION(kAdPopupTriggerActionMetricName,
-                              AdPopupTriggerAction::POPUP_NO_GOOGLE_AD);
+    RecordAdPopupTriggerAction(AdPopupTriggerAction::POPUP_NO_GOOGLE_AD);
     return;
   }
   // Create a report after a short delay. The delay gives more time for ads to
diff --git a/components/sync/base/pref_names.cc b/components/sync/base/pref_names.cc
index cae0453..65f15e0 100644
--- a/components/sync/base/pref_names.cc
+++ b/components/sync/base/pref_names.cc
@@ -76,9 +76,12 @@
 // sync.
 const char kSyncManaged[] = "sync.managed";
 
-// Boolean to prevent sync from automatically starting up.  This is
-// used when sync is disabled by the user in sync settings.
-const char kSyncSuppressStart[] = "sync.suppress_start";
+// Boolean whether has requested sync to be enabled. This is set early in the
+// sync setup flow, after the user has pressed "turn on sync" but before they
+// have accepted the confirmation dialog (that maps to kSyncFirstSetupComplete).
+// This is also set to false when sync is disabled by the user in sync settings,
+// or when sync was reset from the dashboard.
+const char kSyncRequested[] = "sync.requested";
 
 // A string that can be used to restore sync encryption infrastructure on
 // startup so that the user doesn't need to provide credentials on each start.
diff --git a/components/sync/base/pref_names.h b/components/sync/base/pref_names.h
index 02901dbe..c35d408 100644
--- a/components/sync/base/pref_names.h
+++ b/components/sync/base/pref_names.h
@@ -59,7 +59,7 @@
 extern const char kSyncWifiCredentials[];
 
 extern const char kSyncManaged[];
-extern const char kSyncSuppressStart[];
+extern const char kSyncRequested[];
 
 extern const char kSyncEncryptionBootstrapToken[];
 extern const char kSyncKeystoreEncryptionBootstrapToken[];
diff --git a/components/sync/base/sync_prefs.cc b/components/sync/base/sync_prefs.cc
index db4744b..0fc405c 100644
--- a/components/sync/base/sync_prefs.cc
+++ b/components/sync/base/sync_prefs.cc
@@ -42,6 +42,11 @@
 const char kSyncSpareBootstrapToken[] = "sync.spare_bootstrap_token";
 #endif  // defined(OS_CHROMEOS)
 
+// Obsolete pref that used to store if sync should be prevented from
+// automatically starting up. This is now replaced by its inverse
+// kSyncRequested.
+const char kSyncSuppressStart[] = "sync.suppress_start";
+
 std::vector<std::string> GetObsoleteUserTypePrefs() {
   return {prefs::kSyncAutofillProfile,
           prefs::kSyncAutofillWallet,
@@ -128,9 +133,9 @@
       prefs::kSyncFirstSetupComplete, pref_service_,
       base::BindRepeating(&SyncPrefs::OnFirstSetupCompletePrefChange,
                           base::Unretained(this)));
-  pref_sync_suppressed_.Init(
-      prefs::kSyncSuppressStart, pref_service_,
-      base::BindRepeating(&SyncPrefs::OnSyncSuppressedPrefChange,
+  pref_sync_requested_.Init(
+      prefs::kSyncRequested, pref_service_,
+      base::BindRepeating(&SyncPrefs::OnSyncRequestedPrefChange,
                           base::Unretained(this)));
 
   // Cache the value of the kEnableLocalSyncBackend pref to avoid it flipping
@@ -148,7 +153,7 @@
     user_prefs::PrefRegistrySyncable* registry) {
   // Actual user-controlled preferences.
   registry->RegisterBooleanPref(prefs::kSyncFirstSetupComplete, false);
-  registry->RegisterBooleanPref(prefs::kSyncSuppressStart, false);
+  registry->RegisterBooleanPref(prefs::kSyncRequested, false);
   registry->RegisterBooleanPref(prefs::kSyncKeepEverythingSynced, true);
   for (UserSelectableType type : UserSelectableTypeSet::All()) {
     RegisterTypeSelectedPref(registry, type);
@@ -186,6 +191,7 @@
 #if defined(OS_CHROMEOS)
   registry->RegisterStringPref(kSyncSpareBootstrapToken, "");
 #endif
+  registry->RegisterBooleanPref(kSyncSuppressStart, false);
 }
 
 void SyncPrefs::AddSyncPrefObserver(SyncPrefObserver* sync_pref_observer) {
@@ -242,15 +248,12 @@
 
 bool SyncPrefs::IsSyncRequested() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  // IsSyncRequested is the inverse of the old SuppressStart pref.
-  // Since renaming a pref value is hard, here we still use the old one.
-  return !pref_service_->GetBoolean(prefs::kSyncSuppressStart);
+  return pref_service_->GetBoolean(prefs::kSyncRequested);
 }
 
 void SyncPrefs::SetSyncRequested(bool is_requested) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  // See IsSyncRequested for why we use this pref and !is_requested.
-  pref_service_->SetBoolean(prefs::kSyncSuppressStart, !is_requested);
+  pref_service_->SetBoolean(prefs::kSyncRequested, is_requested);
 }
 
 void SyncPrefs::SetSyncRequestedIfNotSetExplicitly() {
@@ -258,8 +261,8 @@
   // GetUserPrefValue() returns nullptr if there is no user-set value for this
   // pref (there might still be a non-default value, e.g. from a policy, but we
   // explicitly don't care about that here).
-  if (!pref_service_->GetUserPrefValue(prefs::kSyncSuppressStart)) {
-    pref_service_->SetBoolean(prefs::kSyncSuppressStart, false);
+  if (!pref_service_->GetUserPrefValue(prefs::kSyncRequested)) {
+    pref_service_->SetBoolean(prefs::kSyncRequested, true);
   }
 }
 
@@ -380,11 +383,10 @@
     observer.OnFirstSetupCompletePrefChange(*pref_first_setup_complete_);
 }
 
-void SyncPrefs::OnSyncSuppressedPrefChange() {
+void SyncPrefs::OnSyncRequestedPrefChange() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  // Note: The pref is inverted for historic reasons; see IsSyncRequested.
   for (SyncPrefObserver& observer : sync_pref_observers_)
-    observer.OnSyncRequestedPrefChange(!*pref_sync_suppressed_);
+    observer.OnSyncRequestedPrefChange(*pref_sync_requested_);
 }
 
 void SyncPrefs::SetManagedForTest(bool is_managed) {
@@ -540,4 +542,39 @@
 }
 #endif  // defined(OS_CHROMEOS)
 
+void MigrateSyncSuppressedPref(PrefService* pref_service) {
+  // If the new kSyncRequested already has a value, there's nothing to be
+  // done: Either the migration already happened, or we wrote to the new pref
+  // directly.
+  if (pref_service->GetUserPrefValue(prefs::kSyncRequested)) {
+    return;
+  }
+
+  // If the old kSyncSuppressed has an explicit value, migrate it over.
+  if (pref_service->GetUserPrefValue(kSyncSuppressStart)) {
+    pref_service->SetBoolean(prefs::kSyncRequested,
+                             !pref_service->GetBoolean(kSyncSuppressStart));
+    pref_service->ClearPref(kSyncSuppressStart);
+    DCHECK(pref_service->GetUserPrefValue(prefs::kSyncRequested));
+    return;
+  }
+
+  // Neither old nor new pref have an explicit value. There should be nothing to
+  // migrate, but it turns out some users are in a state that depends on the
+  // implicit default value of the old pref (which was that Sync is NOT
+  // suppressed, i.e. Sync is requested), see crbug.com/973770. To migrate these
+  // users to the new pref correctly, use kSyncFirstSetupComplete as a signal
+  // that Sync should be considered requested.
+  if (pref_service->GetBoolean(prefs::kSyncFirstSetupComplete)) {
+    // CHECK rather than DCHECK to make sure we never accidentally enable Sync
+    // for users which had it previously disabled.
+    CHECK(!pref_service->GetBoolean(kSyncSuppressStart));
+    pref_service->SetBoolean(prefs::kSyncRequested, true);
+    DCHECK(pref_service->GetUserPrefValue(prefs::kSyncRequested));
+    return;
+  }
+  // Otherwise, nothing to be done: Sync was likely never enabled in this
+  // profile.
+}
+
 }  // namespace syncer
diff --git a/components/sync/base/sync_prefs.h b/components/sync/base/sync_prefs.h
index d9a27afb..02bc54d 100644
--- a/components/sync/base/sync_prefs.h
+++ b/components/sync/base/sync_prefs.h
@@ -187,7 +187,7 @@
 
   void OnSyncManagedPrefChanged();
   void OnFirstSetupCompletePrefChange();
-  void OnSyncSuppressedPrefChange();
+  void OnSyncRequestedPrefChange();
 
   // Never null.
   PrefService* const pref_service_;
@@ -200,7 +200,7 @@
 
   BooleanPrefMember pref_first_setup_complete_;
 
-  BooleanPrefMember pref_sync_suppressed_;
+  BooleanPrefMember pref_sync_requested_;
 
   bool local_sync_enabled_;
 
@@ -218,6 +218,7 @@
 #if defined(OS_CHROMEOS)
 void ClearObsoleteSyncSpareBootstrapToken(PrefService* pref_service);
 #endif  // defined(OS_CHROMEOS)
+void MigrateSyncSuppressedPref(PrefService* pref_service);
 
 }  // namespace syncer
 
diff --git a/components/sync/base/sync_prefs_unittest.cc b/components/sync/base/sync_prefs_unittest.cc
index 529c387..61f2a93 100644
--- a/components/sync/base/sync_prefs_unittest.cc
+++ b/components/sync/base/sync_prefs_unittest.cc
@@ -23,6 +23,11 @@
 using ::testing::InSequence;
 using ::testing::StrictMock;
 
+// Obsolete pref that used to store if sync should be prevented from
+// automatically starting up. This is now replaced by its inverse
+// kSyncRequested.
+const char kSyncSuppressStart[] = "sync.suppress_start";
+
 class SyncPrefsTest : public testing::Test {
  protected:
   SyncPrefsTest() {
@@ -77,12 +82,12 @@
   EXPECT_CALL(mock_sync_pref_observer, OnSyncManagedPrefChange(false));
   EXPECT_CALL(mock_sync_pref_observer, OnFirstSetupCompletePrefChange(true));
   EXPECT_CALL(mock_sync_pref_observer, OnFirstSetupCompletePrefChange(false));
-  EXPECT_CALL(mock_sync_pref_observer, OnSyncRequestedPrefChange(false));
   EXPECT_CALL(mock_sync_pref_observer, OnSyncRequestedPrefChange(true));
+  EXPECT_CALL(mock_sync_pref_observer, OnSyncRequestedPrefChange(false));
 
   ASSERT_FALSE(sync_prefs_->IsManaged());
   ASSERT_FALSE(sync_prefs_->IsFirstSetupComplete());
-  ASSERT_TRUE(sync_prefs_->IsSyncRequested());
+  ASSERT_FALSE(sync_prefs_->IsSyncRequested());
 
   sync_prefs_->AddSyncPrefObserver(&mock_sync_pref_observer);
 
@@ -98,10 +103,10 @@
   sync_prefs_->ClearPreferences();
   EXPECT_FALSE(sync_prefs_->IsFirstSetupComplete());
 
-  sync_prefs_->SetSyncRequested(false);
-  EXPECT_FALSE(sync_prefs_->IsSyncRequested());
   sync_prefs_->SetSyncRequested(true);
   EXPECT_TRUE(sync_prefs_->IsSyncRequested());
+  sync_prefs_->SetSyncRequested(false);
+  EXPECT_FALSE(sync_prefs_->IsSyncRequested());
 
   sync_prefs_->RemoveSyncPrefObserver(&mock_sync_pref_observer);
 }
@@ -126,20 +131,16 @@
   EXPECT_TRUE(sync_prefs_->GetEncryptionBootstrapToken().empty());
 }
 
-// -----------------------------------------------------------------------------
-// Test that manipulate selected types.
-// -----------------------------------------------------------------------------
-
 TEST_F(SyncPrefsTest, Basic) {
   EXPECT_FALSE(sync_prefs_->IsFirstSetupComplete());
   sync_prefs_->SetFirstSetupComplete();
   EXPECT_TRUE(sync_prefs_->IsFirstSetupComplete());
 
-  EXPECT_TRUE(sync_prefs_->IsSyncRequested());
-  sync_prefs_->SetSyncRequested(false);
   EXPECT_FALSE(sync_prefs_->IsSyncRequested());
   sync_prefs_->SetSyncRequested(true);
   EXPECT_TRUE(sync_prefs_->IsSyncRequested());
+  sync_prefs_->SetSyncRequested(false);
+  EXPECT_FALSE(sync_prefs_->IsSyncRequested());
 
   EXPECT_EQ(base::Time(), sync_prefs_->GetLastSyncedTime());
   const base::Time& now = base::Time::Now();
@@ -192,6 +193,201 @@
   }
 }
 
+// Similar to SyncPrefsTest, but does not create a SyncPrefs instance. This lets
+// individual tests set up the "before" state of the PrefService before
+// SyncPrefs gets created.
+class SyncPrefsMigrationTest : public testing::Test {
+ protected:
+  SyncPrefsMigrationTest() {
+    SyncPrefs::RegisterProfilePrefs(pref_service_.registry());
+  }
+
+  base::test::ScopedTaskEnvironment task_environment_;
+  sync_preferences::TestingPrefServiceSyncable pref_service_;
+};
+
+TEST_F(SyncPrefsMigrationTest, SyncSuppressed_NotSet) {
+  // Sync was never enabled, so none of the relevant prefs have an explicit
+  // value.
+  ASSERT_FALSE(pref_service_.GetUserPrefValue(kSyncSuppressStart));
+  ASSERT_FALSE(pref_service_.GetUserPrefValue(prefs::kSyncFirstSetupComplete));
+  ASSERT_FALSE(pref_service_.GetUserPrefValue(prefs::kSyncRequested));
+
+  syncer::MigrateSyncSuppressedPref(&pref_service_);
+
+  // After the migration, Sync should still be disabled.
+  SyncPrefs prefs(&pref_service_);
+  EXPECT_FALSE(prefs.IsSyncRequested());
+  EXPECT_FALSE(prefs.IsFirstSetupComplete());
+
+  // The new pref should still not have an explicit value.
+  EXPECT_FALSE(pref_service_.GetUserPrefValue(kSyncSuppressStart));
+  EXPECT_FALSE(pref_service_.GetUserPrefValue(prefs::kSyncRequested));
+}
+
+TEST_F(SyncPrefsMigrationTest, SyncSuppressed_SyncEnabled) {
+  // Sync is enabled, so kSyncSuppressStart is false and kSyncFirstSetupComplete
+  // is true.
+  pref_service_.SetBoolean(kSyncSuppressStart, false);
+  pref_service_.SetBoolean(prefs::kSyncFirstSetupComplete, true);
+  ASSERT_FALSE(pref_service_.GetUserPrefValue(prefs::kSyncRequested));
+
+  syncer::MigrateSyncSuppressedPref(&pref_service_);
+
+  // After the migration, Sync should still be enabled, and the old pref value
+  // should be gone.
+  SyncPrefs prefs(&pref_service_);
+  EXPECT_TRUE(prefs.IsSyncRequested());
+  EXPECT_TRUE(prefs.IsFirstSetupComplete());
+
+  EXPECT_FALSE(pref_service_.GetUserPrefValue(kSyncSuppressStart));
+  EXPECT_TRUE(pref_service_.GetUserPrefValue(prefs::kSyncRequested));
+}
+
+TEST_F(SyncPrefsMigrationTest, SyncSuppressed_SyncEnabledImplicitly) {
+  // Sync is enabled implicitly: kSyncSuppressStart does not have a value, so it
+  // defaults to false, but kSyncFirstSetupComplete is true. This state should
+  // not exist, but it could happen if at some point in the past, the Sync setup
+  // flow failed to actually set Sync to requested (see crbug.com/973770).
+  ASSERT_FALSE(pref_service_.GetUserPrefValue(kSyncSuppressStart));
+  pref_service_.SetBoolean(prefs::kSyncFirstSetupComplete, true);
+  ASSERT_FALSE(pref_service_.GetUserPrefValue(prefs::kSyncRequested));
+
+  syncer::MigrateSyncSuppressedPref(&pref_service_);
+
+  // After the migration, Sync should still be enabled, and the old pref value
+  // should be gone.
+  SyncPrefs prefs(&pref_service_);
+  EXPECT_TRUE(prefs.IsSyncRequested());
+  EXPECT_TRUE(prefs.IsFirstSetupComplete());
+
+  EXPECT_FALSE(pref_service_.GetUserPrefValue(kSyncSuppressStart));
+  EXPECT_TRUE(pref_service_.GetUserPrefValue(prefs::kSyncRequested));
+}
+
+TEST_F(SyncPrefsMigrationTest, SyncSuppressed_SyncDisabledWithFirstSetup) {
+  // Sync is explicitly disabled, so kSyncSuppressStart is true.
+  pref_service_.SetBoolean(kSyncSuppressStart, true);
+  pref_service_.SetBoolean(prefs::kSyncFirstSetupComplete, true);
+  ASSERT_FALSE(pref_service_.GetUserPrefValue(prefs::kSyncRequested));
+
+  syncer::MigrateSyncSuppressedPref(&pref_service_);
+
+  // After the migration, Sync should still be disabled, and the old pref value
+  // should be gone.
+  SyncPrefs prefs(&pref_service_);
+  EXPECT_FALSE(prefs.IsSyncRequested());
+  EXPECT_TRUE(prefs.IsFirstSetupComplete());
+
+  EXPECT_FALSE(pref_service_.GetUserPrefValue(kSyncSuppressStart));
+  EXPECT_TRUE(pref_service_.GetUserPrefValue(prefs::kSyncRequested));
+}
+
+TEST_F(SyncPrefsMigrationTest, SyncSuppressed_SyncDisabledWithoutFirstSetup) {
+  // Sync is explicitly disabled, so kSyncSuppressStart is true.
+  pref_service_.SetBoolean(kSyncSuppressStart, true);
+  pref_service_.SetBoolean(prefs::kSyncFirstSetupComplete, false);
+  ASSERT_FALSE(pref_service_.GetUserPrefValue(prefs::kSyncRequested));
+
+  syncer::MigrateSyncSuppressedPref(&pref_service_);
+
+  // After the migration, Sync should still be disabled, and the old pref value
+  // should be gone.
+  SyncPrefs prefs(&pref_service_);
+  EXPECT_FALSE(prefs.IsSyncRequested());
+  EXPECT_FALSE(prefs.IsFirstSetupComplete());
+
+  EXPECT_FALSE(pref_service_.GetUserPrefValue(kSyncSuppressStart));
+  EXPECT_TRUE(pref_service_.GetUserPrefValue(prefs::kSyncRequested));
+}
+
+enum BooleanPrefState { PREF_FALSE, PREF_TRUE, PREF_UNSET };
+
+// There are three prefs which are relevant for the "SyncSuppressed" migration:
+// The old kSyncSuppressStart, the new kSyncRequested, and the (unchanged)
+// kSyncFirstSetupComplete. Each can be explicitly true, explicitly false, or
+// unset. This class is parameterized to cover all possible combinations.
+class SyncPrefsSyncSuppressedMigrationCombinationsTest
+    : public SyncPrefsMigrationTest,
+      public testing::WithParamInterface<testing::tuple<BooleanPrefState,
+                                                        BooleanPrefState,
+                                                        BooleanPrefState>> {
+ protected:
+  void SetBooleanUserPrefValue(const char* pref_name, BooleanPrefState state) {
+    switch (state) {
+      case PREF_FALSE:
+        pref_service_.SetBoolean(pref_name, false);
+        break;
+      case PREF_TRUE:
+        pref_service_.SetBoolean(pref_name, true);
+        break;
+      case PREF_UNSET:
+        pref_service_.ClearPref(pref_name);
+        break;
+    }
+  }
+
+  BooleanPrefState GetBooleanUserPrefValue(const char* pref_name) const {
+    const base::Value* pref_value = pref_service_.GetUserPrefValue(pref_name);
+    if (!pref_value) {
+      return PREF_UNSET;
+    }
+    return pref_value->GetBool() ? PREF_TRUE : PREF_FALSE;
+  }
+
+  bool BooleanUserPrefMatches(const char* pref_name,
+                              BooleanPrefState state) const {
+    const base::Value* pref_value = pref_service_.GetUserPrefValue(pref_name);
+    switch (state) {
+      case PREF_FALSE:
+        return pref_value && !pref_value->GetBool();
+      case PREF_TRUE:
+        return pref_value && pref_value->GetBool();
+      case PREF_UNSET:
+        return !pref_value;
+    }
+  }
+};
+
+TEST_P(SyncPrefsSyncSuppressedMigrationCombinationsTest, Idempotent) {
+  // Set the initial values (true, false, or unset) of the three prefs from the
+  // test params.
+  SetBooleanUserPrefValue(kSyncSuppressStart, testing::get<0>(GetParam()));
+  SetBooleanUserPrefValue(prefs::kSyncFirstSetupComplete,
+                          testing::get<1>(GetParam()));
+  SetBooleanUserPrefValue(prefs::kSyncRequested, testing::get<2>(GetParam()));
+
+  // Do the first migration.
+  syncer::MigrateSyncSuppressedPref(&pref_service_);
+
+  // Record the resulting pref values.
+  BooleanPrefState expect_suppress_start =
+      GetBooleanUserPrefValue(kSyncSuppressStart);
+  BooleanPrefState expect_first_setup_complete =
+      GetBooleanUserPrefValue(prefs::kSyncFirstSetupComplete);
+  BooleanPrefState expect_requested =
+      GetBooleanUserPrefValue(prefs::kSyncRequested);
+
+  // Do the second migration.
+  syncer::MigrateSyncSuppressedPref(&pref_service_);
+
+  // Verify that the pref values did not change.
+  EXPECT_TRUE(
+      BooleanUserPrefMatches(kSyncSuppressStart, expect_suppress_start));
+  EXPECT_TRUE(BooleanUserPrefMatches(prefs::kSyncFirstSetupComplete,
+                                     expect_first_setup_complete));
+  EXPECT_TRUE(BooleanUserPrefMatches(prefs::kSyncRequested, expect_requested));
+}
+
+// Not all combinations of pref values are possible in practice, but anyway the
+// migration should always be idempotent, so we test all combinations here.
+INSTANTIATE_TEST_SUITE_P(
+    ,
+    SyncPrefsSyncSuppressedMigrationCombinationsTest,
+    testing::Combine(::testing::Values(PREF_FALSE, PREF_TRUE, PREF_UNSET),
+                     ::testing::Values(PREF_FALSE, PREF_TRUE, PREF_UNSET),
+                     ::testing::Values(PREF_FALSE, PREF_TRUE, PREF_UNSET)));
+
 }  // namespace
 
 }  // namespace syncer
diff --git a/components/sync/driver/profile_sync_service_startup_unittest.cc b/components/sync/driver/profile_sync_service_startup_unittest.cc
index 2964141..4a6515fa 100644
--- a/components/sync/driver/profile_sync_service_startup_unittest.cc
+++ b/components/sync/driver/profile_sync_service_startup_unittest.cc
@@ -165,7 +165,8 @@
   // Should not actually start, rather just clean things up and wait
   // to be enabled.
   sync_service()->Initialize();
-  EXPECT_EQ(SyncService::DISABLE_REASON_NOT_SIGNED_IN,
+  EXPECT_EQ(SyncService::DISABLE_REASON_NOT_SIGNED_IN |
+                SyncService::DISABLE_REASON_USER_CHOICE,
             sync_service()->GetDisableReasons());
   EXPECT_EQ(SyncService::TransportState::DISABLED,
             sync_service()->GetTransportState());
@@ -603,7 +604,8 @@
 
   // There is no signed-in user, so also nobody has decided that Sync should be
   // started.
-  EXPECT_EQ(SyncService::DISABLE_REASON_NOT_SIGNED_IN,
+  EXPECT_EQ(SyncService::DISABLE_REASON_NOT_SIGNED_IN |
+                SyncService::DISABLE_REASON_USER_CHOICE,
             sync_service()->GetDisableReasons());
   EXPECT_EQ(SyncService::TransportState::DISABLED,
             sync_service()->GetTransportState());
@@ -611,7 +613,7 @@
   // Sign in. Now Sync-the-transport could start, but gets deferred by default.
   // Sync-the-feature still doesn't start until the user says they want it.
   SimulateTestUserSignin();
-  EXPECT_EQ(SyncService::DISABLE_REASON_NONE,
+  EXPECT_EQ(SyncService::DISABLE_REASON_USER_CHOICE,
             sync_service()->GetDisableReasons());
   EXPECT_EQ(SyncService::TransportState::START_DEFERRED,
             sync_service()->GetTransportState());
diff --git a/components/sync/driver/profile_sync_service_unittest.cc b/components/sync/driver/profile_sync_service_unittest.cc
index be972430..98e53b2 100644
--- a/components/sync/driver/profile_sync_service_unittest.cc
+++ b/components/sync/driver/profile_sync_service_unittest.cc
@@ -486,7 +486,9 @@
   SignIn();
   InitializeForNthSync();
 
-  ASSERT_FALSE(prefs()->GetBoolean(prefs::kSyncSuppressStart));
+  SyncPrefs sync_prefs(prefs());
+
+  ASSERT_TRUE(sync_prefs.IsSyncRequested());
   ASSERT_EQ(SyncService::DISABLE_REASON_NONE, service()->GetDisableReasons());
   ASSERT_EQ(SyncService::TransportState::ACTIVE,
             service()->GetTransportState());
@@ -496,7 +498,7 @@
   testing::Mock::VerifyAndClearExpectations(component_factory());
 
   service()->GetUserSettings()->SetSyncRequested(false);
-  EXPECT_TRUE(prefs()->GetBoolean(prefs::kSyncSuppressStart));
+  EXPECT_FALSE(sync_prefs.IsSyncRequested());
   EXPECT_EQ(SyncService::DISABLE_REASON_USER_CHOICE,
             service()->GetDisableReasons());
   EXPECT_EQ(SyncService::TransportState::ACTIVE,
@@ -505,7 +507,7 @@
   EXPECT_FALSE(service()->IsSyncFeatureEnabled());
 
   service()->GetUserSettings()->SetSyncRequested(true);
-  EXPECT_FALSE(prefs()->GetBoolean(prefs::kSyncSuppressStart));
+  EXPECT_TRUE(sync_prefs.IsSyncRequested());
   EXPECT_EQ(SyncService::DISABLE_REASON_NONE, service()->GetDisableReasons());
   EXPECT_EQ(SyncService::TransportState::ACTIVE,
             service()->GetTransportState());
@@ -521,7 +523,6 @@
   SignIn();
   InitializeForNthSync();
 
-  EXPECT_FALSE(prefs()->GetBoolean(prefs::kSyncSuppressStart));
   EXPECT_EQ(SyncService::DISABLE_REASON_NONE, service()->GetDisableReasons());
   EXPECT_EQ(SyncService::TransportState::ACTIVE,
             service()->GetTransportState());
@@ -999,7 +1000,7 @@
   SignIn();
   InitializeForNthSync();
 
-  ASSERT_FALSE(prefs()->GetBoolean(prefs::kSyncSuppressStart));
+  ASSERT_TRUE(prefs()->GetBoolean(prefs::kSyncRequested));
   ASSERT_EQ(SyncService::TransportState::ACTIVE,
             service()->GetTransportState());
 
diff --git a/components/sync/driver/sync_user_settings.h b/components/sync/driver/sync_user_settings.h
index f831304..d7500cb 100644
--- a/components/sync/driver/sync_user_settings.h
+++ b/components/sync/driver/sync_user_settings.h
@@ -21,10 +21,12 @@
  public:
   ~SyncUserSettings() override = default;
 
-  // Whether the user wants Sync to run, a.k.a. the Sync feature toggle in
-  // settings. This maps to DISABLE_REASON_USER_CHOICE.
-  // NOTE: This is true by default, even if the user has never enabled Sync or
-  // isn't even signed in.
+  // Whether the user wants Sync to run. This is false by default, but gets set
+  // to true early in the Sync setup flow, after the user has pressed "turn on
+  // Sync" but before they have actually confirmed the settings (that's
+  // IsFirstSetupComplete()). After Sync is enabled, this can get set to false
+  // by the Sync feature toggle in settings, or when Sync gets reset from the
+  // dashboard. This maps to DISABLE_REASON_USER_CHOICE.
   virtual bool IsSyncRequested() const = 0;
   virtual void SetSyncRequested(bool requested) = 0;
 
diff --git a/components/sync_bookmarks/bookmark_model_observer_impl_unittest.cc b/components/sync_bookmarks/bookmark_model_observer_impl_unittest.cc
index 6a74391..cf00360 100644
--- a/components/sync_bookmarks/bookmark_model_observer_impl_unittest.cc
+++ b/components/sync_bookmarks/bookmark_model_observer_impl_unittest.cc
@@ -498,12 +498,11 @@
 }
 
 TEST_F(BookmarkModelObserverImplTest, ShouldNotSyncUnsyncableBookmarks) {
-  bookmarks::BookmarkPermanentNodeList extra_nodes;
-  extra_nodes.push_back(
-      std::make_unique<bookmarks::BookmarkPermanentNode>(100));
-  bookmarks::BookmarkPermanentNode* extra_node = extra_nodes.back().get();
+  auto owned_extra_node =
+      std::make_unique<bookmarks::BookmarkPermanentNode>(100);
+  bookmarks::BookmarkPermanentNode* extra_node = owned_extra_node.get();
   auto client = std::make_unique<bookmarks::TestBookmarkClient>();
-  client->SetExtraNodesToLoad(std::move(extra_nodes));
+  client->SetExtraNodeToLoad(std::move(owned_extra_node));
 
   std::unique_ptr<bookmarks::BookmarkModel> model =
       bookmarks::TestBookmarkClient::CreateModelWithClient(std::move(client));
diff --git a/components/sync_bookmarks/synced_bookmark_tracker_unittest.cc b/components/sync_bookmarks/synced_bookmark_tracker_unittest.cc
index b83caa67..330190e3 100644
--- a/components/sync_bookmarks/synced_bookmark_tracker_unittest.cc
+++ b/components/sync_bookmarks/synced_bookmark_tracker_unittest.cc
@@ -559,12 +559,11 @@
      ShouldMatchModelWithUnsyncableNodesAndMetadata) {
   // Add a managed node with an arbitrary id 100.
   const int64_t kManagedNodeId = 100;
-  bookmarks::BookmarkPermanentNodeList extra_nodes;
-  extra_nodes.push_back(
-      std::make_unique<bookmarks::BookmarkPermanentNode>(kManagedNodeId));
-  bookmarks::BookmarkPermanentNode* extra_node = extra_nodes.back().get();
+  auto owned_extra_node =
+      std::make_unique<bookmarks::BookmarkPermanentNode>(kManagedNodeId);
+  bookmarks::BookmarkPermanentNode* extra_node = owned_extra_node.get();
   auto client = std::make_unique<bookmarks::TestBookmarkClient>();
-  client->SetExtraNodesToLoad(std::move(extra_nodes));
+  client->SetExtraNodeToLoad(std::move(owned_extra_node));
 
   std::unique_ptr<bookmarks::BookmarkModel> model =
       bookmarks::TestBookmarkClient::CreateModelWithClient(std::move(client));
diff --git a/components/viz/BUILD.gn b/components/viz/BUILD.gn
index 71424f37..e8464da 100644
--- a/components/viz/BUILD.gn
+++ b/components/viz/BUILD.gn
@@ -47,6 +47,8 @@
     "//components/viz/common:perf_tests",
     "//components/viz/service:perf_tests",
     "//components/viz/test:test_suite",
+    "//mojo/core/embedder",
+    "//skia",
   ]
 
   # This target should not require the Chrome executable to run.
diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn
index f1754d4..3f6def06 100644
--- a/components/viz/service/BUILD.gn
+++ b/components/viz/service/BUILD.gn
@@ -499,6 +499,7 @@
     "display/bsp_tree_perftest.cc",
     "display/display_perftest.cc",
     "display/gl_renderer_copier_perftest.cc",
+    "display/renderer_perftest.cc",
     "display/surface_aggregator_perftest.cc",
   ]
 
@@ -509,6 +510,7 @@
     "//cc",
     "//cc:test_support",
     "//cc/base",
+    "//components/viz/client:client",
     "//components/viz/test:test_support",
     "//testing/gtest",
     "//testing/perf",
diff --git a/components/viz/service/display/display.cc b/components/viz/service/display/display.cc
index 6def139..6162ab2 100644
--- a/components/viz/service/display/display.cc
+++ b/components/viz/service/display/display.cc
@@ -122,6 +122,9 @@
 
 }  // namespace
 
+constexpr base::TimeDelta Display::kDrawToSwapMin;
+constexpr base::TimeDelta Display::kDrawToSwapMax;
+
 Display::Display(
     SharedBitmapManager* bitmap_manager,
     const RendererSettings& settings,
@@ -627,9 +630,8 @@
     base::TimeDelta delta =
         timings.swap_start - draw_start_times_pending_swap_ack_.front();
     UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(
-        "Compositing.Display.DrawToSwapUs", delta,
-        base::TimeDelta::FromMicroseconds(100),
-        base::TimeDelta::FromMilliseconds(100), 50);
+        "Compositing.Display.DrawToSwapUs", delta, kDrawToSwapMin,
+        kDrawToSwapMax, kDrawToSwapUsBuckets);
   }
   draw_start_times_pending_swap_ack_.pop_front();
 }
diff --git a/components/viz/service/display/display.h b/components/viz/service/display/display.h
index 623c1b4..43bbf2b14 100644
--- a/components/viz/service/display/display.h
+++ b/components/viz/service/display/display.h
@@ -13,6 +13,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/single_thread_task_runner.h"
+#include "base/time/time.h"
 #include "components/viz/common/frame_sinks/begin_frame_source.h"
 #include "components/viz/common/gpu/context_lost_observer.h"
 #include "components/viz/common/resources/returned_resource.h"
@@ -79,6 +80,12 @@
 
   ~Display() override;
 
+  static constexpr base::TimeDelta kDrawToSwapMin =
+      base::TimeDelta::FromMicroseconds(5);
+  static constexpr base::TimeDelta kDrawToSwapMax =
+      base::TimeDelta::FromMilliseconds(50);
+  static constexpr uint32_t kDrawToSwapUsBuckets = 50;
+
   // TODO(cblume, crbug.com/900973): |enable_shared_images| is a temporary
   // solution that unblocks us until SharedImages are threadsafe in WebView.
 #if defined(ANDROID)
diff --git a/components/viz/service/display/renderer_perftest.cc b/components/viz/service/display/renderer_perftest.cc
new file mode 100644
index 0000000..50bbbb5
--- /dev/null
+++ b/components/viz/service/display/renderer_perftest.cc
@@ -0,0 +1,432 @@
+// 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.
+
+// This perf test measures the time from when the display compositor starts
+// drawing on the compositor thread to when a swap buffers occurs on the
+// GPU main thread. It tests both GLRenderer and SkiaRenderer under
+// simple work loads.
+//
+// Example usage:
+//
+// $ out/release/viz_perftests --gtest_filter="*RendererPerfTest*" \
+//    --use-gpu-in-tests
+
+#include "base/bind.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/timer/lap_timer.h"
+#include "components/viz/client/client_resource_provider.h"
+#include "components/viz/common/display/renderer_settings.h"
+#include "components/viz/common/quads/texture_draw_quad.h"
+#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
+#include "components/viz/service/display/display.h"
+#include "components/viz/service/display/gl_renderer.h"
+#include "components/viz/service/display/output_surface_client.h"
+#include "components/viz/service/display_embedder/gl_output_surface_offscreen.h"
+#include "components/viz/service/display_embedder/in_process_gpu_memory_buffer_manager.h"
+#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
+#include "components/viz/service/display_embedder/skia_output_surface_dependency_impl.h"
+#include "components/viz/service/display_embedder/skia_output_surface_impl.h"
+#include "components/viz/service/display_embedder/viz_process_context_provider.h"
+#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
+#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+#include "components/viz/service/gl/gpu_service_impl.h"
+#include "components/viz/test/compositor_frame_helpers.h"
+#include "components/viz/test/test_gpu_service_holder.h"
+#include "gpu/command_buffer/client/shared_image_interface.h"
+#include "gpu/command_buffer/common/shared_image_usage.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_test.h"
+#include "third_party/skia/include/core/SkColorPriv.h"
+#include "ui/gfx/color_space.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace viz {
+
+namespace {
+
+static constexpr FrameSinkId kArbitraryFrameSinkId(3, 3);
+static constexpr gfx::Size kSurfaceSize(1000, 1000);
+static constexpr gfx::Rect kSurfaceRect(kSurfaceSize);
+
+class WaitForSwapDisplayClient : public DisplayClient {
+ public:
+  WaitForSwapDisplayClient() = default;
+
+  void DisplayOutputSurfaceLost() override {}
+  void DisplayWillDrawAndSwap(bool will_draw_and_swap,
+                              RenderPassList* render_passes) override {}
+  void DisplayDidDrawAndSwap() override {}
+  void DisplayDidReceiveCALayerParams(
+      const gfx::CALayerParams& ca_layer_params) override {}
+  void DisplayDidCompleteSwapWithSize(const gfx::Size& pixel_size) override {
+    DCHECK(loop_);
+    loop_->Quit();
+  }
+  void SetPreferredFrameInterval(base::TimeDelta interval) override {}
+  base::TimeDelta GetPreferredFrameIntervalForFrameSinkId(
+      const FrameSinkId& id) override {
+    return BeginFrameArgs::MinInterval();
+  }
+
+  void WaitForSwap() {
+    DCHECK(!loop_);
+    loop_ = std::make_unique<base::RunLoop>();
+    loop_->Run();
+    loop_.reset();
+  }
+
+ private:
+  std::unique_ptr<base::RunLoop> loop_;
+
+  DISALLOW_COPY_AND_ASSIGN(WaitForSwapDisplayClient);
+};
+
+std::unique_ptr<RenderPass> CreateTestRootRenderPass() {
+  const RenderPassId id = 1;
+  const gfx::Rect output_rect = kSurfaceRect;
+  const gfx::Rect damage_rect = kSurfaceRect;
+  const gfx::Transform transform_to_root_target;
+  std::unique_ptr<RenderPass> pass = RenderPass::Create();
+  pass->SetNew(id, output_rect, damage_rect, transform_to_root_target);
+  return pass;
+}
+
+SharedQuadState* CreateTestSharedQuadState(
+    gfx::Transform quad_to_target_transform,
+    const gfx::Rect& rect,
+    RenderPass* render_pass,
+    const gfx::RRectF& rrect) {
+  const gfx::Rect layer_rect = rect;
+  const gfx::Rect visible_layer_rect = rect;
+  const gfx::Rect clip_rect = rect;
+  const bool is_clipped = false;
+  const bool are_contents_opaque = false;
+  const float opacity = 1.0f;
+  const gfx::RRectF rounded_corner_bounds = rrect;
+  const SkBlendMode blend_mode = SkBlendMode::kSrcOver;
+  const int sorting_context_id = 0;
+  SharedQuadState* shared_state = render_pass->CreateAndAppendSharedQuadState();
+  shared_state->SetAll(quad_to_target_transform, layer_rect, visible_layer_rect,
+                       rounded_corner_bounds, clip_rect, is_clipped,
+                       are_contents_opaque, opacity, blend_mode,
+                       sorting_context_id);
+  return shared_state;
+}
+
+template <typename T>
+base::span<const uint8_t> MakePixelSpan(const std::vector<T>& vec) {
+  return base::make_span(reinterpret_cast<const uint8_t*>(vec.data()),
+                         vec.size() * sizeof(T));
+}
+
+void DeleteSharedImage(scoped_refptr<ContextProvider> context_provider,
+                       gpu::Mailbox mailbox,
+                       const gpu::SyncToken& sync_token,
+                       bool is_lost) {
+  DCHECK(context_provider);
+  gpu::SharedImageInterface* sii = context_provider->SharedImageInterface();
+  DCHECK(sii);
+  sii->DestroySharedImage(sync_token, mailbox);
+}
+
+TransferableResource CreateTestTexture(
+    const gfx::Rect& rect,
+    SkColor texel_color,
+    bool premultiplied_alpha,
+    ClientResourceProvider* child_resource_provider,
+    scoped_refptr<ContextProvider> child_context_provider) {
+  SkPMColor pixel_color = premultiplied_alpha
+                              ? SkPreMultiplyColor(texel_color)
+                              : SkPackARGB32NoCheck(SkColorGetA(texel_color),
+                                                    SkColorGetR(texel_color),
+                                                    SkColorGetG(texel_color),
+                                                    SkColorGetB(texel_color));
+  size_t num_pixels = static_cast<size_t>(rect.width()) * rect.height();
+  std::vector<uint32_t> pixels(num_pixels, pixel_color);
+
+  gpu::SharedImageInterface* sii =
+      child_context_provider->SharedImageInterface();
+  DCHECK(sii);
+  gpu::Mailbox mailbox = sii->CreateSharedImage(
+      RGBA_8888, rect.size(), gfx::ColorSpace(),
+      gpu::SHARED_IMAGE_USAGE_DISPLAY, MakePixelSpan(pixels));
+  gpu::SyncToken sync_token = sii->GenUnverifiedSyncToken();
+
+  TransferableResource gl_resource = TransferableResource::MakeGL(
+      mailbox, GL_LINEAR, GL_TEXTURE_2D, sync_token, rect.size(),
+      false /* is_overlay_candidate */);
+  gl_resource.format = RGBA_8888;
+  gl_resource.color_space = gfx::ColorSpace();
+  auto release_callback = SingleReleaseCallback::Create(base::BindOnce(
+      &DeleteSharedImage, std::move(child_context_provider), mailbox));
+  gl_resource.id = child_resource_provider->ImportResource(
+      gl_resource, std::move(release_callback));
+  return gl_resource;
+}
+
+void CreateTestTextureDrawQuad(ResourceId resource_id,
+                               const gfx::Rect& rect,
+                               SkColor background_color,
+                               bool premultiplied_alpha,
+                               const SharedQuadState* shared_state,
+                               RenderPass* render_pass) {
+  const bool needs_blending = true;
+  const gfx::PointF uv_top_left(0.0f, 0.0f);
+  const gfx::PointF uv_bottom_right(1.0f, 1.0f);
+  const bool flipped = false;
+  const bool nearest_neighbor = false;
+  const float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+  auto* quad = render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
+  quad->SetNew(shared_state, rect, rect, needs_blending, resource_id,
+               premultiplied_alpha, uv_top_left, uv_bottom_right,
+               background_color, vertex_opacity, flipped, nearest_neighbor,
+               /*secure_output_only=*/false, gfx::ProtectedVideoType::kClear);
+}
+
+}  // namespace
+
+template <typename RendererType>
+class RendererPerfTest : public testing::Test {
+ public:
+  RendererPerfTest()
+      : manager_(&shared_bitmap_manager_),
+        support_(std::make_unique<CompositorFrameSinkSupport>(
+            nullptr,
+            &manager_,
+            kArbitraryFrameSinkId,
+            true /* is_root */,
+            true /* needs_sync_points */)) {}
+
+  // Overloaded for concrete RendererType below.
+  std::unique_ptr<OutputSurface> CreateOutputSurface(
+      GpuServiceImpl* gpu_service);
+
+  void SetUp() override {
+    renderer_settings_.use_skia_renderer =
+        std::is_base_of<SkiaRenderer, RendererType>::value;
+    if (renderer_settings_.use_skia_renderer)
+      printf("Using SkiaRenderer\n");
+    else
+      printf("Using GLRenderer\n");
+
+    auto* gpu_service = TestGpuServiceHolder::GetInstance()->gpu_service();
+
+    gpu_memory_buffer_manager_ =
+        std::make_unique<InProcessGpuMemoryBufferManager>(
+            gpu_service->gpu_memory_buffer_factory(),
+            gpu_service->sync_point_manager());
+    gpu::ImageFactory* image_factory = gpu_service->gpu_image_factory();
+    auto* gpu_channel_manager_delegate =
+        gpu_service->gpu_channel_manager()->delegate();
+    child_context_provider_ = base::MakeRefCounted<VizProcessContextProvider>(
+        TestGpuServiceHolder::GetInstance()->task_executor(),
+        gpu::kNullSurfaceHandle, gpu_memory_buffer_manager_.get(),
+        image_factory, gpu_channel_manager_delegate, renderer_settings_);
+    child_context_provider_->BindToCurrentThread();
+    constexpr bool sync_token_verification = false;
+    child_resource_provider_ =
+        std::make_unique<ClientResourceProvider>(sync_token_verification);
+
+    auto output_surface = CreateOutputSurface(gpu_service);
+    // WaitForSwapDisplayClient depends on this.
+    output_surface->SetNeedsSwapSizeNotifications(true);
+
+    display_ = std::make_unique<Display>(
+        &shared_bitmap_manager_, renderer_settings_, kArbitraryFrameSinkId,
+        std::move(output_surface),
+        /*display_scheduler=*/nullptr, base::ThreadTaskRunnerHandle::Get());
+    display_->SetVisible(true);
+    display_->Initialize(&client_, manager_.surface_manager());
+    display_->Resize(kSurfaceSize);
+
+    id_allocator_.GenerateId();
+    display_->SetLocalSurfaceId(
+        id_allocator_.GetCurrentLocalSurfaceIdAllocation().local_surface_id(),
+        1.f);
+  }
+
+  void TearDown() override {
+    perf_test::PrintResult("Can draw", "", "frames", timer_.LapsPerSecond(),
+                           "runs/s", true);
+
+    auto* histogram = base::StatisticsRecorder::FindHistogram(
+        "Compositing.Display.DrawToSwapUs");
+    ASSERT_TRUE(histogram) << "Likely no swap_start time was returned to "
+                              "Display::DidReceiveSwapBuffersAck.";
+
+    // There is no way to clear a histogram. Part of the reason for this is that
+    // histogram lookups are cached in a pointer once per process for
+    // efficiency.
+    //
+    // To separate histogram results from different test runs, we sample the
+    // delta between successive runs and import the sample into a new unique
+    // histogram that can be graphed.
+    auto* info = testing::UnitTest::GetInstance()->current_test_info();
+    std::string temp_name = base::StringPrintf(
+        "%s.%s.DrawToSwapUs", info->test_case_name(), info->name());
+    auto samples = histogram->SnapshotDelta();
+    base::HistogramBase* temp_histogram =
+        base::Histogram::FactoryMicrosecondsTimeGet(
+            temp_name, Display::kDrawToSwapMin, Display::kDrawToSwapMax,
+            Display::kDrawToSwapUsBuckets, base::Histogram::kNoFlags);
+    temp_histogram->AddSamples(*samples);
+    std::string output;
+    temp_histogram->WriteAscii(&output);
+    printf("%s\n", output.c_str());
+
+    // Tear down the client side context provider, etc.
+    for (const auto& transferable_resource : resource_list_) {
+      child_resource_provider_->RemoveImportedResource(
+          transferable_resource.id);
+    }
+    child_resource_provider_->ShutdownAndReleaseAllResources();
+    child_resource_provider_.reset();
+    child_context_provider_.reset();
+    gpu_memory_buffer_manager_.reset();
+
+    display_.reset();
+  }
+
+  void DrawFrame(RenderPassList pass_list) {
+    CompositorFrame frame = CompositorFrameBuilder()
+                                .SetRenderPassList(std::move(pass_list))
+                                .SetTransferableResources(resource_list_)
+                                .Build();
+    support_->SubmitCompositorFrame(
+        id_allocator_.GetCurrentLocalSurfaceIdAllocation().local_surface_id(),
+        std::move(frame));
+    ASSERT_TRUE(display_->DrawAndSwap());
+  }
+
+  void RunSingleTextureQuad() {
+    resource_list_.push_back(CreateTestTexture(
+        gfx::Rect(kSurfaceSize),
+        /*texel_color=*/SkColorSetARGB(128, 0, 255, 0),
+        /*premultiplied_alpha=*/false, child_resource_provider_.get(),
+        child_context_provider_));
+
+    timer_.Reset();
+    do {
+      std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass();
+
+      SharedQuadState* shared_state = CreateTestSharedQuadState(
+          gfx::Transform(), kSurfaceRect, pass.get(), gfx::RRectF());
+
+      CreateTestTextureDrawQuad(resource_list_.back().id, kSurfaceRect,
+                                /*background_color=*/SK_ColorTRANSPARENT,
+                                /*premultiplied_alpha=*/false, shared_state,
+                                pass.get());
+
+      RenderPassList pass_list;
+      pass_list.push_back(std::move(pass));
+      DrawFrame(std::move(pass_list));
+
+      client_.WaitForSwap();
+      timer_.NextLap();
+    } while (!timer_.HasTimeLimitExpired());
+  }
+
+  void RunTextureQuads5x5() {
+    const gfx::Size kTextureSize =
+        ScaleToCeiledSize(kSurfaceSize, /*x_scale=*/0.2, /*y_scale=*/0.2);
+    ResourceId resource_ids[5][5];
+    for (int i = 0; i < 5; i++) {
+      for (int j = 0; j < 5; j++) {
+        resource_list_.push_back(CreateTestTexture(
+            gfx::Rect(kTextureSize),
+            /*texel_color=*/SkColorSetARGB(128, 0, 255, 0),
+            /*premultiplied_alpha=*/false, child_resource_provider_.get(),
+            child_context_provider_));
+        resource_ids[i][j] = resource_list_.back().id;
+      }
+    }
+
+    timer_.Reset();
+    do {
+      std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass();
+      SharedQuadState* shared_state = CreateTestSharedQuadState(
+          gfx::Transform(), kSurfaceRect, pass.get(), gfx::RRectF());
+
+      for (int i = 0; i < 5; i++) {
+        for (int j = 0; j < 5; j++) {
+          CreateTestTextureDrawQuad(
+              resource_ids[i][j],
+              gfx::Rect(i * kTextureSize.width(), j * kTextureSize.height(),
+                        kTextureSize.width(), kTextureSize.height()),
+              /*background_color=*/SK_ColorTRANSPARENT,
+              /*premultiplied_alpha=*/false, shared_state, pass.get());
+        }
+      }
+
+      RenderPassList pass_list;
+      pass_list.push_back(std::move(pass));
+      DrawFrame(std::move(pass_list));
+
+      client_.WaitForSwap();
+      timer_.NextLap();
+    } while (!timer_.HasTimeLimitExpired());
+  }
+
+ protected:
+  WaitForSwapDisplayClient client_;
+  ParentLocalSurfaceIdAllocator id_allocator_;
+  std::unique_ptr<BeginFrameSource> begin_frame_source_;
+  ServerSharedBitmapManager shared_bitmap_manager_;
+  FrameSinkManagerImpl manager_;
+  std::unique_ptr<CompositorFrameSinkSupport> support_;
+  std::unique_ptr<gpu::GpuMemoryBufferManager> gpu_memory_buffer_manager_;
+  RendererSettings renderer_settings_;
+  std::unique_ptr<Display> display_;
+  scoped_refptr<ContextProvider> child_context_provider_;
+  std::unique_ptr<ClientResourceProvider> child_resource_provider_;
+  std::vector<TransferableResource> resource_list_;
+  base::LapTimer timer_;
+
+  DISALLOW_COPY_AND_ASSIGN(RendererPerfTest);
+};
+
+template <>
+std::unique_ptr<OutputSurface>
+RendererPerfTest<SkiaRenderer>::CreateOutputSurface(
+    GpuServiceImpl* gpu_service) {
+  return std::make_unique<SkiaOutputSurfaceImpl>(
+      std::make_unique<SkiaOutputSurfaceDependencyImpl>(
+          gpu_service, gpu::kNullSurfaceHandle),
+      renderer_settings_);
+}
+
+template <>
+std::unique_ptr<OutputSurface>
+RendererPerfTest<GLRenderer>::CreateOutputSurface(GpuServiceImpl* gpu_service) {
+  gpu::ImageFactory* image_factory = gpu_service->gpu_image_factory();
+  auto* gpu_channel_manager_delegate =
+      gpu_service->gpu_channel_manager()->delegate();
+  auto context_provider = base::MakeRefCounted<VizProcessContextProvider>(
+      TestGpuServiceHolder::GetInstance()->task_executor(),
+      gpu::kNullSurfaceHandle, gpu_memory_buffer_manager_.get(), image_factory,
+      gpu_channel_manager_delegate, renderer_settings_);
+  context_provider->BindToCurrentThread();
+  return std::make_unique<GLOutputSurfaceOffscreen>(
+      std::move(context_provider));
+}
+
+using RendererTypes = ::testing::Types<GLRenderer, SkiaRenderer>;
+TYPED_TEST_SUITE(RendererPerfTest, RendererTypes);
+
+TYPED_TEST(RendererPerfTest, SingleTextureQuad) {
+  this->RunSingleTextureQuad();
+}
+
+TYPED_TEST(RendererPerfTest, TextureQuads5x5) {
+  this->RunTextureQuads5x5();
+}
+
+}  // namespace viz
diff --git a/components/viz/service/display_embedder/gl_output_surface.h b/components/viz/service/display_embedder/gl_output_surface.h
index ce845635..5cd4afa 100644
--- a/components/viz/service/display_embedder/gl_output_surface.h
+++ b/components/viz/service/display_embedder/gl_output_surface.h
@@ -57,6 +57,9 @@
  protected:
   OutputSurfaceClient* client() const { return client_; }
   ui::LatencyTracker* latency_tracker() { return &latency_tracker_; }
+  bool needs_swap_size_notifications() {
+    return needs_swap_size_notifications_;
+  }
 
   // Called when a swap completion is signaled from ImageTransportSurface.
   virtual void DidReceiveSwapBuffersAck(const gfx::SwapResponse& response);
diff --git a/components/viz/service/display_embedder/gl_output_surface_offscreen.cc b/components/viz/service/display_embedder/gl_output_surface_offscreen.cc
index 0efe65f..33dcee3d 100644
--- a/components/viz/service/display_embedder/gl_output_surface_offscreen.cc
+++ b/components/viz/service/display_embedder/gl_output_surface_offscreen.cc
@@ -117,10 +117,15 @@
 void GLOutputSurfaceOffscreen::OnSwapBuffersComplete(
     std::vector<ui::LatencyInfo> latency_info) {
   latency_tracker()->OnGpuSwapBuffersCompleted(latency_info);
-  // Swap timings are not available since for offscreen there is no Swap, just
-  // a SignalSyncToken.
-  client()->DidReceiveSwapBuffersAck(gfx::SwapTimings());
-  client()->DidReceivePresentationFeedback(gfx::PresentationFeedback());
+  // Swap timings are not available since for offscreen there is no Swap, just a
+  // SignalSyncToken. We use base::TimeTicks::Now() as an overestimate.
+  auto now = base::TimeTicks::Now();
+  client()->DidReceiveSwapBuffersAck({.swap_start = now});
+  client()->DidReceivePresentationFeedback(gfx::PresentationFeedback(
+      now, base::TimeDelta::FromMilliseconds(16), /*flags=*/0));
+
+  if (needs_swap_size_notifications())
+    client()->DidSwapWithSize(size_);
 }
 
 }  // namespace viz
diff --git a/components/viz/service/display_embedder/gl_output_surface_offscreen.h b/components/viz/service/display_embedder/gl_output_surface_offscreen.h
index ac23c03a..74afee8 100644
--- a/components/viz/service/display_embedder/gl_output_surface_offscreen.h
+++ b/components/viz/service/display_embedder/gl_output_surface_offscreen.h
@@ -10,6 +10,7 @@
 #include "components/viz/common/frame_sinks/begin_frame_source.h"
 #include "components/viz/service/display_embedder/gl_output_surface.h"
 #include "components/viz/service/display_embedder/viz_process_context_provider.h"
+#include "components/viz/service/viz_service_export.h"
 #include "gpu/command_buffer/common/mailbox.h"
 #include "ui/gfx/color_space.h"
 
@@ -17,7 +18,7 @@
 
 // An OutputSurface implementation that draws and swaps to an offscreen GL
 // framebuffer.
-class GLOutputSurfaceOffscreen : public GLOutputSurface {
+class VIZ_SERVICE_EXPORT GLOutputSurfaceOffscreen : public GLOutputSurface {
  public:
   explicit GLOutputSurfaceOffscreen(
       scoped_refptr<VizProcessContextProvider> context_provider);
diff --git a/components/viz/test/DEPS b/components/viz/test/DEPS
index b9dd6d1b..37e2952 100644
--- a/components/viz/test/DEPS
+++ b/components/viz/test/DEPS
@@ -58,4 +58,9 @@
     "+gpu/vulkan/init/vulkan_factory.h",
     "+gpu/vulkan/vulkan_implementation.h",
   ],
+
+  "run_all_perftests\.cc": [
+    "+mojo/core/embedder/embedder.h",
+    "+skia/ext/event_tracer_impl.h",
+  ],
 }
diff --git a/components/viz/test/run_all_perftests.cc b/components/viz/test/run_all_perftests.cc
index 2b4ee9a..10789bced 100644
--- a/components/viz/test/run_all_perftests.cc
+++ b/components/viz/test/run_all_perftests.cc
@@ -5,10 +5,16 @@
 #include "base/bind.h"
 #include "base/test/launcher/unit_test_launcher.h"
 #include "components/viz/test/viz_test_suite.h"
+#include "mojo/core/embedder/embedder.h"
+#include "skia/ext/event_tracer_impl.h"
 
 int main(int argc, char** argv) {
   viz::VizTestSuite test_suite(argc, argv);
 
+  mojo::core::Init();
+
+  InitSkiaEventTracer();
+
   // Always run the perf tests serially, to avoid distorting
   // perf measurements with randomness resulting from running
   // in parallel.
diff --git a/components/viz/test/test_gpu_service_holder.cc b/components/viz/test/test_gpu_service_holder.cc
index 2a7dbb5..d234a42 100644
--- a/components/viz/test/test_gpu_service_holder.cc
+++ b/components/viz/test/test_gpu_service_holder.cc
@@ -156,7 +156,10 @@
   // Always enable gpu and oop raster, regardless of platform and blacklist.
   // The latter instructs GpuChannelManager::GetSharedContextState to create a
   // GrContext, which is required by SkiaRenderer as well as OOP-R.
-  gpu::GpuFeatureInfo gpu_feature_info;
+  gpu::GPUInfo gpu_info;
+  gpu::GpuFeatureInfo gpu_feature_info = gpu::ComputeGpuFeatureInfo(
+      gpu_info, gpu_preferences, base::CommandLine::ForCurrentProcess(),
+      /*needs_more_info=*/nullptr);
   gpu_feature_info.status_values[gpu::GPU_FEATURE_TYPE_GPU_RASTERIZATION] =
       gpu::kGpuFeatureStatusEnabled;
   gpu_feature_info.status_values[gpu::GPU_FEATURE_TYPE_OOP_RASTERIZATION] =
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index c7b8d05..254b7f68 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -103,6 +103,7 @@
     "//crypto",
     "//device/base",
     "//device/bluetooth",
+    "//device/bluetooth/public/cpp",
     "//device/fido",
     "//device/gamepad",
     "//device/vr/public/mojom",
@@ -1319,12 +1320,6 @@
     "media/video_decoder_proxy.h",
     "media/webaudio/audio_context_manager_impl.cc",
     "media/webaudio/audio_context_manager_impl.h",
-    "memory/memory_monitor.cc",
-    "memory/memory_monitor.h",
-    "memory/memory_monitor_android.cc",
-    "memory/memory_monitor_android.h",
-    "memory/memory_monitor_win.cc",
-    "memory/memory_monitor_win.h",
     "memory/swap_metrics_driver_impl.cc",
     "memory/swap_metrics_driver_impl.h",
     "memory/swap_metrics_driver_impl_linux.cc",
@@ -2062,8 +2057,6 @@
     sources += [
       "media/keyboard_mic_registration.cc",
       "media/keyboard_mic_registration.h",
-      "memory/memory_monitor_chromeos.cc",
-      "memory/memory_monitor_chromeos.h",
       "tracing/cros_tracing_agent.cc",
       "tracing/cros_tracing_agent.h",
     ]
@@ -2071,11 +2064,6 @@
       "//chromeos/resources",
       "//components/chromeos_camera:mojo_mjpeg_decode_accelerator",
     ]
-  } else {
-    sources += [
-      "memory/memory_monitor_linux.cc",
-      "memory/memory_monitor_linux.h",
-    ]
   }
 
   if (is_chromeos || is_android || is_chromecast) {
@@ -2098,10 +2086,7 @@
   }
 
   if (is_fuchsia) {
-    sources += [
-      "child_process_launcher_helper_fuchsia.cc",
-      "memory/memory_monitor_fuchsia.cc",
-    ]
+    sources += [ "child_process_launcher_helper_fuchsia.cc" ]
     deps += [ "//third_party/fuchsia-sdk/sdk:zx" ]
   } else if (is_posix) {
     sources += [
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
index 544c0eca7..0065ffe 100644
--- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -1293,6 +1293,20 @@
   RunHtmlTest(FILE_PATH_LITERAL("heading.html"));
 }
 
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AccessibilityHidden) {
+  RunAriaTest(FILE_PATH_LITERAL("hidden.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest,
+                       AccessibilityHiddenDescribedBy) {
+  RunAriaTest(FILE_PATH_LITERAL("hidden-described-by.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest,
+                       AccessibilityHiddenLabeledBy) {
+  RunAriaTest(FILE_PATH_LITERAL("hidden-labelled-by.html"));
+}
+
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AccessibilityHR) {
   RunHtmlTest(FILE_PATH_LITERAL("hr.html"));
 }
diff --git a/content/browser/bluetooth/bluetooth_blocklist.h b/content/browser/bluetooth/bluetooth_blocklist.h
index 1e5ee04..78db647 100644
--- a/content/browser/bluetooth/bluetooth_blocklist.h
+++ b/content/browser/bluetooth/bluetooth_blocklist.h
@@ -12,7 +12,7 @@
 #include "base/macros.h"
 #include "base/strings/string_piece.h"
 #include "content/common/content_export.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "third_party/blink/public/mojom/bluetooth/web_bluetooth.mojom.h"
 
 namespace content {
diff --git a/content/browser/bluetooth/bluetooth_blocklist_unittest.cc b/content/browser/bluetooth/bluetooth_blocklist_unittest.cc
index 53fcdf5..01630c83 100644
--- a/content/browser/bluetooth/bluetooth_blocklist_unittest.cc
+++ b/content/browser/bluetooth/bluetooth_blocklist_unittest.cc
@@ -4,7 +4,7 @@
 
 #include "content/browser/bluetooth/bluetooth_blocklist.h"
 
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using device::BluetoothUUID;
diff --git a/content/browser/bluetooth/bluetooth_metrics.cc b/content/browser/bluetooth/bluetooth_metrics.cc
index 48f7070..642ad61 100644
--- a/content/browser/bluetooth/bluetooth_metrics.cc
+++ b/content/browser/bluetooth/bluetooth_metrics.cc
@@ -14,7 +14,7 @@
 #include "base/hash/hash.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 using device::BluetoothUUID;
 
diff --git a/content/browser/bluetooth/tools/BUILD.gn b/content/browser/bluetooth/tools/BUILD.gn
index 4971caa..5b5556b0 100644
--- a/content/browser/bluetooth/tools/BUILD.gn
+++ b/content/browser/bluetooth/tools/BUILD.gn
@@ -11,5 +11,6 @@
     "//base",
     "//build/win:default_exe_manifest",
     "//device/bluetooth",
+    "//device/bluetooth/public/cpp",
   ]
 }
diff --git a/content/browser/bluetooth/tools/bluetooth_metrics_hash.cc b/content/browser/bluetooth/tools/bluetooth_metrics_hash.cc
index 830369c..a10f4a4 100644
--- a/content/browser/bluetooth/tools/bluetooth_metrics_hash.cc
+++ b/content/browser/bluetooth/tools/bluetooth_metrics_hash.cc
@@ -6,7 +6,7 @@
 
 #include "base/hash/hash.h"
 #include "base/logging.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 int main(int argc, char** argv) {
   if (argc <= 2) {
diff --git a/content/browser/compositor/gpu_process_transport_factory.cc b/content/browser/compositor/gpu_process_transport_factory.cc
index 36af126..51499807 100644
--- a/content/browser/compositor/gpu_process_transport_factory.cc
+++ b/content/browser/compositor/gpu_process_transport_factory.cc
@@ -111,6 +111,10 @@
 constexpr gpu::SchedulingPriority kStreamPriority =
     content::kGpuStreamPriorityUI;
 
+viz::FrameSinkManagerImpl* GetFrameSinkManager() {
+  return content::BrowserMainLoop::GetInstance()->GetFrameSinkManager();
+}
+
 #if defined(USE_X11)
 class HostDisplayClient : public viz::HostDisplayClient {
  public:
@@ -767,10 +771,6 @@
   return false;
 }
 
-viz::FrameSinkManagerImpl* GpuProcessTransportFactory::GetFrameSinkManager() {
-  return BrowserMainLoop::GetInstance()->GetFrameSinkManager();
-}
-
 scoped_refptr<ContextProvider>
 GpuProcessTransportFactory::SharedMainThreadContextProvider() {
   if (is_gpu_compositing_disabled_)
diff --git a/content/browser/compositor/gpu_process_transport_factory.h b/content/browser/compositor/gpu_process_transport_factory.h
index 0ed56b6..f0322048 100644
--- a/content/browser/compositor/gpu_process_transport_factory.h
+++ b/content/browser/compositor/gpu_process_transport_factory.h
@@ -109,7 +109,6 @@
   bool IsGpuCompositingDisabled() override;
   ui::ContextFactory* GetContextFactory() override;
   ui::ContextFactoryPrivate* GetContextFactoryPrivate() override;
-  viz::FrameSinkManagerImpl* GetFrameSinkManager() override;
 
  private:
   struct PerCompositorData;
diff --git a/content/browser/compositor/surface_utils.cc b/content/browser/compositor/surface_utils.cc
index ed52592..c14f933 100644
--- a/content/browser/compositor/surface_utils.cc
+++ b/content/browser/compositor/surface_utils.cc
@@ -26,17 +26,6 @@
 #endif
 }
 
-viz::FrameSinkManagerImpl* GetFrameSinkManager() {
-#if defined(OS_ANDROID)
-  return CompositorDependenciesAndroid::Get().frame_sink_manager_impl();
-#else
-  ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
-  if (!factory)
-    return nullptr;
-  return factory->GetContextFactoryPrivate()->GetFrameSinkManager();
-#endif
-}
-
 viz::HostFrameSinkManager* GetHostFrameSinkManager() {
 #if defined(OS_ANDROID)
   return CompositorDependenciesAndroid::Get().host_frame_sink_manager();
diff --git a/content/browser/compositor/surface_utils.h b/content/browser/compositor/surface_utils.h
index 8a34418a..05073fd 100644
--- a/content/browser/compositor/surface_utils.h
+++ b/content/browser/compositor/surface_utils.h
@@ -21,8 +21,6 @@
 
 CONTENT_EXPORT viz::FrameSinkId AllocateFrameSinkId();
 
-CONTENT_EXPORT viz::FrameSinkManagerImpl* GetFrameSinkManager();
-
 CONTENT_EXPORT viz::HostFrameSinkManager* GetHostFrameSinkManager();
 
 namespace surface_utils {
diff --git a/content/browser/compositor/test/test_image_transport_factory.cc b/content/browser/compositor/test/test_image_transport_factory.cc
index c7956a2b..7b3c254 100644
--- a/content/browser/compositor/test/test_image_transport_factory.cc
+++ b/content/browser/compositor/test/test_image_transport_factory.cc
@@ -144,17 +144,6 @@
   return &host_frame_sink_manager_;
 }
 
-viz::FrameSinkManagerImpl* TestImageTransportFactory::GetFrameSinkManager() {
-  if (enable_viz_) {
-    // Nothing should use FrameSinkManagerImpl with VizDisplayCompositor
-    // enabled.
-    NOTREACHED();
-    return nullptr;
-  }
-
-  return frame_sink_manager_impl_.get();
-}
-
 void TestImageTransportFactory::DisableGpuCompositing() {
   NOTIMPLEMENTED();
 }
diff --git a/content/browser/compositor/test/test_image_transport_factory.h b/content/browser/compositor/test/test_image_transport_factory.h
index edeb10ae..037c007 100644
--- a/content/browser/compositor/test/test_image_transport_factory.h
+++ b/content/browser/compositor/test/test_image_transport_factory.h
@@ -83,7 +83,6 @@
   void AddVSyncParameterObserver(
       ui::Compositor* compositor,
       viz::mojom::VSyncParameterObserverPtr observer) override {}
-  viz::FrameSinkManagerImpl* GetFrameSinkManager() override;
 
   // ImageTransportFactory implementation.
   void DisableGpuCompositing() override;
diff --git a/content/browser/loader/resource_loader_unittest.cc b/content/browser/loader/resource_loader_unittest.cc
index 5f9e8f7..4db6d4d 100644
--- a/content/browser/loader/resource_loader_unittest.cc
+++ b/content/browser/loader/resource_loader_unittest.cc
@@ -165,8 +165,7 @@
 
   // net::URLRequestTestJob:
   void Start() override {
-    scoped_refptr<net::SSLCertRequestInfo> cert_request_info(
-        new net::SSLCertRequestInfo);
+    auto cert_request_info = base::MakeRefCounted<net::SSLCertRequestInfo>();
     cert_request_info->cert_authorities = test_authorities();
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
diff --git a/content/browser/memory/memory_monitor.cc b/content/browser/memory/memory_monitor.cc
deleted file mode 100644
index a9e16845..0000000
--- a/content/browser/memory/memory_monitor.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/memory/memory_monitor.h"
-
-#include "base/process/process_metrics.h"
-
-namespace content {
-
-// static
-MemoryMonitorDelegate* MemoryMonitorDelegate::GetInstance() {
-  return base::Singleton<
-      MemoryMonitorDelegate,
-      base::LeakySingletonTraits<MemoryMonitorDelegate>>::get();
-}
-
-MemoryMonitorDelegate::~MemoryMonitorDelegate() {}
-
-void MemoryMonitorDelegate::GetSystemMemoryInfo(
-    base::SystemMemoryInfoKB* mem_info) {
-  base::GetSystemMemoryInfo(mem_info);
-}
-
-#if defined(OS_MACOSX)
-// TODO(bashi,bcwhite): Remove when memory monitor for mac is available.
-std::unique_ptr<MemoryMonitor> CreateMemoryMonitor() {
-  NOTREACHED();
-  return std::unique_ptr<MemoryMonitor>();
-}
-#endif
-
-}  // namespace content
diff --git a/content/browser/memory/memory_monitor.h b/content/browser/memory/memory_monitor.h
deleted file mode 100644
index a9d0f21..0000000
--- a/content/browser/memory/memory_monitor.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_MEMORY_BROWSER_MEMORY_MONITOR_H_
-#define CONTENT_BROWSER_MEMORY_BROWSER_MEMORY_MONITOR_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/singleton.h"
-#include "content/common/content_export.h"
-
-namespace base {
-struct SystemMemoryInfoKB;
-}
-
-namespace content {
-
-// A simple class that monitors the amount of free memory available on a system.
-// This is an interface to facilitate dependency injection for testing.
-class CONTENT_EXPORT MemoryMonitor {
- public:
-  MemoryMonitor() {}
-  virtual ~MemoryMonitor() {}
-
-  // Returns the amount of free memory available on the system until the system
-  // will be in a critical state. Critical is as defined by the OS (swapping
-  // will occur, or physical memory will run out, etc). It is possible for this
-  // to return negative values, in which case that much memory would have to be
-  // freed in order to exit a critical memory state.
-  virtual int GetFreeMemoryUntilCriticalMB() = 0;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(MemoryMonitor);
-};
-
-// Factory function for creating a monitor for the current platform.
-CONTENT_EXPORT std::unique_ptr<MemoryMonitor> CreateMemoryMonitor();
-
-// A class for fetching system information used by a memory monitor. This can
-// be subclassed for testing or if a particular MemoryMonitor implementation
-// needs additional functionality.
-class CONTENT_EXPORT MemoryMonitorDelegate {
- public:
-  static MemoryMonitorDelegate* GetInstance();
-
-  MemoryMonitorDelegate() {}
-  virtual ~MemoryMonitorDelegate();
-
-  // Returns system memory information.
-  virtual void GetSystemMemoryInfo(base::SystemMemoryInfoKB* mem_info);
-
- private:
-  friend struct base::DefaultSingletonTraits<MemoryMonitorDelegate>;
-
-  DISALLOW_COPY_AND_ASSIGN(MemoryMonitorDelegate);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_MEMORY_BROWSER_MEMORY_MONITOR_H_
diff --git a/content/browser/memory/memory_monitor_android.cc b/content/browser/memory/memory_monitor_android.cc
deleted file mode 100644
index 0d316bb..0000000
--- a/content/browser/memory/memory_monitor_android.cc
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/memory/memory_monitor_android.h"
-
-#include "base/android/jni_android.h"
-#include "base/memory/memory_pressure_listener.h"
-#include "base/memory/ptr_util.h"
-#include "content/public/android/content_jni_headers/MemoryMonitorAndroid_jni.h"
-
-namespace content {
-
-namespace {
-
-const size_t kMBShift = 20;
-
-void RegisterComponentCallbacks() {
-  Java_MemoryMonitorAndroid_registerComponentCallbacks(
-      base::android::AttachCurrentThread());
-}
-
-}
-
-// An implementation of MemoryMonitorAndroid::Delegate using the Android APIs.
-class MemoryMonitorAndroidDelegateImpl : public MemoryMonitorAndroid::Delegate {
- public:
-  MemoryMonitorAndroidDelegateImpl() {}
-  ~MemoryMonitorAndroidDelegateImpl() override {}
-
-  using MemoryInfo = MemoryMonitorAndroid::MemoryInfo;
-  void GetMemoryInfo(MemoryInfo* out) override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(MemoryMonitorAndroidDelegateImpl);
-};
-
-void MemoryMonitorAndroidDelegateImpl::GetMemoryInfo(MemoryInfo* out) {
-  DCHECK(out);
-  JNIEnv* env = base::android::AttachCurrentThread();
-  Java_MemoryMonitorAndroid_getMemoryInfo(env, reinterpret_cast<intptr_t>(out));
-}
-
-// Called by JNI to populate ActivityManager.MemoryInfo.
-static void JNI_MemoryMonitorAndroid_GetMemoryInfoCallback(
-    JNIEnv* env,
-    jlong avail_mem,
-    jboolean low_memory,
-    jlong threshold,
-    jlong total_mem,
-    jlong out_ptr) {
-  DCHECK(out_ptr);
-  MemoryMonitorAndroid::MemoryInfo* info =
-      reinterpret_cast<MemoryMonitorAndroid::MemoryInfo*>(out_ptr);
-  info->avail_mem = avail_mem;
-  info->low_memory = low_memory;
-  info->threshold = threshold;
-  info->total_mem = total_mem;
-}
-
-// The maximum level of onTrimMemory (TRIM_MEMORY_COMPLETE).
-const int kTrimMemoryLevelMax = 80;
-const int kTrimMemoryRunningCritical = 15;
-
-// Called by JNI.
-static void JNI_MemoryMonitorAndroid_OnTrimMemory(
-    JNIEnv* env,
-    jint level) {
-  DCHECK(level >= 0 && level <= kTrimMemoryLevelMax);
-
-  if (level >= kTrimMemoryRunningCritical) {
-    base::MemoryPressureListener::NotifyMemoryPressure(
-        base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
-  }
-}
-
-// static
-std::unique_ptr<MemoryMonitorAndroid> MemoryMonitorAndroid::Create() {
-  auto delegate = base::WrapUnique(new MemoryMonitorAndroidDelegateImpl);
-  return base::WrapUnique(new MemoryMonitorAndroid(std::move(delegate)));
-}
-
-MemoryMonitorAndroid::MemoryMonitorAndroid(std::unique_ptr<Delegate> delegate)
-    : delegate_(std::move(delegate)) {
-  DCHECK(delegate_.get());
-  RegisterComponentCallbacks();
-}
-
-MemoryMonitorAndroid::~MemoryMonitorAndroid() {}
-
-int MemoryMonitorAndroid::GetFreeMemoryUntilCriticalMB() {
-  MemoryInfo info;
-  GetMemoryInfo(&info);
-  return (info.avail_mem - info.threshold) >> kMBShift;
-}
-
-void MemoryMonitorAndroid::GetMemoryInfo(MemoryInfo* out) {
-  delegate_->GetMemoryInfo(out);
-}
-
-// Implementation of a factory function defined in memory_monitor.h.
-std::unique_ptr<MemoryMonitor> CreateMemoryMonitor() {
-  return MemoryMonitorAndroid::Create();
-}
-
-}  // namespace content
diff --git a/content/browser/memory/memory_monitor_android.h b/content/browser/memory/memory_monitor_android.h
deleted file mode 100644
index 58b6981..0000000
--- a/content/browser/memory/memory_monitor_android.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_MEMORY_MEMORY_MONITOR_ANDROID_H_
-#define CONTENT_BROWSER_MEMORY_MEMORY_MONITOR_ANDROID_H_
-
-#include <jni.h>
-
-#include "base/android/application_status_listener.h"
-#include "content/browser/memory/memory_monitor.h"
-
-namespace content {
-
-// A memory monitor for the Android system.
-class CONTENT_EXPORT MemoryMonitorAndroid : public MemoryMonitor {
- public:
-  static std::unique_ptr<MemoryMonitorAndroid> Create();
-
-  // C++ counter-part of ActivityManager.MemoryInfo
-  struct MemoryInfo {
-    jlong avail_mem;
-    jboolean low_memory;
-    jlong threshold;
-    jlong total_mem;
-  };
-
-  // Delegate interface used by MemoryMonitorAndroid.
-  class Delegate {
-   public:
-    Delegate() {}
-    virtual ~Delegate() {}
-
-    // Get MemoryInfo. Implementations should fill |out| accordingly.
-    virtual void GetMemoryInfo(MemoryInfo* out) = 0;
-  };
-
-  MemoryMonitorAndroid(std::unique_ptr<Delegate> delegate);
-  ~MemoryMonitorAndroid() override;
-
-  // MemoryMonitor implementation:
-  int GetFreeMemoryUntilCriticalMB() override;
-
-  // Get memory info from the Android system.
-  void GetMemoryInfo(MemoryInfo* out);
-
-  Delegate* delegate() { return delegate_.get(); }
-
- private:
-  std::unique_ptr<Delegate> delegate_;
-
-  DISALLOW_COPY_AND_ASSIGN(MemoryMonitorAndroid);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_MEMORY_MEMORY_MONITOR_ANDROID_H_
diff --git a/content/browser/memory/memory_monitor_android_unittest.cc b/content/browser/memory/memory_monitor_android_unittest.cc
deleted file mode 100644
index 7c62d5f1..0000000
--- a/content/browser/memory/memory_monitor_android_unittest.cc
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/memory/memory_monitor_android.h"
-
-#include "base/memory/ptr_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace content {
-
-class MockMemoryMonitorAndroidDelegate : public MemoryMonitorAndroid::Delegate {
- public:
-  MockMemoryMonitorAndroidDelegate() {}
-  ~MockMemoryMonitorAndroidDelegate() override {}
-
-  using MemoryInfo = MemoryMonitorAndroid::MemoryInfo;
-
-  void SetMemoryInfo(const MemoryInfo& info) {
-    memcpy(&memory_info_, &info, sizeof(memory_info_));
-  }
-
-  void GetMemoryInfo(MemoryInfo* out) override {
-    memcpy(out, &memory_info_, sizeof(memory_info_));
-  }
-
- private:
-  MemoryInfo memory_info_;
-
-  DISALLOW_COPY_AND_ASSIGN(MockMemoryMonitorAndroidDelegate);
-};
-
-class MemoryMonitorAndroidTest : public testing::Test {
- public:
-  MemoryMonitorAndroidTest() : monitor_(MemoryMonitorAndroid::Create()) {
-    auto mock_delegate = base::WrapUnique(new MockMemoryMonitorAndroidDelegate);
-    mocked_monitor_.reset(
-        new MemoryMonitorAndroid(std::move(mock_delegate)));
-  }
-
- protected:
-  static const int kMBShift = 20;
-
-  MockMemoryMonitorAndroidDelegate* mock_delegate() {
-    return static_cast<MockMemoryMonitorAndroidDelegate*>(
-        mocked_monitor_->delegate());
-  }
-
-  std::unique_ptr<MemoryMonitorAndroid> monitor_;
-  std::unique_ptr<MemoryMonitorAndroid> mocked_monitor_;
-};
-
-TEST_F(MemoryMonitorAndroidTest, GetMemoryInfo) {
-  MemoryMonitorAndroid::MemoryInfo info;
-  monitor_->GetMemoryInfo(&info);
-  EXPECT_GT(info.avail_mem, 0);
-  EXPECT_GT(info.threshold, 0);
-  EXPECT_GT(info.total_mem, 0);
-}
-
-TEST_F(MemoryMonitorAndroidTest, GetFreeMemoryUntilCriticalMB) {
-  MemoryMonitorAndroid::MemoryInfo info = {
-    .avail_mem = 100 << kMBShift,
-    .low_memory = false,
-    .threshold = 80 << kMBShift,
-    .total_mem = 150 << kMBShift,
-  };
-  mock_delegate()->SetMemoryInfo(info);
-  EXPECT_EQ(20, mocked_monitor_->GetFreeMemoryUntilCriticalMB());
-}
-
-}  // namespace content
diff --git a/content/browser/memory/memory_monitor_chromeos.cc b/content/browser/memory/memory_monitor_chromeos.cc
deleted file mode 100644
index 64450af..0000000
--- a/content/browser/memory/memory_monitor_chromeos.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/memory/memory_monitor_chromeos.h"
-
-#include "base/process/process_metrics.h"
-
-namespace content {
-
-namespace {
-
-// The number of bits to shift to convert KiB to MiB.
-const int kShiftKiBtoMiB = 10;
-
-}  // namespace
-
-MemoryMonitorChromeOS::MemoryMonitorChromeOS(MemoryMonitorDelegate* delegate)
-    : delegate_(delegate) {}
-
-MemoryMonitorChromeOS::~MemoryMonitorChromeOS() {}
-
-int MemoryMonitorChromeOS::GetFreeMemoryUntilCriticalMB() {
-  base::SystemMemoryInfoKB mem_info = {};
-  delegate_->GetSystemMemoryInfo(&mem_info);
-
-  // Use available free memory provided by the OS if the OS supports it.
-  if (mem_info.available > 0)
-    return mem_info.available >> kShiftKiBtoMiB;
-
-  // The kernel internally uses 50MB.
-  const int kMinFileMemory = 50 * 1024;
-
-  // Most file memory can be easily reclaimed.
-  int file_memory = mem_info.active_file + mem_info.inactive_file;
-  // unless it is dirty or it's a minimal portion which is required.
-  file_memory -= mem_info.dirty + kMinFileMemory;
-
-  // Available memory is the sum of free and easy reclaimable memory.
-  return (mem_info.free + file_memory) >> kShiftKiBtoMiB;
-}
-
-// static
-std::unique_ptr<MemoryMonitorChromeOS> MemoryMonitorChromeOS::Create(
-    MemoryMonitorDelegate* delegate) {
-  return std::make_unique<MemoryMonitorChromeOS>(delegate);
-}
-
-// Implementation of factory function defined in memory_monitor.h.
-std::unique_ptr<MemoryMonitor> CreateMemoryMonitor() {
-  return MemoryMonitorChromeOS::Create(MemoryMonitorDelegate::GetInstance());
-}
-
-}  // namespace content
diff --git a/content/browser/memory/memory_monitor_chromeos.h b/content/browser/memory/memory_monitor_chromeos.h
deleted file mode 100644
index f007a7d..0000000
--- a/content/browser/memory/memory_monitor_chromeos.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_MEMORY_MEMORY_MONITOR_CHROMEOS_H_
-#define CONTENT_BROWSER_MEMORY_MEMORY_MONITOR_CHROMEOS_H_
-
-#include "content/browser/memory/memory_monitor.h"
-#include "content/common/content_export.h"
-
-namespace content {
-
-// A memory monitor for the ChromeOS platform.
-class CONTENT_EXPORT MemoryMonitorChromeOS : public MemoryMonitor {
- public:
-  MemoryMonitorChromeOS(MemoryMonitorDelegate* delegate);
-  ~MemoryMonitorChromeOS() override;
-
-  // MemoryMonitor:
-  int GetFreeMemoryUntilCriticalMB() override;
-
-  // Factory function to create an instance of this class.
-  static std::unique_ptr<MemoryMonitorChromeOS> Create(
-      MemoryMonitorDelegate* delegate);
-
- private:
-  // The delegate to be used for retrieving system memory information. Used as a
-  // testing seam.
-  MemoryMonitorDelegate* delegate_;
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_MEMORY_MEMORY_MONITOR_CHROMEOS_H_
diff --git a/content/browser/memory/memory_monitor_chromeos_unittest.cc b/content/browser/memory/memory_monitor_chromeos_unittest.cc
deleted file mode 100644
index 905fe8f0..0000000
--- a/content/browser/memory/memory_monitor_chromeos_unittest.cc
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/memory/memory_monitor_chromeos.h"
-
-#include "content/browser/memory/test_memory_monitor.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace content {
-
-namespace {
-
-// A delegate that allows mocking the various inputs to MemoryMonitorChromeOS.
-class TestMemoryMonitorChromeOSDelegate : public TestMemoryMonitorDelegate {
- public:
-  TestMemoryMonitorChromeOSDelegate() {}
-
-  void SetFreeMemoryKB(int free_kb,
-                       int swap_kb,
-                       int active_kb,
-                       int inactive_kb,
-                       int dirty_kb,
-                       int available_kb) {
-    mem_info_.free = free_kb;
-    mem_info_.swap_free = swap_kb;
-    mem_info_.active_file = active_kb;
-    mem_info_.inactive_file = inactive_kb;
-    mem_info_.dirty = dirty_kb;
-    mem_info_.available = available_kb;
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TestMemoryMonitorChromeOSDelegate);
-};
-
-class TestMemoryMonitorChromeOS : public MemoryMonitorChromeOS {};
-
-static const int kKBperMB = 1024;
-
-}  // namespace
-
-class MemoryMonitorChromeOSTest : public testing::Test {
- public:
-  TestMemoryMonitorChromeOSDelegate delegate_;
-  std::unique_ptr<MemoryMonitorChromeOS> monitor_;
-};
-
-TEST_F(MemoryMonitorChromeOSTest, Create) {
-  delegate_.SetTotalMemoryKB(100000 * kKBperMB);
-  monitor_ = MemoryMonitorChromeOS::Create(&delegate_);
-  EXPECT_EQ(0U, delegate_.calls());
-}
-
-TEST_F(MemoryMonitorChromeOSTest, GetFreeMemoryUntilCriticalMB) {
-  delegate_.SetTotalMemoryKB(1000 * kKBperMB);
-
-  monitor_.reset(new MemoryMonitorChromeOS(&delegate_));
-  EXPECT_EQ(0u, delegate_.calls());
-
-  // |available| is supported.
-  delegate_.SetFreeMemoryKB(1 * kKBperMB, 1 * kKBperMB, 1 * kKBperMB,
-                            1 * kKBperMB, 1 * kKBperMB, 286 * kKBperMB);
-  EXPECT_EQ(286, monitor_->GetFreeMemoryUntilCriticalMB());
-  EXPECT_EQ(1U, delegate_.calls());
-
-  // |available| is not supported.
-  delegate_.SetFreeMemoryKB(256 * kKBperMB, 128 * kKBperMB, 64 * kKBperMB,
-                            32 * kKBperMB, 16 * kKBperMB, 0 * kKBperMB);
-  EXPECT_EQ(286, monitor_->GetFreeMemoryUntilCriticalMB());
-  EXPECT_EQ(2U, delegate_.calls());
-}
-
-}  // namespace content
diff --git a/content/browser/memory/memory_monitor_fuchsia.cc b/content/browser/memory/memory_monitor_fuchsia.cc
deleted file mode 100644
index 9bcbf8d3..0000000
--- a/content/browser/memory/memory_monitor_fuchsia.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/memory/memory_monitor.h"
-
-#include "base/logging.h"
-
-namespace content {
-
-// TODO(crbug.com/707031): Implement this.
-std::unique_ptr<MemoryMonitor> CreateMemoryMonitor() {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
-}  // namespace content
diff --git a/content/browser/memory/memory_monitor_linux.cc b/content/browser/memory/memory_monitor_linux.cc
deleted file mode 100644
index 43f108d7..0000000
--- a/content/browser/memory/memory_monitor_linux.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/memory/memory_monitor_linux.h"
-
-#include "base/process/process_metrics.h"
-
-namespace content {
-
-namespace {
-
-// The number of bits to shift to convert KiB to MiB.
-const int kShiftKiBtoMiB = 10;
-
-}  // namespace
-
-MemoryMonitorLinux::MemoryMonitorLinux(MemoryMonitorDelegate* delegate)
-    : delegate_(delegate) {}
-
-MemoryMonitorLinux::~MemoryMonitorLinux() {}
-
-int MemoryMonitorLinux::GetFreeMemoryUntilCriticalMB() {
-  base::SystemMemoryInfoKB mem_info = {};
-  delegate_->GetSystemMemoryInfo(&mem_info);
-
-  // According to kernel commit 34e431b0ae398fc54ea69ff85ec700722c9da773,
-  // "available" is the "amount of memory that is available for a new workload
-  // without pushing the system into swap"; return that value if it is valid.
-  // Old linux kernels (before 3.14) don't support "available" and show zero
-  // instead.
-  if (mem_info.available > 0)
-    return mem_info.available >> kShiftKiBtoMiB;
-
-  // If there is no "available" value, guess at it based on free memory.
-  // Though there will be easily discardable memory (buffers and caches), we
-  // don't count them because discarding them will affect the overall
-  // performance of the OS.
-  return mem_info.free >> kShiftKiBtoMiB;
-}
-
-// static
-std::unique_ptr<MemoryMonitorLinux> MemoryMonitorLinux::Create(
-    MemoryMonitorDelegate* delegate) {
-  return std::make_unique<MemoryMonitorLinux>(delegate);
-}
-
-// Implementation of factory function defined in memory_monitor.h.
-std::unique_ptr<MemoryMonitor> CreateMemoryMonitor() {
-  return MemoryMonitorLinux::Create(MemoryMonitorDelegate::GetInstance());
-}
-
-}  // namespace content
diff --git a/content/browser/memory/memory_monitor_linux.h b/content/browser/memory/memory_monitor_linux.h
deleted file mode 100644
index 5b92b80..0000000
--- a/content/browser/memory/memory_monitor_linux.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_MEMORY_MEMORY_MONITOR_LINUX_H_
-#define CONTENT_BROWSER_MEMORY_MEMORY_MONITOR_LINUX_H_
-
-#include "content/browser/memory/memory_monitor.h"
-#include "content/common/content_export.h"
-
-namespace content {
-
-// A memory monitor for the Linux platform.
-class CONTENT_EXPORT MemoryMonitorLinux : public MemoryMonitor {
- public:
-  MemoryMonitorLinux(MemoryMonitorDelegate* delegate);
-  ~MemoryMonitorLinux() override;
-
-  // MemoryMonitor:
-  int GetFreeMemoryUntilCriticalMB() override;
-
-  // Factory function to create an instance of this class.
-  static std::unique_ptr<MemoryMonitorLinux> Create(
-      MemoryMonitorDelegate* delegate);
-
- private:
-  // The delegate to be used for retrieving system memory information. Used as a
-  // testing seam.
-  MemoryMonitorDelegate* delegate_;
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_MEMORY_MEMORY_MONITOR_LINUX_H_
diff --git a/content/browser/memory/memory_monitor_linux_unittest.cc b/content/browser/memory/memory_monitor_linux_unittest.cc
deleted file mode 100644
index 7914b0f..0000000
--- a/content/browser/memory/memory_monitor_linux_unittest.cc
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/memory/memory_monitor_linux.h"
-
-#include "content/browser/memory/test_memory_monitor.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace content {
-
-namespace {
-
-// A delegate that allows mocking the various inputs to MemoryMonitorLinux.
-class TestMemoryMonitorLinuxDelegate : public TestMemoryMonitorDelegate {
- public:
-  TestMemoryMonitorLinuxDelegate() {}
-
-  void SetAvailableMemoryKB(int available_memory_kb) {
-    // If this is set, other "free" values are ignored.
-    mem_info_.available = available_memory_kb;
-  }
-
-  void SetFreeMemoryKB(int free_kb, int cached_kb, int buffers_kb) {
-    mem_info_.free = free_kb;
-    mem_info_.cached = cached_kb;
-    mem_info_.buffers = buffers_kb;
-
-    // Only if this is zero will the above values be used.
-    mem_info_.available = 0;
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TestMemoryMonitorLinuxDelegate);
-};
-
-class TestMemoryMonitorLinux : public MemoryMonitorLinux {};
-
-static const int kKBperMB = 1024;
-
-}  // namespace
-
-class MemoryMonitorLinuxTest : public testing::Test {
- public:
-  TestMemoryMonitorLinuxDelegate delegate_;
-  std::unique_ptr<MemoryMonitorLinux> monitor_;
-};
-
-TEST_F(MemoryMonitorLinuxTest, Create) {
-  delegate_.SetTotalMemoryKB(100000 * kKBperMB);
-  monitor_ = MemoryMonitorLinux::Create(&delegate_);
-  EXPECT_EQ(0U, delegate_.calls());
-}
-
-TEST_F(MemoryMonitorLinuxTest, GetFreeMemoryUntilCriticalMB) {
-  delegate_.SetTotalMemoryKB(1000 * kKBperMB);
-
-  monitor_.reset(new MemoryMonitorLinux(&delegate_));
-  EXPECT_EQ(0u, delegate_.calls());
-
-  delegate_.SetAvailableMemoryKB(200 * kKBperMB);
-  EXPECT_EQ(200, monitor_->GetFreeMemoryUntilCriticalMB());
-  EXPECT_EQ(1U, delegate_.calls());
-  delegate_.ResetCalls();
-
-  delegate_.SetFreeMemoryKB(64 * kKBperMB, 32 * kKBperMB, 16 * kKBperMB);
-  EXPECT_EQ(64, monitor_->GetFreeMemoryUntilCriticalMB());
-  EXPECT_EQ(1U, delegate_.calls());
-  delegate_.ResetCalls();
-
-  delegate_.SetFreeMemoryKB(0, 0, 0);
-  EXPECT_EQ(0, monitor_->GetFreeMemoryUntilCriticalMB());
-  EXPECT_EQ(1U, delegate_.calls());
-  delegate_.ResetCalls();
-}
-
-}  // namespace content
diff --git a/content/browser/memory/memory_monitor_win.cc b/content/browser/memory/memory_monitor_win.cc
deleted file mode 100644
index 979bb28..0000000
--- a/content/browser/memory/memory_monitor_win.cc
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/memory/memory_monitor_win.h"
-
-#include "base/process/process_metrics.h"
-
-// TODO(chrisha): Implement a mechanism for observing swapping, and updating the
-// memory threshold on a per machine basis.
-
-namespace content {
-
-namespace {
-
-const int kKBperMB = 1024;
-
-}  // namespace
-
-// A system is considered 'large memory' if it has more than 1.5GB of system
-// memory available for use by the memory manager (not reserved for hardware
-// and drivers). This is a fuzzy version of the ~2GB discussed below.
-const int MemoryMonitorWin::kLargeMemoryThresholdMB = 1536;
-
-// This is the target free memory used for systems with < ~2GB of physical
-// memory. Such systems have been observed to always maintain ~100MB of
-// available memory, paging until that is the case. To try to avoid paging a
-// threshold slightly above this is chosen.
-const int MemoryMonitorWin::kSmallMemoryTargetFreeMB = 200;
-
-// This is the target free memory used for systems with >= ~2GB of physical
-// memory. Such systems have been observed to always maintain ~300MB of
-// available memory, paging until that is the case.
-const int MemoryMonitorWin::kLargeMemoryTargetFreeMB = 400;
-
-MemoryMonitorWin::MemoryMonitorWin(MemoryMonitorDelegate* delegate,
-                                   int target_free_mb)
-    : delegate_(delegate), target_free_mb_(target_free_mb) {}
-
-int MemoryMonitorWin::GetFreeMemoryUntilCriticalMB() {
-  base::SystemMemoryInfoKB mem_info = {};
-  delegate_->GetSystemMemoryInfo(&mem_info);
-  int free_mb = mem_info.avail_phys / kKBperMB;
-  free_mb -= target_free_mb_;
-  return free_mb;
-}
-
-// static
-std::unique_ptr<MemoryMonitorWin> MemoryMonitorWin::Create(
-    MemoryMonitorDelegate* delegate) {
-  return std::unique_ptr<MemoryMonitorWin>(new MemoryMonitorWin(
-      delegate, GetTargetFreeMB(delegate)));
-}
-
-// static
-bool MemoryMonitorWin::IsLargeMemory(MemoryMonitorDelegate* delegate) {
-  base::SystemMemoryInfoKB mem_info = {};
-  delegate->GetSystemMemoryInfo(&mem_info);
-  return (mem_info.total / kKBperMB) >=
-      MemoryMonitorWin::kLargeMemoryThresholdMB;
-}
-
-// static
-int MemoryMonitorWin::GetTargetFreeMB(MemoryMonitorDelegate* delegate) {
-  if (IsLargeMemory(delegate))
-    return MemoryMonitorWin::kLargeMemoryTargetFreeMB;
-  return MemoryMonitorWin::kSmallMemoryTargetFreeMB;
-}
-
-// Implementation of factory function defined in memory_monitor.h.
-std::unique_ptr<MemoryMonitor> CreateMemoryMonitor() {
-  return MemoryMonitorWin::Create(MemoryMonitorDelegate::GetInstance());
-}
-
-}  // namespace content
diff --git a/content/browser/memory/memory_monitor_win.h b/content/browser/memory/memory_monitor_win.h
deleted file mode 100644
index bb2d121..0000000
--- a/content/browser/memory/memory_monitor_win.h
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_MEMORY_BROWSER_MEMORY_MONITOR_WIN_H_
-#define CONTENT_BROWSER_MEMORY_BROWSER_MEMORY_MONITOR_WIN_H_
-
-#include "content/browser/memory/memory_monitor.h"
-
-namespace base {
-struct SystemMemoryInfoKB;
-}  // namespace base
-
-namespace content {
-
-// A memory monitor for the Windows platform. After much experimentation this
-// class uses a very simple heuristic to anticipate paging (critical memory
-// pressure). When the amount of memory available dips below a provided
-// threshold, it is assumed that paging is inevitable.
-class CONTENT_EXPORT MemoryMonitorWin : public MemoryMonitor {
- public:
-  // Default constants governing the amount of free memory that the memory
-  // manager attempts to maintain.
-  static const int kLargeMemoryThresholdMB;
-  static const int kSmallMemoryTargetFreeMB;
-  static const int kLargeMemoryTargetFreeMB;
-
-  MemoryMonitorWin(MemoryMonitorDelegate* delegate, int target_free_mb);
-  ~MemoryMonitorWin() override {}
-
-  // MemoryMonitor:
-  int GetFreeMemoryUntilCriticalMB() override;
-
-  // Returns the current free memory target.
-  int target_free_mb() const { return target_free_mb_; }
-
-  // Factory function. Automatically sizes |target_free_mb| based on the
-  // system.
-  static std::unique_ptr<MemoryMonitorWin> Create(
-      MemoryMonitorDelegate* delegate);
-
- protected:
-  // Determines if the system is in large memory mode. Exposed so that this
-  // function can be tested.
-  static bool IsLargeMemory(MemoryMonitorDelegate* delegate);
-
-  // Determines the default target free MB value. Exposed so that this function
-  // can be tested.
-  static int GetTargetFreeMB(MemoryMonitorDelegate* delegate);
-
- private:
-  // The delegate to be used for retrieving system memory information. Used as a
-  // testing seam.
-  MemoryMonitorDelegate* delegate_;
-
-  // The amount of memory that the memory manager (MM) attempts to keep in a
-  // free state. When less than this amount of physical memory is free, it is
-  // assumed that the MM will start paging things out.
-  int target_free_mb_;
-};
-
-// A delegate that wraps functions used by MemoryMonitorWin. Used as a testing
-// seam.
-class CONTENT_EXPORT MemoryMonitorWinDelegate {
- public:
-  MemoryMonitorWinDelegate() {}
-  virtual ~MemoryMonitorWinDelegate() {}
-
-  // Returns system memory information.
-  virtual void GetSystemMemoryInfo(base::SystemMemoryInfoKB* mem_info) = 0;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(MemoryMonitorWinDelegate);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_MEMORY_BROWSER_MEMORY_MONITOR_WIN_H_
diff --git a/content/browser/memory/memory_monitor_win_unittest.cc b/content/browser/memory/memory_monitor_win_unittest.cc
deleted file mode 100644
index ea22ac3e..0000000
--- a/content/browser/memory/memory_monitor_win_unittest.cc
+++ /dev/null
@@ -1,138 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/memory/memory_monitor_win.h"
-
-#include "content/browser/memory/test_memory_monitor.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace content {
-
-namespace {
-
-// A delegate that allows mocking the various inputs to MemoryMonitorWin.
-class TestMemoryMonitorWinDelegate : public TestMemoryMonitorDelegate {
- public:
-  TestMemoryMonitorWinDelegate() {}
-
-  void SetFreeMemoryKB(int free_memory_kb) {
-    mem_info_.avail_phys = free_memory_kb;
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TestMemoryMonitorWinDelegate);
-};
-
-class TestMemoryMonitorWin : public MemoryMonitorWin {
- public:
-  using MemoryMonitorWin::IsLargeMemory;
-  using MemoryMonitorWin::GetTargetFreeMB;
-};
-
-static const int kKBperMB = 1024;
-
-}  // namespace
-
-class MemoryMonitorWinTest : public testing::Test {
- public:
-  TestMemoryMonitorWinDelegate delegate_;
-  std::unique_ptr<MemoryMonitorWin> monitor_;
-};
-
-TEST_F(MemoryMonitorWinTest, IsLargeMemory) {
-  delegate_.SetTotalMemoryKB(
-        MemoryMonitorWin::kLargeMemoryThresholdMB * kKBperMB  - 1);
-  EXPECT_FALSE(TestMemoryMonitorWin::IsLargeMemory(&delegate_));
-  EXPECT_EQ(1u, delegate_.calls());
-  delegate_.ResetCalls();
-
-  delegate_.SetTotalMemoryKB(
-        MemoryMonitorWin::kLargeMemoryThresholdMB * kKBperMB);
-  EXPECT_TRUE(TestMemoryMonitorWin::IsLargeMemory(&delegate_));
-  EXPECT_EQ(1u, delegate_.calls());
-  delegate_.ResetCalls();
-
-  delegate_.SetTotalMemoryKB(
-        MemoryMonitorWin::kLargeMemoryThresholdMB * kKBperMB + 100);
-  EXPECT_TRUE(TestMemoryMonitorWin::IsLargeMemory(&delegate_));
-  EXPECT_EQ(1u, delegate_.calls());
-  delegate_.ResetCalls();
-}
-
-TEST_F(MemoryMonitorWinTest, GetTargetFreeMB) {
-  delegate_.SetTotalMemoryKB(
-        MemoryMonitorWin::kLargeMemoryThresholdMB * kKBperMB  - 1);
-  EXPECT_EQ(MemoryMonitorWin::kSmallMemoryTargetFreeMB,
-            TestMemoryMonitorWin::GetTargetFreeMB(&delegate_));
-  EXPECT_EQ(1u, delegate_.calls());
-  delegate_.ResetCalls();
-
-  delegate_.SetTotalMemoryKB(
-        MemoryMonitorWin::kLargeMemoryThresholdMB * kKBperMB);
-  EXPECT_EQ(MemoryMonitorWin::kLargeMemoryTargetFreeMB,
-            TestMemoryMonitorWin::GetTargetFreeMB(&delegate_));
-  EXPECT_EQ(1u, delegate_.calls());
-  delegate_.ResetCalls();
-
-  delegate_.SetTotalMemoryKB(
-        MemoryMonitorWin::kLargeMemoryThresholdMB * kKBperMB + 100);
-  EXPECT_EQ(MemoryMonitorWin::kLargeMemoryTargetFreeMB,
-            TestMemoryMonitorWin::GetTargetFreeMB(&delegate_));
-  EXPECT_EQ(1u, delegate_.calls());
-  delegate_.ResetCalls();
-}
-
-TEST_F(MemoryMonitorWinTest, Create) {
-  delegate_.SetTotalMemoryKB(
-        MemoryMonitorWin::kLargeMemoryThresholdMB * kKBperMB  - 1);
-  monitor_ = MemoryMonitorWin::Create(&delegate_);
-  EXPECT_EQ(MemoryMonitorWin::kSmallMemoryTargetFreeMB,
-            monitor_->target_free_mb());
-  EXPECT_EQ(1u, delegate_.calls());
-  delegate_.ResetCalls();
-
-  delegate_.SetTotalMemoryKB(
-        MemoryMonitorWin::kLargeMemoryThresholdMB * kKBperMB);
-  monitor_ = MemoryMonitorWin::Create(&delegate_);
-  EXPECT_EQ(MemoryMonitorWin::kLargeMemoryTargetFreeMB,
-            monitor_->target_free_mb());
-  EXPECT_EQ(1u, delegate_.calls());
-  delegate_.ResetCalls();
-
-  delegate_.SetTotalMemoryKB(
-        MemoryMonitorWin::kLargeMemoryThresholdMB * kKBperMB + 100);
-  monitor_ = MemoryMonitorWin::Create(&delegate_);
-  EXPECT_EQ(MemoryMonitorWin::kLargeMemoryTargetFreeMB,
-            monitor_->target_free_mb());
-  EXPECT_EQ(1u, delegate_.calls());
-  delegate_.ResetCalls();
-}
-
-TEST_F(MemoryMonitorWinTest, Constructor) {
-  monitor_.reset(new MemoryMonitorWin(&delegate_, 100));
-  EXPECT_EQ(100, monitor_->target_free_mb());
-  EXPECT_EQ(0u, delegate_.calls());
-
-  monitor_.reset(new MemoryMonitorWin(&delegate_, 387));
-  EXPECT_EQ(387, monitor_->target_free_mb());
-  EXPECT_EQ(0u, delegate_.calls());
-}
-
-TEST_F(MemoryMonitorWinTest, GetFreeMemoryUntilCriticalMB) {
-  monitor_.reset(new MemoryMonitorWin(&delegate_, 100));
-  EXPECT_EQ(100, monitor_->target_free_mb());
-  EXPECT_EQ(0u, delegate_.calls());
-
-  delegate_.SetFreeMemoryKB(200 * kKBperMB);
-  EXPECT_EQ(100, monitor_->GetFreeMemoryUntilCriticalMB());
-  EXPECT_EQ(1u, delegate_.calls());
-  delegate_.ResetCalls();
-
-  delegate_.SetFreeMemoryKB(50 * kKBperMB);
-  EXPECT_EQ(-50, monitor_->GetFreeMemoryUntilCriticalMB());
-  EXPECT_EQ(1u, delegate_.calls());
-  delegate_.ResetCalls();
-}
-
-}  // namespace content
diff --git a/content/browser/memory/test_memory_monitor.cc b/content/browser/memory/test_memory_monitor.cc
deleted file mode 100644
index a9bf419..0000000
--- a/content/browser/memory/test_memory_monitor.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/memory/test_memory_monitor.h"
-
-namespace content {
-
-TestMemoryMonitorDelegate::~TestMemoryMonitorDelegate() {}
-
-void TestMemoryMonitorDelegate::GetSystemMemoryInfo(
-    base::SystemMemoryInfoKB* mem_info) {
-  *mem_info = mem_info_;
-  ++calls_;
-}
-
-}  // namespace content
diff --git a/content/browser/memory/test_memory_monitor.h b/content/browser/memory/test_memory_monitor.h
deleted file mode 100644
index 946aa566..0000000
--- a/content/browser/memory/test_memory_monitor.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_MEMORY_TEST_MEMORY_MONITOR_H_
-#define CONTENT_BROWSER_MEMORY_TEST_MEMORY_MONITOR_H_
-
-#include "content/browser/memory/memory_monitor.h"
-
-#include "base/process/process_metrics.h"
-
-namespace content {
-
-// A delegate that allows mocking the various inputs to MemoryMonitor.
-class TestMemoryMonitorDelegate : public MemoryMonitorDelegate {
- public:
-  TestMemoryMonitorDelegate() : calls_(0) { mem_info_ = {}; }
-  ~TestMemoryMonitorDelegate() override;
-
-  void GetSystemMemoryInfo(base::SystemMemoryInfoKB* mem_info) override;
-
-  size_t calls() const { return calls_; }
-  void ResetCalls() { calls_ = 0; }
-
-  void SetTotalMemoryKB(int total_memory_kb) {
-    mem_info_.total = total_memory_kb;
-  }
-
- protected:
-  // Because the fields of SystemMemoryInfoKB vary depending on the operating
-  // system, specific derived classes will have to provide methods to load
-  // values into |mem_info_|;
-  base::SystemMemoryInfoKB mem_info_;
-
- private:
-  size_t calls_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestMemoryMonitorDelegate);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_MEMORY_TEST_MEMORY_MONITOR_H_
diff --git a/content/browser/portal/portal_browsertest.cc b/content/browser/portal/portal_browsertest.cc
index 96b4889..ba0b6d69 100644
--- a/content/browser/portal/portal_browsertest.cc
+++ b/content/browser/portal/portal_browsertest.cc
@@ -7,6 +7,7 @@
 #include "base/test/bind_test_util.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
+#include "components/viz/common/features.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/frame_host/render_frame_host_manager.h"
 #include "content/browser/frame_host/render_frame_proxy_host.h"
@@ -490,9 +491,58 @@
   fdo2.Wait();
 }
 
+// This is for testing how portals interact with input hit testing. It is
+// parameterized on the kind of viz hit testing used.
+class PortalHitTestBrowserTest : public PortalBrowserTest,
+                                 public ::testing::WithParamInterface<bool> {
+ protected:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    PortalBrowserTest::SetUpCommandLine(command_line);
+    const bool use_viz_hit_test_surface_layer = GetParam();
+    if (use_viz_hit_test_surface_layer) {
+      feature_list_.InitAndEnableFeature(
+          features::kEnableVizHitTestSurfaceLayer);
+    } else {
+      feature_list_.InitAndDisableFeature(
+          features::kEnableVizHitTestSurfaceLayer);
+    }
+  }
+
+  base::test::ScopedFeatureList feature_list_;
+};
+
+INSTANTIATE_TEST_SUITE_P(/* no prefix */,
+                         PortalHitTestBrowserTest,
+                         ::testing::Bool());
+
+namespace {
+
+// Fails the test if an input event is sent to the given RenderWidgetHost.
+class FailOnInputEvent : public RenderWidgetHost::InputEventObserver {
+ public:
+  explicit FailOnInputEvent(RenderWidgetHostImpl* rwh)
+      : rwh_(rwh->GetWeakPtr()) {
+    rwh->AddInputEventObserver(this);
+  }
+
+  ~FailOnInputEvent() override {
+    if (rwh_)
+      rwh_->RemoveInputEventObserver(this);
+  }
+
+  void OnInputEvent(const blink::WebInputEvent& event) override {
+    FAIL() << "Unexpected " << blink::WebInputEvent::GetName(event.GetType());
+  }
+
+ private:
+  base::WeakPtr<RenderWidgetHostImpl> rwh_;
+};
+
+}  // namespace
+
 // Tests that input events targeting the portal are only received by the parent
 // renderer.
-IN_PROC_BROWSER_TEST_F(PortalBrowserTest, DispatchInputEvent) {
+IN_PROC_BROWSER_TEST_P(PortalHitTestBrowserTest, DispatchInputEvent) {
   EXPECT_TRUE(NavigateToURL(
       shell(), embedded_test_server()->GetURL("portal.test", "/title1.html")));
   WebContentsImpl* web_contents_impl =
@@ -519,10 +569,7 @@
   navigation_observer.Wait();
   WaitForHitTestDataOrChildSurfaceReady(portal_frame);
 
-  // Create listeners for both widgets.
-  RenderWidgetHostMouseEventMonitor main_frame_monitor(
-      main_frame->GetRenderWidgetHost());
-  RenderWidgetHostMouseEventMonitor portal_frame_monitor(
+  FailOnInputEvent no_input_to_portal_frame(
       portal_frame->GetRenderWidgetHost());
   EXPECT_TRUE(ExecJs(main_frame,
                      "var clicked = false;"
@@ -536,8 +583,6 @@
   // Route the mouse event.
   gfx::Point root_location =
       portal_view->TransformPointToRootCoordSpace(gfx::Point(5, 5));
-  main_frame_monitor.ResetEventReceived();
-  portal_frame_monitor.ResetEventReceived();
   InputEventAckWaiter waiter(main_frame->GetRenderWidgetHost(),
                              blink::WebInputEvent::kMouseDown);
   SimulateRoutedMouseEvent(web_contents_impl, blink::WebInputEvent::kMouseDown,
@@ -546,8 +591,6 @@
   waiter.Wait();
 
   // Check that the click event was only received by the main frame.
-  EXPECT_TRUE(main_frame_monitor.EventWasReceived());
-  EXPECT_FALSE(portal_frame_monitor.EventWasReceived());
   EXPECT_EQ(true, EvalJs(main_frame, "clicked"));
   EXPECT_EQ(false, EvalJs(portal_frame, "clicked"));
 }
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index 11bceb3a..9f76f47 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -638,8 +638,9 @@
       display_->ForceImmediateDrawAndSwapIfPossible();
 
     if (display_) {
-      GetFrameSinkManager()->UnregisterBeginFrameSource(
-          root_window_->GetBeginFrameSource());
+      CompositorDependenciesAndroid::Get()
+          .frame_sink_manager_impl()
+          ->UnregisterBeginFrameSource(root_window_->GetBeginFrameSource());
     }
 
     GetHostFrameSinkManager()->InvalidateFrameSinkId(frame_sink_id_);
@@ -830,7 +831,8 @@
     gpu_capabilities_ = context_provider->ContextCapabilities();
   }
 
-  viz::FrameSinkManagerImpl* manager = GetFrameSinkManager();
+  viz::FrameSinkManagerImpl* manager =
+      CompositorDependenciesAndroid::Get().frame_sink_manager_impl();
   scoped_refptr<base::SingleThreadTaskRunner> task_runner =
       base::ThreadTaskRunnerHandle::Get();
   auto scheduler = std::make_unique<viz::DisplayScheduler>(
@@ -866,8 +868,10 @@
   display_->Resize(size_);
   display_->SetColorSpace(display_color_space_, display_color_space_);
   if (should_register_begin_frame_source) {
-    GetFrameSinkManager()->RegisterBeginFrameSource(
-        root_window_->GetBeginFrameSource(), frame_sink_id_);
+    CompositorDependenciesAndroid::Get()
+        .frame_sink_manager_impl()
+        ->RegisterBeginFrameSource(root_window_->GetBeginFrameSource(),
+                                   frame_sink_id_);
   }
   host_->SetLayerTreeFrameSink(std::move(layer_tree_frame_sink));
 }
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index b298331..775cf8b 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -617,7 +617,6 @@
 
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(RenderWidgetHostImpl, msg)
-    IPC_MESSAGE_HANDLER(FrameHostMsg_HittestData, OnHittestData)
     IPC_MESSAGE_HANDLER(WidgetHostMsg_Close, OnClose)
     IPC_MESSAGE_HANDLER(WidgetHostMsg_UpdateScreenRects_ACK,
                         OnUpdateScreenRectsAck)
@@ -2185,12 +2184,6 @@
   // HandleKeyboardEvent destroys this RenderWidgetHostImpl).
 }
 
-void RenderWidgetHostImpl::OnHittestData(
-    const FrameHostMsg_HittestData_Params& params) {
-  if (delegate_)
-    delegate_->GetInputEventRouter()->OnHittestData(params);
-}
-
 void RenderWidgetHostImpl::OnClose() {
   if (owner_delegate_) {
     owner_delegate_->RenderWidgetDidClose();
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index ec657e6..ca5df334 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -75,7 +75,6 @@
 #endif
 
 class SkBitmap;
-struct FrameHostMsg_HittestData_Params;
 struct WidgetHostMsg_SelectionBounds_Params;
 
 namespace blink {
@@ -856,7 +855,6 @@
   void OnSelectionBoundsChanged(
       const WidgetHostMsg_SelectionBounds_Params& params);
   void OnSetNeedsBeginFrames(bool needs_begin_frames);
-  void OnHittestData(const FrameHostMsg_HittestData_Params& params);
   void OnFocusedNodeTouched(bool editable);
   void OnStartDragging(const DropData& drop_data,
                        blink::WebDragOperationsMask operations_allowed,
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.cc b/content/browser/renderer_host/render_widget_host_input_event_router.cc
index b1d091d..c7ecfca 100644
--- a/content/browser/renderer_host/render_widget_host_input_event_router.cc
+++ b/content/browser/renderer_host/render_widget_host_input_event_router.cc
@@ -1351,23 +1351,6 @@
     // call, and shouldn't be used after this point.
     OnRenderWidgetHostViewBaseDestroyed(it_to_remove->second);
   }
-
-  for (auto it = hittest_data_.begin(); it != hittest_data_.end();) {
-    if (it->first.frame_sink_id() == id)
-      it = hittest_data_.erase(it);
-    else
-      ++it;
-  }
-}
-
-void RenderWidgetHostInputEventRouter::OnHittestData(
-    const FrameHostMsg_HittestData_Params& params) {
-  if (owner_map_.find(params.surface_id.frame_sink_id()) == owner_map_.end()) {
-    return;
-  }
-  HittestData data;
-  data.ignored_for_hittest = params.ignored_for_hittest;
-  hittest_data_[params.surface_id] = data;
 }
 
 RenderWidgetHostImpl*
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.h b/content/browser/renderer_host/render_widget_host_input_event_router.h
index 4de25f4..576418e 100644
--- a/content/browser/renderer_host/render_widget_host_input_event_router.h
+++ b/content/browser/renderer_host/render_widget_host_input_event_router.h
@@ -27,8 +27,6 @@
 #include "ui/gfx/geometry/vector2d_conversions.h"
 #include "ui/gfx/transform.h"
 
-struct FrameHostMsg_HittestData_Params;
-
 namespace blink {
 class WebGestureEvent;
 class WebInputEvent;
@@ -119,8 +117,6 @@
     return owner_map_.find(id) != owner_map_.end();
   }
 
-  void OnHittestData(const FrameHostMsg_HittestData_Params& params);
-
   TouchEmulator* GetTouchEmulator();
   // Since GetTouchEmulator will lazily create a touch emulator, the following
   // accessor allows testing for its existence without causing it to be created.
@@ -190,9 +186,6 @@
  private:
   FRIEND_TEST_ALL_PREFIXES(BrowserSideFlingBrowserTest,
                            InertialGSUBubblingStopsWhenParentCannotScroll);
-  struct HittestData {
-    bool ignored_for_hittest;
-  };
 
   using FrameSinkIdOwnerMap = std::unordered_map<viz::FrameSinkId,
                                                  RenderWidgetHostViewBase*,
@@ -408,9 +401,6 @@
   };
   TouchscreenPinchState touchscreen_pinch_state_;
 
-  std::unordered_map<viz::SurfaceId, HittestData, viz::SurfaceIdHash>
-      hittest_data_;
-
   std::unique_ptr<RenderWidgetTargeter> event_targeter_;
   bool events_being_flushed_ = false;
 
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h
index 1521774..1f696b97 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.h
+++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -421,8 +421,6 @@
   FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest,
                            VirtualKeyboardFocusEnsureCaretInRect);
   FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest,
-                           HitTestRegionListSubmitted);
-  FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest,
                            DiscardDelegatedFramesWithMemoryPressure);
   FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraInputMethodTest,
                            OnCaretBoundsChanged);
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
index 781c2ee4..cf362af0 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -170,26 +170,6 @@
   return base::JoinString(result, " ");
 }
 
-uint64_t FrameIndexForView(RenderWidgetHostViewAura* view) {
-  return ImageTransportFactory::GetInstance()
-      ->GetContextFactoryPrivate()
-      ->GetFrameSinkManager()
-      ->surface_manager()
-      ->GetSurfaceForId(view->GetCurrentSurfaceId())
-      ->GetActiveFrameIndex();
-}
-
-const gfx::Rect& DamageRectForView(RenderWidgetHostViewAura* view) {
-  return ImageTransportFactory::GetInstance()
-      ->GetContextFactoryPrivate()
-      ->GetFrameSinkManager()
-      ->surface_manager()
-      ->GetSurfaceForId(view->GetCurrentSurfaceId())
-      ->GetActiveFrame()
-      .render_pass_list.back()
-      ->damage_rect;
-}
-
 // Simple observer that keeps track of changes to a window for tests.
 class TestWindowObserver : public aura::WindowObserver {
  public:
@@ -628,6 +608,15 @@
     events.clear();
   }
 
+  // TODO(crbug.com/844469): Delete this helper once Viz launches as it will be
+  // obsolete.
+  viz::FrameSinkManagerImpl* GetFrameSinkManager() {
+    DCHECK(!features::IsVizDisplayCompositorEnabled());
+    return view_->GetDelegatedFrameHost()
+        ->GetCompositorFrameSinkSupportForTesting()
+        ->frame_sink_manager();
+  }
+
   const ui::MotionEventAura& pointer_state() { return view_->pointer_state(); }
 
  protected:
@@ -3094,12 +3083,7 @@
   if (features::IsVizDisplayCompositorEnabled())
     return;
 
-  viz::FakeSurfaceObserver manager_observer;
-  ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
-  viz::SurfaceManager* manager = factory->GetContextFactoryPrivate()
-                                     ->GetFrameSinkManager()
-                                     ->surface_manager();
-  manager->AddObserver(&manager_observer);
+  viz::SurfaceManager* manager = GetFrameSinkManager()->surface_manager();
 
   gfx::Size view_size(100, 100);
   gfx::Rect view_rect(view_size);
@@ -3138,8 +3122,6 @@
   surface->SendAckToClient();
   view_->renderer_compositor_frame_sink_->Flush();
   EXPECT_TRUE(view_->renderer_compositor_frame_sink_->did_receive_ack());
-
-  manager->RemoveObserver(&manager_observer);
 }
 
 // Resizing in fullscreen mode should send the up-to-date screen info.
@@ -3702,10 +3684,8 @@
   view_->SetSize(view_rect.size());
 
   viz::FakeSurfaceObserver observer;
-  ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
-  viz::SurfaceManager* surface_manager = factory->GetContextFactoryPrivate()
-                                             ->GetFrameSinkManager()
-                                             ->surface_manager();
+  viz::SurfaceManager* surface_manager =
+      GetFrameSinkManager()->surface_manager();
   surface_manager->AddObserver(&observer);
 
   view_->SetNeedsBeginFrames(true);
@@ -5657,12 +5637,8 @@
   viz::TestLatestLocalSurfaceIdLookupDelegate delegate;
   delegate.SetSurfaceIdMap(
       viz::SurfaceId(view_->GetFrameSinkId(), kArbitraryLocalSurfaceId));
-  viz::FrameSinkManagerImpl* frame_sink_manager =
-      view_->GetDelegatedFrameHost()
-          ->GetCompositorFrameSinkSupportForTesting()
-          ->frame_sink_manager();
   const viz::HitTestRegionList* active_hit_test_region_list =
-      frame_sink_manager->hit_test_manager()->GetActiveHitTestRegionList(
+      GetFrameSinkManager()->hit_test_manager()->GetActiveHitTestRegionList(
           &delegate, surface_id.frame_sink_id());
   EXPECT_EQ(active_hit_test_region_list->flags,
             viz::HitTestRegionFlags::kHitTestMine);
diff --git a/content/browser/renderer_host/render_widget_host_view_browsertest.cc b/content/browser/renderer_host/render_widget_host_view_browsertest.cc
index 495da59..693355f 100644
--- a/content/browser/renderer_host/render_widget_host_view_browsertest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_browsertest.cc
@@ -163,7 +163,6 @@
       ::FrameHostMsg_DidCommitProvisionalLoad_Params* params,
       mojom::DidCommitProvisionalLoadInterfaceParamsPtr* interface_params)
       override {
-    base::MessageLoopCurrent::ScopedNestableTaskAllower allow;
     frame_observer_->WaitForAnyFrameSubmission();
     return true;
   }
diff --git a/content/browser/service_worker/embedded_worker_instance.cc b/content/browser/service_worker/embedded_worker_instance.cc
index 88b8aaa..0ef8879 100644
--- a/content/browser/service_worker/embedded_worker_instance.cc
+++ b/content/browser/service_worker/embedded_worker_instance.cc
@@ -992,16 +992,14 @@
         rph, routing_id, &default_factory_request);
   }
 
-  // TODO(crbug.com/955476): network isolation key to be created using worker
-  // script's origin.
   if (GetNetworkFactoryCallbackForTest().is_null()) {
     rph->CreateURLLoaderFactory(
-        origin, nullptr /* preferences */, net::NetworkIsolationKey(),
+        origin, nullptr /* preferences */, net::NetworkIsolationKey(origin),
         std::move(default_header_client), std::move(default_factory_request));
   } else {
     network::mojom::URLLoaderFactoryPtr original_factory;
     rph->CreateURLLoaderFactory(
-        origin, nullptr /* preferences */, net::NetworkIsolationKey(),
+        origin, nullptr /* preferences */, net::NetworkIsolationKey(origin),
         std::move(default_header_client), mojo::MakeRequest(&original_factory));
     GetNetworkFactoryCallbackForTest().Run(std::move(default_factory_request),
                                            rph->GetID(),
diff --git a/content/browser/service_worker/service_worker_network_isolation_key_browsertest.cc b/content/browser/service_worker/service_worker_network_isolation_key_browsertest.cc
new file mode 100644
index 0000000..f8f6264
--- /dev/null
+++ b/content/browser/service_worker/service_worker_network_isolation_key_browsertest.cc
@@ -0,0 +1,173 @@
+// 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 "base/path_service.h"
+#include "base/strings/strcat.h"
+#include "base/test/bind_test_util.h"
+#include "base/test/scoped_feature_list.h"
+#include "content/public/common/content_paths.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/test_navigation_observer.h"
+#include "content/public/test/url_loader_interceptor.h"
+#include "content/shell/browser/shell.h"
+#include "net/base/features.h"
+
+namespace content {
+
+class ServiceWorkerNetworkIsolationKeyBrowserTest
+    : public ContentBrowserTest,
+      public ::testing::WithParamInterface<
+          bool /* test_same_network_isolation_key */> {
+ public:
+  void SetUp() override {
+    feature_list_.InitAndEnableFeature(
+        net::features::kSplitCacheByTopFrameOrigin);
+    ContentBrowserTest::SetUp();
+  }
+
+  void SetUpOnMainThread() override {
+    ASSERT_TRUE(embedded_test_server()->Start());
+  }
+
+  // Does a cross-process navigation to clear the in-memory cache.
+  // We are relying on this navigation to discard the old process.
+  void CrossProcessNavigation() {
+    RenderProcessHost* process =
+        shell()->web_contents()->GetMainFrame()->GetProcess();
+    RenderProcessHostWatcher process_watcher(
+        process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+    NavigateToURL(shell(), GetWebUIURL("version"));
+    process_watcher.Wait();
+  }
+
+  // Register a service worker |main_script_file| in the scope of
+  // |embedded_test_server|'s origin, that does
+  // importScripts(|import_script_url|) and fetch(|fetch_url|).
+  void RegisterServiceWorkerThatDoesImportScriptsAndFetch(
+      const net::EmbeddedTestServer* embedded_test_server,
+      const std::string& main_script_file,
+      const GURL& import_script_url,
+      const GURL& fetch_url) {
+    content::TestNavigationObserver navigation_observer(
+        shell()->web_contents(), /*number_of_navigations*/ 1,
+        content::MessageLoopRunner::QuitMode::DEFERRED);
+    std::string subframe_url =
+        embedded_test_server
+            ->GetURL("/service_worker/create_service_worker.html")
+            .spec();
+
+    std::string subframe_name = GetUniqueSubframeName();
+    EvalJsResult result =
+        EvalJs(shell()->web_contents()->GetMainFrame(),
+               JsReplace("createFrame($1, $2)", subframe_url, subframe_name));
+    ASSERT_TRUE(result.error.empty());
+    navigation_observer.Wait();
+
+    RenderFrameHost* subframe_rfh = FrameMatchingPredicate(
+        shell()->web_contents(),
+        base::BindRepeating(&FrameMatchesName, subframe_name));
+    DCHECK(subframe_rfh);
+
+    std::string main_script_file_with_param = base::StrCat(
+        {main_script_file, "?import_script_url=", import_script_url.spec(),
+         "&fetch_url=", fetch_url.spec()});
+
+    EXPECT_EQ("DONE",
+              EvalJs(subframe_rfh,
+                     JsReplace("register($1)", main_script_file_with_param)));
+  }
+
+ private:
+  std::string GetUniqueSubframeName() {
+    subframe_id_ += 1;
+    return "subframe_name_" + base::NumberToString(subframe_id_);
+  }
+
+  size_t subframe_id_ = 0;
+  base::test::ScopedFeatureList feature_list_;
+};
+
+// Test that network isolation key is filled in correctly for service workers.
+// It checks the cache status of importScripts() as well as fetch() request from
+// two different service workers, where the two workers may be from the same or
+// different origin - network isolation key. When the origins are the same, we
+// expect the 2nd importScripts and/or fetch request to exist in the cache, and
+// when the origins are different, we expect the 2nd request to not exist in the
+// cache. The imported/fetched script are always the same as it's a control
+// variable for this test.
+IN_PROC_BROWSER_TEST_P(ServiceWorkerNetworkIsolationKeyBrowserTest,
+                       ImportScriptsAndFetchRequest) {
+  bool test_same_network_isolation_key = GetParam();
+
+  // Discard the old process to clear the in-memory cache.
+  CrossProcessNavigation();
+
+  net::EmbeddedTestServer cross_origin_server_1;
+  cross_origin_server_1.ServeFilesFromSourceDirectory(GetTestDataFilePath());
+  ASSERT_TRUE(cross_origin_server_1.Start());
+
+  net::EmbeddedTestServer cross_origin_server_tmp;
+  cross_origin_server_tmp.ServeFilesFromSourceDirectory(GetTestDataFilePath());
+  ASSERT_TRUE(cross_origin_server_tmp.Start());
+
+  auto& cross_origin_server_2 = test_same_network_isolation_key
+                                    ? cross_origin_server_1
+                                    : cross_origin_server_tmp;
+
+  net::EmbeddedTestServer resource_request_server;
+  resource_request_server.ServeFilesFromSourceDirectory(GetTestDataFilePath());
+  ASSERT_TRUE(resource_request_server.Start());
+  GURL import_script_url =
+      resource_request_server.GetURL("/service_worker/empty.js");
+  GURL fetch_url =
+      resource_request_server.GetURL("/service_worker/empty2.html");
+
+  std::map<GURL, size_t> request_completed_count;
+
+  base::RunLoop cache_status_waiter;
+  URLLoaderInterceptor interceptor(
+      base::BindLambdaForTesting(
+          [&](URLLoaderInterceptor::RequestParams* params) { return false; }),
+      base::BindLambdaForTesting(
+          [&](const GURL& request_url,
+              const network::URLLoaderCompletionStatus& status) {
+            if (request_url == import_script_url || request_url == fetch_url) {
+              size_t& num_completed = request_completed_count[request_url];
+              num_completed += 1;
+              if (num_completed == 1) {
+                EXPECT_FALSE(status.exists_in_cache);
+              } else if (num_completed == 2) {
+                EXPECT_EQ(status.exists_in_cache,
+                          test_same_network_isolation_key);
+              } else {
+                NOTREACHED();
+              }
+            }
+            if (request_completed_count[import_script_url] == 2 &&
+                request_completed_count[fetch_url] == 2) {
+              cache_status_waiter.Quit();
+            }
+          }),
+      {});
+
+  NavigateToURLBlockUntilNavigationsComplete(
+      shell(),
+      embedded_test_server()->GetURL("/service_worker/frame_factory.html"), 1);
+
+  RegisterServiceWorkerThatDoesImportScriptsAndFetch(
+      &cross_origin_server_1, "worker_with_import_and_fetch.js",
+      import_script_url, fetch_url);
+  RegisterServiceWorkerThatDoesImportScriptsAndFetch(
+      &cross_origin_server_2, "worker_with_import_and_fetch_2.js",
+      import_script_url, fetch_url);
+
+  cache_status_waiter.Run();
+}
+
+INSTANTIATE_TEST_SUITE_P(/* no prefix */,
+                         ServiceWorkerNetworkIsolationKeyBrowserTest,
+                         testing::Bool());
+
+}  // namespace content
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 37e9397c..2cc8cae9 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -591,6 +591,7 @@
       is_overlay_content_(false),
       showing_context_menu_(false),
       text_autosizer_page_info_({0, 0, 1.f}),
+      native_theme_observer_(this),
       had_inner_webcontents_(false),
       loading_weak_factory_(this),
       weak_factory_(this) {
@@ -613,7 +614,10 @@
   registry_.AddInterface(base::BindRepeating(
       &WebContentsImpl::OnColorChooserFactoryRequest, base::Unretained(this)));
 
-  dark_mode_observer_.Start();
+  ui::NativeTheme* native_theme = ui::NativeTheme::GetInstanceForWeb();
+  native_theme_observer_.Add(native_theme);
+  in_high_contrast_ = native_theme->UsesHighContrastColors();
+  in_dark_mode_ = native_theme->SystemDarkModeEnabled();
 }
 
 WebContentsImpl::~WebContentsImpl() {
@@ -7226,8 +7230,24 @@
   GetMainFrame()->SetVisibilityForChildViews(visible);
 }
 
-void WebContentsImpl::OnDarkModeChanged(bool dark_mode) {
-  NotifyPreferencesChanged();
+void WebContentsImpl::OnNativeThemeUpdated(ui::NativeTheme* observed_theme) {
+  DCHECK(native_theme_observer_.IsObserving(observed_theme));
+
+  bool in_dark_mode = observed_theme->SystemDarkModeEnabled();
+  bool in_high_contrast = observed_theme->UsesHighContrastColors();
+  bool preferences_changed = false;
+
+  if (in_dark_mode_ != in_dark_mode) {
+    in_dark_mode_ = in_dark_mode;
+    preferences_changed = true;
+  }
+  if (in_high_contrast_ != in_high_contrast) {
+    in_high_contrast_ = in_high_contrast;
+    preferences_changed = true;
+  }
+
+  if (preferences_changed)
+    NotifyPreferencesChanged();
 }
 
 }  // namespace content
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 210b672..bf85ec4 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -22,6 +22,7 @@
 #include "base/observer_list.h"
 #include "base/optional.h"
 #include "base/process/process.h"
+#include "base/scoped_observer.h"
 #include "base/time/time.h"
 #include "base/values.h"
 #include "build/build_config.h"
@@ -69,6 +70,7 @@
 #include "ui/gfx/geometry/size.h"
 #include "ui/native_theme/dark_mode_observer.h"
 #include "ui/native_theme/native_theme.h"
+#include "ui/native_theme/native_theme_observer.h"
 
 #if defined(OS_ANDROID)
 #include "content/browser/android/nfc_host.h"
@@ -146,7 +148,8 @@
                                        public blink::mojom::ColorChooserFactory,
                                        public NotificationObserver,
                                        public NavigationControllerDelegate,
-                                       public NavigatorDelegate {
+                                       public NavigatorDelegate,
+                                       public ui::NativeThemeObserver {
  public:
   class FriendWrapper;
 
@@ -1495,9 +1498,8 @@
   // |current_fullscreen_frame_| and notify observers whenever it changes.
   void FullscreenFrameSetUpdated();
 
-  // Called by DarkModeObserver when the dark mode state changes; triggers a
-  // preference update.
-  void OnDarkModeChanged(bool dark_mode);
+  // Overridden from ui::NativeThemeObserver:
+  void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) override;
 
   // Data for core operation ---------------------------------------------------
 
@@ -1900,12 +1902,13 @@
   // with OOPIF renderers.
   blink::WebTextAutosizerPageInfo text_autosizer_page_info_;
 
-  // Observe dark mode native theme changes to notify the renderer about
-  // preferred color scheme changes.
-  ui::DarkModeObserver dark_mode_observer_{
-      ui::NativeTheme::GetInstanceForWeb(),
-      base::BindRepeating(&WebContentsImpl::OnDarkModeChanged,
-                          base::Unretained(this))};
+  // Observe native theme for changes to dark mode and high contrast. Used to
+  // notify the renderer of preferred color scheme and forced colors changes.
+  ScopedObserver<ui::NativeTheme, ui::NativeThemeObserver>
+      native_theme_observer_;
+
+  bool in_high_contrast_ = false;
+  bool in_dark_mode_ = false;
 
   // TODO(crbug.com/934637): Remove this field when pdf/any inner web contents
   // user gesture is properly propagated. This is a temporary fix for history
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc
index 77aefd5..02a99c8 100644
--- a/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -68,6 +68,7 @@
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "services/network/public/cpp/features.h"
 #include "testing/gmock/include/gmock/gmock.h"
+#include "third_party/blink/public/common/features.h"
 #include "url/gurl.h"
 
 namespace content {
@@ -1088,11 +1089,26 @@
 };
 
 class WebContentsSplitCacheBrowserTestEnabled
-    : public WebContentsSplitCacheBrowserTest {
+    : public WebContentsSplitCacheBrowserTest,
+      public ::testing::WithParamInterface<bool> {
  public:
   WebContentsSplitCacheBrowserTestEnabled() {
-    feature_list.InitAndEnableFeature(
-        net::features::kSplitCacheByTopFrameOrigin);
+    if (GetParam()) {
+      feature_list.InitWithFeatures(
+          {/*Enabled features*/
+           // To enable kPlzDedicatedWorker, we also need to enable
+           // kOffMainThreadDedicatedWorkerScriptFetch and
+           // kNetworkService.
+           net::features::kSplitCacheByTopFrameOrigin,
+           blink::features::kPlzDedicatedWorker,
+           blink::features::kOffMainThreadDedicatedWorkerScriptFetch,
+           network::features::kNetworkService},
+          {/*Disabled features*/});
+    } else {
+      feature_list.InitWithFeatures(
+          {/*Enabled feature*/ net::features::kSplitCacheByTopFrameOrigin},
+          {/*Disabled feature*/ blink::features::kPlzDedicatedWorker});
+    }
   }
 
  private:
@@ -1111,7 +1127,7 @@
   base::test::ScopedFeatureList feature_list;
 };
 
-IN_PROC_BROWSER_TEST_F(WebContentsSplitCacheBrowserTestEnabled, SplitCache) {
+IN_PROC_BROWSER_TEST_P(WebContentsSplitCacheBrowserTestEnabled, SplitCache) {
   // Load a cacheable resource for the first time, and it's not cached.
   EXPECT_FALSE(TestResourceLoad(GenURL("a.com", "/title1.html"), GURL()));
 
@@ -1189,7 +1205,7 @@
                                GenURL("c.com", "/title1.html")));
 }
 
-IN_PROC_BROWSER_TEST_F(WebContentsSplitCacheBrowserTestEnabled,
+IN_PROC_BROWSER_TEST_P(WebContentsSplitCacheBrowserTestEnabled,
                        SplitCacheDedicatedWorkers) {
   // Load 3p.com/script from a.com's worker. The first time it's loaded from the
   // network and the second it's cached.
@@ -1264,6 +1280,10 @@
       GenURL("e.com", "/worker.js")));
 }
 
+INSTANTIATE_TEST_SUITE_P(SplitCacheParamByPlzDedicatedWorker,
+                         WebContentsSplitCacheBrowserTestEnabled,
+                         ::testing::Values(true, false));
+
 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
                        ResourceLoadCompleteFromLocalResource) {
   ResourceLoadObserver observer(shell());
diff --git a/content/browser/web_contents/web_contents_view_aura.cc b/content/browser/web_contents/web_contents_view_aura.cc
index ee5760e..c6f51d6 100644
--- a/content/browser/web_contents/web_contents_view_aura.cc
+++ b/content/browser/web_contents/web_contents_view_aura.cc
@@ -1064,11 +1064,11 @@
       ui::OSExchangeDataProviderFactory::CreateProvider();
   PrepareDragData(drop_data, provider.get(), web_contents_);
 
-  ui::OSExchangeData data(
-      std::move(provider));  // takes ownership of |provider|.
+  auto data(std::make_unique<ui::OSExchangeData>(
+      std::move(provider)));  // takes ownership of |provider|.
 
   if (!image.isNull())
-    data.provider().SetDragImage(image, image_offset);
+    data->provider().SetDragImage(image, image_offset);
 
   std::unique_ptr<WebDragSourceAura> drag_source(
       new WebDragSourceAura(GetNativeView(), web_contents_));
@@ -1080,12 +1080,10 @@
     gfx::NativeView content_native_view = GetContentNativeView();
     base::MessageLoopCurrent::ScopedNestableTaskAllower allow;
     result_op = aura::client::GetDragDropClient(root_window)
-        ->StartDragAndDrop(data,
-                           root_window,
-                           content_native_view,
-                           event_info.event_location,
-                           ConvertFromWeb(operations),
-                           event_info.event_source);
+                    ->StartDragAndDrop(
+                        std::move(data), root_window, content_native_view,
+                        event_info.event_location, ConvertFromWeb(operations),
+                        event_info.event_source);
   }
 
   // Bail out immediately if the contents view window is gone. Note that it is
@@ -1342,7 +1340,9 @@
   current_drop_data_.reset();
 }
 
-int WebContentsViewAura::OnPerformDrop(const ui::DropTargetEvent& event) {
+int WebContentsViewAura::OnPerformDrop(
+    const ui::DropTargetEvent& event,
+    std::unique_ptr<ui::OSExchangeData> data) {
   gfx::PointF transformed_pt;
   RenderWidgetHostImpl* target_rwh =
       web_contents_->GetInputEventRouter()->GetRenderWidgetHostAtPoint(
diff --git a/content/browser/web_contents/web_contents_view_aura.h b/content/browser/web_contents/web_contents_view_aura.h
index 46ca496..b74bb80d2 100644
--- a/content/browser/web_contents/web_contents_view_aura.h
+++ b/content/browser/web_contents/web_contents_view_aura.h
@@ -191,7 +191,8 @@
   void OnDragEntered(const ui::DropTargetEvent& event) override;
   int OnDragUpdated(const ui::DropTargetEvent& event) override;
   void OnDragExited() override;
-  int OnPerformDrop(const ui::DropTargetEvent& event) override;
+  int OnPerformDrop(const ui::DropTargetEvent& event,
+                    std::unique_ptr<ui::OSExchangeData> data) override;
 
   // Completes a drop operation by communicating the drop data to the renderer
   // process.
diff --git a/content/browser/web_contents/web_contents_view_aura_unittest.cc b/content/browser/web_contents/web_contents_view_aura_unittest.cc
index 03b712ec..ea14b66 100644
--- a/content/browser/web_contents/web_contents_view_aura_unittest.cc
+++ b/content/browser/web_contents/web_contents_view_aura_unittest.cc
@@ -158,10 +158,10 @@
 
 TEST_F(WebContentsViewAuraTest, DragDropFiles) {
   WebContentsViewAura* view = GetView();
-  ui::OSExchangeData data;
+  auto data = std::make_unique<ui::OSExchangeData>();
 
   const base::string16 string_data = base::ASCIIToUTF16("Some string data");
-  data.SetString(string_data);
+  data->SetString(string_data);
 
 #if defined(OS_WIN)
   const std::vector<ui::FileInfo> test_file_infos = {
@@ -181,9 +181,9 @@
       {base::FilePath(FILE_PATH_LITERAL("/tmp/test_file3")), base::FilePath()},
   };
 #endif
-  data.SetFilenames(test_file_infos);
+  data->SetFilenames(test_file_infos);
 
-  ui::DropTargetEvent event(data, kClientPt, kScreenPt,
+  ui::DropTargetEvent event(*data.get(), kClientPt, kScreenPt,
                             ui::DragDropTypes::DRAG_COPY);
 
   // Simulate drag enter.
@@ -216,7 +216,7 @@
   base::RunLoop run_loop;
   async_drop_closure_ = run_loop.QuitClosure();
 
-  view->OnPerformDrop(event);
+  view->OnPerformDrop(event, std::move(data));
   run_loop.Run();
 
   CheckDropData(view);
@@ -241,10 +241,10 @@
 #if defined(OS_WIN) || defined(USE_X11)
 TEST_F(WebContentsViewAuraTest, DragDropFilesOriginateFromRenderer) {
   WebContentsViewAura* view = GetView();
-  ui::OSExchangeData data;
+  auto data = std::make_unique<ui::OSExchangeData>();
 
   const base::string16 string_data = base::ASCIIToUTF16("Some string data");
-  data.SetString(string_data);
+  data->SetString(string_data);
 
 #if defined(OS_WIN)
   const std::vector<ui::FileInfo> test_file_infos = {
@@ -264,13 +264,13 @@
       {base::FilePath(FILE_PATH_LITERAL("/tmp/test_file3")), base::FilePath()},
   };
 #endif
-  data.SetFilenames(test_file_infos);
+  data->SetFilenames(test_file_infos);
 
   // Simulate the drag originating in the renderer process, in which case
   // any file data should be filtered out (anchor drag scenario).
-  data.MarkOriginatedFromRenderer();
+  data->MarkOriginatedFromRenderer();
 
-  ui::DropTargetEvent event(data, kClientPt, kScreenPt,
+  ui::DropTargetEvent event(*data.get(), kClientPt, kScreenPt,
                             ui::DragDropTypes::DRAG_COPY);
 
   // Simulate drag enter.
@@ -296,7 +296,7 @@
   base::RunLoop run_loop;
   async_drop_closure_ = run_loop.QuitClosure();
 
-  view->OnPerformDrop(event);
+  view->OnPerformDrop(event, std::move(data));
   run_loop.Run();
 
   CheckDropData(view);
@@ -316,10 +316,10 @@
 #if defined(OS_WIN)
 TEST_F(WebContentsViewAuraTest, DragDropVirtualFiles) {
   WebContentsViewAura* view = GetView();
-  ui::OSExchangeData data;
+  auto data = std::make_unique<ui::OSExchangeData>();
 
   const base::string16 string_data = base::ASCIIToUTF16("Some string data");
-  data.SetString(string_data);
+  data->SetString(string_data);
 
   const std::vector<std::pair<base::FilePath, std::string>>
       test_filenames_and_contents = {
@@ -331,10 +331,10 @@
            std::string("just some more data")},
       };
 
-  data.provider().SetVirtualFileContentsForTesting(test_filenames_and_contents,
-                                                   TYMED_ISTREAM);
+  data->provider().SetVirtualFileContentsForTesting(test_filenames_and_contents,
+                                                    TYMED_ISTREAM);
 
-  ui::DropTargetEvent event(data, kClientPt, kScreenPt,
+  ui::DropTargetEvent event(*data.get(), kClientPt, kScreenPt,
                             ui::DragDropTypes::DRAG_COPY);
 
   // Simulate drag enter.
@@ -363,7 +363,7 @@
   base::RunLoop run_loop;
   async_drop_closure_ = run_loop.QuitClosure();
 
-  view->OnPerformDrop(event);
+  view->OnPerformDrop(event, std::move(data));
   run_loop.Run();
 
   CheckDropData(view);
@@ -395,10 +395,10 @@
 
 TEST_F(WebContentsViewAuraTest, DragDropVirtualFilesOriginateFromRenderer) {
   WebContentsViewAura* view = GetView();
-  ui::OSExchangeData data;
+  auto data = std::make_unique<ui::OSExchangeData>();
 
   const base::string16 string_data = base::ASCIIToUTF16("Some string data");
-  data.SetString(string_data);
+  data->SetString(string_data);
 
   const std::vector<std::pair<base::FilePath, std::string>>
       test_filenames_and_contents = {
@@ -410,14 +410,14 @@
            std::string("just some more data")},
       };
 
-  data.provider().SetVirtualFileContentsForTesting(test_filenames_and_contents,
-                                                   TYMED_ISTREAM);
+  data->provider().SetVirtualFileContentsForTesting(test_filenames_and_contents,
+                                                    TYMED_ISTREAM);
 
   // Simulate the drag originating in the renderer process, in which case
   // any file data should be filtered out (anchor drag scenario).
-  data.MarkOriginatedFromRenderer();
+  data->MarkOriginatedFromRenderer();
 
-  ui::DropTargetEvent event(data, kClientPt, kScreenPt,
+  ui::DropTargetEvent event(*data.get(), kClientPt, kScreenPt,
                             ui::DragDropTypes::DRAG_COPY);
 
   // Simulate drag enter.
@@ -438,7 +438,7 @@
   base::RunLoop run_loop;
   async_drop_closure_ = run_loop.QuitClosure();
 
-  view->OnPerformDrop(event);
+  view->OnPerformDrop(event, std::move(data));
   run_loop.Run();
 
   CheckDropData(view);
@@ -450,21 +450,21 @@
 
 TEST_F(WebContentsViewAuraTest, DragDropUrlData) {
   WebContentsViewAura* view = GetView();
-  ui::OSExchangeData data;
+  auto data = std::make_unique<ui::OSExchangeData>();
 
   const std::string url_spec = "https://www.wikipedia.org/";
   const GURL url(url_spec);
   const base::string16 url_title = base::ASCIIToUTF16("Wikipedia");
-  data.SetURL(url, url_title);
+  data->SetURL(url, url_title);
 
   // SetUrl should also add a virtual .url (internet shortcut) file.
   std::vector<ui::FileInfo> file_infos;
-  EXPECT_TRUE(data.GetVirtualFilenames(&file_infos));
+  EXPECT_TRUE(data->GetVirtualFilenames(&file_infos));
   ASSERT_EQ(1ULL, file_infos.size());
   EXPECT_EQ(base::FilePath(url_title + base::ASCIIToUTF16(".url")),
             file_infos[0].display_name);
 
-  ui::DropTargetEvent event(data, kClientPt, kScreenPt,
+  ui::DropTargetEvent event(*data.get(), kClientPt, kScreenPt,
                             ui::DragDropTypes::DRAG_COPY);
 
   // Simulate drag enter.
@@ -487,7 +487,7 @@
   base::RunLoop run_loop;
   async_drop_closure_ = run_loop.QuitClosure();
 
-  view->OnPerformDrop(event);
+  view->OnPerformDrop(event, std::move(data));
   run_loop.Run();
 
   CheckDropData(view);
diff --git a/content/browser/worker_host/dedicated_worker_host.cc b/content/browser/worker_host/dedicated_worker_host.cc
index bed3cddf..6617b00 100644
--- a/content/browser/worker_host/dedicated_worker_host.cc
+++ b/content/browser/worker_host/dedicated_worker_host.cc
@@ -11,6 +11,7 @@
 #include "base/bind.h"
 #include "content/browser/appcache/appcache_navigation_handle.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
+#include "content/browser/frame_host/frame_tree.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/interface_provider_filtering.h"
 #include "content/browser/renderer_interface_binders.h"
@@ -223,10 +224,17 @@
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
     network::mojom::TrustedURLLoaderHeaderClientPtrInfo no_header_client;
 
-    // TODO(crbug.com/955476): Create network_isolation_key cache key using
-    // worker script's origin.
+    // Get the origin of the frame tree's root to use as top-frame origin.
+    // TODO(cammie): Change this approach when we support shared workers
+    // creating dedicated workers, as there might be no ancestor frame.
+    auto* host =
+        RenderFrameHostImpl::FromID(process_id_, ancestor_render_frame_id_);
+    base::Optional<url::Origin> top_frame_origin(
+        host->frame_tree_node()->frame_tree()->root()->current_origin());
+
     process->CreateURLLoaderFactory(
-        origin_, nullptr /* preferences */, net::NetworkIsolationKey(),
+        origin_, nullptr /* preferences */,
+        net::NetworkIsolationKey(top_frame_origin, origin_),
         std::move(no_header_client), std::move(request));
   }
 
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index d523ad2..a54b13eb 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -626,17 +626,6 @@
   IPC_STRUCT_TRAITS_MEMBER(routing_id)
 IPC_STRUCT_TRAITS_END()
 
-// This message is used to send hittesting data from the renderer in order
-// to perform hittesting on the browser process.
-IPC_STRUCT_BEGIN(FrameHostMsg_HittestData_Params)
-  // |surface_id| represents the surface used by this remote frame.
-  IPC_STRUCT_MEMBER(viz::SurfaceId, surface_id)
-
-  // If |ignored_for_hittest| then this surface should be ignored during
-  // hittesting.
-  IPC_STRUCT_MEMBER(bool, ignored_for_hittest)
-IPC_STRUCT_END()
-
 IPC_STRUCT_BEGIN(FrameHostMsg_CreateChildFrame_Params)
   IPC_STRUCT_MEMBER(int32_t, parent_routing_id)
   IPC_STRUCT_MEMBER(blink::WebTreeScopeType, scope)
@@ -1575,9 +1564,6 @@
                     blink::WebFocusType /* type */,
                     int32_t /* source_routing_id */)
 
-// Sends hittesting data needed to perform hittesting on the browser process.
-IPC_MESSAGE_ROUTED1(FrameHostMsg_HittestData, FrameHostMsg_HittestData_Params)
-
 // Request that the host send its overlay routing token for this render frame
 // via SetOverlayRoutingToken.
 IPC_MESSAGE_ROUTED0(FrameHostMsg_RequestOverlayRoutingToken)
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn
index 54f9eea..48a4c77f 100644
--- a/content/public/android/BUILD.gn
+++ b/content/public/android/BUILD.gn
@@ -142,7 +142,6 @@
     "java/src/org/chromium/content/browser/LauncherThread.java",
     "java/src/org/chromium/content/browser/LollipopTtsPlatformImpl.java",
     "java/src/org/chromium/content/browser/MediaSessionImpl.java",
-    "java/src/org/chromium/content/browser/MemoryMonitorAndroid.java",
     "java/src/org/chromium/content/browser/MotionEventSynthesizerImpl.java",
     "java/src/org/chromium/content/browser/NfcHost.java",
     "java/src/org/chromium/content/browser/TtsPlatformImpl.java",
@@ -405,7 +404,6 @@
     "java/src/org/chromium/content/browser/JavascriptInjectorImpl.java",
     "java/src/org/chromium/content/browser/LauncherThread.java",
     "java/src/org/chromium/content/browser/MediaSessionImpl.java",
-    "java/src/org/chromium/content/browser/MemoryMonitorAndroid.java",
     "java/src/org/chromium/content/browser/NfcHost.java",
     "java/src/org/chromium/content/browser/RenderWidgetHostViewImpl.java",
     "java/src/org/chromium/content/browser/ScreenOrientationProviderImpl.java",
diff --git a/content/public/android/java/src/org/chromium/content/browser/MemoryMonitorAndroid.java b/content/public/android/java/src/org/chromium/content/browser/MemoryMonitorAndroid.java
deleted file mode 100644
index 3cd56df..0000000
--- a/content/public/android/java/src/org/chromium/content/browser/MemoryMonitorAndroid.java
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.content.browser;
-
-import android.app.ActivityManager;
-import android.content.ComponentCallbacks2;
-import android.content.Context;
-import android.content.res.Configuration;
-
-import org.chromium.base.ContextUtils;
-import org.chromium.base.Log;
-import org.chromium.base.annotations.CalledByNative;
-import org.chromium.base.annotations.JNINamespace;
-
-/**
- * Android implementation of MemoryMonitor.
- */
-@JNINamespace("content")
-class MemoryMonitorAndroid {
-    private static final String TAG = "MemoryMonitorAndroid";
-    private static final ActivityManager.MemoryInfo sMemoryInfo =
-            new ActivityManager.MemoryInfo();
-    private static ComponentCallbacks2 sCallbacks;
-
-    private MemoryMonitorAndroid() {
-    }
-
-    /**
-     * Get the current MemoryInfo from ActivityManager and invoke the native
-     * callback to populate the MemoryInfo.
-     *
-     * @param outPtr A native output pointer to populate MemoryInfo. This is
-     * passed back to the native callback.
-     */
-    @CalledByNative
-    private static void getMemoryInfo(long outPtr) {
-        ActivityManager am =
-                (ActivityManager) ContextUtils.getApplicationContext().getSystemService(
-                        Context.ACTIVITY_SERVICE);
-        try {
-            am.getMemoryInfo(sMemoryInfo);
-        } catch (RuntimeException e) {
-            // RuntimeException can be thrown when the system is going to
-            // restart. Pass arbitrary values to the callback.
-            Log.e(TAG,
-                    "Failed to get memory info due to a runtime exception: %s",
-                    e);
-            sMemoryInfo.availMem = 1;
-            sMemoryInfo.lowMemory = true;
-            sMemoryInfo.threshold = 1;
-            sMemoryInfo.totalMem = 1;
-        }
-        nativeGetMemoryInfoCallback(
-                sMemoryInfo.availMem, sMemoryInfo.lowMemory,
-                sMemoryInfo.threshold, sMemoryInfo.totalMem, outPtr);
-    }
-
-    /**
-     * Register ComponentCallbacks2 to receive memory pressure signals.
-     *
-     */
-    @CalledByNative
-    private static void registerComponentCallbacks() {
-        sCallbacks = new ComponentCallbacks2() {
-                @Override
-                public void onTrimMemory(int level) {
-                    if (level != ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
-                        nativeOnTrimMemory(level);
-                    }
-                }
-                @Override
-                public void onLowMemory() {
-                    // Don't support old onLowMemory().
-                }
-                @Override
-                public void onConfigurationChanged(Configuration config) {
-                }
-            };
-        ContextUtils.getApplicationContext().registerComponentCallbacks(sCallbacks);
-    }
-
-    private static native void nativeGetMemoryInfoCallback(
-            long availMem, boolean lowMemory,
-            long threshold, long totalMem, long outPtr);
-
-    private static native void nativeOnTrimMemory(int level);
-}
diff --git a/content/public/common/common_param_traits_macros.h b/content/public/common/common_param_traits_macros.h
index 9ad8ad0..8ef20bc 100644
--- a/content/public/common/common_param_traits_macros.h
+++ b/content/public/common/common_param_traits_macros.h
@@ -81,6 +81,9 @@
 IPC_ENUM_TRAITS_MIN_MAX_VALUE(blink::PreferredColorScheme,
                               blink::PreferredColorScheme::kNoPreference,
                               blink::PreferredColorScheme::kLight)
+IPC_ENUM_TRAITS_MIN_MAX_VALUE(blink::ForcedColors,
+                              blink::ForcedColors::kNone,
+                              blink::ForcedColors::kMaxValue)
 
 IPC_STRUCT_TRAITS_BEGIN(blink::WebPoint)
   IPC_STRUCT_TRAITS_MEMBER(x)
@@ -242,6 +245,7 @@
   IPC_STRUCT_TRAITS_MEMBER(do_not_update_selection_on_mutating_selection_range)
   IPC_STRUCT_TRAITS_MEMBER(autoplay_policy)
   IPC_STRUCT_TRAITS_MEMBER(preferred_color_scheme)
+  IPC_STRUCT_TRAITS_MEMBER(forced_colors)
   IPC_STRUCT_TRAITS_MEMBER(low_priority_iframes_threshold)
   IPC_STRUCT_TRAITS_MEMBER(picture_in_picture_enabled)
   IPC_STRUCT_TRAITS_MEMBER(translate_service_available)
diff --git a/content/public/common/web_preferences.cc b/content/public/common/web_preferences.cc
index e2f3d5b..6d7b8905 100644
--- a/content/public/common/web_preferences.cc
+++ b/content/public/common/web_preferences.cc
@@ -225,6 +225,7 @@
       do_not_update_selection_on_mutating_selection_range(false),
       autoplay_policy(AutoplayPolicy::kDocumentUserActivationRequired),
       preferred_color_scheme(blink::PreferredColorScheme::kNoPreference),
+      forced_colors(blink::ForcedColors::kNone),
       low_priority_iframes_threshold(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
       picture_in_picture_enabled(true),
       translate_service_available(false),
diff --git a/content/public/common/web_preferences.h b/content/public/common/web_preferences.h
index f9a99647..6677d8e 100644
--- a/content/public/common/web_preferences.h
+++ b/content/public/common/web_preferences.h
@@ -14,6 +14,7 @@
 #include "build/build_config.h"
 #include "content/common/content_export.h"
 #include "net/nqe/effective_connection_type.h"
+#include "third_party/blink/public/common/css/forced_colors.h"
 #include "third_party/blink/public/common/css/preferred_color_scheme.h"
 #include "third_party/blink/public/mojom/v8_cache_options.mojom.h"
 #include "ui/base/pointer/pointer_device.h"
@@ -305,6 +306,12 @@
   blink::PreferredColorScheme preferred_color_scheme =
       blink::PreferredColorScheme::kNoPreference;
 
+  // Forced colors indicates whether forced color mode is active or not. Forced
+  // colors is used to evaluate the forced-colors and prefers-color-scheme
+  // media queries and is used to resolve the default color scheme as indicated
+  // by the preferred_color_scheme.
+  blink::ForcedColors forced_colors = blink::ForcedColors::kNone;
+
   // Network quality threshold below which resources from iframes are assigned
   // either kVeryLow or kVeryLow Blink priority.
   net::EffectiveConnectionType low_priority_iframes_threshold;
diff --git a/content/public/renderer/render_frame_observer.h b/content/public/renderer/render_frame_observer.h
index 0153862..29405a94 100644
--- a/content/public/renderer/render_frame_observer.h
+++ b/content/public/renderer/render_frame_observer.h
@@ -197,6 +197,15 @@
       const network::URLLoaderCompletionStatus& status) {}
   virtual void DidCancelResponse(int request_id) {}
 
+  // Reports that a resource was loaded from the blink memory cache.
+  // |request_id| uniquely identifies this resource within this render frame.
+  // |from_archive| indicates if the resource originated from a MHTML archive.
+  virtual void DidLoadResourceFromMemoryCache(const GURL& response_url,
+                                              int request_id,
+                                              int64_t encoded_body_length,
+                                              const std::string& mime_type,
+                                              bool from_archive) {}
+
   // Notification when the renderer observes data used during the page load.
   // This is used for page load metrics. |received_data_length| is the received
   // network bytes. |resource_id| uniquely identifies the resource within this
diff --git a/content/public/test/test_browser_thread_bundle_unittest.cc b/content/public/test/test_browser_thread_bundle_unittest.cc
index f796325d..28ebbab 100644
--- a/content/public/test/test_browser_thread_bundle_unittest.cc
+++ b/content/public/test/test_browser_thread_bundle_unittest.cc
@@ -150,7 +150,7 @@
   signaled_on_real_io_thread.TimedWait(base::TimeDelta::FromSeconds(5));
   EXPECT_TRUE(signaled_on_real_io_thread.IsSignaled());
 
-  // Tasks posted via PostTask don't run in ExecutionMode::QUEUED until
+  // Tasks posted via PostTask don't run in ThreadPoolExecutionMode::QUEUED until
   // RunUntilIdle is called.
   base::AtomicFlag task_ran;
   PostTask(FROM_HERE,
diff --git a/content/public/test/url_loader_interceptor.cc b/content/public/test/url_loader_interceptor.cc
index 9de8415..e3f3e2ec 100644
--- a/content/public/test/url_loader_interceptor.cc
+++ b/content/public/test/url_loader_interceptor.cc
@@ -56,7 +56,10 @@
     : public base::RefCountedThreadSafe<URLLoaderInterceptor::IOState> {
  public:
   explicit IOState(URLLoaderInterceptor* parent) : parent_(parent) {}
-  void Initialize(base::OnceClosure closure);
+  void Initialize(
+      const URLLoaderCompletionStatusCallback& completion_status_callback,
+      base::OnceClosure closure);
+
   // Called when a SubresourceWrapper's binding has an error.
   void SubresourceWrapperBindingError(SubresourceWrapper* wrapper);
 
@@ -157,6 +160,10 @@
             std::move(proxied_request), std::move(target_factory), this));
   }
 
+  URLLoaderCompletionStatusCallback GetCompletionStatusCallback() {
+    return completion_status_callback_;
+  }
+
  private:
   friend class base::RefCountedThreadSafe<IOState>;
   ~IOState() {}
@@ -166,6 +173,8 @@
   base::Lock intercept_lock_;
   URLLoaderInterceptor* parent_ GUARDED_BY(intercept_lock_);
 
+  URLLoaderCompletionStatusCallback completion_status_callback_;
+
   // For intercepting frame requests with network service. There is one per
   // StoragePartition. Only accessed on IO thread.
   std::set<std::unique_ptr<URLLoaderFactoryGetterWrapper>>
@@ -183,6 +192,68 @@
   DISALLOW_COPY_AND_ASSIGN(IOState);
 };
 
+class URLLoaderClientInterceptor : public network::mojom::URLLoaderClient {
+ public:
+  explicit URLLoaderClientInterceptor(
+      const base::Callback<network::mojom::URLLoaderFactory*()>& factory_getter,
+      URLLoaderInterceptor::RequestParams params,
+      const URLLoaderInterceptor::URLLoaderCompletionStatusCallback&
+          completion_status_callback)
+      : original_client_(std::move(params.client)),
+        delegating_client_binding_(this),
+        completion_status_callback_(std::move(completion_status_callback)),
+        request_url_(params.url_request.url) {
+    network::mojom::URLLoaderClientPtr delegating_client;
+    delegating_client_binding_.Bind(mojo::MakeRequest(&delegating_client));
+    factory_getter.Run()->CreateLoaderAndStart(
+        std::move(params.request), params.routing_id, params.request_id,
+        params.options, std::move(params.url_request),
+        std::move(delegating_client), params.traffic_annotation);
+  }
+
+  void OnReceiveResponse(const network::ResourceResponseHead& head) override {
+    original_client_->OnReceiveResponse(head);
+  }
+
+  void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
+                         const network::ResourceResponseHead& head) override {
+    original_client_->OnReceiveRedirect(redirect_info, head);
+  }
+
+  void OnUploadProgress(int64_t current_position,
+                        int64_t total_size,
+                        base::OnceCallback<void()> callback) override {
+    original_client_->OnUploadProgress(current_position, total_size,
+                                       std::move(callback));
+  }
+
+  void OnReceiveCachedMetadata(mojo_base::BigBuffer data) override {
+    original_client_->OnReceiveCachedMetadata(std::move(data));
+  }
+
+  void OnTransferSizeUpdated(int32_t transfer_size_diff) override {
+    original_client_->OnTransferSizeUpdated(transfer_size_diff);
+  }
+
+  void OnStartLoadingResponseBody(
+      mojo::ScopedDataPipeConsumerHandle body) override {
+    original_client_->OnStartLoadingResponseBody(std::move(body));
+  }
+
+  void OnComplete(const network::URLLoaderCompletionStatus& status) override {
+    if (!completion_status_callback_.is_null())
+      completion_status_callback_.Run(request_url_, status);
+    original_client_->OnComplete(status);
+  }
+
+ private:
+  network::mojom::URLLoaderClientPtr original_client_;
+  mojo::Binding<network::mojom::URLLoaderClient> delegating_client_binding_;
+  URLLoaderInterceptor::URLLoaderCompletionStatusCallback
+      completion_status_callback_;
+  GURL request_url_;
+};
+
 class URLLoaderInterceptor::Interceptor
     : public network::mojom::URLLoaderFactory {
  public:
@@ -233,10 +304,10 @@
     if (parent_->Intercept(&params))
       return;
 
-    original_factory_getter_.Run()->CreateLoaderAndStart(
-        std::move(params.request), params.routing_id, params.request_id,
-        params.options, std::move(params.url_request), std::move(params.client),
-        params.traffic_annotation);
+    url_loader_client_interceptor_ =
+        std::make_unique<URLLoaderClientInterceptor>(
+            std::move(original_factory_getter_), std::move(params),
+            parent_->GetCompletionStatusCallback());
   }
 
   void Clone(network::mojom::URLLoaderFactoryRequest request) override {
@@ -253,6 +324,7 @@
   OriginalFactoryGetter original_factory_getter_;
   mojo::BindingSet<network::mojom::URLLoaderFactory> bindings_;
   base::OnceClosure error_handler_;
+  std::unique_ptr<URLLoaderClientInterceptor> url_loader_client_interceptor_;
 
   DISALLOW_COPY_AND_ASSIGN(Interceptor);
 };
@@ -378,10 +450,12 @@
 operator=(RequestParams&& other) = default;
 
 URLLoaderInterceptor::URLLoaderInterceptor(const InterceptCallback& callback)
-    : URLLoaderInterceptor(callback, {}) {}
+    : URLLoaderInterceptor(callback, {}, {}) {}
 
-URLLoaderInterceptor::URLLoaderInterceptor(const InterceptCallback& callback,
-                                           base::OnceClosure ready_callback)
+URLLoaderInterceptor::URLLoaderInterceptor(
+    const InterceptCallback& callback,
+    const URLLoaderCompletionStatusCallback& completion_status_callback,
+    base::OnceClosure ready_callback)
     : callback_(callback), io_thread_(base::MakeRefCounted<IOState>(this)) {
   DCHECK(!BrowserThread::IsThreadInitialized(BrowserThread::UI) ||
          BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -418,6 +492,7 @@
       base::PostTaskWithTraits(
           FROM_HERE, {BrowserThread::IO},
           base::BindOnce(&URLLoaderInterceptor::IOState::Initialize, io_thread_,
+                         std::move(completion_status_callback),
                          run_loop.QuitClosure()));
       run_loop.Run();
     } else {
@@ -431,10 +506,12 @@
       base::PostTaskWithTraits(
           FROM_HERE, {BrowserThread::IO},
           base::BindOnce(&URLLoaderInterceptor::IOState::Initialize, io_thread_,
+                         std::move(completion_status_callback),
                          std::move(wrapped_callback)));
     }
   } else {
-    io_thread_->Initialize(std::move(ready_callback));
+    io_thread_->Initialize(std::move(completion_status_callback),
+                           std::move(ready_callback));
   }
 }
 
@@ -610,7 +687,10 @@
   subresource_wrappers_.erase(it);
 }
 
-void URLLoaderInterceptor::IOState::Initialize(base::OnceClosure closure) {
+void URLLoaderInterceptor::IOState::Initialize(
+    const URLLoaderCompletionStatusCallback& completion_status_callback,
+    base::OnceClosure closure) {
+  completion_status_callback_ = std::move(completion_status_callback);
   if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
     URLLoaderFactoryGetter::SetGetNetworkFactoryCallbackForTesting(
         base::BindRepeating(
@@ -679,7 +759,7 @@
             return true;
           },
           url, error),
-      std::move(ready_callback));
+      URLLoaderCompletionStatusCallback(), std::move(ready_callback));
 }
 
 }  // namespace content
diff --git a/content/public/test/url_loader_interceptor.h b/content/public/test/url_loader_interceptor.h
index eab5cef..4bcceffd 100644
--- a/content/public/test/url_loader_interceptor.h
+++ b/content/public/test/url_loader_interceptor.h
@@ -79,13 +79,25 @@
   // forward the request to the original URLLoaderFactory.
   using InterceptCallback = base::Callback<bool(RequestParams* params)>;
 
+  // Function signature for a loading completion method.
+  // This class will listen on loading completion responses from the network,
+  // invoke this callback, and delegate the response to the original client.
+  using URLLoaderCompletionStatusCallback = base::RepeatingCallback<void(
+      const GURL& request_url,
+      const network::URLLoaderCompletionStatus& status)>;
+
   // Create an interceptor which calls |callback|. If |ready_callback| is not
   // provided, a nested RunLoop is used to ensure the interceptor is ready
   // before returning. If |ready_callback| is provided, no RunLoop is called,
   // and instead |ready_callback| is called after the interceptor is installed.
+  // If provided, |completion_status_callback| is called when the load
+  // completes.
   explicit URLLoaderInterceptor(const InterceptCallback& callback);
-  URLLoaderInterceptor(const InterceptCallback& callback,
-                       base::OnceClosure ready_callback);
+  URLLoaderInterceptor(
+      const InterceptCallback& callback,
+      const URLLoaderCompletionStatusCallback& completion_status_callback,
+      base::OnceClosure ready_callback);
+
   ~URLLoaderInterceptor();
 
   // Helper methods for use when intercepting.
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 15d4d297..4d27f405 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -286,8 +286,6 @@
     "media/webrtc/webrtc_audio_device_impl.h",
     "media/webrtc/webrtc_audio_device_not_impl.cc",
     "media/webrtc/webrtc_audio_device_not_impl.h",
-    "media/webrtc/webrtc_audio_renderer.cc",
-    "media/webrtc/webrtc_audio_renderer.h",
     "media/webrtc/webrtc_audio_sink.cc",
     "media/webrtc/webrtc_audio_sink.h",
     "media/webrtc/webrtc_media_stream_track_adapter.cc",
diff --git a/content/renderer/accessibility/blink_ax_tree_source.cc b/content/renderer/accessibility/blink_ax_tree_source.cc
index 988c1d46..0d4a7d3 100644
--- a/content/renderer/accessibility/blink_ax_tree_source.cc
+++ b/content/renderer/accessibility/blink_ax_tree_source.cc
@@ -1211,6 +1211,11 @@
   if (!base::FeatureList::IsEnabled(features::kExperimentalAccessibilityLabels))
     return;
 
+  // Reject ignored objects
+  if (src.AccessibilityIsIgnored()) {
+    return;
+  }
+
   // Reject images that are explicitly empty, or that have a name already.
   //
   // In the future, we may annotate some images that have a name
diff --git a/content/renderer/loader/web_url_loader_impl.cc b/content/renderer/loader/web_url_loader_impl.cc
index fea44b2..987dd7ae 100644
--- a/content/renderer/loader/web_url_loader_impl.cc
+++ b/content/renderer/loader/web_url_loader_impl.cc
@@ -1098,6 +1098,7 @@
   response->SetDidServiceWorkerNavigationPreload(
       info.did_service_worker_navigation_preload);
   response->SetEncodedDataLength(info.encoded_data_length);
+  response->SetEncodedBodyLength(info.encoded_body_length);
   response->SetAlpnNegotiatedProtocol(
       WebString::FromUTF8(info.alpn_negotiated_protocol));
   response->SetConnectionInfo(info.connection_info);
diff --git a/content/renderer/media/stream/media_stream_renderer_factory_impl.cc b/content/renderer/media/stream/media_stream_renderer_factory_impl.cc
index b8612ddb..8e767eb0 100644
--- a/content/renderer/media/stream/media_stream_renderer_factory_impl.cc
+++ b/content/renderer/media/stream/media_stream_renderer_factory_impl.cc
@@ -10,7 +10,7 @@
 #include "content/public/renderer/render_frame.h"
 #include "content/renderer/media/stream/track_audio_renderer.h"
 #include "content/renderer/media/webrtc/peer_connection_dependency_factory.h"
-#include "content/renderer/media/webrtc/webrtc_audio_renderer.h"
+#include "content/renderer/media/webrtc/webrtc_audio_device_impl.h"
 #include "content/renderer/render_thread_impl.h"
 #include "third_party/blink/public/platform/modules/mediastream/media_stream_audio_track.h"
 #include "third_party/blink/public/platform/modules/webrtc/peer_connection_remote_audio_source.h"
@@ -18,6 +18,7 @@
 #include "third_party/blink/public/platform/web_media_stream.h"
 #include "third_party/blink/public/web/modules/mediastream/media_stream_video_renderer_sink.h"
 #include "third_party/blink/public/web/modules/mediastream/media_stream_video_track.h"
+#include "third_party/blink/public/web/modules/webrtc/webrtc_audio_renderer.h"
 #include "third_party/blink/public/web/web_local_frame.h"
 #include "third_party/webrtc/api/media_stream_interface.h"
 
@@ -107,8 +108,6 @@
     return nullptr;
   }
 
-  int render_frame_id = RenderFrame::GetRoutingIdForWebFrame(web_frame);
-
   // If the track has a local source, or is a remote track that does not use the
   // WebRTC audio pipeline, return a new TrackAudioRenderer instance.
   if (!blink::PeerConnectionRemoteAudioTrack::From(audio_track)) {
@@ -117,6 +116,7 @@
     DVLOG(1) << "Creating TrackAudioRenderer for "
              << (audio_track->is_local_track() ? "local" : "remote")
              << " track.";
+    int render_frame_id = RenderFrame::GetRoutingIdForWebFrame(web_frame);
     return new TrackAudioRenderer(audio_tracks[0], render_frame_id,
                                   0 /* no session_id */, device_id);
   }
@@ -127,15 +127,15 @@
   DCHECK(audio_device);
 
   // Share the existing renderer if any, otherwise create a new one.
-  scoped_refptr<WebRtcAudioRenderer> renderer(audio_device->renderer());
+  scoped_refptr<blink::WebRtcAudioRenderer> renderer(audio_device->renderer());
   if (renderer) {
     DVLOG(1) << "Using existing WebRtcAudioRenderer for remote WebRTC track.";
   } else {
     DVLOG(1) << "Creating WebRtcAudioRenderer for remote WebRTC track.";
-    renderer = new WebRtcAudioRenderer(
+
+    renderer = new blink::WebRtcAudioRenderer(
         GetPeerConnectionDependencyFactory()->GetWebRtcSignalingThread(),
-        web_stream, render_frame_id, GetSessionIdForWebRtcAudioRenderer(),
-        device_id);
+        web_stream, web_frame, GetSessionIdForWebRtcAudioRenderer(), device_id);
 
     if (!audio_device->SetAudioRenderer(renderer.get())) {
       blink::WebRtcLogMessage(
diff --git a/content/renderer/media/stream/webmediaplayer_ms_unittest.cc b/content/renderer/media/stream/webmediaplayer_ms_unittest.cc
index 2897d8de..e64120a7 100644
--- a/content/renderer/media/stream/webmediaplayer_ms_unittest.cc
+++ b/content/renderer/media/stream/webmediaplayer_ms_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
+#include "base/strings/stringprintf.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
diff --git a/content/renderer/media/webrtc/webrtc_audio_device_impl.cc b/content/renderer/media/webrtc/webrtc_audio_device_impl.cc
index 1cb3dfb..16a6e84 100644
--- a/content/renderer/media/webrtc/webrtc_audio_device_impl.cc
+++ b/content/renderer/media/webrtc/webrtc_audio_device_impl.cc
@@ -10,10 +10,10 @@
 #include "base/strings/string_util.h"
 #include "base/trace_event/trace_event.h"
 #include "content/renderer/media/stream/processed_local_audio_source.h"
-#include "content/renderer/media/webrtc/webrtc_audio_renderer.h"
 #include "media/base/audio_bus.h"
 #include "media/base/audio_parameters.h"
 #include "media/base/sample_rates.h"
+#include "third_party/blink/public/web/modules/webrtc/webrtc_audio_renderer.h"
 
 using media::AudioParameters;
 using media::ChannelLayout;
@@ -102,7 +102,8 @@
     sink->OnPlayoutData(audio_bus, sample_rate, audio_delay_milliseconds);
 }
 
-void WebRtcAudioDeviceImpl::RemoveAudioRenderer(WebRtcAudioRenderer* renderer) {
+void WebRtcAudioDeviceImpl::RemoveAudioRenderer(
+    blink::WebRtcAudioRenderer* renderer) {
   DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
   base::AutoLock auto_lock(lock_);
   DCHECK_EQ(renderer, renderer_.get());
@@ -334,7 +335,8 @@
   return 0;
 }
 
-bool WebRtcAudioDeviceImpl::SetAudioRenderer(WebRtcAudioRenderer* renderer) {
+bool WebRtcAudioDeviceImpl::SetAudioRenderer(
+    blink::WebRtcAudioRenderer* renderer) {
   DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
   DCHECK(renderer);
 
diff --git a/content/renderer/media/webrtc/webrtc_audio_device_impl.h b/content/renderer/media/webrtc/webrtc_audio_device_impl.h
index ddd1d137..28dac021 100644
--- a/content/renderer/media/webrtc/webrtc_audio_device_impl.h
+++ b/content/renderer/media/webrtc/webrtc_audio_device_impl.h
@@ -39,6 +39,10 @@
 //    important to be careful with the order in which locks are acquired in
 //    order to avoid potential deadlocks.
 //
+namespace blink {
+class WebRtcAudioRenderer;
+}
+
 namespace media {
 class AudioBus;
 }
@@ -46,44 +50,13 @@
 namespace content {
 
 class ProcessedLocalAudioSource;
-class WebRtcAudioRenderer;
-
-// TODO(xians): Move the following two interfaces to webrtc so that
-// libjingle can own references to the renderer and capturer.
-class WebRtcAudioRendererSource {
- public:
-  // Callback to get the rendered data.
-  // |audio_bus| must have buffer size |sample_rate/100| and 1-2 channels.
-  virtual void RenderData(media::AudioBus* audio_bus,
-                          int sample_rate,
-                          int audio_delay_milliseconds,
-                          base::TimeDelta* current_time) = 0;
-
-  // Callback to notify the client that the renderer is going away.
-  virtual void RemoveAudioRenderer(WebRtcAudioRenderer* renderer) = 0;
-
-  // Callback to notify the client that the audio renderer thread stopped.
-  // This function must be called only when that thread is actually stopped.
-  // Otherwise a race may occur.
-  virtual void AudioRendererThreadStopped() = 0;
-
-  // Callback to notify the client of the output device the renderer is using.
-  virtual void SetOutputDeviceForAec(const std::string& output_device_id) = 0;
-
-  // Returns the UnguessableToken used to connect this stream to an input stream
-  // for echo cancellation.
-  virtual base::UnguessableToken GetAudioProcessingId() const = 0;
-
- protected:
-  virtual ~WebRtcAudioRendererSource() {}
-};
 
 // Note that this class inherits from webrtc::AudioDeviceModule but due to
 // the high number of non-implemented methods, we move the cruft over to the
 // WebRtcAudioDeviceNotImpl.
 class CONTENT_EXPORT WebRtcAudioDeviceImpl
     : public WebRtcAudioDeviceNotImpl,
-      public WebRtcAudioRendererSource,
+      public blink::WebRtcAudioRendererSource,
       public blink::WebRtcPlayoutDataSource {
  public:
   // The maximum volume value WebRtc uses.
@@ -134,7 +107,7 @@
  public:
   // Sets the |renderer_|, returns false if |renderer_| already exists.
   // Called on the main renderer thread.
-  bool SetAudioRenderer(WebRtcAudioRenderer* renderer);
+  bool SetAudioRenderer(blink::WebRtcAudioRenderer* renderer);
 
   // Adds/Removes the |capturer| to the ADM.  Does NOT take ownership.
   // Capturers must remain valid until RemoveAudioCapturer() is called.
@@ -150,11 +123,11 @@
   // function will not be able to pick an appropriate device and return 0.
   int GetAuthorizedDeviceSessionIdForAudioRenderer();
 
-  const scoped_refptr<WebRtcAudioRenderer>& renderer() const {
+  const scoped_refptr<blink::WebRtcAudioRenderer>& renderer() const {
     return renderer_;
   }
 
-  // WebRtcAudioRendererSource implementation.
+  // blink::WebRtcAudioRendererSource implementation.
 
   // Called on the AudioOutputDevice worker thread.
   void RenderData(media::AudioBus* audio_bus,
@@ -163,7 +136,7 @@
                   base::TimeDelta* current_time) override;
 
   // Called on the main render thread.
-  void RemoveAudioRenderer(WebRtcAudioRenderer* renderer) override;
+  void RemoveAudioRenderer(blink::WebRtcAudioRenderer* renderer) override;
   void AudioRendererThreadStopped() override;
   void SetOutputDeviceForAec(const std::string& output_device_id) override;
   base::UnguessableToken GetAudioProcessingId() const override;
@@ -194,7 +167,7 @@
   CapturerList capturers_;
 
   // Provides access to the audio renderer in the browser process.
-  scoped_refptr<WebRtcAudioRenderer> renderer_ GUARDED_BY(lock_);
+  scoped_refptr<blink::WebRtcAudioRenderer> renderer_ GUARDED_BY(lock_);
 
   // A list of raw pointer of blink::WebRtcPlayoutDataSource::Sink objects which
   // want to get the playout data, the sink need to call RemovePlayoutSink()
diff --git a/content/renderer/media/webrtc/webrtc_audio_renderer_unittest.cc b/content/renderer/media/webrtc/webrtc_audio_renderer_unittest.cc
index f58b9773..de1d6b7 100644
--- a/content/renderer/media/webrtc/webrtc_audio_renderer_unittest.cc
+++ b/content/renderer/media/webrtc/webrtc_audio_renderer_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/renderer/media/webrtc/webrtc_audio_renderer.h"
+#include "third_party/blink/public/web/modules/webrtc/webrtc_audio_renderer.h"
 
 #include <string>
 #include <utility>
@@ -14,18 +14,20 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "content/renderer/media/audio/audio_device_factory.h"
-#include "content/renderer/media/webrtc/webrtc_audio_device_impl.h"
 #include "media/base/audio_capturer_source.h"
 #include "media/base/mock_audio_renderer_sink.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/platform/audio/web_audio_device_source_type.h"
 #include "third_party/blink/public/platform/modules/mediastream/web_media_stream_audio_renderer.h"
+#include "third_party/blink/public/platform/modules/webrtc/webrtc_source.h"
+#include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "third_party/blink/public/platform/web_media_stream.h"
 #include "third_party/blink/public/platform/web_media_stream_track.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/web/web_heap.h"
+#include "third_party/blink/public/web/web_local_frame.h"
 #include "third_party/webrtc/api/media_stream_interface.h"
 
 using testing::Return;
@@ -41,7 +43,7 @@
 const char kOtherOutputDeviceId[] = "other-output-device";
 const char kInvalidOutputDeviceId[] = "invalid-device";
 
-class MockAudioRendererSource : public WebRtcAudioRendererSource {
+class MockAudioRendererSource : public blink::WebRtcAudioRendererSource {
  public:
   MockAudioRendererSource() {}
   ~MockAudioRendererSource() override {}
@@ -49,12 +51,41 @@
                                 int sample_rate,
                                 int audio_delay_milliseconds,
                                 base::TimeDelta* current_time));
-  MOCK_METHOD1(RemoveAudioRenderer, void(WebRtcAudioRenderer* renderer));
+  MOCK_METHOD1(RemoveAudioRenderer, void(blink::WebRtcAudioRenderer* renderer));
   MOCK_METHOD0(AudioRendererThreadStopped, void());
   MOCK_METHOD1(SetOutputDeviceForAec, void(const std::string&));
   MOCK_CONST_METHOD0(GetAudioProcessingId, base::UnguessableToken());
 };
 
+// Mock blink::Platform implementation needed for creating
+// media::AudioRendererSink instances.
+//
+// TODO(crbug.com/704136): Remove this class once this test is Onion souped
+// (which is blocked on Onion souping AudioDeviceFactory).
+//
+// TODO(crbug.com/704136): When this test gets Onion soup'ed, consider
+// factorying this class out of it into its own reusable helper file.
+// The class could inherit from TestingPlatformSupport and use
+// ScopedTestingPlatformSupport.
+class AudioDeviceFactoryTestingPlatformSupport : public blink::Platform {
+ public:
+  scoped_refptr<media::AudioRendererSink> NewAudioRendererSink(
+      blink::WebAudioDeviceSourceType source_type,
+      blink::WebLocalFrame* web_frame,
+      const media::AudioSinkParameters& params) override {
+    MockNewAudioRendererSink(source_type, web_frame, params);
+    // The actual |web_frame| is irrelevant in this mock implementation,
+    // hence it is fine to use MSG_ROUTING_NONE
+    return AudioDeviceFactory::NewAudioRendererSink(source_type,
+                                                    MSG_ROUTING_NONE, params);
+  }
+
+  MOCK_METHOD3(MockNewAudioRendererSink,
+               void(blink::WebAudioDeviceSourceType,
+                    blink::WebLocalFrame*,
+                    const media::AudioSinkParameters&));
+};
+
 }  // namespace
 
 class WebRtcAudioRendererTest : public testing::Test,
@@ -69,6 +100,9 @@
 
  protected:
   WebRtcAudioRendererTest() : source_(new MockAudioRendererSource()) {
+    blink::Platform::SetCurrentPlatformForTesting(
+        &audio_device_factory_platform_);
+
     blink::WebVector<blink::WebMediaStreamTrack> dummy_tracks;
     stream_.Initialize(blink::WebString::FromUTF8("new stream"), dummy_tracks,
                        dummy_tracks);
@@ -77,9 +111,14 @@
   }
 
   void SetupRenderer(const std::string& device_id) {
-    renderer_ = new WebRtcAudioRenderer(
-        blink::scheduler::GetSingleThreadTaskRunnerForTesting(), stream_, 1, 1,
-        device_id);
+    renderer_ = new blink::WebRtcAudioRenderer(
+        blink::scheduler::GetSingleThreadTaskRunnerForTesting(), stream_,
+        nullptr, 1, device_id);
+
+    EXPECT_CALL(
+        audio_device_factory_platform_,
+        MockNewAudioRendererSink(_, nullptr /*blink::WebLocalFrame*/, _))
+        .Times(testing::AtLeast(1));
     EXPECT_CALL(*this, MockCreateAudioRendererSink(
                            blink::WebAudioDeviceSourceType::kWebRtc, _, _,
                            device_id, _));
@@ -143,6 +182,7 @@
     blink::WebHeap::CollectAllGarbageForTesting();
   }
 
+  AudioDeviceFactoryTestingPlatformSupport audio_device_factory_platform_;
   const base::Optional<base::UnguessableToken> kAudioProcessingId =
       base::UnguessableToken::Create();
   base::test::ScopedTaskEnvironment task_environment_{
@@ -150,7 +190,7 @@
   scoped_refptr<media::MockAudioRendererSink> mock_sink_;
   std::unique_ptr<MockAudioRendererSource> source_;
   blink::WebMediaStream stream_;
-  scoped_refptr<WebRtcAudioRenderer> renderer_;
+  scoped_refptr<blink::WebRtcAudioRenderer> renderer_;
   scoped_refptr<blink::WebMediaStreamAudioRenderer> renderer_proxy_;
 };
 
@@ -297,9 +337,9 @@
 }
 
 TEST_F(WebRtcAudioRendererTest, InitializeWithInvalidDevice) {
-  renderer_ = new WebRtcAudioRenderer(
-      blink::scheduler::GetSingleThreadTaskRunnerForTesting(), stream_, 1, 1,
-      kInvalidOutputDeviceId);
+  renderer_ = new blink::WebRtcAudioRenderer(
+      blink::scheduler::GetSingleThreadTaskRunnerForTesting(), stream_,
+      nullptr /*blink::WebLocalFrame*/, 1, kInvalidOutputDeviceId);
 
   EXPECT_CALL(*this, MockCreateAudioRendererSink(
                          blink::WebAudioDeviceSourceType::kWebRtc, _, _,
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index ef1b6af..e2d0776 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -5399,6 +5399,12 @@
   if (request.Url().ProtocolIs(url::kDataScheme))
     return;
 
+  for (auto& observer : observers_) {
+    observer.DidLoadResourceFromMemoryCache(
+        request.Url(), response.RequestId(), response.EncodedBodyLength(),
+        response.MimeType().Utf8(), response.FromArchive());
+  }
+
   // Let the browser know we loaded a resource from the memory cache.  This
   // message is needed to display the correct SSL indicators.
   Send(new FrameHostMsg_DidLoadResourceFromMemoryCache(
diff --git a/content/renderer/render_frame_proxy.cc b/content/renderer/render_frame_proxy.cc
index 9dbcd82..33fb2c1b 100644
--- a/content/renderer/render_frame_proxy.cc
+++ b/content/renderer/render_frame_proxy.cc
@@ -267,16 +267,6 @@
   SynchronizeVisualProperties();
 }
 
-void RenderFrameProxy::WillBeginCompositorFrame() {
-  if (compositing_helper_ && compositing_helper_->surface_id().is_valid()) {
-    FrameHostMsg_HittestData_Params params;
-    params.surface_id = compositing_helper_->surface_id();
-    params.ignored_for_hittest = web_frame_->IsIgnoredForHitTest();
-    render_widget_->QueueMessage(
-        new FrameHostMsg_HittestData(render_widget_->routing_id(), params));
-  }
-}
-
 void RenderFrameProxy::OnScreenInfoChanged(const ScreenInfo& screen_info) {
   pending_visual_properties_.screen_info = screen_info;
   if (crashed_) {
diff --git a/content/renderer/render_frame_proxy.h b/content/renderer/render_frame_proxy.h
index 04a8e0f..52202a29 100644
--- a/content/renderer/render_frame_proxy.h
+++ b/content/renderer/render_frame_proxy.h
@@ -123,10 +123,6 @@
   // IPC::Listener
   bool OnMessageReceived(const IPC::Message& msg) override;
 
-  // Out-of-process child frames receive a signal from blink::LayerTreeView
-  // when a compositor frame will begin.
-  void WillBeginCompositorFrame();
-
   // Out-of-process child frames receive a signal from RenderWidget when the
   // ScreenInfo has changed.
   void OnScreenInfoChanged(const ScreenInfo& screen_info);
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index dae2f5a0..e136b0a 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -935,6 +935,7 @@
 
   settings->SetLazyLoadEnabled(prefs.lazy_load_enabled);
   settings->SetPreferredColorScheme(prefs.preferred_color_scheme);
+  settings->SetForcedColors(prefs.forced_colors);
 
   for (const auto& ect_distance_pair :
        prefs.lazy_frame_loading_distance_thresholds_px) {
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index 5af0983..c1dea93 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -1364,9 +1364,6 @@
   // is done.
   UpdateTextInputState();
   UpdateSelectionBounds();
-
-  for (auto& observer : render_frame_proxies_)
-    observer.WillBeginCompositorFrame();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/content/shell/android/linker_test_apk/chromium_linker_test_linker_tests.cc b/content/shell/android/linker_test_apk/chromium_linker_test_linker_tests.cc
index fa410e3..4bae8bc 100644
--- a/content/shell/android/linker_test_apk/chromium_linker_test_linker_tests.cc
+++ b/content/shell/android/linker_test_apk/chromium_linker_test_linker_tests.cc
@@ -41,7 +41,7 @@
       in_browser_process ? "BROWSER_LINKER_TEST: " : "RENDERER_LINKER_TEST: ";
 
   // The RELRO section(s) will appear in /proc/self/maps as a mapped memory
-  // region for a file with a recognizable name. For the Chromium Linker the
+  // region for a file with a recognizable name. For the LegacyLinker the
   // full name will be something like:
   //
   //   "/dev/ashmem/RELRO:<libname> (deleted)"
diff --git a/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/LinkerTests.java b/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/LinkerTests.java
index 0f54be1..f41e44dab 100644
--- a/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/LinkerTests.java
+++ b/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/LinkerTests.java
@@ -23,7 +23,7 @@
                              boolean isBrowserProcess) {
         boolean checkSharedRelro;
         if (isBrowserProcess) {
-            // Linker may share RELROs in the browser.
+            // LegacyLinker may share RELROs in the browser.
             switch (Linker.BROWSER_SHARED_RELRO_CONFIG) {
                 case Linker.BROWSER_SHARED_RELRO_CONFIG_NEVER:
                     checkSharedRelro = false;
diff --git a/content/shell/browser/web_test/web_test_bluetooth_adapter_provider.cc b/content/shell/browser/web_test/web_test_bluetooth_adapter_provider.cc
index 180bcca..dc21c32b 100644
--- a/content/shell/browser/web_test/web_test_bluetooth_adapter_provider.cc
+++ b/content/shell/browser/web_test/web_test_bluetooth_adapter_provider.cc
@@ -20,7 +20,7 @@
 #include "device/bluetooth/bluetooth_adapter.h"
 #include "device/bluetooth/bluetooth_device.h"
 #include "device/bluetooth/bluetooth_discovery_session.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
 #include "device/bluetooth/test/mock_bluetooth_gatt_connection.h"
 #include "device/bluetooth/test/mock_bluetooth_gatt_descriptor.h"
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 7821e7e..a1df61d 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -951,6 +951,7 @@
     "../browser/service_worker/service_worker_browsertest.cc",
     "../browser/service_worker/service_worker_clients_api_browsertest.cc",
     "../browser/service_worker/service_worker_file_upload_browsertest.cc",
+    "../browser/service_worker/service_worker_network_isolation_key_browsertest.cc",
     "../browser/service_worker/service_worker_no_best_effort_tasks_browsertest.cc",
     "../browser/session_history_browsertest.cc",
     "../browser/shape_detection/shape_detection_browsertest.cc",
@@ -1637,11 +1638,7 @@
     "../browser/media/session/media_session_impl_unittest.cc",
     "../browser/media/session/media_session_uma_helper_unittest.cc",
     "../browser/media/webaudio/audio_context_manager_impl_unittest.cc",
-    "../browser/memory/memory_monitor_android_unittest.cc",
-    "../browser/memory/memory_monitor_win_unittest.cc",
     "../browser/memory/swap_metrics_driver_impl_unittest.cc",
-    "../browser/memory/test_memory_monitor.cc",
-    "../browser/memory/test_memory_monitor.h",
     "../browser/native_file_system/file_system_chooser_unittest.cc",
     "../browser/native_file_system/native_file_system_file_writer_impl_unittest.cc",
     "../browser/native_file_system/native_file_system_handle_base_unittest.cc",
@@ -1928,13 +1925,6 @@
     "url_request_context_builder_mojo_unittest.cc",
   ]
 
-  # ChromeOS also defines linux but their memory-monitors conflict.
-  if (is_chromeos) {
-    sources += [ "../browser/memory/memory_monitor_chromeos_unittest.cc" ]
-  } else {
-    sources += [ "../browser/memory/memory_monitor_linux_unittest.cc" ]
-  }
-
   if (is_mac) {
     sources += [
       "../browser/media/now_playing_info_center_notifier_unittest.cc",
diff --git a/content/test/data/accessibility/aria/hidden-described-by-expected-blink.txt b/content/test/data/accessibility/aria/hidden-described-by-expected-blink.txt
new file mode 100644
index 0000000..035d2fd5
--- /dev/null
+++ b/content/test/data/accessibility/aria/hidden-described-by-expected-blink.txt
@@ -0,0 +1,12 @@
+rootWebArea
+++genericContainer ignored
+++++genericContainer ignored
+++++++genericContainer ignored name='span-A1'
+++++++++staticText ignored
+++++++++genericContainer ignored name='span-A2'
+++++++++staticText ignored
+++++++++genericContainer description='span-A4' name='span-A3' descriptionFrom=relatedElement describedbyIds=genericContainer
+++++++++++genericContainer ignored name='span-A4'
+++++++++staticText ignored
+++++++genericContainer description='span-A2' name='span-B' descriptionFrom=relatedElement describedbyIds=genericContainer
+++++++genericContainer name='span-C'
diff --git a/content/test/data/accessibility/aria/hidden-described-by-expected-uia-win.txt b/content/test/data/accessibility/aria/hidden-described-by-expected-uia-win.txt
new file mode 100644
index 0000000..9d3a6a6
--- /dev/null
+++ b/content/test/data/accessibility/aria/hidden-described-by-expected-uia-win.txt
@@ -0,0 +1,4 @@
+document
+++group Name='span-A3' DescribedBy='span-A4'
+++group Name='span-B' DescribedBy='span-A2'
+++group Name='span-C'
diff --git a/content/test/data/accessibility/aria/hidden-described-by-expected-win.txt b/content/test/data/accessibility/aria/hidden-described-by-expected-win.txt
new file mode 100644
index 0000000..6e77a04
--- /dev/null
+++ b/content/test/data/accessibility/aria/hidden-described-by-expected-win.txt
@@ -0,0 +1,4 @@
+ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
+++IA2_ROLE_SECTION name='span-A3' description='span-A4'
+++IA2_ROLE_SECTION name='span-B' description='span-A2'
+++IA2_ROLE_SECTION name='span-C'
diff --git a/content/test/data/accessibility/aria/hidden-described-by.html b/content/test/data/accessibility/aria/hidden-described-by.html
new file mode 100644
index 0000000..9fd3f8b
--- /dev/null
+++ b/content/test/data/accessibility/aria/hidden-described-by.html
@@ -0,0 +1,29 @@
+<!--
+@UIA-WIN-ALLOW:Descr*
+@BLINK-ALLOW:descr*
+@WIN-ALLOW:descr*
+-->
+<!DOCTYPE html>
+<html>
+<style>
+  .hide {
+    visibility: hidden;
+  }
+  .visible {
+    visibility: visible;
+  }
+</style>
+<body>
+  <div>
+    <span class="hide" aria-label="span-A1">
+      <span aria-label="span-A2" id="a2"></span>
+      <span class="visible" aria-label="span-A3" aria-describedby="a4">
+        <span class="hide" aria-label="span-A4" id="a4"></span>
+      </span>
+    </span>
+
+    <span aria-label="span-B" aria-describedby="a2"></span>
+    <span aria-label="span-C"></span>
+  </div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/aria/hidden-expected-blink.txt b/content/test/data/accessibility/aria/hidden-expected-blink.txt
new file mode 100644
index 0000000..20e0cec1
--- /dev/null
+++ b/content/test/data/accessibility/aria/hidden-expected-blink.txt
@@ -0,0 +1,9 @@
+rootWebArea
+++genericContainer ignored
+++++genericContainer ignored
+++++++genericContainer ignored name='a1'
+++++++++staticText ignored
+++++++++genericContainer ignored name='a2'
+++++++++staticText ignored
+++++++genericContainer name='b'
+++++++genericContainer name='c'
diff --git a/content/test/data/accessibility/aria/hidden-expected-uia-win.txt b/content/test/data/accessibility/aria/hidden-expected-uia-win.txt
new file mode 100644
index 0000000..ef2fe77
--- /dev/null
+++ b/content/test/data/accessibility/aria/hidden-expected-uia-win.txt
@@ -0,0 +1,3 @@
+document
+++group Name='b'
+++group Name='c'
diff --git a/content/test/data/accessibility/aria/hidden-expected-win.txt b/content/test/data/accessibility/aria/hidden-expected-win.txt
new file mode 100644
index 0000000..1d262c97
--- /dev/null
+++ b/content/test/data/accessibility/aria/hidden-expected-win.txt
@@ -0,0 +1,3 @@
+ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
+++IA2_ROLE_SECTION name='b'
+++IA2_ROLE_SECTION name='c'
diff --git a/content/test/data/accessibility/aria/hidden-labelled-by-expected-blink.txt b/content/test/data/accessibility/aria/hidden-labelled-by-expected-blink.txt
new file mode 100644
index 0000000..3164933d
--- /dev/null
+++ b/content/test/data/accessibility/aria/hidden-labelled-by-expected-blink.txt
@@ -0,0 +1,9 @@
+rootWebArea
+++genericContainer ignored
+++++genericContainer ignored
+++++++genericContainer ignored name='span-A1'
+++++++genericContainer name='span-A2'
+++++++genericContainer name='span-A4' labelledbyIds=genericContainer
+++++++++genericContainer ignored name='span-A4'
+++++++genericContainer name='span-A2' labelledbyIds=genericContainer
+++++++genericContainer name='span-C'
diff --git a/content/test/data/accessibility/aria/hidden-labelled-by-expected-uia-win.txt b/content/test/data/accessibility/aria/hidden-labelled-by-expected-uia-win.txt
new file mode 100644
index 0000000..f21bba3
--- /dev/null
+++ b/content/test/data/accessibility/aria/hidden-labelled-by-expected-uia-win.txt
@@ -0,0 +1,5 @@
+document
+++group Name='span-A2'
+++group Name='span-A4' LabeledBy='span-A4'
+++group Name='span-A2' LabeledBy='span-A2'
+++group Name='span-C'
diff --git a/content/test/data/accessibility/aria/hidden-labelled-by-expected-win.txt b/content/test/data/accessibility/aria/hidden-labelled-by-expected-win.txt
new file mode 100644
index 0000000..54cba32
--- /dev/null
+++ b/content/test/data/accessibility/aria/hidden-labelled-by-expected-win.txt
@@ -0,0 +1,5 @@
+ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
+++IA2_ROLE_SECTION name='span-A2'
+++IA2_ROLE_SECTION name='span-A4'
+++IA2_ROLE_SECTION name='span-A2'
+++IA2_ROLE_SECTION name='span-C'
diff --git a/content/test/data/accessibility/aria/hidden-labelled-by.html b/content/test/data/accessibility/aria/hidden-labelled-by.html
new file mode 100644
index 0000000..15b6380
--- /dev/null
+++ b/content/test/data/accessibility/aria/hidden-labelled-by.html
@@ -0,0 +1,29 @@
+<!--
+@UIA-WIN-ALLOW:Label*
+@BLINK-ALLOW:label*
+@WIN-ALLOW:label*
+-->
+<!DOCTYPE html>
+<html>
+<style>
+  .hide {
+    visibility: hidden;
+  }
+  .visible {
+    visibility: visible;
+  }
+</style>
+<body>
+  <div>
+    <span class="hide" aria-label="span-A1"></span>
+      <span aria-label="span-A2" id="a2"></span>
+      <span class="visible" aria-label="span-A3" aria-labelledby="a4">
+        <span class="hide" aria-label="span-A4" id="a4"></span>
+      </span>
+    </span>
+
+    <span aria-label="span-B" aria-labeledby="a2"></span>
+    <span aria-label="span-C"></span>
+  </div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/aria/hidden.html b/content/test/data/accessibility/aria/hidden.html
new file mode 100644
index 0000000..4d8f972
--- /dev/null
+++ b/content/test/data/accessibility/aria/hidden.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<style>
+  .hide {
+    visibility: hidden;
+  }
+</style>
+<body>
+  <div>
+    <span class="hide" aria-label="a1">
+      <span aria-label="a2"></span>
+    </span>
+
+    <span aria-label="b"></span>
+    <span aria-label="c"></span>
+  </div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/event/css-visibility-expected-win.txt b/content/test/data/accessibility/event/css-visibility-expected-win.txt
index a267f80..d04c621 100644
--- a/content/test/data/accessibility/event/css-visibility-expected-win.txt
+++ b/content/test/data/accessibility/event/css-visibility-expected-win.txt
@@ -1,4 +1,4 @@
-EVENT_OBJECT_HIDE on <div.a> role=DIV level=2
+EVENT_OBJECT_HIDE on <div.a> role=DIV name="Heading" level=2
 EVENT_OBJECT_REORDER on <div> role=ROLE_SYSTEM_TOOLBAR IA2_STATE_HORIZONTAL
 EVENT_OBJECT_SHOW on <div.b> role=ROLE_SYSTEM_GROUPING name="Banner"
 IA2_EVENT_TEXT_INSERTED on <div> role=ROLE_SYSTEM_TOOLBAR IA2_STATE_HORIZONTAL new_text={'<obj>' start=0 end=1}
diff --git a/content/test/data/page_with_cached_subresource.html b/content/test/data/page_with_cached_subresource.html
index 2fc67bc..9d9d2ce 100644
--- a/content/test/data/page_with_cached_subresource.html
+++ b/content/test/data/page_with_cached_subresource.html
@@ -4,4 +4,4 @@
 </head>
 <body>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/content/test/data/service_worker/empty.js.mock-http-headers b/content/test/data/service_worker/empty.js.mock-http-headers
new file mode 100644
index 0000000..c6025e4
--- /dev/null
+++ b/content/test/data/service_worker/empty.js.mock-http-headers
@@ -0,0 +1,4 @@
+HTTP/1.1 200 OK
+Content-Type: application/javascript
+Cache-Control: max-age=100000
+Access-Control-Allow-Origin: *
\ No newline at end of file
diff --git a/content/test/data/service_worker/empty2.html b/content/test/data/service_worker/empty2.html
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/content/test/data/service_worker/empty2.html
diff --git a/content/test/data/service_worker/empty2.html.mock-http-headers b/content/test/data/service_worker/empty2.html.mock-http-headers
new file mode 100644
index 0000000..c6025e4
--- /dev/null
+++ b/content/test/data/service_worker/empty2.html.mock-http-headers
@@ -0,0 +1,4 @@
+HTTP/1.1 200 OK
+Content-Type: application/javascript
+Cache-Control: max-age=100000
+Access-Control-Allow-Origin: *
\ No newline at end of file
diff --git a/content/test/data/service_worker/frame_factory.html b/content/test/data/service_worker/frame_factory.html
new file mode 100644
index 0000000..1347117
--- /dev/null
+++ b/content/test/data/service_worker/frame_factory.html
@@ -0,0 +1,10 @@
+<body></body>
+<script>
+function createFrame(url, name) {
+  let frame = document.createElement('iframe');
+  frame.name = name;
+  frame.id = name;
+  frame.src = url;
+  document.body.appendChild(frame);
+}
+</script>
\ No newline at end of file
diff --git a/content/test/data/service_worker/worker_with_import_and_fetch.js b/content/test/data/service_worker/worker_with_import_and_fetch.js
new file mode 100644
index 0000000..e1c3bbb
--- /dev/null
+++ b/content/test/data/service_worker/worker_with_import_and_fetch.js
@@ -0,0 +1,10 @@
+// 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.
+
+// The service worker for the network isolation key test.
+const url_params = new URLSearchParams(location.search);
+let import_script_url = url_params.get("import_script_url");
+let fetch_url = url_params.get("fetch_url");
+importScripts(import_script_url);
+fetch(fetch_url);
diff --git a/content/test/data/service_worker/worker_with_import_and_fetch_2.js b/content/test/data/service_worker/worker_with_import_and_fetch_2.js
new file mode 100644
index 0000000..e1c3bbb
--- /dev/null
+++ b/content/test/data/service_worker/worker_with_import_and_fetch_2.js
@@ -0,0 +1,10 @@
+// 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.
+
+// The service worker for the network isolation key test.
+const url_params = new URLSearchParams(location.search);
+let import_script_url = url_params.get("import_script_url");
+let fetch_url = url_params.get("fetch_url");
+importScripts(import_script_url);
+fetch(fetch_url);
diff --git a/content/test/url_loader_interceptor_test.cc b/content/test/url_loader_interceptor_test.cc
index 7c715a5..8bfd081 100644
--- a/content/test/url_loader_interceptor_test.cc
+++ b/content/test/url_loader_interceptor_test.cc
@@ -119,7 +119,7 @@
             params->client->OnComplete(status);
             return true;
           }),
-      run_loop.QuitClosure());
+      /*completion_status_callback=*/{}, run_loop.QuitClosure());
   run_loop.Run();
   EXPECT_FALSE(NavigateToURL(shell(), GetPageURL()));
   EXPECT_TRUE(seen);
@@ -142,7 +142,7 @@
               params->client->OnComplete(status);
               return true;
             }),
-        run_loop.QuitClosure());
+        /*completion_status_callback=*/{}, run_loop.QuitClosure());
     run_loop.Run();
 
     ASSERT_FALSE(NavigateToURL(shell(), url));
diff --git a/device/BUILD.gn b/device/BUILD.gn
index 8bc2a11..d2fe7c6 100644
--- a/device/BUILD.gn
+++ b/device/BUILD.gn
@@ -38,8 +38,8 @@
     "bluetooth/bluetooth_remote_gatt_service_unittest.cc",
     "bluetooth/bluetooth_service_record_win_unittest.cc",
     "bluetooth/bluetooth_task_manager_win_unittest.cc",
-    "bluetooth/bluetooth_uuid_unittest.cc",
     "bluetooth/device_unittest.cc",
+    "bluetooth/public/cpp/bluetooth_uuid_unittest.cc",
     "bluetooth/string_util_icu_unittest.cc",
     "bluetooth/test/bluetooth_gatt_server_test.cc",
     "bluetooth/test/bluetooth_gatt_server_test.h",
diff --git a/device/bluetooth/BUILD.gn b/device/bluetooth/BUILD.gn
index 271f992..0e00d73 100644
--- a/device/bluetooth/BUILD.gn
+++ b/device/bluetooth/BUILD.gn
@@ -78,6 +78,7 @@
 
   deps = [
     ":bluetooth",
+    "//device/bluetooth/public/cpp",
     "//device/bluetooth/public/mojom:fake_bluetooth_interfaces",
     "//mojo/public/cpp/bindings",
   ]
@@ -206,8 +207,6 @@
     "bluetooth_socket_win.h",
     "bluetooth_task_manager_win.cc",
     "bluetooth_task_manager_win.h",
-    "bluetooth_uuid.cc",
-    "bluetooth_uuid.h",
     "string_util_icu.cc",
     "string_util_icu.h",
   ]
@@ -229,6 +228,10 @@
     "//ui/base",
   ]
 
+  public_deps = [
+    "//device/bluetooth/public/cpp",
+  ]
+
   if (is_android) {
     deps += [ ":jni_headers" ]
   }
@@ -447,9 +450,7 @@
           "cast/bluetooth_utils.h",
         ]
 
-        public_deps = [
-          "//chromecast/public",
-        ]
+        public_deps += [ "//chromecast/public" ]
 
         deps += [
           "//chromecast/device/bluetooth:util",
@@ -496,6 +497,7 @@
   public_deps = [
     ":bluetooth",
     "//base",
+    "//device/bluetooth/public/cpp",
     "//net",
     "//testing/gmock",
   ]
diff --git a/device/bluetooth/bluetooth_adapter_mac.h b/device/bluetooth/bluetooth_adapter_mac.h
index 7d089c3..0ff96757 100644
--- a/device/bluetooth/bluetooth_adapter_mac.h
+++ b/device/bluetooth/bluetooth_adapter_mac.h
@@ -26,7 +26,7 @@
 #include "device/bluetooth/bluetooth_low_energy_device_mac.h"
 #include "device/bluetooth/bluetooth_low_energy_device_watcher_mac.h"
 #include "device/bluetooth/bluetooth_low_energy_discovery_manager_mac.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 @class CBUUID;
 @class IOBluetoothDevice;
diff --git a/device/bluetooth/bluetooth_adapter_win.cc b/device/bluetooth/bluetooth_adapter_win.cc
index 8e66949ce..5057a942 100644
--- a/device/bluetooth/bluetooth_adapter_win.cc
+++ b/device/bluetooth/bluetooth_adapter_win.cc
@@ -26,7 +26,7 @@
 #include "device/bluetooth/bluetooth_socket_thread.h"
 #include "device/bluetooth/bluetooth_socket_win.h"
 #include "device/bluetooth/bluetooth_task_manager_win.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace device {
 
diff --git a/device/bluetooth/bluetooth_classic_device_mac.mm b/device/bluetooth/bluetooth_classic_device_mac.mm
index e15ae74..9a76125 100644
--- a/device/bluetooth/bluetooth_classic_device_mac.mm
+++ b/device/bluetooth/bluetooth_classic_device_mac.mm
@@ -15,7 +15,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/time/time.h"
 #include "device/bluetooth/bluetooth_socket_mac.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 // Undocumented API for accessing the Bluetooth transmit power level.
 // Similar to the API defined here [ http://goo.gl/20Q5vE ].
diff --git a/device/bluetooth/bluetooth_device.h b/device/bluetooth/bluetooth_device.h
index 74028fc..8a45ce71 100644
--- a/device/bluetooth/bluetooth_device.h
+++ b/device/bluetooth/bluetooth_device.h
@@ -27,7 +27,7 @@
 #include "device/bluetooth/bluetooth_common.h"
 #include "device/bluetooth/bluetooth_export.h"
 #include "device/bluetooth/bluetooth_remote_gatt_service.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace device {
 
diff --git a/device/bluetooth/bluetooth_device_win.cc b/device/bluetooth/bluetooth_device_win.cc
index 4b0d1717..4c244c1 100644
--- a/device/bluetooth/bluetooth_device_win.cc
+++ b/device/bluetooth/bluetooth_device_win.cc
@@ -18,7 +18,7 @@
 #include "device/bluetooth/bluetooth_socket_thread.h"
 #include "device/bluetooth/bluetooth_socket_win.h"
 #include "device/bluetooth/bluetooth_task_manager_win.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace {
 
diff --git a/device/bluetooth/bluetooth_device_win_unittest.cc b/device/bluetooth/bluetooth_device_win_unittest.cc
index 025092d..226ae3b5 100644
--- a/device/bluetooth/bluetooth_device_win_unittest.cc
+++ b/device/bluetooth/bluetooth_device_win_unittest.cc
@@ -15,7 +15,7 @@
 #include "device/bluetooth/bluetooth_service_record_win.h"
 #include "device/bluetooth/bluetooth_socket_thread.h"
 #include "device/bluetooth/bluetooth_task_manager_win.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
diff --git a/device/bluetooth/bluetooth_discovery_filter.h b/device/bluetooth/bluetooth_discovery_filter.h
index 4fb3835a..5e41fd32 100644
--- a/device/bluetooth/bluetooth_discovery_filter.h
+++ b/device/bluetooth/bluetooth_discovery_filter.h
@@ -15,7 +15,7 @@
 #include "base/optional.h"
 #include "device/bluetooth/bluetooth_common.h"
 #include "device/bluetooth/bluetooth_export.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace device {
 
diff --git a/device/bluetooth/bluetooth_gatt_characteristic.h b/device/bluetooth/bluetooth_gatt_characteristic.h
index 89030bf..d430b79 100644
--- a/device/bluetooth/bluetooth_gatt_characteristic.h
+++ b/device/bluetooth/bluetooth_gatt_characteristic.h
@@ -13,7 +13,7 @@
 #include "base/macros.h"
 #include "device/bluetooth/bluetooth_export.h"
 #include "device/bluetooth/bluetooth_gatt_service.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace device {
 
diff --git a/device/bluetooth/bluetooth_gatt_descriptor.h b/device/bluetooth/bluetooth_gatt_descriptor.h
index 7442ff26..2d87792 100644
--- a/device/bluetooth/bluetooth_gatt_descriptor.h
+++ b/device/bluetooth/bluetooth_gatt_descriptor.h
@@ -13,7 +13,7 @@
 #include "device/bluetooth/bluetooth_export.h"
 #include "device/bluetooth/bluetooth_gatt_characteristic.h"
 #include "device/bluetooth/bluetooth_gatt_service.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace device {
 
diff --git a/device/bluetooth/bluetooth_gatt_service.h b/device/bluetooth/bluetooth_gatt_service.h
index 7e78b2b..8bb1d6f6 100644
--- a/device/bluetooth/bluetooth_gatt_service.h
+++ b/device/bluetooth/bluetooth_gatt_service.h
@@ -10,7 +10,7 @@
 #include "base/callback_forward.h"
 #include "base/macros.h"
 #include "device/bluetooth/bluetooth_export.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace device {
 
diff --git a/device/bluetooth/bluetooth_local_gatt_characteristic.h b/device/bluetooth/bluetooth_local_gatt_characteristic.h
index d573cac..200f1751 100644
--- a/device/bluetooth/bluetooth_local_gatt_characteristic.h
+++ b/device/bluetooth/bluetooth_local_gatt_characteristic.h
@@ -12,7 +12,7 @@
 #include "device/bluetooth/bluetooth_export.h"
 #include "device/bluetooth/bluetooth_gatt_characteristic.h"
 #include "device/bluetooth/bluetooth_local_gatt_service.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace device {
 
diff --git a/device/bluetooth/bluetooth_local_gatt_descriptor.h b/device/bluetooth/bluetooth_local_gatt_descriptor.h
index c339e36..6565764 100644
--- a/device/bluetooth/bluetooth_local_gatt_descriptor.h
+++ b/device/bluetooth/bluetooth_local_gatt_descriptor.h
@@ -12,7 +12,7 @@
 #include "device/bluetooth/bluetooth_export.h"
 #include "device/bluetooth/bluetooth_gatt_descriptor.h"
 #include "device/bluetooth/bluetooth_local_gatt_characteristic.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace device {
 
diff --git a/device/bluetooth/bluetooth_local_gatt_service.h b/device/bluetooth/bluetooth_local_gatt_service.h
index c374583..7e31355c 100644
--- a/device/bluetooth/bluetooth_local_gatt_service.h
+++ b/device/bluetooth/bluetooth_local_gatt_service.h
@@ -16,7 +16,7 @@
 #include "device/bluetooth/bluetooth_export.h"
 #include "device/bluetooth/bluetooth_gatt_characteristic.h"
 #include "device/bluetooth/bluetooth_gatt_service.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace device {
 
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic.h b/device/bluetooth/bluetooth_remote_gatt_characteristic.h
index 6e26850..f7ab17f 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic.h
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic.h
@@ -22,7 +22,7 @@
 #include "device/bluetooth/bluetooth_export.h"
 #include "device/bluetooth/bluetooth_gatt_characteristic.h"
 #include "device/bluetooth/bluetooth_remote_gatt_service.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace device {
 
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.cc b/device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.cc
index 334e26b2..c58f1a8 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.cc
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.cc
@@ -22,8 +22,8 @@
 #include "device/bluetooth/bluetooth_remote_gatt_descriptor_winrt.h"
 #include "device/bluetooth/bluetooth_remote_gatt_service.h"
 #include "device/bluetooth/bluetooth_remote_gatt_service_winrt.h"
-#include "device/bluetooth/bluetooth_uuid.h"
 #include "device/bluetooth/event_utils_winrt.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace device {
 
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.h b/device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.h
index b84862b1..4d45c4d 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.h
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.h
@@ -18,7 +18,7 @@
 #include "base/macros.h"
 #include "device/bluetooth/bluetooth_export.h"
 #include "device/bluetooth/bluetooth_remote_gatt_characteristic.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace device {
 
diff --git a/device/bluetooth/bluetooth_remote_gatt_descriptor.h b/device/bluetooth/bluetooth_remote_gatt_descriptor.h
index fa44324c..25f0d7f 100644
--- a/device/bluetooth/bluetooth_remote_gatt_descriptor.h
+++ b/device/bluetooth/bluetooth_remote_gatt_descriptor.h
@@ -13,7 +13,7 @@
 #include "base/macros.h"
 #include "device/bluetooth/bluetooth_export.h"
 #include "device/bluetooth/bluetooth_gatt_descriptor.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace device {
 
diff --git a/device/bluetooth/bluetooth_remote_gatt_descriptor_winrt.h b/device/bluetooth/bluetooth_remote_gatt_descriptor_winrt.h
index 9195387..e749c497 100644
--- a/device/bluetooth/bluetooth_remote_gatt_descriptor_winrt.h
+++ b/device/bluetooth/bluetooth_remote_gatt_descriptor_winrt.h
@@ -20,7 +20,7 @@
 #include "device/bluetooth/bluetooth_export.h"
 #include "device/bluetooth/bluetooth_remote_gatt_characteristic.h"
 #include "device/bluetooth/bluetooth_remote_gatt_descriptor.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace device {
 
diff --git a/device/bluetooth/bluetooth_remote_gatt_service.cc b/device/bluetooth/bluetooth_remote_gatt_service.cc
index 1441f58..9a026d5 100644
--- a/device/bluetooth/bluetooth_remote_gatt_service.cc
+++ b/device/bluetooth/bluetooth_remote_gatt_service.cc
@@ -7,7 +7,7 @@
 #include <utility>
 
 #include "device/bluetooth/bluetooth_remote_gatt_characteristic.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace device {
 
diff --git a/device/bluetooth/bluetooth_remote_gatt_service_android.h b/device/bluetooth/bluetooth_remote_gatt_service_android.h
index 5f76758..00242e92 100644
--- a/device/bluetooth/bluetooth_remote_gatt_service_android.h
+++ b/device/bluetooth/bluetooth_remote_gatt_service_android.h
@@ -14,7 +14,7 @@
 #include "base/android/scoped_java_ref.h"
 #include "base/macros.h"
 #include "device/bluetooth/bluetooth_remote_gatt_service.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace device {
 
diff --git a/device/bluetooth/bluetooth_remote_gatt_service_mac.mm b/device/bluetooth/bluetooth_remote_gatt_service_mac.mm
index a9db0c0..2038061 100644
--- a/device/bluetooth/bluetooth_remote_gatt_service_mac.mm
+++ b/device/bluetooth/bluetooth_remote_gatt_service_mac.mm
@@ -13,7 +13,7 @@
 #include "device/bluetooth/bluetooth_adapter_mac.h"
 #include "device/bluetooth/bluetooth_low_energy_device_mac.h"
 #include "device/bluetooth/bluetooth_remote_gatt_characteristic_mac.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace device {
 
diff --git a/device/bluetooth/bluetooth_remote_gatt_service_winrt.h b/device/bluetooth/bluetooth_remote_gatt_service_winrt.h
index e8ea154..4c887c3 100644
--- a/device/bluetooth/bluetooth_remote_gatt_service_winrt.h
+++ b/device/bluetooth/bluetooth_remote_gatt_service_winrt.h
@@ -18,7 +18,7 @@
 #include "device/bluetooth/bluetooth_export.h"
 #include "device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.h"
 #include "device/bluetooth/bluetooth_remote_gatt_service.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace device {
 
diff --git a/device/bluetooth/bluetooth_service_record_win.cc b/device/bluetooth/bluetooth_service_record_win.cc
index 2ed1323..1067128 100644
--- a/device/bluetooth/bluetooth_service_record_win.cc
+++ b/device/bluetooth/bluetooth_service_record_win.cc
@@ -11,7 +11,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "device/bluetooth/bluetooth_init_win.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace {
 
diff --git a/device/bluetooth/bluetooth_service_record_win.h b/device/bluetooth/bluetooth_service_record_win.h
index b7662a2..4c220d1 100644
--- a/device/bluetooth/bluetooth_service_record_win.h
+++ b/device/bluetooth/bluetooth_service_record_win.h
@@ -13,7 +13,7 @@
 #include "base/macros.h"
 #include "device/bluetooth/bluetooth_export.h"
 #include "device/bluetooth/bluetooth_init_win.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace device {
 
diff --git a/device/bluetooth/bluetooth_service_record_win_unittest.cc b/device/bluetooth/bluetooth_service_record_win_unittest.cc
index 59d6c89..c0b5c4e 100644
--- a/device/bluetooth/bluetooth_service_record_win_unittest.cc
+++ b/device/bluetooth/bluetooth_service_record_win_unittest.cc
@@ -6,7 +6,7 @@
 
 #include "base/strings/string_number_conversions.h"
 #include "device/bluetooth/bluetooth_service_record_win.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
diff --git a/device/bluetooth/bluetooth_socket_mac.h b/device/bluetooth/bluetooth_socket_mac.h
index 3ff49094..c50560c 100644
--- a/device/bluetooth/bluetooth_socket_mac.h
+++ b/device/bluetooth/bluetooth_socket_mac.h
@@ -19,7 +19,7 @@
 #include "base/threading/thread_checker.h"
 #include "device/bluetooth/bluetooth_adapter.h"
 #include "device/bluetooth/bluetooth_socket.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 @class BluetoothRfcommConnectionListener;
 @class BluetoothL2capConnectionListener;
diff --git a/device/bluetooth/bluetooth_socket_win.h b/device/bluetooth/bluetooth_socket_win.h
index 42985b8..7a9aada 100644
--- a/device/bluetooth/bluetooth_socket_win.h
+++ b/device/bluetooth/bluetooth_socket_win.h
@@ -18,7 +18,7 @@
 #include "device/bluetooth/bluetooth_service_record_win.h"
 #include "device/bluetooth/bluetooth_socket.h"
 #include "device/bluetooth/bluetooth_socket_net.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "net/base/ip_endpoint.h"
 #include "net/socket/tcp_socket.h"
 
diff --git a/device/bluetooth/bluez/bluetooth_adapter_bluez.cc b/device/bluetooth/bluez/bluetooth_adapter_bluez.cc
index e3a6beef..990703eb 100644
--- a/device/bluetooth/bluez/bluetooth_adapter_bluez.cc
+++ b/device/bluetooth/bluez/bluetooth_adapter_bluez.cc
@@ -29,7 +29,6 @@
 #include "device/bluetooth/bluetooth_device.h"
 #include "device/bluetooth/bluetooth_discovery_session_outcome.h"
 #include "device/bluetooth/bluetooth_socket_thread.h"
-#include "device/bluetooth/bluetooth_uuid.h"
 #include "device/bluetooth/bluez/bluetooth_adapter_profile_bluez.h"
 #include "device/bluetooth/bluez/bluetooth_advertisement_bluez.h"
 #include "device/bluetooth/bluez/bluetooth_device_bluez.h"
@@ -47,6 +46,7 @@
 #include "device/bluetooth/dbus/bluetooth_input_client.h"
 #include "device/bluetooth/dbus/bluetooth_le_advertising_manager_client.h"
 #include "device/bluetooth/dbus/bluez_dbus_manager.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 
 #if defined(OS_CHROMEOS)
diff --git a/device/bluetooth/bluez/bluetooth_adapter_profile_bluez.cc b/device/bluetooth/bluez/bluetooth_adapter_profile_bluez.cc
index 5c24f2a..adc8038 100644
--- a/device/bluetooth/bluez/bluetooth_adapter_profile_bluez.cc
+++ b/device/bluetooth/bluez/bluetooth_adapter_profile_bluez.cc
@@ -13,10 +13,10 @@
 #include "base/strings/string_util.h"
 #include "dbus/bus.h"
 #include "dbus/object_path.h"
-#include "device/bluetooth/bluetooth_uuid.h"
 #include "device/bluetooth/bluez/bluetooth_adapter_bluez.h"
 #include "device/bluetooth/dbus/bluetooth_profile_service_provider.h"
 #include "device/bluetooth/dbus/bluez_dbus_manager.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace bluez {
 
diff --git a/device/bluetooth/bluez/bluetooth_adapter_profile_bluez_unittest.cc b/device/bluetooth/bluez/bluetooth_adapter_profile_bluez_unittest.cc
index cbf8630..b799ffd 100644
--- a/device/bluetooth/bluez/bluetooth_adapter_profile_bluez_unittest.cc
+++ b/device/bluetooth/bluez/bluetooth_adapter_profile_bluez_unittest.cc
@@ -12,7 +12,6 @@
 #include "base/test/scoped_task_environment.h"
 #include "device/bluetooth/bluetooth_adapter.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
-#include "device/bluetooth/bluetooth_uuid.h"
 #include "device/bluetooth/bluez/bluetooth_adapter_bluez.h"
 #include "device/bluetooth/dbus/bluetooth_profile_service_provider.h"
 #include "device/bluetooth/dbus/bluez_dbus_manager.h"
@@ -20,6 +19,7 @@
 #include "device/bluetooth/dbus/fake_bluetooth_agent_manager_client.h"
 #include "device/bluetooth/dbus/fake_bluetooth_device_client.h"
 #include "device/bluetooth/dbus/fake_bluetooth_profile_manager_client.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using device::BluetoothAdapter;
diff --git a/device/bluetooth/bluez/bluetooth_device_bluez.cc b/device/bluetooth/bluez/bluetooth_device_bluez.cc
index 935d626..f7002ed0 100644
--- a/device/bluetooth/bluez/bluetooth_device_bluez.cc
+++ b/device/bluetooth/bluez/bluetooth_device_bluez.cc
@@ -20,7 +20,6 @@
 #include "dbus/bus.h"
 #include "device/bluetooth/bluetooth_socket.h"
 #include "device/bluetooth/bluetooth_socket_thread.h"
-#include "device/bluetooth/bluetooth_uuid.h"
 #include "device/bluetooth/bluez/bluetooth_adapter_bluez.h"
 #include "device/bluetooth/bluez/bluetooth_gatt_connection_bluez.h"
 #include "device/bluetooth/bluez/bluetooth_pairing_bluez.h"
@@ -32,6 +31,7 @@
 #include "device/bluetooth/dbus/bluetooth_gatt_service_client.h"
 #include "device/bluetooth/dbus/bluetooth_input_client.h"
 #include "device/bluetooth/dbus/bluez_dbus_manager.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 
 using device::BluetoothDevice;
diff --git a/device/bluetooth/bluez/bluetooth_gatt_bluez_unittest.cc b/device/bluetooth/bluez/bluetooth_gatt_bluez_unittest.cc
index 484351b..078ea5a 100644
--- a/device/bluetooth/bluez/bluetooth_gatt_bluez_unittest.cc
+++ b/device/bluetooth/bluez/bluetooth_gatt_bluez_unittest.cc
@@ -25,7 +25,6 @@
 #include "device/bluetooth/bluetooth_remote_gatt_characteristic.h"
 #include "device/bluetooth/bluetooth_remote_gatt_descriptor.h"
 #include "device/bluetooth/bluetooth_remote_gatt_service.h"
-#include "device/bluetooth/bluetooth_uuid.h"
 #include "device/bluetooth/bluez/bluetooth_device_bluez.h"
 #include "device/bluetooth/dbus/bluez_dbus_manager.h"
 #include "device/bluetooth/dbus/fake_bluetooth_adapter_client.h"
@@ -35,6 +34,7 @@
 #include "device/bluetooth/dbus/fake_bluetooth_gatt_descriptor_client.h"
 #include "device/bluetooth/dbus/fake_bluetooth_gatt_service_client.h"
 #include "device/bluetooth/dbus/fake_bluetooth_input_client.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "device/bluetooth/test/test_bluetooth_adapter_observer.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/device/bluetooth/bluez/bluetooth_local_gatt_characteristic_bluez.h b/device/bluetooth/bluez/bluetooth_local_gatt_characteristic_bluez.h
index 5566c80..6f70019 100644
--- a/device/bluetooth/bluez/bluetooth_local_gatt_characteristic_bluez.h
+++ b/device/bluetooth/bluez/bluetooth_local_gatt_characteristic_bluez.h
@@ -12,9 +12,9 @@
 #include "base/memory/weak_ptr.h"
 #include "device/bluetooth/bluetooth_gatt_characteristic.h"
 #include "device/bluetooth/bluetooth_local_gatt_characteristic.h"
-#include "device/bluetooth/bluetooth_uuid.h"
 #include "device/bluetooth/bluez/bluetooth_gatt_characteristic_bluez.h"
 #include "device/bluetooth/bluez/bluetooth_local_gatt_descriptor_bluez.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace bluez {
 
diff --git a/device/bluetooth/bluez/bluetooth_local_gatt_descriptor_bluez.h b/device/bluetooth/bluez/bluetooth_local_gatt_descriptor_bluez.h
index c5a68b6..1cd0b35 100644
--- a/device/bluetooth/bluez/bluetooth_local_gatt_descriptor_bluez.h
+++ b/device/bluetooth/bluez/bluetooth_local_gatt_descriptor_bluez.h
@@ -9,8 +9,8 @@
 #include "base/memory/weak_ptr.h"
 #include "device/bluetooth/bluetooth_local_gatt_characteristic.h"
 #include "device/bluetooth/bluetooth_local_gatt_descriptor.h"
-#include "device/bluetooth/bluetooth_uuid.h"
 #include "device/bluetooth/bluez/bluetooth_gatt_descriptor_bluez.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace bluez {
 
diff --git a/device/bluetooth/bluez/bluetooth_local_gatt_service_bluez.h b/device/bluetooth/bluez/bluetooth_local_gatt_service_bluez.h
index bcb72df..1fdc972 100644
--- a/device/bluetooth/bluez/bluetooth_local_gatt_service_bluez.h
+++ b/device/bluetooth/bluez/bluetooth_local_gatt_service_bluez.h
@@ -12,9 +12,9 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "device/bluetooth/bluetooth_local_gatt_service.h"
-#include "device/bluetooth/bluetooth_uuid.h"
 #include "device/bluetooth/bluez/bluetooth_gatt_service_bluez.h"
 #include "device/bluetooth/bluez/bluetooth_local_gatt_characteristic_bluez.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace bluez {
 
diff --git a/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.h b/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.h
index 2e4d7f8..2259b46 100644
--- a/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.h
+++ b/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.h
@@ -20,9 +20,9 @@
 #include "dbus/object_path.h"
 #include "device/bluetooth/bluetooth_remote_gatt_characteristic.h"
 #include "device/bluetooth/bluetooth_remote_gatt_service.h"
-#include "device/bluetooth/bluetooth_uuid.h"
 #include "device/bluetooth/bluez/bluetooth_gatt_characteristic_bluez.h"
 #include "device/bluetooth/dbus/bluetooth_gatt_descriptor_client.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace device {
 
diff --git a/device/bluetooth/bluez/bluetooth_remote_gatt_descriptor_bluez.h b/device/bluetooth/bluez/bluetooth_remote_gatt_descriptor_bluez.h
index 4242501..6b4f4766 100644
--- a/device/bluetooth/bluez/bluetooth_remote_gatt_descriptor_bluez.h
+++ b/device/bluetooth/bluez/bluetooth_remote_gatt_descriptor_bluez.h
@@ -15,9 +15,9 @@
 #include "dbus/object_path.h"
 #include "device/bluetooth/bluetooth_remote_gatt_characteristic.h"
 #include "device/bluetooth/bluetooth_remote_gatt_descriptor.h"
-#include "device/bluetooth/bluetooth_uuid.h"
 #include "device/bluetooth/bluez/bluetooth_gatt_descriptor_bluez.h"
 #include "device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace bluez {
 
diff --git a/device/bluetooth/bluez/bluetooth_remote_gatt_service_bluez.h b/device/bluetooth/bluez/bluetooth_remote_gatt_service_bluez.h
index b192ead..d3b7753d 100644
--- a/device/bluetooth/bluez/bluetooth_remote_gatt_service_bluez.h
+++ b/device/bluetooth/bluez/bluetooth_remote_gatt_service_bluez.h
@@ -15,10 +15,10 @@
 #include "base/memory/weak_ptr.h"
 #include "dbus/object_path.h"
 #include "device/bluetooth/bluetooth_remote_gatt_service.h"
-#include "device/bluetooth/bluetooth_uuid.h"
 #include "device/bluetooth/bluez/bluetooth_gatt_service_bluez.h"
 #include "device/bluetooth/dbus/bluetooth_gatt_characteristic_client.h"
 #include "device/bluetooth/dbus/bluetooth_gatt_service_client.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace device {
 
diff --git a/device/bluetooth/bluez/bluetooth_socket_bluez.h b/device/bluetooth/bluez/bluetooth_socket_bluez.h
index 327a7e9..ef3e3454 100644
--- a/device/bluetooth/bluez/bluetooth_socket_bluez.h
+++ b/device/bluetooth/bluez/bluetooth_socket_bluez.h
@@ -16,9 +16,9 @@
 #include "device/bluetooth/bluetooth_export.h"
 #include "device/bluetooth/bluetooth_socket.h"
 #include "device/bluetooth/bluetooth_socket_net.h"
-#include "device/bluetooth/bluetooth_uuid.h"
 #include "device/bluetooth/dbus/bluetooth_profile_manager_client.h"
 #include "device/bluetooth/dbus/bluetooth_profile_service_provider.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace bluez {
 
diff --git a/device/bluetooth/bluez/bluetooth_socket_bluez_unittest.cc b/device/bluetooth/bluez/bluetooth_socket_bluez_unittest.cc
index eb5df55..d210a27 100644
--- a/device/bluetooth/bluez/bluetooth_socket_bluez_unittest.cc
+++ b/device/bluetooth/bluez/bluetooth_socket_bluez_unittest.cc
@@ -16,7 +16,6 @@
 #include "device/bluetooth/bluetooth_device.h"
 #include "device/bluetooth/bluetooth_socket.h"
 #include "device/bluetooth/bluetooth_socket_thread.h"
-#include "device/bluetooth/bluetooth_uuid.h"
 #include "device/bluetooth/bluez/bluetooth_adapter_bluez.h"
 #include "device/bluetooth/bluez/bluetooth_device_bluez.h"
 #include "device/bluetooth/dbus/bluez_dbus_manager.h"
@@ -27,6 +26,7 @@
 #include "device/bluetooth/dbus/fake_bluetooth_input_client.h"
 #include "device/bluetooth/dbus/fake_bluetooth_profile_manager_client.h"
 #include "device/bluetooth/dbus/fake_bluetooth_profile_service_provider.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/device/bluetooth/cast/bluetooth_device_cast.h b/device/bluetooth/cast/bluetooth_device_cast.h
index 5adb9144..05bb497 100644
--- a/device/bluetooth/cast/bluetooth_device_cast.h
+++ b/device/bluetooth/cast/bluetooth_device_cast.h
@@ -25,7 +25,7 @@
 #include "chromecast/device/bluetooth/le/remote_device.h"
 #include "device/bluetooth/bluetooth_device.h"
 #include "device/bluetooth/bluetooth_remote_gatt_service.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace device {
 
diff --git a/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.cc b/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.cc
index 8f8e25f..83cdc28 100644
--- a/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.cc
+++ b/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.cc
@@ -14,10 +14,10 @@
 #include "base/memory/weak_ptr.h"
 #include "chromecast/device/bluetooth/le/remote_characteristic.h"
 #include "chromecast/device/bluetooth/le/remote_descriptor.h"
-#include "device/bluetooth/bluetooth_uuid.h"
 #include "device/bluetooth/cast/bluetooth_remote_gatt_descriptor_cast.h"
 #include "device/bluetooth/cast/bluetooth_remote_gatt_service_cast.h"
 #include "device/bluetooth/cast/bluetooth_utils.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 namespace device {
 namespace {
diff --git a/device/bluetooth/cast/bluetooth_utils.h b/device/bluetooth/cast/bluetooth_utils.h
index 2b49a9b3..093bca9 100644
--- a/device/bluetooth/cast/bluetooth_utils.h
+++ b/device/bluetooth/cast/bluetooth_utils.h
@@ -9,7 +9,7 @@
 
 #include "chromecast/public/bluetooth/bluetooth_types.h"
 #include "device/bluetooth/bluetooth_export.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 // This file contains common utilities for implementing Chromium bluetooth
 // interfaces with the Cast Bluetooth stack.
diff --git a/device/bluetooth/dbus/bluetooth_gatt_application_service_provider.cc b/device/bluetooth/dbus/bluetooth_gatt_application_service_provider.cc
index dc344cd..6ccfcc27 100644
--- a/device/bluetooth/dbus/bluetooth_gatt_application_service_provider.cc
+++ b/device/bluetooth/dbus/bluetooth_gatt_application_service_provider.cc
@@ -9,13 +9,13 @@
 
 #include "base/memory/ptr_util.h"
 #include "device/bluetooth/bluetooth_gatt_characteristic.h"
-#include "device/bluetooth/bluetooth_uuid.h"
 #include "device/bluetooth/bluez/bluetooth_gatt_service_bluez.h"
 #include "device/bluetooth/dbus/bluetooth_gatt_application_service_provider_impl.h"
 #include "device/bluetooth/dbus/bluetooth_gatt_characteristic_delegate_wrapper.h"
 #include "device/bluetooth/dbus/bluetooth_gatt_descriptor_delegate_wrapper.h"
 #include "device/bluetooth/dbus/bluez_dbus_manager.h"
 #include "device/bluetooth/dbus/fake_bluetooth_gatt_application_service_provider.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 
 namespace bluez {
diff --git a/device/bluetooth/public/cpp/BUILD.gn b/device/bluetooth/public/cpp/BUILD.gn
new file mode 100644
index 0000000..03775b0
--- /dev/null
+++ b/device/bluetooth/public/cpp/BUILD.gn
@@ -0,0 +1,14 @@
+# 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.
+
+source_set("cpp") {
+  sources = [
+    "bluetooth_uuid.cc",
+    "bluetooth_uuid.h",
+  ]
+
+  deps = [
+    "//base",
+  ]
+}
diff --git a/device/bluetooth/bluetooth_uuid.cc b/device/bluetooth/public/cpp/bluetooth_uuid.cc
similarity index 96%
rename from device/bluetooth/bluetooth_uuid.cc
rename to device/bluetooth/public/cpp/bluetooth_uuid.cc
index 9680b6aa..c1afb39 100644
--- a/device/bluetooth/bluetooth_uuid.cc
+++ b/device/bluetooth/public/cpp/bluetooth_uuid.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 #include <stddef.h>
 
@@ -73,7 +73,6 @@
 
 }  // namespace
 
-
 BluetoothUUID::BluetoothUUID(const std::string& uuid) {
   GetCanonicalUuid(uuid, &value_, &canonical_value_, &format_);
 }
@@ -90,8 +89,7 @@
 }
 #endif  // defined(OS_WIN)
 
-BluetoothUUID::BluetoothUUID() : format_(kFormatInvalid) {
-}
+BluetoothUUID::BluetoothUUID() : format_(kFormatInvalid) {}
 
 BluetoothUUID::~BluetoothUUID() = default;
 
diff --git a/device/bluetooth/bluetooth_uuid.h b/device/bluetooth/public/cpp/bluetooth_uuid.h
similarity index 90%
rename from device/bluetooth/bluetooth_uuid.h
rename to device/bluetooth/public/cpp/bluetooth_uuid.h
index 36e21c0..2650490 100644
--- a/device/bluetooth/bluetooth_uuid.h
+++ b/device/bluetooth/public/cpp/bluetooth_uuid.h
@@ -2,13 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef DEVICE_BLUETOOTH_BLUETOOTH_UUID_H_
-#define DEVICE_BLUETOOTH_BLUETOOTH_UUID_H_
+#ifndef DEVICE_BLUETOOTH_PUBLIC_CPP_BLUETOOTH_UUID_H_
+#define DEVICE_BLUETOOTH_PUBLIC_CPP_BLUETOOTH_UUID_H_
 
 #include <string>
 
 #include "build/build_config.h"
-#include "device/bluetooth/bluetooth_export.h"
 
 #if defined(OS_WIN)
 #include <rpc.h>
@@ -23,15 +22,10 @@
 // used in Bluetooth based communication, such as a peripheral's services,
 // characteristics, and characteristic descriptors. An instance are
 // constructed using a string representing 16, 32, or 128 bit UUID formats.
-class DEVICE_BLUETOOTH_EXPORT BluetoothUUID {
+class BluetoothUUID {
  public:
   // Possible representation formats used during construction.
-  enum Format {
-    kFormatInvalid,
-    kFormat16Bit,
-    kFormat32Bit,
-    kFormat128Bit
-  };
+  enum Format { kFormatInvalid, kFormat16Bit, kFormat32Bit, kFormat128Bit };
 
   // Single argument constructor. |uuid| can be a 16, 32, or 128 bit UUID
   // represented as a 4, 8, or 36 character string with the following
@@ -110,8 +104,7 @@
 };
 
 // This is required by gtest to print a readable output on test failures.
-void DEVICE_BLUETOOTH_EXPORT
-PrintTo(const BluetoothUUID& uuid, std::ostream* out);
+void PrintTo(const BluetoothUUID& uuid, std::ostream* out);
 
 struct BluetoothUUIDHash {
   size_t operator()(const device::BluetoothUUID& uuid) const {
@@ -121,4 +114,4 @@
 
 }  // namespace device
 
-#endif  // DEVICE_BLUETOOTH_BLUETOOTH_UUID_H_
+#endif  // DEVICE_BLUETOOTH_PUBLIC_CPP_BLUETOOTH_UUID_H_
diff --git a/device/bluetooth/bluetooth_uuid_unittest.cc b/device/bluetooth/public/cpp/bluetooth_uuid_unittest.cc
similarity index 92%
rename from device/bluetooth/bluetooth_uuid_unittest.cc
rename to device/bluetooth/public/cpp/bluetooth_uuid_unittest.cc
index 4f89420..d52d6c2 100644
--- a/device/bluetooth/bluetooth_uuid_unittest.cc
+++ b/device/bluetooth/public/cpp/bluetooth_uuid_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 
 #include <stddef.h>
 
@@ -130,15 +130,15 @@
     const std::string input_uuid;
     const std::string expected_value;
   } test_cases[] = {
-    { "1abc", k16Bit },
-    { "1ABC", k16Bit },
-    { "1aBc", k16Bit },
-    { "00001abc", k32Bit },
-    { "00001ABC", k32Bit },
-    { "00001aBc", k32Bit },
-    { "00001abc-0000-1000-8000-00805f9b34fb", k128Bit },
-    { "00001ABC-0000-1000-8000-00805F9B34FB", k128Bit },
-    { "00001aBc-0000-1000-8000-00805F9b34fB", k128Bit },
+      {"1abc", k16Bit},
+      {"1ABC", k16Bit},
+      {"1aBc", k16Bit},
+      {"00001abc", k32Bit},
+      {"00001ABC", k32Bit},
+      {"00001aBc", k32Bit},
+      {"00001abc-0000-1000-8000-00805f9b34fb", k128Bit},
+      {"00001ABC-0000-1000-8000-00805F9B34FB", k128Bit},
+      {"00001aBc-0000-1000-8000-00805F9b34fB", k128Bit},
   };
 
   for (size_t i = 0; i < base::size(test_cases); ++i) {
diff --git a/device/bluetooth/public/mojom/uuid.typemap b/device/bluetooth/public/mojom/uuid.typemap
index 258208f8..304864167 100644
--- a/device/bluetooth/public/mojom/uuid.typemap
+++ b/device/bluetooth/public/mojom/uuid.typemap
@@ -3,9 +3,9 @@
 # found in the LICENSE file.
 
 mojom = "//device/bluetooth/public/mojom/uuid.mojom"
-public_headers = [ "//device/bluetooth/bluetooth_uuid.h" ]
+public_headers = [ "//device/bluetooth/public/cpp/bluetooth_uuid.h" ]
 traits_headers = [ "//device/bluetooth/public/mojom/uuid_mojom_traits.h" ]
 deps = [
-  "//device/bluetooth",
+  "//device/bluetooth/public/cpp",
 ]
 type_mappings = [ "bluetooth.mojom.UUID=device::BluetoothUUID" ]
diff --git a/device/bluetooth/public/mojom/uuid_mojom_traits.h b/device/bluetooth/public/mojom/uuid_mojom_traits.h
index c9d565a..1810976 100644
--- a/device/bluetooth/public/mojom/uuid_mojom_traits.h
+++ b/device/bluetooth/public/mojom/uuid_mojom_traits.h
@@ -7,7 +7,7 @@
 
 #include <string>
 
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "device/bluetooth/public/mojom/uuid.mojom.h"
 
 namespace mojo {
diff --git a/device/bluetooth/test/bluetooth_gatt_server_test.cc b/device/bluetooth/test/bluetooth_gatt_server_test.cc
index 71ab01c3..d79111c 100644
--- a/device/bluetooth/test/bluetooth_gatt_server_test.cc
+++ b/device/bluetooth/test/bluetooth_gatt_server_test.cc
@@ -7,7 +7,7 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "device/bluetooth/test/bluetooth_test.h"
 
 namespace device {
diff --git a/device/bluetooth/test/bluetooth_test_win.cc b/device/bluetooth/test/bluetooth_test_win.cc
index b697f17..7c4c1b6 100644
--- a/device/bluetooth/test/bluetooth_test_win.cc
+++ b/device/bluetooth/test/bluetooth_test_win.cc
@@ -36,7 +36,7 @@
 #include "device/bluetooth/bluetooth_remote_gatt_descriptor_win.h"
 #include "device/bluetooth/bluetooth_remote_gatt_descriptor_winrt.h"
 #include "device/bluetooth/bluetooth_remote_gatt_service_win.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "device/bluetooth/test/fake_bluetooth_adapter_winrt.h"
 #include "device/bluetooth/test/fake_bluetooth_le_advertisement_publisher_winrt.h"
 #include "device/bluetooth/test/fake_bluetooth_le_advertisement_watcher_winrt.h"
diff --git a/device/bluetooth/test/fake_central.cc b/device/bluetooth/test/fake_central.cc
index 9e3b6c0..f9973ec 100644
--- a/device/bluetooth/test/fake_central.cc
+++ b/device/bluetooth/test/fake_central.cc
@@ -15,7 +15,7 @@
 #include "device/bluetooth/bluetooth_device.h"
 #include "device/bluetooth/bluetooth_discovery_filter.h"
 #include "device/bluetooth/bluetooth_discovery_session_outcome.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "device/bluetooth/public/mojom/test/fake_bluetooth.mojom.h"
 #include "device/bluetooth/test/fake_peripheral.h"
 #include "device/bluetooth/test/fake_remote_gatt_characteristic.h"
diff --git a/device/bluetooth/test/fake_gatt_characteristic_winrt.cc b/device/bluetooth/test/fake_gatt_characteristic_winrt.cc
index 9f433944..47a5822 100644
--- a/device/bluetooth/test/fake_gatt_characteristic_winrt.cc
+++ b/device/bluetooth/test/fake_gatt_characteristic_winrt.cc
@@ -12,7 +12,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/win/async_operation.h"
 #include "base/win/winrt_storage_util.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "device/bluetooth/test/bluetooth_test_win.h"
 #include "device/bluetooth/test/fake_gatt_descriptor_winrt.h"
 #include "device/bluetooth/test/fake_gatt_descriptors_result_winrt.h"
diff --git a/device/bluetooth/test/fake_gatt_descriptor_winrt.cc b/device/bluetooth/test/fake_gatt_descriptor_winrt.cc
index fb8da37..1518516 100644
--- a/device/bluetooth/test/fake_gatt_descriptor_winrt.cc
+++ b/device/bluetooth/test/fake_gatt_descriptor_winrt.cc
@@ -9,7 +9,7 @@
 #include "base/strings/string_piece.h"
 #include "base/win/async_operation.h"
 #include "base/win/winrt_storage_util.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "device/bluetooth/test/bluetooth_test_win.h"
 #include "device/bluetooth/test/fake_gatt_read_result_winrt.h"
 #include "device/bluetooth/test/fake_gatt_write_result_winrt.h"
diff --git a/device/bluetooth/test/fake_gatt_device_service_winrt.cc b/device/bluetooth/test/fake_gatt_device_service_winrt.cc
index f5c0569..50e2f63 100644
--- a/device/bluetooth/test/fake_gatt_device_service_winrt.cc
+++ b/device/bluetooth/test/fake_gatt_device_service_winrt.cc
@@ -14,7 +14,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/win/async_operation.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "device/bluetooth/test/fake_bluetooth_le_device_winrt.h"
 #include "device/bluetooth/test/fake_gatt_characteristic_winrt.h"
 #include "device/bluetooth/test/fake_gatt_characteristics_result_winrt.h"
diff --git a/device/bluetooth/test/fake_peripheral.cc b/device/bluetooth/test/fake_peripheral.cc
index d9305f3..c0838d2 100644
--- a/device/bluetooth/test/fake_peripheral.cc
+++ b/device/bluetooth/test/fake_peripheral.cc
@@ -12,7 +12,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "device/bluetooth/test/fake_remote_gatt_service.h"
 
 namespace bluetooth {
diff --git a/device/bluetooth/test/fake_remote_gatt_characteristic.cc b/device/bluetooth/test/fake_remote_gatt_characteristic.cc
index 3f4eb2a..bc0c159 100644
--- a/device/bluetooth/test/fake_remote_gatt_characteristic.cc
+++ b/device/bluetooth/test/fake_remote_gatt_characteristic.cc
@@ -10,7 +10,7 @@
 #include "base/bind.h"
 #include "base/optional.h"
 #include "base/strings/stringprintf.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "device/bluetooth/public/mojom/test/fake_bluetooth.mojom.h"
 #include "device/bluetooth/test/fake_read_response.h"
 
diff --git a/device/bluetooth/test/fake_remote_gatt_characteristic.h b/device/bluetooth/test/fake_remote_gatt_characteristic.h
index 8dc91e0..2d1f41b 100644
--- a/device/bluetooth/test/fake_remote_gatt_characteristic.h
+++ b/device/bluetooth/test/fake_remote_gatt_characteristic.h
@@ -11,7 +11,7 @@
 
 #include "base/memory/weak_ptr.h"
 #include "device/bluetooth/bluetooth_remote_gatt_characteristic.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "device/bluetooth/public/mojom/test/fake_bluetooth.mojom.h"
 #include "device/bluetooth/test/fake_read_response.h"
 #include "device/bluetooth/test/fake_remote_gatt_descriptor.h"
diff --git a/device/bluetooth/test/fake_remote_gatt_descriptor.h b/device/bluetooth/test/fake_remote_gatt_descriptor.h
index 0ef5ed5..3a997a5 100644
--- a/device/bluetooth/test/fake_remote_gatt_descriptor.h
+++ b/device/bluetooth/test/fake_remote_gatt_descriptor.h
@@ -11,7 +11,7 @@
 #include "base/optional.h"
 #include "device/bluetooth/bluetooth_remote_gatt_characteristic.h"
 #include "device/bluetooth/bluetooth_remote_gatt_descriptor.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "device/bluetooth/test/fake_read_response.h"
 
 namespace bluetooth {
diff --git a/device/bluetooth/test/fake_remote_gatt_service.cc b/device/bluetooth/test/fake_remote_gatt_service.cc
index 9ec5c67..91d725c 100644
--- a/device/bluetooth/test/fake_remote_gatt_service.cc
+++ b/device/bluetooth/test/fake_remote_gatt_service.cc
@@ -12,7 +12,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/strings/stringprintf.h"
 #include "device/bluetooth/bluetooth_device.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "device/bluetooth/public/mojom/test/fake_bluetooth.mojom.h"
 #include "device/bluetooth/test/fake_remote_gatt_characteristic.h"
 
diff --git a/device/bluetooth/test/fake_remote_gatt_service.h b/device/bluetooth/test/fake_remote_gatt_service.h
index 97ad98e..8367927 100644
--- a/device/bluetooth/test/fake_remote_gatt_service.h
+++ b/device/bluetooth/test/fake_remote_gatt_service.h
@@ -10,7 +10,7 @@
 #include <vector>
 
 #include "device/bluetooth/bluetooth_remote_gatt_service.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "device/bluetooth/public/mojom/test/fake_bluetooth.mojom.h"
 #include "device/bluetooth/test/fake_remote_gatt_characteristic.h"
 
diff --git a/device/bluetooth/test/mock_bluetooth_device.h b/device/bluetooth/test/mock_bluetooth_device.h
index 50823e7..e75471eb 100644
--- a/device/bluetooth/test/mock_bluetooth_device.h
+++ b/device/bluetooth/test/mock_bluetooth_device.h
@@ -16,7 +16,7 @@
 #include "base/strings/string16.h"
 #include "device/bluetooth/bluetooth_common.h"
 #include "device/bluetooth/bluetooth_device.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "device/bluetooth/test/mock_bluetooth_gatt_service.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
diff --git a/device/bluetooth/test/mock_bluetooth_gatt_characteristic.h b/device/bluetooth/test/mock_bluetooth_gatt_characteristic.h
index a521b62..7838e19b 100644
--- a/device/bluetooth/test/mock_bluetooth_gatt_characteristic.h
+++ b/device/bluetooth/test/mock_bluetooth_gatt_characteristic.h
@@ -16,7 +16,7 @@
 #include "base/macros.h"
 #include "device/bluetooth/bluetooth_remote_gatt_characteristic.h"
 #include "device/bluetooth/bluetooth_remote_gatt_descriptor.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace device {
diff --git a/device/bluetooth/test/mock_bluetooth_gatt_descriptor.h b/device/bluetooth/test/mock_bluetooth_gatt_descriptor.h
index 565b108..b4216f9 100644
--- a/device/bluetooth/test/mock_bluetooth_gatt_descriptor.h
+++ b/device/bluetooth/test/mock_bluetooth_gatt_descriptor.h
@@ -14,7 +14,7 @@
 #include "base/macros.h"
 #include "device/bluetooth/bluetooth_remote_gatt_characteristic.h"
 #include "device/bluetooth/bluetooth_remote_gatt_descriptor.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace device {
diff --git a/device/bluetooth/test/mock_bluetooth_gatt_service.h b/device/bluetooth/test/mock_bluetooth_gatt_service.h
index 5c0c424e..f5c5921c 100644
--- a/device/bluetooth/test/mock_bluetooth_gatt_service.h
+++ b/device/bluetooth/test/mock_bluetooth_gatt_service.h
@@ -11,7 +11,7 @@
 
 #include "base/macros.h"
 #include "device/bluetooth/bluetooth_remote_gatt_service.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "device/bluetooth/test/mock_bluetooth_gatt_characteristic.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
diff --git a/device/bluetooth/test/mock_bluetooth_socket.h b/device/bluetooth/test/mock_bluetooth_socket.h
index 518123dc..3e6c57f 100644
--- a/device/bluetooth/test/mock_bluetooth_socket.h
+++ b/device/bluetooth/test/mock_bluetooth_socket.h
@@ -8,7 +8,7 @@
 #include <string>
 
 #include "device/bluetooth/bluetooth_socket.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "net/base/io_buffer.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
diff --git a/device/fido/BUILD.gn b/device/fido/BUILD.gn
index 7825ad0..e8c4026 100644
--- a/device/fido/BUILD.gn
+++ b/device/fido/BUILD.gn
@@ -166,6 +166,7 @@
   public_deps = [
     "//base",
     "//device/bluetooth",
+    "//device/bluetooth/public/cpp",
     "//services/device/public/mojom",
   ]
 
diff --git a/device/fido/ble/fido_ble_connection.cc b/device/fido/ble/fido_ble_connection.cc
index 96b73ac3..23dadd9 100644
--- a/device/fido/ble/fido_ble_connection.cc
+++ b/device/fido/ble/fido_ble_connection.cc
@@ -20,7 +20,7 @@
 #include "device/bluetooth/bluetooth_gatt_notify_session.h"
 #include "device/bluetooth/bluetooth_remote_gatt_characteristic.h"
 #include "device/bluetooth/bluetooth_remote_gatt_service.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "device/fido/ble/fido_ble_uuids.h"
 
 namespace device {
diff --git a/device/fido/ble/fido_ble_device.cc b/device/fido/ble/fido_ble_device.cc
index 7a77188..9d08912 100644
--- a/device/fido/ble/fido_ble_device.cc
+++ b/device/fido/ble/fido_ble_device.cc
@@ -12,7 +12,7 @@
 #include "base/strings/string_piece.h"
 #include "components/apdu/apdu_response.h"
 #include "components/device_event_log/device_event_log.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "device/fido/ble/fido_ble_frames.h"
 #include "device/fido/ble/fido_ble_uuids.h"
 #include "device/fido/fido_constants.h"
diff --git a/device/fido/ble/fido_ble_discovery.cc b/device/fido/ble/fido_ble_discovery.cc
index de7cc60..996805709 100644
--- a/device/fido/ble/fido_ble_discovery.cc
+++ b/device/fido/ble/fido_ble_discovery.cc
@@ -13,7 +13,7 @@
 #include "device/bluetooth/bluetooth_adapter.h"
 #include "device/bluetooth/bluetooth_common.h"
 #include "device/bluetooth/bluetooth_discovery_session.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "device/fido/ble/fido_ble_device.h"
 #include "device/fido/ble/fido_ble_uuids.h"
 #include "device/fido/fido_authenticator.h"
diff --git a/device/fido/ble/fido_ble_discovery_base.h b/device/fido/ble/fido_ble_discovery_base.h
index c8885d7..42e6aa6 100644
--- a/device/fido/ble/fido_ble_discovery_base.h
+++ b/device/fido/ble/fido_ble_discovery_base.h
@@ -12,7 +12,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "device/bluetooth/bluetooth_adapter.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "device/fido/fido_device_discovery.h"
 
 namespace device {
diff --git a/device/fido/cable/fido_cable_discovery.cc b/device/fido/cable/fido_cable_discovery.cc
index 645850a..48e1b55 100644
--- a/device/fido/cable/fido_cable_discovery.cc
+++ b/device/fido/cable/fido_cable_discovery.cc
@@ -18,7 +18,7 @@
 #include "components/device_event_log/device_event_log.h"
 #include "device/bluetooth/bluetooth_advertisement.h"
 #include "device/bluetooth/bluetooth_discovery_session.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "device/fido/ble/fido_ble_uuids.h"
 #include "device/fido/cable/fido_cable_device.h"
 #include "device/fido/cable/fido_cable_handshake_handler.h"
diff --git a/extensions/browser/api/bluetooth/bluetooth_apitest.cc b/extensions/browser/api/bluetooth/bluetooth_apitest.cc
index 2e527a9..656ae18 100644
--- a/extensions/browser/api/bluetooth/bluetooth_apitest.cc
+++ b/extensions/browser/api/bluetooth/bluetooth_apitest.cc
@@ -11,7 +11,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "device/bluetooth/bluetooth_adapter.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
 #include "device/bluetooth/test/mock_bluetooth_device.h"
 #include "extensions/browser/api/bluetooth/bluetooth_api.h"
diff --git a/extensions/browser/api/bluetooth/bluetooth_event_router_unittest.cc b/extensions/browser/api/bluetooth/bluetooth_event_router_unittest.cc
index f269276..5b61182 100644
--- a/extensions/browser/api/bluetooth/bluetooth_event_router_unittest.cc
+++ b/extensions/browser/api/bluetooth/bluetooth_event_router_unittest.cc
@@ -13,7 +13,7 @@
 #include "base/run_loop.h"
 #include "content/public/test/test_browser_context.h"
 #include "device/bluetooth/bluetooth_common.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
 #include "extensions/browser/event_router.h"
 #include "extensions/browser/extension_registry.h"
diff --git a/extensions/browser/api/bluetooth_low_energy/BUILD.gn b/extensions/browser/api/bluetooth_low_energy/BUILD.gn
index 2370edaf..3f392b0f 100644
--- a/extensions/browser/api/bluetooth_low_energy/BUILD.gn
+++ b/extensions/browser/api/bluetooth_low_energy/BUILD.gn
@@ -30,6 +30,7 @@
 
   deps = [
     "//device/bluetooth",
+    "//device/bluetooth/public/cpp",
     "//extensions/common/api",
   ]
 
diff --git a/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.cc b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.cc
index adbe0ca..2d4cf40 100644
--- a/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.cc
+++ b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.cc
@@ -26,7 +26,7 @@
 #include "device/bluetooth/bluetooth_local_gatt_characteristic.h"
 #include "device/bluetooth/bluetooth_local_gatt_descriptor.h"
 #include "device/bluetooth/bluetooth_local_gatt_service.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "extensions/browser/api/bluetooth_low_energy/utils.h"
 #include "extensions/browser/api/extensions_api_client.h"
 #include "extensions/browser/kiosk/kiosk_delegate.h"
diff --git a/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h
index 26b7c4bb..917a21f 100644
--- a/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h
+++ b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h
@@ -24,7 +24,7 @@
 #include "device/bluetooth/bluetooth_gatt_notify_session.h"
 #include "device/bluetooth/bluetooth_local_gatt_service.h"
 #include "device/bluetooth/bluetooth_remote_gatt_service.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "extensions/browser/extension_event_histogram_value.h"
 #include "extensions/browser/extension_registry_observer.h"
 #include "extensions/common/api/bluetooth_low_energy.h"
diff --git a/extensions/browser/api/bluetooth_socket/bluetooth_api_socket.h b/extensions/browser/api/bluetooth_socket/bluetooth_api_socket.h
index dbf68e1..31d566af 100644
--- a/extensions/browser/api/bluetooth_socket/bluetooth_api_socket.h
+++ b/extensions/browser/api/bluetooth_socket/bluetooth_api_socket.h
@@ -11,7 +11,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "device/bluetooth/bluetooth_device.h"
 #include "device/bluetooth/bluetooth_socket.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "extensions/browser/api/api_resource.h"
 #include "extensions/browser/api/api_resource_manager.h"
 
diff --git a/extensions/browser/api/bluetooth_socket/bluetooth_socket_apitest.cc b/extensions/browser/api/bluetooth_socket/bluetooth_socket_apitest.cc
index e22e225..724602cd 100644
--- a/extensions/browser/api/bluetooth_socket/bluetooth_socket_apitest.cc
+++ b/extensions/browser/api/bluetooth_socket/bluetooth_socket_apitest.cc
@@ -9,7 +9,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/run_loop.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
 #include "device/bluetooth/test/mock_bluetooth_device.h"
 #include "device/bluetooth/test/mock_bluetooth_socket.h"
diff --git a/extensions/common/api/bluetooth/bluetooth_manifest_permission.cc b/extensions/common/api/bluetooth/bluetooth_manifest_permission.cc
index 9758b850..b4abda7b 100644
--- a/extensions/common/api/bluetooth/bluetooth_manifest_permission.cc
+++ b/extensions/common/api/bluetooth/bluetooth_manifest_permission.cc
@@ -9,7 +9,7 @@
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
-#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "extensions/common/api/bluetooth/bluetooth_manifest_data.h"
 #include "extensions/common/api/extensions_manifest_types.h"
 #include "extensions/common/error_utils.h"
diff --git a/extensions/renderer/extension_frame_helper.cc b/extensions/renderer/extension_frame_helper.cc
index 4fc06c4..ad73948 100644
--- a/extensions/renderer/extension_frame_helper.cc
+++ b/extensions/renderer/extension_frame_helper.cc
@@ -233,31 +233,6 @@
     if (extension != GetExtensionFromFrame(target->render_frame()))
       continue;
 
-    // TODO(lukasza): https://crbug.com/764487: Investigate if we can further
-    // restrict scenarios that allow piercing of browsing instance boundaries.
-    // We hope that the piercing is only needed if the source or target frames
-    // are for background contents or background page.
-    ViewType target_view_type = target->view_type();
-    ViewType source_view_type =
-        ExtensionFrameHelper::Get(relative_to_frame)->view_type();
-    UMA_HISTOGRAM_ENUMERATION(
-        "Extensions.BrowsingInstanceViolation.ExtensionType",
-        extension->GetType(), Manifest::NUM_LOAD_TYPES);
-    UMA_HISTOGRAM_ENUMERATION(
-        "Extensions.BrowsingInstanceViolation.SourceExtensionViewType",
-        source_view_type, VIEW_TYPE_LAST + 1);
-    UMA_HISTOGRAM_ENUMERATION(
-        "Extensions.BrowsingInstanceViolation.TargetExtensionViewType",
-        target_view_type, VIEW_TYPE_LAST + 1);
-    bool is_background_source_or_target =
-        source_view_type == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE ||
-        source_view_type == VIEW_TYPE_BACKGROUND_CONTENTS ||
-        target_view_type == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE ||
-        target_view_type == VIEW_TYPE_BACKGROUND_CONTENTS;
-    UMA_HISTOGRAM_BOOLEAN(
-        "Extensions.BrowsingInstanceViolation.IsBackgroundSourceOrTarget",
-        is_background_source_or_target);
-
     return target->render_frame();
   }
 
diff --git a/gpu/command_buffer/service/webgpu_decoder_impl.cc b/gpu/command_buffer/service/webgpu_decoder_impl.cc
index d5a1901..fcd8aae8 100644
--- a/gpu/command_buffer/service/webgpu_decoder_impl.cc
+++ b/gpu/command_buffer/service/webgpu_decoder_impl.cc
@@ -585,8 +585,8 @@
   }
 
   static constexpr uint32_t kAllowedTextureUsages = static_cast<uint32_t>(
-      DAWN_TEXTURE_USAGE_BIT_TRANSFER_SRC |
-      DAWN_TEXTURE_USAGE_BIT_TRANSFER_DST | DAWN_TEXTURE_USAGE_BIT_SAMPLED |
+      DAWN_TEXTURE_USAGE_BIT_COPY_SRC | DAWN_TEXTURE_USAGE_BIT_COPY_DST |
+      DAWN_TEXTURE_USAGE_BIT_SAMPLED |
       DAWN_TEXTURE_USAGE_BIT_OUTPUT_ATTACHMENT);
   if (usage & ~kAllowedTextureUsages) {
     DLOG(ERROR) << "AssociateMailbox: Invalid usage";
diff --git a/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc b/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc
index c50ec507..de124e6 100644
--- a/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc
+++ b/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc
@@ -141,7 +141,7 @@
     webgpu()->FlushCommands();
 
     webgpu()->AssociateMailbox(0, 0, reservation.id, reservation.generation,
-                               DAWN_TEXTURE_USAGE_BIT_TRANSFER_SRC,
+                               DAWN_TEXTURE_USAGE_BIT_COPY_SRC,
                                reinterpret_cast<GLbyte*>(&mailbox));
     dawn::Texture texture = dawn::Texture::Acquire(reservation.texture);
 
@@ -149,13 +149,13 @@
     dawn::BufferDescriptor buffer_desc;
     buffer_desc.size = 4;
     buffer_desc.usage =
-        dawn::BufferUsageBit::MapRead | dawn::BufferUsageBit::TransferDst;
+        dawn::BufferUsageBit::MapRead | dawn::BufferUsageBit::CopyDst;
     dawn::Buffer readback_buffer = device.CreateBuffer(&buffer_desc);
 
     dawn::TextureCopyView copy_src;
     copy_src.texture = texture;
-    copy_src.level = 0;
-    copy_src.slice = 0;
+    copy_src.mipLevel = 0;
+    copy_src.arrayLayer = 0;
     copy_src.origin = {0, 0, 0};
 
     dawn::BufferCopyView copy_dst;
diff --git a/ios/chrome/app/application_delegate/metrics_mediator.mm b/ios/chrome/app/application_delegate/metrics_mediator.mm
index 41042f89..276e123 100644
--- a/ios/chrome/app/application_delegate/metrics_mediator.mm
+++ b/ios/chrome/app/application_delegate/metrics_mediator.mm
@@ -23,9 +23,9 @@
 #import "ios/chrome/browser/net/connection_type_observer_bridge.h"
 #include "ios/chrome/browser/pref_names.h"
 #include "ios/chrome/browser/system_flags.h"
-#import "ios/chrome/browser/tabs/tab.h"
 #import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/ui/main/browser_interface_provider.h"
+#import "ios/chrome/browser/web_state_list/web_state_list.h"
 #include "ios/chrome/common/app_group/app_group_metrics_mainapp.h"
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #include "ios/public/provider/chrome/browser/distribution/app_distribution_provider.h"
@@ -142,9 +142,10 @@
     [startupInformation
         activateFirstUserActionRecorderWithBackgroundTime:interval];
 
-    Tab* currentTab = interfaceProvider.currentInterface.tabModel.currentTab;
-    if (currentTab.webState &&
-        currentTab.webState->GetLastCommittedURL() == kChromeUINewTabURL) {
+    web::WebState* currentWebState = interfaceProvider.currentInterface.tabModel
+                                         .webStateList->GetActiveWebState();
+    if (currentWebState &&
+        currentWebState->GetLastCommittedURL() == kChromeUINewTabURL) {
       startupInformation.firstUserActionRecorder->RecordStartOnNTP();
       [startupInformation resetFirstUserActionRecorder];
     } else {
diff --git a/ios/chrome/app/application_delegate/metrics_mediator_unittest.mm b/ios/chrome/app/application_delegate/metrics_mediator_unittest.mm
index f2b744f..01ac611 100644
--- a/ios/chrome/app/application_delegate/metrics_mediator_unittest.mm
+++ b/ios/chrome/app/application_delegate/metrics_mediator_unittest.mm
@@ -17,6 +17,8 @@
 #import "ios/chrome/browser/ui/main/browser_interface_provider.h"
 #import "ios/chrome/browser/ui/main/test/stub_browser_interface.h"
 #import "ios/chrome/browser/ui/main/test/stub_browser_interface_provider.h"
+#import "ios/chrome/browser/web_state_list/fake_web_state_list_delegate.h"
+#import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/chrome/test/base/scoped_block_swizzler.h"
 #import "ios/chrome/test/ocmock/OCMockObject+BreakpadControllerTesting.h"
 #include "net/base/network_change_notifier.h"
@@ -123,13 +125,17 @@
 
 class MetricsMediatorLogLaunchTest : public PlatformTest {
  protected:
-  MetricsMediatorLogLaunchTest() : has_been_called_(FALSE) {}
+  MetricsMediatorLogLaunchTest()
+      : has_been_called_(FALSE),
+        web_state_list_(
+            std::make_unique<WebStateList>(&web_state_list_delegate_)) {}
 
   void initiateMetricsMediator(BOOL coldStart, int tabCount) {
     id mainTabModel = [OCMockObject mockForClass:[TabModel class]];
     [[[mainTabModel stub] andReturnValue:@(tabCount)] count];
-    [[[mainTabModel stub] andReturn:nil] currentTab];
-
+    WebStateList* web_state_list = web_state_list_.get();
+    [[[mainTabModel stub] andReturnValue:OCMOCK_VALUE(web_state_list)]
+        webStateList];
     StubBrowserInterfaceProvider* concreteProvider =
         [[StubBrowserInterfaceProvider alloc] init];
     concreteProvider.mainInterface.tabModel = mainTabModel;
@@ -162,6 +168,8 @@
   __block BOOL has_been_called_;
   logLaunchMetricsBlock swizzle_block_;
   std::unique_ptr<ScopedBlockSwizzler> uma_histogram_swizzler_;
+  std::unique_ptr<WebStateList> web_state_list_;
+  FakeWebStateListDelegate web_state_list_delegate_;
 };
 
 // Verifies that the log of the number of open tabs is sent and verifies
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index b40021a3..bb36e1b 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -110,7 +110,6 @@
 #import "ios/chrome/browser/snapshots/snapshot_cache_factory.h"
 #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h"
 #include "ios/chrome/browser/system_flags.h"
-#import "ios/chrome/browser/tabs/tab.h"
 #import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/ui/authentication/signed_in_accounts_view_controller.h"
 #import "ios/chrome/browser/ui/browser_view/browser_coordinator.h"
@@ -1496,7 +1495,8 @@
 }
 
 - (void)prepareTabSwitcher {
-  web::WebState* currentWebState = self.currentBVC.tabModel.currentTab.webState;
+  web::WebState* currentWebState =
+      self.currentBVC.tabModel.webStateList->GetActiveWebState();
   if (currentWebState) {
     BOOL loading = currentWebState->IsLoading();
     SnapshotTabHelper::FromWebState(currentWebState)
@@ -2171,7 +2171,10 @@
   // Removing browsing data triggers session restore in navigation manager. If
   // there is an in-progress session restore, wait for it to finish before
   // attempting to clear browsing data again.
-  web::WebState* webState = [[[self.currentBVC tabModel] currentTab] webState];
+  web::WebState* webState =
+      self.currentBVC.tabModel
+          ? self.currentBVC.tabModel.webStateList->GetActiveWebState()
+          : nullptr;
   if (webState && webState->GetNavigationManager()) {
     webState->GetNavigationManager()->AddRestoreCompletionCallback(
         base::BindOnce(^{
@@ -2262,15 +2265,13 @@
          tabOpenedCompletion:(ProceduralBlock)tabOpenedCompletion {
   BrowserViewController* targetBVC =
       targetMode == ApplicationMode::NORMAL ? self.mainBVC : self.otrBVC;
-  TabModel* targetTabModel = targetBVC.tabModel;
-
-  Tab* currentTabInTargetBVC = [targetTabModel currentTab];
+  web::WebState* currentWebState =
+      targetBVC.tabModel.webStateList->GetActiveWebState();
 
   // Don't call loadWithParams for chrome://newtab when it's already loaded.
   // Note that it's safe to use -GetVisibleURL here, as it doesn't matter if the
   // NTP hasn't finished loading.
-  if (currentTabInTargetBVC.webState &&
-      IsURLNtp(currentTabInTargetBVC.webState->GetVisibleURL()) &&
+  if (currentWebState && IsURLNtp(currentWebState->GetVisibleURL()) &&
       IsURLNtp(urlLoadParams.web_params.url)) {
     if (tabOpenedCompletion) {
       tabOpenedCompletion();
@@ -2287,8 +2288,7 @@
   // If the current tab isn't an NTP, open a new tab.  Be sure to use
   // -GetLastCommittedURL incase the NTP is still loading.
   if (alwaysInsertNewTab ||
-      !(currentTabInTargetBVC.webState &&
-        IsURLNtp(currentTabInTargetBVC.webState->GetVisibleURL()))) {
+      !(currentWebState && IsURLNtp(currentWebState->GetVisibleURL()))) {
     [targetBVC appendTabAddedCompletion:tabOpenedCompletion];
     UrlLoadParams newTabParams = urlLoadParams;
     newTabParams.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
@@ -2590,7 +2590,8 @@
 - (NSString*)currentPageDisplayURL {
   if (_tabSwitcherIsActive)
     return nil;
-  web::WebState* webState = [[[self currentTabModel] currentTab] webState];
+  web::WebState* webState =
+      self.currentTabModel.webStateList->GetActiveWebState();
   if (!webState)
     return nil;
   // Returns URL of browser tab that is currently showing.
diff --git a/ios/chrome/browser/bookmarks/bookmark_client_impl.cc b/ios/chrome/browser/bookmarks/bookmark_client_impl.cc
index 5ba4d5ec..a9db3f65 100644
--- a/ios/chrome/browser/bookmarks/bookmark_client_impl.cc
+++ b/ios/chrome/browser/bookmarks/bookmark_client_impl.cc
@@ -80,7 +80,7 @@
   base::RecordAction(action);
 }
 
-bookmarks::LoadExtraCallback BookmarkClientImpl::GetLoadExtraNodesCallback() {
+bookmarks::LoadExtraCallback BookmarkClientImpl::GetLoadExtraNodeCallback() {
   return bookmarks::LoadExtraCallback();
 }
 
diff --git a/ios/chrome/browser/bookmarks/bookmark_client_impl.h b/ios/chrome/browser/bookmarks/bookmark_client_impl.h
index 5d3236e..9a634c75 100644
--- a/ios/chrome/browser/bookmarks/bookmark_client_impl.h
+++ b/ios/chrome/browser/bookmarks/bookmark_client_impl.h
@@ -48,7 +48,7 @@
   bool IsPermanentNodeVisible(
       const bookmarks::BookmarkPermanentNode* node) override;
   void RecordAction(const base::UserMetricsAction& action) override;
-  bookmarks::LoadExtraCallback GetLoadExtraNodesCallback() override;
+  bookmarks::LoadExtraCallback GetLoadExtraNodeCallback() override;
   bool CanSetPermanentNodeTitle(
       const bookmarks::BookmarkNode* permanent_node) override;
   bool CanSyncNode(const bookmarks::BookmarkNode* node) override;
diff --git a/ios/chrome/browser/metrics/new_tab_page_uma.mm b/ios/chrome/browser/metrics/new_tab_page_uma.mm
index ff0121ba..0f24afb 100644
--- a/ios/chrome/browser/metrics/new_tab_page_uma.mm
+++ b/ios/chrome/browser/metrics/new_tab_page_uma.mm
@@ -8,9 +8,9 @@
 #include "components/google/core/common/google_util.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
-#import "ios/chrome/browser/tabs/tab.h"
 #import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/tabs/tab_model_list.h"
+#import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "url/gurl.h"
 
@@ -21,10 +21,12 @@
 namespace new_tab_page_uma {
 
 bool IsCurrentlyOnNTP(ios::ChromeBrowserState* browser_state) {
-  TabModel* tab_model =
-      TabModelList::GetLastActiveTabModelForChromeBrowserState(browser_state);
-  return tab_model.currentTab.webState &&
-         tab_model.currentTab.webState->GetVisibleURL() == kChromeUINewTabURL;
+  WebStateList* webStateList =
+      TabModelList::GetLastActiveTabModelForChromeBrowserState(browser_state)
+          .webStateList;
+  return webStateList->GetActiveWebState() &&
+         webStateList->GetActiveWebState()->GetVisibleURL() ==
+             kChromeUINewTabURL;
 }
 
 void RecordAction(ios::ChromeBrowserState* browserState, ActionType type) {
diff --git a/ios/chrome/browser/tabs/tab_model.mm b/ios/chrome/browser/tabs/tab_model.mm
index 2d168a2..37ed359 100644
--- a/ios/chrome/browser/tabs/tab_model.mm
+++ b/ios/chrome/browser/tabs/tab_model.mm
@@ -306,6 +306,7 @@
 }
 
 - (WebStateList*)webStateList {
+  DCHECK(_webStateList);
   return _webStateList.get();
 }
 
diff --git a/ios/chrome/browser/ui/activity_services/BUILD.gn b/ios/chrome/browser/ui/activity_services/BUILD.gn
index cd31a20..4009ba1a 100644
--- a/ios/chrome/browser/ui/activity_services/BUILD.gn
+++ b/ios/chrome/browser/ui/activity_services/BUILD.gn
@@ -73,6 +73,7 @@
     "//ios/chrome/browser/ui/activity_services/requirements",
     "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
+    "//ios/chrome/browser/web_state_list",
     "//url",
   ]
 }
diff --git a/ios/chrome/browser/ui/activity_services/activity_service_legacy_coordinator.mm b/ios/chrome/browser/ui/activity_services/activity_service_legacy_coordinator.mm
index 35bd049a..401c8e1b 100644
--- a/ios/chrome/browser/ui/activity_services/activity_service_legacy_coordinator.mm
+++ b/ios/chrome/browser/ui/activity_services/activity_service_legacy_coordinator.mm
@@ -8,7 +8,6 @@
 #include "base/time/time.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/passwords/password_tab_helper.h"
-#import "ios/chrome/browser/tabs/tab.h"
 #import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/ui/activity_services/activity_service_controller.h"
 #import "ios/chrome/browser/ui/activity_services/canonical_url_retriever.h"
@@ -20,6 +19,7 @@
 #import "ios/chrome/browser/ui/activity_services/share_to_data_builder.h"
 #import "ios/chrome/browser/ui/commands/activity_service_commands.h"
 #import "ios/chrome/browser/ui/commands/command_dispatcher.h"
+#import "ios/chrome/browser/web_state_list/web_state_list.h"
 #include "url/gurl.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -86,7 +86,7 @@
   self.sharePageStartTime = base::TimeTicks::Now();
   __weak ActivityServiceLegacyCoordinator* weakSelf = self;
   activity_services::RetrieveCanonicalUrl(
-      self.tabModel.currentTab.webState, ^(const GURL& url) {
+      self.tabModel.webStateList->GetActiveWebState(), ^(const GURL& url) {
         [weakSelf sharePageWithCanonicalURL:url];
       });
 }
@@ -94,7 +94,7 @@
 #pragma mark - Providers
 
 - (id<PasswordFormFiller>)currentPasswordFormFiller {
-  web::WebState* webState = self.tabModel.currentTab.webState;
+  web::WebState* webState = self.tabModel.webStateList->GetActiveWebState();
   return webState ? PasswordTabHelper::FromWebState(webState)
                         ->GetPasswordFormFiller()
                   : nil;
@@ -103,8 +103,8 @@
 #pragma mark - Private Methods
 
 - (void)sharePageWithCanonicalURL:(const GURL&)canonicalURL {
-  ShareToData* data = activity_services::ShareToDataForTab(
-      [self.tabModel currentTab], canonicalURL);
+  ShareToData* data = activity_services::ShareToDataForWebState(
+      self.tabModel.webStateList->GetActiveWebState(), canonicalURL);
   if (!data)
     return;
 
diff --git a/ios/chrome/browser/ui/activity_services/share_to_data_builder.h b/ios/chrome/browser/ui/activity_services/share_to_data_builder.h
index 448dea0..3d7dbb7 100644
--- a/ios/chrome/browser/ui/activity_services/share_to_data_builder.h
+++ b/ios/chrome/browser/ui/activity_services/share_to_data_builder.h
@@ -10,13 +10,17 @@
 @class ShareToData;
 @class Tab;
 
+namespace web {
+class WebState;
+}
 namespace activity_services {
 
-// Returns a ShareToData object using data from |tab|. |shareURL| is the URL to
-// be shared with share extensions (excluding password managers). If |shareURL|
-// is empty, the visible URL associated with |tab| will be used instead. |tab|
-// must not be nil. Function may return nil.
-ShareToData* ShareToDataForTab(Tab* tab, const GURL& shareURL);
+// Returns a ShareToData object using data from |web_state|. |share_url| is the
+// URL to be shared with share extensions (excluding password managers). If
+// |share_url| is empty, the visible URL associated with |web_state| will be
+// used instead. |web_state| must not be nil. Function may return nil.
+ShareToData* ShareToDataForWebState(web::WebState* web_state,
+                                    const GURL& share_url);
 
 }  // namespace activity_services
 
diff --git a/ios/chrome/browser/ui/activity_services/share_to_data_builder.mm b/ios/chrome/browser/ui/activity_services/share_to_data_builder.mm
index 2dc2bc6..186f9ce 100644
--- a/ios/chrome/browser/ui/activity_services/share_to_data_builder.mm
+++ b/ios/chrome/browser/ui/activity_services/share_to_data_builder.mm
@@ -7,7 +7,7 @@
 #include "base/logging.h"
 #import "base/strings/sys_string_conversions.h"
 #import "ios/chrome/browser/find_in_page/find_tab_helper.h"
-#include "ios/chrome/browser/tabs/tab.h"
+#import "ios/chrome/browser/tabs/legacy_tab_helper.h"
 #import "ios/chrome/browser/tabs/tab_title_util.h"
 #include "ios/chrome/browser/ui/activity_services/chrome_activity_item_thumbnail_generator.h"
 #include "ios/chrome/browser/ui/activity_services/share_to_data.h"
@@ -22,20 +22,19 @@
 
 namespace activity_services {
 
-ShareToData* ShareToDataForTab(Tab* tab, const GURL& shareURL) {
-  DCHECK(tab);
+ShareToData* ShareToDataForWebState(web::WebState* web_state,
+                                    const GURL& share_url) {
   // For crash documented in crbug.com/503955, tab.url which is being passed
   // as a reference parameter caused a crash due to invalid address which
-  // which suggests that |tab| may be deallocated along the way. Check that
-  // tab is still valid by checking webState which would be deallocated if
-  // tab is being closed.
-  if (!tab.webState)
+  // suggests that tab may get closed along the way. Check that web_state
+  // is still valid.
+  if (!web_state)
     return nil;
 
   BOOL is_original_title = NO;
-  DCHECK(tab.webState->GetNavigationManager());
+  DCHECK(web_state->GetNavigationManager());
   web::NavigationItem* last_committed_item =
-      tab.webState->GetNavigationManager()->GetLastCommittedItem();
+      web_state->GetNavigationManager()->GetLastCommittedItem();
   if (last_committed_item) {
     // Do not use WebState::GetTitle() as it returns the display title, not the
     // original page title.
@@ -44,31 +43,32 @@
       // If the original page title exists, it is expected to match the Tab's
       // title. If this ever changes, then a decision has to be made on which
       // one should be used for sharing.
-      DCHECK([tab_util::GetTabTitle(tab.webState)
+      DCHECK([tab_util::GetTabTitle(web_state)
           isEqual:base::SysUTF16ToNSString(original_title)]);
       is_original_title = YES;
     }
   }
 
-  BOOL is_page_printable = [tab.webState->GetView() viewPrintFormatter] != nil;
+  BOOL is_page_printable = [web_state->GetView() viewPrintFormatter] != nil;
+  Tab* tab = LegacyTabHelper::GetTabForWebState(web_state);
   ThumbnailGeneratorBlock thumbnail_generator =
       activity_services::ThumbnailGeneratorForTab(tab);
   const GURL& finalURLToShare =
-      !shareURL.is_empty() ? shareURL : tab.webState->GetVisibleURL();
+      !share_url.is_empty() ? share_url : web_state->GetVisibleURL();
 
   web::NavigationItem* visibleItem =
-      tab.webState->GetNavigationManager()->GetVisibleItem();
+      web_state->GetNavigationManager()->GetVisibleItem();
   web::UserAgentType userAgent = web::UserAgentType::NONE;
   if (visibleItem)
     userAgent = visibleItem->GetUserAgentType();
 
-  auto* helper = FindTabHelper::FromWebState(tab.webState);
+  FindTabHelper* helper = FindTabHelper::FromWebState(web_state);
   BOOL is_page_searchable =
       (helper && helper->CurrentPageSupportsFindInPage() &&
        !helper->IsFindUIActive());
-  NSString* tab_title = tab_util::GetTabTitle(tab.webState);
+  NSString* tab_title = tab_util::GetTabTitle(web_state);
   return [[ShareToData alloc] initWithShareURL:finalURLToShare
-                                    visibleURL:tab.webState->GetVisibleURL()
+                                    visibleURL:web_state->GetVisibleURL()
                                          title:tab_title
                                isOriginalTitle:is_original_title
                                isPagePrintable:is_page_printable
diff --git a/ios/chrome/browser/ui/activity_services/share_to_data_builder_unittest.mm b/ios/chrome/browser/ui/activity_services/share_to_data_builder_unittest.mm
index f32bae3d..7c943f6 100644
--- a/ios/chrome/browser/ui/activity_services/share_to_data_builder_unittest.mm
+++ b/ios/chrome/browser/ui/activity_services/share_to_data_builder_unittest.mm
@@ -13,7 +13,7 @@
 #import "ios/chrome/browser/download/download_manager_tab_helper.h"
 #import "ios/chrome/browser/snapshots/fake_snapshot_generator_delegate.h"
 #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h"
-#import "ios/chrome/browser/tabs/tab.h"
+#import "ios/chrome/browser/tabs/legacy_tab_helper.h"
 #import "ios/chrome/browser/ui/activity_services/share_to_data.h"
 #import "ios/testing/ocmock_complex_type_helper.h"
 #import "ios/web/public/test/fakes/test_navigation_manager.h"
@@ -38,33 +38,6 @@
 const char kExpectedTitle[] = "title";
 }  // namespace
 
-@interface ShareToDataBuilderTestTabMock : OCMockComplexTypeHelper {
-  std::unique_ptr<web::TestWebState> _webState;
-}
-
-@property(nonatomic, readonly) web::WebState* webState;
-
-@end
-
-@implementation ShareToDataBuilderTestTabMock
-
-- (web::WebState*)webState {
-  return _webState.get();
-}
-
-- (instancetype)initWithWebState:(std::unique_ptr<web::TestWebState>)webState {
-  id representedObject = [OCMockObject niceMockForClass:[Tab class]];
-  if ((self = [super initWithRepresentedObject:representedObject])) {
-    _webState = std::move(webState);
-  }
-  return self;
-}
-
-- (void)close {
-  _webState.reset();
-}
-
-@end
 
 class ShareToDataBuilderTest : public PlatformTest {
  public:
@@ -78,47 +51,38 @@
     navigation_manager->GetLastCommittedItem()->SetTitle(
         base::UTF8ToUTF16(kExpectedTitle));
 
-    auto web_state = std::make_unique<web::TestWebState>();
-    web_state->SetNavigationManager(std::move(navigation_manager));
-    web_state->SetBrowserState(chrome_browser_state_.get());
-    web_state->SetVisibleURL(GURL(kExpectedUrl));
+    web_state_ = std::make_unique<web::TestWebState>();
+    web_state_->SetNavigationManager(std::move(navigation_manager));
+    web_state_->SetBrowserState(chrome_browser_state_.get());
+    web_state_->SetVisibleURL(GURL(kExpectedUrl));
 
     // Attach SnapshotTabHelper to allow snapshot generation.
-    SnapshotTabHelper::CreateForWebState(web_state.get(),
+    SnapshotTabHelper::CreateForWebState(web_state_.get(),
                                          [[NSUUID UUID] UUIDString]);
     delegate_ = [[FakeSnapshotGeneratorDelegate alloc] init];
-    SnapshotTabHelper::FromWebState(web_state.get())->SetDelegate(delegate_);
+    SnapshotTabHelper::FromWebState(web_state_.get())->SetDelegate(delegate_);
+    LegacyTabHelper::CreateForWebState(web_state_.get());
 
-    // Needed by the ShareToDataForTab to get the tab title.
-    DownloadManagerTabHelper::CreateForWebState(web_state.get(),
+    // Needed by the ShareToDataForWebState to get the tab title.
+    DownloadManagerTabHelper::CreateForWebState(web_state_.get(),
                                                 /*delegate=*/nullptr);
-    web_state->SetTitle(base::UTF8ToUTF16(kExpectedTitle));
+    web_state_->SetTitle(base::UTF8ToUTF16(kExpectedTitle));
 
     // Add a fake view to the TestWebState. This will be used to capture the
     // snapshot. By default the WebState is not ready for taking snapshot.
     CGRect frame = {CGPointZero, CGSizeMake(300, 400)};
     delegate_.view = [[UIView alloc] initWithFrame:frame];
     delegate_.view.backgroundColor = [UIColor blueColor];
-
-    tab_ = [[ShareToDataBuilderTestTabMock alloc]
-        initWithWebState:std::move(web_state)];
   }
 
-  void TearDown() override {
-    [tab_ close];
-    tab_ = nil;
-    PlatformTest::TearDown();
-  }
-
-  Tab* tab() { return static_cast<Tab*>(tab_); }
-
-  ShareToDataBuilderTestTabMock* tab_mock() { return tab_; }
+  web::WebState* web_state() { return web_state_.get(); }
 
  private:
   FakeSnapshotGeneratorDelegate* delegate_ = nil;
   web::TestWebThreadBundle thread_bundle_;
   std::unique_ptr<ios::ChromeBrowserState> chrome_browser_state_;
-  ShareToDataBuilderTestTabMock* tab_;
+  std::unique_ptr<web::TestWebState> web_state_;
+
   DISALLOW_COPY_AND_ASSIGN(ShareToDataBuilderTest);
 };
 
@@ -126,8 +90,8 @@
 // is a URL provided for share extensions.
 TEST_F(ShareToDataBuilderTest, TestSharePageCommandHandlingNpShareUrl) {
   const char* kExpectedShareUrl = "http://www.testurl.com/";
-  ShareToData* actual_data =
-      activity_services::ShareToDataForTab(tab(), GURL(kExpectedShareUrl));
+  ShareToData* actual_data = activity_services::ShareToDataForWebState(
+      web_state(), GURL(kExpectedShareUrl));
 
   ASSERT_TRUE(actual_data);
   EXPECT_EQ(kExpectedShareUrl, actual_data.shareURL);
@@ -146,7 +110,7 @@
 // URL designated for share extensions is empty.
 TEST_F(ShareToDataBuilderTest, TestSharePageCommandHandlingNoShareUrl) {
   ShareToData* actual_data =
-      activity_services::ShareToDataForTab(tab(), GURL());
+      activity_services::ShareToDataForWebState(web_state(), GURL());
 
   ASSERT_TRUE(actual_data);
   EXPECT_EQ(kExpectedUrl, actual_data.shareURL);
@@ -161,10 +125,8 @@
       UIImageWithSizeAndSolidColor(size, [UIColor blueColor])));
 }
 
-// Verifies that |ShareToDataForTab()| returns nil if the Tab is in the process
-// of being closed.
+// Verifies that |ShareToDataForWebState()| returns nil if the WebState passed
+// is nullptr.
 TEST_F(ShareToDataBuilderTest, TestReturnsNilWhenClosing) {
-  [tab_mock() close];
-
-  EXPECT_EQ(nil, activity_services::ShareToDataForTab(tab(), GURL()));
+  EXPECT_EQ(nil, activity_services::ShareToDataForWebState(nullptr, GURL()));
 }
diff --git a/ios/chrome/browser/ui/authentication/cells/table_view_signin_promo_item.mm b/ios/chrome/browser/ui/authentication/cells/table_view_signin_promo_item.mm
index 39723f5..1569ccbfe 100644
--- a/ios/chrome/browser/ui/authentication/cells/table_view_signin_promo_item.mm
+++ b/ios/chrome/browser/ui/authentication/cells/table_view_signin_promo_item.mm
@@ -41,6 +41,11 @@
   [self.configurator configureSigninPromoView:cell.signinPromoView];
   if (styler.cellTitleColor)
     cell.signinPromoView.textLabel.textColor = styler.cellTitleColor;
+  if (styler.tintColor) {
+    cell.signinPromoView.primaryButton.backgroundColor = styler.tintColor;
+    [cell.signinPromoView.secondaryButton setTitleColor:styler.tintColor
+                                               forState:UIControlStateNormal];
+  }
 }
 
 @end
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm b/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm
index 71994e0..e8a28e5 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm
+++ b/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm
@@ -330,7 +330,8 @@
 
 // Tests that the Password View Controller is resumed after selecting other
 // password.
-- (void)testPasswordControllerResumes {
+// TODO(crbug.com/981922): Re-enable this test due to failing DB call.
+- (void)DISABLED_testPasswordControllerResumes {
   if (([UIDevice currentDevice].systemVersion.doubleValue < 12)) {
     // TODO(crbug.com/976348): iOS 11 support is being deprecated, disable this
     // failing test for now.
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.h b/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.h
index 945da25..7e00e3c 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.h
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.h
@@ -18,6 +18,10 @@
 class ChromeBrowserState;
 }
 
+namespace web {
+class WebState;
+}
+
 class WebStateList;
 
 // The BookmarkInteractionController abstracts the management of the various
@@ -35,8 +39,8 @@
 - (instancetype)init NS_UNAVAILABLE;
 
 // Presents the bookmark UI for a single bookmark.
-- (void)presentBookmarkEditorForTab:(Tab*)tab
-                currentlyBookmarked:(BOOL)bookmarked;
+- (void)presentBookmarkEditorForWebState:(web::WebState*)webState
+                     currentlyBookmarked:(BOOL)bookmarked;
 
 // Presents the bookmarks browser modally.
 - (void)presentBookmarks;
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm
index 5004398..78308da 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm
@@ -122,7 +122,7 @@
     BookmarkTransitioningDelegate* bookmarkTransitioningDelegate;
 
 // Builds a controller and brings it on screen.
-- (void)presentBookmarkEditorForBookmarkedTab:(Tab*)tab;
+- (void)presentBookmarkEditorForBookmarkedURL:(const GURL&)URL;
 
 // Dismisses the bookmark browser.  If |urlsToOpen| is not empty, then the user
 // has selected to navigate to those URLs with specified tab mode.
@@ -181,37 +181,32 @@
   _bookmarkEditor.delegate = nil;
 }
 
-- (void)presentBookmarkEditorForBookmarkedTab:(Tab*)tab {
-  DCHECK(tab && tab.webState);
-
+- (void)presentBookmarkEditorForBookmarkedURL:(const GURL&)URL {
   const BookmarkNode* bookmark =
-      self.bookmarkModel->GetMostRecentlyAddedUserNodeForURL(
-          tab.webState->GetLastCommittedURL());
+      self.bookmarkModel->GetMostRecentlyAddedUserNodeForURL(URL);
   if (!bookmark)
     return;
   [self presentEditorForNode:bookmark];
 }
 
-- (void)presentBookmarkEditorForTab:(Tab*)tab
-                currentlyBookmarked:(BOOL)bookmarked {
+- (void)presentBookmarkEditorForWebState:(web::WebState*)webState
+                     currentlyBookmarked:(BOOL)bookmarked {
   if (!self.bookmarkModel->loaded())
     return;
-  if (!tab || !tab.webState)
+  if (!webState)
     return;
 
+  GURL bookmarkedURL = webState->GetLastCommittedURL();
+
   if (bookmarked) {
-    [self presentBookmarkEditorForBookmarkedTab:tab];
+    [self presentBookmarkEditorForBookmarkedURL:bookmarkedURL];
   } else {
     __weak BookmarkInteractionController* weakSelf = self;
-    __weak Tab* weakTab = tab;
     void (^editAction)() = ^{
-      BookmarkInteractionController* strongSelf = weakSelf;
-      if (!strongSelf || !weakTab || !weakTab.webState)
-        return;
-      [strongSelf presentBookmarkEditorForBookmarkedTab:weakTab];
+      [weakSelf presentBookmarkEditorForBookmarkedURL:bookmarkedURL];
     };
-    [self.mediator addBookmarkWithTitle:tab_util::GetTabTitle(tab.webState)
-                                    URL:tab.webState->GetLastCommittedURL()
+    [self.mediator addBookmarkWithTitle:tab_util::GetTabTitle(webState)
+                                    URL:bookmarkedURL
                              editAction:editAction];
   }
 }
diff --git a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
index 174ebaf..8897222 100644
--- a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
@@ -501,6 +501,9 @@
 
 // Uninstalls delegates for each WebState in WebStateList.
 - (void)uninstallDelegatesForAllWebStates {
+  // OpenInMediator is controlled directly monitors the webStateList and should
+  // be deleted.
+  self.openInMediator = nil;
   for (int i = 0; i < self.tabModel.webStateList->count(); i++) {
     web::WebState* webState = self.tabModel.webStateList->GetWebStateAt(i);
     [self uninstallDelegatesForWebState:webState];
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
index 362fb94..6974501 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -373,6 +373,9 @@
   // by the BVC.
   BrowserViewControllerDependencyFactory* _dependencyFactory;
 
+  // Identifier for each animation of an NTP opening.
+  NSInteger _NTPAnimationIdentifier;
+
   // Backing ivar for the public property, strong even though the property is
   // weak, because things explode otherwise.
   // Do not directly access this ivar outside of object initialization; use the
@@ -4184,9 +4187,9 @@
 - (void)bookmarkPage {
   [self initializeBookmarkInteractionController];
   [_bookmarkInteractionController
-      presentBookmarkEditorForTab:self.tabModel.currentTab
-              currentlyBookmarked:[self.helper isWebStateBookmarkedByUser:
-                                                   self.currentWebState]];
+      presentBookmarkEditorForWebState:self.currentWebState
+                   currentlyBookmarked:[self.helper isWebStateBookmarkedByUser:
+                                                        self.currentWebState]];
 }
 
 - (void)addToReadingList:(ReadingListAddCommand*)command {
@@ -4618,9 +4621,20 @@
     newPage.userInteractionEnabled = NO;
   }
 
+  NSInteger currentAnimationIdentifier = ++_NTPAnimationIdentifier;
+
   // Cleanup steps needed for both UI Refresh and stack-view style animations.
   UIView* webStateView = [self viewForWebState:webState];
   auto commonCompletion = ^{
+    if (currentAnimationIdentifier != _NTPAnimationIdentifier) {
+      // Prevent the completion block from being executed if a new animation has
+      // started in between. |self.foregroundTabWasAddedCompletionBlock| isn't
+      // called because it is overridden when a new animation is started.
+      // Calling it here would call the block from the lastest animation that
+      // haved started.
+      return;
+    }
+
     webStateView.frame = self.contentArea.bounds;
     newPage.userInteractionEnabled = YES;
     self.inNewTabAnimation = NO;
diff --git a/ios/chrome/browser/ui/first_run/BUILD.gn b/ios/chrome/browser/ui/first_run/BUILD.gn
index dcb29b85..deee874 100644
--- a/ios/chrome/browser/ui/first_run/BUILD.gn
+++ b/ios/chrome/browser/ui/first_run/BUILD.gn
@@ -47,6 +47,7 @@
     "//ios/chrome/browser/ui/settings/utils",
     "//ios/chrome/browser/ui/util",
     "//ios/chrome/browser/ui/util:terms_util",
+    "//ios/chrome/browser/web_state_list",
     "//ios/chrome/common",
     "//ios/public/provider/chrome/browser",
     "//ios/public/provider/chrome/browser/signin",
diff --git a/ios/chrome/browser/ui/first_run/first_run_chrome_signin_view_controller.mm b/ios/chrome/browser/ui/first_run/first_run_chrome_signin_view_controller.mm
index 266014eb..87f0f6b 100644
--- a/ios/chrome/browser/ui/first_run/first_run_chrome_signin_view_controller.mm
+++ b/ios/chrome/browser/ui/first_run/first_run_chrome_signin_view_controller.mm
@@ -16,11 +16,14 @@
 #import "ios/chrome/browser/ui/first_run/first_run_util.h"
 #import "ios/chrome/browser/ui/promos/signin_promo_view_controller.h"
 #include "ios/chrome/browser/ui/util/ui_util.h"
+#import "ios/chrome/browser/web_state_list/web_state_list.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #import "ios/public/provider/chrome/browser/signin/chrome_identity.h"
 #import "ios/public/provider/chrome/browser/signin/chrome_identity_service.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
+#import "ios/web/public/web_state/web_state.h"
+
 #import "ui/base/l10n/l10n_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -109,7 +112,8 @@
 
 - (void)finishFirstRunAndDismissWithCompletion:(ProceduralBlock)completion {
   DCHECK(self.presentingViewController);
-  FinishFirstRun(self.browserState, [_tabModel currentTab], _firstRunConfig,
+  web::WebState* currentWebState = _tabModel.webStateList->GetActiveWebState();
+  FinishFirstRun(self.browserState, currentWebState, _firstRunConfig,
                  self.presenter);
   [self.presentingViewController dismissViewControllerAnimated:YES
                                                     completion:^{
diff --git a/ios/chrome/browser/ui/first_run/first_run_util.h b/ios/chrome/browser/ui/first_run/first_run_util.h
index 2f5b378..61ef002 100644
--- a/ios/chrome/browser/ui/first_run/first_run_util.h
+++ b/ios/chrome/browser/ui/first_run/first_run_util.h
@@ -18,6 +18,9 @@
 namespace ios {
 class ChromeBrowserState;
 }
+namespace web {
+class WebState;
+}
 
 // Notification sent when the first run ends, right before dimissing the Terms
 // of Service modal view.
@@ -45,7 +48,7 @@
 
 // Methods for writing sentinel and recording metrics and posting notifications
 void FinishFirstRun(ios::ChromeBrowserState* browserState,
-                    Tab* tab,
+                    web::WebState* web_state,
                     FirstRunConfiguration* config,
                     id<SyncPresenter> presenter);
 
diff --git a/ios/chrome/browser/ui/first_run/first_run_util.mm b/ios/chrome/browser/ui/first_run/first_run_util.mm
index a71e9119..51b823f 100644
--- a/ios/chrome/browser/ui/first_run/first_run_util.mm
+++ b/ios/chrome/browser/ui/first_run/first_run_util.mm
@@ -18,12 +18,12 @@
 #import "ios/chrome/browser/first_run/first_run_configuration.h"
 #include "ios/chrome/browser/first_run/first_run_metrics.h"
 #include "ios/chrome/browser/signin/identity_manager_factory.h"
-#include "ios/chrome/browser/tabs/tab.h"
 #include "ios/chrome/browser/ui/first_run/first_run_histograms.h"
 #import "ios/chrome/browser/ui/settings/sync/utils/sync_util.h"
 #import "ios/chrome/browser/ui/settings/utils/settings_utils.h"
 #include "ios/chrome/browser/ui/util/ui_util.h"
 #include "ios/web/public/thread/web_thread.h"
+#import "ios/web/public/web_state/web_state.h"
 #import "ui/gfx/ios/NSString+CrStringDrawing.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -153,7 +153,7 @@
 }
 
 void FinishFirstRun(ios::ChromeBrowserState* browserState,
-                    Tab* tab,
+                    web::WebState* web_state,
                     FirstRunConfiguration* config,
                     id<SyncPresenter> presenter) {
   [[NSNotificationCenter defaultCenter]
@@ -163,7 +163,7 @@
                                         config.hasSSOAccount);
 
   // Display the sync errors infobar.
-  DisplaySyncErrors(browserState, tab.webState, presenter);
+  DisplaySyncErrors(browserState, web_state, presenter);
 }
 
 void RecordProductTourTimingMetrics(NSString* timer_name,
diff --git a/ios/chrome/browser/ui/page_info/BUILD.gn b/ios/chrome/browser/ui/page_info/BUILD.gn
index a86df900..c7548ae1 100644
--- a/ios/chrome/browser/ui/page_info/BUILD.gn
+++ b/ios/chrome/browser/ui/page_info/BUILD.gn
@@ -29,6 +29,7 @@
     "//ios/chrome/browser/ui/popup_menu",
     "//ios/chrome/browser/ui/util",
     "//ios/chrome/common",
+    "//ios/chrome/common/colors",
     "//ios/web",
     "//ios/web/public/security",
     "//ui/base",
diff --git a/ios/chrome/browser/ui/page_info/page_info_legacy_coordinator.mm b/ios/chrome/browser/ui/page_info/page_info_legacy_coordinator.mm
index 146d1a06..96b603e 100644
--- a/ios/chrome/browser/ui/page_info/page_info_legacy_coordinator.mm
+++ b/ios/chrome/browser/ui/page_info/page_info_legacy_coordinator.mm
@@ -13,7 +13,6 @@
 #include "ios/chrome/browser/reading_list/features.h"
 #import "ios/chrome/browser/reading_list/offline_page_tab_helper.h"
 #include "ios/chrome/browser/reading_list/offline_url_utils.h"
-#import "ios/chrome/browser/tabs/tab.h"
 #import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/ui/commands/command_dispatcher.h"
 #import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
@@ -165,7 +164,7 @@
 #pragma mark - PageInfoReloading
 
 - (void)reload {
-  web::WebState* webState = self.tabModel.currentTab.webState;
+  web::WebState* webState = self.tabModel.webStateList->GetActiveWebState();
   if (webState) {
     // |check_for_repost| is true because the reload is explicitly initiated
     // by the user.
diff --git a/ios/chrome/browser/ui/page_info/page_info_view_controller.mm b/ios/chrome/browser/ui/page_info/page_info_view_controller.mm
index e994e29a8..a44d6f48 100644
--- a/ios/chrome/browser/ui/page_info/page_info_view_controller.mm
+++ b/ios/chrome/browser/ui/page_info/page_info_view_controller.mm
@@ -22,6 +22,8 @@
 #include "ios/chrome/browser/ui/util/rtl_geometry.h"
 #include "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_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/material_timing.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
@@ -66,18 +68,6 @@
 const CGFloat kImageSize = 24;
 // The height of the headline label.
 const CGFloat kHeadlineHeight = 19;
-// The hex color for the help button text.
-const int kPageInfoHelpButtonRGB = 0x3b8cfe;
-// The grey scale color for the text within the page info alert.
-const CGFloat kPageInfoTextGreyComponent = 0.2;
-
-inline UIColor* PageInfoTextColor() {
-  return [UIColor colorWithWhite:kPageInfoTextGreyComponent alpha:1];
-}
-
-inline UIColor* PageInfoHelpButtonColor() {
-  return UIColorFromRGB(kPageInfoHelpButtonRGB);
-}
 
 inline UIFont* PageInfoHeadlineFont() {
   return [[MDCTypography fontLoader] mediumFontOfSize:16];
@@ -197,10 +187,6 @@
 
 @implementation PageInfoViewController
 
-@synthesize containerView = containerView_;
-@synthesize popupContainer = popupContainer_;
-@synthesize dispatcher = dispatcher_;
-
 - (id)initWithModel:(PageInfoModel*)model
                   bridge:(PageInfoModelObserver*)bridge
              sourcePoint:(CGPoint)sourcePoint
@@ -221,7 +207,6 @@
 
     innerContainerView_ =
         [[BidiContainerView alloc] initWithFrame:CGRectMake(0, 0, 194, 327)];
-    [innerContainerView_ setBackgroundColor:[UIColor clearColor]];
     [innerContainerView_
         setAccessibilityLabel:@"Page Security Info Scroll Container"];
     [innerContainerView_
@@ -231,7 +216,7 @@
     model_.reset(model);
     bridge_.reset(bridge);
     origin_ = sourcePoint;
-    dispatcher_ = dispatcher;
+    _dispatcher = dispatcher;
 
     UIInterfaceOrientation orientation =
         [[UIApplication sharedApplication] statusBarOrientation];
@@ -252,20 +237,20 @@
     [touchDownRecognizer setMinimumPressDuration:.001];
     [touchDownRecognizer setDelegate:self];
 
-    containerView_ = [[UIView alloc] init];
-    [containerView_ addGestureRecognizer:touchDownRecognizer];
-    [containerView_
-        setBackgroundColor:[UIColor colorWithWhite:0 alpha:kShieldAlpha]];
-    [containerView_ setOpaque:NO];
-    [containerView_ setAlpha:0];
-    [containerView_ setAccessibilityViewIsModal:YES];
-    containerView_.accessibilityIdentifier =
+    _containerView = [[UIView alloc] init];
+    [_containerView addGestureRecognizer:touchDownRecognizer];
+    [_containerView setBackgroundColor:[UIColor colorWithWhite:0
+                                                         alpha:kShieldAlpha]];
+    [_containerView setOpaque:NO];
+    [_containerView setAlpha:0];
+    [_containerView setAccessibilityViewIsModal:YES];
+    _containerView.accessibilityIdentifier =
         kPageInfoViewAccessibilityIdentifier;
 
-    popupContainer_ = [[UIView alloc] initWithFrame:CGRectZero];
-    [popupContainer_ setBackgroundColor:[UIColor whiteColor]];
-    [popupContainer_ setClipsToBounds:YES];
-    [containerView_ addSubview:popupContainer_];
+    _popupContainer = [[UIView alloc] initWithFrame:CGRectZero];
+    [_popupContainer setBackgroundColor:UIColor.cr_systemBackgroundColor];
+    [_popupContainer setClipsToBounds:YES];
+    [_containerView addSubview:_popupContainer];
 
     [self.popupContainer addSubview:scrollView_];
     [scrollView_ addSubview:innerContainerView_];
@@ -275,7 +260,7 @@
 
     [self animatePageInfoViewIn:sourcePoint];
     UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification,
-                                    containerView_);
+                                    _containerView);
   }
 
   return self;
@@ -366,7 +351,7 @@
     [scrollView_ setScrollEnabled:NO];
   }
 
-  CGRect containerBounds = [containerView_ bounds];
+  CGRect containerBounds = [_containerView bounds];
   CGRect popupFrame = frame;
   popupFrame.origin.x =
       CGRectGetMidX(containerBounds) - CGRectGetWidth(popupFrame) / 2.0;
@@ -383,15 +368,15 @@
                              curve:ios::material::CurveEaseInOut
                            options:0
                         animations:^{
-                          [popupContainer_ setFrame:popupFrame];
-                          [scrollView_ setFrame:[popupContainer_ bounds]];
+                          [_popupContainer setFrame:popupFrame];
+                          [scrollView_ setFrame:[_popupContainer bounds]];
                           [innerContainerView_ setFrame:innerFrame];
                         }
                         completion:nil];
   } else {
     // Popup hasn't finished animating in yet. Set frames immediately.
-    [popupContainer_ setFrame:popupFrame];
-    [scrollView_ setFrame:[popupContainer_ bounds]];
+    [_popupContainer setFrame:popupFrame];
+    [scrollView_ setFrame:[_popupContainer bounds]];
     [innerContainerView_ setFrame:innerFrame];
   }
 
@@ -420,7 +405,10 @@
                    atOffset:(CGFloat)offset {
   CGRect frame = CGRectMake(kFramePadding, offset, kImageSize, kImageSize);
   UIImageView* imageView = [[UIImageView alloc] initWithFrame:frame];
-  [imageView setImage:model_->GetIconImage(info.icon_id)->ToUIImage()];
+  imageView.tintColor = UIColor.cr_labelColor;
+  UIImage* image = [model_->GetIconImage(info.icon_id)->ToUIImage()
+      imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
+  [imageView setImage:image];
   [subviews addObject:imageView];
 }
 
@@ -431,9 +419,8 @@
   UILabel* label = [[UILabel alloc] initWithFrame:frame];
   [label setTextAlignment:NSTextAlignmentNatural];
   [label setText:base::SysUTF16ToNSString(info.headline)];
-  [label setTextColor:PageInfoTextColor()];
+  [label setTextColor:UIColor.cr_labelColor];
   [label setFont:PageInfoHeadlineFont()];
-  [label setBackgroundColor:[UIColor clearColor]];
   [label setFrame:frame];
   [label setLineBreakMode:NSLineBreakByTruncatingHead];
   [subviews addObject:label];
@@ -448,11 +435,10 @@
   [label setTextAlignment:NSTextAlignmentNatural];
   NSString* description = base::SysUTF16ToNSString(info.description);
   UIFont* font = [MDCTypography captionFont];
-  [label setTextColor:PageInfoTextColor()];
+  [label setTextColor:UIColor.cr_labelColor];
   [label setText:description];
   [label setFont:font];
   [label setNumberOfLines:0];
-  [label setBackgroundColor:[UIColor clearColor]];
 
   // If the text is oversized, resize the text field.
   CGSize constraintSize = CGSizeMake(textWidth_, CGFLOAT_MAX);
@@ -523,11 +509,10 @@
 
   [button.titleLabel setFont:font];
   [button.titleLabel setTextAlignment:NSTextAlignmentLeft];
-  [button setTitleColor:PageInfoHelpButtonColor()
+  [button setTitleColor:[UIColor colorNamed:kTintColor]
                forState:UIControlStateNormal];
-  [button setTitleColor:PageInfoHelpButtonColor()
+  [button setTitleColor:[UIColor colorNamed:kTintColor]
                forState:UIControlStateSelected];
-  [button setBackgroundColor:[UIColor clearColor]];
 
   [subviews addObject:button];
 
@@ -537,16 +522,16 @@
 #pragma mark - UIGestureRecognizerDelegate Implemenation
 
 - (void)rootViewTapped:(UIGestureRecognizer*)sender {
-  CGPoint pt = [sender locationInView:containerView_];
-  if (!CGRectContainsPoint([popupContainer_ frame], pt)) {
+  CGPoint pt = [sender locationInView:_containerView];
+  if (!CGRectContainsPoint([_popupContainer frame], pt)) {
     [self.dispatcher hidePageInfo];
   }
 }
 
 - (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer
        shouldReceiveTouch:(UITouch*)touch {
-  CGPoint pt = [touch locationInView:containerView_];
-  return !CGRectContainsPoint([popupContainer_ frame], pt);
+  CGPoint pt = [touch locationInView:_containerView];
+  return !CGRectContainsPoint([_popupContainer frame], pt);
 }
 
 - (void)animatePageInfoViewIn:(CGPoint)sourcePoint {
@@ -574,8 +559,8 @@
   [fadeAnimation setFromValue:@0];
   [fadeAnimation setToValue:@1];
 
-  [[popupContainer_ layer] addAnimation:fadeAnimation forKey:@"fade"];
-  [[popupContainer_ layer] addAnimation:sizeAnimation forKey:@"size"];
+  [[_popupContainer layer] addAnimation:fadeAnimation forKey:@"fade"];
+  [[_popupContainer layer] addAnimation:sizeAnimation forKey:@"size"];
 
   // Animation the background grey overlay.
   CABasicAnimation* overlayAnimation =
@@ -586,8 +571,8 @@
   [overlayAnimation setFromValue:@0];
   [overlayAnimation setToValue:@1];
 
-  [[containerView_ layer] addAnimation:overlayAnimation forKey:@"fade"];
-  [containerView_ setAlpha:1];
+  [[_containerView layer] addAnimation:overlayAnimation forKey:@"fade"];
+  [_containerView setAlpha:1];
 
   // Animate the contents of the info card.
   CALayer* contentsLayer = [innerContainerView_ layer];
@@ -636,10 +621,10 @@
   [opacityAnimation setDuration:ios::material::kDuration3];
   [opacityAnimation setFromValue:@1];
   [opacityAnimation setToValue:@0];
-  [[containerView_ layer] addAnimation:opacityAnimation forKey:@"animateOut"];
+  [[_containerView layer] addAnimation:opacityAnimation forKey:@"animateOut"];
 
-  [popupContainer_ setAlpha:0];
-  [containerView_ setAlpha:0];
+  [_popupContainer setAlpha:0];
+  [_containerView setAlpha:0];
   [CATransaction commit];
 }
 
diff --git a/ios/chrome/browser/ui/send_tab_to_self/send_tab_to_self_coordinator.mm b/ios/chrome/browser/ui/send_tab_to_self/send_tab_to_self_coordinator.mm
index c19f2d5..a719af9 100644
--- a/ios/chrome/browser/ui/send_tab_to_self/send_tab_to_self_coordinator.mm
+++ b/ios/chrome/browser/ui/send_tab_to_self/send_tab_to_self_coordinator.mm
@@ -23,11 +23,7 @@
                                         SendTabToSelfModalPositioner,
                                         SendTabToSelfModalDelegate>
 
-// The presentationController that shows the Send Tab To Self UI.
-@property(nonatomic, strong) SendTabToSelfModalPresentationController*
-    sendTabToSelfModalPresentationController;
-
-// The presentationController that shows the Send Tab To Self UI.
+// The TableViewController that shows the Send Tab To Self UI.
 @property(nonatomic, strong)
     SendTabToSelfTableViewController* sendTabToSelfViewController;
 
@@ -58,7 +54,14 @@
 }
 
 - (void)stop {
-  // TODO(crbug.com/970284) clean up any presented VC here.
+  DCHECK(self.baseViewController);
+  if (self.baseViewController.presentedViewController &&
+      self.baseViewController.presentedViewController ==
+          self.sendTabToSelfViewController) {
+    [self.sendTabToSelfViewController dismissViewControllerAnimated:NO
+                                                         completion:nil];
+  }
+  self.sendTabToSelfViewController = nil;
 }
 
 #pragma mark-- UIViewControllerTransitioningDelegate
@@ -99,14 +102,16 @@
                            completion:(void (^)())completion {
   [self.baseViewController dismissViewControllerAnimated:animated
                                               completion:completion];
+  [self stop];
 }
 
 - (void)sendTabToTargetDeviceCacheGUID:(NSString*)cacheGUID {
+  // TODO(crbug.com/970284) log histogram of send event.
   SendTabToSelfCommand* command =
       [[SendTabToSelfCommand alloc] initWithTargetDeviceID:cacheGUID];
 
   [self.dispatcher sendTabToSelf:command];
-  // TODO(crbug.com/970284) log histogram of send event.
+  [self stop];
 }
 
 @end
diff --git a/ios/chrome/browser/ui/send_tab_to_self/send_tab_to_self_table_view_controller.mm b/ios/chrome/browser/ui/send_tab_to_self/send_tab_to_self_table_view_controller.mm
index 993c3354..0d2b4c3 100644
--- a/ios/chrome/browser/ui/send_tab_to_self/send_tab_to_self_table_view_controller.mm
+++ b/ios/chrome/browser/ui/send_tab_to_self/send_tab_to_self_table_view_controller.mm
@@ -6,6 +6,7 @@
 
 #include "base/logging.h"
 #include "base/mac/foundation_util.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/sys_string_conversions.h"
 #include "components/send_tab_to_self/send_tab_to_self_model.h"
@@ -37,6 +38,24 @@
 NSString* const kSendTabToSelfModalSendButton =
     @"kSendTabToSelfModalSendButton";
 
+// Per histograms.xml this records whether the user has clicked the item when it
+// is shown.
+const char kClickResultHistogramName[] = "SendTabToSelf.ShareMenu.ClickResult";
+// Per histograms.xml this records how many valid devices are shown when user
+// trigger to see the device list.
+const char kDeviceCountHistogramName[] = "SendTabToSelf.ShareMenu.DeviceCount";
+
+// TODO(crbug.com/970886): Move to a directory accessible on all platforms.
+// State of the send tab to self option in the context menu.
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class SendTabToSelfClickResult {
+  kShowItem = 0,
+  kClickItem = 1,
+  kShowDeviceList = 2,
+  kMaxValue = kShowDeviceList,
+};
+
 }  // namespace
 
 typedef NS_ENUM(NSInteger, SectionIdentifier) {
@@ -113,7 +132,6 @@
 
   TableViewModel* model = self.tableViewModel;
   [model addSectionWithIdentifier:SectionIdentifierDevicesToSend];
-
   for (auto iter = _target_device_map.begin(); iter != _target_device_map.end();
        ++iter) {
     int daysSinceLastUpdate =
@@ -166,6 +184,14 @@
       toSectionWithIdentifier:SectionIdentifierActionButton];
 }
 
+- (void)viewDidAppear:(BOOL)animated {
+  [super viewDidAppear:animated];
+  base::UmaHistogramEnumeration(kClickResultHistogramName,
+                                SendTabToSelfClickResult::kShowDeviceList);
+  base::UmaHistogramCounts100(kDeviceCountHistogramName,
+                              _target_device_map.size());
+}
+
 #pragma mark - UITableViewDataSource
 
 - (UITableViewCell*)tableView:(UITableView*)tableView
@@ -209,6 +235,8 @@
 #pragma mark - Helpers
 
 - (void)sendTabWhenPressed:(UIButton*)sender {
+  base::UmaHistogramEnumeration(kClickResultHistogramName,
+                                SendTabToSelfClickResult::kClickItem);
   [self.delegate sendTabToTargetDeviceCacheGUID:self.selectedItem.cacheGuid];
   [self.delegate dismissViewControllerAnimated:YES completion:nil];
 }
diff --git a/ios/chrome/browser/ui/settings/settings_root_table_view_controller.mm b/ios/chrome/browser/ui/settings/settings_root_table_view_controller.mm
index 9ec36c9..3ec1318 100644
--- a/ios/chrome/browser/ui/settings/settings_root_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/settings_root_table_view_controller.mm
@@ -118,7 +118,6 @@
     self.styler.tableViewBackgroundColor =
         UIColor.cr_systemGroupedBackgroundColor;
   }
-  self.styler.tableViewSectionHeaderBlurEffect = nil;
   [super viewDidLoad];
   if (base::FeatureList::IsEnabled(kSettingsRefresh)) {
     self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
diff --git a/ios/chrome/browser/ui/side_swipe/card_side_swipe_view.mm b/ios/chrome/browser/ui/side_swipe/card_side_swipe_view.mm
index daf2e48..84127db 100644
--- a/ios/chrome/browser/ui/side_swipe/card_side_swipe_view.mm
+++ b/ios/chrome/browser/ui/side_swipe/card_side_swipe_view.mm
@@ -11,7 +11,6 @@
 #include "base/metrics/user_metrics_action.h"
 #include "base/strings/sys_string_conversions.h"
 #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h"
-#import "ios/chrome/browser/tabs/tab.h"
 #import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/ui/side_swipe/side_swipe_gesture_recognizer.h"
 #import "ios/chrome/browser/ui/side_swipe/side_swipe_util.h"
@@ -22,8 +21,10 @@
 #include "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #import "ios/chrome/browser/web/page_placeholder_tab_helper.h"
+#import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/chrome/common/ui_util/constraints_ui_util.h"
 #include "ios/chrome/grit/ios_theme_resources.h"
+#import "ios/web/public/web_state/web_state.h"
 #include "url/gurl.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -52,8 +53,8 @@
 - (void)finishPan;
 // Is the current card is an edge card based on swipe direction.
 - (BOOL)isEdgeSwipe;
-// Initialize card based on model_ index.
-- (void)setupCard:(SwipeView*)card withIndex:(NSInteger)index;
+// Initialize card based on model_'s webstatelist index.
+- (void)setupCard:(SwipeView*)card withIndex:(int)index;
 // Build a |kResizeFactor| sized greyscaled version of |image|.
 - (UIImage*)smallGreyImage:(UIImage*)image;
 
@@ -137,11 +138,11 @@
   return CGRectGetWidth(self.bounds);
 }
 
-// Set up left and right card views depending on current tab and swipe
+// Set up left and right card views depending on current WebState and swipe
 // direction.
 - (void)updateViewsForDirection:(UISwipeGestureRecognizerDirection)direction {
   _direction = direction;
-  NSUInteger currentIndex = [model_ indexOfTab:model_.currentTab];
+  int currentIndex = model_.webStateList->active_index();
   CGFloat offset = UseRTLLayout() ? -1 : 1;
   if (_direction == UISwipeGestureRecognizerDirectionRight) {
     [self setupCard:_rightCard withIndex:currentIndex];
@@ -164,20 +165,20 @@
   return greyImage;
 }
 
-// Create card view based on TabModel index.
-- (void)setupCard:(SwipeView*)card withIndex:(NSInteger)index {
+// Create card view based on TabModel's WebStateList index.
+- (void)setupCard:(SwipeView*)card withIndex:(int)index {
   if (index < 0 || index >= (NSInteger)[model_ count]) {
     [card setHidden:YES];
     return;
   }
   [card setHidden:NO];
 
-  Tab* tab = [model_ tabAtIndex:index];
+  web::WebState* webState = model_.webStateList->GetWebStateAt(index);
   UIImage* topToolbarSnapshot = [self.topToolbarSnapshotProvider
-      toolbarSideSwipeSnapshotForWebState:tab.webState];
+      toolbarSideSwipeSnapshotForWebState:webState];
   [card setTopToolbarImage:topToolbarSnapshot];
   UIImage* bottomToolbarSnapshot = [self.bottomToolbarSnapshotProvider
-      toolbarSideSwipeSnapshotForWebState:tab.webState];
+      toolbarSideSwipeSnapshotForWebState:webState];
   [card setBottomToolbarImage:bottomToolbarSnapshot];
 
   // Converting snapshotted images to grey takes too much time for single core
@@ -185,9 +186,9 @@
   // grey image for multi core devices.
   dispatch_queue_t priorityQueue =
       dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
-  SnapshotTabHelper::FromWebState(tab.webState)
-      ->RetrieveColorSnapshot(^(UIImage* image) {
-        if (PagePlaceholderTabHelper::FromWebState(tab.webState)
+  SnapshotTabHelper::FromWebState(webState)->RetrieveColorSnapshot(
+      ^(UIImage* image) {
+        if (PagePlaceholderTabHelper::FromWebState(webState)
                 ->will_add_placeholder_for_next_navigation() &&
             !ios::device_util::IsSingleCoreDevice()) {
           [card setImage:nil];
@@ -259,24 +260,26 @@
 }
 
 - (BOOL)isEdgeSwipe {
-  NSUInteger currentIndex = [model_ indexOfTab:model_.currentTab];
+  int currentIndex = model_.webStateList->active_index();
   return (IsSwipingBack(_direction) && currentIndex == 0) ||
-         (IsSwipingForward(_direction) && currentIndex == [model_ count] - 1);
+         (IsSwipingForward(_direction) &&
+          currentIndex == model_.webStateList->count() - 1);
 }
 
-// Update the current tab and animate the proper card view if the
+// Update the current WebState and animate the proper card view if the
 // |currentPoint_| is past the center of |bounds|.
 - (void)finishPan {
-  NSUInteger currentIndex = [model_ indexOfTab:model_.currentTab];
-  // Something happened and now currentTab is gone.  End card side swipe and let
-  // BVC show no tabs UI.
-  if (currentIndex == NSNotFound)
+  WebStateList* webStateList = model_.webStateList;
+  int currentIndex = webStateList->active_index();
+  // Something happened and now there is not active WebState.  End card side let
+  // swipe and BVC show no tabs UI.
+  if (currentIndex == WebStateList::kInvalidIndex)
     return [_delegate sideSwipeViewDismissAnimationDidEnd:self];
 
   CGFloat width = [self cardWidth];
   CGAffineTransform rightTransform, leftTransform;
   SwipeView* dominantCard;
-  Tab* destinationTab = model_.currentTab;
+  int destinationWebStateIndex = currentIndex;
   CGFloat offset = UseRTLLayout() ? -1 : 1;
   if (_direction == UISwipeGestureRecognizerDirectionRight) {
     // If swipe is right and |currentPoint_.x| is over the first 1/3, move left.
@@ -284,7 +287,7 @@
       rightTransform =
           CGAffineTransformMakeTranslation(width + kCardHorizontalSpacing, 0);
       leftTransform = CGAffineTransformIdentity;
-      destinationTab = [model_ tabAtIndex:currentIndex - offset];
+      destinationWebStateIndex = currentIndex - offset;
       dominantCard = _leftCard;
       base::RecordAction(UserMetricsAction("MobileStackSwipeCompleted"));
     } else {
@@ -300,7 +303,7 @@
       leftTransform =
           CGAffineTransformMakeTranslation(-width - kCardHorizontalSpacing, 0);
       rightTransform = CGAffineTransformIdentity;
-      destinationTab = [model_ tabAtIndex:currentIndex + offset];
+      destinationWebStateIndex = currentIndex + offset;
       dominantCard = _rightCard;
       base::RecordAction(UserMetricsAction("MobileStackSwipeCompleted"));
     } else {
@@ -312,10 +315,10 @@
     }
   }
 
-  if (destinationTab != model_.currentTab) {
-    // The old tab is now hidden. The new tab will be inserted once the
-    // animation is complete.
-    model_.currentTab.webState->WasHidden();
+  if (destinationWebStateIndex != currentIndex) {
+    // The old webstate is now hidden. The new WebState will be inserted once
+    // the animation is complete.
+    webStateList->GetActiveWebState()->WasHidden();
   }
 
   // Make sure the dominant card animates on top.
@@ -334,12 +337,12 @@
         [_leftCard setBottomToolbarImage:nil];
         [_rightCard setBottomToolbarImage:nil];
         [_delegate sideSwipeViewDismissAnimationDidEnd:self];
-        // Changing the model even when the tab is the same at the end of the
-        // animation allows the UI to recover.  This call must come last,
-        // because setCurrentTab triggers behavior that depends on the view
+        // Changing the model even when the webstate is the same at the end of
+        // the animation allows the UI to recover.  This call must come last,
+        // because ActivateWebStateAt triggers behavior that depends on the view
         // hierarchy being reassembled, which happens in
         // sideSwipeViewDismissAnimationDidEnd.
-        [model_ setCurrentTab:destinationTab];
+        webStateList->ActivateWebStateAt(destinationWebStateIndex);
       }];
 }
 
diff --git a/ios/chrome/browser/ui/side_swipe/side_swipe_controller.mm b/ios/chrome/browser/ui/side_swipe/side_swipe_controller.mm
index 50f6203b..1baa1e9 100644
--- a/ios/chrome/browser/ui/side_swipe/side_swipe_controller.mm
+++ b/ios/chrome/browser/ui/side_swipe/side_swipe_controller.mm
@@ -13,7 +13,6 @@
 #import "ios/chrome/browser/snapshots/snapshot_cache.h"
 #import "ios/chrome/browser/snapshots/snapshot_cache_factory.h"
 #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h"
-#import "ios/chrome/browser/tabs/tab.h"
 #import "ios/chrome/browser/ui/fullscreen/animated_scoped_fullscreen_disabler.h"
 #import "ios/chrome/browser/ui/fullscreen/fullscreen_controller_factory.h"
 #import "ios/chrome/browser/ui/fullscreen/scoped_fullscreen_disabler.h"
@@ -80,7 +79,7 @@
   SideSwipeGestureRecognizer* panGestureRecognizer_;
 
   // Used in iPad side swipe gesture, tracks the starting tab index.
-  NSUInteger startingTabIndex_;
+  unsigned int startingTabIndex_;
 
   // If the swipe is for a page change or a tab change.
   SwipeType swipeType_;
@@ -309,11 +308,10 @@
     if (index == (NSInteger)startingTabIndex_)
       break;
 
-    Tab* tab = [model_ tabAtIndex:index];
-    if (tab && PagePlaceholderTabHelper::FromWebState(tab.webState)
-                   ->will_add_placeholder_for_next_navigation()) {
-      [sessionIDs
-          addObject:TabIdTabHelper::FromWebState(tab.webState)->tab_id()];
+    web::WebState* webState = model_.webStateList->GetWebStateAt(index);
+    if (webState && PagePlaceholderTabHelper::FromWebState(webState)
+                        ->will_add_placeholder_for_next_navigation()) {
+      [sessionIDs addObject:TabIdTabHelper::FromWebState(webState)->tab_id()];
     }
     index = index + dx;
   }
@@ -365,7 +363,7 @@
         postNotificationName:kSideSwipeWillStartNotification
                       object:nil];
     [self.tabStripDelegate setHighlightsSelectedTab:YES];
-    startingTabIndex_ = [model_ indexOfTab:[model_ currentTab]];
+    startingTabIndex_ = model_.webStateList->active_index();
     [self createGreyCache:gesture.direction];
   } else if (gesture.state == UIGestureRecognizerStateChanged) {
     // Side swipe for iPad involves changing the selected tab as the swipe moves
@@ -379,41 +377,43 @@
       distance -= gesture.startPoint.x;
     }
 
-    NSInteger indexDelta = std::floor(distance / kIpadTabSwipeDistance);
+    int indexDelta = std::floor(distance / kIpadTabSwipeDistance);
     // Don't wrap past the first tab.
     if (indexDelta < count) {
       // Flip delta when swiping forward.
       if (IsSwipingForward(gesture.direction))
         indexDelta = 0 - indexDelta;
 
-      Tab* currentTab = [model_ currentTab];
-      NSInteger currentIndex = [model_ indexOfTab:currentTab];
-
+      web::WebState* currentWebState = self.activeWebState;
+      int currentIndex =
+          model_.webStateList->GetIndexOfWebState(currentWebState);
+      DCHECK_GE(currentIndex, 0);
       // Wrap around edges.
-      NSInteger newIndex = (NSInteger)(startingTabIndex_ + indexDelta) % count;
+      int newIndex = (int)(startingTabIndex_ + indexDelta) % count;
 
       // C99 defines the modulo result as negative if our offset is negative.
       if (newIndex < 0)
         newIndex += count;
 
       if (newIndex != currentIndex) {
-        Tab* tab = [model_ tabAtIndex:newIndex];
+        web::WebState* webState = model_.webStateList->GetWebStateAt(newIndex);
         // Toggle overlay preview mode for selected tab.
-        PagePlaceholderTabHelper::FromWebState(tab.webState)
+        PagePlaceholderTabHelper::FromWebState(webState)
             ->AddPlaceholderForNextNavigation();
-        [model_ setCurrentTab:tab];
+        model_.webStateList->ActivateWebStateAt(newIndex);
 
         // And disable overlay preview mode for last selected tab.
-        PagePlaceholderTabHelper::FromWebState(currentTab.webState)
+        PagePlaceholderTabHelper::FromWebState(currentWebState)
             ->CancelPlaceholderForNextNavigation();
       }
     }
   } else {
     if (gesture.state == UIGestureRecognizerStateCancelled) {
-      Tab* tab = [model_ tabAtIndex:startingTabIndex_];
-      PagePlaceholderTabHelper::FromWebState(tab.webState)
+      web::WebState* webState =
+          model_.webStateList->GetWebStateAt(startingTabIndex_);
+      PagePlaceholderTabHelper::FromWebState(webState)
           ->CancelPlaceholderForNextNavigation();
-      [model_ setCurrentTab:tab];
+      model_.webStateList->ActivateWebStateAt(startingTabIndex_);
     }
     PagePlaceholderTabHelper::FromWebState(self.activeWebState)
         ->CancelPlaceholderForNextNavigation();
diff --git a/ios/chrome/browser/ui/tab_grid/grid/grid_constants.h b/ios/chrome/browser/ui/tab_grid/grid/grid_constants.h
index e22756c..cc08f25 100644
--- a/ios/chrome/browser/ui/tab_grid/grid/grid_constants.h
+++ b/ios/chrome/browser/ui/tab_grid/grid/grid_constants.h
@@ -71,6 +71,11 @@
 extern const int kGridDarkThemeCellCloseButtonTintColor;
 extern const CGFloat kGridDarkThemeCellHighlightColorAlpha;
 extern const int kGridDarkThemeCellSeparatorColor;
+// TODO (crbug.com/981889): remove with iOS 12.
+// Extra dark theme colors until iOS 12 gets removed.
+extern const int kGridDarkThemeCellDetailColor;
+extern const CGFloat kGridDarkThemeCellDetailAlpha;
+extern const int kGridDarkThemeCellTintColor;
 
 // GridCell dimensions.
 extern const CGSize kGridCellSizeSmall;
diff --git a/ios/chrome/browser/ui/tab_grid/grid/grid_constants.mm b/ios/chrome/browser/ui/tab_grid/grid/grid_constants.mm
index 04fae2837..00d0469 100644
--- a/ios/chrome/browser/ui/tab_grid/grid/grid_constants.mm
+++ b/ios/chrome/browser/ui/tab_grid/grid/grid_constants.mm
@@ -64,6 +64,10 @@
 const int kGridDarkThemeCellCloseButtonTintColor = 0xFFFFFF;
 const CGFloat kGridDarkThemeCellHighlightColorAlpha = 0.7;
 const int kGridDarkThemeCellSeparatorColor = 0x535354;
+// Extra dark theme colors until iOS 12 gets removed.
+const int kGridDarkThemeCellDetailColor = 0xEBEBF5;
+const CGFloat kGridDarkThemeCellDetailAlpha = 0.6;
+const int kGridDarkThemeCellTintColor = 0x8AB4F9;
 
 // GridCell dimensions.
 const CGSize kGridCellSizeSmall = CGSize{144.0f, 168.0f};
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
index e0e34098..db11b14 100644
--- a/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
@@ -654,13 +654,28 @@
   // TODO(crbug.com/804589) : Dark style on remote tabs.
   // The styler must be set before the view controller is loaded.
   ChromeTableViewStyler* styler = [[ChromeTableViewStyler alloc] init];
-  styler.tableViewSectionHeaderBlurEffect = nil;
   styler.tableViewBackgroundColor = UIColorFromRGB(kGridBackgroundColor);
-  styler.cellTitleColor = UIColorFromRGB(kGridDarkThemeCellTitleColor);
-  styler.headerFooterTitleColor = UIColorFromRGB(kGridDarkThemeCellTitleColor);
   styler.cellHighlightColor =
       [UIColor colorWithWhite:0 alpha:kGridDarkThemeCellHighlightColorAlpha];
-  styler.cellSeparatorColor = UIColorFromRGB(kGridDarkThemeCellSeparatorColor);
+  // For iOS 13, setting the overrideUserInterfaceStyle to dark forces the use
+  // of dark mode colors for all the colors in this view. However, this
+  // override is not available on pre-iOS 13 devices, so the dark mode colors
+  // must be provided manually.
+  if (@available(iOS 13, *)) {
+#if defined(__IPHONE_13_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0)
+    self.remoteTabsViewController.overrideUserInterfaceStyle =
+        UIUserInterfaceStyleDark;
+#endif
+  } else {
+    styler.cellTitleColor = UIColorFromRGB(kGridDarkThemeCellTitleColor);
+    styler.headerFooterTitleColor =
+        UIColorFromRGB(kGridDarkThemeCellTitleColor);
+    styler.cellDetailColor = UIColorFromRGB(kGridDarkThemeCellDetailColor,
+                                            kGridDarkThemeCellDetailAlpha);
+    styler.headerFooterDetailColor = UIColorFromRGB(
+        kGridDarkThemeCellDetailColor, kGridDarkThemeCellDetailAlpha);
+    styler.tintColor = UIColorFromRGB(kGridDarkThemeCellTintColor);
+  }
   self.remoteTabsViewController.styler = styler;
 
   UIView* contentView = self.scrollContentView;
diff --git a/ios/chrome/browser/ui/table_view/BUILD.gn b/ios/chrome/browser/ui/table_view/BUILD.gn
index ffe51bf..e6471f21 100644
--- a/ios/chrome/browser/ui/table_view/BUILD.gn
+++ b/ios/chrome/browser/ui/table_view/BUILD.gn
@@ -40,6 +40,7 @@
   ]
   public_deps = [
     "//ios/chrome/browser/ui/util",
+    "//ios/chrome/common/colors",
   ]
 }
 
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_disclosure_header_footer_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_disclosure_header_footer_item.mm
index 6bd69c8f..4dd91b2 100644
--- a/ios/chrome/browser/ui/table_view/cells/table_view_disclosure_header_footer_item.mm
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_disclosure_header_footer_item.mm
@@ -51,6 +51,8 @@
   [header setInitialDirection:direction];
   if (styler.headerFooterTitleColor)
     header.titleLabel.textColor = styler.headerFooterTitleColor;
+  if (styler.headerFooterDetailColor)
+    header.subtitleLabel.textColor = styler.headerFooterDetailColor;
   if (styler.cellHighlightColor)
     header.highlightColor = styler.cellHighlightColor;
 }
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_header_footer_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_header_footer_item.mm
index 6571c43..d3fc1a9a 100644
--- a/ios/chrome/browser/ui/table_view/cells/table_view_header_footer_item.mm
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_header_footer_item.mm
@@ -25,14 +25,9 @@
   DCHECK([headerFooter class] == self.cellClass);
   headerFooter.accessibilityTraits = self.accessibilityTraits;
   headerFooter.accessibilityIdentifier = self.accessibilityIdentifier;
-  // Use the styler tableViewSectionHeaderBlurEffect if available, if not use
-  // the styler tableViewBackgroundColor (as a performance optimization) if
+  // Use the styler tableViewBackgroundColor (as a performance optimization) if
   // available.
-  if (styler.tableViewSectionHeaderBlurEffect) {
-    UIVisualEffectView* visualEffect = [[UIVisualEffectView alloc]
-        initWithEffect:styler.tableViewSectionHeaderBlurEffect];
-    headerFooter.backgroundView = visualEffect;
-  } else if (styler.tableViewBackgroundColor) {
+  if (styler.tableViewBackgroundColor) {
     UIView* backgroundView = [[UIView alloc] init];
     backgroundView.backgroundColor = styler.tableViewBackgroundColor;
     headerFooter.backgroundView = backgroundView;
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_url_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_url_item.mm
index 18cc993..f50feeb 100644
--- a/ios/chrome/browser/ui/table_view/cells/table_view_url_item.mm
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_url_item.mm
@@ -76,6 +76,10 @@
 
   if (styler.cellTitleColor)
     cell.titleLabel.textColor = styler.cellTitleColor;
+  if (styler.cellDetailColor) {
+    cell.URLLabel.textColor = styler.cellDetailColor;
+    cell.metadataLabel.textColor = styler.cellDetailColor;
+  }
 
   [cell configureUILayout];
 }
diff --git a/ios/chrome/browser/ui/table_view/chrome_table_view_styler.h b/ios/chrome/browser/ui/table_view/chrome_table_view_styler.h
index acd34194..0e9e8c17 100644
--- a/ios/chrome/browser/ui/table_view/chrome_table_view_styler.h
+++ b/ios/chrome/browser/ui/table_view/chrome_table_view_styler.h
@@ -9,10 +9,6 @@
 
 @interface ChromeTableViewStyler : NSObject
 
-// The BlurEffect used on the UITableView section headers.
-@property(nonatomic, readwrite, strong)
-    UIBlurEffect* tableViewSectionHeaderBlurEffect;
-
 // The background color for the table view and its cells. If this is set to an
 // opaque color, cells can choose to make themselves opaque and draw their own
 // background as a performance optimization.
@@ -25,9 +21,18 @@
 @property(nonatomic, readwrite, strong) UIColor* headerFooterTitleColor;
 // Cell highlight color.
 @property(nonatomic, readwrite, strong) UIColor* cellHighlightColor;
-// Color of cell separator line. If not set, defaults to 0xC8C7CC.
+// Color of cell separator line. If not set, defaults to the default UIKit
+// color.
 @property(nonatomic, readwrite, strong) UIColor* cellSeparatorColor;
 
+// TODO (crbug.com/981889): Remove with iOS 12.
+// Color overrides. These should not be in general use, but
+// are necessary to provide colors on pre-iOS 13 devices for screens that are
+// always in dark mode. They can be removed then.
+@property(nonatomic, readwrite, strong) UIColor* cellDetailColor;
+@property(nonatomic, readwrite, strong) UIColor* headerFooterDetailColor;
+@property(nonatomic, readwrite, strong) UIColor* tintColor;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_TABLE_VIEW_CHROME_TABLE_VIEW_STYLER_H_
diff --git a/ios/chrome/browser/ui/table_view/chrome_table_view_styler.mm b/ios/chrome/browser/ui/table_view/chrome_table_view_styler.mm
index b09b78d..20937b4d 100644
--- a/ios/chrome/browser/ui/table_view/chrome_table_view_styler.mm
+++ b/ios/chrome/browser/ui/table_view/chrome_table_view_styler.mm
@@ -5,39 +5,17 @@
 #import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h"
 
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
+#import "ios/chrome/common/colors/UIColor+cr_semantic_colors.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
-namespace {
-// The width and height of the favicon ImageView.
-const int kTableViewBackgroundRGBColor = 0xF9F9F9;
-// The default color used to highlight tableview cells.
-const CGFloat kTableViewHighlightColorAlpha = 0.05;
-// The default cell separator color.
-const CGFloat kDefaultTableViewSeparatorColor = 0xC8C7CC;
-}
-
 @implementation ChromeTableViewStyler
-@synthesize cellSeparatorColor = _cellSeparatorColor;
-@synthesize tableViewSectionHeaderBlurEffect =
-    _tableViewSectionHeaderBlurEffect;
-@synthesize tableViewBackgroundColor = _tableViewBackgroundColor;
-@synthesize cellBackgroundColor = _cellBackgroundColor;
-@synthesize cellTitleColor = _cellTitleColor;
-@synthesize headerFooterTitleColor = _headerFooterTitleColor;
-@synthesize cellHighlightColor = _cellHighlightColor;
 
 - (instancetype)init {
   if ((self = [super init])) {
-    _tableViewBackgroundColor = UIColorFromRGB(kTableViewBackgroundRGBColor, 1);
-    _cellSeparatorColor = UIColorFromRGB(kDefaultTableViewSeparatorColor, 1);
-    _tableViewSectionHeaderBlurEffect =
-        [UIBlurEffect effectWithStyle:UIBlurEffectStyleExtraLight];
-
-    _cellHighlightColor =
-        [UIColor colorWithWhite:0 alpha:kTableViewHighlightColorAlpha];
+    _tableViewBackgroundColor = UIColor.cr_systemBackgroundColor;
   }
   return self;
 }
diff --git a/ios/chrome/browser/ui/tabs/tab_strip_controller.mm b/ios/chrome/browser/ui/tabs/tab_strip_controller.mm
index 7063bb3..3c7ab1e 100644
--- a/ios/chrome/browser/ui/tabs/tab_strip_controller.mm
+++ b/ios/chrome/browser/ui/tabs/tab_strip_controller.mm
@@ -22,7 +22,6 @@
 #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h"
 #include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/tabs/legacy_tab_helper.h"
-#import "ios/chrome/browser/tabs/tab.h"
 #import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/tabs/tab_title_util.h"
 #import "ios/chrome/browser/ui/bubble/bubble_util.h"
@@ -779,10 +778,9 @@
 
   // Install the dimming view, hide the new tab button, and select the tab so it
   // appears highlighted.
-  Tab* tab = [_tabModel tabAtIndex:index];
   self.highlightsSelectedTab = YES;
   _buttonNewTab.hidden = YES;
-  [_tabModel setCurrentTab:tab];
+  _tabModel.webStateList->ActivateWebStateAt(index);
 
   // Set up initial drag state.
   _lastDragLocation = [gesture locationInView:[_tabStripView superview]];
@@ -842,15 +840,14 @@
     return;
   }
 
-  Tab* tab = [_tabModel tabAtIndex:fromIndex];
   NSUInteger toIndex = _placeholderGapModelIndex;
   DCHECK_NE(NSNotFound, static_cast<NSInteger>(toIndex));
   DCHECK_LT(toIndex, [_tabModel count]);
 
   // Reset drag state variables before notifying the model that the tab moved.
   [self resetDragState];
-
-  [_tabModel moveTab:tab toIndex:toIndex];
+  _tabModel.webStateList->MoveWebStateAt(static_cast<int>(fromIndex),
+                                         static_cast<int>(toIndex));
   [self setNeedsLayoutWithAnimation];
 }
 
@@ -1470,7 +1467,8 @@
                                              : [self tabStripVisibleSpace];
 
   // The array and model indexes of the selected tab.
-  NSUInteger selectedModelIndex = [_tabModel indexOfTab:[_tabModel currentTab]];
+  NSUInteger selectedModelIndex =
+      static_cast<NSUInteger>(_tabModel.webStateList->active_index());
   NSUInteger selectedArrayIndex = [self indexForModelIndex:selectedModelIndex];
 
   // This method lays out tabs in two coordinate systems.  The first, the
diff --git a/ios/chrome/browser/ui/tabs/tab_strip_controller_unittest.mm b/ios/chrome/browser/ui/tabs/tab_strip_controller_unittest.mm
index ffa2987..11dec9e 100644
--- a/ios/chrome/browser/ui/tabs/tab_strip_controller_unittest.mm
+++ b/ios/chrome/browser/ui/tabs/tab_strip_controller_unittest.mm
@@ -10,7 +10,6 @@
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #import "ios/chrome/browser/sessions/test_session_service.h"
 #import "ios/chrome/browser/tabs/legacy_tab_helper.h"
-#import "ios/chrome/browser/tabs/tab.h"
 #import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/ui/tabs/tab_strip_controller.h"
 #import "ios/chrome/browser/ui/tabs/tab_strip_view.h"
@@ -106,25 +105,6 @@
   return tab;
 }
 
-- (Tab*)currentTab {
-  web::WebState* activeWebState = _webStateList->GetActiveWebState();
-  return activeWebState ? LegacyTabHelper::GetTabForWebState(activeWebState)
-                        : nil;
-}
-
-- (Tab*)tabAtIndex:(NSUInteger)index {
-  DCHECK(index < static_cast<NSUInteger>(INT_MAX));
-  DCHECK(static_cast<int>(index) < _webStateList->count());
-  return LegacyTabHelper::GetTabForWebState(
-      _webStateList->GetWebStateAt(static_cast<int>(index)));
-}
-
-- (NSUInteger)indexOfTab:(Tab*)tab {
-  const int index = _webStateList->GetIndexOfWebState(tab.webState);
-  return index == WebStateList::kInvalidIndex ? NSNotFound
-                                              : static_cast<NSUInteger>(index);
-}
-
 - (BOOL)isEmpty {
   return _webStateList->empty();
 }
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_egtest.mm b/ios/chrome/browser/ui/toolbar/toolbar_egtest.mm
index 34c759c..9d34780 100644
--- a/ios/chrome/browser/ui/toolbar/toolbar_egtest.mm
+++ b/ios/chrome/browser/ui/toolbar/toolbar_egtest.mm
@@ -299,11 +299,6 @@
 
 // Types JavaScript into Omnibox and verify that an alert is displayed.
 - (void)testTypeJavaScriptIntoOmnibox {
-  // TODO(crbug.com/642544): Enable the test for iPad when typing bug is fixed.
-  if ([ChromeEarlGrey isIPadIdiom]) {
-    EARL_GREY_TEST_DISABLED(@"Disabled for iPad due to a typing bug.");
-  }
-
   std::map<GURL, std::string> responses;
   GURL URL = web::test::HttpServer::MakeUrl("http://foo");
   responses[URL] = "bar";
@@ -320,10 +315,6 @@
 // not displayed. WebUI pages have elevated privileges and should not allow
 // script execution.
 - (void)testTypeJavaScriptIntoOmniboxWithWebUIPage {
-  // TODO(crbug.com/642544): Enable the test for iPad when typing bug is fixed.
-  if ([ChromeEarlGrey isIPadIdiom]) {
-    EARL_GREY_TEST_DISABLED(@"Disabled for iPad due to a typing bug.");
-  }
   [ChromeEarlGrey loadURL:GURL("chrome://version")];
   [ChromeEarlGreyUI focusOmniboxAndType:@"javascript:alert('Hello');\n"];
 
diff --git a/ios/chrome/browser/url_loading/app_url_loading_service.mm b/ios/chrome/browser/url_loading/app_url_loading_service.mm
index cf9eb0e..936436c 100644
--- a/ios/chrome/browser/url_loading/app_url_loading_service.mm
+++ b/ios/chrome/browser/url_loading/app_url_loading_service.mm
@@ -7,11 +7,12 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/main/browser.h"
 #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h"
-#import "ios/chrome/browser/tabs/tab.h"
 #import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/url_loading/url_loading_params.h"
 #import "ios/chrome/browser/url_loading/url_loading_service.h"
 #import "ios/chrome/browser/url_loading/url_loading_service_factory.h"
+#import "ios/chrome/browser/web_state_list/web_state_list.h"
+#import "ios/web/public/web_state/web_state.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -56,9 +57,10 @@
                                                params.in_incognito) {
       // Must take a snapshot of the tab before we switch the incognito mode
       // because the currentTab will change after the switch.
-      Tab* currentTab = [delegate_ currentTabModel].currentTab;
-      if (currentTab) {
-        SnapshotTabHelper::FromWebState(currentTab.webState)
+      web::WebState* currentWebState =
+          [delegate_ currentTabModel].webStateList->GetActiveWebState();
+      if (currentWebState) {
+        SnapshotTabHelper::FromWebState(currentWebState)
             ->UpdateSnapshotWithCallback(nil);
       }
 
diff --git a/ios/chrome/common/colors/UIColor+cr_semantic_colors.h b/ios/chrome/common/colors/UIColor+cr_semantic_colors.h
index 65a3619..9ceee5f 100644
--- a/ios/chrome/common/colors/UIColor+cr_semantic_colors.h
+++ b/ios/chrome/common/colors/UIColor+cr_semantic_colors.h
@@ -10,6 +10,7 @@
 // This category wraps the Apple-provided semantic colors because many of them
 // are only available in iOS 13. Only these wrapper functions should be added
 // to this file. Custom dynamic colors should go in ColorSets.
+// TODO (crbug.com/981889): Remove along with iOS 12.
 @interface UIColor (CRSemanticColors)
 
 // System Background Color
diff --git a/ios/chrome/test/earl_grey2/smoke_egtest.mm b/ios/chrome/test/earl_grey2/smoke_egtest.mm
index ad27d01b..7f14120 100644
--- a/ios/chrome/test/earl_grey2/smoke_egtest.mm
+++ b/ios/chrome/test/earl_grey2/smoke_egtest.mm
@@ -186,4 +186,10 @@
   [ChromeEarlGrey deleteHistoryServiceTypedURL:mockURL];
 }
 
+// Tests accessibility util converted helper in chrome_earl_grey.h.
+- (void)testAccessibilityUtil {
+  [ChromeEarlGrey loadURL:GURL("chrome://version")];
+  [ChromeEarlGrey verifyAccessibilityForCurrentScreen];
+}
+
 @end
diff --git a/ios/chrome/test/wpt/tools/run_cwt_chromedriver.py b/ios/chrome/test/wpt/tools/run_cwt_chromedriver.py
new file mode 100755
index 0000000..8906df91
--- /dev/null
+++ b/ios/chrome/test/wpt/tools/run_cwt_chromedriver.py
@@ -0,0 +1,66 @@
+#!/usr/bin/python
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import argparse
+import os
+import sys
+import subprocess
+import time
+
+def GetChromiumSrcDir():
+  return os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir,
+                                      os.pardir, os.pardir, os.pardir,
+                                      os.pardir))
+
+def GetIosDir():
+  return os.path.join(GetChromiumSrcDir(), 'ios')
+
+sys.path.append(os.path.join(GetIosDir(), 'build', 'bots', 'scripts'))
+
+import xcodebuild_runner
+
+def GetDefaultBuildDir():
+  return os.path.join(GetChromiumSrcDir(), 'out', 'Debug-iphonesimulator')
+
+parser=argparse.ArgumentParser(
+    formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+parser.add_argument('--port', default='9999',
+    help='The port to listen on for WebDriver commands')
+parser.add_argument('--build-dir', default=GetDefaultBuildDir(),
+    help='Chrome build directory')
+parser.add_argument('--out-dir', default='/tmp/cwt_chromedriver',
+    help='Output directory for CWTChromeDriver\'s dummy test case')
+parser.add_argument('--os', default='12.2', help='iOS version')
+parser.add_argument('--device', default='iPhone 8', help='Device type')
+args=parser.parse_args()
+
+test_app = os.path.join(
+    args.build_dir, 'ios_cwt_chromedriver_tests_module-Runner.app')
+host_app = os.path.join(args.build_dir, 'ios_cwt_chromedriver_tests.app')
+destination = 'platform=iOS Simulator,OS=%s,name=%s' % (args.os, args.device)
+
+# Shutdown running simulators. This is needed since a running simulator may
+# be in a hung state.
+# TODO(crbug.com/673423): Change this logic to only shut down the simulator that
+# will be used for this run, when adding support for running multiple instances
+# of CWTChromeDriver.
+subprocess.check_call(['xcrun', 'simctl', 'shutdown', 'booted'])
+
+if not os.path.exists(args.out_dir):
+  os.mkdir(args.out_dir)
+
+# Make sure each run produces a unique output directory, since reusing an
+# existing directory will cause CWTChromeDriver's dummy test case to get
+# skipped, meaning that CWTChromeDriver's http server won't get launched.
+output_directory = os.path.join(args.out_dir, 'run%d' %  int(time.time()))
+
+egtests_app = xcodebuild_runner.EgtestsApp(
+    egtests_app=test_app, test_args=['--port %s' % args.port],
+    host_app_path=host_app, invert=True)
+
+launch_command = xcodebuild_runner.LaunchCommand(egtests_app, destination,
+    shards=1, retries=1, out_dir=output_directory)
+
+launch_command.launch()
diff --git a/media/gpu/v4l2/v4l2_slice_video_decoder.h b/media/gpu/v4l2/v4l2_slice_video_decoder.h
index c540ee06..64eab649 100644
--- a/media/gpu/v4l2/v4l2_slice_video_decoder.h
+++ b/media/gpu/v4l2/v4l2_slice_video_decoder.h
@@ -234,13 +234,13 @@
   // Next bitstream ID.
   int32_t next_bitstream_buffer_id_ = 0;
 
+  SEQUENCE_CHECKER(client_sequence_checker_);
+  SEQUENCE_CHECKER(decoder_sequence_checker_);
+
   // |weak_this_| must be dereferenced and invalidated on
   // |decoder_task_runner_|.
   base::WeakPtr<V4L2SliceVideoDecoder> weak_this_;
   base::WeakPtrFactory<V4L2SliceVideoDecoder> weak_this_factory_;
-
-  SEQUENCE_CHECKER(client_sequence_checker_);
-  SEQUENCE_CHECKER(decoder_sequence_checker_);
 };
 
 }  // namespace media
diff --git a/mojo/core/trap_unittest.cc b/mojo/core/trap_unittest.cc
index 309e5476..b7ae4f3 100644
--- a/mojo/core/trap_unittest.cc
+++ b/mojo/core/trap_unittest.cc
@@ -1486,6 +1486,10 @@
       [](MojoHandle b) { WriteMessage(b, kTestMessageToA); }, b));
   runner.Start();
 
+  // To enforce that the two traps run concurrently, wait until the WriteMessage
+  // above has made a readable before firing the readable trap on b.
+  wait_for_a_to_notify.Wait();
+
   WriteMessage(a, kTestMessageToB);
 
   wait_for_a_to_cancel.Wait();
diff --git a/net/base/chunked_upload_data_stream.cc b/net/base/chunked_upload_data_stream.cc
index f7e2a66..f4db7d7 100644
--- a/net/base/chunked_upload_data_stream.cc
+++ b/net/base/chunked_upload_data_stream.cc
@@ -31,8 +31,7 @@
       read_index_(0),
       read_offset_(0),
       all_data_appended_(false),
-      read_buffer_len_(0),
-      weak_factory_(this) {}
+      read_buffer_len_(0) {}
 
 ChunkedUploadDataStream::~ChunkedUploadDataStream() = default;
 
diff --git a/net/base/chunked_upload_data_stream.h b/net/base/chunked_upload_data_stream.h
index 65da00d..50f644f 100644
--- a/net/base/chunked_upload_data_stream.h
+++ b/net/base/chunked_upload_data_stream.h
@@ -98,7 +98,7 @@
   scoped_refptr<IOBuffer> read_buffer_;
   int read_buffer_len_;
 
-  base::WeakPtrFactory<ChunkedUploadDataStream> weak_factory_;
+  base::WeakPtrFactory<ChunkedUploadDataStream> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(ChunkedUploadDataStream);
 };
diff --git a/net/base/elements_upload_data_stream.cc b/net/base/elements_upload_data_stream.cc
index 9465b746..5cc6590 100644
--- a/net/base/elements_upload_data_stream.cc
+++ b/net/base/elements_upload_data_stream.cc
@@ -19,8 +19,7 @@
     : UploadDataStream(false, identifier),
       element_readers_(std::move(element_readers)),
       element_index_(0),
-      read_error_(OK),
-      weak_ptr_factory_(this) {}
+      read_error_(OK) {}
 
 ElementsUploadDataStream::~ElementsUploadDataStream() = default;
 
diff --git a/net/base/elements_upload_data_stream.h b/net/base/elements_upload_data_stream.h
index 4ad4048..ba8f9457 100644
--- a/net/base/elements_upload_data_stream.h
+++ b/net/base/elements_upload_data_stream.h
@@ -80,7 +80,7 @@
   // Set to actual error if read fails, otherwise set to net::OK.
   int read_error_;
 
-  base::WeakPtrFactory<ElementsUploadDataStream> weak_ptr_factory_;
+  base::WeakPtrFactory<ElementsUploadDataStream> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(ElementsUploadDataStream);
 };
diff --git a/net/base/mock_file_stream.cc b/net/base/mock_file_stream.cc
index 4cff945..64104ee 100644
--- a/net/base/mock_file_stream.cc
+++ b/net/base/mock_file_stream.cc
@@ -20,9 +20,7 @@
     : FileStream(task_runner),
       forced_error_(OK),
       async_error_(false),
-      throttled_(false),
-      weak_factory_(this) {
-}
+      throttled_(false) {}
 
 MockFileStream::MockFileStream(
     base::File file,
@@ -30,8 +28,7 @@
     : FileStream(std::move(file), task_runner),
       forced_error_(OK),
       async_error_(false),
-      throttled_(false),
-      weak_factory_(this) {}
+      throttled_(false) {}
 
 MockFileStream::~MockFileStream() = default;
 
diff --git a/net/base/mock_file_stream.h b/net/base/mock_file_stream.h
index 9f1eb98..fba7843 100644
--- a/net/base/mock_file_stream.h
+++ b/net/base/mock_file_stream.h
@@ -98,7 +98,7 @@
   base::OnceClosure throttled_task_;
   base::FilePath path_;
 
-  base::WeakPtrFactory<MockFileStream> weak_factory_;
+  base::WeakPtrFactory<MockFileStream> weak_factory_{this};
 };
 
 }  // namespace testing
diff --git a/net/base/upload_file_element_reader.cc b/net/base/upload_file_element_reader.cc
index adf4e74..b3936000 100644
--- a/net/base/upload_file_element_reader.cc
+++ b/net/base/upload_file_element_reader.cc
@@ -38,8 +38,7 @@
       content_length_(0),
       bytes_remaining_(0),
       next_state_(State::IDLE),
-      init_called_while_operation_pending_(false),
-      weak_ptr_factory_(this) {
+      init_called_while_operation_pending_(false) {
   DCHECK(file.IsValid());
   DCHECK(task_runner_.get());
   file_stream_ = std::make_unique<FileStream>(std::move(file), task_runner);
@@ -59,8 +58,7 @@
       content_length_(0),
       bytes_remaining_(0),
       next_state_(State::IDLE),
-      init_called_while_operation_pending_(false),
-      weak_ptr_factory_(this) {
+      init_called_while_operation_pending_(false) {
   DCHECK(task_runner_.get());
 }
 
diff --git a/net/base/upload_file_element_reader.h b/net/base/upload_file_element_reader.h
index 190bbc4..706137af 100644
--- a/net/base/upload_file_element_reader.h
+++ b/net/base/upload_file_element_reader.h
@@ -129,7 +129,7 @@
   // True if Init() was called while an async operation was in progress.
   bool init_called_while_operation_pending_;
 
-  base::WeakPtrFactory<UploadFileElementReader> weak_ptr_factory_;
+  base::WeakPtrFactory<UploadFileElementReader> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(UploadFileElementReader);
 };
diff --git a/net/cert/mock_cert_verifier.cc b/net/cert/mock_cert_verifier.cc
index 3a5161f..e65dadb 100644
--- a/net/cert/mock_cert_verifier.cc
+++ b/net/cert/mock_cert_verifier.cc
@@ -43,7 +43,7 @@
 class MockCertVerifier::MockRequest : public CertVerifier::Request {
  public:
   MockRequest(CertVerifyResult* result, CompletionOnceCallback callback)
-      : result_(result), callback_(std::move(callback)), weak_factory_(this) {}
+      : result_(result), callback_(std::move(callback)) {}
 
   void ReturnResultLater(int rv, const CertVerifyResult& result) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -59,7 +59,7 @@
 
   CertVerifyResult* result_;
   CompletionOnceCallback callback_;
-  base::WeakPtrFactory<MockRequest> weak_factory_;
+  base::WeakPtrFactory<MockRequest> weak_factory_{this};
 };
 
 MockCertVerifier::MockCertVerifier()
diff --git a/net/cert/multi_threaded_cert_verifier.cc b/net/cert/multi_threaded_cert_verifier.cc
index 531aa0e..e2c6013 100644
--- a/net/cert/multi_threaded_cert_verifier.cc
+++ b/net/cert/multi_threaded_cert_verifier.cc
@@ -221,8 +221,7 @@
         net_log_(NetLogWithSource::Make(net_log,
                                         NetLogSourceType::CERT_VERIFIER_JOB)),
         cert_verifier_(cert_verifier),
-        is_first_job_(false),
-        weak_ptr_factory_(this) {
+        is_first_job_(false) {
     net_log_.BeginEvent(NetLogEventType::CERT_VERIFIER_JOB,
                         base::Bind(&NetLogX509CertificateCallback,
                                    base::Unretained(key.certificate().get())));
@@ -345,7 +344,7 @@
   MultiThreadedCertVerifier* cert_verifier_;  // Non-owned.
 
   bool is_first_job_;
-  base::WeakPtrFactory<CertVerifierJob> weak_ptr_factory_;
+  base::WeakPtrFactory<CertVerifierJob> weak_ptr_factory_{this};
 };
 
 MultiThreadedCertVerifier::MultiThreadedCertVerifier(
diff --git a/net/cert/nss_cert_database.cc b/net/cert/nss_cert_database.cc
index bc966fbe..56dd127 100644
--- a/net/cert/nss_cert_database.cc
+++ b/net/cert/nss_cert_database.cc
@@ -70,8 +70,7 @@
                                  crypto::ScopedPK11Slot private_slot)
     : public_slot_(std::move(public_slot)),
       private_slot_(std::move(private_slot)),
-      observer_list_(new base::ObserverListThreadSafe<Observer>),
-      weak_factory_(this) {
+      observer_list_(new base::ObserverListThreadSafe<Observer>) {
   CHECK(public_slot_);
 
   CertDatabase* cert_db = CertDatabase::GetInstance();
diff --git a/net/cert/nss_cert_database.h b/net/cert/nss_cert_database.h
index cee2f01..97be8c4 100644
--- a/net/cert/nss_cert_database.h
+++ b/net/cert/nss_cert_database.h
@@ -282,7 +282,7 @@
 
   const scoped_refptr<base::ObserverListThreadSafe<Observer>> observer_list_;
 
-  base::WeakPtrFactory<NSSCertDatabase> weak_factory_;
+  base::WeakPtrFactory<NSSCertDatabase> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(NSSCertDatabase);
 };
diff --git a/net/cert/x509_certificate.cc b/net/cert/x509_certificate.cc
index a5d16167..6973f4a 100644
--- a/net/cert/x509_certificate.cc
+++ b/net/cert/x509_certificate.cc
@@ -37,6 +37,7 @@
 #include "net/cert/x509_util.h"
 #include "net/der/encode_values.h"
 #include "net/der/parser.h"
+#include "net/dns/dns_util.h"
 #include "third_party/boringssl/src/include/openssl/evp.h"
 #include "third_party/boringssl/src/include/openssl/pkcs7.h"
 #include "third_party/boringssl/src/include/openssl/pool.h"
@@ -475,11 +476,8 @@
       "[" + hostname + "]" : hostname;
   url::CanonHostInfo host_info;
   std::string reference_name = CanonicalizeHost(host_or_ip, &host_info);
-  // CanonicalizeHost does not normalize absolute vs relative DNS names. If
-  // the input name was absolute (included trailing .), normalize it as if it
-  // was relative.
-  if (!reference_name.empty() && *reference_name.rbegin() == '.')
-    reference_name.resize(reference_name.size() - 1);
+
+  // If the host cannot be canonicalized, fail fast.
   if (reference_name.empty())
     return false;
 
@@ -491,6 +489,21 @@
     return base::Contains(cert_san_ip_addrs, ip_addr_string);
   }
 
+  // The host portion of a URL may support a variety of name resolution formats
+  // and services. However, the only supported name types in this code are IP
+  // addresses, which have been handled above via iPAddress subjectAltNames,
+  // and DNS names, via dNSName subjectAltNames.
+  // Validate that the host conforms to the DNS preferred name syntax, in
+  // either relative or absolute form, and exclude the "root" label for DNS.
+  if (reference_name == "." || !IsValidDNSDomain(reference_name))
+    return false;
+
+  // CanonicalizeHost does not normalize absolute vs relative DNS names. If
+  // the input name was absolute (included trailing .), normalize it as if it
+  // was relative.
+  if (reference_name.back() == '.')
+    reference_name.pop_back();
+
   // |reference_domain| is the remainder of |host| after the leading host
   // component is stripped off, but includes the leading dot e.g.
   // "www.f.com" -> ".f.com".
diff --git a/net/cert/x509_certificate_unittest.cc b/net/cert/x509_certificate_unittest.cc
index bd42292..6fd1172 100644
--- a/net/cert/x509_certificate_unittest.cc
+++ b/net/cert/x509_certificate_unittest.cc
@@ -1202,8 +1202,14 @@
     {false, "wwww.bar.foo.com", "w*w.bar.foo.c0m"},
     {false, "WALLY.bar.foo.com", "wa*.bar.foo.com"},
     {false, "wally.bar.foo.com", "*Ly.bar.foo.com"},
+    // Hostname escaping tests
     {true, "ww%57.foo.com", "www.foo.com"},
-    {true, "www&.foo.com", "www%26.foo.com"},
+    {true, "www%2Efoo.com", "www.foo.com"},
+    {false, "www%00.foo.com", "www,foo.com,www.foo.com"},
+    {false, "www%0D.foo.com", "www.foo.com,www\r.foo.com"},
+    {false, "www%40foo.com", "www@foo.com"},
+    {false, "www%2E%2Efoo.com", "www.foo.com,www..foo.com"},
+    {false, "www%252Efoo.com", "www.foo.com"},
     // IDN tests
     {true, "xn--poema-9qae5a.com.br", "xn--poema-9qae5a.com.br"},
     {true, "www.xn--poema-9qae5a.com.br", "*.xn--poema-9qae5a.com.br"},
@@ -1287,6 +1293,16 @@
     {false, "1.2.3.4.5.6", "*.2.3.4.5.6"},
     {true, "1.2.3.4.5", "1.2.3.4.5"},
     // Invalid host names.
+    {false, ".", ""},
+    {false, ".", "."},
+    {false, "1.2.3.4..", "", "1.2.3.4"},
+    {false, "www..domain.example", "www.domain.example"},
+    {false, "www^domain.example", "www^domain.example"},
+    {false, "www%20.domain.example", "www .domain.example"},
+    {false, "www%2520.domain.example", "www .domain.example"},
+    {false, "www%5E.domain.example", "www^domain.example"},
+    {false, "www,domain.example", "www,domain.example"},
+    {false, "0x000000002200037955161..", "0x000000002200037955161"},
     {false, "junk)(£)$*!@~#", "junk)(£)$*!@~#"},
     {false, "www.*.com", "www.*.com"},
     {false, "w$w.f.com", "w$w.f.com"},
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
index a13fb0f..909d5aa 100644
--- a/net/cookies/cookie_monster.cc
+++ b/net/cookies/cookie_monster.cc
@@ -355,8 +355,7 @@
       store_(std::move(store)),
       last_access_threshold_(last_access_threshold),
       last_statistic_record_time_(base::Time::Now()),
-      persist_session_cookies_(false),
-      weak_ptr_factory_(this) {
+      persist_session_cookies_(false) {
   InitializeHistograms();
   cookieable_schemes_.insert(
       cookieable_schemes_.begin(), kDefaultCookieableSchemes,
diff --git a/net/cookies/cookie_monster.h b/net/cookies/cookie_monster.h
index 85ca69f..913737e 100644
--- a/net/cookies/cookie_monster.h
+++ b/net/cookies/cookie_monster.h
@@ -623,7 +623,7 @@
 
   base::ThreadChecker thread_checker_;
 
-  base::WeakPtrFactory<CookieMonster> weak_ptr_factory_;
+  base::WeakPtrFactory<CookieMonster> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(CookieMonster);
 };
diff --git a/net/cookies/cookie_monster_change_dispatcher.cc b/net/cookies/cookie_monster_change_dispatcher.cc
index 39ccf3b..7d09ea4 100644
--- a/net/cookies/cookie_monster_change_dispatcher.cc
+++ b/net/cookies/cookie_monster_change_dispatcher.cc
@@ -35,8 +35,7 @@
       name_key_(std::move(name_key)),
       url_(std::move(url)),
       callback_(std::move(callback)),
-      task_runner_(base::ThreadTaskRunnerHandle::Get()),
-      weak_ptr_factory_(this) {
+      task_runner_(base::ThreadTaskRunnerHandle::Get()) {
   DCHECK(url_.is_valid() || url_.is_empty());
   DCHECK_EQ(url_.is_empty(), domain_key_ == kGlobalDomainKey);
 
@@ -80,8 +79,7 @@
   callback_.Run(cookie, change_cause);
 }
 
-CookieMonsterChangeDispatcher::CookieMonsterChangeDispatcher()
-    : weak_ptr_factory_(this) {}
+CookieMonsterChangeDispatcher::CookieMonsterChangeDispatcher() {}
 
 CookieMonsterChangeDispatcher::~CookieMonsterChangeDispatcher() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
diff --git a/net/cookies/cookie_monster_change_dispatcher.h b/net/cookies/cookie_monster_change_dispatcher.h
index caf35e8..b1d7c51 100644
--- a/net/cookies/cookie_monster_change_dispatcher.h
+++ b/net/cookies/cookie_monster_change_dispatcher.h
@@ -105,7 +105,7 @@
 
     // Used to cancel delayed calls to DoDispatchChange() when the subscription
     // gets destroyed.
-    base::WeakPtrFactory<Subscription> weak_ptr_factory_;
+    base::WeakPtrFactory<Subscription> weak_ptr_factory_{this};
 
     DISALLOW_COPY_AND_ASSIGN(Subscription);
   };
@@ -149,7 +149,7 @@
   THREAD_CHECKER(thread_checker_);
 
   // Vends weak pointers to subscriptions.
-  base::WeakPtrFactory<CookieMonsterChangeDispatcher> weak_ptr_factory_;
+  base::WeakPtrFactory<CookieMonsterChangeDispatcher> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(CookieMonsterChangeDispatcher);
 };
diff --git a/net/disk_cache/blockfile/backend_impl.cc b/net/disk_cache/blockfile/backend_impl.cc
index bc53189..b231b7c 100644
--- a/net/disk_cache/blockfile/backend_impl.cc
+++ b/net/disk_cache/blockfile/backend_impl.cc
@@ -173,8 +173,7 @@
       consider_evicting_at_op_end_(false),
       net_log_(net_log),
       done_(base::WaitableEvent::ResetPolicy::MANUAL,
-            base::WaitableEvent::InitialState::NOT_SIGNALED),
-      ptr_factory_(this) {}
+            base::WaitableEvent::InitialState::NOT_SIGNALED) {}
 
 BackendImpl::BackendImpl(
     const base::FilePath& path,
@@ -202,8 +201,7 @@
       consider_evicting_at_op_end_(false),
       net_log_(net_log),
       done_(base::WaitableEvent::ResetPolicy::MANUAL,
-            base::WaitableEvent::InitialState::NOT_SIGNALED),
-      ptr_factory_(this) {}
+            base::WaitableEvent::InitialState::NOT_SIGNALED) {}
 
 BackendImpl::~BackendImpl() {
   if (user_flags_ & kNoRandom) {
@@ -1937,11 +1935,6 @@
   stats_.SetCounter(Stats::DOOM_CACHE, 0);
   stats_.SetCounter(Stats::DOOM_RECENT, 0);
 
-  int age = (Time::Now() -
-             Time::FromInternalValue(data_->header.create_time)).InHours();
-  if (age)
-    CACHE_UMA(HOURS, "FilesAge", 0, age);
-
   int64_t total_hours = stats_.GetCounter(Stats::TIMER) / 120;
   if (!data_->header.create_time || !data_->header.lru.filled) {
     int cause = data_->header.create_time ? 0 : 1;
diff --git a/net/disk_cache/blockfile/backend_impl.h b/net/disk_cache/blockfile/backend_impl.h
index 99d28d7b..16a492ba 100644
--- a/net/disk_cache/blockfile/backend_impl.h
+++ b/net/disk_cache/blockfile/backend_impl.h
@@ -430,7 +430,7 @@
   std::unique_ptr<base::RepeatingTimer> timer_;  // Usage timer.
   base::WaitableEvent done_;  // Signals the end of background work.
   scoped_refptr<TraceObject> trace_object_;  // Initializes internal tracing.
-  base::WeakPtrFactory<BackendImpl> ptr_factory_;
+  base::WeakPtrFactory<BackendImpl> ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(BackendImpl);
 };
diff --git a/net/disk_cache/blockfile/eviction.cc b/net/disk_cache/blockfile/eviction.cc
index 2608c7a..489f549 100644
--- a/net/disk_cache/blockfile/eviction.cc
+++ b/net/disk_cache/blockfile/eviction.cc
@@ -79,7 +79,7 @@
 
 // The real initialization happens during Init(), init_ is the only member that
 // has to be initialized here.
-Eviction::Eviction() : backend_(nullptr), init_(false), ptr_factory_(this) {}
+Eviction::Eviction() : backend_(nullptr), init_(false) {}
 
 Eviction::~Eviction() = default;
 
diff --git a/net/disk_cache/blockfile/eviction.h b/net/disk_cache/blockfile/eviction.h
index baea659..283463f 100644
--- a/net/disk_cache/blockfile/eviction.h
+++ b/net/disk_cache/blockfile/eviction.h
@@ -81,7 +81,7 @@
   bool delay_trim_;
   bool init_;
   bool test_mode_;
-  base::WeakPtrFactory<Eviction> ptr_factory_;
+  base::WeakPtrFactory<Eviction> ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(Eviction);
 };
diff --git a/net/disk_cache/blockfile/in_flight_backend_io.cc b/net/disk_cache/blockfile/in_flight_backend_io.cc
index 32895a5..c492295 100644
--- a/net/disk_cache/blockfile/in_flight_backend_io.cc
+++ b/net/disk_cache/blockfile/in_flight_backend_io.cc
@@ -396,10 +396,7 @@
 InFlightBackendIO::InFlightBackendIO(
     BackendImpl* backend,
     const scoped_refptr<base::SingleThreadTaskRunner>& background_thread)
-    : backend_(backend),
-      background_thread_(background_thread),
-      ptr_factory_(this) {
-}
+    : backend_(backend), background_thread_(background_thread) {}
 
 InFlightBackendIO::~InFlightBackendIO() = default;
 
diff --git a/net/disk_cache/blockfile/in_flight_backend_io.h b/net/disk_cache/blockfile/in_flight_backend_io.h
index 7d050219..724cc33 100644
--- a/net/disk_cache/blockfile/in_flight_backend_io.h
+++ b/net/disk_cache/blockfile/in_flight_backend_io.h
@@ -251,7 +251,7 @@
   void PostOperation(const base::Location& from_here, BackendIO* operation);
   BackendImpl* backend_;
   scoped_refptr<base::SingleThreadTaskRunner> background_thread_;
-  base::WeakPtrFactory<InFlightBackendIO> ptr_factory_;
+  base::WeakPtrFactory<InFlightBackendIO> ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(InFlightBackendIO);
 };
diff --git a/net/disk_cache/blockfile/stats.cc b/net/disk_cache/blockfile/stats.cc
index 161e013..43c6758 100644
--- a/net/disk_cache/blockfile/stats.cc
+++ b/net/disk_cache/blockfile/stats.cc
@@ -139,26 +139,12 @@
     return;
 
   first_time = false;
-  int min = 1;
-  int max = 64 * 1024;
-  int num_buckets = 75;
-  base::BucketRanges ranges(num_buckets + 1);
-  base::Histogram::InitializeBucketRanges(min, max, &ranges);
-
-  base::HistogramBase* stats_histogram = base::Histogram::FactoryGet(
-      "DiskCache.SizeStats2", min, max, num_buckets,
-      base::HistogramBase::kUmaTargetedHistogramFlag);
-
-  base::SampleVector samples(&ranges);
   for (int i = 0; i < kDataSizesLength; i++) {
     // This is a good time to fix any inconsistent data. The count should be
     // always positive, but if it's not, reset the value now.
     if (data_sizes_[i] < 0)
       data_sizes_[i] = 0;
-
-    samples.Accumulate(GetBucketRange(i) / 1024, data_sizes_[i]);
   }
-  stats_histogram->AddSamples(samples);
 }
 
 int Stats::StorageSize() {
diff --git a/net/disk_cache/memory/mem_backend_impl.cc b/net/disk_cache/memory/mem_backend_impl.cc
index a03c53d..bddd8858 100644
--- a/net/disk_cache/memory/mem_backend_impl.cc
+++ b/net/disk_cache/memory/mem_backend_impl.cc
@@ -63,8 +63,7 @@
       net_log_(net_log),
       memory_pressure_listener_(
           base::BindRepeating(&MemBackendImpl::OnMemoryPressure,
-                              base::Unretained(this))),
-      weak_factory_(this) {}
+                              base::Unretained(this))) {}
 
 MemBackendImpl::~MemBackendImpl() {
   DCHECK(CheckLRUListOrder(lru_list_));
diff --git a/net/disk_cache/memory/mem_backend_impl.h b/net/disk_cache/memory/mem_backend_impl.h
index f79ef3320..046fed2 100644
--- a/net/disk_cache/memory/mem_backend_impl.h
+++ b/net/disk_cache/memory/mem_backend_impl.h
@@ -149,7 +149,7 @@
 
   base::MemoryPressureListener memory_pressure_listener_;
 
-  base::WeakPtrFactory<MemBackendImpl> weak_factory_;
+  base::WeakPtrFactory<MemBackendImpl> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(MemBackendImpl);
 };
diff --git a/net/disk_cache/simple/simple_backend_impl.cc b/net/disk_cache/simple/simple_backend_impl.cc
index 76d510d..018d6ae 100644
--- a/net/disk_cache/simple/simple_backend_impl.cc
+++ b/net/disk_cache/simple/simple_backend_impl.cc
@@ -68,46 +68,6 @@
 // Overrides the above.
 const int64_t kMinFileSizeLimit = 5 * 1024 * 1024;
 
-bool g_fd_limit_histogram_has_been_populated = false;
-
-void MaybeHistogramFdLimit() {
-  if (g_fd_limit_histogram_has_been_populated)
-    return;
-
-  // Used in histograms; add new entries at end.
-  enum FdLimitStatus {
-    FD_LIMIT_STATUS_UNSUPPORTED = 0,
-    FD_LIMIT_STATUS_FAILED      = 1,
-    FD_LIMIT_STATUS_SUCCEEDED   = 2,
-    FD_LIMIT_STATUS_MAX         = 3
-  };
-  FdLimitStatus fd_limit_status = FD_LIMIT_STATUS_UNSUPPORTED;
-  int soft_fd_limit = 0;
-  int hard_fd_limit = 0;
-
-#if defined(OS_POSIX)
-  struct rlimit nofile;
-  if (!getrlimit(RLIMIT_NOFILE, &nofile)) {
-    soft_fd_limit = nofile.rlim_cur;
-    hard_fd_limit = nofile.rlim_max;
-    fd_limit_status = FD_LIMIT_STATUS_SUCCEEDED;
-  } else {
-    fd_limit_status = FD_LIMIT_STATUS_FAILED;
-  }
-#endif
-
-  UMA_HISTOGRAM_ENUMERATION("SimpleCache.FileDescriptorLimitStatus",
-                            fd_limit_status, FD_LIMIT_STATUS_MAX);
-  if (fd_limit_status == FD_LIMIT_STATUS_SUCCEEDED) {
-    base::UmaHistogramSparse("SimpleCache.FileDescriptorLimitSoft",
-                             soft_fd_limit);
-    base::UmaHistogramSparse("SimpleCache.FileDescriptorLimitHard",
-                             hard_fd_limit);
-  }
-
-  g_fd_limit_histogram_has_been_populated = true;
-}
-
 // Global context of all the files we have open --- this permits some to be
 // closed on demand if too many FDs are being used, to avoid running out.
 base::LazyInstance<SimpleFileTracker>::Leaky g_simple_file_tracker =
@@ -260,7 +220,6 @@
   // backends, as default (if first call).
   if (orig_max_size_ < 0)
     orig_max_size_ = 0;
-  MaybeHistogramFdLimit();
 }
 
 SimpleBackendImpl::~SimpleBackendImpl() {
@@ -599,9 +558,7 @@
 class SimpleBackendImpl::SimpleIterator final : public Iterator {
  public:
   explicit SimpleIterator(base::WeakPtr<SimpleBackendImpl> backend)
-      : backend_(backend),
-        weak_factory_(this) {
-  }
+      : backend_(backend) {}
 
   // From Backend::Iterator:
   net::Error OpenNextEntry(Entry** next_entry,
@@ -665,7 +622,7 @@
  private:
   base::WeakPtr<SimpleBackendImpl> backend_;
   std::unique_ptr<std::vector<uint64_t>> hashes_to_enumerate_;
-  base::WeakPtrFactory<SimpleIterator> weak_factory_;
+  base::WeakPtrFactory<SimpleIterator> weak_factory_{this};
 };
 
 std::unique_ptr<Backend::Iterator> SimpleBackendImpl::CreateIterator() {
diff --git a/net/disk_cache/simple/simple_entry_impl.cc b/net/disk_cache/simple/simple_entry_impl.cc
index 2a4754f..d2aa25b 100644
--- a/net/disk_cache/simple/simple_entry_impl.cc
+++ b/net/disk_cache/simple/simple_entry_impl.cc
@@ -85,14 +85,6 @@
   SIMPLE_CACHE_UMA(COUNTS_10000, "HeaderSize", cache_type, size);
 }
 
-int g_open_entry_count = 0;
-
-void AdjustOpenEntryCountBy(net::CacheType cache_type, int offset) {
-  g_open_entry_count += offset;
-  SIMPLE_CACHE_UMA(COUNTS_10000,
-                   "GlobalOpenEntryCount", cache_type, g_open_entry_count);
-}
-
 void InvokeCallbackIfBackendIsAlive(
     const base::WeakPtr<SimpleBackendImpl>& backend,
     net::CompletionOnceCallback completion_callback,
@@ -1510,7 +1502,6 @@
   SIMPLE_CACHE_UMA(TIMES,
                    "EntryCreationTime", cache_type_,
                    (base::TimeTicks::Now() - start_time));
-  AdjustOpenEntryCountBy(cache_type_, 1);
 
   net_log_.AddEvent(end_event_type);
 
@@ -1702,7 +1693,6 @@
   DCHECK(STATE_IO_PENDING == state_ || STATE_FAILURE == state_ ||
          STATE_UNINITIALIZED == state_);
   net_log_.AddEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY_CLOSE_END);
-  AdjustOpenEntryCountBy(cache_type_, -1);
   if (cache_type_ == net::APP_CACHE &&
       in_results->estimated_trailer_prefetch_size > 0 && backend_.get() &&
       backend_->index()) {
diff --git a/net/dns/dns_config_service_posix.cc b/net/dns/dns_config_service_posix.cc
index 21852fe..328cdd8 100644
--- a/net/dns/dns_config_service_posix.cc
+++ b/net/dns/dns_config_service_posix.cc
@@ -239,8 +239,7 @@
 
 class DnsConfigServicePosix::Watcher {
  public:
-  explicit Watcher(DnsConfigServicePosix* service)
-      : service_(service), weak_factory_(this) {}
+  explicit Watcher(DnsConfigServicePosix* service) : service_(service) {}
   ~Watcher() = default;
 
   bool Watch() {
@@ -294,7 +293,7 @@
   base::FilePathWatcher hosts_watcher_;
 #endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
 
-  base::WeakPtrFactory<Watcher> weak_factory_;
+  base::WeakPtrFactory<Watcher> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(Watcher);
 };
diff --git a/net/dns/dns_socket_pool_unittest.cc b/net/dns/dns_socket_pool_unittest.cc
index eba9749..2138518 100644
--- a/net/dns/dns_socket_pool_unittest.cc
+++ b/net/dns/dns_socket_pool_unittest.cc
@@ -16,14 +16,14 @@
 
 class DummyObject {
  public:
-  DummyObject() : weak_factory_(this) {}
+  DummyObject() {}
 
   base::WeakPtr<DummyObject> GetWeakPtr() { return weak_factory_.GetWeakPtr(); }
 
   bool HasWeakPtrs() const { return weak_factory_.HasWeakPtrs(); }
 
  private:
-  base::WeakPtrFactory<DummyObject> weak_factory_;
+  base::WeakPtrFactory<DummyObject> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(DummyObject);
 };
diff --git a/net/dns/dns_transaction.cc b/net/dns/dns_transaction.cc
index 8bced98..4623473 100644
--- a/net/dns/dns_transaction.cc
+++ b/net/dns/dns_transaction.cc
@@ -329,9 +329,7 @@
                  bool use_post,
                  URLRequestContext* url_request_context,
                  RequestPriority request_priority_)
-      : DnsAttempt(server_index),
-        query_(std::move(query)),
-        weak_factory_(this) {
+      : DnsAttempt(server_index), query_(std::move(query)) {
     GURL url;
     if (use_post) {
       // Set url for a POST request
@@ -531,7 +529,7 @@
   std::unique_ptr<URLRequest> request_;
   NetLogWithSource net_log_;
 
-  base::WeakPtrFactory<DnsHTTPAttempt> weak_factory_;
+  base::WeakPtrFactory<DnsHTTPAttempt> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(DnsHTTPAttempt);
 };
diff --git a/net/dns/dns_transaction_unittest.cc b/net/dns/dns_transaction_unittest.cc
index 7c01c64581..ec5f56e 100644
--- a/net/dns/dns_transaction_unittest.cc
+++ b/net/dns/dns_transaction_unittest.cc
@@ -418,8 +418,7 @@
         content_length_(0),
         leftover_data_len_(0),
         data_provider_(data_provider),
-        response_modifier_(response_modifier),
-        weak_factory_(this) {
+        response_modifier_(response_modifier) {
     data_provider_->Initialize(this);
     MatchQueryData(request, data_provider);
   }
@@ -559,7 +558,7 @@
   IOBuffer* pending_buf_;
   int pending_buf_size_;
 
-  base::WeakPtrFactory<URLRequestMockDohJob> weak_factory_;
+  base::WeakPtrFactory<URLRequestMockDohJob> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(URLRequestMockDohJob);
 };
diff --git a/net/dns/fuzzed_host_resolver_util.cc b/net/dns/fuzzed_host_resolver_util.cc
index b547c5a..c384abf 100644
--- a/net/dns/fuzzed_host_resolver_util.cc
+++ b/net/dns/fuzzed_host_resolver_util.cc
@@ -174,8 +174,7 @@
  public:
   explicit FuzzedMdnsSocket(FuzzedDataProvider* data_provider)
       : data_provider_(data_provider),
-        local_address_(FuzzIPAddress(data_provider_), 5353),
-        weak_factory_(this) {}
+        local_address_(FuzzIPAddress(data_provider_), 5353) {}
 
   int Listen(const IPEndPoint& address) override { return OK; }
 
@@ -281,7 +280,7 @@
   const IPEndPoint local_address_;
   const NetLogWithSource net_log_;
 
-  base::WeakPtrFactory<FuzzedMdnsSocket> weak_factory_;
+  base::WeakPtrFactory<FuzzedMdnsSocket> weak_factory_{this};
 };
 
 class FuzzedMdnsSocketFactory : public MDnsSocketFactory {
diff --git a/net/dns/host_resolver_manager.cc b/net/dns/host_resolver_manager.cc
index fc932a2..a9bc7ef7 100644
--- a/net/dns/host_resolver_manager.cc
+++ b/net/dns/host_resolver_manager.cc
@@ -807,8 +807,7 @@
         proc_task_runner_(std::move(proc_task_runner)),
         attempt_number_(0),
         net_log_(job_net_log),
-        tick_clock_(tick_clock),
-        weak_ptr_factory_(this) {
+        tick_clock_(tick_clock) {
     DCHECK(callback_);
     if (!params_.resolver_proc.get())
       params_.resolver_proc = HostResolverProc::GetDefault();
@@ -991,7 +990,7 @@
   // Used to loop back from the blocking lookup attempt tasks as well as from
   // delayed retry tasks. Invalidate WeakPtrs on completion and cancellation to
   // cancel handling of such posted tasks.
-  base::WeakPtrFactory<ProcTask> weak_ptr_factory_;
+  base::WeakPtrFactory<ProcTask> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(ProcTask);
 };
@@ -1522,8 +1521,7 @@
         tick_clock_(tick_clock),
         net_log_(
             NetLogWithSource::Make(source_net_log.net_log(),
-                                   NetLogSourceType::HOST_RESOLVER_IMPL_JOB)),
-        weak_ptr_factory_(this) {
+                                   NetLogSourceType::HOST_RESOLVER_IMPL_JOB)) {
     source_net_log.AddEvent(NetLogEventType::HOST_RESOLVER_IMPL_CREATE_JOB);
 
     net_log_.BeginEvent(NetLogEventType::HOST_RESOLVER_IMPL_JOB,
@@ -2348,7 +2346,7 @@
   // Iterator to |this| in the JobMap. |nullopt| if not owned by the JobMap.
   base::Optional<JobMap::iterator> self_iterator_;
 
-  base::WeakPtrFactory<Job> weak_ptr_factory_;
+  base::WeakPtrFactory<Job> weak_ptr_factory_{this};
 };
 
 //-----------------------------------------------------------------------------
@@ -2372,9 +2370,7 @@
       use_proctask_by_default_(false),
       allow_fallback_to_proctask_(true),
       tick_clock_(base::DefaultTickClock::GetInstance()),
-      invalidation_in_progress_(false),
-      weak_ptr_factory_(this),
-      probe_weak_ptr_factory_(this) {
+      invalidation_in_progress_(false) {
   PrioritizedDispatcher::Limits job_limits = GetDispatcherLimits(options);
   dispatcher_.reset(new PrioritizedDispatcher(job_limits));
   max_queued_jobs_ = job_limits.total_jobs * 100u;
diff --git a/net/dns/host_resolver_manager.h b/net/dns/host_resolver_manager.h
index 428fead..8f904491 100644
--- a/net/dns/host_resolver_manager.h
+++ b/net/dns/host_resolver_manager.h
@@ -534,9 +534,9 @@
 
   THREAD_CHECKER(thread_checker_);
 
-  base::WeakPtrFactory<HostResolverManager> weak_ptr_factory_;
+  base::WeakPtrFactory<HostResolverManager> weak_ptr_factory_{this};
 
-  base::WeakPtrFactory<HostResolverManager> probe_weak_ptr_factory_;
+  base::WeakPtrFactory<HostResolverManager> probe_weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(HostResolverManager);
 };
diff --git a/net/dns/host_resolver_mdns_task.cc b/net/dns/host_resolver_mdns_task.cc
index cc5c364..356278b5 100644
--- a/net/dns/host_resolver_mdns_task.cc
+++ b/net/dns/host_resolver_mdns_task.cc
@@ -128,7 +128,7 @@
     MDnsClient* mdns_client,
     const std::string& hostname,
     const std::vector<DnsQueryType>& query_types)
-    : mdns_client_(mdns_client), hostname_(hostname), weak_ptr_factory_(this) {
+    : mdns_client_(mdns_client), hostname_(hostname) {
   DCHECK(!query_types.empty());
   for (DnsQueryType query_type : query_types) {
     transactions_.emplace_back(query_type, this);
diff --git a/net/dns/host_resolver_mdns_task.h b/net/dns/host_resolver_mdns_task.h
index 5a1c829..e0e408a 100644
--- a/net/dns/host_resolver_mdns_task.h
+++ b/net/dns/host_resolver_mdns_task.h
@@ -63,7 +63,7 @@
 
   SEQUENCE_CHECKER(sequence_checker_);
 
-  base::WeakPtrFactory<HostResolverMdnsTask> weak_ptr_factory_;
+  base::WeakPtrFactory<HostResolverMdnsTask> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(HostResolverMdnsTask);
 };
diff --git a/net/dns/mdns_client_impl.cc b/net/dns/mdns_client_impl.cc
index 4d3ce6c..9ac0592f 100644
--- a/net/dns/mdns_client_impl.cc
+++ b/net/dns/mdns_client_impl.cc
@@ -131,8 +131,7 @@
 }
 
 MDnsConnection::MDnsConnection(MDnsConnection::Delegate* delegate)
-    : delegate_(delegate), weak_ptr_factory_(this) {
-}
+    : delegate_(delegate) {}
 
 MDnsConnection::~MDnsConnection() = default;
 
diff --git a/net/dns/mdns_client_impl.h b/net/dns/mdns_client_impl.h
index fd911dc..0efda0b 100644
--- a/net/dns/mdns_client_impl.h
+++ b/net/dns/mdns_client_impl.h
@@ -111,7 +111,7 @@
 
   Delegate* delegate_;
 
-  base::WeakPtrFactory<MDnsConnection> weak_ptr_factory_;
+  base::WeakPtrFactory<MDnsConnection> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(MDnsConnection);
 };
diff --git a/net/dns/serial_worker.cc b/net/dns/serial_worker.cc
index 520bd3a..f66abb1 100644
--- a/net/dns/serial_worker.cc
+++ b/net/dns/serial_worker.cc
@@ -15,8 +15,7 @@
 SerialWorker::SerialWorker()
     : base::RefCountedDeleteOnSequence<SerialWorker>(
           base::SequencedTaskRunnerHandle::Get()),
-      state_(IDLE),
-      weak_factory_(this) {}
+      state_(IDLE) {}
 
 SerialWorker::~SerialWorker() = default;
 
diff --git a/net/dns/serial_worker.h b/net/dns/serial_worker.h
index b647b69..a16e846 100644
--- a/net/dns/serial_worker.h
+++ b/net/dns/serial_worker.h
@@ -76,7 +76,7 @@
 
   State state_;
 
-  base::WeakPtrFactory<SerialWorker> weak_factory_;
+  base::WeakPtrFactory<SerialWorker> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(SerialWorker);
 };
diff --git a/net/dns/system_dns_config_change_notifier.cc b/net/dns/system_dns_config_change_notifier.cc
index a75e24c..a865243 100644
--- a/net/dns/system_dns_config_change_notifier.cc
+++ b/net/dns/system_dns_config_change_notifier.cc
@@ -29,8 +29,7 @@
  public:
   explicit WrappedObserver(SystemDnsConfigChangeNotifier::Observer* observer)
       : task_runner_(base::SequencedTaskRunnerHandle::Get()),
-        observer_(observer),
-        weak_ptr_factory_(this) {}
+        observer_(observer) {}
 
   ~WrappedObserver() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); }
 
@@ -53,7 +52,7 @@
   SystemDnsConfigChangeNotifier::Observer* const observer_;
 
   SEQUENCE_CHECKER(sequence_checker_);
-  base::WeakPtrFactory<WrappedObserver> weak_ptr_factory_;
+  base::WeakPtrFactory<WrappedObserver> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(WrappedObserver);
 };
@@ -67,8 +66,7 @@
   Core(scoped_refptr<base::SequencedTaskRunner> task_runner,
        std::unique_ptr<DnsConfigService> dns_config_service)
       : task_runner_(std::move(task_runner)),
-        dns_config_service_(std::move(dns_config_service)),
-        weak_ptr_factory_(this) {
+        dns_config_service_(std::move(dns_config_service)) {
     DCHECK(task_runner_);
     DCHECK(dns_config_service_);
 
@@ -170,7 +168,7 @@
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
   SEQUENCE_CHECKER(sequence_checker_);
   std::unique_ptr<DnsConfigService> dns_config_service_;
-  base::WeakPtrFactory<Core> weak_ptr_factory_;
+  base::WeakPtrFactory<Core> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(Core);
 };
diff --git a/net/extras/sqlite/sqlite_persistent_reporting_and_nel_store.cc b/net/extras/sqlite/sqlite_persistent_reporting_and_nel_store.cc
index e0f6f15..f67e487c 100644
--- a/net/extras/sqlite/sqlite_persistent_reporting_and_nel_store.cc
+++ b/net/extras/sqlite/sqlite_persistent_reporting_and_nel_store.cc
@@ -1257,8 +1257,7 @@
     const base::FilePath& path,
     const scoped_refptr<base::SequencedTaskRunner>& client_task_runner,
     const scoped_refptr<base::SequencedTaskRunner>& background_task_runner)
-    : backend_(new Backend(path, client_task_runner, background_task_runner)),
-      weak_factory_(this) {}
+    : backend_(new Backend(path, client_task_runner, background_task_runner)) {}
 
 SQLitePersistentReportingAndNelStore::~SQLitePersistentReportingAndNelStore() {
   backend_->Close();
diff --git a/net/extras/sqlite/sqlite_persistent_reporting_and_nel_store.h b/net/extras/sqlite/sqlite_persistent_reporting_and_nel_store.h
index 1a6a7fb..cbd8646 100644
--- a/net/extras/sqlite/sqlite_persistent_reporting_and_nel_store.h
+++ b/net/extras/sqlite/sqlite_persistent_reporting_and_nel_store.h
@@ -77,7 +77,8 @@
 
   const scoped_refptr<Backend> backend_;
 
-  base::WeakPtrFactory<SQLitePersistentReportingAndNelStore> weak_factory_;
+  base::WeakPtrFactory<SQLitePersistentReportingAndNelStore> weak_factory_{
+      this};
 
   DISALLOW_COPY_AND_ASSIGN(SQLitePersistentReportingAndNelStore);
 };
diff --git a/net/http/bidirectional_stream.cc b/net/http/bidirectional_stream.cc
index 780b8e4..0e23845 100644
--- a/net/http/bidirectional_stream.cc
+++ b/net/http/bidirectional_stream.cc
@@ -86,8 +86,7 @@
       send_request_headers_automatically_(send_request_headers_automatically),
       request_headers_sent_(false),
       delegate_(delegate),
-      timer_(std::move(timer)),
-      weak_factory_(this) {
+      timer_(std::move(timer)) {
   DCHECK(delegate_);
   DCHECK(request_info_);
 
diff --git a/net/http/bidirectional_stream.h b/net/http/bidirectional_stream.h
index d4f56f4b..4f0b4ab 100644
--- a/net/http/bidirectional_stream.h
+++ b/net/http/bidirectional_stream.h
@@ -263,7 +263,7 @@
   // are received. Other fields are populated at different stages of the request
   LoadTimingInfo load_timing_info_;
 
-  base::WeakPtrFactory<BidirectionalStream> weak_factory_;
+  base::WeakPtrFactory<BidirectionalStream> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(BidirectionalStream);
 };
diff --git a/net/http/bidirectional_stream_unittest.cc b/net/http/bidirectional_stream_unittest.cc
index 7c9e1d32..319e455c4 100644
--- a/net/http/bidirectional_stream_unittest.cc
+++ b/net/http/bidirectional_stream_unittest.cc
@@ -591,7 +591,7 @@
 }
 
 TEST_F(BidirectionalStreamTest, ClientAuthRequestIgnored) {
-  scoped_refptr<SSLCertRequestInfo> cert_request(new SSLCertRequestInfo());
+  auto cert_request = base::MakeRefCounted<SSLCertRequestInfo>();
   cert_request->host_and_port = host_port_pair_;
 
   // First attempt receives client auth request.
diff --git a/net/http/broken_alternative_services.cc b/net/http/broken_alternative_services.cc
index e2a7185..fcb9548 100644
--- a/net/http/broken_alternative_services.cc
+++ b/net/http/broken_alternative_services.cc
@@ -34,7 +34,7 @@
 BrokenAlternativeServices::BrokenAlternativeServices(
     Delegate* delegate,
     const base::TickClock* clock)
-    : delegate_(delegate), clock_(clock), weak_ptr_factory_(this) {
+    : delegate_(delegate), clock_(clock) {
   DCHECK(delegate_);
   DCHECK(clock_);
 }
diff --git a/net/http/broken_alternative_services.h b/net/http/broken_alternative_services.h
index 3d6690f2..2d93fb4 100644
--- a/net/http/broken_alternative_services.h
+++ b/net/http/broken_alternative_services.h
@@ -165,7 +165,7 @@
   // services.
   base::OneShotTimer expiration_timer_;
 
-  base::WeakPtrFactory<BrokenAlternativeServices> weak_ptr_factory_;
+  base::WeakPtrFactory<BrokenAlternativeServices> weak_ptr_factory_{this};
 };
 
 }  // namespace net
diff --git a/net/http/http_auth_handler_mock.cc b/net/http/http_auth_handler_mock.cc
index 74d9fef..2f051ced 100644
--- a/net/http/http_auth_handler_mock.cc
+++ b/net/http/http_auth_handler_mock.cc
@@ -49,8 +49,7 @@
       first_round_(true),
       connection_based_(false),
       allows_default_credentials_(false),
-      allows_explicit_credentials_(true),
-      weak_factory_(this) {}
+      allows_explicit_credentials_(true) {}
 
 HttpAuthHandlerMock::~HttpAuthHandlerMock() = default;
 
diff --git a/net/http/http_auth_handler_mock.h b/net/http/http_auth_handler_mock.h
index abc3693..5e7e32c8 100644
--- a/net/http/http_auth_handler_mock.h
+++ b/net/http/http_auth_handler_mock.h
@@ -111,7 +111,7 @@
   bool allows_default_credentials_;
   bool allows_explicit_credentials_;
   GURL request_url_;
-  base::WeakPtrFactory<HttpAuthHandlerMock> weak_factory_;
+  base::WeakPtrFactory<HttpAuthHandlerMock> weak_factory_{this};
 };
 
 void PrintTo(const HttpAuthHandlerMock::State& state, ::std::ostream* os);
diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc
index acd5cf8..dfea258 100644
--- a/net/http/http_cache.cc
+++ b/net/http/http_cache.cc
@@ -250,8 +250,7 @@
       fail_conditionalization_for_test_(false),
       mode_(NORMAL),
       network_layer_(std::move(network_layer)),
-      clock_(base::DefaultClock::GetInstance()),
-      weak_factory_(this) {
+      clock_(base::DefaultClock::GetInstance()) {
   HttpNetworkSession* session = network_layer_->GetSession();
   // Session may be NULL in unittests.
   // TODO(mmenke): Seems like tests could be changed to provide a session,
diff --git a/net/http/http_cache.h b/net/http/http_cache.h
index 832a5dcc..c6422af 100644
--- a/net/http/http_cache.h
+++ b/net/http/http_cache.h
@@ -663,7 +663,7 @@
 
   THREAD_CHECKER(thread_checker_);
 
-  base::WeakPtrFactory<HttpCache> weak_factory_;
+  base::WeakPtrFactory<HttpCache> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(HttpCache);
 };
diff --git a/net/http/http_cache_lookup_manager.cc b/net/http/http_cache_lookup_manager.cc
index db6240b..770552b 100644
--- a/net/http/http_cache_lookup_manager.cc
+++ b/net/http/http_cache_lookup_manager.cc
@@ -61,7 +61,7 @@
 }
 
 HttpCacheLookupManager::HttpCacheLookupManager(HttpCache* http_cache)
-    : http_cache_(http_cache), weak_factory_(this) {}
+    : http_cache_(http_cache) {}
 
 HttpCacheLookupManager::~HttpCacheLookupManager() = default;
 
diff --git a/net/http/http_cache_lookup_manager.h b/net/http/http_cache_lookup_manager.h
index ba649cd..d7ece67 100644
--- a/net/http/http_cache_lookup_manager.h
+++ b/net/http/http_cache_lookup_manager.h
@@ -57,7 +57,7 @@
   // HttpCache must outlive the HttpCacheLookupManager.
   HttpCache* http_cache_;
   std::map<GURL, std::unique_ptr<LookupTransaction>> lookup_transactions_;
-  base::WeakPtrFactory<HttpCacheLookupManager> weak_factory_;
+  base::WeakPtrFactory<HttpCacheLookupManager> weak_factory_{this};
 };
 
 }  // namespace net
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc
index d9e6d3ec..8ac21b2 100644
--- a/net/http/http_cache_transaction.cc
+++ b/net/http/http_cache_transaction.cc
@@ -193,8 +193,7 @@
       parallel_writing_pattern_(PARALLEL_WRITING_NONE),
       moved_network_transaction_to_writers_(false),
       websocket_handshake_stream_base_create_helper_(nullptr),
-      in_do_loop_(false),
-      weak_factory_(this) {
+      in_do_loop_(false) {
   TRACE_EVENT0("io", "HttpCacheTransaction::Transaction");
   static_assert(HttpCache::Transaction::kNumValidationHeaders ==
                     base::size(kValidationHeaders),
diff --git a/net/http/http_cache_transaction.h b/net/http/http_cache_transaction.h
index 640f851..da341f2 100644
--- a/net/http/http_cache_transaction.h
+++ b/net/http/http_cache_transaction.h
@@ -652,7 +652,7 @@
   // True if the Transaction is currently processing the DoLoop.
   bool in_do_loop_;
 
-  base::WeakPtrFactory<Transaction> weak_factory_;
+  base::WeakPtrFactory<Transaction> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(Transaction);
 };
diff --git a/net/http/http_cache_writers.cc b/net/http/http_cache_writers.cc
index c20d5d3..5d8e78d 100644
--- a/net/http/http_cache_writers.cc
+++ b/net/http/http_cache_writers.cc
@@ -50,7 +50,7 @@
     default;
 
 HttpCache::Writers::Writers(HttpCache* cache, HttpCache::ActiveEntry* entry)
-    : cache_(cache), entry_(entry), weak_factory_(this) {}
+    : cache_(cache), entry_(entry) {}
 
 HttpCache::Writers::~Writers() = default;
 
diff --git a/net/http/http_cache_writers.h b/net/http/http_cache_writers.h
index e914ab1..c638aeb 100644
--- a/net/http/http_cache_writers.h
+++ b/net/http/http_cache_writers.h
@@ -283,7 +283,7 @@
   // end of DoLoop().
   base::OnceClosure cache_callback_;  // Callback for cache_.
 
-  base::WeakPtrFactory<Writers> weak_factory_;
+  base::WeakPtrFactory<Writers> weak_factory_{this};
   DISALLOW_COPY_AND_ASSIGN(Writers);
 };
 
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index b9cfb31c..4e86490 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -1060,7 +1060,7 @@
   } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
     DCHECK(stream_.get());
     DCHECK(IsSecureRequest());
-    response_.cert_request_info = new SSLCertRequestInfo;
+    response_.cert_request_info = base::MakeRefCounted<SSLCertRequestInfo>();
     stream_->GetSSLCertRequestInfo(response_.cert_request_info.get());
     result = HandleCertificateRequest(result);
     if (result == OK)
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index 388842c8..a5f7a90 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -15097,7 +15097,7 @@
   request_info.traffic_annotation =
       net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
 
-  scoped_refptr<SSLCertRequestInfo> cert_request(new SSLCertRequestInfo());
+  auto cert_request = base::MakeRefCounted<SSLCertRequestInfo>();
   cert_request->host_and_port = HostPortPair("www.example.com", 443);
 
   // [ssl_]data1 contains the data for the first SSL handshake. When a
@@ -15202,7 +15202,7 @@
   request_info.traffic_annotation =
       net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
 
-  scoped_refptr<SSLCertRequestInfo> cert_request(new SSLCertRequestInfo());
+  auto cert_request = base::MakeRefCounted<SSLCertRequestInfo>();
   cert_request->host_and_port = HostPortPair("www.example.com", 443);
 
   // When TLS False Start is used, SSLClientSocket::Connect() calls will
diff --git a/net/http/http_proxy_connect_job.cc b/net/http/http_proxy_connect_job.cc
index bc41834..a9fbbdc 100644
--- a/net/http/http_proxy_connect_job.cc
+++ b/net/http/http_proxy_connect_job.cc
@@ -188,8 +188,7 @@
                     common_connect_job_params->http_auth_cache,
                     common_connect_job_params->http_auth_handler_factory,
                     host_resolver())
-              : nullptr),
-      weak_ptr_factory_(this) {}
+              : nullptr) {}
 
 HttpProxyConnectJob::~HttpProxyConnectJob() {}
 
diff --git a/net/http/http_proxy_connect_job.h b/net/http/http_proxy_connect_job.h
index ef12a1e..7a7b967 100644
--- a/net/http/http_proxy_connect_job.h
+++ b/net/http/http_proxy_connect_job.h
@@ -239,7 +239,7 @@
   // Time when the connection to the proxy was started.
   base::TimeTicks connect_start_time_;
 
-  base::WeakPtrFactory<HttpProxyConnectJob> weak_ptr_factory_;
+  base::WeakPtrFactory<HttpProxyConnectJob> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(HttpProxyConnectJob);
 };
diff --git a/net/http/http_response_body_drainer_unittest.cc b/net/http/http_response_body_drainer_unittest.cc
index a1c3c961..b40cdca 100644
--- a/net/http/http_response_body_drainer_unittest.cc
+++ b/net/http/http_response_body_drainer_unittest.cc
@@ -85,8 +85,7 @@
         is_sync_(false),
         is_last_chunk_zero_size_(false),
         is_complete_(false),
-        can_reuse_connection_(true),
-        weak_factory_(this) {}
+        can_reuse_connection_(true) {}
   ~MockHttpStream() override = default;
 
   // HttpStream implementation.
@@ -177,7 +176,7 @@
   bool is_complete_;
   bool can_reuse_connection_;
 
-  base::WeakPtrFactory<MockHttpStream> weak_factory_;
+  base::WeakPtrFactory<MockHttpStream> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(MockHttpStream);
 };
diff --git a/net/http/http_stream_factory_job.cc b/net/http/http_stream_factory_job.cc
index 8fded9b..036dcde8 100644
--- a/net/http/http_stream_factory_job.cc
+++ b/net/http/http_stream_factory_job.cc
@@ -169,8 +169,7 @@
                                           request_info_.socket_tag,
                                           request_info_.network_isolation_key)),
       stream_type_(HttpStreamRequest::BIDIRECTIONAL_STREAM),
-      init_connection_already_resumed_(false),
-      ptr_factory_(this) {
+      init_connection_already_resumed_(false) {
   // QUIC can only be spoken to servers, never to proxies.
   if (alternative_protocol == kProtoQUIC)
     DCHECK(proxy_info_.is_direct());
diff --git a/net/http/http_stream_factory_job.h b/net/http/http_stream_factory_job.h
index 3a5488e3..94d1a91 100644
--- a/net/http/http_stream_factory_job.h
+++ b/net/http/http_stream_factory_job.h
@@ -477,7 +477,7 @@
 
   std::unique_ptr<SpdySessionPool::SpdySessionRequest> spdy_session_request_;
 
-  base::WeakPtrFactory<Job> ptr_factory_;
+  base::WeakPtrFactory<Job> ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(Job);
 };
diff --git a/net/http/http_stream_factory_job_controller.cc b/net/http/http_stream_factory_job_controller.cc
index 3ec5177..c8b124b8 100644
--- a/net/http/http_stream_factory_job_controller.cc
+++ b/net/http/http_stream_factory_job_controller.cc
@@ -102,10 +102,9 @@
       proxy_ssl_config_(proxy_ssl_config),
       num_streams_(0),
       priority_(IDLE),
-      net_log_(
-          NetLogWithSource::Make(session->net_log(),
-                                 NetLogSourceType::HTTP_STREAM_JOB_CONTROLLER)),
-      ptr_factory_(this) {
+      net_log_(NetLogWithSource::Make(
+          session->net_log(),
+          NetLogSourceType::HTTP_STREAM_JOB_CONTROLLER)) {
   DCHECK(factory);
   net_log_.BeginEvent(NetLogEventType::HTTP_STREAM_JOB_CONTROLLER,
                       base::Bind(&NetLogJobControllerCallback,
diff --git a/net/http/http_stream_factory_job_controller.h b/net/http/http_stream_factory_job_controller.h
index f24cdd7a..783759e 100644
--- a/net/http/http_stream_factory_job_controller.h
+++ b/net/http/http_stream_factory_job_controller.h
@@ -360,7 +360,7 @@
   RequestPriority priority_;
   const NetLogWithSource net_log_;
 
-  base::WeakPtrFactory<JobController> ptr_factory_;
+  base::WeakPtrFactory<JobController> ptr_factory_{this};
 };
 
 }  // namespace net
diff --git a/net/http/http_stream_factory_unittest.cc b/net/http/http_stream_factory_unittest.cc
index 21d6119..8162bec 100644
--- a/net/http/http_stream_factory_unittest.cc
+++ b/net/http/http_stream_factory_unittest.cc
@@ -113,8 +113,7 @@
     kStreamTypeSpdy,
   };
 
-  explicit MockWebSocketHandshakeStream(StreamType type)
-      : type_(type), weak_ptr_factory_(this) {}
+  explicit MockWebSocketHandshakeStream(StreamType type) : type_(type) {}
 
   ~MockWebSocketHandshakeStream() override = default;
 
@@ -173,7 +172,7 @@
 
  private:
   const StreamType type_;
-  base::WeakPtrFactory<MockWebSocketHandshakeStream> weak_ptr_factory_;
+  base::WeakPtrFactory<MockWebSocketHandshakeStream> weak_ptr_factory_{this};
 };
 
 // HttpStreamFactory subclass that can wait until a preconnect is complete.
diff --git a/net/http/http_stream_parser.cc b/net/http/http_stream_parser.cc
index 6615a48..aa3874c 100644
--- a/net/http/http_stream_parser.cc
+++ b/net/http/http_stream_parser.cc
@@ -211,8 +211,7 @@
       connection_is_reused_(connection_is_reused),
       net_log_(net_log),
       sent_last_chunk_(false),
-      upload_error_(OK),
-      weak_ptr_factory_(this) {
+      upload_error_(OK) {
   io_callback_ = base::BindRepeating(&HttpStreamParser::OnIOComplete,
                                      weak_ptr_factory_.GetWeakPtr());
 }
diff --git a/net/http/http_stream_parser.h b/net/http/http_stream_parser.h
index 16d24e2..0d559c3a 100644
--- a/net/http/http_stream_parser.h
+++ b/net/http/http_stream_parser.h
@@ -303,7 +303,7 @@
 
   MutableNetworkTrafficAnnotationTag traffic_annotation_;
 
-  base::WeakPtrFactory<HttpStreamParser> weak_ptr_factory_;
+  base::WeakPtrFactory<HttpStreamParser> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(HttpStreamParser);
 };
diff --git a/net/http/http_stream_parser_unittest.cc b/net/http/http_stream_parser_unittest.cc
index 16b77a3..e197da3 100644
--- a/net/http/http_stream_parser_unittest.cc
+++ b/net/http/http_stream_parser_unittest.cc
@@ -71,7 +71,7 @@
   enum class FailureMode { SYNC, ASYNC };
 
   explicit ReadErrorUploadDataStream(FailureMode mode)
-      : UploadDataStream(true, 0), async_(mode), weak_factory_(this) {}
+      : UploadDataStream(true, 0), async_(mode) {}
 
  private:
   void CompleteRead() { UploadDataStream::OnReadCompleted(ERR_FAILED); }
@@ -93,7 +93,7 @@
 
   const FailureMode async_;
 
-  base::WeakPtrFactory<ReadErrorUploadDataStream> weak_factory_;
+  base::WeakPtrFactory<ReadErrorUploadDataStream> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(ReadErrorUploadDataStream);
 };
@@ -200,7 +200,7 @@
 class InitAsyncUploadDataStream : public ChunkedUploadDataStream {
  public:
   explicit InitAsyncUploadDataStream(int64_t identifier)
-      : ChunkedUploadDataStream(identifier), weak_factory_(this) {}
+      : ChunkedUploadDataStream(identifier) {}
 
  private:
   void CompleteInit() { UploadDataStream::OnInitCompleted(OK); }
@@ -212,7 +212,7 @@
     return ERR_IO_PENDING;
   }
 
-  base::WeakPtrFactory<InitAsyncUploadDataStream> weak_factory_;
+  base::WeakPtrFactory<InitAsyncUploadDataStream> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(InitAsyncUploadDataStream);
 };
diff --git a/net/http/http_transaction_test_util.cc b/net/http/http_transaction_test_util.cc
index ce61d097..28b65dd1 100644
--- a/net/http/http_transaction_test_util.cc
+++ b/net/http/http_transaction_test_util.cc
@@ -263,8 +263,7 @@
       sent_bytes_(0),
       socket_log_id_(NetLogSource::kInvalidId),
       done_reading_called_(false),
-      reading_(false),
-      weak_factory_(this) {}
+      reading_(false) {}
 
 MockNetworkTransaction::~MockNetworkTransaction() {
   // Use request_ as in ~HttpNetworkTransaction to make sure its valid and not
diff --git a/net/http/http_transaction_test_util.h b/net/http/http_transaction_test_util.h
index 745a31f1..f1724b0 100644
--- a/net/http/http_transaction_test_util.h
+++ b/net/http/http_transaction_test_util.h
@@ -291,8 +291,7 @@
 
   CompletionOnceCallback resume_start_callback_;  // used for pause and restart.
 
-  base::WeakPtrFactory<MockNetworkTransaction> weak_factory_;
-
+  base::WeakPtrFactory<MockNetworkTransaction> weak_factory_{this};
 };
 
 class MockNetworkLayer : public HttpTransactionFactory,
diff --git a/net/http/partial_data.cc b/net/http/partial_data.cc
index fa6b488..e0eb396 100644
--- a/net/http/partial_data.cc
+++ b/net/http/partial_data.cc
@@ -41,8 +41,7 @@
       final_range_(false),
       sparse_entry_(true),
       truncated_(false),
-      initial_validation_(false),
-      weak_factory_(this) {}
+      initial_validation_(false) {}
 
 PartialData::~PartialData() = default;
 
diff --git a/net/http/partial_data.h b/net/http/partial_data.h
index 0ca5926..3e8b1a40 100644
--- a/net/http/partial_data.h
+++ b/net/http/partial_data.h
@@ -159,7 +159,7 @@
   bool truncated_;  // We have an incomplete 200 stored.
   bool initial_validation_;  // Only used for truncated entries.
   CompletionOnceCallback callback_;
-  base::WeakPtrFactory<PartialData> weak_factory_;
+  base::WeakPtrFactory<PartialData> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(PartialData);
 };
diff --git a/net/http/transport_security_persister.cc b/net/http/transport_security_persister.cc
index 804ea45d..0df5a0f 100644
--- a/net/http/transport_security_persister.cc
+++ b/net/http/transport_security_persister.cc
@@ -219,8 +219,7 @@
     : transport_security_state_(state),
       writer_(profile_path.AppendASCII("TransportSecurity"), background_runner),
       foreground_runner_(base::ThreadTaskRunnerHandle::Get()),
-      background_runner_(background_runner),
-      weak_ptr_factory_(this) {
+      background_runner_(background_runner) {
   transport_security_state_->SetDelegate(this);
 
   base::PostTaskAndReplyWithResult(
diff --git a/net/http/transport_security_persister.h b/net/http/transport_security_persister.h
index bfc85cb3..c8ba1d8 100644
--- a/net/http/transport_security_persister.h
+++ b/net/http/transport_security_persister.h
@@ -131,7 +131,7 @@
   scoped_refptr<base::SequencedTaskRunner> foreground_runner_;
   scoped_refptr<base::SequencedTaskRunner> background_runner_;
 
-  base::WeakPtrFactory<TransportSecurityPersister> weak_ptr_factory_;
+  base::WeakPtrFactory<TransportSecurityPersister> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(TransportSecurityPersister);
 };
diff --git a/net/log/trace_net_log_observer.cc b/net/log/trace_net_log_observer.cc
index a6ecb034..7b572840 100644
--- a/net/log/trace_net_log_observer.cc
+++ b/net/log/trace_net_log_observer.cc
@@ -47,8 +47,7 @@
 
 }  // namespace
 
-TraceNetLogObserver::TraceNetLogObserver()
-    : net_log_to_watch_(nullptr), weak_factory_(this) {}
+TraceNetLogObserver::TraceNetLogObserver() : net_log_to_watch_(nullptr) {}
 
 TraceNetLogObserver::~TraceNetLogObserver() {
   DCHECK(!net_log_to_watch_);
diff --git a/net/log/trace_net_log_observer.h b/net/log/trace_net_log_observer.h
index 0d7d8567..eea49c8 100644
--- a/net/log/trace_net_log_observer.h
+++ b/net/log/trace_net_log_observer.h
@@ -41,7 +41,7 @@
 
  private:
   NetLog* net_log_to_watch_;
-  base::WeakPtrFactory<TraceNetLogObserver> weak_factory_;
+  base::WeakPtrFactory<TraceNetLogObserver> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(TraceNetLogObserver);
 };
diff --git a/net/network_error_logging/network_error_logging_service.cc b/net/network_error_logging/network_error_logging_service.cc
index cf75fb6..6603eb8 100644
--- a/net/network_error_logging/network_error_logging_service.cc
+++ b/net/network_error_logging/network_error_logging_service.cc
@@ -182,10 +182,7 @@
 class NetworkErrorLoggingServiceImpl : public NetworkErrorLoggingService {
  public:
   explicit NetworkErrorLoggingServiceImpl(PersistentNelStore* store)
-      : store_(store),
-        started_loading_policies_(false),
-        initialized_(false),
-        weak_factory_(this) {
+      : store_(store), started_loading_policies_(false), initialized_(false) {
     if (!PoliciesArePersisted())
       initialized_ = true;
   }
@@ -345,7 +342,7 @@
   // Backlog of tasks waiting on initialization.
   std::vector<base::OnceClosure> task_backlog_;
 
-  base::WeakPtrFactory<NetworkErrorLoggingServiceImpl> weak_factory_;
+  base::WeakPtrFactory<NetworkErrorLoggingServiceImpl> weak_factory_{this};
 
   bool PoliciesArePersisted() const { return store_ != nullptr; }
 
diff --git a/net/nqe/network_quality_estimator.cc b/net/nqe/network_quality_estimator.cc
index b1f456e..d5b6730 100644
--- a/net/nqe/network_quality_estimator.cc
+++ b/net/nqe/network_quality_estimator.cc
@@ -174,8 +174,7 @@
       net_log_(NetLogWithSource::Make(
           net_log,
           net::NetLogSourceType::NETWORK_QUALITY_ESTIMATOR)),
-      event_creator_(net_log_),
-      weak_ptr_factory_(this) {
+      event_creator_(net_log_) {
   DCHECK_EQ(nqe::internal::OBSERVATION_CATEGORY_COUNT,
             base::size(rtt_ms_observations_));
 
diff --git a/net/nqe/network_quality_estimator.h b/net/nqe/network_quality_estimator.h
index 3c111ea..32977a9 100644
--- a/net/nqe/network_quality_estimator.h
+++ b/net/nqe/network_quality_estimator.h
@@ -698,7 +698,7 @@
   bool get_network_id_asynchronously_ = false;
 #endif
 
-  base::WeakPtrFactory<NetworkQualityEstimator> weak_ptr_factory_;
+  base::WeakPtrFactory<NetworkQualityEstimator> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(NetworkQualityEstimator);
 };
diff --git a/net/nqe/network_quality_store.cc b/net/nqe/network_quality_store.cc
index aa444b0..102ad4b 100644
--- a/net/nqe/network_quality_store.cc
+++ b/net/nqe/network_quality_store.cc
@@ -15,7 +15,7 @@
 
 namespace internal {
 
-NetworkQualityStore::NetworkQualityStore() : weak_ptr_factory_(this) {
+NetworkQualityStore::NetworkQualityStore() {
   static_assert(kMaximumNetworkQualityCacheSize > 0,
                 "Size of the network quality cache must be > 0");
   // This limit should not be increased unless the logic for removing the
diff --git a/net/nqe/network_quality_store.h b/net/nqe/network_quality_store.h
index 5250e52..a1aedc35 100644
--- a/net/nqe/network_quality_store.h
+++ b/net/nqe/network_quality_store.h
@@ -99,7 +99,7 @@
 
   SEQUENCE_CHECKER(sequence_checker_);
 
-  base::WeakPtrFactory<NetworkQualityStore> weak_ptr_factory_;
+  base::WeakPtrFactory<NetworkQualityStore> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(NetworkQualityStore);
 };
diff --git a/net/proxy_resolution/pac_file_fetcher_impl.cc b/net/proxy_resolution/pac_file_fetcher_impl.cc
index da10413f..506eeac 100644
--- a/net/proxy_resolution/pac_file_fetcher_impl.cc
+++ b/net/proxy_resolution/pac_file_fetcher_impl.cc
@@ -335,8 +335,7 @@
       result_text_(nullptr),
       max_response_bytes_(kDefaultMaxResponseBytes),
       max_duration_(kDefaultMaxDuration),
-      allow_file_url_(allow_file_url),
-      weak_factory_(this) {
+      allow_file_url_(allow_file_url) {
   DCHECK(url_request_context);
 }
 
diff --git a/net/proxy_resolution/pac_file_fetcher_impl.h b/net/proxy_resolution/pac_file_fetcher_impl.h
index 7bc1daa..397bf228 100644
--- a/net/proxy_resolution/pac_file_fetcher_impl.h
+++ b/net/proxy_resolution/pac_file_fetcher_impl.h
@@ -161,7 +161,7 @@
 
   // Factory for creating the time-out task. This takes care of revoking
   // outstanding tasks when |this| is deleted.
-  base::WeakPtrFactory<PacFileFetcherImpl> weak_factory_;
+  base::WeakPtrFactory<PacFileFetcherImpl> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(PacFileFetcherImpl);
 };
diff --git a/net/proxy_resolution/proxy_resolution_service.cc b/net/proxy_resolution/proxy_resolution_service.cc
index 9f906ae1..9d817f7 100644
--- a/net/proxy_resolution/proxy_resolution_service.cc
+++ b/net/proxy_resolution/proxy_resolution_service.cc
@@ -691,8 +691,7 @@
         dhcp_pac_file_fetcher_(dhcp_pac_file_fetcher),
         last_error_(init_net_error),
         last_script_data_(init_script_data),
-        last_poll_time_(TimeTicks::Now()),
-        weak_factory_(this) {
+        last_poll_time_(TimeTicks::Now()) {
     // Set the initial poll delay.
     next_poll_mode_ = poll_policy()->GetNextDelay(
         last_error_, TimeDelta::FromSeconds(-1), &next_poll_delay_);
@@ -846,7 +845,7 @@
 
   bool quick_check_enabled_;
 
-  base::WeakPtrFactory<PacFileDeciderPoller> weak_factory_;
+  base::WeakPtrFactory<PacFileDeciderPoller> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(PacFileDeciderPoller);
 };
@@ -1066,8 +1065,7 @@
       net_log_(net_log),
       stall_proxy_auto_config_delay_(
           TimeDelta::FromMilliseconds(kDelayAfterNetworkChangesMs)),
-      quick_check_enabled_(true),
-      weak_ptr_factory_(this) {
+      quick_check_enabled_(true) {
   NetworkChangeNotifier::AddIPAddressObserver(this);
   NetworkChangeNotifier::AddDNSObserver(this);
   config_service_->AddObserver(this);
diff --git a/net/proxy_resolution/proxy_resolution_service.h b/net/proxy_resolution/proxy_resolution_service.h
index d2f1edc..cf516ef 100644
--- a/net/proxy_resolution/proxy_resolution_service.h
+++ b/net/proxy_resolution/proxy_resolution_service.h
@@ -443,7 +443,7 @@
 
   // Flag used by |SetReady()| to check if |this| has been deleted by a
   // synchronous callback.
-  base::WeakPtrFactory<ProxyResolutionService> weak_ptr_factory_;
+  base::WeakPtrFactory<ProxyResolutionService> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(ProxyResolutionService);
 };
diff --git a/net/quic/bidirectional_stream_quic_impl.cc b/net/quic/bidirectional_stream_quic_impl.cc
index 06392df0..4445445 100644
--- a/net/quic/bidirectional_stream_quic_impl.cc
+++ b/net/quic/bidirectional_stream_quic_impl.cc
@@ -54,8 +54,7 @@
       closed_is_first_stream_(false),
       has_sent_headers_(false),
       send_request_headers_automatically_(true),
-      may_invoke_callbacks_(true),
-      weak_factory_(this) {}
+      may_invoke_callbacks_(true) {}
 
 BidirectionalStreamQuicImpl::~BidirectionalStreamQuicImpl() {
   if (stream_) {
diff --git a/net/quic/bidirectional_stream_quic_impl.h b/net/quic/bidirectional_stream_quic_impl.h
index aa5f938..cb3927b 100644
--- a/net/quic/bidirectional_stream_quic_impl.h
+++ b/net/quic/bidirectional_stream_quic_impl.h
@@ -128,7 +128,7 @@
   // True when callbacks to the delegate may be invoked synchronously.
   bool may_invoke_callbacks_;
 
-  base::WeakPtrFactory<BidirectionalStreamQuicImpl> weak_factory_;
+  base::WeakPtrFactory<BidirectionalStreamQuicImpl> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(BidirectionalStreamQuicImpl);
 };
diff --git a/net/quic/quic_chromium_alarm_factory.cc b/net/quic/quic_chromium_alarm_factory.cc
index 9124fb0..2eaf0bf 100644
--- a/net/quic/quic_chromium_alarm_factory.cc
+++ b/net/quic/quic_chromium_alarm_factory.cc
@@ -23,8 +23,7 @@
       : quic::QuicAlarm(std::move(delegate)),
         clock_(clock),
         task_runner_(task_runner),
-        task_deadline_(quic::QuicTime::Zero()),
-        weak_factory_(this) {}
+        task_deadline_(quic::QuicTime::Zero()) {}
 
  protected:
   void SetImpl() override {
@@ -84,7 +83,7 @@
   // post a new task when the new deadline now earlier than when
   // previously posted.
   quic::QuicTime task_deadline_;
-  base::WeakPtrFactory<QuicChromeAlarm> weak_factory_;
+  base::WeakPtrFactory<QuicChromeAlarm> weak_factory_{this};
 };
 
 }  // namespace
@@ -92,7 +91,7 @@
 QuicChromiumAlarmFactory::QuicChromiumAlarmFactory(
     base::TaskRunner* task_runner,
     const quic::QuicClock* clock)
-    : task_runner_(task_runner), clock_(clock), weak_factory_(this) {}
+    : task_runner_(task_runner), clock_(clock) {}
 
 QuicChromiumAlarmFactory::~QuicChromiumAlarmFactory() {}
 
diff --git a/net/quic/quic_chromium_alarm_factory.h b/net/quic/quic_chromium_alarm_factory.h
index 1e47833..d190a05 100644
--- a/net/quic/quic_chromium_alarm_factory.h
+++ b/net/quic/quic_chromium_alarm_factory.h
@@ -40,7 +40,7 @@
  private:
   base::TaskRunner* task_runner_;
   const quic::QuicClock* clock_;
-  base::WeakPtrFactory<QuicChromiumAlarmFactory> weak_factory_;
+  base::WeakPtrFactory<QuicChromiumAlarmFactory> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(QuicChromiumAlarmFactory);
 };
diff --git a/net/quic/quic_chromium_client_session.cc b/net/quic/quic_chromium_client_session.cc
index a4a7b34c..adbe7514 100644
--- a/net/quic/quic_chromium_client_session.cc
+++ b/net/quic/quic_chromium_client_session.cc
@@ -566,8 +566,7 @@
     : session_(session),
       requires_confirmation_(requires_confirmation),
       stream_(nullptr),
-      traffic_annotation_(traffic_annotation),
-      weak_factory_(this) {}
+      traffic_annotation_(traffic_annotation) {}
 
 QuicChromiumClientSession::StreamRequest::~StreamRequest() {
   if (stream_)
@@ -789,8 +788,7 @@
       ignore_read_error_(false),
       headers_include_h2_stream_dependency_(
           headers_include_h2_stream_dependency &&
-          this->connection()->transport_version() >= quic::QUIC_VERSION_43),
-      weak_factory_(this) {
+          this->connection()->transport_version() >= quic::QUIC_VERSION_43) {
   // Make sure connection migration and goaway on path degrading are not turned
   // on at the same time.
   DCHECK(!(migrate_session_early_v2_ && go_away_on_path_degrading_));
diff --git a/net/quic/quic_chromium_client_session.h b/net/quic/quic_chromium_client_session.h
index 7f6b919..35efd18 100644
--- a/net/quic/quic_chromium_client_session.h
+++ b/net/quic/quic_chromium_client_session.h
@@ -355,7 +355,7 @@
 
     const NetworkTrafficAnnotationTag traffic_annotation_;
 
-    base::WeakPtrFactory<StreamRequest> weak_factory_;
+    base::WeakPtrFactory<StreamRequest> weak_factory_{this};
 
     DISALLOW_COPY_AND_ASSIGN(StreamRequest);
   };
@@ -840,7 +840,7 @@
   bool headers_include_h2_stream_dependency_;
   Http2PriorityDependencies priority_dependency_state_;
 
-  base::WeakPtrFactory<QuicChromiumClientSession> weak_factory_;
+  base::WeakPtrFactory<QuicChromiumClientSession> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(QuicChromiumClientSession);
 };
diff --git a/net/quic/quic_chromium_client_stream.cc b/net/quic/quic_chromium_client_stream.cc
index 7b0c7a9..a2ce78f 100644
--- a/net/quic/quic_chromium_client_stream.cc
+++ b/net/quic/quic_chromium_client_stream.cc
@@ -46,8 +46,7 @@
       read_headers_buffer_(nullptr),
       read_body_buffer_len_(0),
       net_error_(ERR_UNEXPECTED),
-      net_log_(stream->net_log()),
-      weak_factory_(this) {
+      net_log_(stream->net_log()) {
   SaveState();
 }
 
@@ -414,8 +413,7 @@
       quic_version_(session->connection()->transport_version()),
       can_migrate_to_cellular_network_(true),
       initial_headers_frame_len_(0),
-      trailing_headers_frame_len_(0),
-      weak_factory_(this) {}
+      trailing_headers_frame_len_(0) {}
 
 QuicChromiumClientStream::QuicChromiumClientStream(
     quic::PendingStream* pending,
@@ -432,8 +430,7 @@
       quic_version_(session->connection()->transport_version()),
       can_migrate_to_cellular_network_(true),
       initial_headers_frame_len_(0),
-      trailing_headers_frame_len_(0),
-      weak_factory_(this) {}
+      trailing_headers_frame_len_(0) {}
 
 QuicChromiumClientStream::~QuicChromiumClientStream() {
   if (handle_)
diff --git a/net/quic/quic_chromium_client_stream.h b/net/quic/quic_chromium_client_stream.h
index b9773198..30baf2a5 100644
--- a/net/quic/quic_chromium_client_stream.h
+++ b/net/quic/quic_chromium_client_stream.h
@@ -192,7 +192,7 @@
 
     NetLogWithSource net_log_;
 
-    base::WeakPtrFactory<Handle> weak_factory_;
+    base::WeakPtrFactory<Handle> weak_factory_{this};
 
     DISALLOW_COPY_AND_ASSIGN(Handle);
   };
@@ -311,7 +311,7 @@
   // Length of the HEADERS frame containing trailing headers.
   size_t trailing_headers_frame_len_;
 
-  base::WeakPtrFactory<QuicChromiumClientStream> weak_factory_;
+  base::WeakPtrFactory<QuicChromiumClientStream> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(QuicChromiumClientStream);
 };
diff --git a/net/quic/quic_chromium_packet_reader.cc b/net/quic/quic_chromium_packet_reader.cc
index 4f7ec5b..c0c2bc7 100644
--- a/net/quic/quic_chromium_packet_reader.cc
+++ b/net/quic/quic_chromium_packet_reader.cc
@@ -32,8 +32,7 @@
       yield_after_(quic::QuicTime::Infinite()),
       read_buffer_(base::MakeRefCounted<IOBufferWithSize>(
           static_cast<size_t>(quic::kMaxOutgoingPacketSize))),
-      net_log_(net_log),
-      weak_factory_(this) {}
+      net_log_(net_log) {}
 
 QuicChromiumPacketReader::~QuicChromiumPacketReader() {}
 
diff --git a/net/quic/quic_chromium_packet_reader.h b/net/quic/quic_chromium_packet_reader.h
index 5734aa72..b4d2507 100644
--- a/net/quic/quic_chromium_packet_reader.h
+++ b/net/quic/quic_chromium_packet_reader.h
@@ -70,7 +70,7 @@
   scoped_refptr<IOBufferWithSize> read_buffer_;
   NetLogWithSource net_log_;
 
-  base::WeakPtrFactory<QuicChromiumPacketReader> weak_factory_;
+  base::WeakPtrFactory<QuicChromiumPacketReader> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(QuicChromiumPacketReader);
 };
diff --git a/net/quic/quic_chromium_packet_writer.cc b/net/quic/quic_chromium_packet_writer.cc
index 4cb3be9f..7c38674e 100644
--- a/net/quic/quic_chromium_packet_writer.cc
+++ b/net/quic/quic_chromium_packet_writer.cc
@@ -81,7 +81,7 @@
   std::memcpy(data(), buffer, buf_len);
 }
 
-QuicChromiumPacketWriter::QuicChromiumPacketWriter() : weak_factory_(this) {}
+QuicChromiumPacketWriter::QuicChromiumPacketWriter() {}
 
 QuicChromiumPacketWriter::QuicChromiumPacketWriter(
     DatagramClientSocket* socket,
@@ -92,8 +92,7 @@
           base::MakeRefCounted<ReusableIOBuffer>(quic::kMaxOutgoingPacketSize)),
       write_in_progress_(false),
       force_write_blocked_(false),
-      retry_count_(0),
-      weak_factory_(this) {
+      retry_count_(0) {
   retry_timer_.SetTaskRunner(task_runner);
   write_callback_ = base::BindRepeating(
       &QuicChromiumPacketWriter::OnWriteComplete, weak_factory_.GetWeakPtr());
diff --git a/net/quic/quic_chromium_packet_writer.h b/net/quic/quic_chromium_packet_writer.h
index 1a667f2..82acb30 100644
--- a/net/quic/quic_chromium_packet_writer.h
+++ b/net/quic/quic_chromium_packet_writer.h
@@ -126,7 +126,7 @@
   base::OneShotTimer retry_timer_;
 
   CompletionRepeatingCallback write_callback_;
-  base::WeakPtrFactory<QuicChromiumPacketWriter> weak_factory_;
+  base::WeakPtrFactory<QuicChromiumPacketWriter> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(QuicChromiumPacketWriter);
 };
diff --git a/net/quic/quic_connectivity_probing_manager.cc b/net/quic/quic_connectivity_probing_manager.cc
index 7f33513..646d7cc 100644
--- a/net/quic/quic_connectivity_probing_manager.cc
+++ b/net/quic/quic_connectivity_probing_manager.cc
@@ -63,8 +63,7 @@
       network_(NetworkChangeNotifier::kInvalidNetworkHandle),
       retry_count_(0),
       probe_start_time_(base::TimeTicks()),
-      task_runner_(task_runner),
-      weak_factory_(this) {
+      task_runner_(task_runner) {
   retransmit_timer_.SetTaskRunner(task_runner_);
 }
 
diff --git a/net/quic/quic_connectivity_probing_manager.h b/net/quic/quic_connectivity_probing_manager.h
index e18ae034..aa5bc7a 100644
--- a/net/quic/quic_connectivity_probing_manager.h
+++ b/net/quic/quic_connectivity_probing_manager.h
@@ -128,7 +128,7 @@
 
   base::SequencedTaskRunner* task_runner_;
 
-  base::WeakPtrFactory<QuicConnectivityProbingManager> weak_factory_;
+  base::WeakPtrFactory<QuicConnectivityProbingManager> weak_factory_{this};
   DISALLOW_COPY_AND_ASSIGN(QuicConnectivityProbingManager);
 };
 
diff --git a/net/quic/quic_http_stream.cc b/net/quic/quic_http_stream.cc
index e2bbe9a..0d1da7f8 100644
--- a/net/quic/quic_http_stream.cc
+++ b/net/quic/quic_http_stream.cc
@@ -67,8 +67,7 @@
       user_buffer_len_(0),
       session_error_(ERR_UNEXPECTED),
       found_promise_(false),
-      in_loop_(false),
-      weak_factory_(this) {}
+      in_loop_(false) {}
 
 QuicHttpStream::~QuicHttpStream() {
   CHECK(!in_loop_);
diff --git a/net/quic/quic_http_stream.h b/net/quic/quic_http_stream.h
index babc2a1..0440c76 100644
--- a/net/quic/quic_http_stream.h
+++ b/net/quic/quic_http_stream.h
@@ -218,7 +218,7 @@
   // Session connect timing info.
   LoadTimingInfo::ConnectTiming connect_timing_;
 
-  base::WeakPtrFactory<QuicHttpStream> weak_factory_;
+  base::WeakPtrFactory<QuicHttpStream> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(QuicHttpStream);
 };
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index 0d1a74d..eff65950 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -115,7 +115,7 @@
   enum class FailureMode { SYNC, ASYNC };
 
   explicit ReadErrorUploadDataStream(FailureMode mode)
-      : UploadDataStream(true, 0), async_(mode), weak_factory_(this) {}
+      : UploadDataStream(true, 0), async_(mode) {}
   ~ReadErrorUploadDataStream() override {}
 
  private:
@@ -138,7 +138,7 @@
 
   const FailureMode async_;
 
-  base::WeakPtrFactory<ReadErrorUploadDataStream> weak_factory_;
+  base::WeakPtrFactory<ReadErrorUploadDataStream> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(ReadErrorUploadDataStream);
 };
diff --git a/net/quic/quic_proxy_client_socket.cc b/net/quic/quic_proxy_client_socket.cc
index 3e925c90..36c67d1 100644
--- a/net/quic/quic_proxy_client_socket.cc
+++ b/net/quic/quic_proxy_client_socket.cc
@@ -36,8 +36,7 @@
       endpoint_(endpoint),
       auth_(auth_controller),
       user_agent_(user_agent),
-      net_log_(net_log),
-      weak_factory_(this) {
+      net_log_(net_log) {
   DCHECK(stream_->IsOpen());
 
   request_.method = "CONNECT";
diff --git a/net/quic/quic_proxy_client_socket.h b/net/quic/quic_proxy_client_socket.h
index d72aed88..299526c8 100644
--- a/net/quic/quic_proxy_client_socket.h
+++ b/net/quic/quic_proxy_client_socket.h
@@ -145,7 +145,7 @@
   const NetLogWithSource net_log_;
 
   // The default weak pointer factory.
-  base::WeakPtrFactory<QuicProxyClientSocket> weak_factory_;
+  base::WeakPtrFactory<QuicProxyClientSocket> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(QuicProxyClientSocket);
 };
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index d118d1dd..a4e2c6d0 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -267,8 +267,7 @@
             std::make_unique<ProofVerifyContextChromium>(cert_verify_flags,
                                                          net_log)),
         start_time_(base::TimeTicks::Now()),
-        net_log_(net_log),
-        weak_factory_(this) {}
+        net_log_(net_log) {}
 
   ~CertVerifierJob() {
     if (verify_callback_)
@@ -319,7 +318,7 @@
   const base::TimeTicks start_time_;
   const NetLogWithSource net_log_;
   CompletionOnceCallback callback_;
-  base::WeakPtrFactory<CertVerifierJob> weak_factory_;
+  base::WeakPtrFactory<CertVerifierJob> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(CertVerifierJob);
 };
@@ -500,7 +499,7 @@
   base::TimeTicks dns_resolution_start_time_;
   base::TimeTicks dns_resolution_end_time_;
   std::set<QuicStreamRequest*> stream_requests_;
-  base::WeakPtrFactory<Job> weak_factory_;
+  base::WeakPtrFactory<Job> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(Job);
 };
@@ -533,8 +532,7 @@
       host_resolution_finished_(false),
       connection_retried_(false),
       session_(nullptr),
-      network_(NetworkChangeNotifier::kInvalidNetworkHandle),
-      weak_factory_(this) {
+      network_(NetworkChangeNotifier::kInvalidNetworkHandle) {
   net_log_.BeginEvent(
       NetLogEventType::QUIC_STREAM_FACTORY_JOB,
       base::Bind(&NetLogQuicStreamFactoryJobCallback, &key_.server_id()));
@@ -1156,8 +1154,7 @@
       ssl_config_service_(ssl_config_service),
       enable_socket_recv_optimization_(enable_socket_recv_optimization),
       initial_rtt_for_handshake_milliseconds_(
-          initial_rtt_for_handshake_milliseconds),
-      weak_factory_(this) {
+          initial_rtt_for_handshake_milliseconds) {
   DCHECK(transport_security_state_);
   DCHECK(http_server_properties_);
   crypto_config_.set_user_agent_id(user_agent_id);
diff --git a/net/quic/quic_stream_factory.h b/net/quic/quic_stream_factory.h
index c3cc96f..a5de5f7 100644
--- a/net/quic/quic_stream_factory.h
+++ b/net/quic/quic_stream_factory.h
@@ -634,7 +634,7 @@
   // The initial rtt for handshake.
   const int initial_rtt_for_handshake_milliseconds_;
 
-  base::WeakPtrFactory<QuicStreamFactory> weak_factory_;
+  base::WeakPtrFactory<QuicStreamFactory> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(QuicStreamFactory);
 };
diff --git a/net/reporting/reporting_delivery_agent.cc b/net/reporting/reporting_delivery_agent.cc
index 31bfde7a..c3069c93 100644
--- a/net/reporting/reporting_delivery_agent.cc
+++ b/net/reporting/reporting_delivery_agent.cc
@@ -55,9 +55,7 @@
                                    public ReportingCacheObserver {
  public:
   ReportingDeliveryAgentImpl(ReportingContext* context)
-      : context_(context),
-        timer_(std::make_unique<base::OneShotTimer>()),
-        weak_factory_(this) {
+      : context_(context), timer_(std::make_unique<base::OneShotTimer>()) {
     context_->AddCacheObserver(this);
   }
 
@@ -278,7 +276,7 @@
   // (Would be an unordered_set, but there's no hash on pair.)
   std::set<OriginGroup> pending_origin_groups_;
 
-  base::WeakPtrFactory<ReportingDeliveryAgentImpl> weak_factory_;
+  base::WeakPtrFactory<ReportingDeliveryAgentImpl> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(ReportingDeliveryAgentImpl);
 };
diff --git a/net/server/http_server.cc b/net/server/http_server.cc
index 9b9116d..678d6f4 100644
--- a/net/server/http_server.cc
+++ b/net/server/http_server.cc
@@ -56,8 +56,7 @@
                        HttpServer::Delegate* delegate)
     : server_socket_(std::move(server_socket)),
       delegate_(delegate),
-      last_id_(0),
-      weak_ptr_factory_(this) {
+      last_id_(0) {
   DCHECK(server_socket_);
   // Start accepting connections in next run loop in case when delegate is not
   // ready to get callbacks.
diff --git a/net/server/http_server.h b/net/server/http_server.h
index c6e2554c..cb70b57 100644
--- a/net/server/http_server.h
+++ b/net/server/http_server.h
@@ -131,7 +131,7 @@
   int last_id_;
   std::map<int, std::unique_ptr<HttpConnection>> id_to_connection_;
 
-  base::WeakPtrFactory<HttpServer> weak_ptr_factory_;
+  base::WeakPtrFactory<HttpServer> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(HttpServer);
 };
diff --git a/net/socket/client_socket_pool_base_unittest.cc b/net/socket/client_socket_pool_base_unittest.cc
index faa4951..7ece0376 100644
--- a/net/socket/client_socket_pool_base_unittest.cc
+++ b/net/socket/client_socket_pool_base_unittest.cc
@@ -334,8 +334,7 @@
         client_socket_factory_(client_socket_factory),
         load_state_(LOAD_STATE_IDLE),
         has_established_connection_(false),
-        store_additional_error_state_(false),
-        weak_factory_(this) {}
+        store_additional_error_state_(false) {}
 
   void Signal() {
     DoConnect(waiting_success_, true /* async */, false /* recoverable */);
@@ -524,7 +523,7 @@
   bool has_established_connection_;
   bool store_additional_error_state_;
 
-  base::WeakPtrFactory<TestConnectJob> weak_factory_;
+  base::WeakPtrFactory<TestConnectJob> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(TestConnectJob);
 };
diff --git a/net/socket/fuzzed_datagram_client_socket.cc b/net/socket/fuzzed_datagram_client_socket.cc
index aea50374..db03e578 100644
--- a/net/socket/fuzzed_datagram_client_socket.cc
+++ b/net/socket/fuzzed_datagram_client_socket.cc
@@ -30,7 +30,7 @@
 
 FuzzedDatagramClientSocket::FuzzedDatagramClientSocket(
     FuzzedDataProvider* data_provider)
-    : data_provider_(data_provider), weak_factory_(this) {}
+    : data_provider_(data_provider) {}
 
 FuzzedDatagramClientSocket::~FuzzedDatagramClientSocket() = default;
 
diff --git a/net/socket/fuzzed_datagram_client_socket.h b/net/socket/fuzzed_datagram_client_socket.h
index 9659bec..f53eaec 100644
--- a/net/socket/fuzzed_datagram_client_socket.h
+++ b/net/socket/fuzzed_datagram_client_socket.h
@@ -91,7 +91,7 @@
 
   IPEndPoint remote_address_;
 
-  base::WeakPtrFactory<FuzzedDatagramClientSocket> weak_factory_;
+  base::WeakPtrFactory<FuzzedDatagramClientSocket> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(FuzzedDatagramClientSocket);
 };
diff --git a/net/socket/fuzzed_server_socket.cc b/net/socket/fuzzed_server_socket.cc
index 7e2d4b9..a5fc9dbe 100644
--- a/net/socket/fuzzed_server_socket.cc
+++ b/net/socket/fuzzed_server_socket.cc
@@ -18,8 +18,7 @@
     : data_provider_(data_provider),
       net_log_(net_log),
       first_accept_(true),
-      listen_called_(false),
-      weak_factory_(this) {}
+      listen_called_(false) {}
 
 FuzzedServerSocket::~FuzzedServerSocket() = default;
 
diff --git a/net/socket/fuzzed_server_socket.h b/net/socket/fuzzed_server_socket.h
index 006fa85..03c64672 100644
--- a/net/socket/fuzzed_server_socket.h
+++ b/net/socket/fuzzed_server_socket.h
@@ -52,7 +52,7 @@
   bool first_accept_;
   bool listen_called_;
 
-  base::WeakPtrFactory<FuzzedServerSocket> weak_factory_;
+  base::WeakPtrFactory<FuzzedServerSocket> weak_factory_{this};
   DISALLOW_COPY_AND_ASSIGN(FuzzedServerSocket);
 };
 
diff --git a/net/socket/fuzzed_socket.cc b/net/socket/fuzzed_socket.cc
index a71a6d5..9952f2d8 100644
--- a/net/socket/fuzzed_socket.cc
+++ b/net/socket/fuzzed_socket.cc
@@ -40,8 +40,7 @@
                            net::NetLog* net_log)
     : data_provider_(data_provider),
       net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::SOCKET)),
-      remote_address_(IPEndPoint(IPAddress::IPv4Localhost(), 80)),
-      weak_factory_(this) {}
+      remote_address_(IPEndPoint(IPAddress::IPv4Localhost(), 80)) {}
 
 FuzzedSocket::~FuzzedSocket() = default;
 
diff --git a/net/socket/fuzzed_socket.h b/net/socket/fuzzed_socket.h
index 63d069e..8e420c1 100644
--- a/net/socket/fuzzed_socket.h
+++ b/net/socket/fuzzed_socket.h
@@ -131,7 +131,7 @@
 
   IPEndPoint remote_address_;
 
-  base::WeakPtrFactory<FuzzedSocket> weak_factory_;
+  base::WeakPtrFactory<FuzzedSocket> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(FuzzedSocket);
 };
diff --git a/net/socket/socket_bio_adapter.cc b/net/socket/socket_bio_adapter.cc
index 6e24969..6f134af6 100644
--- a/net/socket/socket_bio_adapter.cc
+++ b/net/socket/socket_bio_adapter.cc
@@ -66,8 +66,7 @@
       write_buffer_capacity_(write_buffer_capacity),
       write_buffer_used_(0),
       write_error_(OK),
-      delegate_(delegate),
-      weak_factory_(this) {
+      delegate_(delegate) {
   bio_.reset(BIO_new(&kBIOMethod));
   bio_->ptr = this;
   bio_->init = 1;
diff --git a/net/socket/socket_bio_adapter.h b/net/socket/socket_bio_adapter.h
index 9547535..98421c7 100644
--- a/net/socket/socket_bio_adapter.h
+++ b/net/socket/socket_bio_adapter.h
@@ -136,7 +136,7 @@
 
   Delegate* delegate_;
 
-  base::WeakPtrFactory<SocketBIOAdapter> weak_factory_;
+  base::WeakPtrFactory<SocketBIOAdapter> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(SocketBIOAdapter);
 };
diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc
index 69c1f95..183e3a78 100644
--- a/net/socket/socket_test_util.cc
+++ b/net/socket/socket_test_util.cc
@@ -361,8 +361,7 @@
       sequence_number_(0),
       read_state_(IDLE),
       write_state_(IDLE),
-      busy_before_sync_reads_(false),
-      weak_factory_(this) {
+      busy_before_sync_reads_(false) {
   // Check that reads and writes have a contiguous set of sequence numbers
   // starting from 0 and working their way up, with no repeats and skipping
   // no values.
@@ -860,7 +859,7 @@
 }
 
 MockClientSocket::MockClientSocket(const NetLogWithSource& net_log)
-    : connected_(false), net_log_(net_log), weak_factory_(this) {
+    : connected_(false), net_log_(net_log) {
   local_addr_ = IPEndPoint(IPAddress(192, 0, 2, 33), 123);
   peer_addr_ = IPEndPoint(IPAddress(192, 0, 2, 33), 0);
 }
@@ -1305,8 +1304,7 @@
     : net_log_(socket->NetLog()),
       socket_(std::move(socket)),
       data_(data),
-      auth_controller_(auth_controller),
-      weak_factory_(this) {
+      auth_controller_(auth_controller) {
   DCHECK(data_);
 }
 
@@ -1472,8 +1470,7 @@
     SSLSocketDataProvider* data)
     : net_log_(stream_socket->NetLog()),
       stream_socket_(std::move(stream_socket)),
-      data_(data),
-      weak_factory_(this) {
+      data_(data) {
   DCHECK(data_);
   peer_addr_ = data->connect.peer_addr;
 }
@@ -1674,8 +1671,7 @@
       network_(NetworkChangeNotifier::kInvalidNetworkHandle),
       pending_read_buf_(nullptr),
       pending_read_buf_len_(0),
-      net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::NONE)),
-      weak_factory_(this) {
+      net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::NONE)) {
   DCHECK(data_);
   data_->Initialize(this);
   peer_addr_ = data->connect_data().peer_addr;
diff --git a/net/socket/socket_test_util.h b/net/socket/socket_test_util.h
index 9a53e1c..b9740cd 100644
--- a/net/socket/socket_test_util.h
+++ b/net/socket/socket_test_util.h
@@ -588,7 +588,7 @@
   // Used by RunUntilPaused.  NULL at all other times.
   std::unique_ptr<base::RunLoop> run_until_paused_run_loop_;
 
-  base::WeakPtrFactory<SequencedSocketData> weak_factory_;
+  base::WeakPtrFactory<SequencedSocketData> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(SequencedSocketData);
 };
@@ -752,7 +752,7 @@
   NetLogWithSource net_log_;
 
  private:
-  base::WeakPtrFactory<MockClientSocket> weak_factory_;
+  base::WeakPtrFactory<MockClientSocket> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(MockClientSocket);
 };
@@ -913,7 +913,7 @@
   ProxyClientSocketDataProvider* data_;
   scoped_refptr<HttpAuthController> auth_controller_;
 
-  base::WeakPtrFactory<MockProxyClientSocket> weak_factory_;
+  base::WeakPtrFactory<MockProxyClientSocket> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(MockProxyClientSocket);
 };
@@ -995,7 +995,7 @@
   // Address of the "remote" peer we're connected to.
   IPEndPoint peer_addr_;
 
-  base::WeakPtrFactory<MockSSLClientSocket> weak_factory_;
+  base::WeakPtrFactory<MockSSLClientSocket> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(MockSSLClientSocket);
 };
@@ -1102,7 +1102,7 @@
   bool data_transferred_ = false;
   bool tagged_before_data_transferred_ = true;
 
-  base::WeakPtrFactory<MockUDPClientSocket> weak_factory_;
+  base::WeakPtrFactory<MockUDPClientSocket> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(MockUDPClientSocket);
 };
diff --git a/net/socket/ssl_client_socket_impl.cc b/net/socket/ssl_client_socket_impl.cc
index 19ca9e2..292c138 100644
--- a/net/socket/ssl_client_socket_impl.cc
+++ b/net/socket/ssl_client_socket_impl.cc
@@ -427,8 +427,7 @@
       policy_enforcer_(context.ct_policy_enforcer),
       pkp_bypassed_(false),
       is_fatal_cert_error_(false),
-      net_log_(stream_socket_->NetLog()),
-      weak_factory_(this) {
+      net_log_(stream_socket_->NetLog()) {
   CHECK(cert_verifier_);
   CHECK(transport_security_state_);
   CHECK(cert_transparency_verifier_);
diff --git a/net/socket/ssl_client_socket_impl.h b/net/socket/ssl_client_socket_impl.h
index f4a1a687..4facc3da 100644
--- a/net/socket/ssl_client_socket_impl.h
+++ b/net/socket/ssl_client_socket_impl.h
@@ -302,7 +302,7 @@
   bool is_fatal_cert_error_;
 
   NetLogWithSource net_log_;
-  base::WeakPtrFactory<SSLClientSocketImpl> weak_factory_;
+  base::WeakPtrFactory<SSLClientSocketImpl> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(SSLClientSocketImpl);
 };
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc
index 3d39d635..97d62b52 100644
--- a/net/socket/ssl_client_socket_unittest.cc
+++ b/net/socket/ssl_client_socket_unittest.cc
@@ -1152,7 +1152,7 @@
     rv = callback.GetResult(sock->Connect(callback.callback()));
     EXPECT_THAT(rv, IsError(ERR_SSL_CLIENT_AUTH_CERT_NEEDED));
 
-    scoped_refptr<SSLCertRequestInfo> request_info = new SSLCertRequestInfo();
+    auto request_info = base::MakeRefCounted<SSLCertRequestInfo>();
     sock->GetSSLCertRequestInfo(request_info.get());
     sock->Disconnect();
     EXPECT_FALSE(sock->IsConnected());
diff --git a/net/socket/ssl_server_socket_impl.cc b/net/socket/ssl_server_socket_impl.cc
index dac7d7e..1fe8b18b 100644
--- a/net/socket/ssl_server_socket_impl.cc
+++ b/net/socket/ssl_server_socket_impl.cc
@@ -212,7 +212,7 @@
 
   NextProto negotiated_protocol_;
 
-  base::WeakPtrFactory<SocketImpl> weak_factory_;
+  base::WeakPtrFactory<SocketImpl> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(SocketImpl);
 };
@@ -228,8 +228,7 @@
       transport_socket_(std::move(transport_socket)),
       next_handshake_state_(STATE_NONE),
       completed_handshake_(false),
-      negotiated_protocol_(kProtoUnknown),
-      weak_factory_(this) {
+      negotiated_protocol_(kProtoUnknown) {
   ssl_.reset(SSL_new(context_->ssl_ctx_.get()));
   SSL_set_app_data(ssl_.get(), this);
   SSL_set_shed_handshake_config(ssl_.get(), 1);
diff --git a/net/socket/ssl_server_socket_unittest.cc b/net/socket/ssl_server_socket_unittest.cc
index 0a4c466..200b90a 100644
--- a/net/socket/ssl_server_socket_unittest.cc
+++ b/net/socket/ssl_server_socket_unittest.cc
@@ -103,11 +103,7 @@
 class FakeDataChannel {
  public:
   FakeDataChannel()
-      : read_buf_len_(0),
-        closed_(false),
-        write_called_after_close_(false),
-        weak_factory_(this) {
-  }
+      : read_buf_len_(0), closed_(false), write_called_after_close_(false) {}
 
   int Read(IOBuffer* buf, int buf_len, CompletionOnceCallback callback) {
     DCHECK(read_callback_.is_null());
@@ -214,7 +210,7 @@
   // asynchronously.
   bool write_called_after_close_;
 
-  base::WeakPtrFactory<FakeDataChannel> weak_factory_;
+  base::WeakPtrFactory<FakeDataChannel> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(FakeDataChannel);
 };
@@ -791,7 +787,7 @@
             connect_callback.GetResult(
                 client_socket_->Connect(connect_callback.callback())));
 
-  scoped_refptr<SSLCertRequestInfo> request_info = new SSLCertRequestInfo();
+  auto request_info = base::MakeRefCounted<SSLCertRequestInfo>();
   client_socket_->GetSSLCertRequestInfo(request_info.get());
 
   // Check that the authority name that arrived in the CertificateRequest
@@ -825,7 +821,7 @@
             connect_callback.GetResult(
                 client_socket_->Connect(connect_callback.callback())));
 
-  scoped_refptr<SSLCertRequestInfo> request_info = new SSLCertRequestInfo();
+  auto request_info = base::MakeRefCounted<SSLCertRequestInfo>();
   client_socket_->GetSSLCertRequestInfo(request_info.get());
 
   // Check that the authority name that arrived in the CertificateRequest
@@ -851,7 +847,7 @@
             connect_callback2.GetResult(
                 client_socket_->Connect(connect_callback2.callback())));
 
-  scoped_refptr<SSLCertRequestInfo> request_info2 = new SSLCertRequestInfo();
+  auto request_info2 = base::MakeRefCounted<SSLCertRequestInfo>();
   client_socket_->GetSSLCertRequestInfo(request_info2.get());
 
   // Check that the authority name that arrived in the CertificateRequest
diff --git a/net/socket/tcp_client_socket.cc b/net/socket/tcp_client_socket.cc
index 088d768..46d0a7d 100644
--- a/net/socket/tcp_client_socket.cc
+++ b/net/socket/tcp_client_socket.cc
@@ -142,8 +142,7 @@
       previously_disconnected_(false),
       total_received_bytes_(0),
       was_ever_used_(false),
-      was_disconnected_on_suspend_(false),
-      weak_ptr_factory_(this) {
+      was_disconnected_on_suspend_(false) {
   DCHECK(socket_);
   if (socket_->IsValid())
     socket_->SetDefaultOptionsForClient();
diff --git a/net/socket/tcp_client_socket.h b/net/socket/tcp_client_socket.h
index 1bf0038..306c6b35 100644
--- a/net/socket/tcp_client_socket.h
+++ b/net/socket/tcp_client_socket.h
@@ -207,7 +207,7 @@
   // Connect() or Disconnect() is called.
   bool was_disconnected_on_suspend_;
 
-  base::WeakPtrFactory<TCPClientSocket> weak_ptr_factory_;
+  base::WeakPtrFactory<TCPClientSocket> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(TCPClientSocket);
 };
diff --git a/net/socket/transport_client_socket_pool.cc b/net/socket/transport_client_socket_pool.cc
index a69add8a5..86f647c10 100644
--- a/net/socket/transport_client_socket_pool.cc
+++ b/net/socket/transport_client_socket_pool.cc
@@ -780,8 +780,7 @@
       connect_job_factory_(std::move(connect_job_factory)),
       connect_backup_jobs_enabled_(connect_backup_jobs_enabled &&
                                    g_connect_backup_jobs_enabled),
-      ssl_config_service_(ssl_config_service),
-      weak_factory_(this) {
+      ssl_config_service_(ssl_config_service) {
   DCHECK_LE(0, max_sockets_per_group);
   DCHECK_LE(max_sockets_per_group, max_sockets);
 
diff --git a/net/socket/transport_client_socket_pool.h b/net/socket/transport_client_socket_pool.h
index 2f611482..02ac61e 100644
--- a/net/socket/transport_client_socket_pool.h
+++ b/net/socket/transport_client_socket_pool.h
@@ -795,7 +795,7 @@
 
   SSLConfigService* const ssl_config_service_;
 
-  base::WeakPtrFactory<TransportClientSocketPool> weak_factory_;
+  base::WeakPtrFactory<TransportClientSocketPool> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(TransportClientSocketPool);
 };
diff --git a/net/socket/transport_client_socket_pool_test_util.cc b/net/socket/transport_client_socket_pool_test_util.cc
index bf8b36601..8d67fbf 100644
--- a/net/socket/transport_client_socket_pool_test_util.cc
+++ b/net/socket/transport_client_socket_pool_test_util.cc
@@ -194,8 +194,7 @@
       : should_connect_(should_connect),
         is_connected_(false),
         addrlist_(addrlist),
-        net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::SOCKET)),
-        weak_factory_(this) {}
+        net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::SOCKET)) {}
 
   // Call this method to get a closure which will trigger the connect callback
   // when called. The closure can be called even after the socket is deleted; it
@@ -322,7 +321,7 @@
   CompletionOnceCallback callback_;
   ConnectionAttempts connection_attempts_;
 
-  base::WeakPtrFactory<MockTriggerableClientSocket> weak_factory_;
+  base::WeakPtrFactory<MockTriggerableClientSocket> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(MockTriggerableClientSocket);
 };
diff --git a/net/socket/transport_connect_job.cc b/net/socket/transport_connect_job.cc
index 047ac7a..dafaeca 100644
--- a/net/socket/transport_connect_job.cc
+++ b/net/socket/transport_connect_job.cc
@@ -101,8 +101,7 @@
                  NetLogEventType::TRANSPORT_CONNECT_JOB_CONNECT),
       params_(params),
       next_state_(STATE_NONE),
-      resolve_result_(OK),
-      weak_ptr_factory_(this) {
+      resolve_result_(OK) {
   // This is only set for WebSockets.
   DCHECK(!common_connect_job_params->websocket_endpoint_lock_manager);
 }
diff --git a/net/socket/transport_connect_job.h b/net/socket/transport_connect_job.h
index 0258e52..69b763d 100644
--- a/net/socket/transport_connect_job.h
+++ b/net/socket/transport_connect_job.h
@@ -170,7 +170,7 @@
   ConnectionAttempts connection_attempts_;
   ConnectionAttempts fallback_connection_attempts_;
 
-  base::WeakPtrFactory<TransportConnectJob> weak_ptr_factory_;
+  base::WeakPtrFactory<TransportConnectJob> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(TransportConnectJob);
 };
diff --git a/net/socket/udp_socket_perftest.cc b/net/socket/udp_socket_perftest.cc
index 4c340828..05018ff 100644
--- a/net/socket/udp_socket_perftest.cc
+++ b/net/socket/udp_socket_perftest.cc
@@ -30,8 +30,7 @@
 class UDPSocketPerfTest : public PlatformTest {
  public:
   UDPSocketPerfTest()
-      : buffer_(base::MakeRefCounted<IOBufferWithSize>(kPacketSize)),
-        weak_factory_(this) {}
+      : buffer_(base::MakeRefCounted<IOBufferWithSize>(kPacketSize)) {}
 
   void DoneWritePacketsToSocket(UDPClientSocket* socket,
                                 int num_of_packets,
@@ -52,7 +51,7 @@
  protected:
   static const int kPacketSize = 1024;
   scoped_refptr<IOBufferWithSize> buffer_;
-  base::WeakPtrFactory<UDPSocketPerfTest> weak_factory_;
+  base::WeakPtrFactory<UDPSocketPerfTest> weak_factory_{this};
 };
 
 const int UDPSocketPerfTest::kPacketSize;
diff --git a/net/socket/udp_socket_posix.cc b/net/socket/udp_socket_posix.cc
index 08bf79c..f09bd57 100644
--- a/net/socket/udp_socket_posix.cc
+++ b/net/socket/udp_socket_posix.cc
@@ -200,8 +200,7 @@
       write_buf_len_(0),
       net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::UDP_SOCKET)),
       bound_network_(NetworkChangeNotifier::kInvalidNetworkHandle),
-      experimental_recv_optimization_enabled_(false),
-      weak_factory_(this) {
+      experimental_recv_optimization_enabled_(false) {
   net_log_.BeginEvent(NetLogEventType::SOCKET_ALIVE,
                       source.ToEventParametersCallback());
 }
diff --git a/net/socket/udp_socket_posix.h b/net/socket/udp_socket_posix.h
index c62b4a8..ce96046e 100644
--- a/net/socket/udp_socket_posix.h
+++ b/net/socket/udp_socket_posix.h
@@ -632,7 +632,7 @@
   THREAD_CHECKER(thread_checker_);
 
   // Used for alternate writes that are posted for concurrent execution.
-  base::WeakPtrFactory<UDPSocketPosix> weak_factory_;
+  base::WeakPtrFactory<UDPSocketPosix> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(UDPSocketPosix);
 };
diff --git a/net/socket/udp_socket_posix_unittest.cc b/net/socket/udp_socket_posix_unittest.cc
index 42a42a1..b4a773fd3 100644
--- a/net/socket/udp_socket_posix_unittest.cc
+++ b/net/socket/udp_socket_posix_unittest.cc
@@ -133,8 +133,7 @@
       : TestWithScopedTaskEnvironment(
             base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME),
         socket_(DatagramSocket::DEFAULT_BIND, &client_log_, NetLogSource()),
-        callback_fired_(false),
-        weak_factory_(this) {
+        callback_fired_(false) {
     write_callback_ = base::BindRepeating(&UDPSocketPosixTest::OnWriteComplete,
                                           weak_factory_.GetWeakPtr());
   }
@@ -236,7 +235,7 @@
   struct iovec msg_iov_[kNumMsgs];
   struct mmsghdr msgvec_[kNumMsgs];
 #endif
-  base::WeakPtrFactory<UDPSocketPosixTest> weak_factory_;
+  base::WeakPtrFactory<UDPSocketPosixTest> weak_factory_{this};
 };
 
 TEST_F(UDPSocketPosixTest, InternalSendBuffers) {
diff --git a/net/socket/websocket_endpoint_lock_manager.cc b/net/socket/websocket_endpoint_lock_manager.cc
index cdf90aa..9124b235 100644
--- a/net/socket/websocket_endpoint_lock_manager.cc
+++ b/net/socket/websocket_endpoint_lock_manager.cc
@@ -47,8 +47,7 @@
 
 WebSocketEndpointLockManager::WebSocketEndpointLockManager()
     : unlock_delay_(base::TimeDelta::FromMilliseconds(kUnlockDelayInMs)),
-      pending_unlock_count_(0),
-      weak_factory_(this) {}
+      pending_unlock_count_(0) {}
 
 WebSocketEndpointLockManager::~WebSocketEndpointLockManager() {
   DCHECK_EQ(lock_info_map_.size(), pending_unlock_count_);
diff --git a/net/socket/websocket_endpoint_lock_manager.h b/net/socket/websocket_endpoint_lock_manager.h
index 2d7cdf5..4e96c73 100644
--- a/net/socket/websocket_endpoint_lock_manager.h
+++ b/net/socket/websocket_endpoint_lock_manager.h
@@ -130,7 +130,7 @@
   // Number of sockets currently pending unlock.
   size_t pending_unlock_count_;
 
-  base::WeakPtrFactory<WebSocketEndpointLockManager> weak_factory_;
+  base::WeakPtrFactory<WebSocketEndpointLockManager> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(WebSocketEndpointLockManager);
 };
diff --git a/net/socket/websocket_transport_client_socket_pool.cc b/net/socket/websocket_transport_client_socket_pool.cc
index 820288f6..8202699 100644
--- a/net/socket/websocket_transport_client_socket_pool.cc
+++ b/net/socket/websocket_transport_client_socket_pool.cc
@@ -36,8 +36,7 @@
       common_connect_job_params_(common_connect_job_params),
       max_sockets_(max_sockets),
       handed_out_socket_count_(0),
-      flushing_(false),
-      weak_factory_(this) {
+      flushing_(false) {
   DCHECK(common_connect_job_params_->websocket_endpoint_lock_manager);
 }
 
diff --git a/net/socket/websocket_transport_client_socket_pool.h b/net/socket/websocket_transport_client_socket_pool.h
index f1d5f0d..904e719 100644
--- a/net/socket/websocket_transport_client_socket_pool.h
+++ b/net/socket/websocket_transport_client_socket_pool.h
@@ -211,7 +211,7 @@
   int handed_out_socket_count_;
   bool flushing_;
 
-  base::WeakPtrFactory<WebSocketTransportClientSocketPool> weak_factory_;
+  base::WeakPtrFactory<WebSocketTransportClientSocketPool> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(WebSocketTransportClientSocketPool);
 };
diff --git a/net/socket/websocket_transport_connect_job.cc b/net/socket/websocket_transport_connect_job.cc
index 1b80ee69..5510ec1 100644
--- a/net/socket/websocket_transport_connect_job.cc
+++ b/net/socket/websocket_transport_connect_job.cc
@@ -41,8 +41,7 @@
       next_state_(STATE_NONE),
       race_result_(TransportConnectJob::RACE_UNKNOWN),
       had_ipv4_(false),
-      had_ipv6_(false),
-      weak_ptr_factory_(this) {
+      had_ipv6_(false) {
   DCHECK(common_connect_job_params->websocket_endpoint_lock_manager);
 }
 
diff --git a/net/socket/websocket_transport_connect_job.h b/net/socket/websocket_transport_connect_job.h
index 6ba51a0..cfd0ed3 100644
--- a/net/socket/websocket_transport_connect_job.h
+++ b/net/socket/websocket_transport_connect_job.h
@@ -106,7 +106,7 @@
   bool had_ipv4_;
   bool had_ipv6_;
 
-  base::WeakPtrFactory<WebSocketTransportConnectJob> weak_ptr_factory_;
+  base::WeakPtrFactory<WebSocketTransportConnectJob> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(WebSocketTransportConnectJob);
 };
diff --git a/net/spdy/bidirectional_stream_spdy_impl.cc b/net/spdy/bidirectional_stream_spdy_impl.cc
index 32d0999..f428a75 100644
--- a/net/spdy/bidirectional_stream_spdy_impl.cc
+++ b/net/spdy/bidirectional_stream_spdy_impl.cc
@@ -45,8 +45,7 @@
       closed_stream_status_(ERR_FAILED),
       closed_stream_received_bytes_(0),
       closed_stream_sent_bytes_(0),
-      closed_has_load_timing_info_(false),
-      weak_factory_(this) {}
+      closed_has_load_timing_info_(false) {}
 
 BidirectionalStreamSpdyImpl::~BidirectionalStreamSpdyImpl() {
   // Sends a RST to the remote if the stream is destroyed before it completes.
diff --git a/net/spdy/bidirectional_stream_spdy_impl.h b/net/spdy/bidirectional_stream_spdy_impl.h
index 7266e66..954a6782 100644
--- a/net/spdy/bidirectional_stream_spdy_impl.h
+++ b/net/spdy/bidirectional_stream_spdy_impl.h
@@ -130,7 +130,7 @@
   // Keep a reference here so it is alive until OnDataSent is invoked.
   scoped_refptr<IOBuffer> pending_combined_buffer_;
 
-  base::WeakPtrFactory<BidirectionalStreamSpdyImpl> weak_factory_;
+  base::WeakPtrFactory<BidirectionalStreamSpdyImpl> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(BidirectionalStreamSpdyImpl);
 };
diff --git a/net/spdy/spdy_http_stream.cc b/net/spdy/spdy_http_stream.cc
index e451588..438d41a4d 100644
--- a/net/spdy/spdy_http_stream.cc
+++ b/net/spdy/spdy_http_stream.cc
@@ -121,8 +121,7 @@
       request_body_buf_size_(0),
       buffered_read_callback_pending_(false),
       more_read_data_pending_(false),
-      was_alpn_negotiated_(false),
-      weak_factory_(this) {
+      was_alpn_negotiated_(false) {
   DCHECK(spdy_session_.get());
 }
 
diff --git a/net/spdy/spdy_http_stream.h b/net/spdy/spdy_http_stream.h
index 643c4f3..a647849b 100644
--- a/net/spdy/spdy_http_stream.h
+++ b/net/spdy/spdy_http_stream.h
@@ -233,7 +233,7 @@
   base::debug::StackTrace stack_trace_;
 #endif
 
-  base::WeakPtrFactory<SpdyHttpStream> weak_factory_;
+  base::WeakPtrFactory<SpdyHttpStream> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(SpdyHttpStream);
 };
diff --git a/net/spdy/spdy_http_stream_unittest.cc b/net/spdy/spdy_http_stream_unittest.cc
index 6993bbbe..fd84847 100644
--- a/net/spdy/spdy_http_stream_unittest.cc
+++ b/net/spdy/spdy_http_stream_unittest.cc
@@ -76,7 +76,7 @@
   enum class FailureMode { SYNC, ASYNC };
 
   explicit ReadErrorUploadDataStream(FailureMode mode)
-      : UploadDataStream(true, 0), async_(mode), weak_factory_(this) {}
+      : UploadDataStream(true, 0), async_(mode) {}
 
  private:
   void CompleteRead() { UploadDataStream::OnReadCompleted(ERR_FAILED); }
@@ -98,7 +98,7 @@
 
   const FailureMode async_;
 
-  base::WeakPtrFactory<ReadErrorUploadDataStream> weak_factory_;
+  base::WeakPtrFactory<ReadErrorUploadDataStream> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(ReadErrorUploadDataStream);
 };
diff --git a/net/spdy/spdy_proxy_client_socket.cc b/net/spdy/spdy_proxy_client_socket.cc
index 3330305..ee9883f 100644
--- a/net/spdy/spdy_proxy_client_socket.cc
+++ b/net/spdy/spdy_proxy_client_socket.cc
@@ -46,9 +46,7 @@
       was_ever_used_(false),
       net_log_(NetLogWithSource::Make(spdy_stream->net_log().net_log(),
                                       NetLogSourceType::PROXY_CLIENT_SOCKET)),
-      source_dependency_(source_net_log.source()),
-      weak_factory_(this),
-      write_callback_weak_factory_(this) {
+      source_dependency_(source_net_log.source()) {
   request_.method = "CONNECT";
   request_.url = GURL("https://" + endpoint.ToString());
   net_log_.BeginEvent(NetLogEventType::SOCKET_ALIVE,
diff --git a/net/spdy/spdy_proxy_client_socket.h b/net/spdy/spdy_proxy_client_socket.h
index 02a2ecf..eb47162 100644
--- a/net/spdy/spdy_proxy_client_socket.h
+++ b/net/spdy/spdy_proxy_client_socket.h
@@ -173,11 +173,12 @@
   const NetLogSource source_dependency_;
 
   // The default weak pointer factory.
-  base::WeakPtrFactory<SpdyProxyClientSocket> weak_factory_;
+  base::WeakPtrFactory<SpdyProxyClientSocket> weak_factory_{this};
 
   // Only used for posting write callbacks. Weak pointers created by this
   // factory are invalidated in Disconnect().
-  base::WeakPtrFactory<SpdyProxyClientSocket> write_callback_weak_factory_;
+  base::WeakPtrFactory<SpdyProxyClientSocket> write_callback_weak_factory_{
+      this};
 
   DISALLOW_COPY_AND_ASSIGN(SpdyProxyClientSocket);
 };
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc
index db133a9..3f9913d8 100644
--- a/net/spdy/spdy_session.cc
+++ b/net/spdy/spdy_session.cc
@@ -646,7 +646,7 @@
   }
 }
 
-SpdyStreamRequest::SpdyStreamRequest() : weak_ptr_factory_(this) {
+SpdyStreamRequest::SpdyStreamRequest() {
   Reset();
 }
 
@@ -953,8 +953,7 @@
           base::TimeDelta::FromSeconds(kDefaultConnectionAtRiskOfLossSeconds)),
       hung_interval_(base::TimeDelta::FromSeconds(kHungIntervalSeconds)),
       time_func_(time_func),
-      network_quality_estimator_(network_quality_estimator),
-      weak_factory_(this) {
+      network_quality_estimator_(network_quality_estimator) {
   net_log_.BeginEvent(
       NetLogEventType::HTTP2_SESSION,
       base::Bind(&NetLogSpdySessionCallback, &host_port_proxy_pair()));
diff --git a/net/spdy/spdy_session.h b/net/spdy/spdy_session.h
index f936200..7de36a4 100644
--- a/net/spdy/spdy_session.h
+++ b/net/spdy/spdy_session.h
@@ -285,7 +285,7 @@
   MutableNetworkTrafficAnnotationTag traffic_annotation_;
   State next_state_;
 
-  base::WeakPtrFactory<SpdyStreamRequest> weak_ptr_factory_;
+  base::WeakPtrFactory<SpdyStreamRequest> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(SpdyStreamRequest);
 };
@@ -1212,7 +1212,7 @@
   // SpdySession is refcounted because we don't need to keep the SpdySession
   // alive if the last reference is within a RunnableMethod.  Just revoke the
   // method.
-  base::WeakPtrFactory<SpdySession> weak_factory_;
+  base::WeakPtrFactory<SpdySession> weak_factory_{this};
 };
 
 }  // namespace net
diff --git a/net/spdy/spdy_session_pool.cc b/net/spdy/spdy_session_pool.cc
index 924c40c1a..7a6e27fc 100644
--- a/net/spdy/spdy_session_pool.cc
+++ b/net/spdy/spdy_session_pool.cc
@@ -103,8 +103,7 @@
       greased_http2_frame_(greased_http2_frame),
       time_func_(time_func),
       push_delegate_(nullptr),
-      network_quality_estimator_(network_quality_estimator),
-      weak_ptr_factory_(this) {
+      network_quality_estimator_(network_quality_estimator) {
   NetworkChangeNotifier::AddIPAddressObserver(this);
   if (ssl_config_service_)
     ssl_config_service_->AddObserver(this);
diff --git a/net/spdy/spdy_session_pool.h b/net/spdy/spdy_session_pool.h
index 143d5645..3dbfba25 100644
--- a/net/spdy/spdy_session_pool.h
+++ b/net/spdy/spdy_session_pool.h
@@ -447,7 +447,7 @@
 
   NetworkQualityEstimator* network_quality_estimator_;
 
-  base::WeakPtrFactory<SpdySessionPool> weak_ptr_factory_;
+  base::WeakPtrFactory<SpdySessionPool> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(SpdySessionPool);
 };
diff --git a/net/spdy/spdy_stream.cc b/net/spdy/spdy_stream.cc
index 0580256..93e68b3 100644
--- a/net/spdy/spdy_stream.cc
+++ b/net/spdy/spdy_stream.cc
@@ -111,8 +111,7 @@
       raw_sent_bytes_(0),
       recv_bytes_(0),
       write_handler_guard_(false),
-      traffic_annotation_(traffic_annotation),
-      weak_ptr_factory_(this) {
+      traffic_annotation_(traffic_annotation) {
   CHECK(type_ == SPDY_BIDIRECTIONAL_STREAM ||
         type_ == SPDY_REQUEST_RESPONSE_STREAM ||
         type_ == SPDY_PUSH_STREAM);
diff --git a/net/spdy/spdy_stream.h b/net/spdy/spdy_stream.h
index a7a8e7b4c..efdc0d9b 100644
--- a/net/spdy/spdy_stream.h
+++ b/net/spdy/spdy_stream.h
@@ -530,7 +530,7 @@
 
   const NetworkTrafficAnnotationTag traffic_annotation_;
 
-  base::WeakPtrFactory<SpdyStream> weak_ptr_factory_;
+  base::WeakPtrFactory<SpdyStream> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(SpdyStream);
 };
diff --git a/net/ssl/client_cert_store_mac_unittest.cc b/net/ssl/client_cert_store_mac_unittest.cc
index 8427b7c9..4dd4d6fe 100644
--- a/net/ssl/client_cert_store_mac_unittest.cc
+++ b/net/ssl/client_cert_store_mac_unittest.cc
@@ -63,7 +63,7 @@
   EXPECT_FALSE(cert_1->IsIssuedByEncoded(authority_2));
 
   std::vector<scoped_refptr<X509Certificate> > certs;
-  scoped_refptr<SSLCertRequestInfo> request(new SSLCertRequestInfo());
+  auto request = base::MakeRefCounted<SSLCertRequestInfo>();
   request->cert_authorities = authority_2;
 
   ClientCertIdentityList selected_certs;
@@ -85,7 +85,7 @@
 
   std::vector<scoped_refptr<X509Certificate> > certs;
   certs.push_back(cert_2);
-  scoped_refptr<SSLCertRequestInfo> request(new SSLCertRequestInfo());
+  auto request = base::MakeRefCounted<SSLCertRequestInfo>();
 
   ClientCertIdentityList selected_certs;
   bool rv = SelectClientCertsGivenPreferred(
diff --git a/net/ssl/client_cert_store_nss_unittest.cc b/net/ssl/client_cert_store_nss_unittest.cc
index c6c7f29..cf3a294 100644
--- a/net/ssl/client_cert_store_nss_unittest.cc
+++ b/net/ssl/client_cert_store_nss_unittest.cc
@@ -100,7 +100,7 @@
 
   {
     // Request certificates matching B CA, |client_1|'s issuer.
-    scoped_refptr<SSLCertRequestInfo> request(new SSLCertRequestInfo);
+    auto request = base::MakeRefCounted<SSLCertRequestInfo>();
     request->cert_authorities.push_back(std::string(
         reinterpret_cast<const char*>(kAuthority1DN), sizeof(kAuthority1DN)));
 
@@ -133,7 +133,7 @@
 
   {
     // Request certificates matching C Root CA, |client_1_ca|'s issuer.
-    scoped_refptr<SSLCertRequestInfo> request(new SSLCertRequestInfo);
+    auto request = base::MakeRefCounted<SSLCertRequestInfo>();
     request->cert_authorities.push_back(
         std::string(reinterpret_cast<const char*>(kAuthorityRootDN),
                     sizeof(kAuthorityRootDN)));
@@ -212,7 +212,7 @@
       0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x49,
       0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
       0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64};
-  scoped_refptr<SSLCertRequestInfo> request(new SSLCertRequestInfo);
+  auto request = base::MakeRefCounted<SSLCertRequestInfo>();
   request->cert_authorities.push_back(std::string(
       reinterpret_cast<const char*>(kAuthorityDN), sizeof(kAuthorityDN)));
 
diff --git a/net/ssl/client_cert_store_unittest-inl.h b/net/ssl/client_cert_store_unittest-inl.h
index 6cc1118..71318b5 100644
--- a/net/ssl/client_cert_store_unittest-inl.h
+++ b/net/ssl/client_cert_store_unittest-inl.h
@@ -67,7 +67,7 @@
 
 TYPED_TEST_P(ClientCertStoreTest, EmptyQuery) {
   CertificateList certs;
-  scoped_refptr<SSLCertRequestInfo> request(new SSLCertRequestInfo());
+  auto request = base::MakeRefCounted<SSLCertRequestInfo>();
 
   ClientCertIdentityList selected_identities;
   bool rv = this->delegate_.SelectClientCerts(certs, *request.get(),
@@ -85,7 +85,7 @@
 
   std::vector<scoped_refptr<X509Certificate> > certs;
   certs.push_back(cert);
-  scoped_refptr<SSLCertRequestInfo> request(new SSLCertRequestInfo());
+  auto request = base::MakeRefCounted<SSLCertRequestInfo>();
 
   ClientCertIdentityList selected_identities;
   bool rv = this->delegate_.SelectClientCerts(certs, *request.get(),
@@ -120,7 +120,7 @@
   std::vector<scoped_refptr<X509Certificate> > certs;
   certs.push_back(cert_1);
   certs.push_back(cert_2);
-  scoped_refptr<SSLCertRequestInfo> request(new SSLCertRequestInfo());
+  auto request = base::MakeRefCounted<SSLCertRequestInfo>();
   request->cert_authorities = authority_1;
 
   ClientCertIdentityList selected_identities;
@@ -158,7 +158,7 @@
                                                      options);
   ASSERT_TRUE(cert);
 
-  scoped_refptr<SSLCertRequestInfo> request(new SSLCertRequestInfo());
+  auto request = base::MakeRefCounted<SSLCertRequestInfo>();
 
   ClientCertIdentityList selected_identities;
   bool rv = this->delegate_.SelectClientCerts({cert}, *request.get(),
diff --git a/net/ssl/threaded_ssl_private_key.cc b/net/ssl/threaded_ssl_private_key.cc
index 67597609..df24528c 100644
--- a/net/ssl/threaded_ssl_private_key.cc
+++ b/net/ssl/threaded_ssl_private_key.cc
@@ -53,8 +53,7 @@
     std::unique_ptr<ThreadedSSLPrivateKey::Delegate> delegate,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner)
     : core_(new Core(std::move(delegate))),
-      task_runner_(std::move(task_runner)),
-      weak_factory_(this) {}
+      task_runner_(std::move(task_runner)) {}
 
 std::string ThreadedSSLPrivateKey::GetProviderName() {
   return core_->delegate()->GetProviderName();
diff --git a/net/ssl/threaded_ssl_private_key.h b/net/ssl/threaded_ssl_private_key.h
index 87dd94a..21c0483 100644
--- a/net/ssl/threaded_ssl_private_key.h
+++ b/net/ssl/threaded_ssl_private_key.h
@@ -81,7 +81,7 @@
 
   scoped_refptr<Core> core_;
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-  base::WeakPtrFactory<ThreadedSSLPrivateKey> weak_factory_;
+  base::WeakPtrFactory<ThreadedSSLPrivateKey> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(ThreadedSSLPrivateKey);
 };
diff --git a/net/test/embedded_test_server/controllable_http_response.cc b/net/test/embedded_test_server/controllable_http_response.cc
index bb50901..e7470f2b 100644
--- a/net/test/embedded_test_server/controllable_http_response.cc
+++ b/net/test/embedded_test_server/controllable_http_response.cc
@@ -45,8 +45,7 @@
 ControllableHttpResponse::ControllableHttpResponse(
     EmbeddedTestServer* embedded_test_server,
     const std::string& relative_url,
-    bool relative_url_is_prefix)
-    : weak_ptr_factory_(this) {
+    bool relative_url_is_prefix) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   embedded_test_server->RegisterRequestHandler(base::BindRepeating(
       RequestHandler, weak_ptr_factory_.GetWeakPtr(),
diff --git a/net/test/embedded_test_server/controllable_http_response.h b/net/test/embedded_test_server/controllable_http_response.h
index efb23fd..22406a7 100644
--- a/net/test/embedded_test_server/controllable_http_response.h
+++ b/net/test/embedded_test_server/controllable_http_response.h
@@ -88,7 +88,7 @@
 
   SEQUENCE_CHECKER(sequence_checker_);
 
-  base::WeakPtrFactory<ControllableHttpResponse> weak_ptr_factory_;
+  base::WeakPtrFactory<ControllableHttpResponse> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(ControllableHttpResponse);
 };
diff --git a/net/test/embedded_test_server/embedded_test_server.cc b/net/test/embedded_test_server/embedded_test_server.cc
index b24b44f5..6ebe322c 100644
--- a/net/test/embedded_test_server/embedded_test_server.cc
+++ b/net/test/embedded_test_server/embedded_test_server.cc
@@ -50,8 +50,7 @@
     : is_using_ssl_(type == TYPE_HTTPS),
       connection_listener_(nullptr),
       port_(0),
-      cert_(CERT_OK),
-      weak_factory_(this) {
+      cert_(CERT_OK) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   if (!is_using_ssl_)
diff --git a/net/test/embedded_test_server/embedded_test_server.h b/net/test/embedded_test_server/embedded_test_server.h
index 7978c024..cb416137 100644
--- a/net/test/embedded_test_server/embedded_test_server.h
+++ b/net/test/embedded_test_server/embedded_test_server.h
@@ -319,7 +319,7 @@
   ServerCertificate cert_;
   std::unique_ptr<SSLServerContext> context_;
 
-  base::WeakPtrFactory<EmbeddedTestServer> weak_factory_;
+  base::WeakPtrFactory<EmbeddedTestServer> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(EmbeddedTestServer);
 };
diff --git a/net/test/embedded_test_server/embedded_test_server_unittest.cc b/net/test/embedded_test_server/embedded_test_server_unittest.cc
index 18bd4c7..52bae82 100644
--- a/net/test/embedded_test_server/embedded_test_server_unittest.cc
+++ b/net/test/embedded_test_server/embedded_test_server_unittest.cc
@@ -412,7 +412,7 @@
 
 class InfiniteResponse : public BasicHttpResponse {
  public:
-  InfiniteResponse() : weak_ptr_factory_(this) {}
+  InfiniteResponse() {}
 
   void SendResponse(const SendBytesCallback& send,
                     const SendCompleteCallback& done) override {
@@ -430,7 +430,7 @@
                                   weak_ptr_factory_.GetWeakPtr(), send)));
   }
 
-  base::WeakPtrFactory<InfiniteResponse> weak_ptr_factory_;
+  base::WeakPtrFactory<InfiniteResponse> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(InfiniteResponse);
 };
diff --git a/net/test/embedded_test_server/http_connection.cc b/net/test/embedded_test_server/http_connection.cc
index 8d30091f..93186075 100644
--- a/net/test/embedded_test_server/http_connection.cc
+++ b/net/test/embedded_test_server/http_connection.cc
@@ -18,8 +18,7 @@
                                const HandleRequestCallback& callback)
     : socket_(std::move(socket)),
       callback_(callback),
-      read_buf_(base::MakeRefCounted<IOBufferWithSize>(4096)),
-      weak_factory_(this) {}
+      read_buf_(base::MakeRefCounted<IOBufferWithSize>(4096)) {}
 
 HttpConnection::~HttpConnection() {
   weak_factory_.InvalidateWeakPtrs();
diff --git a/net/test/embedded_test_server/http_connection.h b/net/test/embedded_test_server/http_connection.h
index bbf0398..041cea53 100644
--- a/net/test/embedded_test_server/http_connection.h
+++ b/net/test/embedded_test_server/http_connection.h
@@ -66,7 +66,7 @@
   HttpRequestParser request_parser_;
   scoped_refptr<IOBufferWithSize> read_buf_;
 
-  base::WeakPtrFactory<HttpConnection> weak_factory_;
+  base::WeakPtrFactory<HttpConnection> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(HttpConnection);
 };
diff --git a/net/test/tcp_socket_proxy.cc b/net/test/tcp_socket_proxy.cc
index b7d79064..22584a9 100644
--- a/net/test/tcp_socket_proxy.cc
+++ b/net/test/tcp_socket_proxy.cc
@@ -134,13 +134,13 @@
 
   THREAD_CHECKER(thread_checker_);
 
-  base::WeakPtrFactory<ConnectionProxy> weak_factory_;
+  base::WeakPtrFactory<ConnectionProxy> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(ConnectionProxy);
 };
 
 ConnectionProxy::ConnectionProxy(std::unique_ptr<StreamSocket> local_socket)
-    : local_socket_(std::move(local_socket)), weak_factory_(this) {}
+    : local_socket_(std::move(local_socket)) {}
 
 ConnectionProxy::~ConnectionProxy() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
diff --git a/net/test/url_request/ssl_certificate_error_job.cc b/net/test/url_request/ssl_certificate_error_job.cc
index f7bcf66f..5044c74 100644
--- a/net/test/url_request/ssl_certificate_error_job.cc
+++ b/net/test/url_request/ssl_certificate_error_job.cc
@@ -42,8 +42,7 @@
 SSLCertificateErrorJob::SSLCertificateErrorJob(
     URLRequest* request,
     NetworkDelegate* network_delegate)
-    : URLRequestJob(request, network_delegate), weak_factory_(this) {
-}
+    : URLRequestJob(request, network_delegate) {}
 
 void SSLCertificateErrorJob::Start() {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
diff --git a/net/test/url_request/ssl_certificate_error_job.h b/net/test/url_request/ssl_certificate_error_job.h
index b3b372e8..7a2c86f7 100644
--- a/net/test/url_request/ssl_certificate_error_job.h
+++ b/net/test/url_request/ssl_certificate_error_job.h
@@ -34,7 +34,7 @@
 
   void NotifyError();
 
-  base::WeakPtrFactory<SSLCertificateErrorJob> weak_factory_;
+  base::WeakPtrFactory<SSLCertificateErrorJob> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(SSLCertificateErrorJob);
 };
diff --git a/net/test/url_request/url_request_failed_job.cc b/net/test/url_request/url_request_failed_job.cc
index a893f72..3000861 100644
--- a/net/test/url_request/url_request_failed_job.cc
+++ b/net/test/url_request/url_request_failed_job.cc
@@ -84,8 +84,7 @@
     : URLRequestJob(request, network_delegate),
       phase_(phase),
       net_error_(net_error),
-      total_received_bytes_(0),
-      weak_factory_(this) {
+      total_received_bytes_(0) {
   CHECK_GE(phase, URLRequestFailedJob::FailurePhase::START);
   CHECK_LE(phase, URLRequestFailedJob::FailurePhase::READ_ASYNC);
   CHECK_LT(net_error, OK);
diff --git a/net/test/url_request/url_request_failed_job.h b/net/test/url_request/url_request_failed_job.h
index 1e2695c..8ce4763f 100644
--- a/net/test/url_request/url_request_failed_job.h
+++ b/net/test/url_request/url_request_failed_job.h
@@ -81,7 +81,7 @@
   const int net_error_;
   int64_t total_received_bytes_;
 
-  base::WeakPtrFactory<URLRequestFailedJob> weak_factory_;
+  base::WeakPtrFactory<URLRequestFailedJob> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(URLRequestFailedJob);
 };
diff --git a/net/test/url_request/url_request_hanging_read_job.cc b/net/test/url_request/url_request_hanging_read_job.cc
index 2cae64e..df9bf44 100644
--- a/net/test/url_request/url_request_hanging_read_job.cc
+++ b/net/test/url_request/url_request_hanging_read_job.cc
@@ -47,8 +47,8 @@
     URLRequest* request,
     NetworkDelegate* network_delegate)
     : URLRequestJob(request, network_delegate),
-      content_length_(10),  // non-zero content-length
-      weak_factory_(this) {}
+      content_length_(10)  // non-zero content-length
+{}
 
 void URLRequestHangingReadJob::Start() {
   // Start reading asynchronously so that all error reporting and data
diff --git a/net/test/url_request/url_request_hanging_read_job.h b/net/test/url_request/url_request_hanging_read_job.h
index 83ac941e..bd4a4a7 100644
--- a/net/test/url_request/url_request_hanging_read_job.h
+++ b/net/test/url_request/url_request_hanging_read_job.h
@@ -36,7 +36,7 @@
   void StartAsync();
 
   const int content_length_;
-  base::WeakPtrFactory<URLRequestHangingReadJob> weak_factory_;
+  base::WeakPtrFactory<URLRequestHangingReadJob> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(URLRequestHangingReadJob);
 };
diff --git a/net/test/url_request/url_request_mock_data_job.cc b/net/test/url_request/url_request_mock_data_job.cc
index b1d17fd..59e69f9 100644
--- a/net/test/url_request/url_request_mock_data_job.cc
+++ b/net/test/url_request/url_request_mock_data_job.cc
@@ -101,8 +101,7 @@
                                              bool request_client_certificate)
     : URLRequestJob(request, network_delegate),
       data_offset_(0),
-      request_client_certificate_(request_client_certificate),
-      weak_factory_(this) {
+      request_client_certificate_(request_client_certificate) {
   DCHECK_GT(data_repeat_count, 0);
   for (int i = 0; i < data_repeat_count; ++i) {
     data_.append(data);
@@ -168,7 +167,7 @@
 
   set_expected_content_size(data_.length());
   if (request_client_certificate_) {
-    scoped_refptr<SSLCertRequestInfo> request_all(new SSLCertRequestInfo());
+    auto request_all = base::MakeRefCounted<SSLCertRequestInfo>();
     NotifyCertificateRequested(request_all.get());
     return;
   }
diff --git a/net/test/url_request/url_request_mock_data_job.h b/net/test/url_request/url_request_mock_data_job.h
index cd70f2a..1e183699 100644
--- a/net/test/url_request/url_request_mock_data_job.h
+++ b/net/test/url_request/url_request_mock_data_job.h
@@ -73,7 +73,7 @@
   std::string data_;
   size_t data_offset_;
   bool request_client_certificate_;
-  base::WeakPtrFactory<URLRequestMockDataJob> weak_factory_;
+  base::WeakPtrFactory<URLRequestMockDataJob> weak_factory_{this};
 };
 
 }  // namespace net
diff --git a/net/test/url_request/url_request_mock_http_job.cc b/net/test/url_request/url_request_mock_http_job.cc
index 803480e2..40495441 100644
--- a/net/test/url_request/url_request_mock_http_job.cc
+++ b/net/test/url_request/url_request_mock_http_job.cc
@@ -130,8 +130,7 @@
     : URLRequestFileJob(request,
                         network_delegate,
                         file_path,
-                        base::CreateTaskRunnerWithTraits({base::MayBlock()})),
-      weak_ptr_factory_(this) {}
+                        base::CreateTaskRunnerWithTraits({base::MayBlock()})) {}
 
 URLRequestMockHTTPJob::~URLRequestMockHTTPJob() = default;
 
diff --git a/net/test/url_request/url_request_mock_http_job.h b/net/test/url_request/url_request_mock_http_job.h
index e0c4ce8..9c35bf95 100644
--- a/net/test/url_request/url_request_mock_http_job.h
+++ b/net/test/url_request/url_request_mock_http_job.h
@@ -77,7 +77,7 @@
   std::string raw_headers_;
   int64_t total_received_bytes_ = 0;
 
-  base::WeakPtrFactory<URLRequestMockHTTPJob> weak_ptr_factory_;
+  base::WeakPtrFactory<URLRequestMockHTTPJob> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(URLRequestMockHTTPJob);
 };
diff --git a/net/test/url_request/url_request_slow_download_job.cc b/net/test/url_request/url_request_slow_download_job.cc
index 3b54373..2195db8 100644
--- a/net/test/url_request/url_request_slow_download_job.cc
+++ b/net/test/url_request/url_request_slow_download_job.cc
@@ -115,9 +115,7 @@
       bytes_already_sent_(0),
       should_error_download_(false),
       should_finish_download_(false),
-      buffer_size_(0),
-      weak_factory_(this) {
-}
+      buffer_size_(0) {}
 
 void URLRequestSlowDownloadJob::StartAsync() {
   if (base::LowerCaseEqualsASCII(kFinishDownloadUrl,
diff --git a/net/test/url_request/url_request_slow_download_job.h b/net/test/url_request/url_request_slow_download_job.h
index d90acb2f4..c7302c9 100644
--- a/net/test/url_request/url_request_slow_download_job.h
+++ b/net/test/url_request/url_request_slow_download_job.h
@@ -94,7 +94,7 @@
   scoped_refptr<IOBuffer> buffer_;
   int buffer_size_;
 
-  base::WeakPtrFactory<URLRequestSlowDownloadJob> weak_factory_;
+  base::WeakPtrFactory<URLRequestSlowDownloadJob> weak_factory_{this};
 };
 
 }  // namespace net
diff --git a/net/tools/quic/quic_http_proxy_backend_stream.cc b/net/tools/quic/quic_http_proxy_backend_stream.cc
index cdd598cc..9c05123 100644
--- a/net/tools/quic/quic_http_proxy_backend_stream.cc
+++ b/net/tools/quic/quic_http_proxy_backend_stream.cc
@@ -53,8 +53,7 @@
       buf_(base::MakeRefCounted<IOBuffer>(kBufferSize)),
       response_completed_(false),
       headers_set_(false),
-      quic_response_(new quic::QuicBackendResponse()),
-      weak_factory_(this) {}
+      quic_response_(new quic::QuicBackendResponse()) {}
 
 QuicHttpProxyBackendStream::~QuicHttpProxyBackendStream() {}
 
diff --git a/net/tools/quic/quic_http_proxy_backend_stream.h b/net/tools/quic/quic_http_proxy_backend_stream.h
index e578c1a..6d87391 100644
--- a/net/tools/quic/quic_http_proxy_backend_stream.h
+++ b/net/tools/quic/quic_http_proxy_backend_stream.h
@@ -156,7 +156,7 @@
   bool headers_set_;
   std::unique_ptr<quic::QuicBackendResponse> quic_response_;
 
-  base::WeakPtrFactory<QuicHttpProxyBackendStream> weak_factory_;
+  base::WeakPtrFactory<QuicHttpProxyBackendStream> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(QuicHttpProxyBackendStream);
 };
diff --git a/net/tools/quic/quic_simple_client.cc b/net/tools/quic/quic_simple_client.cc
index f3a25e8..fb8651d1 100644
--- a/net/tools/quic/quic_simple_client.cc
+++ b/net/tools/quic/quic_simple_client.cc
@@ -47,8 +47,7 @@
           quic::QuicWrapUnique(
               new QuicClientMessageLooplNetworkHelper(&clock_, this)),
           std::move(proof_verifier)),
-      initialized_(false),
-      weak_factory_(this) {
+      initialized_(false) {
   set_server_address(server_address);
 }
 
diff --git a/net/tools/quic/quic_simple_client.h b/net/tools/quic/quic_simple_client.h
index 2c682a5..add25ad7 100644
--- a/net/tools/quic/quic_simple_client.h
+++ b/net/tools/quic/quic_simple_client.h
@@ -57,7 +57,7 @@
   // Tracks if the client is initialized to connect.
   bool initialized_;
 
-  base::WeakPtrFactory<QuicSimpleClient> weak_factory_;
+  base::WeakPtrFactory<QuicSimpleClient> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(QuicSimpleClient);
 };
diff --git a/net/tools/quic/quic_simple_server.cc b/net/tools/quic/quic_simple_server.cc
index 2349d45..a4f09f7 100644
--- a/net/tools/quic/quic_simple_server.cc
+++ b/net/tools/quic/quic_simple_server.cc
@@ -59,8 +59,7 @@
       read_pending_(false),
       synchronous_read_count_(0),
       read_buffer_(base::MakeRefCounted<IOBufferWithSize>(kReadBufferSize)),
-      quic_simple_server_backend_(quic_simple_server_backend),
-      weak_factory_(this) {
+      quic_simple_server_backend_(quic_simple_server_backend) {
   DCHECK(quic_simple_server_backend);
   Initialize();
 }
diff --git a/net/tools/quic/quic_simple_server.h b/net/tools/quic/quic_simple_server.h
index 743b883..6d7c36c 100644
--- a/net/tools/quic/quic_simple_server.h
+++ b/net/tools/quic/quic_simple_server.h
@@ -119,7 +119,7 @@
 
   quic::QuicSimpleServerBackend* quic_simple_server_backend_;
 
-  base::WeakPtrFactory<QuicSimpleServer> weak_factory_;
+  base::WeakPtrFactory<QuicSimpleServer> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(QuicSimpleServer);
 };
diff --git a/net/tools/quic/quic_simple_server_packet_writer.cc b/net/tools/quic/quic_simple_server_packet_writer.cc
index 6e71a9d..10730abc 100644
--- a/net/tools/quic/quic_simple_server_packet_writer.cc
+++ b/net/tools/quic/quic_simple_server_packet_writer.cc
@@ -21,10 +21,7 @@
 QuicSimpleServerPacketWriter::QuicSimpleServerPacketWriter(
     UDPServerSocket* socket,
     quic::QuicDispatcher* dispatcher)
-    : socket_(socket),
-      dispatcher_(dispatcher),
-      write_blocked_(false),
-      weak_factory_(this) {}
+    : socket_(socket), dispatcher_(dispatcher), write_blocked_(false) {}
 
 QuicSimpleServerPacketWriter::~QuicSimpleServerPacketWriter() = default;
 
diff --git a/net/tools/quic/quic_simple_server_packet_writer.h b/net/tools/quic/quic_simple_server_packet_writer.h
index 967eda87..76f8b8e 100644
--- a/net/tools/quic/quic_simple_server_packet_writer.h
+++ b/net/tools/quic/quic_simple_server_packet_writer.h
@@ -67,7 +67,7 @@
   // Whether a write is currently in flight.
   bool write_blocked_;
 
-  base::WeakPtrFactory<QuicSimpleServerPacketWriter> weak_factory_;
+  base::WeakPtrFactory<QuicSimpleServerPacketWriter> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(QuicSimpleServerPacketWriter);
 };
diff --git a/net/url_request/test_url_fetcher_factory.cc b/net/url_request/test_url_fetcher_factory.cc
index 7528b22..5a77624 100644
--- a/net/url_request/test_url_fetcher_factory.cc
+++ b/net/url_request/test_url_fetcher_factory.cc
@@ -359,8 +359,7 @@
                                const std::string& response_data,
                                HttpStatusCode response_code,
                                URLRequestStatus::Status status)
-    : TestURLFetcher(0, url, d),
-      weak_factory_(this) {
+    : TestURLFetcher(0, url, d) {
   Error error = OK;
   switch(status) {
     case URLRequestStatus::SUCCESS:
diff --git a/net/url_request/test_url_fetcher_factory.h b/net/url_request/test_url_fetcher_factory.h
index cbd0cde8a..2bf8b6f 100644
--- a/net/url_request/test_url_fetcher_factory.h
+++ b/net/url_request/test_url_fetcher_factory.h
@@ -326,7 +326,7 @@
   void RunDelegate();
 
   int64_t response_bytes_;
-  base::WeakPtrFactory<FakeURLFetcher> weak_factory_;
+  base::WeakPtrFactory<FakeURLFetcher> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(FakeURLFetcher);
 };
diff --git a/net/url_request/url_fetcher_response_writer.cc b/net/url_request/url_fetcher_response_writer.cc
index e4237b9a..acc7563 100644
--- a/net/url_request/url_fetcher_response_writer.cc
+++ b/net/url_request/url_fetcher_response_writer.cc
@@ -56,8 +56,7 @@
     const base::FilePath& file_path)
     : file_task_runner_(file_task_runner),
       file_path_(file_path),
-      owns_file_(false),
-      weak_factory_(this) {
+      owns_file_(false) {
   DCHECK(file_task_runner_.get());
 }
 
diff --git a/net/url_request/url_fetcher_response_writer.h b/net/url_request/url_fetcher_response_writer.h
index 1415ba6..202cf63 100644
--- a/net/url_request/url_fetcher_response_writer.h
+++ b/net/url_request/url_fetcher_response_writer.h
@@ -141,7 +141,7 @@
 
   CompletionOnceCallback callback_;
 
-  base::WeakPtrFactory<URLFetcherFileWriter> weak_factory_;
+  base::WeakPtrFactory<URLFetcherFileWriter> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(URLFetcherFileWriter);
 };
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc
index 974cd09..ea057ba 100644
--- a/net/url_request/url_request.cc
+++ b/net/url_request/url_request.cc
@@ -616,8 +616,7 @@
       raw_header_size_(0),
       is_pac_request_(false),
       traffic_annotation_(traffic_annotation),
-      upgrade_if_insecure_(false),
-      weak_factory_(this) {
+      upgrade_if_insecure_(false) {
   // Sanity check out environment.
   DCHECK(base::ThreadTaskRunnerHandle::IsSet());
 
diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h
index 695fb9a..2a095007 100644
--- a/net/url_request/url_request.h
+++ b/net/url_request/url_request.h
@@ -1025,7 +1025,7 @@
 
   THREAD_CHECKER(thread_checker_);
 
-  base::WeakPtrFactory<URLRequest> weak_factory_;
+  base::WeakPtrFactory<URLRequest> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(URLRequest);
 };
diff --git a/net/url_request/url_request_error_job.cc b/net/url_request/url_request_error_job.cc
index 0eda199..aba7e57 100644
--- a/net/url_request/url_request_error_job.cc
+++ b/net/url_request/url_request_error_job.cc
@@ -14,11 +14,10 @@
 
 namespace net {
 
-URLRequestErrorJob::URLRequestErrorJob(
-    URLRequest* request, NetworkDelegate* network_delegate, int error)
-    : URLRequestJob(request, network_delegate),
-      error_(error),
-      weak_factory_(this) {}
+URLRequestErrorJob::URLRequestErrorJob(URLRequest* request,
+                                       NetworkDelegate* network_delegate,
+                                       int error)
+    : URLRequestJob(request, network_delegate), error_(error) {}
 
 URLRequestErrorJob::~URLRequestErrorJob() = default;
 
diff --git a/net/url_request/url_request_error_job.h b/net/url_request/url_request_error_job.h
index efd6b66..2ce3f8d 100644
--- a/net/url_request/url_request_error_job.h
+++ b/net/url_request/url_request_error_job.h
@@ -30,7 +30,7 @@
 
   int error_;
 
-  base::WeakPtrFactory<URLRequestErrorJob> weak_factory_;
+  base::WeakPtrFactory<URLRequestErrorJob> weak_factory_{this};
 };
 
 }  // namespace net
diff --git a/net/url_request/url_request_file_dir_job.cc b/net/url_request/url_request_file_dir_job.cc
index ca05b6c3..97d9384 100644
--- a/net/url_request/url_request_file_dir_job.cc
+++ b/net/url_request/url_request_file_dir_job.cc
@@ -36,8 +36,7 @@
       list_complete_(false),
       wrote_header_(false),
       read_pending_(false),
-      read_buffer_length_(0),
-      weak_factory_(this) {}
+      read_buffer_length_(0) {}
 
 void URLRequestFileDirJob::StartAsync() {
   base::PostTaskWithTraitsAndReplyWithResult(
diff --git a/net/url_request/url_request_file_dir_job.h b/net/url_request/url_request_file_dir_job.h
index b0858ac9..4184f3c 100644
--- a/net/url_request/url_request_file_dir_job.h
+++ b/net/url_request/url_request_file_dir_job.h
@@ -75,7 +75,7 @@
   scoped_refptr<IOBuffer> read_buffer_;
   int read_buffer_length_;
 
-  base::WeakPtrFactory<URLRequestFileDirJob> weak_factory_;
+  base::WeakPtrFactory<URLRequestFileDirJob> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(URLRequestFileDirJob);
 };
diff --git a/net/url_request/url_request_file_job.cc b/net/url_request/url_request_file_job.cc
index 7896803..955816bd 100644
--- a/net/url_request/url_request_file_job.cc
+++ b/net/url_request/url_request_file_job.cc
@@ -64,8 +64,7 @@
       stream_(new FileStream(file_task_runner)),
       file_task_runner_(file_task_runner),
       remaining_bytes_(0),
-      range_parse_result_(OK),
-      weak_ptr_factory_(this) {}
+      range_parse_result_(OK) {}
 
 void URLRequestFileJob::Start() {
   FileMetaInfo* meta_info = new FileMetaInfo();
diff --git a/net/url_request/url_request_file_job.h b/net/url_request/url_request_file_job.h
index d074eb5..b41eda0 100644
--- a/net/url_request/url_request_file_job.h
+++ b/net/url_request/url_request_file_job.h
@@ -132,7 +132,7 @@
 
   Error range_parse_result_;
 
-  base::WeakPtrFactory<URLRequestFileJob> weak_ptr_factory_;
+  base::WeakPtrFactory<URLRequestFileJob> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(URLRequestFileJob);
 };
diff --git a/net/url_request/url_request_ftp_job.cc b/net/url_request/url_request_ftp_job.cc
index b136af5..85b36e2 100644
--- a/net/url_request/url_request_ftp_job.cc
+++ b/net/url_request/url_request_ftp_job.cc
@@ -50,8 +50,7 @@
           request_->context()->proxy_resolution_service()),
       read_in_progress_(false),
       ftp_transaction_factory_(ftp_transaction_factory),
-      ftp_auth_cache_(ftp_auth_cache),
-      weak_factory_(this) {
+      ftp_auth_cache_(ftp_auth_cache) {
   DCHECK(proxy_resolution_service_);
   DCHECK(ftp_transaction_factory);
   DCHECK(ftp_auth_cache);
diff --git a/net/url_request/url_request_ftp_job.h b/net/url_request/url_request_ftp_job.h
index 7d0648e..a8dd912 100644
--- a/net/url_request/url_request_ftp_job.h
+++ b/net/url_request/url_request_ftp_job.h
@@ -93,7 +93,7 @@
   FtpTransactionFactory* ftp_transaction_factory_;
   FtpAuthCache* ftp_auth_cache_;
 
-  base::WeakPtrFactory<URLRequestFtpJob> weak_factory_;
+  base::WeakPtrFactory<URLRequestFtpJob> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(URLRequestFtpJob);
 };
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index 90be1ef..9981b87 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -292,8 +292,7 @@
       awaiting_callback_(false),
       http_user_agent_settings_(http_user_agent_settings),
       total_received_bytes_from_previous_transactions_(0),
-      total_sent_bytes_from_previous_transactions_(0),
-      weak_factory_(this) {
+      total_sent_bytes_from_previous_transactions_(0) {
   URLRequestThrottlerManager* manager = request->context()->throttler_manager();
   if (manager)
     throttling_entry_ = manager->RegisterRequestUrl(request->url());
diff --git a/net/url_request/url_request_http_job.h b/net/url_request/url_request_http_job.h
index b02453a..0162bfb 100644
--- a/net/url_request/url_request_http_job.h
+++ b/net/url_request/url_request_http_job.h
@@ -255,7 +255,7 @@
   RequestHeadersCallback request_headers_callback_;
   ResponseHeadersCallback response_headers_callback_;
 
-  base::WeakPtrFactory<URLRequestHttpJob> weak_factory_;
+  base::WeakPtrFactory<URLRequestHttpJob> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(URLRequestHttpJob);
 };
diff --git a/net/url_request/url_request_job.cc b/net/url_request/url_request_job.cc
index 18d56f1e..4cc5bb4 100644
--- a/net/url_request/url_request_job.cc
+++ b/net/url_request/url_request_job.cc
@@ -87,9 +87,7 @@
       expected_content_size_(-1),
       network_delegate_(network_delegate),
       last_notified_total_received_bytes_(0),
-      last_notified_total_sent_bytes_(0),
-      weak_factory_(this) {
-}
+      last_notified_total_sent_bytes_(0) {}
 
 URLRequestJob::~URLRequestJob() {
 }
diff --git a/net/url_request/url_request_job.h b/net/url_request/url_request_job.h
index df3eda2..c24ee2e 100644
--- a/net/url_request/url_request_job.h
+++ b/net/url_request/url_request_job.h
@@ -462,7 +462,7 @@
   // completed.
   CompletionOnceCallback read_raw_callback_;
 
-  base::WeakPtrFactory<URLRequestJob> weak_factory_;
+  base::WeakPtrFactory<URLRequestJob> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(URLRequestJob);
 };
diff --git a/net/url_request/url_request_job_factory_impl_unittest.cc b/net/url_request/url_request_job_factory_impl_unittest.cc
index 7f887ea..55664cf79 100644
--- a/net/url_request/url_request_job_factory_impl_unittest.cc
+++ b/net/url_request/url_request_job_factory_impl_unittest.cc
@@ -30,7 +30,7 @@
 class MockURLRequestJob : public URLRequestJob {
  public:
   MockURLRequestJob(URLRequest* request, NetworkDelegate* network_delegate)
-      : URLRequestJob(request, network_delegate), weak_factory_(this) {}
+      : URLRequestJob(request, network_delegate) {}
 
   void Start() override {
     // Start reading asynchronously so that all error reporting and data
@@ -48,7 +48,7 @@
     NotifyHeadersComplete();
   }
 
-  base::WeakPtrFactory<MockURLRequestJob> weak_factory_;
+  base::WeakPtrFactory<MockURLRequestJob> weak_factory_{this};
 };
 
 class DummyProtocolHandler : public URLRequestJobFactory::ProtocolHandler {
diff --git a/net/url_request/url_request_redirect_job.cc b/net/url_request/url_request_redirect_job.cc
index 028d0b6..13778fd 100644
--- a/net/url_request/url_request_redirect_job.cc
+++ b/net/url_request/url_request_redirect_job.cc
@@ -33,8 +33,7 @@
     : URLRequestJob(request, network_delegate),
       redirect_destination_(redirect_destination),
       response_code_(response_code),
-      redirect_reason_(redirect_reason),
-      weak_factory_(this) {
+      redirect_reason_(redirect_reason) {
   DCHECK(!redirect_reason_.empty());
 }
 
diff --git a/net/url_request/url_request_redirect_job.h b/net/url_request/url_request_redirect_job.h
index 097ffa8..8d7b861 100644
--- a/net/url_request/url_request_redirect_job.h
+++ b/net/url_request/url_request_redirect_job.h
@@ -61,7 +61,7 @@
 
   scoped_refptr<HttpResponseHeaders> fake_headers_;
 
-  base::WeakPtrFactory<URLRequestRedirectJob> weak_factory_;
+  base::WeakPtrFactory<URLRequestRedirectJob> weak_factory_{this};
 };
 
 }  // namespace net
diff --git a/net/url_request/url_request_simple_job.cc b/net/url_request/url_request_simple_job.cc
index 6b5b585..c514128 100644
--- a/net/url_request/url_request_simple_job.cc
+++ b/net/url_request/url_request_simple_job.cc
@@ -35,10 +35,7 @@
 
 URLRequestSimpleJob::URLRequestSimpleJob(URLRequest* request,
                                          NetworkDelegate* network_delegate)
-    : URLRangeRequestJob(request, network_delegate),
-      next_data_offset_(0),
-      weak_factory_(this) {
-}
+    : URLRangeRequestJob(request, network_delegate), next_data_offset_(0) {}
 
 void URLRequestSimpleJob::Start() {
   // Start reading asynchronously so that all error reporting and data
diff --git a/net/url_request/url_request_simple_job.h b/net/url_request/url_request_simple_job.h
index a27e819..18ead7d 100644
--- a/net/url_request/url_request_simple_job.h
+++ b/net/url_request/url_request_simple_job.h
@@ -70,7 +70,7 @@
   std::string charset_;
   scoped_refptr<base::RefCountedMemory> data_;
   int64_t next_data_offset_;
-  base::WeakPtrFactory<URLRequestSimpleJob> weak_factory_;
+  base::WeakPtrFactory<URLRequestSimpleJob> weak_factory_{this};
 };
 
 }  // namespace net
diff --git a/net/url_request/url_request_test_job.cc b/net/url_request/url_request_test_job.cc
index da2b8d61..45861e53 100644
--- a/net/url_request/url_request_test_job.cc
+++ b/net/url_request/url_request_test_job.cc
@@ -157,8 +157,7 @@
       async_buf_(nullptr),
       async_buf_size_(0),
       response_headers_length_(0),
-      async_reads_(false),
-      weak_factory_(this) {}
+      async_reads_(false) {}
 
 URLRequestTestJob::URLRequestTestJob(URLRequest* request,
                                      NetworkDelegate* network_delegate,
@@ -176,8 +175,7 @@
       response_headers_(base::MakeRefCounted<net::HttpResponseHeaders>(
           net::HttpUtil::AssembleRawHeaders(response_headers))),
       response_headers_length_(response_headers.size()),
-      async_reads_(false),
-      weak_factory_(this) {}
+      async_reads_(false) {}
 
 URLRequestTestJob::~URLRequestTestJob() {
   base::Erase(g_pending_jobs.Get(), this);
diff --git a/net/url_request/url_request_test_job.h b/net/url_request/url_request_test_job.h
index 88df017..59e91cc6 100644
--- a/net/url_request/url_request_test_job.h
+++ b/net/url_request/url_request_test_job.h
@@ -200,7 +200,7 @@
 
   bool async_reads_;
 
-  base::WeakPtrFactory<URLRequestTestJob> weak_factory_;
+  base::WeakPtrFactory<URLRequestTestJob> weak_factory_{this};
 };
 
 }  // namespace net
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 50599f61..74d7bb22 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -537,7 +537,7 @@
   // Closure to run to exit RunUntilBlocked().
   base::OnceClosure on_blocked_;
 
-  base::WeakPtrFactory<BlockingNetworkDelegate> weak_factory_;
+  base::WeakPtrFactory<BlockingNetworkDelegate> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(BlockingNetworkDelegate);
 };
@@ -548,8 +548,7 @@
       auth_retval_(AUTH_REQUIRED_RESPONSE_NO_ACTION),
       block_on_(0),
       target_auth_credentials_(nullptr),
-      stage_blocked_for_callback_(NOT_BLOCKED),
-      weak_factory_(this) {}
+      stage_blocked_for_callback_(NOT_BLOCKED) {}
 
 void BlockingNetworkDelegate::RunUntilBlocked() {
   base::RunLoop run_loop;
diff --git a/net/websockets/websocket_basic_handshake_stream.cc b/net/websockets/websocket_basic_handshake_stream.cc
index 88f8646..3199a93 100644
--- a/net/websockets/websocket_basic_handshake_stream.cc
+++ b/net/websockets/websocket_basic_handshake_stream.cc
@@ -179,8 +179,7 @@
       requested_sub_protocols_(std::move(requested_sub_protocols)),
       requested_extensions_(std::move(requested_extensions)),
       stream_request_(request),
-      websocket_endpoint_lock_manager_(websocket_endpoint_lock_manager),
-      weak_ptr_factory_(this) {
+      websocket_endpoint_lock_manager_(websocket_endpoint_lock_manager) {
   DCHECK(connect_delegate);
   DCHECK(request);
 }
diff --git a/net/websockets/websocket_basic_handshake_stream.h b/net/websockets/websocket_basic_handshake_stream.h
index 69e14b8..31986aa 100644
--- a/net/websockets/websocket_basic_handshake_stream.h
+++ b/net/websockets/websocket_basic_handshake_stream.h
@@ -149,7 +149,7 @@
 
   WebSocketEndpointLockManager* const websocket_endpoint_lock_manager_;
 
-  base::WeakPtrFactory<WebSocketBasicHandshakeStream> weak_ptr_factory_;
+  base::WeakPtrFactory<WebSocketBasicHandshakeStream> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(WebSocketBasicHandshakeStream);
 };
diff --git a/net/websockets/websocket_basic_stream_adapters.cc b/net/websockets/websocket_basic_stream_adapters.cc
index 7bdf9dbbd..789804f0 100644
--- a/net/websockets/websocket_basic_stream_adapters.cc
+++ b/net/websockets/websocket_basic_stream_adapters.cc
@@ -57,8 +57,7 @@
       stream_error_(ERR_CONNECTION_CLOSED),
       delegate_(delegate),
       write_length_(0),
-      net_log_(net_log),
-      weak_factory_(this) {
+      net_log_(net_log) {
   stream_->SetDelegate(this);
 }
 
diff --git a/net/websockets/websocket_basic_stream_adapters.h b/net/websockets/websocket_basic_stream_adapters.h
index 350a722..6c2ee1f 100644
--- a/net/websockets/websocket_basic_stream_adapters.h
+++ b/net/websockets/websocket_basic_stream_adapters.h
@@ -144,7 +144,7 @@
 
   NetLogWithSource net_log_;
 
-  base::WeakPtrFactory<WebSocketSpdyStreamAdapter> weak_factory_;
+  base::WeakPtrFactory<WebSocketSpdyStreamAdapter> weak_factory_{this};
 };
 
 }  // namespace net
diff --git a/net/websockets/websocket_channel_test.cc b/net/websockets/websocket_channel_test.cc
index a55e266f..cb83f9c0 100644
--- a/net/websockets/websocket_channel_test.cc
+++ b/net/websockets/websocket_channel_test.cc
@@ -660,7 +660,7 @@
 // 2. Calling either callback may delete the stream altogether.
 class ResetOnWriteFakeWebSocketStream : public FakeWebSocketStream {
  public:
-  ResetOnWriteFakeWebSocketStream() : closed_(false), weak_ptr_factory_(this) {}
+  ResetOnWriteFakeWebSocketStream() : closed_(false) {}
 
   int WriteFrames(std::vector<std::unique_ptr<WebSocketFrame>>* frames,
                   CompletionOnceCallback callback) override {
@@ -697,7 +697,7 @@
   bool closed_;
   // An IO error can result in the socket being deleted, so we use weak pointers
   // to ensure correct behaviour in that case.
-  base::WeakPtrFactory<ResetOnWriteFakeWebSocketStream> weak_ptr_factory_;
+  base::WeakPtrFactory<ResetOnWriteFakeWebSocketStream> weak_ptr_factory_{this};
 };
 
 // This mock is for verifying that WebSocket protocol semantics are obeyed (to
diff --git a/net/websockets/websocket_http2_handshake_stream.cc b/net/websockets/websocket_http2_handshake_stream.cc
index ecd4ecc..99910c99b 100644
--- a/net/websockets/websocket_http2_handshake_stream.cc
+++ b/net/websockets/websocket_http2_handshake_stream.cc
@@ -53,8 +53,7 @@
       request_info_(nullptr),
       stream_closed_(false),
       stream_error_(OK),
-      response_headers_complete_(false),
-      weak_ptr_factory_(this) {
+      response_headers_complete_(false) {
   DCHECK(connect_delegate);
   DCHECK(request);
 }
diff --git a/net/websockets/websocket_http2_handshake_stream.h b/net/websockets/websocket_http2_handshake_stream.h
index af73445..23ab9d2 100644
--- a/net/websockets/websocket_http2_handshake_stream.h
+++ b/net/websockets/websocket_http2_handshake_stream.h
@@ -177,7 +177,7 @@
   // to avoid including extension-related header files here.
   std::unique_ptr<WebSocketExtensionParams> extension_params_;
 
-  base::WeakPtrFactory<WebSocketHttp2HandshakeStream> weak_ptr_factory_;
+  base::WeakPtrFactory<WebSocketHttp2HandshakeStream> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(WebSocketHttp2HandshakeStream);
 };
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index e2399f4..0bc5715 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -2582,6 +2582,25 @@
     FinishLoadingDocument();
 }
 
+void PDFiumEngine::AppendPageRectToPages(const pp::Rect& page_rect,
+                                         size_t page_index,
+                                         bool reload) {
+  if (!reload) {
+    // The page is marked as not being available even if |doc_complete| is
+    // true because FPDFAvail_IsPageAvail() still has to be called for this
+    // page, which will be done in FinishLoadingDocument().
+    pages_.push_back(
+        std::make_unique<PDFiumPage>(this, page_index, page_rect, false));
+  } else if (page_index < pages_.size()) {
+    pages_[page_index]->set_rect(page_rect);
+  } else {
+    bool available =
+        FPDFAvail_IsPageAvail(fpdf_availability(), page_index, nullptr);
+    pages_.push_back(
+        std::make_unique<PDFiumPage>(this, page_index, page_rect, available));
+  }
+}
+
 void PDFiumEngine::LoadPageInfo(bool reload) {
   if (!doc_loader_)
     return;
@@ -2634,21 +2653,9 @@
   for (size_t i = 0; i < new_page_count; ++i) {
     // Center pages relative to the entire document.
     page_rects[i].set_x((document_size_.width() - page_rects[i].width()) / 2);
-    pp::Rect page_rect(page_rects[i]);
-    page_rect.Inset(kPageShadowLeft, kPageShadowTop, kPageShadowRight,
-                    kPageShadowBottom);
-    if (!reload) {
-      // The page is marked as not being available even if |doc_complete| is
-      // true because FPDFAvail_IsPageAvail() still has to be called for this
-      // page, which will be done in FinishLoadingDocument().
-      pages_.push_back(std::make_unique<PDFiumPage>(this, i, page_rect, false));
-    } else if (i < pages_.size()) {
-      pages_[i]->set_rect(page_rect);
-    } else {
-      bool available = FPDFAvail_IsPageAvail(fpdf_availability(), i, nullptr);
-      pages_.push_back(
-          std::make_unique<PDFiumPage>(this, i, page_rect, available));
-    }
+    page_rects[i].Inset(kPageShadowLeft, kPageShadowTop, kPageShadowRight,
+                        kPageShadowBottom);
+    AppendPageRectToPages(page_rects[i], i, reload);
   }
 
   // Remove pages that do not exist anymore.
diff --git a/pdf/pdfium/pdfium_engine.h b/pdf/pdfium/pdfium_engine.h
index 96b7841..c96dcc86 100644
--- a/pdf/pdfium/pdfium_engine.h
+++ b/pdf/pdfium/pdfium_engine.h
@@ -227,6 +227,12 @@
   // If this has been run once, it will not notify the client again.
   void FinishLoadingDocument();
 
+  // Appends a PDFiumPage with |page_rect| to |pages_| or sets existing
+  // PDFiumPage for |page_index| to |page_rect|. |page_index| is 0-based.
+  void AppendPageRectToPages(const pp::Rect& page_rect,
+                             size_t page_index,
+                             bool reload);
+
   // Loads information about the pages in the document and calculate the
   // document size.
   void LoadPageInfo(bool reload);
diff --git a/sandbox/win/src/handle_closer.cc b/sandbox/win/src/handle_closer.cc
index 3e2f1f0..23fe0c8 100644
--- a/sandbox/win/src/handle_closer.cc
+++ b/sandbox/win/src/handle_closer.cc
@@ -104,23 +104,11 @@
   if (!SetupHandleList(local_buffer.get(), bytes_needed))
     return false;
 
-  HANDLE child = target->Process();
-
-  // Allocate memory in the target process without specifying the address
-  void* remote_data = ::VirtualAllocEx(child, nullptr, bytes_needed, MEM_COMMIT,
-                                       PAGE_READWRITE);
-  if (!remote_data)
+  void* remote_data;
+  if (!CopyToChildMemory(target->Process(), local_buffer.get(), bytes_needed,
+                         &remote_data))
     return false;
 
-  // Copy the handle buffer over.
-  SIZE_T bytes_written;
-  bool result = ::WriteProcessMemory(child, remote_data, local_buffer.get(),
-                                     bytes_needed, &bytes_written);
-  if (!result || bytes_written != bytes_needed) {
-    ::VirtualFreeEx(child, remote_data, 0, MEM_RELEASE);
-    return false;
-  }
-
   g_handles_to_close = reinterpret_cast<HandleCloserInfo*>(remote_data);
 
   ResultCode rc = target->TransferVariable(
diff --git a/sandbox/win/src/interception.cc b/sandbox/win/src/interception.cc
index d66ceb2..cfe9b0b7 100644
--- a/sandbox/win/src/interception.cc
+++ b/sandbox/win/src/interception.cc
@@ -142,14 +142,12 @@
     return SBOX_ERROR_CANNOT_SETUP_INTERCEPTION_CONFIG_BUFFER;
 
   void* remote_buffer;
-  ResultCode rc =
-      CopyDataToChild(local_buffer.get(), buffer_bytes, &remote_buffer);
-
-  if (rc != SBOX_ALL_OK)
-    return rc;
+  if (!CopyToChildMemory(child_->Process(), local_buffer.get(), buffer_bytes,
+                         &remote_buffer))
+    return SBOX_ERROR_CANNOT_COPY_DATA_TO_CHILD;
 
   bool hot_patch_needed = (0 != buffer_bytes);
-  rc = PatchNtdll(hot_patch_needed);
+  ResultCode rc = PatchNtdll(hot_patch_needed);
 
   if (rc != SBOX_ALL_OK)
     return rc;
@@ -333,36 +331,6 @@
   return true;
 }
 
-ResultCode InterceptionManager::CopyDataToChild(const void* local_buffer,
-                                                size_t buffer_bytes,
-                                                void** remote_buffer) const {
-  DCHECK(remote_buffer);
-  if (0 == buffer_bytes) {
-    *remote_buffer = nullptr;
-    return SBOX_ALL_OK;
-  }
-
-  HANDLE child = child_->Process();
-
-  // Allocate memory on the target process without specifying the address
-  void* remote_data = ::VirtualAllocEx(child, nullptr, buffer_bytes, MEM_COMMIT,
-                                       PAGE_READWRITE);
-  if (!remote_data)
-    return SBOX_ERROR_NO_SPACE;
-
-  SIZE_T bytes_written;
-  bool success = ::WriteProcessMemory(child, remote_data, local_buffer,
-                                      buffer_bytes, &bytes_written);
-  if (!success || bytes_written != buffer_bytes) {
-    ::VirtualFreeEx(child, remote_data, 0, MEM_RELEASE);
-    return SBOX_ERROR_CANNOT_COPY_DATA_TO_CHILD;
-  }
-
-  *remote_buffer = remote_data;
-
-  return SBOX_ALL_OK;
-}
-
 // Only return true if the child should be able to perform this interception.
 bool InterceptionManager::IsInterceptionPerformedByChild(
     const InterceptionData& data) const {
diff --git a/sandbox/win/src/target_process.h b/sandbox/win/src/target_process.h
index 7242166..f55fa46 100644
--- a/sandbox/win/src/target_process.h
+++ b/sandbox/win/src/target_process.h
@@ -98,7 +98,7 @@
   // Returns the handle to the main thread.
   HANDLE MainThread() const { return sandbox_process_info_.thread_handle(); }
 
-  // Transfers a 32-bit variable between the broker and the target.
+  // Transfers variable at |address| of |size| bytes from broker to target.
   ResultCode TransferVariable(const char* name, void* address, size_t size);
 
  private:
diff --git a/sandbox/win/src/win_utils.cc b/sandbox/win/src/win_utils.cc
index 863b874..2225c88 100644
--- a/sandbox/win/src/win_utils.cc
+++ b/sandbox/win/src/win_utils.cc
@@ -474,6 +474,35 @@
   return ok;
 }
 
+bool CopyToChildMemory(HANDLE child,
+                       const void* local_buffer,
+                       size_t buffer_bytes,
+                       void** remote_buffer) {
+  DCHECK(remote_buffer);
+  if (0 == buffer_bytes) {
+    *remote_buffer = nullptr;
+    return true;
+  }
+
+  // Allocate memory in the target process without specifying the address
+  void* remote_data = ::VirtualAllocEx(child, nullptr, buffer_bytes, MEM_COMMIT,
+                                       PAGE_READWRITE);
+  if (!remote_data)
+    return false;
+
+  SIZE_T bytes_written;
+  bool success = ::WriteProcessMemory(child, remote_data, local_buffer,
+                                      buffer_bytes, &bytes_written);
+  if (!success || bytes_written != buffer_bytes) {
+    ::VirtualFreeEx(child, remote_data, 0, MEM_RELEASE);
+    return false;
+  }
+
+  *remote_buffer = remote_data;
+
+  return true;
+}
+
 DWORD GetLastErrorFromNtStatus(NTSTATUS status) {
   RtlNtStatusToDosErrorFunction NtStatusToDosError = nullptr;
   ResolveNTFunctionPtr("RtlNtStatusToDosError", &NtStatusToDosError);
diff --git a/sandbox/win/src/win_utils.h b/sandbox/win/src/win_utils.h
index f69ddf7..fed7b4c 100644
--- a/sandbox/win/src/win_utils.h
+++ b/sandbox/win/src/win_utils.h
@@ -119,6 +119,17 @@
                                const void* buffer,
                                size_t length);
 
+// Allocates |buffer_bytes| in child (PAGE_READWRITE) and copies data
+// from |local_buffer| in this process into |child|. |remote_buffer|
+// contains the address in the chile.  If a zero byte copy is
+// requested |true| is returned and no allocation or copying is
+// attempted.  Returns false if allocation or copying fails. If
+// copying fails, the allocation will be reversed.
+bool CopyToChildMemory(HANDLE child,
+                       const void* local_buffer,
+                       size_t buffer_bytes,
+                       void** remote_buffer);
+
 // Returns true if the provided path points to a pipe.
 bool IsPipe(const base::string16& path);
 
diff --git a/services/audio/test/service_lifetime_connector_test.cc b/services/audio/test/service_lifetime_connector_test.cc
index f8d82e4..1d1807c6 100644
--- a/services/audio/test/service_lifetime_connector_test.cc
+++ b/services/audio/test/service_lifetime_connector_test.cc
@@ -83,7 +83,7 @@
       connector_factory.RegisterInstance(mojom::kServiceName));
   service_->set_termination_closure(quit_request_.Get());
   connector_ = connector_factory.CreateConnector();
-  scoped_task_environment_.FastForwardUntilNoTasksRemain();
+  scoped_task_environment_.RunUntilIdle();
 
   mojom::SystemInfoPtr info;
   connector_->BindInterface(mojom::kServiceName, &info);
@@ -124,7 +124,7 @@
       connector_factory.RegisterInstance(mojom::kServiceName));
   service_->set_termination_closure(quit_request_.Get());
   connector_ = connector_factory.CreateConnector();
-  scoped_task_environment_.FastForwardUntilNoTasksRemain();
+  scoped_task_environment_.RunUntilIdle();
 
   mojom::SystemInfoPtr info;
   connector_->BindInterface(mojom::kServiceName, &info);
@@ -138,7 +138,7 @@
 
   info.reset();
 
-  scoped_task_environment_.FastForwardUntilNoTasksRemain();
+  scoped_task_environment_.RunUntilIdle();
 
   service_.reset();
 }
@@ -153,7 +153,7 @@
       connector_factory.RegisterInstance(mojom::kServiceName));
   service_->set_termination_closure(quit_request_.Get());
   connector_ = connector_factory.CreateConnector();
-  scoped_task_environment_.FastForwardUntilNoTasksRemain();
+  scoped_task_environment_.RunUntilIdle();
 
   mojom::SystemInfoPtr info;
   connector_->BindInterface(mojom::kServiceName, &info);
@@ -167,7 +167,7 @@
 
   info.reset();
 
-  scoped_task_environment_.FastForwardUntilNoTasksRemain();
+  scoped_task_environment_.RunUntilIdle();
 
   service_.reset();
 }
diff --git a/services/network/public/cpp/net_ipc_param_traits.cc b/services/network/public/cpp/net_ipc_param_traits.cc
index e8f28e7c..4791422 100644
--- a/services/network/public/cpp/net_ipc_param_traits.cc
+++ b/services/network/public/cpp/net_ipc_param_traits.cc
@@ -245,7 +245,7 @@
   if (!ReadParam(m, iter, &has_object))
     return false;
   if (has_object)
-    *r = new net::HttpResponseHeaders(iter);
+    *r = base::MakeRefCounted<net::HttpResponseHeaders>(iter);
   return true;
 }
 
@@ -328,7 +328,7 @@
     const base::Pickle* m,
     base::PickleIterator* iter,
     param_type* r) {
-  *r = new net::SSLCertRequestInfo();
+  *r = base::MakeRefCounted<net::SSLCertRequestInfo>();
   return ReadParam(m, iter, &(*r)->host_and_port) &&
          ReadParam(m, iter, &(*r)->is_proxy) &&
          ReadParam(m, iter, &(*r)->cert_authorities) &&
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index a90158d..82b8bb7 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -7223,6 +7223,12 @@
     "scripts": [
       {
         "isolate_coverage_data": true,
+        "name": "check_static_initializers",
+        "script": "check_static_initializers.py",
+        "swarming": {}
+      },
+      {
+        "isolate_coverage_data": true,
         "name": "checkdeps",
         "script": "checkdeps.py",
         "swarming": {}
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 82210f7..3944c441 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -296,12 +296,6 @@
       },
     },
   },
-  # TODO(crbug.com/956591): Remove this once the bug is fixed.
-  'check_static_initializers': {
-    'remove_from': [
-      'Linux Tests Code Coverage',
-    ],
-  },
   'checkbins': {
     'remove_from': [
       'linux-archive-dbg',
diff --git a/testing/variations/README.md b/testing/variations/README.md
index b71e663..41eb858 100644
--- a/testing/variations/README.md
+++ b/testing/variations/README.md
@@ -53,7 +53,8 @@
 `experiments`.
 
 `platforms` is an array of strings, indicating the targetted platforms. The
-strings may be `android`, `chromeos`, `ios`, `linux`, `mac`, or `windows`.
+strings may be `android`, `android_webview`, `chromeos`, `ios`, `linux`, `mac`,
+or `windows`.
 
 `experiments` is an array containing the *experiments*.
 
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 3d010c4..8fdd0b8 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2196,6 +2196,7 @@
         {
             "platforms": [
                 "android",
+                "android_webview",
                 "chromeos",
                 "linux",
                 "mac",
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn
index 757a9d5..7b838b0d 100644
--- a/third_party/blink/public/BUILD.gn
+++ b/third_party/blink/public/BUILD.gn
@@ -384,6 +384,7 @@
     "web/modules/peerconnection/media_stream_remote_video_source.h",
     "web/modules/service_worker/web_service_worker_context_client.h",
     "web/modules/service_worker/web_service_worker_context_proxy.h",
+    "web/modules/webrtc/webrtc_audio_renderer.h",
     "web/web_active_fling_parameters.h",
     "web/web_apply_constraints_request.h",
     "web/web_array_buffer.h",
diff --git a/third_party/blink/public/common/css/forced_colors.h b/third_party/blink/public/common/css/forced_colors.h
index fac2270..6edbf9b 100644
--- a/third_party/blink/public/common/css/forced_colors.h
+++ b/third_party/blink/public/common/css/forced_colors.h
@@ -11,6 +11,7 @@
 enum class ForcedColors {
   kNone,
   kActive,
+  kMaxValue = kActive,
 };
 
 }  // namespace blink
diff --git a/third_party/blink/public/platform/modules/mediastream/media_stream_audio_source.h b/third_party/blink/public/platform/modules/mediastream/media_stream_audio_source.h
index 11fdce2..a55ea463 100644
--- a/third_party/blink/public/platform/modules/mediastream/media_stream_audio_source.h
+++ b/third_party/blink/public/platform/modules/mediastream/media_stream_audio_source.h
@@ -185,7 +185,7 @@
 
   // Provides weak pointers so that MediaStreamAudioTracks won't call
   // StopAudioDeliveryTo() if this instance dies first.
-  base::WeakPtrFactory<MediaStreamAudioSource> weak_factory_;
+  base::WeakPtrFactory<MediaStreamAudioSource> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(MediaStreamAudioSource);
 };
diff --git a/third_party/blink/public/platform/modules/mediastream/media_stream_audio_track.h b/third_party/blink/public/platform/modules/mediastream/media_stream_audio_track.h
index 8efbce2..28487db 100644
--- a/third_party/blink/public/platform/modules/mediastream/media_stream_audio_track.h
+++ b/third_party/blink/public/platform/modules/mediastream/media_stream_audio_track.h
@@ -112,7 +112,7 @@
   std::unique_ptr<media::AudioBus> silent_bus_;
 
   // Provides weak pointers that are valid until Stop() is called.
-  base::WeakPtrFactory<MediaStreamAudioTrack> weak_factory_;
+  base::WeakPtrFactory<MediaStreamAudioTrack> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(MediaStreamAudioTrack);
 };
diff --git a/third_party/blink/public/platform/modules/webrtc/webrtc_source.h b/third_party/blink/public/platform/modules/webrtc/webrtc_source.h
index 4af07f2d..9310c7f 100644
--- a/third_party/blink/public/platform/modules/webrtc/webrtc_source.h
+++ b/third_party/blink/public/platform/modules/webrtc/webrtc_source.h
@@ -13,16 +13,45 @@
 
 namespace blink {
 
-// TODO(xians): Move the following interface to webrtc so that
+class WebRtcAudioRenderer;
+
+// TODO(xians): Move the following two interfaces to webrtc so that
 // libjingle can own references to the renderer and capturer.
 //
+// TODO(crbug.com/704136): Move the classes below out of the Blink exposed
+// API when all users of it have been Onion souped.
+class BLINK_PLATFORM_EXPORT WebRtcAudioRendererSource {
+ public:
+  // Callback to get the rendered data.
+  // |audio_bus| must have buffer size |sample_rate/100| and 1-2 channels.
+  virtual void RenderData(media::AudioBus* audio_bus,
+                          int sample_rate,
+                          int audio_delay_milliseconds,
+                          base::TimeDelta* current_time) = 0;
+
+  // Callback to notify the client that the renderer is going away.
+  virtual void RemoveAudioRenderer(WebRtcAudioRenderer* renderer) = 0;
+
+  // Callback to notify the client that the audio renderer thread stopped.
+  // This function must be called only when that thread is actually stopped.
+  // Otherwise a race may occur.
+  virtual void AudioRendererThreadStopped() = 0;
+
+  // Callback to notify the client of the output device the renderer is using.
+  virtual void SetOutputDeviceForAec(const std::string& output_device_id) = 0;
+
+  // Returns the UnguessableToken used to connect this stream to an input stream
+  // for echo cancellation.
+  virtual base::UnguessableToken GetAudioProcessingId() const = 0;
+
+ protected:
+  virtual ~WebRtcAudioRendererSource() {}
+};
+
 // TODO(xians): Merge this interface with WebRtcAudioRendererSource.
 // The reason why we could not do it today is that WebRtcAudioRendererSource
 // gets the data by pulling, while the data is pushed into
 // WebRtcPlayoutDataSource::Sink.
-//
-// TODO(crbug.com/704136): Move the class below out of the Blink exposed
-// API when all users of it have been Onion souped.
 class BLINK_PLATFORM_EXPORT WebRtcPlayoutDataSource {
  public:
   class Sink {
diff --git a/third_party/blink/public/platform/web_url_response.h b/third_party/blink/public/platform/web_url_response.h
index 53b36d19..d0e9c07 100644
--- a/third_party/blink/public/platform/web_url_response.h
+++ b/third_party/blink/public/platform/web_url_response.h
@@ -288,9 +288,16 @@
   // Original size of the response before decompression.
   BLINK_PLATFORM_EXPORT void SetEncodedDataLength(int64_t);
 
+  // Original size of the response body before decompression.
+  BLINK_PLATFORM_EXPORT int64_t EncodedBodyLength() const;
+  BLINK_PLATFORM_EXPORT void SetEncodedBodyLength(int64_t);
+
   BLINK_PLATFORM_EXPORT void SetIsSignedExchangeInnerResponse(bool);
   BLINK_PLATFORM_EXPORT void SetWasInPrefetchCache(bool);
 
+  // Whether this resource is from a MHTML archive.
+  BLINK_PLATFORM_EXPORT bool FromArchive() const;
+
 #if INSIDE_BLINK
  protected:
   // Permit subclasses to set arbitrary ResourceResponse pointer as
diff --git a/third_party/blink/public/platform/webaudiosourceprovider_impl.h b/third_party/blink/public/platform/webaudiosourceprovider_impl.h
index ef60ba0..ee0d096 100644
--- a/third_party/blink/public/platform/webaudiosourceprovider_impl.h
+++ b/third_party/blink/public/platform/webaudiosourceprovider_impl.h
@@ -116,7 +116,7 @@
   media::MediaLog* const media_log_;
 
   // NOTE: Weak pointers must be invalidated before all other member variables.
-  base::WeakPtrFactory<WebAudioSourceProviderImpl> weak_factory_;
+  base::WeakPtrFactory<WebAudioSourceProviderImpl> weak_factory_{this};
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(WebAudioSourceProviderImpl);
 };
diff --git a/third_party/blink/public/web/modules/mediastream/media_stream_video_renderer_sink.h b/third_party/blink/public/web/modules/mediastream/media_stream_video_renderer_sink.h
index 40b3bf3..4aba46a2 100644
--- a/third_party/blink/public/web/modules/mediastream/media_stream_video_renderer_sink.h
+++ b/third_party/blink/public/web/modules/mediastream/media_stream_video_renderer_sink.h
@@ -82,7 +82,7 @@
 
   THREAD_CHECKER(main_thread_checker_);
 
-  base::WeakPtrFactory<MediaStreamVideoRendererSink> weak_factory_;
+  base::WeakPtrFactory<MediaStreamVideoRendererSink> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(MediaStreamVideoRendererSink);
 };
diff --git a/third_party/blink/public/web/modules/mediastream/media_stream_video_source.h b/third_party/blink/public/web/modules/mediastream/media_stream_video_source.h
index 2510934..49bef5e 100644
--- a/third_party/blink/public/web/modules/mediastream/media_stream_video_source.h
+++ b/third_party/blink/public/web/modules/mediastream/media_stream_video_source.h
@@ -328,7 +328,7 @@
   base::OnceClosure remove_last_track_callback_;
 
   // NOTE: Weak pointers must be invalidated before all other member variables.
-  base::WeakPtrFactory<MediaStreamVideoSource> weak_factory_;
+  base::WeakPtrFactory<MediaStreamVideoSource> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(MediaStreamVideoSource);
 };
diff --git a/third_party/blink/public/web/modules/mediastream/media_stream_video_track.h b/third_party/blink/public/web/modules/mediastream/media_stream_video_track.h
index 6969003..42127066 100644
--- a/third_party/blink/public/web/modules/mediastream/media_stream_video_track.h
+++ b/third_party/blink/public/web/modules/mediastream/media_stream_video_track.h
@@ -177,7 +177,7 @@
   base::Optional<double> computed_frame_rate_;
   media::VideoCaptureFormat computed_source_format_;
 
-  base::WeakPtrFactory<MediaStreamVideoTrack> weak_factory_;
+  base::WeakPtrFactory<MediaStreamVideoTrack> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(MediaStreamVideoTrack);
 };
diff --git a/third_party/blink/public/web/modules/webrtc/DEPS b/third_party/blink/public/web/modules/webrtc/DEPS
new file mode 100644
index 0000000..d376bf3d
--- /dev/null
+++ b/third_party/blink/public/web/modules/webrtc/DEPS
@@ -0,0 +1,6 @@
+include_rules = [
+    "+base/sequence_checker.h",
+    "+base/single_thread_task_runner.h",
+    "+base/synchronization/lock.h",
+    "+media/base",
+]
diff --git a/content/renderer/media/webrtc/webrtc_audio_renderer.h b/third_party/blink/public/web/modules/webrtc/webrtc_audio_renderer.h
similarity index 91%
rename from content/renderer/media/webrtc/webrtc_audio_renderer.h
rename to third_party/blink/public/web/modules/webrtc/webrtc_audio_renderer.h
index 829115d..425cbd7 100644
--- a/content/renderer/media/webrtc/webrtc_audio_renderer.h
+++ b/third_party/blink/public/web/modules/webrtc/webrtc_audio_renderer.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_RENDERER_MEDIA_WEBRTC_WEBRTC_AUDIO_RENDERER_H_
-#define CONTENT_RENDERER_MEDIA_WEBRTC_WEBRTC_AUDIO_RENDERER_H_
+#ifndef THIRD_PARTY_BLINK_PUBLIC_WEB_MODULES_WEBRTC_WEBRTC_AUDIO_RENDERER_H_
+#define THIRD_PARTY_BLINK_PUBLIC_WEB_MODULES_WEBRTC_WEBRTC_AUDIO_RENDERER_H_
 
 #include <stdint.h>
 
@@ -18,25 +18,27 @@
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_checker.h"
-#include "content/renderer/media/webrtc/webrtc_audio_device_impl.h"
 #include "media/base/audio_decoder.h"
 #include "media/base/audio_pull_fifo.h"
 #include "media/base/audio_renderer_sink.h"
 #include "media/base/channel_layout.h"
 #include "third_party/blink/public/platform/modules/mediastream/web_media_stream_audio_renderer.h"
+#include "third_party/blink/public/platform/modules/webrtc/webrtc_source.h"
+#include "third_party/blink/public/platform/web_common.h"
 #include "third_party/blink/public/platform/web_media_stream.h"
 
 namespace webrtc {
 class AudioSourceInterface;
 }  // namespace webrtc
 
-namespace content {
+namespace blink {
 
+class WebLocalFrame;
 class WebRtcAudioRendererSource;
 
 // This renderer handles calls from the pipeline and WebRtc ADM. It is used
 // for connecting WebRtc MediaStream with the audio pipeline.
-class CONTENT_EXPORT WebRtcAudioRenderer
+class BLINK_MODULES_EXPORT WebRtcAudioRenderer
     : public media::AudioRendererSink::RenderCallback,
       public blink::WebMediaStreamAudioRenderer {
  public:
@@ -81,7 +83,7 @@
   WebRtcAudioRenderer(
       const scoped_refptr<base::SingleThreadTaskRunner>& signaling_thread,
       const blink::WebMediaStream& media_stream,
-      int source_render_frame_id,
+      WebLocalFrame* web_frame,
       int session_id,
       const std::string& device_id);
 
@@ -203,8 +205,13 @@
   // |sink_|.
   void PrepareSink();
 
-  // The RenderFrame in which the audio is rendered into |sink_|.
-  const int source_render_frame_id_;
+  // The WebLocalFrame in which the audio is rendered into |sink_|.
+  //
+  // TODO(crbug.com/704136): Replace |source_internal_frame_| with regular
+  // fields once this header file moves to blink/renderer.
+  class InternalFrame;
+  std::unique_ptr<InternalFrame> source_internal_frame_;
+
   const int session_id_;
 
   const scoped_refptr<base::SingleThreadTaskRunner> signaling_thread_;
@@ -216,6 +223,8 @@
   const blink::WebMediaStream media_stream_;
 
   // Audio data source from the browser process.
+  //
+  // TODO(crbug.com/704136): Make it a Member.
   WebRtcAudioRendererSource* source_;
 
   // Protects access to |state_|, |source_|, |audio_fifo_|,
@@ -263,6 +272,6 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(WebRtcAudioRenderer);
 };
 
-}  // namespace content
+}  // namespace blink
 
-#endif  // CONTENT_RENDERER_MEDIA_WEBRTC_WEBRTC_AUDIO_RENDERER_H_
+#endif  // THIRD_PARTY_BLINK_PUBLIC_WEB_MODULES_WEBRTC_WEBRTC_AUDIO_RENDERER_H_
diff --git a/third_party/blink/renderer/config.gni b/third_party/blink/renderer/config.gni
index bfee64c6..397088e1 100644
--- a/third_party/blink/renderer/config.gni
+++ b/third_party/blink/renderer/config.gni
@@ -15,8 +15,9 @@
 
 declare_args() {
   # If true, use PFFFT for WebAudio FFT support.  This can be used for
-  # any Android architecture and also Linux and Windows.
-  use_webaudio_pffft = is_android || target_os == "linux"
+  # any Android architecture and also Linux and Windows.  Do not use for Mac
+  # because the FFT library there is much faster.
+  use_webaudio_pffft = is_android || target_os == "linux" || target_os == "win"
 }
 
 declare_args() {
diff --git a/third_party/blink/renderer/core/animation/css/css_animations.cc b/third_party/blink/renderer/core/animation/css/css_animations.cc
index f83470e4..6e90fc5 100644
--- a/third_party/blink/renderer/core/animation/css/css_animations.cc
+++ b/third_party/blink/renderer/core/animation/css/css_animations.cc
@@ -559,7 +559,7 @@
 
     Animation* animation = transitions_.Take(property).animation;
     KeyframeEffect* effect = ToKeyframeEffect(animation->effect());
-    if (effect->HasActiveAnimationsOnCompositor(property) &&
+    if (effect && effect->HasActiveAnimationsOnCompositor(property) &&
         pending_update_.NewTransitions().find(property) !=
             pending_update_.NewTransitions().end() &&
         !animation->Limited()) {
@@ -671,7 +671,7 @@
       state.update.CancelTransition(property);
       KeyframeEffect* effect =
           ToKeyframeEffect(running_transition->animation->effect());
-      if (effect->HasActiveAnimationsOnCompositor())
+      if (effect && effect->HasActiveAnimationsOnCompositor())
         retargeted_compositor_transition = running_transition;
       DCHECK(!state.animating_element->GetElementAnimations() ||
              !state.animating_element->GetElementAnimations()
diff --git a/third_party/blink/renderer/core/content_capture/content_capture_task_histogram_reporter.cc b/third_party/blink/renderer/core/content_capture/content_capture_task_histogram_reporter.cc
index 7ffd4d1..a008c48 100644
--- a/third_party/blink/renderer/core/content_capture/content_capture_task_histogram_reporter.cc
+++ b/third_party/blink/renderer/core/content_capture/content_capture_task_histogram_reporter.cc
@@ -10,7 +10,6 @@
 
 // static
 constexpr char ContentCaptureTaskHistogramReporter::kCaptureContentTime[];
-constexpr char ContentCaptureTaskHistogramReporter::kCaptureOneContentTime[];
 constexpr char ContentCaptureTaskHistogramReporter::kCaptureContentDelayTime[];
 constexpr char ContentCaptureTaskHistogramReporter::kSendContentTime[];
 constexpr char ContentCaptureTaskHistogramReporter::kSentContentCount[];
@@ -21,7 +20,6 @@
                                             30000,
                                             50),
       capture_content_time_histogram_(kCaptureContentTime, 0, 50000, 50),
-      capture_one_content_time_histogram_(kCaptureOneContentTime, 0, 50000, 50),
       send_content_time_histogram_(kSendContentTime, 0, 50000, 50),
       sent_content_count_histogram_(kSentContentCount, 0, 10000, 50) {}
 
@@ -51,8 +49,6 @@
   captured_content_change_time_ = std::move(content_change_time_);
   base::TimeDelta delta = WTF::CurrentTimeTicks() - capture_content_start_time_;
   capture_content_time_histogram_.CountMicroseconds(delta);
-  capture_one_content_time_histogram_.CountMicroseconds(delta /
-                                                        captured_content_count);
 }
 
 void ContentCaptureTaskHistogramReporter::OnSendContentStarted() {
diff --git a/third_party/blink/renderer/core/content_capture/content_capture_task_histogram_reporter.h b/third_party/blink/renderer/core/content_capture/content_capture_task_histogram_reporter.h
index a97d67b..502894f 100644
--- a/third_party/blink/renderer/core/content_capture/content_capture_task_histogram_reporter.h
+++ b/third_party/blink/renderer/core/content_capture/content_capture_task_histogram_reporter.h
@@ -22,8 +22,6 @@
       "ContentCapture.CaptureContentDelayTime";
   static constexpr char kCaptureContentTime[] =
       "ContentCapture.CaptureContentTime";
-  static constexpr char kCaptureOneContentTime[] =
-      "ContentCapture.CaptureOneContentTime";
   static constexpr char kSendContentTime[] = "ContentCapture.SendContentTime";
   static constexpr char kSentContentCount[] = "ContentCapture.SentContentCount";
 
@@ -55,10 +53,6 @@
   // Records time to capture the content, its range is from 0 to 50,000
   // microseconds.
   CustomCountHistogram capture_content_time_histogram_;
-  // Records time to capture one content, this is the average of all captured
-  // content for a specific ContentCapture, its range is from 0 to 50,000
-  // microseconds.
-  CustomCountHistogram capture_one_content_time_histogram_;
   // Records time to send the content, its range is from 0 to 50,000
   // microseconds.
   CustomCountHistogram send_content_time_histogram_;
diff --git a/third_party/blink/renderer/core/content_capture/content_capture_test.cc b/third_party/blink/renderer/core/content_capture/content_capture_test.cc
index 3b1baa87..e2a802a 100644
--- a/third_party/blink/renderer/core/content_capture/content_capture_test.cc
+++ b/third_party/blink/renderer/core/content_capture/content_capture_test.cc
@@ -441,8 +441,6 @@
   histograms.ExpectTotalCount(
       ContentCaptureTaskHistogramReporter::kCaptureContentTime, 0u);
   histograms.ExpectTotalCount(
-      ContentCaptureTaskHistogramReporter::kCaptureOneContentTime, 0u);
-  histograms.ExpectTotalCount(
       ContentCaptureTaskHistogramReporter::kSendContentTime, 0u);
   histograms.ExpectTotalCount(
       ContentCaptureTaskHistogramReporter::kCaptureContentDelayTime, 0u);
@@ -457,8 +455,6 @@
   histograms.ExpectTotalCount(
       ContentCaptureTaskHistogramReporter::kCaptureContentTime, 1u);
   histograms.ExpectTotalCount(
-      ContentCaptureTaskHistogramReporter::kCaptureOneContentTime, 1u);
-  histograms.ExpectTotalCount(
       ContentCaptureTaskHistogramReporter::kSendContentTime, 0u);
   histograms.ExpectTotalCount(
       ContentCaptureTaskHistogramReporter::kCaptureContentDelayTime, 0u);
@@ -475,8 +471,6 @@
   histograms.ExpectTotalCount(
       ContentCaptureTaskHistogramReporter::kCaptureContentTime, 1u);
   histograms.ExpectTotalCount(
-      ContentCaptureTaskHistogramReporter::kCaptureOneContentTime, 1u);
-  histograms.ExpectTotalCount(
       ContentCaptureTaskHistogramReporter::kSendContentTime, 1u);
   histograms.ExpectTotalCount(
       ContentCaptureTaskHistogramReporter::kCaptureContentDelayTime, 1u);
@@ -492,8 +486,6 @@
   histograms.ExpectTotalCount(
       ContentCaptureTaskHistogramReporter::kCaptureContentTime, 1u);
   histograms.ExpectTotalCount(
-      ContentCaptureTaskHistogramReporter::kCaptureOneContentTime, 1u);
-  histograms.ExpectTotalCount(
       ContentCaptureTaskHistogramReporter::kSendContentTime, 2u);
   histograms.ExpectTotalCount(
       ContentCaptureTaskHistogramReporter::kCaptureContentDelayTime, 1u);
@@ -508,8 +500,6 @@
   histograms.ExpectTotalCount(
       ContentCaptureTaskHistogramReporter::kCaptureContentTime, 2u);
   histograms.ExpectTotalCount(
-      ContentCaptureTaskHistogramReporter::kCaptureOneContentTime, 2u);
-  histograms.ExpectTotalCount(
       ContentCaptureTaskHistogramReporter::kSendContentTime, 3u);
   histograms.ExpectTotalCount(
       ContentCaptureTaskHistogramReporter::kCaptureContentDelayTime, 2u);
@@ -521,8 +511,6 @@
   histograms.ExpectTotalCount(
       ContentCaptureTaskHistogramReporter::kCaptureContentTime, 2u);
   histograms.ExpectTotalCount(
-      ContentCaptureTaskHistogramReporter::kCaptureOneContentTime, 2u);
-  histograms.ExpectTotalCount(
       ContentCaptureTaskHistogramReporter::kSendContentTime, 3u);
   histograms.ExpectTotalCount(
       ContentCaptureTaskHistogramReporter::kCaptureContentDelayTime, 2u);
diff --git a/third_party/blink/renderer/core/css/css_numeric_literal_value.cc b/third_party/blink/renderer/core/css/css_numeric_literal_value.cc
index c1e038b..dee3667 100644
--- a/third_party/blink/renderer/core/css/css_numeric_literal_value.cc
+++ b/third_party/blink/renderer/core/css/css_numeric_literal_value.cc
@@ -31,7 +31,7 @@
                                                        UnitType type) {
   // TODO(timloh): This looks wrong.
   if (std::isinf(value))
-    return nullptr;
+    value = 0;
 
   if (value < 0 || value > CSSValuePool::kMaximumCacheableIntegerValue)
     return MakeGarbageCollected<CSSNumericLiteralValue>(value, type);
diff --git a/third_party/blink/renderer/core/css/css_paint_value.cc b/third_party/blink/renderer/core/css/css_paint_value.cc
index 7b57a8e..5aeda58 100644
--- a/third_party/blink/renderer/core/css/css_paint_value.cc
+++ b/third_party/blink/renderer/core/css/css_paint_value.cc
@@ -63,6 +63,12 @@
         GetName(), document, paint_image_generator_observer_);
   }
 
+  // If the generator isn't ready yet, we have nothing to paint. Our
+  // |paint_image_generator_observer_| will cause us to be called again once the
+  // generator is ready.
+  if (!generator_->IsImageGeneratorReady())
+    return nullptr;
+
   if (!ParseInputArguments(document))
     return nullptr;
 
@@ -119,9 +125,7 @@
       !RuntimeEnabledFeatures::CSSPaintAPIArgumentsEnabled())
     return true;
 
-  if (!generator_->IsImageGeneratorReady())
-    return false;
-
+  DCHECK(generator_->IsImageGeneratorReady());
   const Vector<CSSSyntaxDescriptor>& input_argument_types =
       generator_->InputArgumentTypes();
   if (argument_variable_data_.size() != input_argument_types.size()) {
diff --git a/third_party/blink/renderer/core/css/css_paint_value_test.cc b/third_party/blink/renderer/core/css/css_paint_value_test.cc
index 30919feb7..d412d5f 100644
--- a/third_party/blink/renderer/core/css/css_paint_value_test.cc
+++ b/third_party/blink/renderer/core/css/css_paint_value_test.cc
@@ -29,16 +29,29 @@
 namespace blink {
 namespace {
 
-class CSSPaintValueTest : public RenderingTest,
-                          public ::testing::WithParamInterface<bool> {
- public:
-  CSSPaintValueTest() : scoped_off_main_thread_css_paint_(GetParam()) {}
-
- private:
-  ScopedOffMainThreadCSSPaintForTest scoped_off_main_thread_css_paint_;
+enum {
+  kCSSPaintAPIArguments = 1 << 0,
+  kOffMainThreadCSSPaint = 1 << 1,
 };
 
-INSTANTIATE_TEST_SUITE_P(, CSSPaintValueTest, Values(false, true));
+class CSSPaintValueTest : public RenderingTest,
+                          public ::testing::WithParamInterface<unsigned>,
+                          private ScopedCSSPaintAPIArgumentsForTest,
+                          private ScopedOffMainThreadCSSPaintForTest {
+ public:
+  CSSPaintValueTest()
+      : ScopedCSSPaintAPIArgumentsForTest(GetParam() & kCSSPaintAPIArguments),
+        ScopedOffMainThreadCSSPaintForTest(GetParam() &
+                                           kOffMainThreadCSSPaint) {}
+};
+
+INSTANTIATE_TEST_SUITE_P(,
+                         CSSPaintValueTest,
+                         Values(0,
+                                kCSSPaintAPIArguments,
+                                kOffMainThreadCSSPaint,
+                                kCSSPaintAPIArguments |
+                                    kOffMainThreadCSSPaint));
 
 class MockCSSPaintImageGenerator : public CSSPaintImageGenerator {
  public:
@@ -93,14 +106,6 @@
           ProvideOverrideGenerator);
 
   const FloatSize target_size(100, 100);
-  if (RuntimeEnabledFeatures::OffMainThreadCSSPaintEnabled()) {
-    // In off-thread CSS Paint, the actual paint call is deferred.
-    EXPECT_CALL(*mock_generator, Paint(_, _, _)).Times(0);
-  } else {
-    ON_CALL(*mock_generator, Paint(_, _, _))
-        .WillByDefault(
-            Return(PaintGeneratedImage::Create(nullptr, target_size)));
-  }
 
   SetBodyInnerHTML(R"HTML(
     <div id="target"></div>
@@ -111,12 +116,22 @@
   auto* ident = MakeGarbageCollected<CSSCustomIdentValue>("testpainter");
   CSSPaintValue* paint_value = MakeGarbageCollected<CSSPaintValue>(ident);
 
-  // Initially the generator is not ready, so GetImage should fail.
+  // Initially the generator is not ready, so GetImage should fail (and no paint
+  // should happen).
+  EXPECT_CALL(*mock_generator, Paint(_, _, _)).Times(0);
   EXPECT_FALSE(
       paint_value->GetImage(*target, GetDocument(), style, target_size));
 
   // Now mark the generator as ready - GetImage should then succeed.
-  EXPECT_CALL(*mock_generator, IsImageGeneratorReady()).WillOnce(Return(true));
+  ON_CALL(*mock_generator, IsImageGeneratorReady()).WillByDefault(Return(true));
+  // In off-thread CSS Paint, the actual paint call is deferred and so will
+  // never happen.
+  if (!RuntimeEnabledFeatures::OffMainThreadCSSPaintEnabled()) {
+    EXPECT_CALL(*mock_generator, Paint(_, _, _))
+        .WillRepeatedly(
+            Return(PaintGeneratedImage::Create(nullptr, target_size)));
+  }
+
   EXPECT_TRUE(
       paint_value->GetImage(*target, GetDocument(), style, target_size));
 }
diff --git a/third_party/blink/renderer/core/css/local_font_face_source.cc b/third_party/blink/renderer/core/css/local_font_face_source.cc
index 2cac90d..3240cb7 100644
--- a/third_party/blink/renderer/core/css/local_font_face_source.cc
+++ b/third_party/blink/renderer/core/css/local_font_face_source.cc
@@ -33,9 +33,7 @@
                                          const String& font_name)
     : face_(css_font_face),
       font_selector_(font_selector),
-      font_name_(font_name),
-      weak_factory_(this) {
-}
+      font_name_(font_name) {}
 
 LocalFontFaceSource::~LocalFontFaceSource() {}
 
@@ -101,6 +99,9 @@
           unstyled_description, font_name_,
           AlternateFontName::kLocalUniqueFace);
   histograms_.Record(font_data.get());
+  if (font_data) {
+    LOG(ERROR) << "LOCAL FONT DATA CREATED FOR UNIQUE NAME: " << font_name_;
+  }
   return font_data;
 }
 
diff --git a/third_party/blink/renderer/core/css/local_font_face_source.h b/third_party/blink/renderer/core/css/local_font_face_source.h
index 2494e9fe..b96de2fc 100644
--- a/third_party/blink/renderer/core/css/local_font_face_source.h
+++ b/third_party/blink/renderer/core/css/local_font_face_source.h
@@ -75,7 +75,7 @@
 
   AtomicString font_name_;
   LocalFontHistograms histograms_;
-  base::WeakPtrFactory<LocalFontFaceSource> weak_factory_;
+  base::WeakPtrFactory<LocalFontFaceSource> weak_factory_{this};
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/media_values.cc b/third_party/blink/renderer/core/css/media_values.cc
index 260f7c6..c31ccf3 100644
--- a/third_party/blink/renderer/core/css/media_values.cc
+++ b/third_party/blink/renderer/core/css/media_values.cc
@@ -193,7 +193,8 @@
 ForcedColors MediaValues::CalculateForcedColors(LocalFrame* frame) {
   DCHECK(frame);
   DCHECK(frame->GetSettings());
-  return frame->GetSettings()->GetForcedColors();
+  DCHECK(frame->GetDocument());
+  return frame->GetDocument()->GetStyleEngine().GetForcedColors();
 }
 
 bool MediaValues::ComputeLengthImpl(double value,
diff --git a/third_party/blink/renderer/core/css/style_engine.cc b/third_party/blink/renderer/core/css/style_engine.cc
index 12011a64..5f88201 100644
--- a/third_party/blink/renderer/core/css/style_engine.cc
+++ b/third_party/blink/renderer/core/css/style_engine.cc
@@ -95,8 +95,10 @@
     global_rule_set_ = MakeGarbageCollected<CSSGlobalRuleSet>();
   // Document is initially style dirty.
   style_recalc_root_.Update(nullptr, &document);
-  if (auto* settings = GetDocument().GetSettings())
+  if (auto* settings = GetDocument().GetSettings()) {
     preferred_color_scheme_ = settings->GetPreferredColorScheme();
+    forced_colors_ = settings->GetForcedColors();
+  }
 }
 
 StyleEngine::~StyleEngine() = default;
@@ -1863,6 +1865,10 @@
 void StyleEngine::UpdateColorScheme() {
   auto* settings = GetDocument().GetSettings();
   DCHECK(settings);
+
+  ForcedColors old_forced_colors = forced_colors_;
+  forced_colors_ = settings->GetForcedColors();
+
   PreferredColorScheme old_preferred_color_scheme = preferred_color_scheme_;
   preferred_color_scheme_ = settings->GetPreferredColorScheme();
   bool use_dark_scheme =
@@ -1873,7 +1879,9 @@
     // darkening is enabled.
     preferred_color_scheme_ = PreferredColorScheme::kNoPreference;
   }
-  if (preferred_color_scheme_ != old_preferred_color_scheme)
+
+  if (forced_colors_ != old_forced_colors ||
+      preferred_color_scheme_ != old_preferred_color_scheme)
     PlatformColorsChanged();
   UpdateColorSchemeBackground();
 }
@@ -1898,7 +1906,8 @@
 
   bool use_dark_background = false;
 
-  if (preferred_color_scheme_ == PreferredColorScheme::kDark) {
+  if (preferred_color_scheme_ == PreferredColorScheme::kDark &&
+      forced_colors_ != ForcedColors::kActive) {
     const ComputedStyle* style = nullptr;
     if (auto* root_element = GetDocument().documentElement())
       style = root_element->GetComputedStyle();
diff --git a/third_party/blink/renderer/core/css/style_engine.h b/third_party/blink/renderer/core/css/style_engine.h
index 17ee2cf..9f1410d 100644
--- a/third_party/blink/renderer/core/css/style_engine.h
+++ b/third_party/blink/renderer/core/css/style_engine.h
@@ -33,6 +33,7 @@
 #include <memory>
 #include <utility>
 #include "base/auto_reset.h"
+#include "third_party/blink/public/common/css/forced_colors.h"
 #include "third_party/blink/public/common/css/preferred_color_scheme.h"
 #include "third_party/blink/public/web/web_document.h"
 #include "third_party/blink/renderer/core/core_export.h"
@@ -347,6 +348,7 @@
   PreferredColorScheme GetPreferredColorScheme() const {
     return preferred_color_scheme_;
   }
+  ForcedColors GetForcedColors() const { return forced_colors_; }
   void UpdateColorSchemeBackground();
 
   void Trace(blink::Visitor*) override;
@@ -551,11 +553,14 @@
   Member<const CSSValue> meta_color_scheme_;
 
   // The preferred color scheme is set in settings, but may be overridden by the
-  // ForceDarkMode setting where the preferred_color_scheme_ will be set no
+  // ForceDarkMode setting where the preferred_color_scheme_ will be set to
   // kNoPreference to avoid dark styling to be applied before auto darkening.
   PreferredColorScheme preferred_color_scheme_ =
       PreferredColorScheme::kNoPreference;
 
+  // Forced colors is set in settings.
+  ForcedColors forced_colors_ = ForcedColors::kNone;
+
   friend class NodeTest;
   friend class StyleEngineTest;
   friend class WhitespaceAttacherTest;
diff --git a/third_party/blink/renderer/core/dom/mutation_observer.cc b/third_party/blink/renderer/core/dom/mutation_observer.cc
index b280167..6405538 100644
--- a/third_party/blink/renderer/core/dom/mutation_observer.cc
+++ b/third_party/blink/renderer/core/dom/mutation_observer.cc
@@ -108,9 +108,7 @@
                   .NextObserverPriority();
 }
 
-MutationObserver::~MutationObserver() {
-  CancelInspectorAsyncTasks();
-}
+MutationObserver::~MutationObserver() = default;
 
 void MutationObserver::observe(Node* node,
                                const MutationObserverInit* observer_init,
diff --git a/third_party/blink/renderer/core/dom/mutation_observer.h b/third_party/blink/renderer/core/dom/mutation_observer.h
index 535f22e..48a0ac5 100644
--- a/third_party/blink/renderer/core/dom/mutation_observer.h
+++ b/third_party/blink/renderer/core/dom/mutation_observer.h
@@ -66,6 +66,8 @@
       public ContextClient {
   DEFINE_WRAPPERTYPEINFO();
   USING_GARBAGE_COLLECTED_MIXIN(MutationObserver);
+  // Using CancelInspectorAsyncTasks as pre-finalizer to cancel async tasks.
+  USING_PRE_FINALIZER(MutationObserver, CancelInspectorAsyncTasks);
 
  public:
   enum ObservationFlags { kSubtree = 1 << 3, kAttributeFilter = 1 << 4 };
@@ -110,8 +112,6 @@
 
   bool HasPendingActivity() const override { return !records_.IsEmpty(); }
 
-  // Eagerly finalized as destructor accesses heap object members.
-  EAGERLY_FINALIZE();
   void Trace(Visitor*) override;
 
   // Methods to be used by MutationObserverNotifier
diff --git a/third_party/blink/renderer/core/exported/web_shared_worker_impl.cc b/third_party/blink/renderer/core/exported/web_shared_worker_impl.cc
index 0b31406..d42b1d92 100644
--- a/third_party/blink/renderer/core/exported/web_shared_worker_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_shared_worker_impl.cc
@@ -87,8 +87,7 @@
       creation_address_space_(mojom::IPAddressSpace::kPublic),
       parent_execution_context_task_runners_(
           ParentExecutionContextTaskRunners::Create()),
-      appcache_host_id_(appcache_host_id),
-      weak_ptr_factory_(this) {
+      appcache_host_id_(appcache_host_id) {
   DCHECK(IsMainThread());
 }
 
diff --git a/third_party/blink/renderer/core/exported/web_shared_worker_impl.h b/third_party/blink/renderer/core/exported/web_shared_worker_impl.h
index 05d1ed7..e7bfc5e 100644
--- a/third_party/blink/renderer/core/exported/web_shared_worker_impl.h
+++ b/third_party/blink/renderer/core/exported/web_shared_worker_impl.h
@@ -171,7 +171,7 @@
       parent_execution_context_task_runners_;
   const base::UnguessableToken appcache_host_id_;
 
-  base::WeakPtrFactory<WebSharedWorkerImpl> weak_ptr_factory_;
+  base::WeakPtrFactory<WebSharedWorkerImpl> weak_ptr_factory_{this};
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/fileapi/file_reader_loader.cc b/third_party/blink/renderer/core/fileapi/file_reader_loader.cc
index 43ad834..7c6f949 100644
--- a/third_party/blink/renderer/core/fileapi/file_reader_loader.cc
+++ b/third_party/blink/renderer/core/fileapi/file_reader_loader.cc
@@ -76,8 +76,7 @@
           mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC,
           task_runner ? task_runner : base::SequencedTaskRunnerHandle::Get()),
       binding_(this),
-      task_runner_(std::move(task_runner)),
-      weak_factory_(this) {
+      task_runner_(std::move(task_runner)) {
   // TODO(https://crbug.com/957651): Change this into a DCHECK once we figured
   // out where code is passing in a null task runner,
   CHECK(task_runner_);
diff --git a/third_party/blink/renderer/core/fileapi/file_reader_loader.h b/third_party/blink/renderer/core/fileapi/file_reader_loader.h
index f486c79..d460a3f 100644
--- a/third_party/blink/renderer/core/fileapi/file_reader_loader.h
+++ b/third_party/blink/renderer/core/fileapi/file_reader_loader.h
@@ -185,7 +185,7 @@
 
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
-  base::WeakPtrFactory<FileReaderLoader> weak_factory_;
+  base::WeakPtrFactory<FileReaderLoader> weak_factory_{this};
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy_fuzzer.cc b/third_party/blink/renderer/core/frame/csp/content_security_policy_fuzzer.cc
index 61e3586..c296c95 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy_fuzzer.cc
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy_fuzzer.cc
@@ -23,6 +23,14 @@
   // that Oilpan be initialized to access blink::ThreadState::Current.
   LEAK_SANITIZER_DISABLED_SCOPE;
   g_page_holder = std::make_unique<DummyPageHolder>().release();
+
+  // Set loader sandbox flags and install a new document so the document
+  // has all possible sandbox flags set on the document already when the
+  // CSP is bound.
+  scoped_refptr<SharedBuffer> empty_document_data = SharedBuffer::Create();
+  g_page_holder->GetFrame().Loader().ForceSandboxFlags(WebSandboxFlags::kAll);
+  g_page_holder->GetFrame().ForceSynchronousDocumentInstall(
+      "text/html", empty_document_data);
   return 0;
 }
 
@@ -45,18 +53,6 @@
                         : kContentSecurityPolicyHeaderSourceOriginPolicy;
   }
 
-  // Set loader sandbox flags and install a new document so the document
-  // has all possible sandbox flags set on the document already when the
-  // CSP is bound. CSP from Meta tags sources shouldn't have sandbox flags
-  // so we set it to kNone.
-  scoped_refptr<SharedBuffer> empty_document_data = SharedBuffer::Create();
-  g_page_holder->GetFrame().Loader().ForceSandboxFlags(
-      header_source == kContentSecurityPolicyHeaderSourceMeta
-          ? WebSandboxFlags::kNone
-          : WebSandboxFlags::kAll);
-  g_page_holder->GetFrame().ForceSynchronousDocumentInstall(
-      "text/html", empty_document_data);
-
   // Construct and initialize a policy from the string.
   auto* csp = MakeGarbageCollected<ContentSecurityPolicy>();
   csp->DidReceiveHeader(header, header_type, header_source);
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 3ad1c16..12a131c 100644
--- a/third_party/blink/renderer/core/frame/frame_test_helpers.cc
+++ b/third_party/blink/renderer/core/frame/frame_test_helpers.cc
@@ -486,8 +486,7 @@
 
 TestWebFrameClient::TestWebFrameClient()
     : interface_provider_(new service_manager::InterfaceProvider()),
-      effective_connection_type_(WebEffectiveConnectionType::kTypeUnknown),
-      weak_factory_(this) {}
+      effective_connection_type_(WebEffectiveConnectionType::kTypeUnknown) {}
 
 void TestWebFrameClient::Bind(WebLocalFrame* frame,
                               std::unique_ptr<TestWebFrameClient> self_owned) {
diff --git a/third_party/blink/renderer/core/frame/frame_test_helpers.h b/third_party/blink/renderer/core/frame/frame_test_helpers.h
index 110455e..ccbc336 100644
--- a/third_party/blink/renderer/core/frame/frame_test_helpers.h
+++ b/third_party/blink/renderer/core/frame/frame_test_helpers.h
@@ -450,7 +450,7 @@
   WebEffectiveConnectionType effective_connection_type_;
   Vector<String> console_messages_;
 
-  base::WeakPtrFactory<TestWebFrameClient> weak_factory_;
+  base::WeakPtrFactory<TestWebFrameClient> weak_factory_{this};
 };
 
 // Minimal implementation of WebRemoteFrameClient needed for unit tests that
diff --git a/third_party/blink/renderer/core/frame/settings.json5 b/third_party/blink/renderer/core/frame/settings.json5
index 3806cba0..c92364f 100644
--- a/third_party/blink/renderer/core/frame/settings.json5
+++ b/third_party/blink/renderer/core/frame/settings.json5
@@ -1041,7 +1041,7 @@
     {
       name: "forcedColors",
       initial: "ForcedColors::kNone",
-      invalidate: "MediaQuery",
+      invalidate: "ColorScheme",
       type: "ForcedColors",
     },
   ],
diff --git a/third_party/blink/renderer/core/html/parser/background_html_parser.cc b/third_party/blink/renderer/core/html/parser/background_html_parser.cc
index e96292a62..99ef5b81 100644
--- a/third_party/blink/renderer/core/html/parser/background_html_parser.cc
+++ b/third_party/blink/renderer/core/html/parser/background_html_parser.cc
@@ -101,8 +101,7 @@
       loading_task_runner_(std::move(loading_task_runner)),
       pending_csp_meta_token_index_(
           HTMLDocumentParser::TokenizedChunk::kNoPendingToken),
-      starting_script_(false),
-      weak_factory_(this) {}
+      starting_script_(false) {}
 
 BackgroundHTMLParser::~BackgroundHTMLParser() = default;
 
diff --git a/third_party/blink/renderer/core/html/parser/background_html_parser.h b/third_party/blink/renderer/core/html/parser/background_html_parser.h
index 76b01e4..5b4fc4d 100644
--- a/third_party/blink/renderer/core/html/parser/background_html_parser.h
+++ b/third_party/blink/renderer/core/html/parser/background_html_parser.h
@@ -133,7 +133,7 @@
 
   bool starting_script_;
 
-  base::WeakPtrFactory<BackgroundHTMLParser> weak_factory_;
+  base::WeakPtrFactory<BackgroundHTMLParser> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(BackgroundHTMLParser);
 };
diff --git a/third_party/blink/renderer/core/html/parser/html_document_parser.cc b/third_party/blink/renderer/core/html/parser/html_document_parser.cc
index a1463f3..e60433b 100644
--- a/third_party/blink/renderer/core/html/parser/html_document_parser.cc
+++ b/third_party/blink/renderer/core/html/parser/html_document_parser.cc
@@ -153,8 +153,7 @@
       is_parsing_at_line_number_(false),
       tried_loading_link_headers_(false),
       added_pending_parser_blocking_stylesheet_(false),
-      is_waiting_for_stylesheets_(false),
-      weak_factory_(this) {
+      is_waiting_for_stylesheets_(false) {
   DCHECK(ShouldUseThreading() || (token_ && tokenizer_));
   // Threading is not allowed in prefetch mode.
   DCHECK(!document.IsPrefetchOnly() || !ShouldUseThreading());
diff --git a/third_party/blink/renderer/core/html/parser/html_document_parser.h b/third_party/blink/renderer/core/html/parser/html_document_parser.h
index eb38afe..878ef1a 100644
--- a/third_party/blink/renderer/core/html/parser/html_document_parser.h
+++ b/third_party/blink/renderer/core/html/parser/html_document_parser.h
@@ -271,7 +271,7 @@
   bool added_pending_parser_blocking_stylesheet_;
   bool is_waiting_for_stylesheets_;
 
-  base::WeakPtrFactory<HTMLDocumentParser> weak_factory_;
+  base::WeakPtrFactory<HTMLDocumentParser> weak_factory_{this};
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/image_loader.cc b/third_party/blink/renderer/core/loader/image_loader.cc
index 8ba1d7d9..ebfacde5 100644
--- a/third_party/blink/renderer/core/loader/image_loader.cc
+++ b/third_party/blink/renderer/core/loader/image_loader.cc
@@ -196,8 +196,7 @@
         should_bypass_main_world_csp_(ShouldBypassMainWorldCSP(loader)),
         update_behavior_(update_behavior),
         referrer_policy_(referrer_policy),
-        request_url_(request_url),
-        weak_factory_(this) {
+        request_url_(request_url) {
     ExecutionContext& context = loader_->GetElement()->GetDocument();
     probe::AsyncTaskScheduled(&context, "Image", this);
     v8::Isolate* isolate = V8PerIsolateData::MainThreadIsolate();
@@ -245,7 +244,7 @@
   WeakPersistent<ScriptState> script_state_;
   network::mojom::ReferrerPolicy referrer_policy_;
   KURL request_url_;
-  base::WeakPtrFactory<Task> weak_factory_;
+  base::WeakPtrFactory<Task> weak_factory_{this};
 };
 
 ImageLoader::ImageLoader(Element* element)
diff --git a/third_party/blink/renderer/core/loader/prefetched_signed_exchange_manager.cc b/third_party/blink/renderer/core/loader/prefetched_signed_exchange_manager.cc
index 082844f..8313c44 100644
--- a/third_party/blink/renderer/core/loader/prefetched_signed_exchange_manager.cc
+++ b/third_party/blink/renderer/core/loader/prefetched_signed_exchange_manager.cc
@@ -39,9 +39,7 @@
   PrefetchedSignedExchangeLoader(
       const WebURLRequest& request,
       scoped_refptr<base::SingleThreadTaskRunner> task_runner)
-      : request_(request),
-        task_runner_(std::move(task_runner)),
-        weak_ptr_factory_(this) {}
+      : request_(request), task_runner_(std::move(task_runner)) {}
 
   ~PrefetchedSignedExchangeLoader() override {}
 
@@ -119,7 +117,7 @@
   std::unique_ptr<WebURLLoader> url_loader_;
   std::queue<base::OnceClosure> pending_method_calls_;
 
-  base::WeakPtrFactory<PrefetchedSignedExchangeLoader> weak_ptr_factory_;
+  base::WeakPtrFactory<PrefetchedSignedExchangeLoader> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(PrefetchedSignedExchangeLoader);
 };
diff --git a/third_party/blink/renderer/core/page/context_menu_controller.cc b/third_party/blink/renderer/core/page/context_menu_controller.cc
index 548fa54..33b2840e 100644
--- a/third_party/blink/renderer/core/page/context_menu_controller.cc
+++ b/third_party/blink/renderer/core/page/context_menu_controller.cc
@@ -138,11 +138,6 @@
 
 static int ComputeEditFlags(Document& selected_document, Editor& editor) {
   int edit_flags = WebContextMenuData::kCanDoNone;
-  if (!selected_document.IsHTMLDocument() &&
-      !selected_document.IsXHTMLDocument())
-    return edit_flags;
-
-  edit_flags |= WebContextMenuData::kCanTranslate;
   if (editor.CanUndo())
     edit_flags |= WebContextMenuData::kCanUndo;
   if (editor.CanRedo())
@@ -157,8 +152,12 @@
     edit_flags |= WebContextMenuData::kCanDelete;
   if (editor.CanEditRichly())
     edit_flags |= WebContextMenuData::kCanEditRichly;
-  if (selected_document.queryCommandEnabled("selectAll", ASSERT_NO_EXCEPTION))
-    edit_flags |= WebContextMenuData::kCanSelectAll;
+  if (selected_document.IsHTMLDocument() ||
+      selected_document.IsXHTMLDocument()) {
+    edit_flags |= WebContextMenuData::kCanTranslate;
+    if (selected_document.queryCommandEnabled("selectAll", ASSERT_NO_EXCEPTION))
+      edit_flags |= WebContextMenuData::kCanSelectAll;
+  }
   return edit_flags;
 }
 
diff --git a/third_party/blink/renderer/core/page/context_menu_controller_test.cc b/third_party/blink/renderer/core/page/context_menu_controller_test.cc
index a7815a0f..1c840bb 100644
--- a/third_party/blink/renderer/core/page/context_menu_controller_test.cc
+++ b/third_party/blink/renderer/core/page/context_menu_controller_test.cc
@@ -9,6 +9,7 @@
 #include "third_party/blink/public/platform/web_media_stream_track.h"
 #include "third_party/blink/public/platform/web_menu_source_type.h"
 #include "third_party/blink/public/web/web_context_menu_data.h"
+#include "third_party/blink/renderer/core/editing/frame_selection.h"
 #include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
 #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
 #include "third_party/blink/renderer/core/geometry/dom_rect.h"
@@ -80,12 +81,24 @@
         .ShowContextMenu(GetDocument()->GetFrame(), location, source);
   }
 
+  bool ShowContextMenuForElement(Element* element, WebMenuSourceType source) {
+    const DOMRect* rect = element->getBoundingClientRect();
+    PhysicalOffset location(LayoutUnit((rect->left() + rect->right()) / 2),
+                            LayoutUnit((rect->top() + rect->bottom()) / 2));
+    ContextMenuAllowedScope context_menu_allowed_scope;
+    return ShowContextMenu(location, source);
+  }
+
   Document* GetDocument() {
     return static_cast<Document*>(
         web_view_helper_.LocalMainFrame()->GetDocument());
   }
 
   Page* GetPage() { return web_view_helper_.GetWebView()->GetPage(); }
+  WebLocalFrameImpl* LocalMainFrame() {
+    return web_view_helper_.LocalMainFrame();
+  }
+  void LoadAhem() { web_view_helper_.LoadAhem(); }
 
   const TestWebFrameClientImpl& GetWebFrameClient() const {
     return web_frame_client_;
@@ -456,4 +469,78 @@
   }
 }
 
+TEST_F(ContextMenuControllerTest, EditingActionsEnabledInSVGDocument) {
+  frame_test_helpers::LoadFrame(LocalMainFrame(), R"SVG(data:image/svg+xml,
+    <svg xmlns='http://www.w3.org/2000/svg'
+         xmlns:h='http://www.w3.org/1999/xhtml'
+         font-family='Ahem'>
+      <text y='20' id='t'>Copyable text</text>
+      <foreignObject y='30' width='100' height='200'>
+        <h:div id='e' style='width: 100px; height: 50px'
+               contenteditable='true'>
+          XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+        </h:div>
+      </foreignObject>
+    </svg>
+  )SVG");
+  LoadAhem();
+
+  Document* document = GetDocument();
+  ASSERT_TRUE(document->IsSVGDocument());
+
+  Element* text_element = document->getElementById("t");
+  document->UpdateStyleAndLayout();
+  FrameSelection& selection = document->GetFrame()->Selection();
+
+  // <text> element
+  selection.SelectSubString(*text_element, 4, 8);
+  EXPECT_TRUE(ShowContextMenuForElement(text_element, kMenuSourceMouse));
+
+  WebContextMenuData context_menu_data =
+      GetWebFrameClient().GetContextMenuData();
+  EXPECT_EQ(context_menu_data.media_type, WebContextMenuData::kMediaTypeNone);
+  EXPECT_EQ(context_menu_data.edit_flags, WebContextMenuData::kCanCopy);
+  EXPECT_EQ(context_menu_data.selected_text, "able tex");
+
+  // <div contenteditable=true>
+  Element* editable_element = document->getElementById("e");
+  selection.SelectSubString(*editable_element, 0, 42);
+  EXPECT_TRUE(ShowContextMenuForElement(editable_element, kMenuSourceMouse));
+
+  context_menu_data = GetWebFrameClient().GetContextMenuData();
+  EXPECT_EQ(context_menu_data.media_type, WebContextMenuData::kMediaTypeNone);
+  EXPECT_EQ(context_menu_data.edit_flags,
+            WebContextMenuData::kCanCut | WebContextMenuData::kCanCopy |
+                WebContextMenuData::kCanPaste | WebContextMenuData::kCanDelete |
+                WebContextMenuData::kCanEditRichly);
+}
+
+TEST_F(ContextMenuControllerTest, EditingActionsEnabledInXMLDocument) {
+  frame_test_helpers::LoadFrame(LocalMainFrame(), R"XML(data:text/xml,
+    <root>
+      <style xmlns="http://www.w3.org/1999/xhtml">
+        root { color: blue; }
+      </style>
+      <text id="t">Blue text</text>
+    </root>
+  )XML");
+
+  Document* document = GetDocument();
+  ASSERT_TRUE(document->IsXMLDocument());
+  ASSERT_FALSE(document->IsHTMLDocument());
+
+  Element* text_element = document->getElementById("t");
+  document->UpdateStyleAndLayout();
+  FrameSelection& selection = document->GetFrame()->Selection();
+
+  selection.SelectAll();
+  EXPECT_TRUE(ShowContextMenuForElement(text_element, kMenuSourceMouse));
+
+  WebContextMenuData context_menu_data =
+      GetWebFrameClient().GetContextMenuData();
+  EXPECT_EQ(context_menu_data.media_type, WebContextMenuData::kMediaTypeNone);
+  EXPECT_EQ(context_menu_data.edit_flags, WebContextMenuData::kCanCopy);
+  EXPECT_EQ(context_menu_data.selected_text, "Blue text");
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/workers/worker_animation_frame_provider.cc b/third_party/blink/renderer/core/workers/worker_animation_frame_provider.cc
index f24465f..094fe6c 100644
--- a/third_party/blink/renderer/core/workers/worker_animation_frame_provider.cc
+++ b/third_party/blink/renderer/core/workers/worker_animation_frame_provider.cc
@@ -18,8 +18,7 @@
           std::make_unique<BeginFrameProvider>(begin_frame_provider_params,
                                                this)),
       callback_collection_(context),
-      context_(context),
-      weak_factory_(this) {}
+      context_(context) {}
 
 int WorkerAnimationFrameProvider::RegisterCallback(
     FrameRequestCallbackCollection::FrameCallback* callback) {
diff --git a/third_party/blink/renderer/core/workers/worker_animation_frame_provider.h b/third_party/blink/renderer/core/workers/worker_animation_frame_provider.h
index 20628c3..b075b80 100644
--- a/third_party/blink/renderer/core/workers/worker_animation_frame_provider.h
+++ b/third_party/blink/renderer/core/workers/worker_animation_frame_provider.h
@@ -59,7 +59,7 @@
 
   Member<ExecutionContext> context_;
 
-  base::WeakPtrFactory<WorkerAnimationFrameProvider> weak_factory_;
+  base::WeakPtrFactory<WorkerAnimationFrameProvider> weak_factory_{this};
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/BUILD.gn b/third_party/blink/renderer/modules/BUILD.gn
index afb8575..6737a5e 100644
--- a/third_party/blink/renderer/modules/BUILD.gn
+++ b/third_party/blink/renderer/modules/BUILD.gn
@@ -130,6 +130,7 @@
     "//third_party/blink/renderer/modules/mediasession",
     "//third_party/blink/renderer/modules/mediasource",
     "//third_party/blink/renderer/modules/mediastream",
+    "//third_party/blink/renderer/modules/webrtc",
     "//third_party/blink/renderer/modules/native_file_system",
     "//third_party/blink/renderer/modules/navigatorcontentutils",
     "//third_party/blink/renderer/modules/netinfo",
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.cc b/third_party/blink/renderer/modules/accessibility/ax_object.cc
index 4482889..c8cc077 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_object.cc
@@ -1179,14 +1179,28 @@
   if (!GetNode())
     return false;
 
+  // If the node is part of the user agent shadow dom, or has the explicit
+  // internal Role::kIgnored, they aren't interesting for paragraph navigation
+  // or LabelledBy/DescribedBy relationships.
+  if (RoleValue() == ax::mojom::Role::kIgnored ||
+      GetNode()->IsInUserAgentShadowRoot()) {
+    return false;
+  }
+
   // Always pass through Line Breaking objects, this is necessary to
   // detect paragraph edges, which are defined as hard-line breaks.
-  //
-  // Though if the node is part of the shadow dom, or has the explicit
-  // internal Role::kIgnored, they aren't interesting for paragraph
-  // navigation so exclude those cases.
-  return RoleValue() != ax::mojom::Role::kIgnored &&
-         !GetNode()->IsInUserAgentShadowRoot() && IsLineBreakingObject();
+  if (IsLineBreakingObject())
+    return true;
+
+  // Allow the browser side ax tree to access "visibility: hidden" nodes. This
+  // is useful for APIs that return the node referenced by aria-labeledby and
+  // aria-descibedby
+  if (GetLayoutObject() &&
+      GetLayoutObject()->Style()->Visibility() == EVisibility::kHidden) {
+    return true;
+  }
+
+  return false;
 }
 
 const AXObject* AXObject::DatetimeAncestor(int max_levels_to_check) const {
@@ -1492,8 +1506,15 @@
                          AXObject::AXObjectVector* name_objects) const {
   HeapHashSet<Member<const AXObject>> visited;
   AXRelatedObjectVector related_objects;
-  String text = TextAlternative(false, false, visited, name_from,
-                                &related_objects, nullptr);
+  // For purposes of computing a text alternative, if an ignored node is
+  // included in the tree, assume that it is the target of aria-labelledby or
+  // aria-describedby, since we can't tell yet whether that's the case. If it
+  // isn't exposed, the AT will never see the name anyways.
+  bool hidden_and_ignored_but_included_in_tree =
+      IsHiddenForTextAlternativeCalculation() && AccessibilityIsIgnored() &&
+      AccessibilityIsIncludedInTree();
+  String text = TextAlternative(false, hidden_and_ignored_but_included_in_tree,
+                                visited, name_from, &related_objects, nullptr);
 
   ax::mojom::Role role = RoleValue();
   if (!GetNode() ||
@@ -1514,8 +1535,16 @@
   AXObjectSet visited;
   ax::mojom::NameFrom tmp_name_from;
   AXRelatedObjectVector tmp_related_objects;
-  String text = TextAlternative(false, false, visited, tmp_name_from,
-                                &tmp_related_objects, name_sources);
+  // For purposes of computing a text alternative, if an ignored node is
+  // included in the tree, assume that it is the target of aria-labelledby or
+  // aria-describedby, since we can't tell yet whether that's the case. If it
+  // isn't exposed, the AT will never see the name anyways.
+  bool hidden_and_ignored_but_included_in_tree =
+      IsHiddenForTextAlternativeCalculation() && AccessibilityIsIgnored() &&
+      AccessibilityIsIncludedInTree();
+  String text =
+      TextAlternative(false, hidden_and_ignored_but_included_in_tree, visited,
+                      tmp_name_from, &tmp_related_objects, name_sources);
   text = text.SimplifyWhiteSpace(IsHTMLSpace<UChar>);
   return text;
 }
diff --git a/third_party/blink/renderer/modules/imagecapture/image_capture_frame_grabber.cc b/third_party/blink/renderer/modules/imagecapture/image_capture_frame_grabber.cc
index 52577ee5..d609544 100644
--- a/third_party/blink/renderer/modules/imagecapture/image_capture_frame_grabber.cc
+++ b/third_party/blink/renderer/modules/imagecapture/image_capture_frame_grabber.cc
@@ -132,7 +132,7 @@
 }
 
 ImageCaptureFrameGrabber::ImageCaptureFrameGrabber()
-    : frame_grab_in_progress_(false), weak_factory_(this) {}
+    : frame_grab_in_progress_(false) {}
 
 ImageCaptureFrameGrabber::~ImageCaptureFrameGrabber() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
diff --git a/third_party/blink/renderer/modules/imagecapture/image_capture_frame_grabber.h b/third_party/blink/renderer/modules/imagecapture/image_capture_frame_grabber.h
index 5e0755f..f050a85 100644
--- a/third_party/blink/renderer/modules/imagecapture/image_capture_frame_grabber.h
+++ b/third_party/blink/renderer/modules/imagecapture/image_capture_frame_grabber.h
@@ -145,7 +145,7 @@
   bool frame_grab_in_progress_;
 
   THREAD_CHECKER(thread_checker_);
-  base::WeakPtrFactory<ImageCaptureFrameGrabber> weak_factory_;
+  base::WeakPtrFactory<ImageCaptureFrameGrabber> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(ImageCaptureFrameGrabber);
 };
diff --git a/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.cc b/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.cc
index 6b8e89b1..d0848d2 100644
--- a/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.cc
+++ b/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.cc
@@ -27,8 +27,7 @@
       used_prefetches_(0),
       pending_onsuccess_callbacks_(0),
       prefetch_amount_(kMinPrefetchAmount),
-      task_runner_(task_runner),
-      weak_factory_(this) {
+      task_runner_(task_runner) {
   cursor_.Bind(std::move(cursor_info), std::move(task_runner));
   IndexedDBDispatcher::RegisterCursor(this);
 }
diff --git a/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.h b/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.h
index e58f1d8..f31c8530 100644
--- a/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.h
+++ b/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.h
@@ -88,7 +88,7 @@
 
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
-  base::WeakPtrFactory<WebIDBCursorImpl> weak_factory_;
+  base::WeakPtrFactory<WebIDBCursorImpl> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(WebIDBCursorImpl);
 };
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.cc b/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.cc
index 0b8179a..9016eed 100644
--- a/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.cc
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.cc
@@ -106,7 +106,7 @@
  public:
   explicit CanvasCaptureHandlerDelegate(
       media::VideoCapturerSource::VideoCaptureDeliverFrameCB new_frame_callback)
-      : new_frame_callback_(new_frame_callback), weak_ptr_factory_(this) {
+      : new_frame_callback_(new_frame_callback) {
     DETACH_FROM_THREAD(io_thread_checker_);
   }
   ~CanvasCaptureHandlerDelegate() {
@@ -128,7 +128,7 @@
       new_frame_callback_;
   // Bound to IO thread.
   THREAD_CHECKER(io_thread_checker_);
-  base::WeakPtrFactory<CanvasCaptureHandlerDelegate> weak_ptr_factory_;
+  base::WeakPtrFactory<CanvasCaptureHandlerDelegate> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(CanvasCaptureHandlerDelegate);
 };
@@ -138,9 +138,7 @@
     double frame_rate,
     scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
     blink::WebMediaStreamTrack* track)
-    : ask_for_new_frame_(false),
-      io_task_runner_(std::move(io_task_runner)),
-      weak_ptr_factory_(this) {
+    : ask_for_new_frame_(false), io_task_runner_(std::move(io_task_runner)) {
   std::unique_ptr<media::VideoCapturerSource> video_source(
       new VideoCapturerSource(weak_ptr_factory_.GetWeakPtr(), size,
                               frame_rate));
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.h b/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.h
index ec93dea..85c6a3bb 100644
--- a/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.h
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.h
@@ -120,7 +120,7 @@
 
   // Bound to Main Render thread.
   THREAD_CHECKER(main_render_thread_checker_);
-  base::WeakPtrFactory<CanvasCaptureHandler> weak_ptr_factory_;
+  base::WeakPtrFactory<CanvasCaptureHandler> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(CanvasCaptureHandler);
 };
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/html_audio_element_capturer_source.cc b/third_party/blink/renderer/modules/mediacapturefromelement/html_audio_element_capturer_source.cc
index 2998370..c6a0599 100644
--- a/third_party/blink/renderer/modules/mediacapturefromelement/html_audio_element_capturer_source.cc
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/html_audio_element_capturer_source.cc
@@ -35,8 +35,7 @@
       is_started_(false),
       last_sample_rate_(0),
       last_num_channels_(0),
-      last_bus_frames_(0),
-      weak_factory_(this) {
+      last_bus_frames_(0) {
   DCHECK(audio_source_);
 }
 
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/html_audio_element_capturer_source.h b/third_party/blink/renderer/modules/mediacapturefromelement/html_audio_element_capturer_source.h
index 74e3f46..59bf426e 100644
--- a/third_party/blink/renderer/modules/mediacapturefromelement/html_audio_element_capturer_source.h
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/html_audio_element_capturer_source.h
@@ -59,7 +59,7 @@
 
   THREAD_CHECKER(thread_checker_);
 
-  base::WeakPtrFactory<HtmlAudioElementCapturerSource> weak_factory_;
+  base::WeakPtrFactory<HtmlAudioElementCapturerSource> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(HtmlAudioElementCapturerSource);
 };
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 d2a8051..8f7d836 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
@@ -51,8 +51,7 @@
       io_task_runner_(io_task_runner),
       task_runner_(task_runner),
       is_opaque_(player->IsOpaque()),
-      capture_frame_rate_(0.0),
-      weak_factory_(this) {
+      capture_frame_rate_(0.0) {
   DCHECK(web_media_player_);
 }
 
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.h b/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.h
index a9ead5d..2ba1532 100644
--- a/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.h
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.h
@@ -86,7 +86,7 @@
   THREAD_CHECKER(thread_checker_);
 
   // Used on main render thread to schedule future capture events.
-  base::WeakPtrFactory<HtmlVideoElementCapturerSource> weak_factory_;
+  base::WeakPtrFactory<HtmlVideoElementCapturerSource> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(HtmlVideoElementCapturerSource);
 };
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source_unittest.cc b/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source_unittest.cc
index 99784b41..c2c1bb06 100644
--- a/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source_unittest.cc
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source_unittest.cc
@@ -40,7 +40,7 @@
 // An almost empty WebMediaPlayer to override paint() method.
 class MockWebMediaPlayer : public WebMediaPlayer {
  public:
-  MockWebMediaPlayer() : weak_factory_(this) {}
+  MockWebMediaPlayer() {}
   ~MockWebMediaPlayer() override = default;
 
   LoadTiming Load(LoadType, const WebMediaPlayerSource&, CorsMode) override {
@@ -99,7 +99,7 @@
 
   bool is_video_opaque_ = true;
 
-  base::WeakPtrFactory<MockWebMediaPlayer> weak_factory_;
+  base::WeakPtrFactory<MockWebMediaPlayer> weak_factory_{this};
 };
 
 }  // namespace
diff --git a/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc b/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
index 8091117..9b6f963 100644
--- a/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
+++ b/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
@@ -173,7 +173,7 @@
              : profile->value;
 }
 
-VideoTrackRecorder::Counter::Counter() : count_(0u), weak_factory_(this) {}
+VideoTrackRecorder::Counter::Counter() : count_(0u) {}
 
 VideoTrackRecorder::Counter::~Counter() = default;
 
@@ -436,8 +436,7 @@
     scoped_refptr<base::SingleThreadTaskRunner> main_task_runner)
     : track_(track),
       should_pause_encoder_on_initialization_(false),
-      main_task_runner_(std::move(main_task_runner)),
-      weak_ptr_factory_(this) {
+      main_task_runner_(std::move(main_task_runner)) {
   DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
   DCHECK(track_);
   DCHECK(track_->Source()->GetType() == MediaStreamSource::kTypeVideo);
diff --git a/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.h b/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.h
index 189b3a5..ae8c208 100644
--- a/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.h
+++ b/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.h
@@ -115,7 +115,7 @@
 
    private:
     uint32_t count_;
-    base::WeakPtrFactory<Counter> weak_factory_;
+    base::WeakPtrFactory<Counter> weak_factory_{this};
   };
 
   // Base class to describe a generic Encoder, encapsulating all actual encoder
@@ -317,7 +317,7 @@
 
   scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
 
-  base::WeakPtrFactory<VideoTrackRecorder> weak_ptr_factory_;
+  base::WeakPtrFactory<VideoTrackRecorder> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(VideoTrackRecorder);
 };
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_renderer_sink.cc b/third_party/blink/renderer/modules/mediastream/media_stream_video_renderer_sink.cc
index f74cc35..6694077 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_renderer_sink.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_renderer_sink.cc
@@ -137,8 +137,7 @@
     : repaint_cb_(repaint_cb),
       video_track_(video_track),
       io_task_runner_(std::move(io_task_runner)),
-      main_render_task_runner_(std::move(main_render_task_runner)),
-      weak_factory_(this) {}
+      main_render_task_runner_(std::move(main_render_task_runner)) {}
 
 MediaStreamVideoRendererSink::~MediaStreamVideoRendererSink() {
   DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_source.cc b/third_party/blink/renderer/modules/mediastream/media_stream_video_source.cc
index 36ae4b2f..ae753a97 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_source.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_source.cc
@@ -35,8 +35,7 @@
   return static_cast<MediaStreamVideoSource*>(source.GetPlatformSource());
 }
 
-MediaStreamVideoSource::MediaStreamVideoSource()
-    : state_(NEW), weak_factory_(this) {
+MediaStreamVideoSource::MediaStreamVideoSource() : state_(NEW) {
   track_adapter_ = base::MakeRefCounted<VideoTrackAdapter>(
       Platform::Current()->GetIOTaskRunner(), GetWeakPtr());
 }
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_track.cc b/third_party/blink/renderer/modules/mediastream/media_stream_video_track.cc
index 066c7b61..054f7fc7 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_track.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_track.cc
@@ -309,8 +309,7 @@
       adapter_settings_(std::make_unique<VideoTrackAdapterSettings>(
           VideoTrackAdapterSettings())),
       is_screencast_(false),
-      source_(source->GetWeakPtr()),
-      weak_factory_(this) {
+      source_(source->GetWeakPtr()) {
   frame_deliverer_ =
       base::MakeRefCounted<MediaStreamVideoTrack::FrameDeliverer>(
           source->io_task_runner(), weak_factory_.GetWeakPtr(), enabled);
@@ -341,8 +340,7 @@
       noise_reduction_(noise_reduction),
       is_screencast_(is_screen_cast),
       min_frame_rate_(min_frame_rate),
-      source_(source->GetWeakPtr()),
-      weak_factory_(this) {
+      source_(source->GetWeakPtr()) {
   frame_deliverer_ =
       base::MakeRefCounted<MediaStreamVideoTrack::FrameDeliverer>(
           source->io_task_runner(), weak_factory_.GetWeakPtr(), enabled);
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.cc b/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.cc
index 2195a46c..b235aaa2 100644
--- a/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.cc
+++ b/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.cc
@@ -25,8 +25,7 @@
       feature_handle_for_scheduler_(frame.GetFrameScheduler()->RegisterFeature(
           SchedulingPolicy::Feature::kWebRTC,
           {SchedulingPolicy::DisableAggressiveThrottling(),
-           SchedulingPolicy::RecordMetricsForBackForwardCache()})),
-      weak_ptr_factory_(this) {
+           SchedulingPolicy::RecordMetricsForBackForwardCache()})) {
   DCHECK(host_thread_);
   DCHECK(delegate_);
   DCHECK(adapter_factory);
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.h b/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.h
index f8f0814..8b88267 100644
--- a/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.h
+++ b/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.h
@@ -121,7 +121,7 @@
   THREAD_CHECKER(thread_checker_);
 
   // Must be the last member.
-  base::WeakPtrFactory<IceTransportProxy> weak_ptr_factory_;
+  base::WeakPtrFactory<IceTransportProxy> weak_ptr_factory_{this};
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.cc b/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.cc
index 6f2d4d38..8c10789 100644
--- a/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.cc
+++ b/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.cc
@@ -25,8 +25,7 @@
     : host_(nullptr,
             base::OnTaskRunnerDeleter(ice_transport_proxy->host_thread())),
       delegate_(delegate),
-      ice_transport_proxy_(ice_transport_proxy),
-      weak_ptr_factory_(this) {
+      ice_transport_proxy_(ice_transport_proxy) {
   DCHECK(delegate_);
   DCHECK(ice_transport_proxy_);
   scoped_refptr<base::SingleThreadTaskRunner> proxy_thread =
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.h b/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.h
index a508b7d1..fd33e8a 100644
--- a/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.h
+++ b/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.h
@@ -119,7 +119,7 @@
   THREAD_CHECKER(thread_checker_);
 
   // Must be the last member.
-  base::WeakPtrFactory<QuicTransportProxy> weak_ptr_factory_;
+  base::WeakPtrFactory<QuicTransportProxy> weak_ptr_factory_{this};
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager.cc b/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager.cc
index d44416b9..65afcd6 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager.cc
@@ -175,8 +175,7 @@
   Internal(scoped_refptr<ThreadSafeScriptContainer> script_container,
            scoped_refptr<base::SingleThreadTaskRunner> task_runner)
       : script_container_(std::move(script_container)),
-        task_runner_(std::move(task_runner)),
-        weak_factory_(this) {}
+        task_runner_(std::move(task_runner)) {}
 
   ~Internal() override {
     DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
@@ -233,7 +232,7 @@
   HashMap<KURL, std::unique_ptr<BundledReceivers>> running_receivers_;
   scoped_refptr<ThreadSafeScriptContainer> script_container_;
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-  base::WeakPtrFactory<Internal> weak_factory_;
+  base::WeakPtrFactory<Internal> weak_factory_{this};
 };
 
 std::unique_ptr<TracedValue> UrlToTracedValue(const KURL& url) {
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_timeout_timer.cc b/third_party/blink/renderer/modules/service_worker/service_worker_timeout_timer.cc
index 24d711b..cd504d0 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_timeout_timer.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_timeout_timer.cc
@@ -58,9 +58,7 @@
 ServiceWorkerTimeoutTimer::ServiceWorkerTimeoutTimer(
     base::RepeatingClosure idle_callback,
     const base::TickClock* tick_clock)
-    : idle_callback_(std::move(idle_callback)),
-      tick_clock_(tick_clock),
-      weak_factory_(this) {}
+    : idle_callback_(std::move(idle_callback)), tick_clock_(tick_clock) {}
 
 ServiceWorkerTimeoutTimer::~ServiceWorkerTimeoutTimer() {
   in_dtor_ = true;
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_timeout_timer.h b/third_party/blink/renderer/modules/service_worker/service_worker_timeout_timer.h
index e4f780f..257a1df5 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_timeout_timer.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_timeout_timer.h
@@ -192,7 +192,7 @@
 
   bool in_dtor_ = false;
 
-  base::WeakPtrFactory<ServiceWorkerTimeoutTimer> weak_factory_;
+  base::WeakPtrFactory<ServiceWorkerTimeoutTimer> weak_factory_{this};
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_timeout_timer_test.cc b/third_party/blink/renderer/modules/service_worker/service_worker_timeout_timer_test.cc
index 185a6eed..18119664 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_timeout_timer_test.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_timeout_timer_test.cc
@@ -19,7 +19,7 @@
 
 class MockEvent {
  public:
-  MockEvent() : weak_factory_(this) {}
+  MockEvent() {}
 
   ServiceWorkerTimeoutTimer::AbortCallback CreateAbortCallback() {
     return WTF::Bind(&MockEvent::Abort, weak_factory_.GetWeakPtr());
@@ -40,7 +40,7 @@
 
   int event_id_ = 0;
   base::Optional<mojom::blink::ServiceWorkerEventStatus> status_;
-  base::WeakPtrFactory<MockEvent> weak_factory_;
+  base::WeakPtrFactory<MockEvent> weak_factory_{this};
 };
 
 base::RepeatingClosure CreateReceiverWithCalledFlag(bool* out_is_called) {
diff --git a/third_party/blink/renderer/modules/storage/cached_storage_area.cc b/third_party/blink/renderer/modules/storage/cached_storage_area.cc
index 980bb8d..4b976b7 100644
--- a/third_party/blink/renderer/modules/storage/cached_storage_area.cc
+++ b/third_party/blink/renderer/modules/storage/cached_storage_area.cc
@@ -236,8 +236,7 @@
       mojo_area_(area.get()),
       mojo_area_ptr_(std::move(area)),
       binding_(this),
-      areas_(MakeGarbageCollected<HeapHashMap<WeakMember<Source>, String>>()),
-      weak_factory_(this) {
+      areas_(MakeGarbageCollected<HeapHashMap<WeakMember<Source>, String>>()) {
   mojom::blink::StorageAreaObserverAssociatedPtrInfo ptr_info;
   binding_.Bind(mojo::MakeRequest(&ptr_info), std::move(ipc_runner));
   mojo_area_->AddObserver(std::move(ptr_info));
@@ -258,8 +257,7 @@
       mojo_area_(area.get()),
       mojo_area_associated_ptr_(std::move(area)),
       binding_(this),
-      areas_(MakeGarbageCollected<HeapHashMap<WeakMember<Source>, String>>()),
-      weak_factory_(this) {
+      areas_(MakeGarbageCollected<HeapHashMap<WeakMember<Source>, String>>()) {
   mojom::blink::StorageAreaObserverAssociatedPtrInfo ptr_info;
   binding_.Bind(mojo::MakeRequest(&ptr_info), std::move(ipc_runner));
   mojo_area_->AddObserver(std::move(ptr_info));
diff --git a/third_party/blink/renderer/modules/storage/cached_storage_area.h b/third_party/blink/renderer/modules/storage/cached_storage_area.h
index cb72f50f..904a7c81 100644
--- a/third_party/blink/renderer/modules/storage/cached_storage_area.h
+++ b/third_party/blink/renderer/modules/storage/cached_storage_area.h
@@ -189,7 +189,7 @@
 
   Persistent<HeapHashMap<WeakMember<Source>, String>> areas_;
 
-  base::WeakPtrFactory<CachedStorageArea> weak_factory_;
+  base::WeakPtrFactory<CachedStorageArea> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(CachedStorageArea);
 };
diff --git a/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc b/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc
index d0681e3..3ecc2ab 100644
--- a/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc
+++ b/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc
@@ -498,7 +498,7 @@
     return DAWN_ADDRESS_MODE_REPEAT;
   }
   if (webgpu_enum == "mirror-repeat") {
-    return DAWN_ADDRESS_MODE_MIRRORED_REPEAT;
+    return DAWN_ADDRESS_MODE_MIRROR_REPEAT;
   }
   NOTREACHED();
   return DAWN_ADDRESS_MODE_FORCE32;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.cc b/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.cc
index 79a918eb..d69b9950 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.cc
@@ -80,8 +80,8 @@
   DawnTextureCopyView dawn_view;
   dawn_view.nextInChain = nullptr;
   dawn_view.texture = webgpu_view->texture()->GetHandle();
-  dawn_view.level = webgpu_view->mipLevel();
-  dawn_view.slice = webgpu_view->arrayLayer();
+  dawn_view.mipLevel = webgpu_view->mipLevel();
+  dawn_view.arrayLayer = webgpu_view->arrayLayer();
   dawn_view.origin = AsDawnType(webgpu_view->origin());
 
   return dawn_view;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_sampler.cc b/third_party/blink/renderer/modules/webgpu/gpu_sampler.cc
index 80cc70f..092b726 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_sampler.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_sampler.cc
@@ -29,7 +29,7 @@
       AsDawnEnum<DawnFilterMode>(webgpu_desc->mipmapFilter());
   dawn_desc.lodMinClamp = webgpu_desc->lodMinClamp();
   dawn_desc.lodMaxClamp = webgpu_desc->lodMaxClamp();
-  dawn_desc.compareFunction =
+  dawn_desc.compare =
       AsDawnEnum<DawnCompareFunction>(webgpu_desc->compareFunction());
 
   return dawn_desc;
diff --git a/third_party/blink/renderer/modules/webrtc/BUILD.gn b/third_party/blink/renderer/modules/webrtc/BUILD.gn
new file mode 100644
index 0000000..9d3df17
--- /dev/null
+++ b/third_party/blink/renderer/modules/webrtc/BUILD.gn
@@ -0,0 +1,12 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/jumbo.gni")
+import("//third_party/blink/renderer/modules/modules.gni")
+
+blink_modules_sources("webrtc") {
+  sources = [
+    "webrtc_audio_renderer.cc",
+  ]
+}
diff --git a/third_party/blink/renderer/modules/webrtc/DEPS b/third_party/blink/renderer/modules/webrtc/DEPS
new file mode 100644
index 0000000..96b8016
--- /dev/null
+++ b/third_party/blink/renderer/modules/webrtc/DEPS
@@ -0,0 +1,8 @@
+include_rules = [
+    "+base/strings/stringprintf.h",
+    "+media/audio/audio_sink_parameters.h",
+    "+media/base/audio_capturer_source.h",
+    "+media/base/audio_latency.h",
+    "+media/base/audio_parameters.h",
+    "+media/base/sample_rates.h",
+]
diff --git a/content/renderer/media/webrtc/webrtc_audio_renderer.cc b/third_party/blink/renderer/modules/webrtc/webrtc_audio_renderer.cc
similarity index 82%
rename from content/renderer/media/webrtc/webrtc_audio_renderer.cc
rename to third_party/blink/renderer/modules/webrtc/webrtc_audio_renderer.cc
index c7278b9b..32a2022 100644
--- a/content/renderer/media/webrtc/webrtc_audio_renderer.cc
+++ b/third_party/blink/renderer/modules/webrtc/webrtc_audio_renderer.cc
@@ -2,21 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/renderer/media/webrtc/webrtc_audio_renderer.h"
+#include "third_party/blink/public/web/modules/webrtc/webrtc_audio_renderer.h"
 
 #include <utility>
 
-#include "base/bind.h"
-#include "base/bind_helpers.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/stl_util.h"
-#include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread_checker.h"
 #include "build/build_config.h"
-#include "content/renderer/media/audio/audio_device_factory.h"
+#include "media/audio/audio_sink_parameters.h"
 #include "media/base/audio_capturer_source.h"
 #include "media/base/audio_latency.h"
 #include "media/base/audio_parameters.h"
@@ -24,10 +20,26 @@
 #include "third_party/blink/public/platform/modules/mediastream/media_stream_audio_track.h"
 #include "third_party/blink/public/platform/modules/webrtc/peer_connection_remote_audio_source.h"
 #include "third_party/blink/public/platform/modules/webrtc/webrtc_logging.h"
+#include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/web_media_stream_track.h"
+#include "third_party/blink/public/web/web_local_frame.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
+#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
 #include "third_party/webrtc/api/media_stream_interface.h"
 
-namespace content {
+namespace WTF {
+
+template <typename T>
+struct CrossThreadCopier<rtc::scoped_refptr<T>> {
+  STATIC_ONLY(CrossThreadCopier);
+  using Type = rtc::scoped_refptr<T>;
+  static Type Copy(Type pointer) { return pointer; }
+};
+
+}  // namespace WTF
+
+namespace blink {
 
 namespace {
 
@@ -46,12 +58,12 @@
 // and 'started' states to avoid problems related to incorrect usage which
 // might violate the implementation assumptions inside WebRtcAudioRenderer
 // (see the play reference count).
-class SharedAudioRenderer : public blink::WebMediaStreamAudioRenderer {
+class SharedAudioRenderer : public WebMediaStreamAudioRenderer {
  public:
   // Callback definition for a callback that is called when when Play(), Pause()
   // or SetVolume are called (whenever the internal |playing_state_| changes).
   using OnPlayStateChanged =
-      base::RepeatingCallback<void(const blink::WebMediaStream&,
+      base::RepeatingCallback<void(const WebMediaStream&,
                                    WebRtcAudioRenderer::PlayingState*)>;
 
   // Signals that the PlayingState* is about to become invalid, see comment in
@@ -60,8 +72,8 @@
       base::OnceCallback<void(WebRtcAudioRenderer::PlayingState*)>;
 
   SharedAudioRenderer(
-      const scoped_refptr<blink::WebMediaStreamAudioRenderer>& delegate,
-      const blink::WebMediaStream& media_stream,
+      const scoped_refptr<WebMediaStreamAudioRenderer>& delegate,
+      const WebMediaStream& media_stream,
       const OnPlayStateChanged& on_play_state_changed,
       OnPlayStateRemoved on_play_state_removed)
       : delegate_(delegate),
@@ -139,8 +151,8 @@
 
  private:
   THREAD_CHECKER(thread_checker_);
-  const scoped_refptr<blink::WebMediaStreamAudioRenderer> delegate_;
-  const blink::WebMediaStream media_stream_;
+  const scoped_refptr<WebMediaStreamAudioRenderer> delegate_;
+  const WebMediaStream media_stream_;
   bool started_;
   WebRtcAudioRenderer::PlayingState playing_state_;
   OnPlayStateChanged on_play_state_changed_;
@@ -149,14 +161,33 @@
 
 }  // namespace
 
+class WebRtcAudioRenderer::InternalFrame {
+ public:
+  explicit InternalFrame(WebLocalFrame* web_frame)
+      : frame_(web_frame ? static_cast<LocalFrame*>(
+                               WebLocalFrame::ToCoreFrame(*web_frame))
+                         : nullptr) {}
+
+  LocalFrame* frame() { return frame_.Get(); }
+  WebLocalFrame* web_frame() {
+    if (!frame_)
+      return nullptr;
+
+    return static_cast<WebLocalFrame*>(WebFrame::FromFrame(frame()));
+  }
+
+ private:
+  WeakPersistent<LocalFrame> frame_;
+};
+
 WebRtcAudioRenderer::WebRtcAudioRenderer(
     const scoped_refptr<base::SingleThreadTaskRunner>& signaling_thread,
-    const blink::WebMediaStream& media_stream,
-    int source_render_frame_id,
+    const WebMediaStream& media_stream,
+    WebLocalFrame* web_frame,
     int session_id,
     const std::string& device_id)
     : state_(UNINITIALIZED),
-      source_render_frame_id_(source_render_frame_id),
+      source_internal_frame_(std::make_unique<InternalFrame>(web_frame)),
       session_id_(session_id),
       signaling_thread_(signaling_thread),
       media_stream_(media_stream),
@@ -165,9 +196,8 @@
       start_ref_count_(0),
       sink_params_(kFormat, kChannelLayout, 0, 0),
       output_device_id_(device_id) {
-  blink::WebRtcLogMessage(base::StringPrintf(
-      "WAR::WAR. source_render_frame_id=%d, session_id=%d, effects=%i",
-      source_render_frame_id, session_id, sink_params_.effects()));
+  WebRtcLogMessage(base::StringPrintf("WAR::WAR. session_id=%d, effects=%i",
+                                      session_id, sink_params_.effects()));
 }
 
 WebRtcAudioRenderer::~WebRtcAudioRenderer() {
@@ -189,8 +219,8 @@
 
   media::AudioSinkParameters sink_params(session_id_, output_device_id_);
   sink_params.processing_id = source->GetAudioProcessingId();
-  sink_ = AudioDeviceFactory::NewAudioRendererSink(
-      blink::WebAudioDeviceSourceType::kWebRtc, source_render_frame_id_,
+  sink_ = Platform::Current()->NewAudioRendererSink(
+      WebAudioDeviceSourceType::kWebRtc, source_internal_frame_->web_frame(),
       sink_params);
 
   media::OutputDeviceStatus sink_status =
@@ -219,13 +249,15 @@
   return true;
 }
 
-scoped_refptr<blink::WebMediaStreamAudioRenderer>
+scoped_refptr<WebMediaStreamAudioRenderer>
 WebRtcAudioRenderer::CreateSharedAudioRendererProxy(
-    const blink::WebMediaStream& media_stream) {
+    const WebMediaStream& media_stream) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   SharedAudioRenderer::OnPlayStateChanged on_play_state_changed =
-      base::BindRepeating(&WebRtcAudioRenderer::OnPlayStateChanged, this);
+      WTF::BindRepeating(&WebRtcAudioRenderer::OnPlayStateChanged,
+                         WrapRefCounted(this));
   SharedAudioRenderer::OnPlayStateRemoved on_play_state_removed =
-      base::BindOnce(&WebRtcAudioRenderer::OnPlayStateRemoved, this);
+      WTF::Bind(&WebRtcAudioRenderer::OnPlayStateRemoved, WrapRefCounted(this));
   return new SharedAudioRenderer(this, media_stream,
                                  std::move(on_play_state_changed),
                                  std::move(on_play_state_removed));
@@ -329,7 +361,7 @@
   if (!max_render_time_.is_zero()) {
     UMA_HISTOGRAM_CUSTOM_COUNTS(
         "Media.Audio.Render.GetSourceDataTimeMax.WebRTC",
-        max_render_time_.InMicroseconds(),
+        static_cast<int>(max_render_time_.InMicroseconds()),
         kRenderTimeHistogramMinMicroseconds,
         kRenderTimeHistogramMaxMicroseconds, 50);
     max_render_time_ = base::TimeDelta();
@@ -378,9 +410,9 @@
   media::AudioSinkParameters sink_params(session_id_, device_id);
   sink_params.processing_id = source_->GetAudioProcessingId();
   scoped_refptr<media::AudioRendererSink> new_sink =
-      AudioDeviceFactory::NewAudioRendererSink(
-          blink::WebAudioDeviceSourceType::kWebRtc, source_render_frame_id_,
-          sink_params);
+      Platform::Current()->NewAudioRendererSink(
+          WebAudioDeviceSourceType::kWebRtc,
+          source_internal_frame_->web_frame(), sink_params);
   media::OutputDeviceStatus status =
       new_sink->GetOutputDeviceInfo().device_status();
   UMA_HISTOGRAM_ENUMERATION(
@@ -433,8 +465,9 @@
     if (!audio_fifo_ && prior_frames_skipped != source_frames_per_buffer) {
       audio_fifo_ = std::make_unique<media::AudioPullFifo>(
           kChannels, source_frames_per_buffer,
-          base::BindRepeating(&WebRtcAudioRenderer::SourceCallback,
-                              base::Unretained(this)));
+          ConvertToBaseCallback(
+              CrossThreadBindRepeating(&WebRtcAudioRenderer::SourceCallback,
+                                       CrossThreadUnretained(this))));
     }
 
     std::unique_ptr<media::AudioBus> drop_bus =
@@ -460,15 +493,15 @@
 }
 
 // Called by AudioPullFifo when more data is necessary.
-void WebRtcAudioRenderer::SourceCallback(
-    int fifo_frame_delay, media::AudioBus* audio_bus) {
+void WebRtcAudioRenderer::SourceCallback(int fifo_frame_delay,
+                                         media::AudioBus* audio_bus) {
   DCHECK(sink_->CurrentThreadIsRenderingThread());
   base::TimeTicks start_time = base::TimeTicks::Now();
-  DVLOG(2) << "WebRtcAudioRenderer::SourceCallback("
-           << fifo_frame_delay << ", "
+  DVLOG(2) << "WebRtcAudioRenderer::SourceCallback(" << fifo_frame_delay << ", "
            << audio_bus->frames() << ")";
 
-  int output_delay_milliseconds = audio_delay_.InMilliseconds();
+  int output_delay_milliseconds =
+      static_cast<int>(audio_delay_.InMilliseconds());
   // TODO(grunell): This integer division by sample_rate will cause loss of
   // partial milliseconds, and may cause avsync drift. http://crbug.com/586540
   output_delay_milliseconds += fifo_frame_delay *
@@ -479,8 +512,7 @@
   // We need to keep render data for the |source_| regardless of |state_|,
   // otherwise the data will be buffered up inside |source_|.
   source_->RenderData(audio_bus, sink_params_.sample_rate(),
-                      output_delay_milliseconds,
-                      &current_time_);
+                      output_delay_milliseconds, &current_time_);
 
   // Avoid filling up the audio bus if we are not playing; instead
   // return here and ensure that the returned value in Render() is 0.
@@ -492,7 +524,7 @@
   if (base::TimeTicks::IsHighResolution()) {
     base::TimeDelta elapsed = base::TimeTicks::Now() - start_time;
     UMA_HISTOGRAM_CUSTOM_COUNTS("Media.Audio.Render.GetSourceDataTime.WebRTC",
-                                elapsed.InMicroseconds(),
+                                static_cast<int>(elapsed.InMicroseconds()),
                                 kRenderTimeHistogramMinMicroseconds,
                                 kRenderTimeHistogramMaxMicroseconds, 50);
 
@@ -512,8 +544,8 @@
   auto entry = source_playing_states_.find(source);
   if (entry != source_playing_states_.end()) {
     PlayingStates& states = entry->second;
-    for (PlayingStates::const_iterator it = states.begin();
-         it != states.end(); ++it) {
+    for (PlayingStates::const_iterator it = states.begin(); it != states.end();
+         ++it) {
       if ((*it)->playing())
         volume += (*it)->volume();
     }
@@ -530,19 +562,18 @@
     // Libjingle hands out proxy objects in most cases, but the audio source
     // object is an exception (bug?).  So, to work around that, we need to make
     // sure we call SetVolume on the signaling thread.
-    signaling_thread_->PostTask(
-        FROM_HERE,
-        base::BindOnce(&webrtc::AudioSourceInterface::SetVolume,
-                       rtc::scoped_refptr<webrtc::AudioSourceInterface>(source),
-                       volume));
+    PostCrossThreadTask(
+        *signaling_thread_, FROM_HERE,
+        CrossThreadBindOnce(
+            &webrtc::AudioSourceInterface::SetVolume,
+            rtc::scoped_refptr<webrtc::AudioSourceInterface>(source), volume));
   } else {
     source->SetVolume(volume);
   }
 }
 
-bool WebRtcAudioRenderer::AddPlayingState(
-    webrtc::AudioSourceInterface* source,
-    PlayingState* state) {
+bool WebRtcAudioRenderer::AddPlayingState(webrtc::AudioSourceInterface* source,
+                                          PlayingState* state) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(state->playing());
   // Look up or add the |source| to the map.
@@ -577,20 +608,18 @@
   return true;
 }
 
-void WebRtcAudioRenderer::OnPlayStateChanged(
-    const blink::WebMediaStream& media_stream,
-    PlayingState* state) {
+void WebRtcAudioRenderer::OnPlayStateChanged(const WebMediaStream& media_stream,
+                                             PlayingState* state) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  blink::WebVector<blink::WebMediaStreamTrack> web_tracks =
-      media_stream.AudioTracks();
+  WebVector<WebMediaStreamTrack> web_tracks = media_stream.AudioTracks();
 
-  for (const blink::WebMediaStreamTrack& web_track : web_tracks) {
+  for (const WebMediaStreamTrack& web_track : web_tracks) {
     // WebRtcAudioRenderer can only render audio tracks received from a remote
     // peer. Since the actual MediaStream is mutable from JavaScript, we need
     // to make sure |web_track| is actually a remote track.
-    blink::PeerConnectionRemoteAudioTrack* const remote_track =
-        blink::PeerConnectionRemoteAudioTrack::From(
-            blink::MediaStreamAudioTrack::From(web_track));
+    PeerConnectionRemoteAudioTrack* const remote_track =
+        PeerConnectionRemoteAudioTrack::From(
+            MediaStreamAudioTrack::From(web_track));
     if (!remote_track)
       continue;
     webrtc::AudioSourceInterface* source =
@@ -686,16 +715,18 @@
          audio_fifo_->SizeInFrames() != source_frames_per_buffer)) {
       audio_fifo_ = std::make_unique<media::AudioPullFifo>(
           kChannels, source_frames_per_buffer,
-          base::BindRepeating(&WebRtcAudioRenderer::SourceCallback,
-                              base::Unretained(this)));
+          ConvertToBaseCallback(
+              CrossThreadBindRepeating(&WebRtcAudioRenderer::SourceCallback,
+                                       CrossThreadUnretained(this))));
     }
     sink_params_ = new_sink_params;
   }
 
   // Specify the latency info to be passed to the browser side.
-  new_sink_params.set_latency_tag(AudioDeviceFactory::GetSourceLatencyType(
-      blink::WebAudioDeviceSourceType::kWebRtc));
+  new_sink_params.set_latency_tag(
+      Platform::Current()->GetAudioSourceLatencyType(
+          WebAudioDeviceSourceType::kWebRtc));
   sink_->Initialize(new_sink_params, this);
 }
 
-}  // namespace content
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/exported/mediastream/media_stream_audio_source.cc b/third_party/blink/renderer/platform/exported/mediastream/media_stream_audio_source.cc
index f3fc204..fe3a7ac7 100644
--- a/third_party/blink/renderer/platform/exported/mediastream/media_stream_audio_source.cc
+++ b/third_party/blink/renderer/platform/exported/mediastream/media_stream_audio_source.cc
@@ -44,8 +44,7 @@
     : is_local_source_(is_local_source),
       disable_local_echo_(disable_local_echo),
       is_stopped_(false),
-      task_runner_(std::move(task_runner)),
-      weak_factory_(this) {
+      task_runner_(std::move(task_runner)) {
   DVLOG(1) << "MediaStreamAudioSource@" << this << "::MediaStreamAudioSource("
            << (is_local_source_ ? "local" : "remote") << " source)";
 }
diff --git a/third_party/blink/renderer/platform/exported/mediastream/media_stream_audio_track.cc b/third_party/blink/renderer/platform/exported/mediastream/media_stream_audio_track.cc
index bfad789..1b6c6e15 100644
--- a/third_party/blink/renderer/platform/exported/mediastream/media_stream_audio_track.cc
+++ b/third_party/blink/renderer/platform/exported/mediastream/media_stream_audio_track.cc
@@ -15,9 +15,7 @@
 namespace blink {
 
 MediaStreamAudioTrack::MediaStreamAudioTrack(bool is_local_track)
-    : WebPlatformMediaStreamTrack(is_local_track),
-      is_enabled_(1),
-      weak_factory_(this) {
+    : WebPlatformMediaStreamTrack(is_local_track), is_enabled_(1) {
   DVLOG(1) << "MediaStreamAudioTrack@" << this << "::MediaStreamAudioTrack("
            << (is_local_track ? "local" : "remote") << " track)";
 }
diff --git a/third_party/blink/renderer/platform/exported/web_url_response.cc b/third_party/blink/renderer/platform/exported/web_url_response.cc
index e7de3a6..9157f39 100644
--- a/third_party/blink/renderer/platform/exported/web_url_response.cc
+++ b/third_party/blink/renderer/platform/exported/web_url_response.cc
@@ -381,6 +381,14 @@
   resource_response_->SetEncodedDataLength(length);
 }
 
+int64_t WebURLResponse::EncodedBodyLength() const {
+  return resource_response_->EncodedBodyLength();
+}
+
+void WebURLResponse::SetEncodedBodyLength(int64_t length) {
+  resource_response_->SetEncodedBodyLength(length);
+}
+
 void WebURLResponse::SetIsSignedExchangeInnerResponse(
     bool is_signed_exchange_inner_response) {
   resource_response_->SetIsSignedExchangeInnerResponse(
@@ -417,6 +425,10 @@
   resource_response_->SetNetworkAccessed(network_accessed);
 }
 
+bool WebURLResponse::FromArchive() const {
+  return resource_response_->FromArchive();
+}
+
 WebURLResponse::WebURLResponse(ResourceResponse& r) : resource_response_(&r) {}
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/font_cache.cc b/third_party/blink/renderer/platform/fonts/font_cache.cc
index 17e6db2..d46cb7e 100644
--- a/third_party/blink/renderer/platform/fonts/font_cache.cc
+++ b/third_party/blink/renderer/platform/fonts/font_cache.cc
@@ -63,6 +63,10 @@
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 #include "ui/gfx/font_list.h"
 
+#if defined(OS_WIN)
+#include "third_party/skia/include/ports/SkTypeface_win.h"
+#endif
+
 namespace blink {
 
 // Special locale for retrieving the color emoji font based on the proposed
@@ -86,10 +90,26 @@
   return &FontGlobalContext::GetFontCache();
 }
 
-#if !defined(OS_WIN)
 FontCache::FontCache()
-    : purge_prevent_count_(0), font_manager_(sk_ref_sp(static_font_manager_)) {}
-#endif  // !defined(OS_WIN) && !defined(OS_LINUX)
+    : purge_prevent_count_(0),
+      font_manager_(sk_ref_sp(static_font_manager_)),
+      font_size_limit_(std::nextafter(
+          (static_cast<float>(std::numeric_limits<unsigned>::max()) - 2.f) /
+              static_cast<float>(blink::FontCacheKey::PrecisionMultiplier()),
+          0.f)) {
+#if defined(OS_WIN)
+  if (!font_manager_) {
+    // This code path is only for unit tests. This SkFontMgr does not work in
+    // sandboxed environments, but injecting this initialization code to all
+    // unit tests isn't easy.
+    font_manager_ = SkFontMgr_New_DirectWrite();
+    // Set |is_test_font_mgr_| to capture if this is not happening in the
+    // production code. crbug.com/561873
+    is_test_font_mgr_ = true;
+  }
+  DCHECK(font_manager_.get());
+#endif
+}
 
 #if !defined(OS_MACOSX)
 FontPlatformData* FontCache::SystemFontPlatformData(
@@ -125,11 +145,24 @@
 #endif
 
   float size = font_description.EffectiveFontSize();
+  size = std::min(size, font_size_limit_);
+
   unsigned rounded_size = size * FontCacheKey::PrecisionMultiplier();
+
+  // Assert that the computed hash map key rounded_size value does not hit
+  // the empty (max()) or deleted (max()-1) sentinel values of the hash map,
+  // compare UnsignedWithZeroKeyHashTraits() in hash_traits.h.
+  DCHECK_LT(rounded_size, std::numeric_limits<unsigned>::max() - 1);
+  // Assert that rounded_size was not reset to 0 due to an integer overflow,
+  // i.e. if size was non-zero, rounded_size can't be zero, but if size was 0,
+  // it may be 0.
+  DCHECK_EQ(!!size, !!rounded_size);
+
   bool is_unique_match =
       alternate_font_name == AlternateFontName::kLocalUniqueFace;
   FontCacheKey key =
       font_description.CacheKey(creation_params, is_unique_match);
+  DCHECK(!key.IsHashTableDeletedValue());
 
   // Remove the font size from the cache key, and handle the font size
   // separately in the inner HashMap. So that different size of FontPlatformData
diff --git a/third_party/blink/renderer/platform/fonts/font_cache.h b/third_party/blink/renderer/platform/fonts/font_cache.h
index 9845fcd..f825c5f 100644
--- a/third_party/blink/renderer/platform/fonts/font_cache.h
+++ b/third_party/blink/renderer/platform/fonts/font_cache.h
@@ -350,6 +350,15 @@
   void PurgePlatformFontDataCache();
   void PurgeFallbackListShaperCache();
 
+  // A maximum float value to which we limit incoming font sizes. This is the
+  // smallest float so that multiplying it by
+  // FontCacheKey::PrecisionMultiplier() is still smaller than
+  // std::numeric_limits<unsigned>::max() - 1 in order to avoid hitting HashMap
+  // sentinel values (placed at std::numeric_limits<unsigned>::max() and
+  // std::numeric_limits<unsigned>::max() - 1) for SizedFontPlatformDataSet and
+  // FontPlatformDataCache.
+  const float font_size_limit_;
+
   friend class SimpleFontData;  // For fontDataFromFontPlatformData
   friend class FontFallbackList;
 
diff --git a/third_party/blink/renderer/platform/fonts/font_cache_key.h b/third_party/blink/renderer/platform/fonts/font_cache_key.h
index 73a8779b..0efc8fb9 100644
--- a/third_party/blink/renderer/platform/fonts/font_cache_key.h
+++ b/third_party/blink/renderer/platform/fonts/font_cache_key.h
@@ -31,6 +31,8 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_FONT_CACHE_KEY_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_FONT_CACHE_KEY_H_
 
+#include <limits>
+
 #include "third_party/blink/renderer/platform/fonts/font_face_creation_params.h"
 #include "third_party/blink/renderer/platform/fonts/opentype/font_settings.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -43,7 +45,7 @@
 
 // Multiplying the floating point size by 100 gives two decimal point
 // precision which should be sufficient.
-static const unsigned kFontSizePrecisionMultiplier = 100;
+static constexpr unsigned kFontSizePrecisionMultiplier = 100;
 
 struct FontCacheKey {
   DISALLOW_NEW();
@@ -69,7 +71,13 @@
         is_unique_match_(is_unique_match) {}
 
   FontCacheKey(WTF::HashTableDeletedValueType)
-      : font_size_(HashTableDeletedSize()) {}
+      : font_size_(std::numeric_limits<unsigned>::max()),
+        device_scale_factor_(std::numeric_limits<float>::max()) {}
+
+  bool IsHashTableDeletedValue() const {
+    return font_size_ == std::numeric_limits<unsigned>::max() &&
+           device_scale_factor_ == std::numeric_limits<float>::max();
+  }
 
   unsigned GetHash() const {
     // Convert from float with 3 digit precision before hashing.
@@ -92,16 +100,13 @@
            is_unique_match_ == other.is_unique_match_;
   }
 
-  bool IsHashTableDeletedValue() const {
-    return font_size_ == HashTableDeletedSize();
+  static constexpr unsigned PrecisionMultiplier() {
+    return kFontSizePrecisionMultiplier;
   }
 
-  static unsigned PrecisionMultiplier() { return kFontSizePrecisionMultiplier; }
-
   void ClearFontSize() { font_size_ = 0; }
 
  private:
-  static unsigned HashTableDeletedSize() { return 0xFFFFFFFFU; }
 
   FontFaceCreationParams creation_params_;
   unsigned font_size_;
diff --git a/third_party/blink/renderer/platform/fonts/font_cache_test.cc b/third_party/blink/renderer/platform/fonts/font_cache_test.cc
index b8b1c50e..a923399 100644
--- a/third_party/blink/renderer/platform/fonts/font_cache_test.cc
+++ b/third_party/blink/renderer/platform/fonts/font_cache_test.cc
@@ -63,6 +63,25 @@
             FontCache::FirstAvailableOrFirst(", not exist, not exist"));
 }
 
+// https://crbug.com/969402
+TEST(FontCache, getLargerThanMaxUnsignedFont) {
+  FontCache* font_cache = FontCache::GetFontCache();
+  ASSERT_TRUE(font_cache);
+
+  FontDescription font_description;
+  font_description.SetGenericFamily(FontDescription::kStandardFamily);
+  font_description.SetComputedSize(std::numeric_limits<unsigned>::max() + 1.f);
+  FontFaceCreationParams creation_params;
+  scoped_refptr<blink::SimpleFontData> font_data =
+      font_cache->GetFontData(font_description, AtomicString());
+#if !defined(OS_ANDROID) && !defined(OS_MACOSX) && !defined(OS_WIN)
+  // Unfortunately, we can't ensure a font here since on Android and Mac the
+  // unittests can't access the font configuration. However, this test passes
+  // when it's not crashing in FontCache.
+  EXPECT_TRUE(font_data);
+#endif
+}
+
 #if !defined(OS_MACOSX)
 TEST(FontCache, systemFont) {
   FontCache::SystemFontFamily();
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_cache.h b/third_party/blink/renderer/platform/fonts/shaping/shape_cache.h
index 7d5819d..b6a3ff9 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_cache.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_cache.h
@@ -109,7 +109,7 @@
   };
 
  public:
-  ShapeCache() : weak_factory_(this) {
+  ShapeCache() {
     // TODO(cavalcantii): Investigate tradeoffs of reserving space
     // in short_string_map.
   }
@@ -233,7 +233,7 @@
   SingleCharMap single_char_map_;
   SmallStringMap short_string_map_;
   unsigned version_ = 0;
-  base::WeakPtrFactory<ShapeCache> weak_factory_;
+  base::WeakPtrFactory<ShapeCache> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(ShapeCache);
 };
diff --git a/third_party/blink/renderer/platform/fonts/win/font_cache_skia_win.cc b/third_party/blink/renderer/platform/fonts/win/font_cache_skia_win.cc
index 7c2d603..7c61b250 100644
--- a/third_party/blink/renderer/platform/fonts/win/font_cache_skia_win.cc
+++ b/third_party/blink/renderer/platform/fonts/win/font_cache_skia_win.cc
@@ -151,20 +151,6 @@
   status_font_height_ = EnsureMinimumFontHeightIfNeeded(font_height);
 }
 
-FontCache::FontCache() : purge_prevent_count_(0) {
-  font_manager_ = sk_ref_sp(static_font_manager_);
-  if (!font_manager_) {
-    // This code path is only for unit tests. This SkFontMgr does not work in
-    // sandboxed environments, but injecting this initialization code to all
-    // unit tests isn't easy.
-    font_manager_ = SkFontMgr_New_DirectWrite();
-    // Set |is_test_font_mgr_| to capture if this is not happening in the
-    // production code. crbug.com/561873
-    is_test_font_mgr_ = true;
-  }
-  DCHECK(font_manager_.get());
-}
-
 // Given the desired base font, this will create a SimpleFontData for a specific
 // font that can be used to render the given range of characters.
 scoped_refptr<SimpleFontData> FontCache::PlatformFallbackFontForCharacter(
diff --git a/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.cc b/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.cc
index 826b398..f1a5908 100644
--- a/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.cc
+++ b/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.cc
@@ -66,9 +66,7 @@
 
 AnimationWorkletMutatorDispatcherImpl::AnimationWorkletMutatorDispatcherImpl(
     bool main_thread_task_runner)
-    : client_(nullptr),
-      outputs_(OutputVectorRef::Create()),
-      weak_factory_(this) {
+    : client_(nullptr), outputs_(OutputVectorRef::Create()) {
   // By default web tests run without threaded compositing. See
   // https://crbug.com/770028 For these situations we run on the Main thread.
   host_queue_ = main_thread_task_runner || !Thread::CompositorThread()
diff --git a/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h b/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h
index 98054df5..81bdf2d 100644
--- a/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h
+++ b/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h
@@ -170,7 +170,8 @@
 
   std::unique_ptr<base::TickClock> tick_clock_;
 
-  base::WeakPtrFactory<AnimationWorkletMutatorDispatcherImpl> weak_factory_;
+  base::WeakPtrFactory<AnimationWorkletMutatorDispatcherImpl> weak_factory_{
+      this};
 
   DISALLOW_COPY_AND_ASSIGN(AnimationWorkletMutatorDispatcherImpl);
 };
diff --git a/third_party/blink/renderer/platform/graphics/begin_frame_provider.cc b/third_party/blink/renderer/platform/graphics/begin_frame_provider.cc
index cd8c3e8..1fa8d1d2 100644
--- a/third_party/blink/renderer/platform/graphics/begin_frame_provider.cc
+++ b/third_party/blink/renderer/platform/graphics/begin_frame_provider.cc
@@ -23,8 +23,7 @@
       efs_binding_(this),
       frame_sink_id_(begin_frame_provider_params.frame_sink_id),
       parent_frame_sink_id_(begin_frame_provider_params.parent_frame_sink_id),
-      begin_frame_client_(client),
-      weak_factory_(this) {}
+      begin_frame_client_(client) {}
 
 void BeginFrameProvider::ResetCompositorFrameSink() {
   compositor_frame_sink_.reset();
diff --git a/third_party/blink/renderer/platform/graphics/begin_frame_provider.h b/third_party/blink/renderer/platform/graphics/begin_frame_provider.h
index 2c0edcf..f424332 100644
--- a/third_party/blink/renderer/platform/graphics/begin_frame_provider.h
+++ b/third_party/blink/renderer/platform/graphics/begin_frame_provider.h
@@ -79,7 +79,7 @@
   viz::mojom::blink::CompositorFrameSinkPtr compositor_frame_sink_;
   BeginFrameProviderClient* begin_frame_client_;
 
-  base::WeakPtrFactory<BeginFrameProvider> weak_factory_;
+  base::WeakPtrFactory<BeginFrameProvider> weak_factory_{this};
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.cc b/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.cc
index 3871e2c..a6f68422 100644
--- a/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.cc
+++ b/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.cc
@@ -11,7 +11,6 @@
 #include "third_party/blink/renderer/platform/histogram.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "third_party/blink/renderer/platform/wtf/threading.h"
-#include "third_party/skia/include/third_party/skcms/skcms.h"
 
 namespace blink {
 
@@ -72,15 +71,6 @@
   }
 }
 
-void BitmapImageMetrics::CountImageGammaAndGamut(
-    const skcms_ICCProfile* color_profile) {
-  DEFINE_THREAD_SAFE_STATIC_LOCAL(
-      EnumerationHistogram, gamut_named_histogram,
-      ("Blink.ColorGamut.Source", static_cast<int>(ColorSpaceGamut::kEnd)));
-  gamut_named_histogram.Count(static_cast<int>(
-      color_space_utilities::GetColorSpaceGamut(color_profile)));
-}
-
 void BitmapImageMetrics::CountJpegArea(const IntSize& size) {
   DEFINE_THREAD_SAFE_STATIC_LOCAL(
       CustomCountHistogram, image_area_histogram,
diff --git a/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.h b/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.h
index df8c883..e97697d 100644
--- a/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.h
+++ b/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.h
@@ -10,8 +10,6 @@
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 
-struct skcms_ICCProfile;
-
 namespace blink {
 
 class IntSize;
@@ -78,8 +76,6 @@
   // with a smallest side (width or length) of |image_min_side|.
   static void CountImageJpegDensity(int image_min_side,
                                     uint64_t density_centi_bpp);
-  // Misnamed: Only counts gamut information at the moment.
-  static void CountImageGammaAndGamut(const skcms_ICCProfile*);
   static void CountJpegArea(const IntSize& size);
   static void CountJpegColorSpace(JpegColorSpace color_space);
 };
diff --git a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
index acc5a9a..33b07c3 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
@@ -69,8 +69,7 @@
       snapshot_state_(kInitialSnapshotState),
       resource_host_(nullptr),
       random_generator_((uint32_t)base::RandUint64()),
-      bernoulli_distribution_(kRasterMetricProbability),
-      weak_ptr_factory_(this) {
+      bernoulli_distribution_(kRasterMetricProbability) {
   // Used by browser tests to detect the use of a Canvas2DLayerBridge.
   TRACE_EVENT_INSTANT0("test_gpu", "Canvas2DLayerBridgeCreation",
                        TRACE_EVENT_SCOPE_GLOBAL);
diff --git a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h
index 3b84bf0..9c5c783 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h
+++ b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h
@@ -231,7 +231,7 @@
   std::bernoulli_distribution bernoulli_distribution_;
   Deque<RasterTimer> pending_raster_timers_;
 
-  base::WeakPtrFactory<Canvas2DLayerBridge> weak_ptr_factory_;
+  base::WeakPtrFactory<Canvas2DLayerBridge> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(Canvas2DLayerBridge);
 };
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc
index b21bda3..638a140 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc
@@ -63,8 +63,7 @@
       num_unreclaimed_frames_posted_(0),
       client_(client),
       enable_surface_synchronization_(
-          ::features::IsSurfaceSynchronizationEnabled()),
-      weak_ptr_factory_(this) {
+          ::features::IsSurfaceSynchronizationEnabled()) {
   // Frameless canvas pass an invalid |frame_sink_id_|; don't create mojo
   // channel for this special case.
   if (!frame_sink_id_.is_valid())
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h b/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h
index 6abe9a41..0f49e06 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h
@@ -133,7 +133,7 @@
 
   const bool enable_surface_synchronization_;
 
-  base::WeakPtrFactory<CanvasResourceDispatcher> weak_ptr_factory_;
+  base::WeakPtrFactory<CanvasResourceDispatcher> weak_ptr_factory_{this};
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
index 7a7fb7c..b7d88c0 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
@@ -1022,7 +1022,7 @@
   cc::PlaybackImageProvider playback_image_provider_n32_;
   base::Optional<cc::PlaybackImageProvider> playback_image_provider_f16_;
 
-  base::WeakPtrFactory<CanvasImageProvider> weak_factory_;
+  base::WeakPtrFactory<CanvasImageProvider> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(CanvasImageProvider);
 };
@@ -1036,8 +1036,7 @@
     : is_hardware_decode_cache_(is_hardware_decode_cache),
       playback_image_provider_n32_(cache_n32,
                                    target_color_space,
-                                   cc::PlaybackImageProvider::Settings()),
-      weak_factory_(this) {
+                                   cc::PlaybackImageProvider::Settings()) {
   // If the image provider may require to decode to half float instead of
   // uint8, create a f16 PlaybackImageProvider with the passed cache.
   if (canvas_color_type == kRGBA_F16_SkColorType) {
@@ -1124,8 +1123,7 @@
       resource_dispatcher_(resource_dispatcher),
       size_(size),
       color_params_(color_params),
-      snapshot_paint_image_id_(cc::PaintImage::GetNextId()),
-      weak_ptr_factory_(this) {
+      snapshot_paint_image_id_(cc::PaintImage::GetNextId()) {
   if (context_provider_wrapper_)
     context_provider_wrapper_->AddObserver(this);
 }
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
index a8006dc..a42e84b5 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
@@ -227,7 +227,7 @@
   bool resource_recycling_enabled_ = true;
   bool is_single_buffered_ = false;
 
-  base::WeakPtrFactory<CanvasResourceProvider> weak_ptr_factory_;
+  base::WeakPtrFactory<CanvasResourceProvider> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(CanvasResourceProvider);
 };
diff --git a/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.cc b/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.cc
index fe785b1..7bddf02 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.cc
@@ -28,8 +28,7 @@
       raster_invalidator_(
           base::BindRepeating(&ContentLayerClientImpl::InvalidateRect,
                               base::Unretained(this))),
-      layer_state_(PropertyTreeState::Uninitialized()),
-      weak_ptr_factory_(this) {
+      layer_state_(PropertyTreeState::Uninitialized()) {
   cc_picture_layer_->SetLayerClient(weak_ptr_factory_.GetWeakPtr());
 }
 
diff --git a/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.h b/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.h
index 34808408..a75ad72 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.h
+++ b/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.h
@@ -89,7 +89,7 @@
   std::unique_ptr<JSONArray> paint_chunk_debug_data_;
 #endif
 
-  base::WeakPtrFactory<ContentLayerClientImpl> weak_ptr_factory_;
+  base::WeakPtrFactory<ContentLayerClientImpl> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(ContentLayerClientImpl);
 };
diff --git a/third_party/blink/renderer/platform/graphics/graphics_layer.cc b/third_party/blink/renderer/platform/graphics/graphics_layer.cc
index a5ca5df..e3ea816 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_layer.cc
+++ b/third_party/blink/renderer/platform/graphics/graphics_layer.cc
@@ -86,8 +86,7 @@
       contents_clipping_mask_layer_(nullptr),
       contents_layer_(nullptr),
       contents_layer_id_(0),
-      rendering_context3d_(0),
-      weak_ptr_factory_(this) {
+      rendering_context3d_(0) {
 #if DCHECK_IS_ON()
   DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
   client.VerifyNotPainting();
diff --git a/third_party/blink/renderer/platform/graphics/graphics_layer.h b/third_party/blink/renderer/platform/graphics/graphics_layer.h
index 04e05ee..151b39c 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_layer.h
+++ b/third_party/blink/renderer/platform/graphics/graphics_layer.h
@@ -427,7 +427,7 @@
 
   std::unique_ptr<RasterInvalidator> raster_invalidator_;
 
-  base::WeakPtrFactory<GraphicsLayer> weak_ptr_factory_;
+  base::WeakPtrFactory<GraphicsLayer> weak_ptr_factory_{this};
 
   FRIEND_TEST_ALL_PREFIXES(CompositingLayerPropertyUpdaterTest, MaskLayerState);
 
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc b/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
index 6b87d027..b2ecbe6 100644
--- a/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
+++ b/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
@@ -32,9 +32,7 @@
       resource_provider_(std::move(resource_provider)),
       rotation_(media::VIDEO_ROTATION_0),
       enable_surface_synchronization_(
-          ::features::IsSurfaceSynchronizationEnabled()),
-      empty_frame_weak_ptr_factory_(this),
-      weak_ptr_factory_(this) {
+          ::features::IsSurfaceSynchronizationEnabled()) {
   DETACH_FROM_THREAD(thread_checker_);
 }
 
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_submitter.h b/third_party/blink/renderer/platform/graphics/video_frame_submitter.h
index df6e532..8b8727c 100644
--- a/third_party/blink/renderer/platform/graphics/video_frame_submitter.h
+++ b/third_party/blink/renderer/platform/graphics/video_frame_submitter.h
@@ -177,9 +177,9 @@
   THREAD_CHECKER(thread_checker_);
 
   // Weak factory that's used to cancel empty frame callbacks.
-  base::WeakPtrFactory<VideoFrameSubmitter> empty_frame_weak_ptr_factory_;
+  base::WeakPtrFactory<VideoFrameSubmitter> empty_frame_weak_ptr_factory_{this};
 
-  base::WeakPtrFactory<VideoFrameSubmitter> weak_ptr_factory_;
+  base::WeakPtrFactory<VideoFrameSubmitter> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(VideoFrameSubmitter);
 };
diff --git a/third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_wrapper.h b/third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_wrapper.h
index 452305f..6a79611d 100644
--- a/third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_wrapper.h
+++ b/third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_wrapper.h
@@ -30,7 +30,7 @@
 
   WebGraphicsContext3DProviderWrapper(
       std::unique_ptr<WebGraphicsContext3DProvider> provider)
-      : context_provider_(std::move(provider)), weak_ptr_factory_(this) {
+      : context_provider_(std::move(provider)) {
     DCHECK(context_provider_);
     utils_ = base::WrapUnique(new GraphicsContext3DUtils(GetWeakPtr()));
   }
@@ -52,7 +52,8 @@
   std::unique_ptr<GraphicsContext3DUtils> utils_;
   std::unique_ptr<WebGraphicsContext3DProvider> context_provider_;
   base::ObserverList<DestructionObserver>::Unchecked observers_;
-  base::WeakPtrFactory<WebGraphicsContext3DProviderWrapper> weak_ptr_factory_;
+  base::WeakPtrFactory<WebGraphicsContext3DProviderWrapper> weak_ptr_factory_{
+      this};
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/heap/heap_compact.cc b/third_party/blink/renderer/platform/heap/heap_compact.cc
index b8238fa..2a4259e9 100644
--- a/third_party/blink/renderer/platform/heap/heap_compact.cc
+++ b/third_party/blink/renderer/platform/heap/heap_compact.cc
@@ -107,6 +107,9 @@
     auto interior_it = interior_fixups_.find(slot);
     CHECK(interior_fixups_.end() == interior_it);
     interior_fixups_.insert({slot, nullptr});
+#if DCHECK_IS_ON()
+    interior_slot_to_object_.insert(slot, header->Payload());
+#endif  // DCHECK_IS_ON()
     LOG_HEAP_COMPACTION() << "Interior slot: " << slot;
   }
 
@@ -152,6 +155,20 @@
   }
 
   void Relocate(Address from, Address to) {
+#if DCHECK_IS_ON()
+    moved_objects_.insert(from);
+#endif  // DCHECK_IS_ON()
+
+    // Interior slots always need to be processed for moved objects.
+    // Consider an object A with slot A.x pointing to value B where A is
+    // allocated on a movable page itself. When B is finally moved, it needs to
+    // find the corresponding slot A.x. Object A may be moved already and the
+    // memory may have been freed, which would result in a crash.
+    if (!interior_fixups_.empty()) {
+      RelocateInteriorFixups(from, to,
+                             HeapObjectHeader::FromPayload(to)->PayloadSize());
+    }
+
     auto it = fixups_.find(from);
     // This means that there is no corresponding slot for a live backing store.
     // This may happen because a mutator may change the slot to point to a
@@ -200,6 +217,12 @@
           len = kMaxNameLen;
         strncpy(slot_container_name, name, len);
         slot_container_name[len - 1] = 0;
+#if DCHECK_IS_ON()
+        // Check that the containing object has not been moved yet.
+        auto reverse_it = interior_slot_to_object_.find(slot);
+        DCHECK(interior_slot_to_object_.end() != reverse_it);
+        DCHECK(moved_objects_.end() == moved_objects_.find(reverse_it->value));
+#endif  // DCHECK_IS_ON()
       } else {
         LOG_HEAP_COMPACTION()
             << "Redirected slot: " << slot << " => " << slot_location;
@@ -208,13 +231,9 @@
       }
     }
 
-    // If the slot has subsequently been updated, a prefinalizer or
-    // a destructor having mutated and expanded/shrunk the collection,
-    // do not update and relocate the slot -- |from| is no longer valid
-    // and referenced.
-    //
-    // The slot's contents may also have been cleared during weak processing;
-    // no work to be done in that case either.
+    // If the slot has subsequently been updated, e.g. a destructor having
+    // mutated and expanded/shrunk the collection, do not update and relocate
+    // the slot -- |from| is no longer valid and referenced.
     if (UNLIKELY(*slot != from)) {
       LOG_HEAP_COMPACTION()
           << "No relocation: slot = " << slot << ", *slot = " << *slot
@@ -226,23 +245,14 @@
     // Update the slots new value.
     *slot = to;
 
-    size_t size = 0;
-
     // Execute potential fixup callbacks.
     MovableReference* callback_slot =
         reinterpret_cast<MovableReference*>(it->second);
     auto callback = fixup_callbacks_.find(callback_slot);
     if (UNLIKELY(callback != fixup_callbacks_.end())) {
-      size = HeapObjectHeader::FromPayload(to)->PayloadSize();
-      callback->value.second(callback->value.first, from, to, size);
+      callback->value.second(callback->value.first, from, to,
+                             HeapObjectHeader::FromPayload(to)->PayloadSize());
     }
-
-    if (interior_fixups_.empty())
-      return;
-
-    if (!size)
-      size = HeapObjectHeader::FromPayload(to)->PayloadSize();
-    RelocateInteriorFixups(from, to, size);
   }
 
 #if DEBUG_HEAP_COMPACTION
@@ -318,6 +328,13 @@
   // BasePage instances. The void* type was selected to allow to check
   // arbitrary addresses.
   HashSet<void*> relocatable_pages_;
+
+#if DCHECK_IS_ON()
+  // The following two collections are used to allow refer back from a slot to
+  // an already moved object.
+  HashSet<void*> moved_objects_;
+  HashMap<MovableReference*, MovableReference> interior_slot_to_object_;
+#endif  // DCHECK_IS_ON()
 };
 
 void HeapCompact::MovableObjectFixups::VerifyUpdatedSlot(
diff --git a/third_party/blink/renderer/platform/heap/incremental_marking_test.cc b/third_party/blink/renderer/platform/heap/incremental_marking_test.cc
index 49d9c27..6312feb 100644
--- a/third_party/blink/renderer/platform/heap/incremental_marking_test.cc
+++ b/third_party/blink/renderer/platform/heap/incremental_marking_test.cc
@@ -1926,5 +1926,35 @@
   holder->Grow(8);
 }
 
+TEST(IncrementalMarkingTest, HeapCompactWithStaleSlotInNestedContainer) {
+  // Regression test: https://crbug.com/980962
+  //
+  // Test ensures that interior pointers are updated even if the backing store
+  // itself is not referenced anymore. Consider the case where a |B| is
+  // references a value |V| through slot |B.x|. Even if |B| is not referred to
+  // from an actual object any more, the slot |B.x| needs to be in valid state
+  // when |V| is moved.
+
+  using Nested = HeapVector<HeapVector<Member<Object>>>;
+
+  // Allocate dummy storage so that other vector backings are actually moved.
+  MakeGarbageCollected<HeapVector<Member<Object>>>()->push_back(
+      MakeGarbageCollected<Object>());
+
+  IncrementalMarkingTestDriver driver(ThreadState::Current());
+  ThreadState::Current()->EnableCompactionForNextGCForTesting();
+  driver.Start();
+  Nested* outer = MakeGarbageCollected<Nested>();
+  outer->push_back(HeapVector<Member<Object>>());
+  outer->at(0).push_back(MakeGarbageCollected<Object>());
+  // The outer HeapVector object is not marked, which leaves the backing store
+  // as marked with a valid slot inside. Now, if the outer backing store moves
+  // first and its page is freed, then referring to the slot when the inner
+  // backing store is moved may crash.
+  outer = nullptr;
+  driver.FinishSteps();
+  driver.FinishGC();
+}
+
 }  // namespace incremental_marking_test
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/image-decoders/image_decoder.cc b/third_party/blink/renderer/platform/image-decoders/image_decoder.cc
index 7130954..c4ff566 100644
--- a/third_party/blink/renderer/platform/image-decoders/image_decoder.cc
+++ b/third_party/blink/renderer/platform/image-decoders/image_decoder.cc
@@ -23,7 +23,6 @@
 #include <memory>
 
 #include "base/numerics/safe_conversions.h"
-#include "third_party/blink/renderer/platform/graphics/bitmap_image_metrics.h"
 #include "third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_decoder.h"
 #include "third_party/blink/renderer/platform/image-decoders/fast_shared_buffer_reader.h"
 #include "third_party/blink/renderer/platform/image-decoders/gif/gif_image_decoder.h"
@@ -258,13 +257,6 @@
     Decode(index);
   }
 
-  if (!has_histogrammed_color_space_) {
-    BitmapImageMetrics::CountImageGammaAndGamut(
-        embedded_color_profile_ ? embedded_color_profile_->GetProfile()
-                                : nullptr);
-    has_histogrammed_color_space_ = true;
-  }
-
   frame->NotifyBitmapIfPixelsChanged();
   return frame;
 }
@@ -644,7 +636,6 @@
 void ImageDecoder::SetEmbeddedColorProfile(
     std::unique_ptr<ColorProfile> profile) {
   DCHECK(!IgnoresColorSpace());
-  DCHECK(!has_histogrammed_color_space_);
 
   embedded_color_profile_ = std::move(profile);
   source_to_target_color_transform_needs_update_ = true;
diff --git a/third_party/blink/renderer/platform/image-decoders/image_decoder.h b/third_party/blink/renderer/platform/image-decoders/image_decoder.h
index d962313..e7c6e07 100644
--- a/third_party/blink/renderer/platform/image-decoders/image_decoder.h
+++ b/third_party/blink/renderer/platform/image-decoders/image_decoder.h
@@ -503,7 +503,6 @@
   bool size_available_ = false;
   bool is_all_data_received_ = false;
   bool failed_ = false;
-  bool has_histogrammed_color_space_ = false;
 
   std::unique_ptr<ColorProfile> embedded_color_profile_;
   sk_sp<SkColorSpace> color_space_for_sk_images_;
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
index 5cd19d5..e63450ae 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -707,6 +707,7 @@
     response.SetMimeType(archive_resource->MimeType());
     response.SetExpectedContentLength(data->size());
     response.SetTextEncodingName(archive_resource->TextEncoding());
+    response.SetFromArchive(true);
   }
 
   Resource* resource = factory.Create(
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
index 69d87e2..0f78f24b3c 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
@@ -181,8 +181,7 @@
       : status_(kNoRequestSent),
         code_cache_loader_(std::move(code_cache_loader)),
         gurl_(url),
-        defers_loading_(defers_loading),
-        weak_ptr_factory_(this) {
+        defers_loading_(defers_loading) {
     DCHECK(RuntimeEnabledFeatures::IsolatedCodeCacheEnabled());
   }
 
@@ -236,7 +235,7 @@
   base::Time cached_code_response_time_;
   base::Time resource_response_time_;
   bool use_isolated_code_cache_ = false;
-  base::WeakPtrFactory<CodeCacheRequest> weak_ptr_factory_;
+  base::WeakPtrFactory<CodeCacheRequest> weak_ptr_factory_{this};
 };
 
 bool ResourceLoader::CodeCacheRequest::FetchFromCodeCache(
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_response.h b/third_party/blink/renderer/platform/loader/fetch/resource_response.h
index e7b39c1..2baf57e5 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_response.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_response.h
@@ -428,6 +428,10 @@
     network_accessed_ = network_accessed;
   }
 
+  bool FromArchive() const { return from_archive_; }
+
+  void SetFromArchive(bool from_archive) { from_archive_ = from_archive; }
+
   bool IsSignedExchangeInnerResponse() const {
     return is_signed_exchange_inner_response_;
   }
@@ -513,6 +517,9 @@
   // True if this resource was loaded from the network.
   bool network_accessed_ = false;
 
+  // True if this resource was loaded from a MHTML archive.
+  bool from_archive_ = false;
+
   // https://fetch.spec.whatwg.org/#concept-response-type
   network::mojom::FetchResponseType response_type_ =
       network::mojom::FetchResponseType::kDefault;
diff --git a/third_party/blink/renderer/platform/loader/static_data_navigation_body_loader.cc b/third_party/blink/renderer/platform/loader/static_data_navigation_body_loader.cc
index 8949f62..93c06911 100644
--- a/third_party/blink/renderer/platform/loader/static_data_navigation_body_loader.cc
+++ b/third_party/blink/renderer/platform/loader/static_data_navigation_body_loader.cc
@@ -8,8 +8,7 @@
 
 namespace blink {
 
-StaticDataNavigationBodyLoader::StaticDataNavigationBodyLoader()
-    : weak_factory_(this) {}
+StaticDataNavigationBodyLoader::StaticDataNavigationBodyLoader() {}
 
 StaticDataNavigationBodyLoader::~StaticDataNavigationBodyLoader() = default;
 
diff --git a/third_party/blink/renderer/platform/loader/static_data_navigation_body_loader.h b/third_party/blink/renderer/platform/loader/static_data_navigation_body_loader.h
index 3e17f71..f69356f 100644
--- a/third_party/blink/renderer/platform/loader/static_data_navigation_body_loader.h
+++ b/third_party/blink/renderer/platform/loader/static_data_navigation_body_loader.h
@@ -40,7 +40,7 @@
   bool received_all_data_ = false;
   bool is_in_continue_ = false;
   int64_t total_encoded_data_length_ = 0;
-  base::WeakPtrFactory<StaticDataNavigationBodyLoader> weak_factory_;
+  base::WeakPtrFactory<StaticDataNavigationBodyLoader> weak_factory_{this};
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/media/webaudiosourceprovider_impl.cc b/third_party/blink/renderer/platform/media/webaudiosourceprovider_impl.cc
index 7629c5f..90b1e7c 100644
--- a/third_party/blink/renderer/platform/media/webaudiosourceprovider_impl.cc
+++ b/third_party/blink/renderer/platform/media/webaudiosourceprovider_impl.cc
@@ -109,8 +109,7 @@
       client_(nullptr),
       sink_(std::move(sink)),
       tee_filter_(new TeeFilter()),
-      media_log_(media_log),
-      weak_factory_(this) {}
+      media_log_(media_log) {}
 
 WebAudioSourceProviderImpl::~WebAudioSourceProviderImpl() = default;
 
diff --git a/third_party/blink/renderer/platform/media/webaudiosourceprovider_impl_test.cc b/third_party/blink/renderer/platform/media/webaudiosourceprovider_impl_test.cc
index 631508a..e67e1f8 100644
--- a/third_party/blink/renderer/platform/media/webaudiosourceprovider_impl_test.cc
+++ b/third_party/blink/renderer/platform/media/webaudiosourceprovider_impl_test.cc
@@ -23,7 +23,7 @@
 
 namespace {
 const float kTestVolume = 0.25;
-const int kSampleRate = 48000;
+const int kTestSampleRate = 48000;
 }  // namespace
 
 class WebAudioSourceProviderImplTest : public testing::Test,
@@ -32,9 +32,9 @@
   WebAudioSourceProviderImplTest()
       : params_(media::AudioParameters::AUDIO_PCM_LINEAR,
                 media::CHANNEL_LAYOUT_STEREO,
-                kSampleRate,
+                kTestSampleRate,
                 64),
-        fake_callback_(0.1, kSampleRate),
+        fake_callback_(0.1, kTestSampleRate),
         mock_sink_(new media::MockAudioRendererSink()),
         wasp_impl_(new WebAudioSourceProviderImpl(mock_sink_, &media_log_)) {}
 
diff --git a/third_party/blink/renderer/platform/mojo/interface_invalidator.cc b/third_party/blink/renderer/platform/mojo/interface_invalidator.cc
index 126d022..a0bde42cf 100644
--- a/third_party/blink/renderer/platform/mojo/interface_invalidator.cc
+++ b/third_party/blink/renderer/platform/mojo/interface_invalidator.cc
@@ -6,7 +6,7 @@
 
 namespace blink {
 
-InterfaceInvalidator::InterfaceInvalidator() : weak_factory_(this) {}
+InterfaceInvalidator::InterfaceInvalidator() {}
 
 InterfaceInvalidator::~InterfaceInvalidator() {
   weak_factory_.InvalidateWeakPtrs();
diff --git a/third_party/blink/renderer/platform/mojo/interface_invalidator.h b/third_party/blink/renderer/platform/mojo/interface_invalidator.h
index b14be84..e6e815b 100644
--- a/third_party/blink/renderer/platform/mojo/interface_invalidator.h
+++ b/third_party/blink/renderer/platform/mojo/interface_invalidator.h
@@ -36,7 +36,7 @@
   void NotifyInvalidate();
 
   base::ObserverList<Observer>::Unchecked observers_;
-  base::WeakPtrFactory<InterfaceInvalidator> weak_factory_;
+  base::WeakPtrFactory<InterfaceInvalidator> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(InterfaceInvalidator);
 };
diff --git a/third_party/blink/renderer/platform/mojo/revocable_strong_binding.h b/third_party/blink/renderer/platform/mojo/revocable_strong_binding.h
index 69d7b27..80286873 100644
--- a/third_party/blink/renderer/platform/mojo/revocable_strong_binding.h
+++ b/third_party/blink/renderer/platform/mojo/revocable_strong_binding.h
@@ -98,8 +98,7 @@
                          mojo::InterfaceRequest<Interface> request,
                          InterfaceInvalidator* invalidator)
       : impl_(std::move(impl)),
-        binding_(impl_.get(), std::move(request), invalidator),
-        weak_factory_(this) {
+        binding_(impl_.get(), std::move(request), invalidator) {
     binding_.set_connection_error_handler(base::BindOnce(
         &RevocableStrongBinding::OnConnectionError, base::Unretained(this)));
   }
@@ -116,7 +115,7 @@
   std::unique_ptr<Interface> impl_;
   base::OnceClosure connection_error_handler_;
   RevocableBinding<Interface> binding_;
-  base::WeakPtrFactory<RevocableStrongBinding> weak_factory_;
+  base::WeakPtrFactory<RevocableStrongBinding> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(RevocableStrongBinding);
 };
diff --git a/third_party/blink/renderer/platform/scheduler/common/frame_or_worker_scheduler.cc b/third_party/blink/renderer/platform/scheduler/common/frame_or_worker_scheduler.cc
index f2c6488..ed9490ac 100644
--- a/third_party/blink/renderer/platform/scheduler/common/frame_or_worker_scheduler.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/frame_or_worker_scheduler.cc
@@ -43,7 +43,7 @@
   return *this;
 }
 
-FrameOrWorkerScheduler::FrameOrWorkerScheduler() : weak_factory_(this) {}
+FrameOrWorkerScheduler::FrameOrWorkerScheduler() {}
 
 FrameOrWorkerScheduler::~FrameOrWorkerScheduler() {
   weak_factory_.InvalidateWeakPtrs();
diff --git a/third_party/blink/renderer/platform/scheduler/common/idle_helper.cc b/third_party/blink/renderer/platform/scheduler/common/idle_helper.cc
index ead8dcd5..ff28ddb 100644
--- a/third_party/blink/renderer/platform/scheduler/common/idle_helper.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/idle_helper.cc
@@ -30,8 +30,7 @@
       state_(helper, delegate, idle_period_tracing_name),
       required_quiescence_duration_before_long_idle_period_(
           required_quiescence_duration_before_long_idle_period),
-      is_shutdown_(false),
-      weak_factory_(this) {
+      is_shutdown_(false) {
   weak_idle_helper_ptr_ = weak_factory_.GetWeakPtr();
   enable_next_long_idle_period_closure_.Reset(base::BindRepeating(
       &IdleHelper::EnableLongIdlePeriod, weak_idle_helper_ptr_));
diff --git a/third_party/blink/renderer/platform/scheduler/common/idle_helper.h b/third_party/blink/renderer/platform/scheduler/common/idle_helper.h
index 15fcdfc..9d48e10 100644
--- a/third_party/blink/renderer/platform/scheduler/common/idle_helper.h
+++ b/third_party/blink/renderer/platform/scheduler/common/idle_helper.h
@@ -239,7 +239,7 @@
   bool is_shutdown_;
 
   base::WeakPtr<IdleHelper> weak_idle_helper_ptr_;
-  base::WeakPtrFactory<IdleHelper> weak_factory_;
+  base::WeakPtrFactory<IdleHelper> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(IdleHelper);
 };
diff --git a/third_party/blink/renderer/platform/scheduler/common/post_cancellable_task.cc b/third_party/blink/renderer/platform/scheduler/common/post_cancellable_task.cc
index b32596e..fad56ee1 100644
--- a/third_party/blink/renderer/platform/scheduler/common/post_cancellable_task.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/post_cancellable_task.cc
@@ -12,8 +12,7 @@
 
 class TaskHandle::Runner : public WTF::ThreadSafeRefCounted<Runner> {
  public:
-  explicit Runner(base::OnceClosure task)
-      : task_(std::move(task)), weak_ptr_factory_(this) {}
+  explicit Runner(base::OnceClosure task) : task_(std::move(task)) {}
 
   base::WeakPtr<Runner> AsWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); }
 
@@ -50,7 +49,7 @@
 
  private:
   base::OnceClosure task_;
-  base::WeakPtrFactory<Runner> weak_ptr_factory_;
+  base::WeakPtrFactory<Runner> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(Runner);
 };
diff --git a/third_party/blink/renderer/platform/scheduler/common/post_cancellable_task_unittest.cc b/third_party/blink/renderer/platform/scheduler/common/post_cancellable_task_unittest.cc
index d1a8e56e..e66748b 100644
--- a/third_party/blink/renderer/platform/scheduler/common/post_cancellable_task_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/post_cancellable_task_unittest.cc
@@ -25,7 +25,7 @@
   DISALLOW_NEW();
 
  public:
-  CancellationTestHelper() : weak_ptr_factory_(this) {}
+  CancellationTestHelper() {}
 
   base::WeakPtr<CancellationTestHelper> GetWeakPtr() {
     return weak_ptr_factory_.GetWeakPtr();
@@ -37,7 +37,7 @@
 
  private:
   int counter_ = 0;
-  base::WeakPtrFactory<CancellationTestHelper> weak_ptr_factory_;
+  base::WeakPtrFactory<CancellationTestHelper> weak_ptr_factory_{this};
 };
 
 }  // namespace
diff --git a/third_party/blink/renderer/platform/scheduler/common/single_thread_idle_task_runner.cc b/third_party/blink/renderer/platform/scheduler/common/single_thread_idle_task_runner.cc
index 1f2ce23d..8cf52c3 100644
--- a/third_party/blink/renderer/platform/scheduler/common/single_thread_idle_task_runner.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/single_thread_idle_task_runner.cc
@@ -17,8 +17,7 @@
     Delegate* delegate)
     : idle_priority_task_runner_(idle_priority_task_runner),
       delegate_(delegate),
-      blame_context_(nullptr),
-      weak_factory_(this) {
+      blame_context_(nullptr) {
   DCHECK(!idle_priority_task_runner_ ||
          idle_priority_task_runner_->RunsTasksInCurrentSequence());
   weak_scheduler_ptr_ = weak_factory_.GetWeakPtr();
diff --git a/third_party/blink/renderer/platform/scheduler/common/single_thread_idle_task_runner.h b/third_party/blink/renderer/platform/scheduler/common/single_thread_idle_task_runner.h
index 5e779ae..8786cd5 100644
--- a/third_party/blink/renderer/platform/scheduler/common/single_thread_idle_task_runner.h
+++ b/third_party/blink/renderer/platform/scheduler/common/single_thread_idle_task_runner.h
@@ -109,7 +109,7 @@
   Delegate* delegate_;                              // NOT OWNED
   base::trace_event::BlameContext* blame_context_;  // Not owned.
   base::WeakPtr<SingleThreadIdleTaskRunner> weak_scheduler_ptr_;
-  base::WeakPtrFactory<SingleThreadIdleTaskRunner> weak_factory_;
+  base::WeakPtrFactory<SingleThreadIdleTaskRunner> weak_factory_{this};
   DISALLOW_COPY_AND_ASSIGN(SingleThreadIdleTaskRunner);
 };
 
diff --git a/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.cc b/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.cc
index f47ccc61..377e7fd 100644
--- a/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.cc
@@ -76,8 +76,7 @@
       tracing_controller_(tracing_controller),
       tick_clock_(thread_scheduler->GetTickClock()),
       time_domain_(new ThrottledTimeDomain()),
-      allow_throttling_(true),
-      weak_factory_(this) {
+      allow_throttling_(true) {
   pump_throttled_tasks_closure_.Reset(base::BindRepeating(
       &TaskQueueThrottler::PumpThrottledTasks, weak_factory_.GetWeakPtr()));
   forward_immediate_work_callback_ =
diff --git a/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h b/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h
index da09c62e..467f846 100644
--- a/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h
+++ b/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h
@@ -240,7 +240,7 @@
 
   std::unordered_map<BudgetPool*, std::unique_ptr<BudgetPool>> budget_pools_;
 
-  base::WeakPtrFactory<TaskQueueThrottler> weak_factory_;
+  base::WeakPtrFactory<TaskQueueThrottler> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(TaskQueueThrottler);
 };
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
index 39c9b8c2..57698cd 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
@@ -217,9 +217,7 @@
           "FrameScheduler.KeepActive",
           this,
           &tracing_controller_,
-          KeepActiveStateToString),
-      document_bound_weak_factory_(this),
-      weak_factory_(this) {
+          KeepActiveStateToString) {
   frame_task_queue_controller_.reset(
       new FrameTaskQueueController(main_thread_scheduler_, this, this));
 }
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h
index 3b437ae..30514c8 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h
@@ -339,9 +339,9 @@
 
   // TODO(altimin): Remove after we have have 1:1 relationship between frames
   // and documents.
-  base::WeakPtrFactory<FrameSchedulerImpl> document_bound_weak_factory_;
+  base::WeakPtrFactory<FrameSchedulerImpl> document_bound_weak_factory_{this};
 
-  base::WeakPtrFactory<FrameSchedulerImpl> weak_factory_;
+  base::WeakPtrFactory<FrameSchedulerImpl> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(FrameSchedulerImpl);
 };
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
index 41a68ff..709ba156 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
@@ -238,8 +238,7 @@
                         helper_.GetClock(),
                         helper_.NowTicks()),
       any_thread_(this),
-      policy_may_need_update_(&any_thread_lock_),
-      weak_factory_(this) {
+      policy_may_need_update_(&any_thread_lock_) {
   // Compositor task queue and default task queue should be managed by
   // WebThreadScheduler. Control task queue should not.
   task_runners_.insert(
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
index 13252ca..f12a061 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
@@ -967,7 +967,7 @@
 
   PollableThreadSafeFlag policy_may_need_update_;
 
-  base::WeakPtrFactory<MainThreadSchedulerImpl> weak_factory_;
+  base::WeakPtrFactory<MainThreadSchedulerImpl> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(MainThreadSchedulerImpl);
 };
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc
index 89e9366..fd145d4 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc
@@ -109,8 +109,7 @@
       queue_traits_(params.queue_traits),
       freeze_when_keep_active_(params.freeze_when_keep_active),
       main_thread_scheduler_(main_thread_scheduler),
-      frame_scheduler_(params.frame_scheduler),
-      weak_ptr_factory_(this) {
+      frame_scheduler_(params.frame_scheduler) {
   if (GetTaskQueueImpl() && spec.should_notify_observers) {
     // TaskQueueImpl may be null for tests.
     // TODO(scheduler-dev): Consider mapping directly to
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h
index 6fc2ae30..bbf4964 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h
@@ -362,7 +362,7 @@
 
   FrameSchedulerImpl* frame_scheduler_;  // NOT OWNED
 
-  base::WeakPtrFactory<MainThreadTaskQueue> weak_ptr_factory_;
+  base::WeakPtrFactory<MainThreadTaskQueue> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(MainThreadTaskQueue);
 };
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc
index 0ff968a..5d122d3 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc
@@ -155,8 +155,7 @@
       freeze_on_network_idle_enabled_(base::FeatureList::IsEnabled(
           blink::features::kFreezeBackgroundTabOnNetworkIdle)),
       delay_for_background_and_network_idle_tab_freezing_(
-          GetDelayForBackgroundAndNetworkIdleTabFreezing()),
-      weak_factory_(this) {
+          GetDelayForBackgroundAndNetworkIdleTabFreezing()) {
   page_lifecycle_state_tracker_.reset(new PageLifecycleStateTracker(
       this, kDefaultPageVisibility == PageVisibilityState::kVisible
                 ? PageLifecycleState::kActive
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h
index 90f7e696d..4de806f0 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h
@@ -265,7 +265,7 @@
   const base::TimeDelta delay_for_background_and_network_idle_tab_freezing_;
 
   std::unique_ptr<PageLifecycleStateTracker> page_lifecycle_state_tracker_;
-  base::WeakPtrFactory<PageSchedulerImpl> weak_factory_;
+  base::WeakPtrFactory<PageSchedulerImpl> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(PageSchedulerImpl);
 };
diff --git a/third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h b/third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h
index 0c5e756..3d08743 100644
--- a/third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h
+++ b/third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h
@@ -138,7 +138,7 @@
 
   // Observers are not owned by the scheduler.
   std::unordered_map<Observer*, ObserverType> lifecycle_observers_;
-  base::WeakPtrFactory<FrameOrWorkerScheduler> weak_factory_;
+  base::WeakPtrFactory<FrameOrWorkerScheduler> weak_factory_{this};
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/scheduler/public/worker_scheduler.h b/third_party/blink/renderer/platform/scheduler/public/worker_scheduler.h
index 2c2ab72..537458f 100644
--- a/third_party/blink/renderer/platform/scheduler/public/worker_scheduler.h
+++ b/third_party/blink/renderer/platform/scheduler/public/worker_scheduler.h
@@ -108,7 +108,7 @@
 
   bool is_disposed_ = false;
   uint32_t paused_count_ = 0;
-  base::WeakPtrFactory<WorkerScheduler> weak_factory_;
+  base::WeakPtrFactory<WorkerScheduler> weak_factory_{this};
 };
 
 }  // namespace scheduler
diff --git a/third_party/blink/renderer/platform/scheduler/test/fuzzer/thread_manager.cc b/third_party/blink/renderer/platform/scheduler/test/fuzzer/thread_manager.cc
index 8b3b570..7265f0f 100644
--- a/third_party/blink/renderer/platform/scheduler/test/fuzzer/thread_manager.cc
+++ b/third_party/blink/renderer/platform/scheduler/test/fuzzer/thread_manager.cc
@@ -408,9 +408,7 @@
 }
 
 ThreadManager::Task::Task(ThreadManager* thread_manager)
-    : is_running_(false),
-      thread_manager_(thread_manager),
-      weak_ptr_factory_(this) {
+    : is_running_(false), thread_manager_(thread_manager) {
   DCHECK(thread_manager_);
 }
 
diff --git a/third_party/blink/renderer/platform/scheduler/test/fuzzer/thread_manager.h b/third_party/blink/renderer/platform/scheduler/test/fuzzer/thread_manager.h
index 831b8cf..b0c52af5 100644
--- a/third_party/blink/renderer/platform/scheduler/test/fuzzer/thread_manager.h
+++ b/third_party/blink/renderer/platform/scheduler/test/fuzzer/thread_manager.h
@@ -77,7 +77,7 @@
 
     // Should outlive |this|.
     ThreadManager* thread_manager_;
-    base::WeakPtrFactory<Task> weak_ptr_factory_;
+    base::WeakPtrFactory<Task> weak_ptr_factory_{this};
   };
 
   void RunAction(const SequenceManagerTestDescription::Action& action);
diff --git a/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler.cc b/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler.cc
index a4b6cfc..accdcb6 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler.cc
+++ b/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler.cc
@@ -31,8 +31,7 @@
           worker_thread_scheduler->CreateTaskQueue("worker_pausable_tq")),
       unpausable_task_queue_(
           worker_thread_scheduler->CreateTaskQueue("worker_unpausable_tq")),
-      thread_scheduler_(worker_thread_scheduler),
-      weak_factory_(this) {
+      thread_scheduler_(worker_thread_scheduler) {
   task_runners_.insert(
       std::make_pair(throttleable_task_queue_,
                      throttleable_task_queue_->CreateQueueEnabledVoter()));
diff --git a/third_party/blink/renderer/platform/testing/code_cache_loader_mock.h b/third_party/blink/renderer/platform/testing/code_cache_loader_mock.h
index c45598f..391a41bbe 100644
--- a/third_party/blink/renderer/platform/testing/code_cache_loader_mock.h
+++ b/third_party/blink/renderer/platform/testing/code_cache_loader_mock.h
@@ -14,7 +14,7 @@
 // A simple class for mocking CodeCacheLoader.
 class CodeCacheLoaderMock : public CodeCacheLoader {
  public:
-  CodeCacheLoaderMock() : weak_ptr_factory_(this) {}
+  CodeCacheLoaderMock() {}
   ~CodeCacheLoaderMock() override = default;
 
   // CodeCacheLoader methods:
@@ -29,7 +29,7 @@
   base::WeakPtr<CodeCacheLoaderMock> GetWeakPtr();
 
  private:
-  base::WeakPtrFactory<CodeCacheLoaderMock> weak_ptr_factory_;
+  base::WeakPtrFactory<CodeCacheLoaderMock> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(CodeCacheLoaderMock);
 };
diff --git a/third_party/blink/renderer/platform/testing/weburl_loader_mock.cc b/third_party/blink/renderer/platform/testing/weburl_loader_mock.cc
index ba7eb0b..cb9e49c 100644
--- a/third_party/blink/renderer/platform/testing/weburl_loader_mock.cc
+++ b/third_party/blink/renderer/platform/testing/weburl_loader_mock.cc
@@ -32,9 +32,7 @@
 
 WebURLLoaderMock::WebURLLoaderMock(WebURLLoaderMockFactoryImpl* factory,
                                    std::unique_ptr<WebURLLoader> default_loader)
-    : factory_(factory),
-      default_loader_(std::move(default_loader)),
-      weak_factory_(this) {}
+    : factory_(factory), default_loader_(std::move(default_loader)) {}
 
 WebURLLoaderMock::~WebURLLoaderMock() {
   Cancel();
diff --git a/third_party/blink/renderer/platform/testing/weburl_loader_mock.h b/third_party/blink/renderer/platform/testing/weburl_loader_mock.h
index 999ecb5..e5e74f8 100644
--- a/third_party/blink/renderer/platform/testing/weburl_loader_mock.h
+++ b/third_party/blink/renderer/platform/testing/weburl_loader_mock.h
@@ -74,7 +74,7 @@
   bool using_default_loader_ = false;
   bool is_deferred_ = false;
 
-  base::WeakPtrFactory<WebURLLoaderMock> weak_factory_;
+  base::WeakPtrFactory<WebURLLoaderMock> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(WebURLLoaderMock);
 };
diff --git a/third_party/blink/renderer/platform/timer.cc b/third_party/blink/renderer/platform/timer.cc
index 5d55cbb..a1d92dc 100644
--- a/third_party/blink/renderer/platform/timer.cc
+++ b/third_party/blink/renderer/platform/timer.cc
@@ -37,11 +37,12 @@
 
 TimerBase::TimerBase(
     scoped_refptr<base::SingleThreadTaskRunner> web_task_runner)
-    : web_task_runner_(std::move(web_task_runner)),
+    : web_task_runner_(std::move(web_task_runner))
 #if DCHECK_IS_ON()
-      thread_(CurrentThread()),
+      ,
+      thread_(CurrentThread())
 #endif
-      weak_ptr_factory_(this) {
+{
 }
 
 TimerBase::~TimerBase() {
diff --git a/third_party/blink/renderer/platform/timer.h b/third_party/blink/renderer/platform/timer.h
index 3747294..a00de93c 100644
--- a/third_party/blink/renderer/platform/timer.h
+++ b/third_party/blink/renderer/platform/timer.h
@@ -105,7 +105,7 @@
 #if DCHECK_IS_ON()
   base::PlatformThreadId thread_;
 #endif
-  base::WeakPtrFactory<TimerBase> weak_ptr_factory_;
+  base::WeakPtrFactory<TimerBase> weak_ptr_factory_{this};
 
   friend class ThreadTimers;
   friend class TimerHeapLessThanFunction;
diff --git a/third_party/blink/renderer/platform/wtf/functional_test.cc b/third_party/blink/renderer/platform/wtf/functional_test.cc
index 96b1902..d74ee9c5 100644
--- a/third_party/blink/renderer/platform/wtf/functional_test.cc
+++ b/third_party/blink/renderer/platform/wtf/functional_test.cc
@@ -52,7 +52,7 @@
 
 class HasWeakPtrSupport {
  public:
-  HasWeakPtrSupport() : weak_ptr_factory_(this) {}
+  HasWeakPtrSupport() {}
 
   base::WeakPtr<HasWeakPtrSupport> GetWeakPtr() {
     return weak_ptr_factory_.GetWeakPtr();
@@ -63,7 +63,7 @@
   void Increment(int* counter) { ++*counter; }
 
  private:
-  base::WeakPtrFactory<HasWeakPtrSupport> weak_ptr_factory_;
+  base::WeakPtrFactory<HasWeakPtrSupport> weak_ptr_factory_{this};
 };
 
 }  // namespace WTF
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
index 76a9062e..d82a12ee 100755
--- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
+++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -649,6 +649,19 @@
     },
     {
         'paths': [
+            'third_party/blink/renderer/modules/webrtc/',
+        ],
+        'allowed': [
+            'base::AutoLock',
+            'base::Erase',
+            'base::StringPrintf',
+            'media::.+',
+            'rtc::scoped_refptr',
+            'webrtc::AudioSourceInterface',
+        ]
+    },
+    {
+        'paths': [
             'third_party/blink/renderer/platform/',
         ],
         # Suppress almost all checks on platform since code in this directory is
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 1456aa35..e07bd0c 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -581,7 +581,6 @@
 crbug.com/955170 external/wpt/css/css-contain/contain-size-replaced-003a.html [ Failure ]
 crbug.com/955163 external/wpt/css/css-contain/contain-size-replaced-003b.html [ Failure ]
 crbug.com/955163 external/wpt/css/css-contain/contain-size-replaced-003c.html [ Failure ]
-crbug.com/869296 external/wpt/css/css-contain/contain-style-counters-004.html [ Failure ]
 crbug.com/882383 external/wpt/css/css-contain/counter-scoping-001.html [ Failure ]
 crbug.com/882383 external/wpt/css/css-contain/counter-scoping-002.html [ Failure ]
 crbug.com/882383 external/wpt/css/css-contain/counter-scoping-003.html [ Failure ]
@@ -606,7 +605,6 @@
 crbug.com/955170 virtual/layout_ng_experimental/external/wpt/css/css-contain/contain-size-replaced-003a.html [ Failure ]
 crbug.com/955163 virtual/layout_ng_experimental/external/wpt/css/css-contain/contain-size-replaced-003b.html [ Failure ]
 crbug.com/955163 virtual/layout_ng_experimental/external/wpt/css/css-contain/contain-size-replaced-003c.html [ Failure ]
-crbug.com/869296 virtual/layout_ng_experimental/external/wpt/css/css-contain/contain-style-counters-004.html [ Failure ]
 crbug.com/882383 virtual/layout_ng_experimental/external/wpt/css/css-contain/counter-scoping-001.html [ Failure ]
 crbug.com/882383 virtual/layout_ng_experimental/external/wpt/css/css-contain/counter-scoping-002.html [ Failure ]
 crbug.com/882383 virtual/layout_ng_experimental/external/wpt/css/css-contain/counter-scoping-003.html [ Failure ]
@@ -2707,11 +2705,6 @@
 crbug.com/715148 external/wpt/pointerevents/pointerevent_touch-action-rotated-divs_touch-manual.html  [ Skip ]
 
 # Disabled until v8 roll.
-crbug.com/980917 fast/events/window-onerror-03.html [ Skip ]
-crbug.com/980917 fast/js/assign.html [ Skip ]
-crbug.com/980917 fast/js/postfix-syntax.html [ Skip ]
-crbug.com/980917 fast/js/prefix-syntax.html [ Skip ]
-crbug.com/980917 virtual/mouseevent_fractional/fast/events/window-onerror-03.html [ Skip ]
 crbug.com/906847 inspector-protocol/runtime/runtime-getProperties.js [ Skip ]
 crbug.com/906847 inspector-protocol/debugger/debugger-scope-skip-variables-with-empty-name.js [ Skip ]
 crbug.com/v8/8672 http/tests/devtools/bindings/suspendtarget-bindings.js [ Skip ]
@@ -6266,3 +6259,8 @@
 crbug.com/981331 fast/forms/form-submission-create-crash.xhtml [ Pass Timeout ]
 # TODO(crbug.com/980588): reenable once WPT is fixed
 crbug.com/980588 external/wpt/screen-orientation/lock-unlock-check.html [ Pass Failure ]
+
+# TODO (michaelludwig) - Rebaseline for Skia roll
+crbug.com/981879 virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-png.html [ Pass Failure ]
+crbug.com/981879 virtual/gpu-rasterization/images/color-profile-background-image-cross-fade.html [ Pass Failure ]
+crbug.com/981879 virtual/gpu-rasterization/images/cross-fade-background-size.html [ Pass Failure ]
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 048dc368..c11970a 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
@@ -132500,6 +132500,18 @@
    "css/css-fonts/math-script-level-and-math-style/math-script-level-font-size-clamping-001.tentative-ref.html": [
     []
    ],
+   "css/css-fonts/parsing/font-synthesis-computed-expected.txt": [
+    []
+   ],
+   "css/css-fonts/parsing/font-synthesis-valid-expected.txt": [
+    []
+   ],
+   "css/css-fonts/parsing/font-variant-position-computed-expected.txt": [
+    []
+   ],
+   "css/css-fonts/parsing/font-variant-position-valid-expected.txt": [
+    []
+   ],
    "css/css-fonts/quoted-generic-ignored-ref.html": [
     []
    ],
@@ -167378,6 +167390,18 @@
    "signed-exchange/resources/sxg-navigation-timing.html": [
     []
    ],
+   "signed-exchange/resources/sxg-subresource-iframe.html": [
+    []
+   ],
+   "signed-exchange/resources/sxg-subresource-script-inner.js": [
+    []
+   ],
+   "signed-exchange/resources/sxg-subresource-script.js": [
+    []
+   ],
+   "signed-exchange/resources/sxg-subresource-sxg-inner.html": [
+    []
+   ],
    "signed-exchange/resources/sxg-util.js": [
     []
    ],
@@ -167471,6 +167495,15 @@
    "signed-exchange/resources/sxg/sxg-referrer-same-origin.sxg": [
     []
    ],
+   "signed-exchange/resources/sxg/sxg-subresource-script.sxg": [
+    []
+   ],
+   "signed-exchange/resources/sxg/sxg-subresource.sxg": [
+    []
+   ],
+   "signed-exchange/resources/sxg/sxg-subresource.sxg.sub.headers": [
+    []
+   ],
    "signed-exchange/resources/sxg/sxg-utf8-inner-url.sxg": [
     []
    ],
@@ -167492,6 +167525,9 @@
    "signed-exchange/service-workers/sxg-sw-register.tentative.https-expected.txt": [
     []
    ],
+   "signed-exchange/subresource/sxg-subresource.tentative-expected.txt": [
+    []
+   ],
    "sms/resources/iframe.html": [
     []
    ],
@@ -198898,6 +198934,12 @@
      {}
     ]
    ],
+   "css/css-backgrounds/parsing/box-shadow-computed.html": [
+    [
+     "css/css-backgrounds/parsing/box-shadow-computed.html",
+     {}
+    ]
+   ],
    "css/css-backgrounds/parsing/box-shadow-invalid.html": [
     [
      "css/css-backgrounds/parsing/box-shadow-invalid.html",
@@ -200352,6 +200394,60 @@
      {}
     ]
    ],
+   "css/css-fonts/parsing/font-size-adjust-computed.html": [
+    [
+     "css/css-fonts/parsing/font-size-adjust-computed.html",
+     {}
+    ]
+   ],
+   "css/css-fonts/parsing/font-size-adjust-invalid.html": [
+    [
+     "css/css-fonts/parsing/font-size-adjust-invalid.html",
+     {}
+    ]
+   ],
+   "css/css-fonts/parsing/font-size-adjust-valid.html": [
+    [
+     "css/css-fonts/parsing/font-size-adjust-valid.html",
+     {}
+    ]
+   ],
+   "css/css-fonts/parsing/font-synthesis-computed.html": [
+    [
+     "css/css-fonts/parsing/font-synthesis-computed.html",
+     {}
+    ]
+   ],
+   "css/css-fonts/parsing/font-synthesis-invalid.html": [
+    [
+     "css/css-fonts/parsing/font-synthesis-invalid.html",
+     {}
+    ]
+   ],
+   "css/css-fonts/parsing/font-synthesis-valid.html": [
+    [
+     "css/css-fonts/parsing/font-synthesis-valid.html",
+     {}
+    ]
+   ],
+   "css/css-fonts/parsing/font-variant-position-computed.html": [
+    [
+     "css/css-fonts/parsing/font-variant-position-computed.html",
+     {}
+    ]
+   ],
+   "css/css-fonts/parsing/font-variant-position-invalid.html": [
+    [
+     "css/css-fonts/parsing/font-variant-position-invalid.html",
+     {}
+    ]
+   ],
+   "css/css-fonts/parsing/font-variant-position-valid.html": [
+    [
+     "css/css-fonts/parsing/font-variant-position-valid.html",
+     {}
+    ]
+   ],
    "css/css-fonts/test_datafont_same_origin.html": [
     [
      "css/css-fonts/test_datafont_same_origin.html",
@@ -210726,6 +210822,12 @@
      {}
     ]
    ],
+   "css/css-ui/parsing/caret-color-computed.html": [
+    [
+     "css/css-ui/parsing/caret-color-computed.html",
+     {}
+    ]
+   ],
    "css/css-ui/parsing/caret-color-invalid.html": [
     [
      "css/css-ui/parsing/caret-color-invalid.html",
@@ -210756,6 +210858,12 @@
      {}
     ]
    ],
+   "css/css-ui/parsing/outline-color-computed.html": [
+    [
+     "css/css-ui/parsing/outline-color-computed.html",
+     {}
+    ]
+   ],
    "css/css-ui/parsing/outline-color-invalid.html": [
     [
      "css/css-ui/parsing/outline-color-invalid.html",
@@ -277790,6 +277898,12 @@
      {}
     ]
    ],
+   "signed-exchange/subresource/sxg-subresource.tentative.html": [
+    [
+     "signed-exchange/subresource/sxg-subresource.tentative.html",
+     {}
+    ]
+   ],
    "signed-exchange/sxg-data-cert-url.tentative.html": [
     [
      "signed-exchange/sxg-data-cert-url.tentative.html",
@@ -343333,6 +343447,10 @@
    "552416df3d2fe1a08aeb8145c5d263770543aa5e",
    "testharness"
   ],
+  "css/css-backgrounds/parsing/box-shadow-computed.html": [
+   "5d268bf3fd2347d3da641f1354179157b4a96c91",
+   "testharness"
+  ],
   "css/css-backgrounds/parsing/box-shadow-invalid.html": [
    "44f074d05a85fbdf183544da5c6fb5af075ea8da",
    "testharness"
@@ -351737,6 +351855,58 @@
    "56cb1eca09d7741275df03ea217e2b31acb04371",
    "testharness"
   ],
+  "css/css-fonts/parsing/font-size-adjust-computed.html": [
+   "601e22ee0d13510b8a75ee36afbd508773836b0a",
+   "testharness"
+  ],
+  "css/css-fonts/parsing/font-size-adjust-invalid.html": [
+   "8e83052eb0608c68d6a1fce15ac773e84e52fddd",
+   "testharness"
+  ],
+  "css/css-fonts/parsing/font-size-adjust-valid.html": [
+   "1e4d0aebe1147beba0ce37e2773125a0b742501e",
+   "testharness"
+  ],
+  "css/css-fonts/parsing/font-synthesis-computed-expected.txt": [
+   "e0da8b22288a50a27c2c6ded29625c953a5e7335",
+   "support"
+  ],
+  "css/css-fonts/parsing/font-synthesis-computed.html": [
+   "933a879bfb619626dcded25b99072cac0e477de2",
+   "testharness"
+  ],
+  "css/css-fonts/parsing/font-synthesis-invalid.html": [
+   "adbe9c0236d0d150950b627fd0cba0e734d0e9ab",
+   "testharness"
+  ],
+  "css/css-fonts/parsing/font-synthesis-valid-expected.txt": [
+   "ec33e3ad7531c0c0445f1a728fcfe349de6dc273",
+   "support"
+  ],
+  "css/css-fonts/parsing/font-synthesis-valid.html": [
+   "1d1aa5d29974125dc119223233f237ba4925e699",
+   "testharness"
+  ],
+  "css/css-fonts/parsing/font-variant-position-computed-expected.txt": [
+   "ea96d5585016616586257e1c6cf00f20e362970a",
+   "support"
+  ],
+  "css/css-fonts/parsing/font-variant-position-computed.html": [
+   "f11c0f6ab972a5121b761cdd416cef827814cbe8",
+   "testharness"
+  ],
+  "css/css-fonts/parsing/font-variant-position-invalid.html": [
+   "11110ce53b433595b4aa40ffb580068b1726a910",
+   "testharness"
+  ],
+  "css/css-fonts/parsing/font-variant-position-valid-expected.txt": [
+   "7058ebb9724e06178ec5b3261f8cef93cefaca71",
+   "support"
+  ],
+  "css/css-fonts/parsing/font-variant-position-valid.html": [
+   "3887ab0cc4b59024544338d2338c3a723fe3b625",
+   "testharness"
+  ],
   "css/css-fonts/quoted-generic-ignored-ref.html": [
    "70e2d50cd83f61017f0f22da14065c7afa76e1d1",
    "support"
@@ -387845,6 +388015,10 @@
    "3dfa4f979419af8ced63af5aa73c32ea68d11095",
    "testharness"
   ],
+  "css/css-ui/parsing/caret-color-computed.html": [
+   "0428c783f5b0b0efc664d18529f8cae22acf72e2",
+   "testharness"
+  ],
   "css/css-ui/parsing/caret-color-invalid.html": [
    "a59b01ec2bb6d2ada5acef7ac7ec68417d79fa03",
    "testharness"
@@ -387865,6 +388039,10 @@
    "285c16a4ee513b898d9d1c2852ae40897bb12545",
    "testharness"
   ],
+  "css/css-ui/parsing/outline-color-computed.html": [
+   "b9aab1d230a226e64cd5be736091d6ffaf1d003c",
+   "testharness"
+  ],
   "css/css-ui/parsing/outline-color-invalid.html": [
    "2b910e803038e3c9892a7e3ee09473a410d84465",
    "testharness"
@@ -467870,7 +468048,7 @@
    "support"
   ],
   "signed-exchange/resources/generate-test-sxgs.sh": [
-   "16750f25438a52d4cbe74ea98827bb1743ca37ac",
+   "81a5e043469c5586a49326ac72896c15c7520508",
    "support"
   ],
   "signed-exchange/resources/inner-url.html": [
@@ -467905,6 +468083,22 @@
    "ddbe3503548ae2915253ad1f0ccc62d4278bf17a",
    "support"
   ],
+  "signed-exchange/resources/sxg-subresource-iframe.html": [
+   "bd812857b46a24a69d1c7bb76917fad2e03e4342",
+   "support"
+  ],
+  "signed-exchange/resources/sxg-subresource-script-inner.js": [
+   "dcc7a356a0a222b3cf4064f2aeb5a40c9a209338",
+   "support"
+  ],
+  "signed-exchange/resources/sxg-subresource-script.js": [
+   "c730568fcfa9393c7807e9c5d41ded2d59f394b7",
+   "support"
+  ],
+  "signed-exchange/resources/sxg-subresource-sxg-inner.html": [
+   "9dfff56ad8fced46ee816fc2239ab9efb1560761",
+   "support"
+  ],
   "signed-exchange/resources/sxg-util.js": [
    "78edf137408f93150209f76b6e492d13805ca95a",
    "support"
@@ -468029,6 +468223,18 @@
    "cc7793efa287b21d10c8c92dcd371a7938b31686",
    "support"
   ],
+  "signed-exchange/resources/sxg/sxg-subresource-script.sxg": [
+   "6a6f37e781865db4aaf801ff6ffef1da96f7a33c",
+   "support"
+  ],
+  "signed-exchange/resources/sxg/sxg-subresource.sxg": [
+   "05be42adcc164ad51af413da3745566588cb8ece",
+   "support"
+  ],
+  "signed-exchange/resources/sxg/sxg-subresource.sxg.sub.headers": [
+   "8bc3938df8ac90e655b3aa6aeb342cd092ccc9b1",
+   "support"
+  ],
   "signed-exchange/resources/sxg/sxg-utf8-inner-url.sxg": [
    "3edf285f1bd5affc5c575ca258a8cd3cfa546e35",
    "support"
@@ -468065,6 +468271,14 @@
    "ad21ebb20d44c846bd99cbffeb510c8af2bb81ea",
    "testharness"
   ],
+  "signed-exchange/subresource/sxg-subresource.tentative-expected.txt": [
+   "ee54a8ceeb96b741fd720f2304fc7909c2d41ec3",
+   "support"
+  ],
+  "signed-exchange/subresource/sxg-subresource.tentative.html": [
+   "8ca12b4cbcf3c0950c04deed96e7174247444a25",
+   "testharness"
+  ],
   "signed-exchange/sxg-data-cert-url.tentative.html": [
    "0d6bd5602e0ca0e6610b9fe2fb48b94fd5821bfd",
    "testharness"
diff --git a/third_party/blink/web_tests/external/wpt/bluetooth/README.md b/third_party/blink/web_tests/external/wpt/bluetooth/README.md
index 2d0e9ab..dcf3d283 100644
--- a/third_party/blink/web_tests/external/wpt/bluetooth/README.md
+++ b/third_party/blink/web_tests/external/wpt/bluetooth/README.md
@@ -24,9 +24,9 @@
 
 [Web Bluetooth Testing API]: https://docs.google.com/document/d/1Nhv_oVDCodd1pEH_jj9k8gF4rPGb_84VYaZ9IG8M_WY/
 
-# Generated gen-* files from generator.py
+# Generated gen-* files from generate.py
 
-`generator.py` builds `gen-*.html` tests using templates in
+`generate.py` builds `gen-*.html` tests using templates in
 `script-tests/*/*.js`.
 
 The subdirectory structure in `bluetooth/script-test/*` is recreated into
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/box-shadow-computed.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/box-shadow-computed.html
new file mode 100644
index 0000000..5d268bf
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/box-shadow-computed.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Backgrounds and Borders Module Level 3: getComputedStyle().boxShadow</title>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds/#box-shadow">
+<meta name="assert" content="box-shadow computes to none or a list.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<style>
+  #target {
+    color: blue;
+    font-size: 20px;
+  }
+</style>
+</head>
+<body>
+<div id="target"></div>
+<script>
+'use strict';
+const currentColor = 'rgb(0, 0, 255)';
+test_computed_value('box-shadow', 'none');
+test_computed_value('box-shadow', '1px 2px', currentColor + ' 1px 2px 0px 0px');
+test_computed_value('box-shadow', 'currentcolor -1em -2em 3em -4em', currentColor + ' -20px -40px 60px -80px');
+test_computed_value('box-shadow', 'rgb(0, 255, 0) 1px 2px 3px 4px inset');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/contain-style-counters-004.html b/third_party/blink/web_tests/external/wpt/css/css-contain/contain-style-counters-004.html
index e0e0528..4a366e3 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-contain/contain-style-counters-004.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/contain-style-counters-004.html
@@ -6,7 +6,7 @@
 
   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
   <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-style">
-  <link rel="match" href="reference/contain-style-counters-003-ref.html">
+  <link rel="match" href="reference/contain-style-counters-004-ref.html">
 
   <meta name="flags" content="">
 
@@ -63,8 +63,10 @@
 
   <p> <span></span> <span></span> <span></span> <span></span>
 
-  <!-- 4 span inside the <p> -->
+  <!-- 4 span inside the <p>. However, since div isn't a sibling of spans,
+       it creates a new counter.
+  -->
 
-  <p>Test passes if there is the number 20.
+  <p>Test passes if there is the number 0.
 
   <div></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/reference/contain-style-counters-004-ref.html b/third_party/blink/web_tests/external/wpt/css/css-contain/reference/contain-style-counters-004-ref.html
new file mode 100644
index 0000000..afe60666
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/reference/contain-style-counters-004-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Reference Test</title>
+
+  <link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+
+  <style>
+  div
+    {
+      font-size: 3em;
+    }
+  </style>
+
+  <p>Test passes if there is the number 0.
+
+  <div>0</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/inheritance-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-fonts/inheritance-expected.txt
new file mode 100644
index 0000000..069790b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/inheritance-expected.txt
@@ -0,0 +1,33 @@
+This is a testharness.js-based test.
+PASS Property font-family has initial value "times new roman"
+PASS Property font-family inherits
+PASS Property font-feature-settings has initial value normal
+PASS Property font-feature-settings inherits
+PASS Property font-kerning has initial value auto
+PASS Property font-kerning inherits
+PASS Property font-size has initial value 16px
+PASS Property font-size inherits
+PASS Property font-size-adjust has initial value none
+PASS Property font-size-adjust inherits
+PASS Property font-stretch has initial value 100%
+PASS Property font-stretch inherits
+PASS Property font-style has initial value normal
+PASS Property font-style inherits
+FAIL Property font-synthesis has initial value weight style assert_true: font-synthesis doesn't seem to be supported in the computed style expected true got false
+FAIL Property font-synthesis inherits assert_true: font-synthesis doesn't seem to be supported in the computed style expected true got false
+PASS Property font-variant has initial value normal
+PASS Property font-variant inherits
+PASS Property font-variant-caps has initial value normal
+PASS Property font-variant-caps inherits
+PASS Property font-variant-east-asian has initial value normal
+PASS Property font-variant-east-asian inherits
+PASS Property font-variant-ligatures has initial value normal
+PASS Property font-variant-ligatures inherits
+PASS Property font-variant-numeric has initial value normal
+PASS Property font-variant-numeric inherits
+FAIL Property font-variant-position has initial value normal assert_true: font-variant-position doesn't seem to be supported in the computed style expected true got false
+FAIL Property font-variant-position inherits assert_true: font-variant-position doesn't seem to be supported in the computed style expected true got false
+PASS Property font-weight has initial value 400
+PASS Property font-weight inherits
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/inheritance.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/inheritance.html
new file mode 100644
index 0000000..8ff02fb
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/inheritance.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Inheritance of CSS Fonts Level 3 properties</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#property-index">
+<link rel="help" href="https://www.w3.org/TR/css-fonts-4/#font-stretch-prop">
+<meta name="assert" content="Properties inherit according to the spec.">
+<meta name="assert" content="Properties have initial values according to the spec.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/inheritance-testcommon.js"></script>
+<style>
+  #box {
+    font: initial;
+    font-size: medium;
+  }
+</style>
+</head>
+<body>
+<div id="box"></div>
+<div id="container">
+  <div id="target"></div>
+</div>
+<script>
+'use strict';
+const box = document.getElementById('box');
+const initialFontFamily = getComputedStyle(box).fontFamily;
+const mediumFontSize = getComputedStyle(box).fontSize;
+
+assert_inherited('font-family', initialFontFamily, '"Not Initial!"');
+assert_inherited('font-feature-settings', 'normal', '"smcp", "swsh" 2');
+assert_inherited('font-kerning', 'auto', 'none');
+assert_inherited('font-size', mediumFontSize /* medium */, '123px');
+assert_inherited('font-size-adjust', 'none', '1.5');
+assert_inherited('font-stretch', '100%' /* normal */, '75%');
+assert_inherited('font-style', 'normal', 'italic');
+assert_inherited('font-synthesis', 'weight style', 'none');
+assert_inherited('font-variant', 'normal', 'none');
+assert_inherited('font-variant-caps', 'normal', 'small-caps');
+assert_inherited('font-variant-east-asian', 'normal', 'ruby');
+assert_inherited('font-variant-ligatures', 'normal', 'none');
+assert_inherited('font-variant-numeric', 'normal', 'ordinal');
+assert_inherited('font-variant-position', 'normal', 'super');
+assert_inherited('font-weight', '400' /* normal */, '900');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-family-computed-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-family-computed-expected.txt
new file mode 100644
index 0000000..c937bbbe
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-family-computed-expected.txt
@@ -0,0 +1,13 @@
+This is a testharness.js-based test.
+PASS Property font-family value 'serif' computes to 'serif'
+PASS Property font-family value 'sans-serif' computes to 'sans-serif'
+PASS Property font-family value 'cursive' computes to 'cursive'
+PASS Property font-family value 'fantasy' computes to 'fantasy'
+PASS Property font-family value 'monospace' computes to 'monospace'
+PASS Property font-family value 'serif, sans-serif, cursive, fantasy, monospace' computes to 'serif, sans-serif, cursive, fantasy, monospace'
+PASS Property font-family value 'Helvetica, Verdana, sans-serif' computes to 'Helvetica, Verdana, sans-serif'
+PASS Property font-family value '"New Century Schoolbook", serif' computes to '"New Century Schoolbook", serif'
+PASS Property font-family value '"21st Century", fantasy' computes to '"21st Century", fantasy'
+FAIL Property font-family value '"inherit", "serif"' computes to '"inherit", "serif"' assert_equals: expected "\"inherit\", \"serif\"" but got "inherit, serif"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-family-computed.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-family-computed.html
new file mode 100644
index 0000000..993b72e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-family-computed.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: getComputedValue().fontFamily</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-family-prop">
+<meta name="assert" content="font-family computed value is as specified.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value('font-family', 'serif');
+test_computed_value('font-family', 'sans-serif');
+test_computed_value('font-family', 'cursive');
+test_computed_value('font-family', 'fantasy');
+test_computed_value('font-family', 'monospace');
+test_computed_value('font-family', 'serif, sans-serif, cursive, fantasy, monospace');
+
+test_computed_value('font-family', 'Helvetica, Verdana, sans-serif');
+test_computed_value('font-family', '"New Century Schoolbook", serif');
+test_computed_value('font-family', '"21st Century", fantasy');
+
+test_computed_value('font-family', '"inherit", "serif"');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-family-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-family-invalid.html
new file mode 100644
index 0000000..f4403e7e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-family-invalid.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: parsing font-family with invalid values</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-family-prop">
+<meta name="assert" content="font-family supports only the grammar '[ <family-name> | <generic-family> ] #'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_invalid_value('font-family', 'cursive serif');
+
+test_invalid_value('font-family', 'Red/Black, sans-serif');
+test_invalid_value('font-family', '"Lucida" Grande, sans-serif');
+test_invalid_value('font-family', 'Ahem!, sans-serif');
+test_invalid_value('font-family', 'test@foo, sans-serif');
+test_invalid_value('font-family', '#POUND, sans-serif');
+test_invalid_value('font-family', 'Hawaii 5-0, sans-serif');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-family-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-family-valid-expected.txt
new file mode 100644
index 0000000..30d61bea
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-family-valid-expected.txt
@@ -0,0 +1,13 @@
+This is a testharness.js-based test.
+PASS e.style['font-family'] = "Serif" should set the property value
+PASS e.style['font-family'] = "Sans-Serif" should set the property value
+PASS e.style['font-family'] = "Cursive" should set the property value
+PASS e.style['font-family'] = "Fantasy" should set the property value
+PASS e.style['font-family'] = "Monospace" should set the property value
+PASS e.style['font-family'] = "serif, sans-serif, cursive, fantasy, monospace" should set the property value
+PASS e.style['font-family'] = "Helvetica, Verdana, sans-serif" should set the property value
+PASS e.style['font-family'] = "\"New Century Schoolbook\", serif" should set the property value
+PASS e.style['font-family'] = "'21st Century', fantasy" should set the property value
+FAIL e.style['font-family'] = "\"inherit\", \"serif\"" should set the property value assert_equals: serialization should be canonical expected "\"inherit\", \"serif\"" but got "inherit, serif"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-family-valid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-family-valid.html
new file mode 100644
index 0000000..2dafcc6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-family-valid.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: parsing font-family with valid values</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-family-prop">
+<meta name="assert" content="font-family supports the full grammar '[ <family-name> | <generic-family> ] #'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_valid_value('font-family', 'Serif', 'serif');
+test_valid_value('font-family', 'Sans-Serif', 'sans-serif');
+test_valid_value('font-family', 'Cursive', 'cursive');
+test_valid_value('font-family', 'Fantasy', 'fantasy');
+test_valid_value('font-family', 'Monospace', 'monospace');
+test_valid_value('font-family', 'serif, sans-serif, cursive, fantasy, monospace');
+
+test_valid_value('font-family', 'Helvetica, Verdana, sans-serif');
+test_valid_value('font-family', '"New Century Schoolbook", serif');
+test_valid_value('font-family', "'21st Century', fantasy", '"21st Century", fantasy');
+
+test_valid_value('font-family', '"inherit", "serif"');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-feature-settings-computed.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-feature-settings-computed.html
new file mode 100644
index 0000000..137d9dbb
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-feature-settings-computed.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: getComputedValue().fontFeatureSettings</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-feature-settings-prop">
+<meta name="assert" content="font-feature-settings computed value is as specified.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value('font-feature-settings', 'normal');
+
+test_computed_value('font-feature-settings', '"dlig"');
+test_computed_value('font-feature-settings', '"smcp"');
+test_computed_value('font-feature-settings', '"c2sc"');
+test_computed_value('font-feature-settings', '"liga" 0');
+test_computed_value('font-feature-settings', '"tnum", "hist"');
+
+test_computed_value('font-feature-settings', '"PKRN"');
+
+test_computed_value('font-feature-settings', '"dlig", "smcp", "dlig" 0');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-feature-settings-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-feature-settings-invalid.html
new file mode 100644
index 0000000..37689ce7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-feature-settings-invalid.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: parsing font-feature-settings with invalid values</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-feature-settings-prop">
+<meta name="assert" content="font-feature-settings supports only the grammar 'normal | <feature-tag-value> #'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_invalid_value('font-feature-settings', 'normal "dlig"');
+test_invalid_value('font-feature-settings', '"c2sc", normal');
+
+test_invalid_value('font-feature-settings', '"tnum" "hist"');
+test_invalid_value('font-feature-settings', '"silly" off');
+
+test_invalid_value('font-feature-settings', 'dlig');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-feature-settings-valid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-feature-settings-valid.html
new file mode 100644
index 0000000..9ed4b5c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-feature-settings-valid.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: parsing font-feature-settings with valid values</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-feature-settings-prop">
+<meta name="assert" content="font-feature-settings supports the full grammar 'normal | <feature-tag-value> #'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_valid_value('font-feature-settings', 'normal');
+
+// <feature-tag-value> = <string> [ <integer> | on | off ]?
+test_valid_value('font-feature-settings', '"dlig" 1', '"dlig"');
+test_valid_value('font-feature-settings', '"smcp" on', '"smcp"');
+test_valid_value('font-feature-settings', "'c2sc'", '"c2sc"');
+test_valid_value('font-feature-settings', '"liga" off', '"liga" 0');
+test_valid_value('font-feature-settings', '"tnum", \'hist\'', '"tnum", "hist"');
+
+test_valid_value('font-feature-settings', '"PKRN"');
+
+test_valid_value('font-feature-settings', '"dlig" 1, "smcp" on, "dlig" 0', '"dlig", "smcp", "dlig" 0');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-invalid.html
new file mode 100644
index 0000000..d6db933
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-invalid.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 4: parsing font with invalid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-fonts-4/#font-prop">
+<meta name="assert" content="font supports only the grammar '[ [ <'font-style'> || <font-variant-css2> || <'font-weight'> || <font-stretch-css3> ]? <'font-size'> [ / <'line-height'> ]? <'font-family'> ] | caption | icon | menu | message-box | small-caption | status-bar'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_invalid_value('font', 'menu icon');
+
+test_invalid_value('font', 'italic oblique xx-small serif');
+test_invalid_value('font', 'small-caps small-caps medium/normal sans-serif');
+test_invalid_value('font', 'bold bolder xx-large/1.2 cursive');
+test_invalid_value('font', 'ultra-condensed extra-condensed larger/calc(120% + 1.2em) fantasy');
+test_invalid_value('font', 'italic small-caps lighter condensed normal smaller monospace');
+test_invalid_value('font', 'normal 100 semi-condensed oblique small-caps 10px/normal Menu');
+test_invalid_value('font', 'normal normal normal normal normal 20%/1.2 \"FB Armada\"');
+
+test_invalid_value('font', 'italic small-caps lighter condensed smaller');
+test_invalid_value('font', 'normal 100 semi-condensed oblique small-caps Menu');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-kerning-computed.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-kerning-computed.html
new file mode 100644
index 0000000..5cd0b25
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-kerning-computed.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: getComputedValue().fontKerning</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-kerning-prop">
+<meta name="assert" content="font-kerning computed value is as specified.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value('font-kerning', 'auto');
+test_computed_value('font-kerning', 'normal');
+test_computed_value('font-kerning', 'none');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-kerning-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-kerning-invalid.html
new file mode 100644
index 0000000..46e94b0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-kerning-invalid.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: parsing font-kerning with invalid values</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-kerning-prop">
+<meta name="assert" content="font-kerning supports only the grammar 'auto | normal | none'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_invalid_value('font-kerning', 'normal auto');
+test_invalid_value('font-kerning', 'none, auto');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-kerning-valid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-kerning-valid.html
new file mode 100644
index 0000000..623f860
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-kerning-valid.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: parsing font-kerning with valid values</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-kerning-prop">
+<meta name="assert" content="font-kerning supports the full grammar 'auto | normal | none'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_valid_value('font-kerning', 'auto');
+test_valid_value('font-kerning', 'normal');
+test_valid_value('font-kerning', 'none');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-size-adjust-computed.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-size-adjust-computed.html
new file mode 100644
index 0000000..601e22e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-size-adjust-computed.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: getComputedValue().fontSizeAdjust</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-size-adjust-prop">
+<meta name="assert" content="font-size-adjust computed value is as specified.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value('font-size-adjust', 'none');
+test_computed_value('font-size-adjust', '0.5');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-size-adjust-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-size-adjust-invalid.html
new file mode 100644
index 0000000..8e83052
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-size-adjust-invalid.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: parsing font-size-adjust with invalid values</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-size-adjust-prop">
+<meta name="assert" content="font-size-adjust supports only the grammar 'none | <number>'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_invalid_value('font-size-adjust', 'auto');
+test_invalid_value('font-size-adjust', '-10');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-size-adjust-valid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-size-adjust-valid.html
new file mode 100644
index 0000000..1e4d0ae
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-size-adjust-valid.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: parsing font-size-adjust with valid values</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-size-adjust-prop">
+<meta name="assert" content="font-size-adjust supports the full grammar 'none | <number>'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_valid_value('font-size-adjust', 'none');
+test_valid_value('font-size-adjust', '0.5');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-size-computed-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-size-computed-expected.txt
new file mode 100644
index 0000000..c993fecf
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-size-computed-expected.txt
@@ -0,0 +1,24 @@
+This is a testharness.js-based test.
+PASS xx-small <= x-small
+PASS x-small <= small
+PASS small <= medium
+PASS medium <= large
+PASS large <= x-large
+PASS x-large <= xx-large
+PASS xx-large <= xxx-large
+PASS inherit <= larger
+PASS smaller <= inherit
+PASS Property font-size value '10px' computes to '10px'
+PASS Property font-size value '20%' computes to '8px'
+PASS Property font-size value 'calc(30% - 40px)' computes to '0px'
+PASS Property font-size value 'calc(30% + 40px)' computes to '52px'
+PASS Property font-size value 'calc(10px - 0.5em)' computes to '0px'
+PASS Property font-size value 'calc(10px + 0.5em)' computes to '30px'
+PASS <font size="2"> is font-size: small
+PASS <font size="3"> is font-size: medium
+PASS <font size="4"> is font-size: large
+PASS <font size="5"> is font-size: x-large
+PASS <font size="6"> is font-size: xx-large
+FAIL <font size="7"> is font-size: xxx-large assert_equals: expected "48px" but got "32px"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-size-computed.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-size-computed.html
new file mode 100644
index 0000000..ebbbeac0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-size-computed.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 4: getComputedValue().fontSize</title>
+<link rel="help" href="https://drafts.csswg.org/css-fonts-4/#font-size-prop">
+<meta name="assert" content="font-size computed value is an absolute length.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<style>
+  #container {
+    font-size: 40px;
+  }
+</style>
+</head>
+<body>
+<div id="container">
+  <div id="target"></div>
+</div>
+<font id="reference"></font>
+<script>
+function test_relative_size(first, second) {
+  test(() => {
+    const target = document.getElementById('target');
+    target.style.fontSize = first;
+    const firstResult = Number(getComputedStyle(target).fontSize.replace('px', ''));
+    target.style.fontSize = second;
+    const secondResult = Number(getComputedStyle(target).fontSize.replace('px', ''));
+    assert_less_than_equal(firstResult, secondResult);
+  }, first + ' <= ' + second);
+}
+
+test_relative_size('xx-small', 'x-small');
+test_relative_size('x-small', 'small');
+test_relative_size('small', 'medium');
+test_relative_size('medium', 'large');
+test_relative_size('large', 'x-large');
+test_relative_size('x-large', 'xx-large');
+// Added in Fonts level 4: https://github.com/w3c/csswg-drafts/issues/3907
+test_relative_size('xx-large', 'xxx-large');
+
+// <relative-size>
+test_relative_size('inherit', 'larger');
+test_relative_size('smaller', 'inherit');
+
+// <length-percentage>
+test_computed_value('font-size', '10px');
+test_computed_value('font-size', '20%', '8px');
+test_computed_value('font-size', 'calc(30% - 40px)', '0px');
+test_computed_value('font-size', 'calc(30% + 40px)', '52px');
+test_computed_value('font-size', 'calc(10px - 0.5em)', '0px');
+test_computed_value('font-size', 'calc(10px + 0.5em)', '30px');
+
+function test_font_size(attribute, keyword) {
+  test(() => {
+    const reference = document.getElementById('reference');
+    reference.setAttribute('size', attribute);
+    const target = document.getElementById('target');
+    target.style.fontSize = keyword;
+    assert_equals(getComputedStyle(target).fontSize, getComputedStyle(reference).fontSize);
+  }, '<font size="' + attribute + '"> is font-size: ' + keyword);
+}
+
+test_font_size('2', 'small');
+test_font_size('3', 'medium');
+test_font_size('4', 'large');
+test_font_size('5', 'x-large');
+test_font_size('6', 'xx-large');
+test_font_size('7', 'xxx-large');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-size-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-size-invalid.html
new file mode 100644
index 0000000..b3bccc2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-size-invalid.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: parsing font-size with invalid values</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-size-prop">
+<meta name="assert" content="font-size supports only the grammar '<absolute-size> | <relative-size> | <length-percentage>'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_invalid_value('font-size', 'auto');
+test_invalid_value('font-size', 'medium small');
+
+test_invalid_value('font-size', '-10px');
+test_invalid_value('font-size', '-20%');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-size-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-size-valid-expected.txt
new file mode 100644
index 0000000..372fd174
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-size-valid-expected.txt
@@ -0,0 +1,16 @@
+This is a testharness.js-based test.
+PASS e.style['font-size'] = "xx-small" should set the property value
+PASS e.style['font-size'] = "x-small" should set the property value
+PASS e.style['font-size'] = "small" should set the property value
+PASS e.style['font-size'] = "medium" should set the property value
+PASS e.style['font-size'] = "large" should set the property value
+PASS e.style['font-size'] = "x-large" should set the property value
+PASS e.style['font-size'] = "xx-large" should set the property value
+FAIL e.style['font-size'] = "xxx-large" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font-size'] = "larger" should set the property value
+PASS e.style['font-size'] = "smaller" should set the property value
+PASS e.style['font-size'] = "10px" should set the property value
+PASS e.style['font-size'] = "20%" should set the property value
+PASS e.style['font-size'] = "calc(30% - 40px)" should set the property value
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-size-valid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-size-valid.html
new file mode 100644
index 0000000..72cf6053
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-size-valid.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 4: parsing font-size with valid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-fonts-4/#font-size-prop">
+<meta name="assert" content="font-size supports the full grammar '<absolute-size> | <relative-size> | <length-percentage>'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+// <absolute-size>
+test_valid_value('font-size', 'xx-small');
+test_valid_value('font-size', 'x-small');
+test_valid_value('font-size', 'small');
+test_valid_value('font-size', 'medium');
+test_valid_value('font-size', 'large');
+test_valid_value('font-size', 'x-large');
+test_valid_value('font-size', 'xx-large');
+// Added in Fonts level 4: https://github.com/w3c/csswg-drafts/issues/3907
+test_valid_value('font-size', 'xxx-large');
+
+// <relative-size>
+test_valid_value('font-size', 'larger');
+test_valid_value('font-size', 'smaller');
+
+// <length-percentage>
+test_valid_value('font-size', '10px');
+test_valid_value('font-size', '20%');
+test_valid_value('font-size', 'calc(30% - 40px)');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-stretch-computed.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-stretch-computed.html
new file mode 100644
index 0000000..4a1ecdb6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-stretch-computed.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 4: getComputedValue().fontStretch</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-4/#font-stretch-prop">
+<meta name="assert" content="font-stretch computed value is a percentage.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value('font-stretch', 'ultra-condensed', '50%');
+test_computed_value('font-stretch', 'extra-condensed', '62.5%');
+test_computed_value('font-stretch', 'condensed', '75%');
+test_computed_value('font-stretch', 'semi-condensed', '87.5%');
+test_computed_value('font-stretch', 'normal', '100%');
+test_computed_value('font-stretch', 'semi-expanded', '112.5%');
+test_computed_value('font-stretch', 'expanded', '125%');
+test_computed_value('font-stretch', 'extra-expanded', '150%');
+test_computed_value('font-stretch', 'ultra-expanded', '200%');
+
+test_computed_value('font-stretch', '234.5%');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-stretch-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-stretch-invalid.html
new file mode 100644
index 0000000..9ff8fa5d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-stretch-invalid.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 4: parsing font-stretch with invalid values</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-4/#font-stretch-prop">
+<meta name="assert" content="font-stretch supports only the grammar 'normal | <percentage> | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded'.">
+<meta name="assert" content="Values less than 0% are invalid.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_invalid_value('font-stretch', 'auto');
+test_invalid_value('font-stretch', 'normal, ultra-condensed');
+test_invalid_value('font-stretch', 'condensed expanded');
+test_invalid_value('font-stretch', '-50%');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-stretch-valid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-stretch-valid.html
new file mode 100644
index 0000000..38452c2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-stretch-valid.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 4: parsing font-stretch with valid values</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-4/#font-stretch-prop">
+<meta name="assert" content="font-stretch supports the full grammar 'normal | <percentage> | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_valid_value('font-stretch', 'normal');
+test_valid_value('font-stretch', 'ultra-condensed');
+test_valid_value('font-stretch', 'extra-condensed');
+test_valid_value('font-stretch', 'condensed');
+test_valid_value('font-stretch', 'semi-condensed');
+test_valid_value('font-stretch', 'semi-expanded');
+test_valid_value('font-stretch', 'expanded');
+test_valid_value('font-stretch', 'extra-expanded');
+test_valid_value('font-stretch', 'ultra-expanded');
+
+test_valid_value('font-stretch', '234.5%');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-style-computed-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-style-computed-expected.txt
new file mode 100644
index 0000000..66fc2b59
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-style-computed-expected.txt
@@ -0,0 +1,6 @@
+This is a testharness.js-based test.
+PASS Property font-style value 'normal' computes to 'normal'
+PASS Property font-style value 'italic' computes to 'italic'
+FAIL Property font-style value 'oblique' computes to 'oblique' assert_equals: expected "oblique" but got "italic"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-style-computed.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-style-computed.html
new file mode 100644
index 0000000..a7bb4214
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-style-computed.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: getComputedValue().fontStyle</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-style-prop">
+<meta name="assert" content="font-style computed value is as specified.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<style>
+  #target {
+    font-family: Ahem;
+  }
+</style>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value('font-style', 'normal');
+test_computed_value('font-style', 'italic');
+test_computed_value('font-style', 'oblique');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-style-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-style-invalid.html
new file mode 100644
index 0000000..4542c29
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-style-invalid.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: parsing font-style with invalid values</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-style-prop">
+<meta name="assert" content="font-style supports only the grammar 'normal | italic | oblique'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_invalid_value('font-style', 'auto');
+test_invalid_value('font-style', 'italic oblique');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-style-valid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-style-valid.html
new file mode 100644
index 0000000..b618644
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-style-valid.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: parsing font-style with valid values</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-style-prop">
+<meta name="assert" content="font-style supports the full grammar 'normal | italic | oblique'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_valid_value('font-style', 'normal');
+test_valid_value('font-style', 'italic');
+test_valid_value('font-style', 'oblique');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-synthesis-computed-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-synthesis-computed-expected.txt
new file mode 100644
index 0000000..e0da8b2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-synthesis-computed-expected.txt
@@ -0,0 +1,7 @@
+This is a testharness.js-based test.
+FAIL Property font-synthesis value 'none' computes to 'none' assert_true: font-synthesis doesn't seem to be supported in the computed style expected true got false
+FAIL Property font-synthesis value 'weight' computes to 'weight' assert_true: font-synthesis doesn't seem to be supported in the computed style expected true got false
+FAIL Property font-synthesis value 'style' computes to 'style' assert_true: font-synthesis doesn't seem to be supported in the computed style expected true got false
+FAIL Property font-synthesis value 'weight style' computes to 'weight style' assert_true: font-synthesis doesn't seem to be supported in the computed style expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-synthesis-computed.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-synthesis-computed.html
new file mode 100644
index 0000000..933a879b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-synthesis-computed.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: getComputedValue().fontSynthesis</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-synthesis-prop">
+<meta name="assert" content="font-synthesis computed value is as specified.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value('font-synthesis', 'none');
+test_computed_value('font-synthesis', 'weight');
+test_computed_value('font-synthesis', 'style');
+test_computed_value('font-synthesis', 'weight style');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-synthesis-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-synthesis-invalid.html
new file mode 100644
index 0000000..adbe9c02
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-synthesis-invalid.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: parsing font-synthesis with invalid values</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-synthesis-prop">
+<meta name="assert" content="font-synthesis supports only the grammar 'none | [ weight || style ]'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_invalid_value('font-synthesis', 'auto');
+test_invalid_value('font-synthesis', 'none weight');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-synthesis-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-synthesis-valid-expected.txt
new file mode 100644
index 0000000..ec33e3ad
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-synthesis-valid-expected.txt
@@ -0,0 +1,7 @@
+This is a testharness.js-based test.
+FAIL e.style['font-synthesis'] = "none" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font-synthesis'] = "weight" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font-synthesis'] = "style" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font-synthesis'] = "style weight" should set the property value assert_not_equals: property should be set got disallowed value ""
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-synthesis-valid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-synthesis-valid.html
new file mode 100644
index 0000000..1d1aa5d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-synthesis-valid.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: parsing font-synthesis with valid values</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-synthesis-prop">
+<meta name="assert" content="font-synthesis supports the full grammar 'none | [ weight || style ]'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_valid_value('font-synthesis', 'none');
+test_valid_value('font-synthesis', 'weight');
+test_valid_value('font-synthesis', 'style');
+test_valid_value('font-synthesis', 'style weight', 'weight style');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-valid-expected.txt
new file mode 100644
index 0000000..00a0386
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-valid-expected.txt
@@ -0,0 +1,319 @@
+This is a testharness.js-based test.
+Found 315 tests; 212 PASS, 103 FAIL, 0 TIMEOUT, 0 NOTRUN.
+PASS caption should be a supported system font.
+PASS icon should be a supported system font.
+PASS menu should be a supported system font.
+PASS message-box should be a supported system font.
+PASS small-caption should be a supported system font.
+PASS status-bar should be a supported system font.
+PASS e.style['font'] = "xx-small serif" should set the property value
+PASS e.style['font'] = "normal medium/normal sans-serif" should set the property value
+PASS e.style['font'] = "normal normal xx-large/1.2 cursive" should set the property value
+PASS e.style['font'] = "normal normal normal larger/calc(120% + 1.2em) fantasy" should set the property value
+PASS e.style['font'] = "normal normal normal normal smaller monospace" should set the property value
+FAIL e.style['font'] = "normal normal normal italic 10px/normal Menu" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal normal normal small-caps 20%/1.2 \"FB Armada\"" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal normal normal bold calc(30% - 40px)/calc(120% + 1.2em) serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "normal normal normal ultra-condensed xx-small sans-serif" should set the property value
+FAIL e.style['font'] = "normal normal oblique medium/normal cursive" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal normal italic normal xx-large/1.2 fantasy" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal normal oblique small-caps larger/calc(120% + 1.2em) monospace" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal normal italic bolder smaller Menu" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal normal oblique extra-condensed 10px/normal \"FB Armada\"" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal normal small-caps 20%/1.2 serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal normal small-caps normal calc(30% - 40px)/calc(120% + 1.2em) sans-serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal normal small-caps italic xx-small cursive" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal normal small-caps lighter medium/normal fantasy" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal normal small-caps condensed xx-large/1.2 monospace" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "normal normal 100 larger/calc(120% + 1.2em) Menu" should set the property value
+PASS e.style['font'] = "normal normal 900 normal smaller \"FB Armada\"" should set the property value
+FAIL e.style['font'] = "normal normal bold oblique 10px/normal serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal normal bolder small-caps 20%/1.2 sans-serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "normal normal lighter semi-condensed calc(30% - 40px)/calc(120% + 1.2em) cursive" should set the property value
+PASS e.style['font'] = "normal normal semi-expanded xx-small fantasy" should set the property value
+PASS e.style['font'] = "normal normal expanded normal medium/normal monospace" should set the property value
+FAIL e.style['font'] = "normal normal extra-expanded italic xx-large/1.2 Menu" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal normal ultra-expanded small-caps larger/calc(120% + 1.2em) \"FB Armada\"" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "normal normal ultra-condensed 100 smaller serif" should set the property value
+FAIL e.style['font'] = "normal oblique 10px/normal sans-serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal italic normal 20%/1.2 cursive" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal oblique normal normal calc(30% - 40px)/calc(120% + 1.2em) fantasy" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal italic normal small-caps xx-small monospace" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal oblique normal 900 medium/normal Menu" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal italic normal extra-condensed xx-large/1.2 \"FB Armada\"" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal oblique small-caps larger/calc(120% + 1.2em) serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal italic small-caps normal smaller sans-serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal oblique small-caps bold 10px/normal cursive" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal italic small-caps condensed 20%/1.2 fantasy" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal oblique bolder calc(30% - 40px)/calc(120% + 1.2em) monospace" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal italic lighter normal xx-small Menu" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal oblique 100 small-caps medium/normal \"FB Armada\"" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal italic 900 semi-condensed xx-large/1.2 serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal oblique semi-expanded larger/calc(120% + 1.2em) sans-serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal italic expanded normal smaller cursive" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal oblique extra-expanded small-caps 10px/normal fantasy" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal italic ultra-expanded bold 20%/1.2 monospace" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "normal small-caps calc(30% - 40px)/calc(120% + 1.2em) Menu" should set the property value
+PASS e.style['font'] = "normal small-caps normal xx-small \"FB Armada\"" should set the property value
+PASS e.style['font'] = "normal small-caps normal normal medium/normal serif" should set the property value
+FAIL e.style['font'] = "normal small-caps normal oblique xx-large/1.2 sans-serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal small-caps normal bolder larger/calc(120% + 1.2em) cursive" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "normal small-caps normal ultra-condensed smaller fantasy" should set the property value
+FAIL e.style['font'] = "normal small-caps italic 10px/normal monospace" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal small-caps oblique normal 20%/1.2 Menu" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal small-caps italic lighter calc(30% - 40px)/calc(120% + 1.2em) \"FB Armada\"" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal small-caps oblique extra-condensed xx-small serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "normal small-caps 100 medium/normal sans-serif" should set the property value
+PASS e.style['font'] = "normal small-caps 900 normal xx-large/1.2 cursive" should set the property value
+FAIL e.style['font'] = "normal small-caps bold italic larger/calc(120% + 1.2em) fantasy" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "normal small-caps bolder condensed smaller monospace" should set the property value
+PASS e.style['font'] = "normal small-caps semi-condensed 10px/normal Menu" should set the property value
+PASS e.style['font'] = "normal small-caps semi-expanded normal 20%/1.2 \"FB Armada\"" should set the property value
+FAIL e.style['font'] = "normal small-caps expanded oblique calc(30% - 40px)/calc(120% + 1.2em) serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "normal small-caps extra-expanded lighter xx-small sans-serif" should set the property value
+PASS e.style['font'] = "normal 100 medium/normal cursive" should set the property value
+PASS e.style['font'] = "normal 900 normal xx-large/1.2 fantasy" should set the property value
+PASS e.style['font'] = "normal bold normal normal larger/calc(120% + 1.2em) monospace" should set the property value
+FAIL e.style['font'] = "normal bolder normal italic smaller Menu" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal lighter normal small-caps 10px/normal \"FB Armada\"" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "normal 100 normal ultra-expanded 20%/1.2 serif" should set the property value
+FAIL e.style['font'] = "normal 900 oblique calc(30% - 40px)/calc(120% + 1.2em) sans-serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal bold italic normal xx-small cursive" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal bolder oblique small-caps medium/normal fantasy" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal lighter italic ultra-condensed xx-large/1.2 monospace" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "normal 100 small-caps larger/calc(120% + 1.2em) Menu" should set the property value
+PASS e.style['font'] = "normal 900 small-caps normal smaller \"FB Armada\"" should set the property value
+FAIL e.style['font'] = "normal bold small-caps oblique 10px/normal serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "normal bolder small-caps extra-condensed 20%/1.2 sans-serif" should set the property value
+PASS e.style['font'] = "normal lighter condensed calc(30% - 40px)/calc(120% + 1.2em) cursive" should set the property value
+PASS e.style['font'] = "normal 100 semi-condensed normal xx-small fantasy" should set the property value
+FAIL e.style['font'] = "normal 900 semi-expanded italic medium/normal monospace" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "normal bold expanded small-caps xx-large/1.2 Menu" should set the property value
+PASS e.style['font'] = "normal extra-expanded larger/calc(120% + 1.2em) \"FB Armada\"" should set the property value
+PASS e.style['font'] = "normal ultra-expanded normal smaller serif" should set the property value
+PASS e.style['font'] = "normal ultra-condensed normal normal 10px/normal sans-serif" should set the property value
+FAIL e.style['font'] = "normal extra-condensed normal oblique 20%/1.2 cursive" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal condensed normal small-caps calc(30% - 40px)/calc(120% + 1.2em) fantasy" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "normal semi-condensed normal bolder xx-small monospace" should set the property value
+FAIL e.style['font'] = "normal semi-expanded italic medium/normal Menu" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal expanded oblique normal xx-large/1.2 \"FB Armada\"" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal extra-expanded italic small-caps larger/calc(120% + 1.2em) serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "normal ultra-expanded oblique lighter smaller sans-serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "normal ultra-condensed small-caps 10px/normal cursive" should set the property value
+PASS e.style['font'] = "normal extra-condensed small-caps normal 20%/1.2 fantasy" should set the property value
+FAIL e.style['font'] = "normal condensed small-caps italic calc(30% - 40px)/calc(120% + 1.2em) monospace" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "normal semi-condensed small-caps 100 xx-small Menu" should set the property value
+PASS e.style['font'] = "normal semi-expanded 900 medium/normal \"FB Armada\"" should set the property value
+PASS e.style['font'] = "normal expanded bold normal xx-large/1.2 serif" should set the property value
+FAIL e.style['font'] = "normal extra-expanded bolder oblique larger/calc(120% + 1.2em) sans-serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "normal ultra-expanded lighter small-caps smaller cursive" should set the property value
+PASS e.style['font'] = "italic 10px/normal fantasy" should set the property value
+PASS e.style['font'] = "oblique normal 20%/1.2 monospace" should set the property value
+PASS e.style['font'] = "italic normal normal calc(30% - 40px)/calc(120% + 1.2em) Menu" should set the property value
+PASS e.style['font'] = "oblique normal normal normal xx-small \"FB Armada\"" should set the property value
+FAIL e.style['font'] = "italic normal normal small-caps medium/normal serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "oblique normal normal 100 xx-large/1.2 sans-serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "italic normal normal ultra-condensed larger/calc(120% + 1.2em) cursive" should set the property value
+FAIL e.style['font'] = "oblique normal small-caps smaller fantasy" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "italic normal small-caps normal 10px/normal monospace" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "oblique normal small-caps 900 20%/1.2 Menu" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "italic normal small-caps extra-condensed calc(30% - 40px)/calc(120% + 1.2em) \"FB Armada\"" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "oblique normal bold xx-small serif" should set the property value
+PASS e.style['font'] = "italic normal bolder normal medium/normal sans-serif" should set the property value
+FAIL e.style['font'] = "oblique normal lighter small-caps xx-large/1.2 cursive" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "italic normal 100 condensed larger/calc(120% + 1.2em) fantasy" should set the property value
+PASS e.style['font'] = "oblique normal semi-condensed smaller monospace" should set the property value
+PASS e.style['font'] = "italic normal semi-expanded normal 10px/normal Menu" should set the property value
+FAIL e.style['font'] = "oblique normal expanded small-caps 20%/1.2 \"FB Armada\"" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "italic normal extra-expanded 900 calc(30% - 40px)/calc(120% + 1.2em) serif" should set the property value
+PASS e.style['font'] = "oblique small-caps xx-small sans-serif" should set the property value
+PASS e.style['font'] = "italic small-caps normal medium/normal cursive" should set the property value
+PASS e.style['font'] = "oblique small-caps normal normal xx-large/1.2 fantasy" should set the property value
+FAIL e.style['font'] = "italic small-caps normal bold larger/calc(120% + 1.2em) monospace" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "oblique small-caps normal ultra-expanded smaller Menu" should set the property value
+PASS e.style['font'] = "italic small-caps bolder 10px/normal \"FB Armada\"" should set the property value
+PASS e.style['font'] = "oblique small-caps lighter normal 20%/1.2 serif" should set the property value
+PASS e.style['font'] = "italic small-caps 100 ultra-condensed calc(30% - 40px)/calc(120% + 1.2em) sans-serif" should set the property value
+PASS e.style['font'] = "oblique small-caps extra-condensed xx-small cursive" should set the property value
+PASS e.style['font'] = "italic small-caps condensed normal medium/normal fantasy" should set the property value
+PASS e.style['font'] = "oblique small-caps semi-condensed 900 xx-large/1.2 monospace" should set the property value
+PASS e.style['font'] = "italic bold larger/calc(120% + 1.2em) Menu" should set the property value
+PASS e.style['font'] = "oblique bolder normal smaller \"FB Armada\"" should set the property value
+PASS e.style['font'] = "italic lighter normal normal 10px/normal serif" should set the property value
+FAIL e.style['font'] = "oblique 100 normal small-caps 20%/1.2 sans-serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "italic 900 normal semi-expanded calc(30% - 40px)/calc(120% + 1.2em) cursive" should set the property value
+PASS e.style['font'] = "oblique bold small-caps xx-small fantasy" should set the property value
+PASS e.style['font'] = "italic bolder small-caps normal medium/normal monospace" should set the property value
+PASS e.style['font'] = "oblique lighter small-caps expanded xx-large/1.2 Menu" should set the property value
+PASS e.style['font'] = "italic 100 extra-expanded larger/calc(120% + 1.2em) \"FB Armada\"" should set the property value
+PASS e.style['font'] = "oblique 900 ultra-expanded normal smaller serif" should set the property value
+PASS e.style['font'] = "italic bold ultra-condensed small-caps 10px/normal sans-serif" should set the property value
+PASS e.style['font'] = "oblique extra-condensed 20%/1.2 cursive" should set the property value
+PASS e.style['font'] = "italic condensed normal calc(30% - 40px)/calc(120% + 1.2em) fantasy" should set the property value
+PASS e.style['font'] = "oblique semi-condensed normal normal xx-small monospace" should set the property value
+FAIL e.style['font'] = "italic semi-expanded normal small-caps medium/normal Menu" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "oblique expanded normal bolder xx-large/1.2 \"FB Armada\"" should set the property value
+PASS e.style['font'] = "italic extra-expanded small-caps larger/calc(120% + 1.2em) serif" should set the property value
+PASS e.style['font'] = "oblique ultra-expanded small-caps normal smaller sans-serif" should set the property value
+PASS e.style['font'] = "italic ultra-condensed small-caps lighter 10px/normal cursive" should set the property value
+PASS e.style['font'] = "oblique extra-condensed 100 20%/1.2 fantasy" should set the property value
+PASS e.style['font'] = "italic condensed 900 normal calc(30% - 40px)/calc(120% + 1.2em) monospace" should set the property value
+PASS e.style['font'] = "oblique semi-condensed bold small-caps xx-small Menu" should set the property value
+PASS e.style['font'] = "small-caps medium/normal \"FB Armada\"" should set the property value
+PASS e.style['font'] = "small-caps normal xx-large/1.2 serif" should set the property value
+PASS e.style['font'] = "small-caps normal normal larger/calc(120% + 1.2em) sans-serif" should set the property value
+PASS e.style['font'] = "small-caps normal normal normal smaller cursive" should set the property value
+FAIL e.style['font'] = "small-caps normal normal italic 10px/normal fantasy" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "small-caps normal normal bolder 20%/1.2 monospace" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "small-caps normal normal semi-expanded calc(30% - 40px)/calc(120% + 1.2em) Menu" should set the property value
+FAIL e.style['font'] = "small-caps normal oblique xx-small \"FB Armada\"" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "small-caps normal italic normal medium/normal serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "small-caps normal oblique lighter xx-large/1.2 sans-serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "small-caps normal italic expanded larger/calc(120% + 1.2em) cursive" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "small-caps normal 100 smaller fantasy" should set the property value
+PASS e.style['font'] = "small-caps normal 900 normal 10px/normal monospace" should set the property value
+FAIL e.style['font'] = "small-caps normal bold oblique 20%/1.2 Menu" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "small-caps normal bolder extra-expanded calc(30% - 40px)/calc(120% + 1.2em) \"FB Armada\"" should set the property value
+PASS e.style['font'] = "small-caps normal ultra-expanded xx-small serif" should set the property value
+PASS e.style['font'] = "small-caps normal ultra-condensed normal medium/normal sans-serif" should set the property value
+FAIL e.style['font'] = "small-caps normal extra-condensed italic xx-large/1.2 cursive" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "small-caps normal condensed lighter larger/calc(120% + 1.2em) fantasy" should set the property value
+PASS e.style['font'] = "small-caps oblique smaller monospace" should set the property value
+PASS e.style['font'] = "small-caps italic normal 10px/normal Menu" should set the property value
+PASS e.style['font'] = "small-caps oblique normal normal 20%/1.2 \"FB Armada\"" should set the property value
+FAIL e.style['font'] = "small-caps italic normal 100 calc(30% - 40px)/calc(120% + 1.2em) serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "small-caps oblique normal semi-condensed xx-small sans-serif" should set the property value
+PASS e.style['font'] = "small-caps italic 900 medium/normal cursive" should set the property value
+PASS e.style['font'] = "small-caps oblique bold normal xx-large/1.2 fantasy" should set the property value
+PASS e.style['font'] = "small-caps italic bolder semi-expanded larger/calc(120% + 1.2em) monospace" should set the property value
+PASS e.style['font'] = "small-caps oblique expanded smaller Menu" should set the property value
+PASS e.style['font'] = "small-caps italic extra-expanded normal 10px/normal \"FB Armada\"" should set the property value
+PASS e.style['font'] = "small-caps oblique ultra-expanded lighter 20%/1.2 serif" should set the property value
+PASS e.style['font'] = "small-caps 100 calc(30% - 40px)/calc(120% + 1.2em) sans-serif" should set the property value
+PASS e.style['font'] = "small-caps 900 normal xx-small cursive" should set the property value
+PASS e.style['font'] = "small-caps bold normal normal medium/normal fantasy" should set the property value
+FAIL e.style['font'] = "small-caps bolder normal italic xx-large/1.2 monospace" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "small-caps lighter normal ultra-condensed larger/calc(120% + 1.2em) Menu" should set the property value
+PASS e.style['font'] = "small-caps 100 oblique smaller \"FB Armada\"" should set the property value
+PASS e.style['font'] = "small-caps 900 italic normal 10px/normal serif" should set the property value
+PASS e.style['font'] = "small-caps bold oblique extra-condensed 20%/1.2 sans-serif" should set the property value
+PASS e.style['font'] = "small-caps bolder condensed calc(30% - 40px)/calc(120% + 1.2em) cursive" should set the property value
+PASS e.style['font'] = "small-caps lighter semi-condensed normal xx-small fantasy" should set the property value
+PASS e.style['font'] = "small-caps 100 semi-expanded italic medium/normal monospace" should set the property value
+PASS e.style['font'] = "small-caps expanded xx-large/1.2 Menu" should set the property value
+PASS e.style['font'] = "small-caps extra-expanded normal larger/calc(120% + 1.2em) \"FB Armada\"" should set the property value
+PASS e.style['font'] = "small-caps ultra-expanded normal normal smaller serif" should set the property value
+FAIL e.style['font'] = "small-caps ultra-condensed normal oblique 10px/normal sans-serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "small-caps extra-condensed normal 900 20%/1.2 cursive" should set the property value
+PASS e.style['font'] = "small-caps condensed italic calc(30% - 40px)/calc(120% + 1.2em) fantasy" should set the property value
+PASS e.style['font'] = "small-caps semi-condensed oblique normal xx-small monospace" should set the property value
+PASS e.style['font'] = "small-caps semi-expanded italic bold medium/normal Menu" should set the property value
+PASS e.style['font'] = "small-caps expanded bolder xx-large/1.2 \"FB Armada\"" should set the property value
+PASS e.style['font'] = "small-caps extra-expanded lighter normal larger/calc(120% + 1.2em) serif" should set the property value
+PASS e.style['font'] = "small-caps ultra-expanded 100 oblique smaller sans-serif" should set the property value
+PASS e.style['font'] = "900 10px/normal cursive" should set the property value
+PASS e.style['font'] = "bold normal 20%/1.2 fantasy" should set the property value
+PASS e.style['font'] = "bolder normal normal calc(30% - 40px)/calc(120% + 1.2em) monospace" should set the property value
+PASS e.style['font'] = "lighter normal normal normal xx-small Menu" should set the property value
+FAIL e.style['font'] = "100 normal normal italic medium/normal \"FB Armada\"" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "900 normal normal small-caps xx-large/1.2 serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "bold normal normal ultra-condensed larger/calc(120% + 1.2em) sans-serif" should set the property value
+FAIL e.style['font'] = "bolder normal oblique smaller cursive" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "lighter normal italic normal 10px/normal fantasy" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "100 normal oblique small-caps 20%/1.2 monospace" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "900 normal italic extra-condensed calc(30% - 40px)/calc(120% + 1.2em) Menu" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "bold normal small-caps xx-small \"FB Armada\"" should set the property value
+PASS e.style['font'] = "bolder normal small-caps normal medium/normal serif" should set the property value
+FAIL e.style['font'] = "lighter normal small-caps oblique xx-large/1.2 sans-serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "100 normal small-caps condensed larger/calc(120% + 1.2em) cursive" should set the property value
+PASS e.style['font'] = "900 normal semi-condensed smaller fantasy" should set the property value
+PASS e.style['font'] = "bold normal semi-expanded normal 10px/normal monospace" should set the property value
+FAIL e.style['font'] = "bolder normal expanded italic 20%/1.2 Menu" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "lighter normal extra-expanded small-caps calc(30% - 40px)/calc(120% + 1.2em) \"FB Armada\"" should set the property value
+PASS e.style['font'] = "100 oblique xx-small serif" should set the property value
+PASS e.style['font'] = "900 italic normal medium/normal sans-serif" should set the property value
+PASS e.style['font'] = "bold oblique normal normal xx-large/1.2 cursive" should set the property value
+FAIL e.style['font'] = "bolder italic normal small-caps larger/calc(120% + 1.2em) fantasy" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "lighter oblique normal ultra-expanded smaller monospace" should set the property value
+PASS e.style['font'] = "100 italic small-caps 10px/normal Menu" should set the property value
+PASS e.style['font'] = "900 oblique small-caps normal 20%/1.2 \"FB Armada\"" should set the property value
+PASS e.style['font'] = "bold italic small-caps ultra-condensed calc(30% - 40px)/calc(120% + 1.2em) serif" should set the property value
+PASS e.style['font'] = "bolder oblique extra-condensed xx-small sans-serif" should set the property value
+PASS e.style['font'] = "lighter italic condensed normal medium/normal cursive" should set the property value
+PASS e.style['font'] = "100 oblique semi-condensed small-caps xx-large/1.2 fantasy" should set the property value
+PASS e.style['font'] = "900 small-caps larger/calc(120% + 1.2em) monospace" should set the property value
+PASS e.style['font'] = "bold small-caps normal smaller Menu" should set the property value
+PASS e.style['font'] = "bolder small-caps normal normal 10px/normal \"FB Armada\"" should set the property value
+FAIL e.style['font'] = "lighter small-caps normal italic 20%/1.2 serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "100 small-caps normal semi-expanded calc(30% - 40px)/calc(120% + 1.2em) sans-serif" should set the property value
+PASS e.style['font'] = "900 small-caps oblique xx-small cursive" should set the property value
+PASS e.style['font'] = "bold small-caps italic normal medium/normal fantasy" should set the property value
+PASS e.style['font'] = "bolder small-caps oblique expanded xx-large/1.2 monospace" should set the property value
+PASS e.style['font'] = "lighter small-caps extra-expanded larger/calc(120% + 1.2em) Menu" should set the property value
+PASS e.style['font'] = "100 small-caps ultra-expanded normal smaller \"FB Armada\"" should set the property value
+PASS e.style['font'] = "900 small-caps ultra-condensed italic 10px/normal serif" should set the property value
+PASS e.style['font'] = "bold extra-condensed 20%/1.2 sans-serif" should set the property value
+PASS e.style['font'] = "bolder condensed normal calc(30% - 40px)/calc(120% + 1.2em) cursive" should set the property value
+PASS e.style['font'] = "lighter semi-condensed normal normal xx-small fantasy" should set the property value
+FAIL e.style['font'] = "100 semi-expanded normal oblique medium/normal monospace" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "900 expanded normal small-caps xx-large/1.2 Menu" should set the property value
+PASS e.style['font'] = "bold extra-expanded italic larger/calc(120% + 1.2em) \"FB Armada\"" should set the property value
+PASS e.style['font'] = "bolder ultra-expanded oblique normal smaller serif" should set the property value
+PASS e.style['font'] = "lighter ultra-condensed italic small-caps 10px/normal sans-serif" should set the property value
+PASS e.style['font'] = "100 extra-condensed small-caps 20%/1.2 cursive" should set the property value
+PASS e.style['font'] = "900 condensed small-caps normal calc(30% - 40px)/calc(120% + 1.2em) fantasy" should set the property value
+PASS e.style['font'] = "bold semi-condensed small-caps oblique xx-small monospace" should set the property value
+PASS e.style['font'] = "semi-expanded medium/normal Menu" should set the property value
+PASS e.style['font'] = "expanded normal xx-large/1.2 \"FB Armada\"" should set the property value
+PASS e.style['font'] = "extra-expanded normal normal larger/calc(120% + 1.2em) serif" should set the property value
+PASS e.style['font'] = "ultra-expanded normal normal normal smaller sans-serif" should set the property value
+FAIL e.style['font'] = "ultra-condensed normal normal italic 10px/normal cursive" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "extra-condensed normal normal small-caps 20%/1.2 fantasy" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "condensed normal normal bolder calc(30% - 40px)/calc(120% + 1.2em) monospace" should set the property value
+FAIL e.style['font'] = "semi-condensed normal oblique xx-small Menu" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "semi-expanded normal italic normal medium/normal \"FB Armada\"" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "expanded normal oblique small-caps xx-large/1.2 serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font'] = "extra-expanded normal italic lighter larger/calc(120% + 1.2em) sans-serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "ultra-expanded normal small-caps smaller cursive" should set the property value
+PASS e.style['font'] = "ultra-condensed normal small-caps normal 10px/normal fantasy" should set the property value
+FAIL e.style['font'] = "extra-condensed normal small-caps oblique 20%/1.2 monospace" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "condensed normal small-caps 100 calc(30% - 40px)/calc(120% + 1.2em) Menu" should set the property value
+PASS e.style['font'] = "semi-condensed normal 900 xx-small \"FB Armada\"" should set the property value
+PASS e.style['font'] = "semi-expanded normal bold normal medium/normal serif" should set the property value
+FAIL e.style['font'] = "expanded normal bolder italic xx-large/1.2 sans-serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "extra-expanded normal lighter small-caps larger/calc(120% + 1.2em) cursive" should set the property value
+PASS e.style['font'] = "ultra-expanded oblique smaller fantasy" should set the property value
+PASS e.style['font'] = "ultra-condensed italic normal 10px/normal monospace" should set the property value
+PASS e.style['font'] = "extra-condensed oblique normal normal 20%/1.2 Menu" should set the property value
+FAIL e.style['font'] = "condensed italic normal small-caps calc(30% - 40px)/calc(120% + 1.2em) \"FB Armada\"" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "semi-condensed oblique normal 100 xx-small serif" should set the property value
+PASS e.style['font'] = "semi-expanded italic small-caps medium/normal sans-serif" should set the property value
+PASS e.style['font'] = "expanded oblique small-caps normal xx-large/1.2 cursive" should set the property value
+PASS e.style['font'] = "extra-expanded italic small-caps 900 larger/calc(120% + 1.2em) fantasy" should set the property value
+PASS e.style['font'] = "ultra-expanded oblique bold smaller monospace" should set the property value
+PASS e.style['font'] = "ultra-condensed italic bolder normal 10px/normal Menu" should set the property value
+PASS e.style['font'] = "extra-condensed oblique lighter small-caps 20%/1.2 \"FB Armada\"" should set the property value
+PASS e.style['font'] = "condensed small-caps calc(30% - 40px)/calc(120% + 1.2em) serif" should set the property value
+PASS e.style['font'] = "semi-condensed small-caps normal xx-small sans-serif" should set the property value
+PASS e.style['font'] = "semi-expanded small-caps normal normal medium/normal cursive" should set the property value
+FAIL e.style['font'] = "expanded small-caps normal italic xx-large/1.2 fantasy" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "extra-expanded small-caps normal 100 larger/calc(120% + 1.2em) monospace" should set the property value
+PASS e.style['font'] = "ultra-expanded small-caps oblique smaller Menu" should set the property value
+PASS e.style['font'] = "ultra-condensed small-caps italic normal 10px/normal \"FB Armada\"" should set the property value
+PASS e.style['font'] = "extra-condensed small-caps oblique 900 20%/1.2 serif" should set the property value
+PASS e.style['font'] = "condensed small-caps bold calc(30% - 40px)/calc(120% + 1.2em) sans-serif" should set the property value
+PASS e.style['font'] = "semi-condensed small-caps bolder normal xx-small cursive" should set the property value
+PASS e.style['font'] = "semi-expanded small-caps lighter italic medium/normal fantasy" should set the property value
+PASS e.style['font'] = "expanded 100 xx-large/1.2 monospace" should set the property value
+PASS e.style['font'] = "extra-expanded 900 normal larger/calc(120% + 1.2em) Menu" should set the property value
+PASS e.style['font'] = "ultra-expanded bold normal normal smaller \"FB Armada\"" should set the property value
+FAIL e.style['font'] = "ultra-condensed bolder normal oblique 10px/normal serif" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['font'] = "extra-condensed lighter normal small-caps 20%/1.2 sans-serif" should set the property value
+PASS e.style['font'] = "condensed 100 italic calc(30% - 40px)/calc(120% + 1.2em) cursive" should set the property value
+PASS e.style['font'] = "semi-condensed 900 oblique normal xx-small fantasy" should set the property value
+PASS e.style['font'] = "semi-expanded bold italic small-caps medium/normal monospace" should set the property value
+PASS e.style['font'] = "expanded bolder small-caps xx-large/1.2 Menu" should set the property value
+PASS e.style['font'] = "extra-expanded lighter small-caps normal larger/calc(120% + 1.2em) \"FB Armada\"" should set the property value
+PASS e.style['font'] = "ultra-expanded 100 small-caps oblique smaller serif" should set the property value
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-valid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-valid.html
new file mode 100644
index 0000000..769e6b4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-valid.html
@@ -0,0 +1,205 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 4: parsing font with valid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-fonts-4/#font-prop">
+<meta name="assert" content="font supports the full grammar '[ [ <'font-style'> || <font-variant-css2> || <'font-weight'> || <font-stretch-css3> ]? <'font-size'> [ / <'line-height'> ]? <'font-family'> ] | caption | icon | menu | message-box | small-caption | status-bar'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+'use strict';
+
+// Firefox and Edge 18 serialize these as supplied.
+// Blink and Safari have implementation-dependent or platform-dependent serializations.
+function test_system_font(keyword) {
+  test(() => {
+    const target = document.getElementById('target');
+    const previousValue = 'italic xx-large/0px fantasy';
+    target.style.font = previousValue;
+    target.style.font = keyword;
+    const readValue = target.style.getPropertyValue('font');
+    assert_not_equals(readValue, '', 'font should be set');
+    assert_not_equals(readValue, previousValue, 'font should be updated');
+    target.style.font = previousValue;
+    target.style.font = readValue;
+    assert_equals(target.style.getPropertyValue('font'), readValue, "serialization should round-trip");
+  }, keyword + ' should be a supported system font.');
+}
+
+test_system_font('caption');
+test_system_font('icon');
+test_system_font('menu');
+test_system_font('message-box');
+test_system_font('small-caption');
+test_system_font('status-bar');
+
+// values other than normal
+const generate_style = (() => {
+  const alternatives = [
+    'italic',
+    'oblique'
+  ];
+  let counter = 0;
+  return () => alternatives[counter++ % alternatives.length];
+})();
+
+// value other than normal
+const generate_variant = () => 'small-caps';
+
+// values other than normal
+const generate_weight = (() => {
+  const alternatives = [
+    'bold',
+    'bolder',
+    'lighter',
+    '100',
+    '900'
+  ];
+  let counter = 0;
+  return () => alternatives[counter++ % alternatives.length];
+})();
+
+// values other than normal
+const generate_stretch = (() => {
+  const alternatives = [
+    'ultra-condensed',
+    'extra-condensed',
+    'condensed',
+    'semi-condensed',
+    'semi-expanded',
+    'expanded',
+    'extra-expanded',
+    'ultra-expanded'
+  ];
+  let counter = 0;
+  return () => alternatives[counter++ % alternatives.length];
+})();
+
+const generate_size = (() => {
+  const alternatives = [
+    // <absolute-size>
+    'xx-small',
+    'medium',
+    'xx-large',
+
+    // <relative-size>
+    'larger',
+    'smaller',
+
+    // <length-percentage>
+    '10px',
+    '20%',
+    'calc(30% - 40px)',
+  ];
+  let counter = 0;
+  return () => alternatives[counter++ % alternatives.length];
+})();
+
+const generate_line_height = (() => {
+  const alternatives = [
+    null,
+    'normal',
+    '1.2',
+    'calc(120% + 1.2em)'
+  ];
+  let counter = 0;
+  return () => alternatives[counter++ % alternatives.length];
+})();
+
+const generate_family = (() => {
+  const alternatives = [
+    'serif',
+    'sans-serif',
+    'cursive',
+    'fantasy',
+    'monospace',
+    'Menu',
+    '"FB Armada"'
+  ];
+  let counter = 0;
+  return () => alternatives[counter++ % alternatives.length];
+})();
+
+function test_specific(prefix) {
+  let parts = [];
+  let canonical = [];
+  let style = null;
+  let variant = null;
+  let weight = null;
+  let stretch = null;
+  for (let entry of prefix) {
+    if (entry === 'style') {
+      style = generate_style();
+      parts.push(style);
+    } else if (entry === 'variant') {
+      variant = generate_variant();
+      parts.push(variant);
+    } else if (entry === 'weight') {
+      weight = generate_weight();
+      parts.push(weight);
+    } else if (entry === 'stretch') {
+      stretch = generate_stretch();
+      parts.push(stretch);
+    } else {
+      // normal
+      parts.push('normal');
+    }
+  }
+
+  if (style)
+    canonical.push(style);
+  if (variant)
+    canonical.push(variant);
+  if (weight)
+    canonical.push(weight);
+  if (stretch)
+    canonical.push(stretch);
+
+  const size = generate_size();
+  const lineHeight = generate_line_height();
+  if (lineHeight) {
+    parts.push(size + '/' + lineHeight);
+    if (lineHeight === 'normal')
+      canonical.push(size);
+    else
+      canonical.push(size + '/' + lineHeight);
+  } else {
+    parts.push(size);
+    canonical.push(size);
+  }
+
+  const family = generate_family();
+  parts.push(family);
+  canonical.push(family);
+
+  test_valid_value('font', parts.join(' '), canonical.join(' '));
+}
+
+function test_various(prefix) {
+  test_specific(prefix);
+  if (prefix.length === 4)
+    return;
+
+  const alternatives = [
+    'normal',
+    'style',
+    'variant',
+    'weight',
+    'stretch'
+  ];
+  for (let alternative of alternatives) {
+    if (alternative === 'normal' || !prefix.includes(alternative))
+      test_various(prefix.concat(alternative));
+    // else we would have two styles or two variants, etc.
+  }
+}
+
+test_various([]);
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-caps-computed.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-caps-computed.html
new file mode 100644
index 0000000..03f37ec
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-caps-computed.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: getComputedValue().fontVariantCaps</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-variant-caps-prop">
+<meta name="assert" content="font-variant-caps computed value is as specified.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value('font-variant-caps', 'normal');
+test_computed_value('font-variant-caps', 'small-caps');
+test_computed_value('font-variant-caps', 'all-small-caps');
+test_computed_value('font-variant-caps', 'petite-caps');
+test_computed_value('font-variant-caps', 'all-petite-caps');
+test_computed_value('font-variant-caps', 'unicase');
+test_computed_value('font-variant-caps', 'titling-caps');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-caps-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-caps-invalid.html
new file mode 100644
index 0000000..4c538ad
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-caps-invalid.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: parsing font-variant-caps with invalid values</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-variant-caps-prop">
+<meta name="assert" content="font-variant-caps supports only the grammar 'normal | small-caps | all-small-caps | petite-caps | all-petite-caps | unicase | titling-caps'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_invalid_value('font-variant-caps', 'auto');
+test_invalid_value('font-variant-caps', 'normal unicase');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-caps-valid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-caps-valid.html
new file mode 100644
index 0000000..f34595a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-caps-valid.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: parsing font-variant-caps with valid values</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-variant-caps-prop">
+<meta name="assert" content="font-variant-caps supports the full grammar 'normal | small-caps | all-small-caps | petite-caps | all-petite-caps | unicase | titling-caps'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_valid_value('font-variant-caps', 'normal');
+test_valid_value('font-variant-caps', 'small-caps');
+test_valid_value('font-variant-caps', 'all-small-caps');
+test_valid_value('font-variant-caps', 'petite-caps');
+test_valid_value('font-variant-caps', 'all-petite-caps');
+test_valid_value('font-variant-caps', 'unicase');
+test_valid_value('font-variant-caps', 'titling-caps');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-east-asian-computed.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-east-asian-computed.html
new file mode 100644
index 0000000..27b3b1c8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-east-asian-computed.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: getComputedValue().fontVariantEastAsian</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-variant-east-asian-prop">
+<meta name="assert" content="font-variant-east-asian computed value is as specified.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value('font-variant-east-asian', 'normal');
+
+// <east-asian-variant-values> = [ jis78 | jis83 | jis90 | jis04 | simplified | traditional ]
+test_computed_value('font-variant-east-asian', 'jis78');
+test_computed_value('font-variant-east-asian', 'jis83');
+test_computed_value('font-variant-east-asian', 'jis90');
+test_computed_value('font-variant-east-asian', 'jis04');
+test_computed_value('font-variant-east-asian', 'simplified');
+test_computed_value('font-variant-east-asian', 'traditional');
+
+// <east-asian-width-values>   = [ full-width | proportional-width ]
+test_computed_value('font-variant-east-asian', 'full-width');
+test_computed_value('font-variant-east-asian', 'proportional-width');
+
+test_computed_value('font-variant-east-asian', 'ruby');
+
+test_computed_value('font-variant-east-asian', 'jis78 proportional-width');
+test_computed_value('font-variant-east-asian', 'simplified full-width ruby');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-east-asian-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-east-asian-invalid.html
new file mode 100644
index 0000000..30dbe40
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-east-asian-invalid.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: parsing font-variant-east-asian with invalid values</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-variant-east-asian-prop">
+<meta name="assert" content="font-variant-east-asian supports only the grammar 'normal | [ <east-asian-variant-values> || <east-asian-width-values> || ruby ]'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_invalid_value('font-variant-east-asian', 'normal ruby');
+
+test_invalid_value('font-variant-east-asian', 'jis78 jis83');
+
+test_invalid_value('font-variant-east-asian', 'full-width proportional-width');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-east-asian-valid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-east-asian-valid.html
new file mode 100644
index 0000000..0f16cecc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-east-asian-valid.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: parsing font-variant-east-asian with valid values</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-variant-east-asian-prop">
+<meta name="assert" content="font-variant-east-asian supports the full grammar 'normal | [ <east-asian-variant-values> || <east-asian-width-values> || ruby ]'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_valid_value('font-variant-east-asian', 'normal');
+
+// <east-asian-variant-values> = [ jis78 | jis83 | jis90 | jis04 | simplified | traditional ]
+test_valid_value('font-variant-east-asian', 'jis78');
+test_valid_value('font-variant-east-asian', 'jis83');
+test_valid_value('font-variant-east-asian', 'jis90');
+test_valid_value('font-variant-east-asian', 'jis04');
+test_valid_value('font-variant-east-asian', 'simplified');
+test_valid_value('font-variant-east-asian', 'traditional');
+
+// <east-asian-width-values>   = [ full-width | proportional-width ]
+test_valid_value('font-variant-east-asian', 'full-width');
+test_valid_value('font-variant-east-asian', 'proportional-width');
+
+test_valid_value('font-variant-east-asian', 'ruby');
+
+test_valid_value('font-variant-east-asian', 'jis78 proportional-width');
+test_valid_value('font-variant-east-asian', 'ruby full-width simplified', 'simplified full-width ruby');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-ligatures-computed.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-ligatures-computed.html
new file mode 100644
index 0000000..8cc3fce
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-ligatures-computed.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: getComputedValue().fontVariantLigatures</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-variant-ligatures-prop">
+<meta name="assert" content="font-variant-ligatures computed value is as specified.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value('font-variant-ligatures', 'normal');
+test_computed_value('font-variant-ligatures', 'none');
+
+// <common-lig-values>        = [ common-ligatures | no-common-ligatures ]
+test_computed_value('font-variant-ligatures', 'common-ligatures');
+test_computed_value('font-variant-ligatures', 'no-common-ligatures');
+
+// <discretionary-lig-values> = [ discretionary-ligatures | no-discretionary-ligatures ]
+test_computed_value('font-variant-ligatures', 'discretionary-ligatures');
+test_computed_value('font-variant-ligatures', 'no-discretionary-ligatures');
+
+// <historical-lig-values>    = [ historical-ligatures | no-historical-ligatures ]
+test_computed_value('font-variant-ligatures', 'historical-ligatures');
+test_computed_value('font-variant-ligatures', 'no-historical-ligatures');
+
+// <contextual-alt-values>    = [ contextual | no-contextual ]
+test_computed_value('font-variant-ligatures', 'contextual');
+test_computed_value('font-variant-ligatures', 'no-contextual');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-ligatures-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-ligatures-invalid.html
new file mode 100644
index 0000000..69af66b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-ligatures-invalid.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: parsing font-variant-ligatures with invalid values</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-variant-ligatures-prop">
+<meta name="assert" content="font-variant-ligatures supports only the grammar 'normal | none | [ <common-lig-values> || <discretionary-lig-values> || <historical-lig-values> || <contextual-alt-values> ]'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_invalid_value('font-variant-ligatures', 'none normal');
+
+test_invalid_value('font-variant-ligatures', 'normal common-ligatures');
+
+test_invalid_value('font-variant-ligatures', 'common-ligatures no-common-ligatures');
+
+test_invalid_value('font-variant-ligatures', 'discretionary-ligatures no-discretionary-ligatures');
+
+test_invalid_value('font-variant-ligatures', 'historical-ligatures no-historical-ligatures');
+
+test_invalid_value('font-variant-ligatures', 'contextual no-contextual');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-ligatures-valid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-ligatures-valid.html
new file mode 100644
index 0000000..2fdd99e2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-ligatures-valid.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: parsing font-variant-ligatures with valid values</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-variant-ligatures-prop">
+<meta name="assert" content="font-variant-ligatures supports the full grammar 'normal | none | [ <common-lig-values> || <discretionary-lig-values> || <historical-lig-values> || <contextual-alt-values> ]'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_valid_value('font-variant-ligatures', 'normal');
+test_valid_value('font-variant-ligatures', 'none');
+
+// <common-lig-values>        = [ common-ligatures | no-common-ligatures ]
+test_valid_value('font-variant-ligatures', 'common-ligatures');
+test_valid_value('font-variant-ligatures', 'no-common-ligatures');
+
+// <discretionary-lig-values> = [ discretionary-ligatures | no-discretionary-ligatures ]
+test_valid_value('font-variant-ligatures', 'discretionary-ligatures');
+test_valid_value('font-variant-ligatures', 'no-discretionary-ligatures');
+
+// <historical-lig-values>    = [ historical-ligatures | no-historical-ligatures ]
+test_valid_value('font-variant-ligatures', 'historical-ligatures');
+test_valid_value('font-variant-ligatures', 'no-historical-ligatures');
+
+// <contextual-alt-values>    = [ contextual | no-contextual ]
+test_valid_value('font-variant-ligatures', 'contextual');
+test_valid_value('font-variant-ligatures', 'no-contextual');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-numeric-computed.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-numeric-computed.html
new file mode 100644
index 0000000..b7706e2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-numeric-computed.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: getComputedValue().fontVariantNumeric</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-variant-numeric-prop">
+<meta name="assert" content="font-variant-numeric computed value is as specified.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value('font-variant-numeric', 'normal');
+
+// <numeric-figure-values>   = [ lining-nums | oldstyle-nums ]
+test_computed_value('font-variant-numeric', 'lining-nums');
+test_computed_value('font-variant-numeric', 'oldstyle-nums');
+
+// <numeric-spacing-values>  = [ proportional-nums | tabular-nums ]
+test_computed_value('font-variant-numeric', 'proportional-nums');
+test_computed_value('font-variant-numeric', 'tabular-nums');
+
+// <numeric-fraction-values> = [ diagonal-fractions | stacked-fractions ]
+test_computed_value('font-variant-numeric', 'diagonal-fractions');
+test_computed_value('font-variant-numeric', 'stacked-fractions');
+
+test_computed_value('font-variant-numeric', 'ordinal');
+
+test_computed_value('font-variant-numeric', 'slashed-zero');
+
+test_computed_value('font-variant-numeric', 'oldstyle-nums tabular-nums diagonal-fractions');
+
+test_computed_value('font-variant-numeric', 'lining-nums proportional-nums stacked-fractions ordinal slashed-zero');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-numeric-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-numeric-invalid.html
new file mode 100644
index 0000000..97f9e14
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-numeric-invalid.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: parsing font-variant-numeric with invalid values</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-variant-numeric-prop">
+<meta name="assert" content="font-variant-numeric supports only the grammar 'normal | [ <numeric-figure-values> || <numeric-spacing-values> || <numeric-fraction-values> || ordinal || slashed-zero ]'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_invalid_value('font-variant-numeric', 'auto');
+
+test_invalid_value('font-variant-numeric', 'normal lining-nums');
+test_invalid_value('font-variant-numeric', 'lining-nums oldstyle-nums');
+
+test_invalid_value('font-variant-numeric', 'proportional-nums normal');
+test_invalid_value('font-variant-numeric', 'tabular-nums proportional-nums');
+
+test_invalid_value('font-variant-numeric', 'normal diagonal-fractions');
+test_invalid_value('font-variant-numeric', 'diagonal-fractions stacked-fractions');
+
+test_invalid_value('font-variant-numeric', 'ordinal normal');
+
+test_invalid_value('font-variant-numeric', 'normal slashed-zero');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-numeric-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-numeric-valid-expected.txt
new file mode 100644
index 0000000..28466d3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-numeric-valid-expected.txt
@@ -0,0 +1,14 @@
+This is a testharness.js-based test.
+PASS e.style['font-variant-numeric'] = "normal" should set the property value
+PASS e.style['font-variant-numeric'] = "lining-nums" should set the property value
+PASS e.style['font-variant-numeric'] = "oldstyle-nums" should set the property value
+PASS e.style['font-variant-numeric'] = "proportional-nums" should set the property value
+PASS e.style['font-variant-numeric'] = "tabular-nums" should set the property value
+PASS e.style['font-variant-numeric'] = "diagonal-fractions" should set the property value
+PASS e.style['font-variant-numeric'] = "stacked-fractions" should set the property value
+PASS e.style['font-variant-numeric'] = "ordinal" should set the property value
+PASS e.style['font-variant-numeric'] = "slashed-zero" should set the property value
+PASS e.style['font-variant-numeric'] = "oldstyle-nums tabular-nums diagonal-fractions" should set the property value
+FAIL e.style['font-variant-numeric'] = "slashed-zero ordinal stacked-fractions proportional-nums lining-nums" should set the property value assert_equals: serialization should be canonical expected "lining-nums proportional-nums stacked-fractions ordinal slashed-zero" but got "slashed-zero ordinal stacked-fractions proportional-nums lining-nums"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-numeric-valid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-numeric-valid.html
new file mode 100644
index 0000000..ed240cc36
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-numeric-valid.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: parsing font-variant-numeric with valid values</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-variant-numeric-prop">
+<meta name="assert" content="font-variant-numeric supports the full grammar 'normal | [ <numeric-figure-values> || <numeric-spacing-values> || <numeric-fraction-values> || ordinal || slashed-zero ]'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_valid_value('font-variant-numeric', 'normal');
+
+// <numeric-figure-values>   = [ lining-nums | oldstyle-nums ]
+test_valid_value('font-variant-numeric', 'lining-nums');
+test_valid_value('font-variant-numeric', 'oldstyle-nums');
+
+// <numeric-spacing-values>  = [ proportional-nums | tabular-nums ]
+test_valid_value('font-variant-numeric', 'proportional-nums');
+test_valid_value('font-variant-numeric', 'tabular-nums');
+
+// <numeric-fraction-values> = [ diagonal-fractions | stacked-fractions ]
+test_valid_value('font-variant-numeric', 'diagonal-fractions');
+test_valid_value('font-variant-numeric', 'stacked-fractions');
+
+test_valid_value('font-variant-numeric', 'ordinal');
+
+test_valid_value('font-variant-numeric', 'slashed-zero');
+
+test_valid_value('font-variant-numeric', 'oldstyle-nums tabular-nums diagonal-fractions');
+
+// Blink gives "slashed-zero ordinal stacked-fractions proportional-nums lining-nums".
+test_valid_value('font-variant-numeric', 'slashed-zero ordinal stacked-fractions proportional-nums lining-nums', 'lining-nums proportional-nums stacked-fractions ordinal slashed-zero');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-position-computed-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-position-computed-expected.txt
new file mode 100644
index 0000000..ea96d55
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-position-computed-expected.txt
@@ -0,0 +1,6 @@
+This is a testharness.js-based test.
+FAIL Property font-variant-position value 'normal' computes to 'normal' assert_true: font-variant-position doesn't seem to be supported in the computed style expected true got false
+FAIL Property font-variant-position value 'sub' computes to 'sub' assert_true: font-variant-position doesn't seem to be supported in the computed style expected true got false
+FAIL Property font-variant-position value 'super' computes to 'super' assert_true: font-variant-position doesn't seem to be supported in the computed style expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-position-computed.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-position-computed.html
new file mode 100644
index 0000000..f11c0f6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-position-computed.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: getComputedValue().fontVariantPosition</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-variant-position-prop">
+<meta name="assert" content="font-variant-position computed value is as specified.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value('font-variant-position', 'normal');
+test_computed_value('font-variant-position', 'sub');
+test_computed_value('font-variant-position', 'super');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-position-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-position-invalid.html
new file mode 100644
index 0000000..11110ce
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-position-invalid.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: parsing font-variant-position with invalid values</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-variant-position-prop">
+<meta name="assert" content="font-variant-position supports only the grammar 'normal | sub | super'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_invalid_value('font-variant-position', 'auto');
+test_invalid_value('font-variant-position', 'super sub');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-position-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-position-valid-expected.txt
new file mode 100644
index 0000000..7058ebb
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-position-valid-expected.txt
@@ -0,0 +1,6 @@
+This is a testharness.js-based test.
+FAIL e.style['font-variant-position'] = "normal" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font-variant-position'] = "sub" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['font-variant-position'] = "super" should set the property value assert_not_equals: property should be set got disallowed value ""
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-position-valid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-position-valid.html
new file mode 100644
index 0000000..3887ab0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-position-valid.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: parsing font-variant-position with valid values</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-variant-position-prop">
+<meta name="assert" content="font-variant-position supports the full grammar 'normal | sub | super'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_valid_value('font-variant-position', 'normal');
+test_valid_value('font-variant-position', 'sub');
+test_valid_value('font-variant-position', 'super');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-weight-computed.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-weight-computed.html
new file mode 100644
index 0000000..b88565e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-weight-computed.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: getComputedValue().fontWeight</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-weight-prop">
+<meta name="assert" content="font-weight computed value is a number.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="container">
+  <div id="target"></div>
+</div>
+<script>
+'use strict';
+test_computed_value('font-weight', 'normal', '400');
+test_computed_value('font-weight', 'bold', '700');
+test_computed_value('font-weight', '100');
+test_computed_value('font-weight', '200');
+test_computed_value('font-weight', '300');
+test_computed_value('font-weight', '400');
+test_computed_value('font-weight', '500');
+test_computed_value('font-weight', '600');
+test_computed_value('font-weight', '700');
+test_computed_value('font-weight', '800');
+test_computed_value('font-weight', '900');
+
+function test_relative(specified, inherited, computed) {
+  test(() => {
+    const container = document.getElementById('container');
+    const target = document.getElementById('target');
+    container.style.fontWeight = inherited;
+    target.style.fontWeight = specified;
+    assert_equals(getComputedStyle(target).fontWeight, computed);
+  }, inherited + ' made ' + specified + ' computes to ' + computed);
+}
+
+test_relative('bolder', '100', '400');
+test_relative('bolder', '200', '400');
+test_relative('bolder', '300', '400');
+test_relative('bolder', '400', '700');
+test_relative('bolder', '500', '700');
+test_relative('bolder', '600', '900');
+test_relative('bolder', '700', '900');
+test_relative('bolder', '800', '900');
+test_relative('bolder', '900', '900');
+
+test_relative('lighter', '100', '100');
+test_relative('lighter', '200', '100');
+test_relative('lighter', '300', '100');
+test_relative('lighter', '400', '100');
+test_relative('lighter', '500', '100');
+test_relative('lighter', '600', '400');
+test_relative('lighter', '700', '400');
+test_relative('lighter', '800', '700');
+test_relative('lighter', '900', '700');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-weight-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-weight-invalid.html
new file mode 100644
index 0000000..af81569
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-weight-invalid.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: parsing font-weight with invalid values</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-weight-prop">
+<meta name="assert" content="font-weight supports only the grammar 'normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_invalid_value('font-weight', 'auto');
+test_invalid_value('font-weight', 'bold 900');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-weight-valid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-weight-valid.html
new file mode 100644
index 0000000..09072928
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-weight-valid.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 3: parsing font-weight with valid values</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-weight-prop">
+<meta name="assert" content="font-weight supports the full grammar 'normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_valid_value('font-weight', 'normal');
+test_valid_value('font-weight', 'bold');
+test_valid_value('font-weight', 'bolder');
+test_valid_value('font-weight', 'lighter');
+test_valid_value('font-weight', '100');
+test_valid_value('font-weight', '200');
+test_valid_value('font-weight', '300');
+test_valid_value('font-weight', '400');
+test_valid_value('font-weight', '500');
+test_valid_value('font-weight', '600');
+test_valid_value('font-weight', '700');
+test_valid_value('font-weight', '800');
+test_valid_value('font-weight', '900');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transitions/CSSTransition-effect.tentative-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-transitions/CSSTransition-effect.tentative-expected.txt
index 542b954..065f2d42 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-transitions/CSSTransition-effect.tentative-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/css-transitions/CSSTransition-effect.tentative-expected.txt
@@ -2,6 +2,7 @@
 FAIL After setting a transition's effect to null, it still reports the original transition property assert_equals: expected (string) "left" but got (undefined) undefined
 PASS After setting a transition's effect to null, it becomes finished
 PASS After setting a transition's effect to null, style is updated
+PASS After setting a transition's effect to null, a new transition can be started
 PASS After setting a new keyframe effect with a shorter duration, the transition becomes finished
 FAIL After setting a new keyframe effect targeting different properties, the transition continues to report the original transition property assert_equals: expected (string) "left" but got (undefined) undefined
 FAIL After setting a new keyframe effect on a play-pending transition, the transition remains pending assert_equals: expected (string) "left" but got (undefined) undefined
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transitions/CSSTransition-effect.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-transitions/CSSTransition-effect.tentative.html
index 3979dd2..a6153b3 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-transitions/CSSTransition-effect.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-transitions/CSSTransition-effect.tentative.html
@@ -56,6 +56,37 @@
   assert_equals(getComputedStyle(div).left, '100px');
 }, 'After setting a transition\'s effect to null, style is updated');
 
+// This is a regression test for https://crbug.com/964113, where Chromium would
+// crash if the running transition's effect was set to null and a new transition
+// was started before the running one could finish.
+promise_test(async t => {
+  const div = addDiv(t);
+  div.style.left = '0px';
+
+  div.style.transition = 'left 100s';
+  getComputedStyle(div).left;
+  div.style.left = '100px';
+
+  assert_equals(div.getAnimations().length, 1);
+
+  const transition = div.getAnimations()[0];
+  await transition.ready;
+
+  // Without yielding to the rendering loop, set the current transition's
+  // effect to null and start a new transition. This should work correctly.
+  transition.effect = null;
+
+  div.style.left = '150px';
+
+  // This will run style update.
+  assert_equals(div.getAnimations().length, 1);
+
+  const new_transition = div.getAnimations()[0];
+  await new_transition.ready;
+
+  assert_equals(getComputedStyle(div).left, '0px');
+}, 'After setting a transition\'s effect to null, a new transition can be started');
+
 promise_test(async t => {
   const div = addDiv(t);
   div.style.left = '0px';
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/parsing/caret-color-computed.html b/third_party/blink/web_tests/external/wpt/css/css-ui/parsing/caret-color-computed.html
new file mode 100644
index 0000000..0428c783
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/parsing/caret-color-computed.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS UI Level 3: getComputedStyle().caretColor</title>
+<link rel="help" href="https://drafts.csswg.org/css-ui-3/#caret-color">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<style>
+  #target {
+    color: blue;
+  }
+</style>
+</head>
+<body>
+<div id="target"></div>
+<script>
+'use strict';
+const currentColor = "rgb(0, 0, 255)";
+test_computed_value("caret-color", "auto", currentColor);
+test_computed_value("caret-color", "currentColor", currentColor);
+test_computed_value("caret-color", "red", "rgb(255, 0, 0)");
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/parsing/outline-color-computed.html b/third_party/blink/web_tests/external/wpt/css/css-ui/parsing/outline-color-computed.html
new file mode 100644
index 0000000..b9aab1d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/parsing/outline-color-computed.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS UI Level 3: getComputedStyle().outlineColor</title>
+<link rel="help" href="https://drafts.csswg.org/css-ui-3/#outline-color">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<style>
+  #target {
+    color: blue;
+  }
+</style>
+</head>
+<body>
+<div id="target"></div>
+<script>
+'use strict';
+const currentColor = "rgb(0, 0, 255)";
+test_computed_value("outline-color", "currentColor", currentColor);
+test_computed_value("outline-color", "red", "rgb(255, 0, 0)");
+
+test(() => {
+  const target = document.getElementById('target');
+  target.style.outlineColor = 'invert';
+  if (target.style.outlineColor === 'invert')
+    assert_equals(getComputedStyle(target).outlineColor, 'invert');
+}, 'invert, if supported, computes to invert');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/element-timing/buffered-flag.html b/third_party/blink/web_tests/external/wpt/element-timing/buffered-flag.html
new file mode 100644
index 0000000..19c387d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/element-timing/buffered-flag.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<meta charset=utf-8>
+<title>Element Timing: observe element with buffered flag</title>
+<body>
+<style>
+body {
+  margin: 0;
+}
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/element-timing-helpers.js"></script>
+<script>
+  async_test(t => {
+    const beforeRender = performance.now();
+    const img = document.createElement('img');
+    if (!window.PerformanceElementTiming) {
+      assert_unreached("PerformanceElementTiming is not implemented");
+    }
+    // Initial observer used to know when entry has been dispatched
+    new PerformanceObserver(() => {
+      // Second observer should require buffered flag to receive the already-dispatched entry.
+      new PerformanceObserver(t.step_func_done(entryList => {
+        assert_equals(entryList.getEntries().length, 1);
+        const entry = entryList.getEntries()[0];
+        const pathname = window.location.origin + '/images/black-rectangle.png';
+        checkElement(entry, pathname, 'my_image', 'my_id', beforeRender, document.getElementById('my_id'));
+        // Test that viewport size is at least 100, so element is fully visible.
+        assert_greater_than_equal(document.documentElement.clientWidth, 100, 'Width should be >= 100');
+        assert_greater_than_equal(document.documentElement.clientHeight, 100, 'Height should be >= 100');
+
+        checkRect(entry, [0, 100, 0, 50]);
+        checkNaturalSize(entry, 100, 50);
+      })).observe({type: 'element', buffered: true});
+    }).observe({type: 'element'});
+    img.src = '/images/black-rectangle.png';
+    img.setAttribute('elementtiming', 'my_image');
+    img.setAttribute('id', 'my_id');
+    document.body.appendChild(img);
+  }, 'Element Timing entries are observable via buffered flag.');
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/buffered-flag-after-timeout.any.js b/third_party/blink/web_tests/external/wpt/performance-timeline/buffered-flag-after-timeout.any.js
new file mode 100644
index 0000000..08b3e32
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/performance-timeline/buffered-flag-after-timeout.any.js
@@ -0,0 +1,11 @@
+async_test(t => {
+  performance.mark('foo');
+  t.step_timeout(() => {
+    // After a timeout, PerformanceObserver should still receive entry if using the buffered flag.
+    new PerformanceObserver(t.step_func_done(list => {
+      const entries = list.getEntries();
+      assert_equals(entries.length, 1, 'There should be 1 mark entry.');
+      assert_equals(entries[0].entryType, 'mark');
+    })).observe({type: 'mark', buffered: true});
+  }, 100);
+}, 'PerformanceObserver with buffered flag sees entry after timeout');
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/buffered-flag-observer.any.js b/third_party/blink/web_tests/external/wpt/performance-timeline/buffered-flag-observer.any.js
new file mode 100644
index 0000000..31dc39c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/performance-timeline/buffered-flag-observer.any.js
@@ -0,0 +1,15 @@
+async_test( t=> {
+  for (let i = 0; i < 50; i++)
+    performance.mark('foo' + i);
+  let marksCreated = 50;
+  let marksReceived = 0;
+  new PerformanceObserver(list => {
+    marksReceived += list.getEntries().length;
+    if (marksCreated < 100) {
+      performance.mark('bar' + marksCreated);
+      marksCreated++;
+    }
+    if (marksReceived == 100)
+      t.done();
+  }).observe({type: 'mark', buffered: true});
+}, 'PerformanceObserver with buffered flag should see past and future entries.');
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/multiple-buffered-flag-observers.any.js b/third_party/blink/web_tests/external/wpt/performance-timeline/multiple-buffered-flag-observers.any.js
new file mode 100644
index 0000000..5dd44fb
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/performance-timeline/multiple-buffered-flag-observers.any.js
@@ -0,0 +1,32 @@
+promise_test(() => {
+  // The first promise waits for one buffered flag observer to receive 3 entries.
+  const promise1 = new Promise(resolve1 => {
+    let numObserved1 = 0;
+    new PerformanceObserver((entryList, obs) => {
+      // This buffered flag observer is constructed after a regular observer detects a mark.
+      new PerformanceObserver(list => {
+        numObserved1 += list.getEntries().length;
+        if (numObserved1 == 3)
+          resolve1();
+      }).observe({type: 'mark', buffered: true});
+      obs.disconnect();
+    }).observe({entryTypes: ['mark']});
+    performance.mark('foo');
+  });
+  // The second promise waits for another buffered flag observer to receive 3 entries.
+  const promise2 = new Promise(resolve2 => {
+    step_timeout(() => {
+      let numObserved2 = 0;
+      // This buffered flag observer is constructed after a delay of 100ms.
+      new PerformanceObserver(list => {
+        numObserved2 += list.getEntries().length;
+        if (numObserved2 == 3)
+          resolve2();
+      }).observe({type: 'mark', buffered: true});
+    }, 100);
+    performance.mark('bar');
+  });
+  performance.mark('meow');
+  // Pass if and only if both buffered observers received all 3 mark entries.
+  return Promise.all([promise1, promise2]);
+}, 'Multiple PerformanceObservers with buffered flag see all entries');
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/observer-buffered-false.any.js b/third_party/blink/web_tests/external/wpt/performance-timeline/observer-buffered-false.any.js
new file mode 100644
index 0000000..a28100b0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/performance-timeline/observer-buffered-false.any.js
@@ -0,0 +1,12 @@
+async_test(t => {
+  performance.mark('foo');
+  // Use a timeout to ensure the remainder of the test runs after the entry is created.
+  t.step_timeout(() => {
+    // Observer with buffered flag set to false should not see entry.
+    new PerformanceObserver(() => {
+      assert_unreached('Should not have observed any entry!');
+    }).observe({type: 'mark', buffered: false});
+    // Use a timeout to give time to the observer.
+    t.step_timeout(t.step_func_done(() => {}), 100);
+  }, 0);
+}, 'PerformanceObserver without buffered flag set to false cannot see past entries.');
diff --git a/third_party/blink/web_tests/external/wpt/tools/webdriver/webdriver/client.py b/third_party/blink/web_tests/external/wpt/tools/webdriver/webdriver/client.py
index 1ce4906..781eabd 100644
--- a/third_party/blink/web_tests/external/wpt/tools/webdriver/webdriver/client.py
+++ b/third_party/blink/web_tests/external/wpt/tools/webdriver/webdriver/client.py
@@ -218,7 +218,12 @@
                         ``ActionSequence.dict``.
         """
         body = {"actions": [] if actions is None else actions}
-        return self.session.send_session_command("POST", "actions", body)
+        actions = self.session.send_session_command("POST", "actions", body)
+        """WebDriver window should be set to the top level window when wptrunner
+        processes the next event.
+        """
+        self.session.switch_frame(None)
+        return actions
 
     @command
     def release(self):
@@ -308,8 +313,11 @@
         self.session = session
 
     @command
-    def css(self, selector, all=True):
-        return self._find_element("css selector", selector, all)
+    def css(self, element_selector, frame, all=True):
+        if (frame != "window"):
+            self.session.switch_frame(frame)
+        elements = self._find_element("css selector", element_selector, all)
+        return elements
 
     def _find_element(self, strategy, selector, all):
         route = "elements" if all else "element"
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/base.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/base.py
index d1c123a..588e0b2 100644
--- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/base.py
+++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/base.py
@@ -669,11 +669,11 @@
                 for action in actionSequence["actions"]:
                     if (action["type"] == "pointerMove" and
                         isinstance(action["origin"], dict)):
-                        action["origin"] = self.get_element(action["origin"]["selector"])
+                        action["origin"] = self.get_element(action["origin"]["selector"], action["frame"]["frame"])
         self.protocol.action_sequence.send_actions({"actions": actions})
 
-    def get_element(self, selector):
-        element = self.protocol.select.element_by_selector(selector)
+    def get_element(self, element_selector, frame):
+        element = self.protocol.select.element_by_selector(element_selector, frame)
         return element
 
 class GenerateTestReportAction(object):
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executormarionette.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executormarionette.py
index 7ab7018..c46571b 100644
--- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executormarionette.py
+++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executormarionette.py
@@ -386,6 +386,9 @@
     def elements_by_selector(self, selector):
         return self.marionette.find_elements("css selector", selector)
 
+    def elements_by_selector_and_frame(self, element_selector, frame):
+        return self.marionette.find_elements("css selector", element_selector)
+
 
 class MarionetteClickProtocolPart(ClickProtocolPart):
     def setup(self):
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorselenium.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorselenium.py
index e7b9f45..9a2d223 100644
--- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorselenium.py
+++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorselenium.py
@@ -149,6 +149,9 @@
     def elements_by_selector(self, selector):
         return self.webdriver.find_elements_by_css_selector(selector)
 
+    def elements_by_selector_and_frame(self, element_selector, frame):
+        return self.webdriver.find_elements_by_css_selector(element_selector)
+
 
 class SeleniumClickProtocolPart(ClickProtocolPart):
     def setup(self):
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorwebdriver.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorwebdriver.py
index 65938a76..ce7691c 100644
--- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorwebdriver.py
+++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorwebdriver.py
@@ -142,6 +142,9 @@
     def elements_by_selector(self, selector):
         return self.webdriver.find.css(selector)
 
+    def elements_by_selector_and_frame(self, element_selector, frame):
+        return self.webdriver.find.css(element_selector, frame)
+
 
 class WebDriverClickProtocolPart(ClickProtocolPart):
     def setup(self):
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/protocol.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/protocol.py
index d08b74b..7da59239 100644
--- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/protocol.py
+++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/protocol.py
@@ -235,12 +235,15 @@
 
     name = "select"
 
-    def element_by_selector(self, selector):
-        elements = self.elements_by_selector(selector)
+    def element_by_selector(self, element_selector, frame="window"):
+        elements = self.elements_by_selector_and_frame(element_selector, frame)
+        frame_name = "window"
+        if (frame != "window"):
+            frame_name = frame.id
         if len(elements) == 0:
-            raise ValueError("Selector '%s' matches no elements" % selector)
+            raise ValueError("Selector '%s' in frame '%s' matches no elements" % (element_selector, frame_name))
         elif len(elements) > 1:
-            raise ValueError("Selector '%s' matches multiple elements" % selector)
+            raise ValueError("Selector '%s' in frame '%s' matches multiple elements" % (element_selector, frame_name))
         return elements[0]
 
     @abstractmethod
@@ -251,6 +254,13 @@
         :returns: A list of protocol-specific handles to elements"""
         pass
 
+    @abstractmethod
+    def elements_by_selector_and_frame(self, element_selector, frame):
+        """Select elements matching a CSS selector
+        :param str selector: The CSS selector
+        :returns: A list of protocol-specific handles to elements"""
+        pass
+
 
 class ClickProtocolPart(ProtocolPart):
     """Protocol part for performing trusted clicks"""
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/testdriver-extra.js b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/testdriver-extra.js
index 09d7c29..e23073d 100644
--- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/testdriver-extra.js
+++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/testdriver-extra.js
@@ -21,10 +21,26 @@
         }
     });
 
+    const get_frame = function(element, frame) {
+        let foundFrame = frame;
+        let frameDocument = frame == window ? window.document : frame.contentDocument;
+        if (!frameDocument.contains(element)) {
+          foundFrame = null;
+          let frames = document.getElementsByTagName("iframe");
+          for (let i = 0; i < frames.length; i++) {
+            if (get_frame(element, frames[i])) {
+              foundFrame = frames[i];
+              break;
+            }
+          }
+        }
+        return foundFrame;
+    };
+
     const get_selector = function(element) {
         let selector;
 
-        if (element.id && document.getElementById(element.id) === element) {
+        if (element.id) {
             const id = element.id;
 
             selector = "#";
@@ -81,8 +97,16 @@
         for (let actionSequence of actions) {
             if (actionSequence.type == "pointer") {
                 for (let action of actionSequence.actions) {
-                    if (action.type == "pointerMove" && action.origin instanceof Element) {
-                        action.origin = {selector: get_selector(action.origin)};
+                    // The origin of each action can only be an element or a string of a value "viewport" or "pointer".
+                    if (action.type == "pointerMove" && typeof(action.origin) != 'string') {
+                        let frame = get_frame(action.origin, window);
+                        if (frame != null) {
+                            if (frame == window)
+                                action.frame = {frame: "window"};
+                            else
+                                action.frame = {frame: frame};
+                            action.origin = {selector: get_selector(action.origin)};
+                        } 
                     }
                 }
             }
diff --git a/third_party/blink/web_tests/external/wpt/user-timing/buffered-flag.any.js b/third_party/blink/web_tests/external/wpt/user-timing/buffered-flag.any.js
new file mode 100644
index 0000000..e3e60656
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/user-timing/buffered-flag.any.js
@@ -0,0 +1,29 @@
+async_test(t => {
+  // First observer creates second in callback to ensure the entry has been dispatched by the time
+  // the second observer begins observing.
+  new PerformanceObserver(() => {
+    // Second observer requires 'buffered: true' to see an entry.
+    new PerformanceObserver(list => {
+      const entries = list.getEntries();
+      assert_equals(entries.length, 1, 'There should be 1 mark entry.');
+      assert_equals(entries[0].entryType, 'mark');
+      t.done();
+    }).observe({type: 'mark', buffered: true});
+  }).observe({entryTypes: ['mark']});
+  performance.mark('foo');
+}, 'PerformanceObserver with buffered flag sees previous marks');
+
+async_test(t => {
+  // First observer creates second in callback to ensure the entry has been dispatched by the time
+  // the second observer begins observing.
+  new PerformanceObserver(() => {
+    // Second observer requires 'buffered: true' to see an entry.
+    new PerformanceObserver(list => {
+      const entries = list.getEntries();
+      assert_equals(entries.length, 1, 'There should be 1 measure entry.');
+      assert_equals(entries[0].entryType, 'measure');
+      t.done();
+    }).observe({type: 'measure', buffered: true});
+  }).observe({entryTypes: ['measure']});
+  performance.measure('bar');
+}, 'PerformanceObserver with buffered flag sees previous measures');
diff --git a/third_party/blink/web_tests/fast/events/window-onerror-03-expected.txt b/third_party/blink/web_tests/fast/events/window-onerror-03-expected.txt
index 0322832..e038e04 100644
--- a/third_party/blink/web_tests/fast/events/window-onerror-03-expected.txt
+++ b/third_party/blink/web_tests/fast/events/window-onerror-03-expected.txt
@@ -2,9 +2,9 @@
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
-window.onerror: "Uncaught ReferenceError: Invalid left-hand side in assignment" at window-onerror-03.html (Line: 1, Column: 1)
+window.onerror: "Uncaught SyntaxError: Invalid left-hand side in assignment" at window-onerror-03.html (Line: 1, Column: 1)
 Stack Trace:
-ReferenceError: Invalid left-hand side in assignment
+SyntaxError: Invalid left-hand side in assignment
     at window-onerror-03.html:14:9
 
 Returning 'true': the error should not be reported in the console as an unhandled exception.
diff --git a/third_party/blink/web_tests/fast/js/assign-expected.txt b/third_party/blink/web_tests/fast/js/assign-expected.txt
index f379b95..42e68ff 100644
--- a/third_party/blink/web_tests/fast/js/assign-expected.txt
+++ b/third_party/blink/web_tests/fast/js/assign-expected.txt
@@ -12,9 +12,9 @@
 PASS ((x)) = 8; x is 8
 PASS ((window.x)) = 9; x is 9
 PASS ((window["x"])) = 10; x is 10
-PASS (y, x) = "FAIL"; threw exception ReferenceError: Invalid left-hand side in assignment.
-PASS (true ? x : y) = "FAIL"; threw exception ReferenceError: Invalid left-hand side in assignment.
-PASS x++ = "FAIL"; threw exception ReferenceError: Invalid left-hand side in assignment.
+PASS (y, x) = "FAIL"; threw exception SyntaxError: Invalid left-hand side in assignment.
+PASS (true ? x : y) = "FAIL"; threw exception SyntaxError: Invalid left-hand side in assignment.
+PASS x++ = "FAIL"; threw exception SyntaxError: Invalid left-hand side in assignment.
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/blink/web_tests/fast/js/postfix-syntax-expected.txt b/third_party/blink/web_tests/fast/js/postfix-syntax-expected.txt
index 37012dd..ecfe66b4 100644
--- a/third_party/blink/web_tests/fast/js/postfix-syntax-expected.txt
+++ b/third_party/blink/web_tests/fast/js/postfix-syntax-expected.txt
@@ -12,8 +12,8 @@
 PASS ((x))++ is 7
 PASS ((window.x))++ is 8
 PASS ((window["x"]))++ is 9
-PASS (y, x)++ threw exception ReferenceError: Invalid left-hand side expression in postfix operation.
-PASS (true ? x : y)++ threw exception ReferenceError: Invalid left-hand side expression in postfix operation.
+PASS (y, x)++ threw exception SyntaxError: Invalid left-hand side expression in postfix operation.
+PASS (true ? x : y)++ threw exception SyntaxError: Invalid left-hand side expression in postfix operation.
 PASS x++++ threw exception SyntaxError: Unexpected token '++'.
 PASS x is 0
 PASS y is 0
diff --git a/third_party/blink/web_tests/fast/js/prefix-syntax-expected.txt b/third_party/blink/web_tests/fast/js/prefix-syntax-expected.txt
index 33c061e..c0ecdb3 100644
--- a/third_party/blink/web_tests/fast/js/prefix-syntax-expected.txt
+++ b/third_party/blink/web_tests/fast/js/prefix-syntax-expected.txt
@@ -12,9 +12,9 @@
 PASS ++((x)) is 8
 PASS ++((window.x)) is 9
 PASS ++((window["x"])) is 10
-PASS ++(y, x) threw exception ReferenceError: Invalid left-hand side expression in prefix operation.
-PASS ++(true ? x : y) threw exception ReferenceError: Invalid left-hand side expression in prefix operation.
-PASS ++++x threw exception ReferenceError: Invalid left-hand side expression in prefix operation.
+PASS ++(y, x) threw exception SyntaxError: Invalid left-hand side expression in prefix operation.
+PASS ++(true ? x : y) threw exception SyntaxError: Invalid left-hand side expression in prefix operation.
+PASS ++++x threw exception SyntaxError: Invalid left-hand side expression in prefix operation.
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/css/cssom-view/scrollIntoView-horizontal-tb-writing-mode-and-rtl-direction-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/css/cssom-view/scrollIntoView-horizontal-tb-writing-mode-and-rtl-direction-expected.txt
new file mode 100644
index 0000000..139ee90
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/external/wpt/css/cssom-view/scrollIntoView-horizontal-tb-writing-mode-and-rtl-direction-expected.txt
@@ -0,0 +1,12 @@
+This is a testharness.js-based test.
+FAIL scrollIntoView({"block":"start","inline":"start"}) assert_approx_equals: scrollX expected -200 +/- 0.5 but got 215
+FAIL scrollIntoView({"block":"start","inline":"center"}) assert_approx_equals: scrollX expected -157.5 +/- 0.5 but got 172
+FAIL scrollIntoView({"block":"start","inline":"end"}) assert_approx_equals: scrollX expected -115 +/- 0.5 but got 130
+FAIL scrollIntoView({"block":"center","inline":"start"}) assert_approx_equals: scrollX expected -200 +/- 0.5 but got 215
+FAIL scrollIntoView({"block":"center","inline":"center"}) assert_approx_equals: scrollX expected -157.5 +/- 0.5 but got 172
+FAIL scrollIntoView({"block":"center","inline":"end"}) assert_approx_equals: scrollX expected -115 +/- 0.5 but got 130
+FAIL scrollIntoView({"block":"end","inline":"start"}) assert_approx_equals: scrollX expected -200 +/- 0.5 but got 215
+FAIL scrollIntoView({"block":"end","inline":"center"}) assert_approx_equals: scrollX expected -157.5 +/- 0.5 but got 172
+FAIL scrollIntoView({"block":"end","inline":"end"}) assert_approx_equals: scrollX expected -115 +/- 0.5 but got 130
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/webaudio/Oscillator/osc-sweep-snr-triangle.html b/third_party/blink/web_tests/webaudio/Oscillator/osc-sweep-snr-triangle.html
index 2c70a73..1a40bcf 100644
--- a/third_party/blink/web_tests/webaudio/Oscillator/osc-sweep-snr-triangle.html
+++ b/third_party/blink/web_tests/webaudio/Oscillator/osc-sweep-snr-triangle.html
@@ -22,7 +22,7 @@
             1, tester.sampleRate * tester.lengthInSeconds, tester.sampleRate);
 
         // The thresholds are experimentally determined.
-        tester.setThresholds({snr: 140.09, maxDiff: 2.8313e-6});
+        tester.setThresholds({snr: 139.98, maxDiff: 2.8313e-6});
         tester.runTest(
             context, 'triangle', 'Triangle Oscillator with Exponential Sweep ',
             task, should);
diff --git a/third_party/harfbuzz-ng/README.chromium b/third_party/harfbuzz-ng/README.chromium
index 807337d9..4dbce93 100644
--- a/third_party/harfbuzz-ng/README.chromium
+++ b/third_party/harfbuzz-ng/README.chromium
@@ -1,9 +1,9 @@
 Name: harfbuzz-ng
 Short Name: harfbuzz-ng
 URL: http://harfbuzz.org
-Version: 2.5.3-18
-Date: 20190627
-Revision: 7185bd6ffb4dd8c0efebdab5b930e62c5695e3ab
+Version: 2.5.3-60
+Date: 20190708
+Revision: 2e7021da7d1726a37822e6a001b9218f82255bc8
 Security Critical: yes
 License: MIT
 License File: src/COPYING
diff --git a/tools/clang/traffic_annotation_extractor/traffic_annotation_extractor.cpp b/tools/clang/traffic_annotation_extractor/traffic_annotation_extractor.cpp
index b1e64db..5e67fa5 100644
--- a/tools/clang/traffic_annotation_extractor/traffic_annotation_extractor.cpp
+++ b/tools/clang/traffic_annotation_extractor/traffic_annotation_extractor.cpp
@@ -47,17 +47,6 @@
 struct Location {
   std::string file_path;
   int line_number = -1;
-
-  // Name of the function including this line. E.g., in the following code,
-  // |function_name| will be 'foo' for all |line_number| values 101-103.
-  //
-  // 100 void foo() {
-  // 101   NetworkTrafficAnnotationTag baz =
-  // 102       net::DefineNetworkTrafficAnnotation(...); }
-  // 103   bar(baz);
-  // 104 }
-  // If no function is found, 'Global Namespace' will be returned.
-  std::string function_name;
 };
 
 // An instance of a call to either of the 4 network traffic annotation
@@ -165,13 +154,6 @@
     location->line_number =
         result.SourceManager->getSpellingLineNumber(source_location);
 
-    const clang::FunctionDecl* ancestor =
-        result.Nodes.getNodeAs<clang::FunctionDecl>("function_context");
-    if (ancestor)
-      location->function_name = ancestor->getQualifiedNameAsString();
-    else
-      location->function_name = "Global Namespace";
-
     std::replace(location->file_path.begin(), location->file_path.end(), '\\',
                  '/');
 
@@ -196,45 +178,20 @@
     collector_->calls.push_back(instance);
   }
 
-  // Tests if the given function name belongs to the network traffic annotation
-  // API. These functions are all defined in
-  // 'net/traffic_annotation/network_traffic_annotation.h'.
-  bool IsAPIFunction(const std::string& function_name) {
-    return function_name == "net::NetworkTrafficAnnotationTag::NotReached" ||
-           function_name == "net::DefineNetworkTrafficAnnotation" ||
-           function_name == "net::DefinePartialNetworkTrafficAnnotation" ||
-           function_name == "net::CompleteNetworkTrafficAnnotation" ||
-           function_name == "net::BranchedCompleteNetworkTrafficAnnotation" ||
-           function_name ==
-               "net::MutableNetworkTrafficAnnotationTag::operator "
-               "NetworkTrafficAnnotationTag" ||
-           function_name ==
-               "net::MutablePartialNetworkTrafficAnnotationTag::operator "
-               "PartialNetworkTrafficAnnotationTag";
-  }
-
   // Stores an annotation constructor called with list expression.
   void AddConstructor(const clang::CXXConstructExpr* constructor_expr,
                       const MatchFinder::MatchResult& result) {
     Location instance;
-
     GetInstanceLocation(result, constructor_expr, &instance);
-    // Only report if the constructor is not in one of the API functions for
-    // network traffic annotations.
-    if (!IsAPIFunction(instance.function_name))
-      collector_->assignments.push_back(instance);
+    collector_->assignments.push_back(instance);
   }
 
   // Stores a value assignment to |unique_id_hash_code| of a mutable annotaton.
   void AddAssignment(const clang::MemberExpr* member_expr,
                      const MatchFinder::MatchResult& result) {
     Location instance;
-
     GetInstanceLocation(result, member_expr, &instance);
-    // Only report if the assignment is not in one of the API functions for
-    // network traffic annotations.
-    if (!IsAPIFunction(instance.function_name))
-      collector_->assignments.push_back(instance);
+    collector_->assignments.push_back(instance);
   }
 
   // Stores an annotation.
@@ -414,7 +371,6 @@
   for (const NetworkAnnotationInstance& instance : collector.annotations) {
     llvm::outs() << "==== NEW ANNOTATION ====\n";
     llvm::outs() << instance.location.file_path << "\n";
-    llvm::outs() << instance.location.function_name << "\n";
     llvm::outs() << instance.location.line_number << "\n";
     llvm::outs() << instance.GetTypeName() << "\n";
     llvm::outs() << instance.annotation.unique_id << "\n";
@@ -427,7 +383,6 @@
   for (const CallInstance& instance : collector.calls) {
     llvm::outs() << "==== NEW CALL ====\n";
     llvm::outs() << instance.location.file_path << "\n";
-    llvm::outs() << instance.location.function_name << "\n";
     llvm::outs() << instance.location.line_number << "\n";
     llvm::outs() << instance.called_function_name << "\n";
     llvm::outs() << instance.has_annotation << "\n";
@@ -438,7 +393,6 @@
   for (const Location& instance : collector.assignments) {
     llvm::outs() << "==== NEW ASSIGNMENT ====\n";
     llvm::outs() << instance.file_path << "\n";
-    llvm::outs() << instance.function_name << "\n";
     llvm::outs() << instance.line_number << "\n";
     llvm::outs() << "==== ASSIGNMENT ENDS ====\n";
   }
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 1ff247f..0dac4e6 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -1070,6 +1070,20 @@
   <int value="1" label="Non-isolated ad request"/>
 </enum>
 
+<enum name="AdPopupTriggerAction">
+  <int value="0" label="The trigger was activated"/>
+  <int value="1"
+      label="A popup caused by an ad was detected and a report was collected"/>
+  <int value="2" label="No Google ad was found"/>
+  <int value="3"
+      label="A Google ad led to a popup that was blocked but the report
+             wasn't sent because of user state or settings (Incognito, or
+             non-SBER)"/>
+  <int value="4"
+      label="An ad was found but data collection was rejected to limit
+             frequency"/>
+</enum>
+
 <enum name="AdSamplerTriggerAction">
   <int value="0" label="The trigger was activated"/>
   <int value="1" label="An ad was found and data was collected"/>
@@ -23958,6 +23972,9 @@
   <int value="7" label="CLUSTER_CHILD_NOT_CARD"/>
   <int value="8" label="CARD_CHILD_MISSING_FEATURE"/>
   <int value="9" label="NULL_SHARED_STATES"/>
+  <int value="10" label="FAILED_TO_CREATE_LEAF"/>
+  <int value="11" label="UNHANDLED_TOKEN"/>
+  <int value="12" label="TASK_QUEUE_STARVATION"/>
 </enum>
 
 <enum name="FeedRequestReason">
@@ -53197,6 +53214,383 @@
   <int value="12" label="Unknown"/>
 </enum>
 
+<enum name="SigninSSOAuthGetIdentitiesErrorCode">
+  <int value="-67898" label="errSecTimestampRevocationNotification"/>
+  <int value="-67897" label="errSecTimestampRevocationWarning"/>
+  <int value="-67896" label="errSecTimestampWaiting"/>
+  <int value="-67895" label="errSecTimestampRejection"/>
+  <int value="-67894" label="errSecSigningTimeMissing"/>
+  <int value="-67893" label="errSecTimestampSystemFailure"/>
+  <int value="-67892" label="errSecTimestampAddInfoNotAvailable"/>
+  <int value="-67891" label="errSecTimestampUnacceptedExtension"/>
+  <int value="-67890" label="errSecTimestampUnacceptedPolicy"/>
+  <int value="-67889" label="errSecTimestampTimeNotAvailable"/>
+  <int value="-67888" label="errSecTimestampBadDataFormat"/>
+  <int value="-67887" label="errSecTimestampBadRequest"/>
+  <int value="-67886" label="errSecTimestampBadAlg"/>
+  <int value="-67885" label="errSecTimestampServiceNotAvailable"/>
+  <int value="-67884" label="errSecTimestampNotTrusted"/>
+  <int value="-67883" label="errSecTimestampInvalid"/>
+  <int value="-67882" label="errSecTimestampMissing"/>
+  <int value="-67881" label="errSecExtendedKeyUsageNotCritical"/>
+  <int value="-67880" label="errSecMissingRequiredExtension"/>
+  <int value="-67879" label="errSecInvalidModifyMode"/>
+  <int value="-67878" label="errSecInvalidNewOwner"/>
+  <int value="-67877" label="errSecInvalidIndexInfo"/>
+  <int value="-67876" label="errSecInvalidAccessRequest"/>
+  <int value="-67875" label="errSecInvalidDBLocation"/>
+  <int value="-67874" label="errSecUnsupportedOperator"/>
+  <int value="-67873" label="errSecUnsupportedNumSelectionPreds"/>
+  <int value="-67872" label="errSecUnsupportedQueryLimits"/>
+  <int value="-67871" label="errSecMissingValue"/>
+  <int value="-67870" label="errSecDatastoreIsOpen"/>
+  <int value="-67869" label="errSecDatabaseLocked"/>
+  <int value="-67868" label="errSecInvalidParsingModule"/>
+  <int value="-67867" label="errSecIncompatibleFieldFormat"/>
+  <int value="-67866" label="errSecFieldSpecifiedMultiple"/>
+  <int value="-67865" label="errSecUnsupportedNumRecordTypes"/>
+  <int value="-67864" label="errSecUnsupportedNumIndexes"/>
+  <int value="-67863" label="errSecUnsupportedNumAttributes"/>
+  <int value="-67862" label="errSecUnsupportedLocality"/>
+  <int value="-67861" label="errSecUnsupportedIndexInfo"/>
+  <int value="-67860" label="errSecUnsupportedFieldFormat"/>
+  <int value="-67859" label="errSecNoFieldValues"/>
+  <int value="-67858" label="errSecInvalidCRLIndex"/>
+  <int value="-67857" label="errSecInvalidBundleInfo"/>
+  <int value="-67856" label="errSecRequestDescriptor"/>
+  <int value="-67855" label="errSecInvalidRequestor"/>
+  <int value="-67854" label="errSecInvalidValidityPeriod"/>
+  <int value="-67853" label="errSecInvalidEncoding"/>
+  <int value="-67852" label="errSecInvalidTupleCredendtials"/>
+  <int value="-67851" label="errSecInvalidBaseACLs"/>
+  <int value="-67850" label="errSecInvalidTupleGroup"/>
+  <int value="-67849" label="errSecUnsupportedService"/>
+  <int value="-67848" label="errSecUnsupportedAddressType"/>
+  <int value="-67847" label="errSecRequestRejected"/>
+  <int value="-67846" label="errSecRequestLost"/>
+  <int value="-67845" label="errSecRejectedForm"/>
+  <int value="-67844" label="errSecNoDefaultAuthority"/>
+  <int value="-67843" label="errSecNotTrusted"/>
+  <int value="-67842" label="errSecMultipleValuesUnsupported"/>
+  <int value="-67841" label="errSecInvalidTuple"/>
+  <int value="-67840" label="errSecInvalidStopOnPolicy"/>
+  <int value="-67839" label="errSecInvalidResponseVector"/>
+  <int value="-67838" label="errSecInvalidRequestInputs"/>
+  <int value="-67837" label="errSecInvalidReason"/>
+  <int value="-67836" label="errSecInvalidTimeString"/>
+  <int value="-67835" label="errSecInvalidPolicyIdentifiers"/>
+  <int value="-67834" label="errSecInvalidIndex"/>
+  <int value="-67833" label="errSecInvalidIdentifier"/>
+  <int value="-67832" label="errSecInvalidID"/>
+  <int value="-67831" label="errSecInvalidFormType"/>
+  <int value="-67830" label="errSecInvalidCRL"/>
+  <int value="-67829" label="errSecInvalidCRLType"/>
+  <int value="-67828" label="errSecInvalidCRLEncoding"/>
+  <int value="-67827" label="errSecInvaldCRLAuthority"/>
+  <int value="-67826" label="errSecInvalidCertAuthority"/>
+  <int value="-67825" label="errSecVerifyActionFailed"/>
+  <int value="-67824" label="errSecInvalidAuthority"/>
+  <int value="-67823" label="errSecInvalidAction"/>
+  <int value="-67822" label="errSecInsufficientCredentials"/>
+  <int value="-67821" label="errSecCertificateSuspended"/>
+  <int value="-67820" label="errSecCertificateRevoked"/>
+  <int value="-67819" label="errSecCertificateNotValidYet"/>
+  <int value="-67818" label="errSecCertificateExpired"/>
+  <int value="-67817" label="errSecCertificateCannotOperate"/>
+  <int value="-67816" label="errSecInvalidCRLGroup"/>
+  <int value="-67815" label="errSecInvalidDigestAlgorithm"/>
+  <int value="-67814" label="errSecAlreadyLoggedIn"/>
+  <int value="-67813" label="errSecInvalidLoginName"/>
+  <int value="-67812" label="errSecDeviceVerifyFailed"/>
+  <int value="-67811" label="errSecPublicKeyInconsistent"/>
+  <int value="-67810" label="errSecBlockSizeMismatch"/>
+  <int value="-67809" label="errSecQuerySizeUnknown"/>
+  <int value="-67808" label="errSecVerifyFailed"/>
+  <int value="-67807" label="errSecStagedOperationNotStarted"/>
+  <int value="-67806" label="errSecStagedOperationInProgress"/>
+  <int value="-67805" label="errSecMissingAttributeWrappedKeyFormat"/>
+  <int value="-67804" label="errSecInvalidAttributeWrappedKeyFormat"/>
+  <int value="-67803" label="errSecMissingAttributeSymmetricKeyFormat"/>
+  <int value="-67802" label="errSecInvalidAttributeSymmetricKeyFormat"/>
+  <int value="-67801" label="errSecMissingAttributePrivateKeyFormat"/>
+  <int value="-67800" label="errSecInvalidAttributePrivateKeyFormat"/>
+  <int value="-67799" label="errSecMissingAttributePublicKeyFormat"/>
+  <int value="-67798" label="errSecInvalidAttributePublicKeyFormat"/>
+  <int value="-67797" label="errSecMissingAttributeAccessCredentials"/>
+  <int value="-67796" label="errSecInvalidAttributeAccessCredentials"/>
+  <int value="-67795" label="errSecMissingAttributeDLDBHandle"/>
+  <int value="-67794" label="errSecInvalidAttributeDLDBHandle"/>
+  <int value="-67793" label="errSecMissingAttributeIterationCount"/>
+  <int value="-67792" label="errSecInvalidAttributeIterationCount"/>
+  <int value="-67791" label="errSecMissingAttributeSubprime"/>
+  <int value="-67790" label="errSecInvalidAttributeSubprime"/>
+  <int value="-67789" label="errSecMissingAttributeBase"/>
+  <int value="-67788" label="errSecInvalidAttributeBase"/>
+  <int value="-67787" label="errSecMissingAttributePrime"/>
+  <int value="-67786" label="errSecInvalidAttributePrime"/>
+  <int value="-67785" label="errSecMissingAttributeVersion"/>
+  <int value="-67784" label="errSecInvalidAttributeVersion"/>
+  <int value="-67783" label="errSecMissingAttributeEndDate"/>
+  <int value="-67782" label="errSecInvalidAttributeEndDate"/>
+  <int value="-67781" label="errSecMissingAttributeStartDate"/>
+  <int value="-67780" label="errSecInvalidAttributeStartDate"/>
+  <int value="-67779" label="errSecMissingAttributeEffectiveBits"/>
+  <int value="-67778" label="errSecInvalidAttributeEffectiveBits"/>
+  <int value="-67777" label="errSecMissingAttributeMode"/>
+  <int value="-67776" label="errSecInvalidAttributeMode"/>
+  <int value="-67775" label="errSecMissingAttributeKeyType"/>
+  <int value="-67774" label="errSecInvalidAttributeKeyType"/>
+  <int value="-67773" label="errSecMissingAttributeLabel"/>
+  <int value="-67772" label="errSecInvalidAttributeLabel"/>
+  <int value="-67771" label="errSecMissingAlgorithmParms"/>
+  <int value="-67770" label="errSecInvalidAlgorithmParms"/>
+  <int value="-67769" label="errSecMissingAttributeRounds"/>
+  <int value="-67768" label="errSecInvalidAttributeRounds"/>
+  <int value="-67767" label="errSecMissingAttributeOutputSize"/>
+  <int value="-67766" label="errSecInvalidAttributeOutputSize"/>
+  <int value="-67765" label="errSecMissingAttributeBlockSize"/>
+  <int value="-67764" label="errSecInvalidAttributeBlockSize"/>
+  <int value="-67763" label="errSecMissingAttributeKeyLength"/>
+  <int value="-67762" label="errSecInvalidAttributeKeyLength"/>
+  <int value="-67761" label="errSecMissingAttributePassphrase"/>
+  <int value="-67760" label="errSecInvalidAttributePassphrase"/>
+  <int value="-67759" label="errSecMissingAttributeSeed"/>
+  <int value="-67758" label="errSecInvalidAttributeSeed"/>
+  <int value="-67757" label="errSecMissingAttributeRandom"/>
+  <int value="-67756" label="errSecInvalidAttributeRandom"/>
+  <int value="-67755" label="errSecMissingAttributePadding"/>
+  <int value="-67754" label="errSecInvalidAttributePadding"/>
+  <int value="-67753" label="errSecMissingAttributeSalt"/>
+  <int value="-67752" label="errSecInvalidAttributeSalt"/>
+  <int value="-67751" label="errSecMissingAttributeInitVector"/>
+  <int value="-67750" label="errSecInvalidAttributeInitVector"/>
+  <int value="-67749" label="errSecMissingAttributeKey"/>
+  <int value="-67748" label="errSecInvalidAttributeKey"/>
+  <int value="-67747" label="errSecInvalidAlgorithm"/>
+  <int value="-67746" label="errSecInvalidContext"/>
+  <int value="-67745" label="errSecInvalidOutputVector"/>
+  <int value="-67744" label="errSecInvalidInputVector"/>
+  <int value="-67743" label="errSecUnsupportedVectorOfBuffers"/>
+  <int value="-67742" label="errSecInvalidKeyFormat"/>
+  <int value="-67741" label="errSecUnsupportedKeyLabel"/>
+  <int value="-67740" label="errSecInvalidKeyLabel"/>
+  <int value="-67739" label="errSecUnsupportedKeyAttributeMask"/>
+  <int value="-67738" label="errSecInvalidKeyAttributeMask"/>
+  <int value="-67737" label="errSecUnsupportedKeyUsageMask"/>
+  <int value="-67736" label="errSecInvalidKeyUsageMask"/>
+  <int value="-67735" label="errSecUnsupportedKeySize"/>
+  <int value="-67734" label="errSecUnsupportedKeyFormat"/>
+  <int value="-67733" label="errSecKeyHeaderInconsistent"/>
+  <int value="-67732" label="errSecKeyBlobTypeIncorrect"/>
+  <int value="-67731" label="errSecKeyUsageIncorrect"/>
+  <int value="-67730" label="errSecAlgorithmMismatch"/>
+  <int value="-67729" label="errSecNotLoggedIn"/>
+  <int value="-67728" label="errSecAttachHandleBusy"/>
+  <int value="-67727" label="errSecDeviceError"/>
+  <int value="-67726" label="errSecPrivilegeNotSupported"/>
+  <int value="-67725" label="errSecOutputLengthError"/>
+  <int value="-67724" label="errSecInputLengthError"/>
+  <int value="-67723" label="errSecEventNotificationCallbackNotFound"/>
+  <int value="-67722" label="errSecModuleManagerNotFound"/>
+  <int value="-67721" label="errSecModuleManagerInitializeFailed"/>
+  <int value="-67720" label="errSecAttributeNotInContext"/>
+  <int value="-67719" label="errSecInvalidSubServiceID"/>
+  <int value="-67718" label="errSecModuleNotLoaded"/>
+  <int value="-67717" label="errSecInvalidServiceMask"/>
+  <int value="-67716" label="errSecInvalidAddinFunctionTable"/>
+  <int value="-67715" label="errSecLibraryReferenceNotFound"/>
+  <int value="-67714" label="errSecAddinUnloadFailed"/>
+  <int value="-67713" label="errSecInvalidKeyHierarchy"/>
+  <int value="-67712" label="errSecInvalidKeyRef"/>
+  <int value="-67711" label="errSecAddinLoadFailed"/>
+  <int value="-67710" label="errSecEMMUnloadFailed"/>
+  <int value="-67709" label="errSecEMMLoadFailed"/>
+  <int value="-67708" label="errSecInvalidPVC"/>
+  <int value="-67707" label="errSecPVCAlreadyConfigured"/>
+  <int value="-67706" label="errSecInvalidScope"/>
+  <int value="-67705" label="errSecPrivilegeNotGranted"/>
+  <int value="-67704" label="errSecIncompatibleVersion"/>
+  <int value="-67703" label="errSecInvalidSampleValue"/>
+  <int value="-67702" label="errSecInvalidACL"/>
+  <int value="-67701" label="errSecInvalidRecord"/>
+  <int value="-67700" label="errSecInvalidAccessCredentials"/>
+  <int value="-67699" label="errSecACLChangeFailed"/>
+  <int value="-67698" label="errSecACLAddFailed"/>
+  <int value="-67697" label="errSecACLReplaceFailed"/>
+  <int value="-67696" label="errSecACLDeleteFailed"/>
+  <int value="-67695" label="errSecCallbackFailed"/>
+  <int value="-67694" label="errSecInvalidValue"/>
+  <int value="-67693" label="errSecInvalidQuery"/>
+  <int value="-67692" label="errSecTagNotFound"/>
+  <int value="-67691" label="errSecInvalidCertificateGroup"/>
+  <int value="-67690" label="errSecInvalidCertificateRef"/>
+  <int value="-67689" label="errSecInvalidName"/>
+  <int value="-67688" label="errSecInvalidSignature"/>
+  <int value="-67687" label="errSecUnknownTag"/>
+  <int value="-67686" label="errSecVerificationFailure"/>
+  <int value="-67685" label="errSecInvalidNumberOfFields"/>
+  <int value="-67684" label="errSecCRLAlreadySigned"/>
+  <int value="-67683" label="errSecInvalidNetworkAddress"/>
+  <int value="-67682" label="errSecInvalidPassthroughID"/>
+  <int value="-67681" label="errSecInvalidDBList"/>
+  <int value="-67680" label="errSecInvalidHandle"/>
+  <int value="-67679" label="errSecInvalidGUID"/>
+  <int value="-67678" label="errSecModuleManifestVerifyFailed"/>
+  <int value="-67677" label="errSecFunctionFailed"/>
+  <int value="-67676" label="errSecSelfCheckFailed"/>
+  <int value="-67675" label="errSecInvalidPointer"/>
+  <int value="-67674" label="errSecMDSError"/>
+  <int value="-67673" label="errSecInvalidData"/>
+  <int value="-67672" label="errSecMemoryError"/>
+  <int value="-67671" label="errSecInternalError"/>
+  <int value="-67670" label="errSecFunctionIntegrityFail"/>
+  <int value="-67669" label="errSecPVCReferentNotFound"/>
+  <int value="-67668" label="errSecInvalidHandleUsage"/>
+  <int value="-67667" label="errSecNotInitialized"/>
+  <int value="-67666" label="errSecMobileMeFailedConsistencyCheck"/>
+  <int value="-67665" label="errSecMobileMeCSRVerifyFailure"/>
+  <int value="-67664" label="errSecMobileMeNoRequestPending"/>
+  <int value="-67663" label="errSecMobileMeRequestAlreadyPending"/>
+  <int value="-67662" label="errSecMobileMeServerServiceErr"/>
+  <int value="-67661" label="errSecMobileMeServerAlreadyExists"/>
+  <int value="-67660" label="errSecMobileMeServerNotAvailable"/>
+  <int value="-67659" label="errSecMobileMeServerError"/>
+  <int value="-67658" label="errSecMobileMeRequestRedirected"/>
+  <int value="-67657" label="errSecMobileMeRequestQueued"/>
+  <int value="-67656" label="errSecUnknownQualifiedCertStatement"/>
+  <int value="-67655" label="errSecInvalidSubjectName"/>
+  <int value="-67654" label="errSecTrustSettingDeny"/>
+  <int value="-67653" label="errSecResourceSignBadExtKeyUsage"/>
+  <int value="-67652" label="errSecResourceSignBadCertChainLength"/>
+  <int value="-67651" label="errSecCodeSigningDevelopment"/>
+  <int value="-67650" label="errSecCodeSigningNoExtendedKeyUsage"/>
+  <int value="-67649" label="errSecCodeSigningBadPathLengthConstraint"/>
+  <int value="-67648" label="errSecCodeSigningNoBasicConstraints"/>
+  <int value="-67647" label="errSecCodeSigningBadCertChainLength"/>
+  <int value="-67646" label="errSecOCSPResponseNonceMismatch"/>
+  <int value="-67645" label="errSecOCSPResponderUnauthorized"/>
+  <int value="-67644" label="errSecOCSPResponderSignatureRequired"/>
+  <int value="-67643" label="errSecOCSPResponderTryLater"/>
+  <int value="-67642" label="errSecOCSPResponderInternalError"/>
+  <int value="-67641" label="errSecOCSPResponderMalformedReq"/>
+  <int value="-67640" label="errSecOCSPNoSigner"/>
+  <int value="-67639" label="errSecOCSPSignatureError"/>
+  <int value="-67638" label="errSecRecordModified"/>
+  <int value="-67637" label="errSecOCSPNotTrustedToAnchor"/>
+  <int value="-67636" label="errSecNetworkFailure"/>
+  <int value="-67635" label="errSecIncompleteCertRevocationCheck"/>
+  <int value="-67634" label="errSecEndOfData"/>
+  <int value="-67633" label="errSecOCSPStatusUnrecognized"/>
+  <int value="-67632" label="errSecOCSPUnavailable"/>
+  <int value="-67631" label="errSecOCSPBadRequest"/>
+  <int value="-67630" label="errSecOCSPBadResponse"/>
+  <int value="-67629" label="errSecSSLBadExtendedKeyUsage"/>
+  <int value="-67628" label="errSecSMIMESubjAltNameNotCritical"/>
+  <int value="-67627" label="errSecSMIMENoEmailAddress"/>
+  <int value="-67626" label="errSecSMIMEKeyUsageNotCritical"/>
+  <int value="-67625" label="errSecSMIMEBadKeyUsage"/>
+  <int value="-67624" label="errSecSMIMEBadExtendedKeyUsage"/>
+  <int value="-67623" label="errSecSMIMEEmailAddressesNotFound"/>
+  <int value="-67622" label="errSecIDPFailure"/>
+  <int value="-67621" label="errSecCRLPolicyFailed"/>
+  <int value="-67620" label="errSecCRLNotTrusted"/>
+  <int value="-67619" label="errSecUnknownCRLExtension"/>
+  <int value="-67618" label="errSecUnknownCertExtension"/>
+  <int value="-67617" label="errSecCRLBadURI"/>
+  <int value="-67616" label="errSecCRLServerDown"/>
+  <int value="-67615" label="errSecCRLNotFound"/>
+  <int value="-67614" label="errSecCRLNotValidYet"/>
+  <int value="-67613" label="errSecCRLExpired"/>
+  <int value="-67612" label="errSecInvalidRoot"/>
+  <int value="-67611" label="errSecPathLengthConstraintExceeded"/>
+  <int value="-67610" label="errSecInvalidIDLinkage"/>
+  <int value="-67609" label="errSecInvalidExtendedKeyUsage"/>
+  <int value="-67608" label="errSecInvalidKeyUsageForPolicy"/>
+  <int value="-67607" label="errSecInvalidSubjectKeyID"/>
+  <int value="-67606" label="errSecInvalidAuthorityKeyID"/>
+  <int value="-67605" label="errSecNoBasicConstraintsCA"/>
+  <int value="-67604" label="errSecNoBasicConstraints"/>
+  <int value="-67603" label="errSecUnknownCriticalExtensionFlag"/>
+  <int value="-67602" label="errSecHostNameMismatch"/>
+  <int value="-67601" label="errSecIncompatibleKeyBlob"/>
+  <int value="-67600" label="errSecIncompatibleDatabaseBlob"/>
+  <int value="-67599" label="errSecInvalidKeyBlob"/>
+  <int value="-67598" label="errSecInvalidDatabaseBlob"/>
+  <int value="-67597" label="errSecFileTooBig"/>
+  <int value="-67596" label="errSecQuotaExceeded"/>
+  <int value="-67595" label="errSecAppleSSLv2Rollback"/>
+  <int value="-67594" label="errSecConversionError"/>
+  <int value="-67593" label="errSecAppleInvalidKeyEndDate"/>
+  <int value="-67592" label="errSecAppleInvalidKeyStartDate"/>
+  <int value="-67591" label="errSecAppleSignatureMismatch"/>
+  <int value="-67590" label="errSecApplePublicKeyIncomplete"/>
+  <int value="-67589" label="errSecAppleAddAppACLSubject"/>
+  <int value="-67588" label="errSecDeviceFailed"/>
+  <int value="-67587" label="errSecDeviceReset"/>
+  <int value="-67586" label="errSecInsufficientClientID"/>
+  <int value="-67585" label="errSecServiceNotAvailable"/>
+  <int value="-34018" label="errSecMissingEntitlement"/>
+  <int value="-26275" label="errSecDecode"/>
+  <int value="-26267" label="errSecNotSigner"/>
+  <int value="-25320" label="errSecInDarkWake"/>
+  <int value="-25319" label="errSecInvalidPrefsDomain"/>
+  <int value="-25318" label="errSecCreateChainFailed"/>
+  <int value="-25317" label="errSecDataNotModifiable"/>
+  <int value="-25316" label="errSecDataNotAvailable"/>
+  <int value="-25315" label="errSecInteractionRequired"/>
+  <int value="-25314" label="errSecNoPolicyModule"/>
+  <int value="-25313" label="errSecNoCertificateModule"/>
+  <int value="-25312" label="errSecNoStorageModule"/>
+  <int value="-25311" label="errSecKeySizeNotAllowed"/>
+  <int value="-25310" label="errSecWrongSecVersion"/>
+  <int value="-25309" label="errSecReadOnlyAttr"/>
+  <int value="-25308" label="errSecInteractionNotAllowed"/>
+  <int value="-25307" label="errSecNoDefaultKeychain"/>
+  <int value="-25306" label="errSecNoSuchClass"/>
+  <int value="-25305" label="errSecInvalidSearchRef"/>
+  <int value="-25304" label="errSecInvalidItemRef"/>
+  <int value="-25303" label="errSecNoSuchAttr"/>
+  <int value="-25302" label="errSecDataTooLarge"/>
+  <int value="-25301" label="errSecBufferTooSmall"/>
+  <int value="-25300" label="errSecItemNotFound"/>
+  <int value="-25299" label="errSecDuplicateItem"/>
+  <int value="-25298" label="errSecInvalidCallback"/>
+  <int value="-25297" label="errSecDuplicateCallback"/>
+  <int value="-25296" label="errSecDuplicateKeychain"/>
+  <int value="-25295" label="errSecInvalidKeychain"/>
+  <int value="-25294" label="errSecNoSuchKeychain"/>
+  <int value="-25293" label="errSecAuthFailed"/>
+  <int value="-25292" label="errSecReadOnly"/>
+  <int value="-25291" label="errSecNotAvailable"/>
+  <int value="-25264" label="errSecPkcs12VerifyFailure"/>
+  <int value="-25263" label="errSecNoTrustSettings"/>
+  <int value="-25262" label="errSecInvalidTrustSettings"/>
+  <int value="-25261" label="errSecInvalidPasswordRef"/>
+  <int value="-25260" label="errSecPassphraseRequired"/>
+  <int value="-25259" label="errSecMultiplePrivKeys"/>
+  <int value="-25258" label="errSecKeyIsSensitive"/>
+  <int value="-25257" label="errSecUnknownFormat"/>
+  <int value="-25256" label="errSecUnsupportedFormat"/>
+  <int value="-25245" label="errSecTrustNotAvailable"/>
+  <int value="-25244" label="errSecInvalidOwnerEdit"/>
+  <int value="-25243" label="errSecNoAccessForItem"/>
+  <int value="-25242" label="errSecInvalidTrustSetting"/>
+  <int value="-25241" label="errSecPolicyNotFound"/>
+  <int value="-25240" label="errSecACLNotSimple"/>
+  <int value="-4960" label="errSecCoreFoundationUnknown"/>
+  <int value="-2070" label="errSecInternalComponent"/>
+  <int value="-909" label="errSecBadReq"/>
+  <int value="-128" label="errSecUserCanceled"/>
+  <int value="-108" label="errSecAllocate"/>
+  <int value="-61" label="errSecWrPerm"/>
+  <int value="-50" label="errSecParam"/>
+  <int value="-49" label="errSecOpWr"/>
+  <int value="-36" label="errSecIO"/>
+  <int value="-34" label="errSecDiskFull"/>
+  <int value="-4" label="errSecUnimplemented"/>
+  <int value="0" label="errSecSuccess"/>
+</enum>
+
 <enum name="SigninSSOWKWebViewGetAllCookiesRequest">
   <int value="0" label="Started"/>
   <int value="1" label="Finished"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 1f13161..eac29bb3 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -12685,6 +12685,9 @@
 </histogram>
 
 <histogram name="Blink.ColorGamut.Source" enum="Gamut">
+  <obsolete>
+    No useful signal. Deprecated 7/2019.
+  </obsolete>
   <owner>brianosman@chromium.org</owner>
   <owner>mcasas@google.com</owner>
   <owner>ccameron@chromium.org</owner>
@@ -18203,7 +18206,7 @@
   </summary>
 </histogram>
 
-<histogram name="ChromeOS.UrlXattrsCount" expires_after="M78">
+<histogram name="ChromeOS.UrlXattrsCount" expires_after="M80">
   <owner>jorgelo@chromium.org</owner>
   <owner>tnagel@chromium.org</owner>
   <summary>
@@ -20132,7 +20135,7 @@
 </histogram>
 
 <histogram name="ConnectivityDiagnostics.RESOLVER_LATENCY" units="ms"
-    expires_after="M77">
+    expires_after="M83">
   <owner>ebeach@google.com</owner>
   <summary>Resolution latency seen by the Connectivity Diagnostics.</summary>
   <details>
@@ -20181,6 +20184,9 @@
 
 <histogram name="ContentCapture.CaptureOneContentTime" units="microseconds"
     expires_after="M75">
+  <obsolete>
+    Expired
+  </obsolete>
   <owner>michaelbai@chromium.org</owner>
   <summary>The estimated time taken to capture one on-screen content.</summary>
 </histogram>
@@ -27597,11 +27603,17 @@
 </histogram>
 
 <histogram name="DiskCache.0.FilesAge" units="hours" expires_after="M77">
+  <obsolete>
+    Removed 2019-07-05
+  </obsolete>
   <owner>morlovich@chromium.org</owner>
   <summary>The age of the cache's files (wall time).</summary>
 </histogram>
 
 <histogram name="DiskCache.2.FilesAge" units="hours">
+  <obsolete>
+    Removed 2019-07-05
+  </obsolete>
   <owner>morlovich@chromium.org</owner>
   <summary>
     The age of the cache's files (wall time). Media-specific cache.
@@ -27609,16 +27621,25 @@
 </histogram>
 
 <histogram name="DiskCache.3.FilesAge" units="hours" expires_after="2018-08-30">
+  <obsolete>
+    Removed 2019-07-05
+  </obsolete>
   <owner>morlovich@chromium.org</owner>
   <summary>The age of the cache's files (wall time). AppCache.</summary>
 </histogram>
 
 <histogram name="DiskCache.4.FilesAge" units="hours" expires_after="2018-08-30">
+  <obsolete>
+    Removed 2019-07-05
+  </obsolete>
   <owner>morlovich@chromium.org</owner>
   <summary>The age of the cache's files (wall time). ShaderCache.</summary>
 </histogram>
 
 <histogram name="DiskCache.SizeStats2" units="KB" expires_after="M77">
+  <obsolete>
+    Removed 2019-07-05
+  </obsolete>
   <owner>morlovich@chromium.org</owner>
   <summary>The size distribution of data stored in the HTTP cache.</summary>
 </histogram>
@@ -32854,9 +32875,11 @@
 </histogram>
 
 <histogram name="Enterprise.ExistingInstallAttributesLock"
-    enum="EnterpriseExistingInstallAttributesLockType" expires_after="M70">
+    enum="EnterpriseExistingInstallAttributesLockType"
+    expires_after="2020-07-01">
   <owner>emaxx@chromium.org</owner>
   <owner>poromov@chromium.org</owner>
+  <owner>rsorokin@chromium.org</owner>
   <summary>
     Chrome OS only. Whether the successful locking of install attributes reused
     the previously existing locked attributes, or a fresh lock has being held.
@@ -38390,19 +38413,29 @@
 
 <histogram name="Extensions.BrowsingInstanceViolation.ExtensionType"
     enum="ExtensionType" expires_after="M77">
+  <obsolete>
+    Logging code has been removed in M77. Some historical data may be found at
+    (Google-internal, sorry)
+    https://docs.google.com/document/d/11O-73Hs0avk1xkkULn5HoxtY0gvzz3Ff5I3GFvMI_cY
+  </obsolete>
   <owner>lukasza@chromium.org</owner>
   <summary>
     When an extension violates browsing instance boundaries, this metric records
     the extension type.
 
     This is a temporary metric - probably okay to remove it in M66, after we've
-    gathered sufficient UMA data in M65. See also http://crbug.com/718489.
+    gathered sufficient UMA data in M65. See also https://crbug.com/786411.
   </summary>
 </histogram>
 
 <histogram
     name="Extensions.BrowsingInstanceViolation.IsBackgroundSourceOrTarget"
-    enum="ExtensionViewTypeIsBackground" expires_after="M78">
+    enum="ExtensionViewTypeIsBackground" expires_after="M77">
+  <obsolete>
+    Logging code has been removed in M77. Some historical data may be found at
+    (Google-internal, sorry)
+    https://docs.google.com/document/d/11O-73Hs0avk1xkkULn5HoxtY0gvzz3Ff5I3GFvMI_cY
+  </obsolete>
   <owner>lukasza@chromium.org</owner>
   <summary>
     When an extension violates browsing instance boundaries, this metric records
@@ -38410,24 +38443,34 @@
     of VIEW_TYPE_BACKGROUND_CONTENTS.
 
     This is a temporary metric - probably okay to remove it in M66, after we've
-    gathered sufficient UMA data in M65. See also http://crbug.com/718489.
+    gathered sufficient UMA data in M65. See also https://crbug.com/786411.
   </summary>
 </histogram>
 
 <histogram name="Extensions.BrowsingInstanceViolation.SourceExtensionViewType"
     enum="ExtensionViewType" expires_after="M77">
+  <obsolete>
+    Logging code has been removed in M77. Some historical data may be found at
+    (Google-internal, sorry)
+    https://docs.google.com/document/d/11O-73Hs0avk1xkkULn5HoxtY0gvzz3Ff5I3GFvMI_cY
+  </obsolete>
   <owner>lukasza@chromium.org</owner>
   <summary>
     When an extension violates browsing instance boundaries, this metric records
     the extension view type of the source frame.
 
     This is a temporary metric - probably okay to remove it in M66, after we've
-    gathered sufficient UMA data in M65. See also http://crbug.com/718489.
+    gathered sufficient UMA data in M65. See also https://crbug.com/786411.
   </summary>
 </histogram>
 
 <histogram name="Extensions.BrowsingInstanceViolation.TargetExtensionViewType"
     enum="ExtensionViewType" expires_after="M77">
+  <obsolete>
+    Logging code has been removed in M77. Some historical data may be found at
+    (Google-internal, sorry)
+    https://docs.google.com/document/d/11O-73Hs0avk1xkkULn5HoxtY0gvzz3Ff5I3GFvMI_cY
+  </obsolete>
   <owner>lukasza@chromium.org</owner>
   <summary>
     When an extension violates browsing instance boundaries, this metric records
@@ -38438,7 +38481,7 @@
     pages (of VIEW_TYPE_BACKGROUND_CONTENTS type).
 
     This is a temporary metric - probably okay to remove it in M66, after we've
-    gathered sufficient UMA data in M65. See also http://crbug.com/718489.
+    gathered sufficient UMA data in M65. See also https://crbug.com/786411.
   </summary>
 </histogram>
 
@@ -63840,6 +63883,9 @@
 
 <histogram name="Mojo.MachPortRelay.BrokerError"
     enum="MojoMachPortRelayBrokerError" expires_after="M77">
+  <obsolete>
+    The MachPortRelay was deleted in July 2019.
+  </obsolete>
   <owner>amistry@chromium.org</owner>
   <owner>erikchen@chromium.org</owner>
   <summary>
@@ -63850,6 +63896,9 @@
 
 <histogram name="Mojo.MachPortRelay.ChildError"
     enum="MojoMachPortRelayChildError" expires_after="M77">
+  <obsolete>
+    The MachPortRelay was deleted in July 2019.
+  </obsolete>
   <owner>amistry@chromium.org</owner>
   <owner>erikchen@chromium.org</owner>
   <summary>
@@ -67047,7 +67096,7 @@
 </histogram>
 
 <histogram name="Net.AlternativeServiceTypeForRequest"
-    enum="AlternativeServiceType" expires_after="M77">
+    enum="AlternativeServiceType" expires_after="M92">
   <owner>bnc@chromium.org</owner>
   <summary>
     Information about the AlternativeService used for each request.
@@ -72330,7 +72379,7 @@
 </histogram>
 
 <histogram name="Net.PushedStreamVaryResponseHeader"
-    enum="PushedStreamVaryResponseHeaderValues" expires_after="M77">
+    enum="PushedStreamVaryResponseHeaderValues" expires_after="M92">
   <owner>bnc@chromium.org</owner>
   <summary>
     Information about the value of the Vary response header in HTTP/2 pushed
@@ -74789,7 +74838,7 @@
 </histogram>
 
 <histogram name="Net.SpdyHeadersCompressionPercentage" units="%"
-    expires_after="M77">
+    expires_after="M92">
   <owner>bnc@chromium.org</owner>
   <summary>
     The percent compression achieved when compressing HEADERS frames.
@@ -74818,7 +74867,7 @@
 </histogram>
 
 <histogram name="Net.SpdyIPPoolDomainMatch" enum="SpdyIPPoolDomainMatch"
-    units="count" expires_after="M77">
+    units="count" expires_after="M92">
   <owner>bnc@chromium.org</owner>
   <summary>
     Status of checking if a SPDY domain can handle a IP match. If a match is
@@ -74859,7 +74908,7 @@
 </histogram>
 
 <histogram name="Net.SpdyResponseCode" enum="HttpResponseCode"
-    expires_after="M77">
+    expires_after="M92">
   <owner>bnc@chromium.org</owner>
   <summary>
     HTTP status codes received in HTTP/2 HEADERS frames. If a stream contains
@@ -74929,7 +74978,7 @@
 </histogram>
 
 <histogram name="Net.SpdySession.ServerSupportsWebSocket" units="Boolean"
-    expires_after="M77">
+    expires_after="M92">
   <owner>bnc@chromium.org</owner>
   <summary>
     Whether the server has advertised support for WebSockets over HTTP/2.
@@ -74981,7 +75030,7 @@
 </histogram>
 
 <histogram name="Net.SpdySessionGet" enum="SpdySessionGet" units="count"
-    expires_after="M77">
+    expires_after="M92">
   <owner>bnc@chromium.org</owner>
   <summary>The type of SPDY Session used when looking up a session.</summary>
 </histogram>
@@ -75123,7 +75172,7 @@
   <summary>The number of streams issued over a single session.</summary>
 </histogram>
 
-<histogram name="Net.SpdyStreamsPushedAndClaimedPerSession" expires_after="M77">
+<histogram name="Net.SpdyStreamsPushedAndClaimedPerSession" expires_after="M92">
   <owner>bnc@chromium.org</owner>
   <summary>
     The number of pushed, and used streams over a single session.
@@ -75667,7 +75716,7 @@
 </histogram>
 
 <histogram name="Net.SSLNegotiatedAlpnProtocol"
-    enum="SSLNegotiatedAlpnProtocol" expires_after="M77">
+    enum="SSLNegotiatedAlpnProtocol" expires_after="M92">
   <owner>bnc@chromium.org</owner>
   <summary>
     For each TLS handshake, whether ALPN was negotiated; and if so, the
@@ -84201,6 +84250,9 @@
 
 <histogram name="OfflinePages.Background.CctApiDisableStatus"
     enum="OfflinePagesCctApiPrerenderAllowedStatus" expires_after="M77">
+  <obsolete>
+    Removed as of 7/2019. No longer needed.
+  </obsolete>
   <owner>petewil@chromium.org</owner>
   <summary>
     Reason for the Chrome Custom Tabs API prerender call to be ignored.
@@ -84372,6 +84424,9 @@
 
 <histogram name="OfflinePages.Background.ResourceCompletion.Css"
     enum="BooleanEnabled">
+  <obsolete>
+    Removed as of 7/2019. No longer needed.
+  </obsolete>
   <owner>petewil@chromium.org</owner>
   <summary>
     True if all requested CSS was loaded when a background page loaded.
@@ -84380,6 +84435,9 @@
 
 <histogram name="OfflinePages.Background.ResourceCompletion.Image"
     enum="BooleanEnabled" expires_after="M77">
+  <obsolete>
+    Removed as of 7/2019. No longer needed.
+  </obsolete>
   <owner>petewil@chromium.org</owner>
   <summary>
     True if all requested images were loaded when a background page loaded.
@@ -84388,6 +84446,9 @@
 
 <histogram name="OfflinePages.Background.ResourceCompletion.Xhr"
     enum="BooleanEnabled" expires_after="M77">
+  <obsolete>
+    Removed as of 7/2019. No longer needed.
+  </obsolete>
   <owner>petewil@chromium.org</owner>
   <summary>
     True if all requested XHRs were completed when a background page loaded.
@@ -89840,6 +89901,9 @@
 </histogram>
 
 <histogram name="PageLoad.Experimental.Bytes.Cache" units="KB">
+  <obsolete>
+    Deprecated in favor of PageLoad.Experimental.Bytes.Cache2.
+  </obsolete>
   <owner>jkarlin@chromium.org</owner>
   <summary>
     The number of prefiltered (e.g., compressed) response body KiloBytes loaded
@@ -89848,6 +89912,18 @@
   </summary>
 </histogram>
 
+<histogram name="PageLoad.Experimental.Bytes.Cache2" units="KB"
+    expires_after="2020-05-30">
+  <owner>jkarlin@chromium.org</owner>
+  <owner>johnidel@chromium.org</owner>
+  <summary>
+    The number of prefiltered (e.g., compressed) response body KiloBytes loaded
+    from the cache via the browser process for a page load. Recorded when the
+    page load is terminated. Only recorded for complete resources. Includes
+    resources from both the http cache and memory cache.
+  </summary>
+</histogram>
+
 <histogram name="PageLoad.Experimental.Bytes.Network" units="KB">
   <owner>jkarlin@chromium.org</owner>
   <summary>
@@ -89870,6 +89946,9 @@
 </histogram>
 
 <histogram name="PageLoad.Experimental.Bytes.Total" units="KB">
+  <obsolete>
+    Deprecated in favor of PageLoad.Experimental.Bytes.Total2.
+  </obsolete>
   <owner>jkarlin@chromium.org</owner>
   <summary>
     The number of prefiltered (e.g., compressed) response body KiloBytes loaded
@@ -89879,6 +89958,18 @@
   </summary>
 </histogram>
 
+<histogram name="PageLoad.Experimental.Bytes.Total2" units="KB"
+    expires_after="2020-05-30">
+  <owner>jkarlin@chromium.org</owner>
+  <owner>johnidel@chromium.org</owner>
+  <summary>
+    The number of prefiltered (e.g., compressed) response body KiloBytes loaded
+    via the browser process for a page load. Does not include any header or
+    overhead bytes. Recorded when the page load is terminated. Only recorded for
+    complete resources. Includes resources from both the http and memory cache.
+  </summary>
+</histogram>
+
 <histogram name="PageLoad.Experimental.Bytes.Unfinished" units="KB"
     expires_after="2020-04-05">
   <owner>johnidel@chromium.org</owner>
@@ -89917,6 +90008,9 @@
 
 <histogram name="PageLoad.Experimental.CompletedResources.Cache"
     units="resources" expires_after="M77">
+  <obsolete>
+    Deprecated in favor of PageLoad.Experimental.CompletedResources.Cache2.
+  </obsolete>
   <owner>csharrison@chromium.org</owner>
   <owner>jkarlin@chromium.org</owner>
   <summary>
@@ -89925,9 +90019,20 @@
   </summary>
 </histogram>
 
+<histogram name="PageLoad.Experimental.CompletedResources.Cache2"
+    units="resources" expires_after="2020-05-30">
+  <owner>johnidel@chromium.org</owner>
+  <owner>jkarlin@chromium.org</owner>
+  <summary>
+    The number of completed resources loaded from the cache via the browser
+    process for a page load. Recorded when the page load is terminated. Includes
+    resources from both the http and memory cache.
+  </summary>
+</histogram>
+
 <histogram name="PageLoad.Experimental.CompletedResources.Network"
     units="resources" expires_after="M77">
-  <owner>csharrison@chromium.org</owner>
+  <owner>johnidel@chromium.org</owner>
   <owner>jkarlin@chromium.org</owner>
   <summary>
     The number of completed resources loaded from the network via the browser
@@ -89937,6 +90042,9 @@
 
 <histogram name="PageLoad.Experimental.CompletedResources.Total"
     units="resources">
+  <obsolete>
+    Deprecated in favor of PageLoad.Experimental.CompletedResources.Total2.
+  </obsolete>
   <owner>csharrison@chromium.org</owner>
   <owner>jkarlin@chromium.org</owner>
   <summary>
@@ -89945,6 +90053,16 @@
   </summary>
 </histogram>
 
+<histogram name="PageLoad.Experimental.CompletedResources.Total2"
+    units="resources" expires_after="2020-05-30">
+  <owner>johnidel@chromium.org</owner>
+  <owner>jkarlin@chromium.org</owner>
+  <summary>
+    The total number of completed resources loaded via the browser process for a
+    page load. Recorded when the page load is terminated.
+  </summary>
+</histogram>
+
 <histogram name="PageLoad.Experimental.InputTiming.InputToNavigationStart"
     units="ms" expires_after="2019-08-22">
   <owner>sullivan@chromium.org</owner>
@@ -93066,7 +93184,7 @@
 </histogram>
 
 <histogram name="PasswordManager.HttpCredentials"
-    enum="PasswordManagerHttpCredentialType" expires_after="M77">
+    enum="PasswordManagerHttpCredentialType" expires_after="M87">
   <owner>jdoerrie@chromium.org</owner>
   <owner>vasilii@chromium.org</owner>
   <summary>
@@ -110618,17 +110736,28 @@
   </summary>
 </histogram>
 
+<histogram name="SafeBrowsing.Triggers.AdPopup.Action"
+    enum="AdPopupTriggerAction" expires_after="2020-07-01">
+  <owner>vakh@chromium.org</owner>
+  <owner>chrome-safebrowsing-alerts@google.com</owner>
+  <summary>
+    Tracks the actions taken by the Ad Popup trigger whenever it is executed.
+  </summary>
+</histogram>
+
 <histogram name="SafeBrowsing.Triggers.AdSampler.Action"
-    enum="AdSamplerTriggerAction" expires_after="M77">
+    enum="AdSamplerTriggerAction" expires_after="2020-07-01">
   <owner>lpz@chromium.org</owner>
+  <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
     Tracks the actions taken by the Ad Sampling trigger whenever it is executed.
   </summary>
 </histogram>
 
 <histogram name="SafeBrowsing.Triggers.SuspiciousSite.DelayTimerState"
-    enum="SuspiciousSiteTriggerState" expires_after="M77">
+    enum="SuspiciousSiteTriggerState" expires_after="2020-07-01">
   <owner>lpz@chromium.org</owner>
+  <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
     Tracks the state of the Suspicious Site trigger when its report delay timer
     fires. Used to investigate variance in event order.
@@ -110636,8 +110765,9 @@
 </histogram>
 
 <histogram name="SafeBrowsing.Triggers.SuspiciousSite.Event"
-    enum="SuspiciousSiteTriggerEvent">
+    enum="SuspiciousSiteTriggerEvent" expires_after="2020-07-01">
   <owner>lpz@chromium.org</owner>
+  <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
     Tracks the events occurring in the Suspicious Site trigger whenever it is
     executed.
@@ -110645,8 +110775,9 @@
 </histogram>
 
 <histogram name="SafeBrowsing.Triggers.SuspiciousSite.ReportRejectionReason"
-    enum="TriggerManagerReason" expires_after="M77">
+    enum="TriggerManagerReason" expires_after="2020-07-01">
   <owner>lpz@chromium.org</owner>
+  <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
     Tracks the reasons that a report requested by the Suspicious Site trigger is
     rejected by the Trigger Manager.
@@ -122457,7 +122588,7 @@
 </histogram>
 
 <histogram name="Signin.AuthenticatedLaunchUserEvent"
-    enum="AuthenticatedLaunchUserEvent" expires_after="M77">
+    enum="AuthenticatedLaunchUserEvent" expires_after="M84">
   <owner>zmin@chromium.org</owner>
   <summary>
     Records the UI event when user clicks a locked profile on UserManager.
@@ -122572,7 +122703,7 @@
 </histogram>
 
 <histogram name="Signin.ForceSigninVerificationRequest" enum="BooleanRequested"
-    expires_after="M77">
+    expires_after="M84">
   <owner>zmin@chromium.org</owner>
   <summary>
     The number profile load events that needs a force-sign-in verification
@@ -123062,6 +123193,16 @@
   <summary>Track how a profile gets signed out.</summary>
 </histogram>
 
+<histogram name="Signin.SSOAuth.GetIdentities.ErrorCode"
+    enum="SigninSSOAuthGetIdentitiesErrorCode" expires_after="2019-12-01">
+  <owner>jlebel@chromium.org</owner>
+  <owner>chrome-signin-team@google.com</owner>
+  <summary>
+    Tracks the error code by -[SSOService identitiesWithError:]. See:
+    https://crbug.com/981082.
+  </summary>
+</histogram>
+
 <histogram name="Signin.SSOWKWebView.GetAllCookies.CookieCount" units="cookies">
   <owner>jlebel@chromium.org</owner>
   <summary>
@@ -123517,7 +123658,7 @@
 </histogram>
 
 <histogram name="SimpleCache.FileDescriptorLimiterAction"
-    enum="SimpleCache.FileDescriptorLimiterOp" expires_after="M77">
+    enum="SimpleCache.FileDescriptorLimiterOp" expires_after="M85">
   <owner>morlovich@chromium.org</owner>
   <summary>
     This even is emitted when SimpleCache is forced to either close some files
@@ -123527,6 +123668,9 @@
 </histogram>
 
 <histogram name="SimpleCache.FileDescriptorLimitHard" units="file descriptors">
+  <obsolete>
+    Removed 2019-07-03
+  </obsolete>
   <owner>morlovich@chromium.org</owner>
   <summary>
     The maximum limit of how many file descriptors a process can open. Emitted
@@ -123536,6 +123680,10 @@
 </histogram>
 
 <histogram name="SimpleCache.FileDescriptorLimitSoft" units="file descriptors">
+  <obsolete>
+    Removed 2019-07-03. Consider Memory.Browser.OpenFDsSoftLimit for similar
+    information.
+  </obsolete>
   <owner>morlovich@chromium.org</owner>
   <summary>
     The current limit of how many file descriptors a process can open. Emitted
@@ -123546,6 +123694,9 @@
 
 <histogram name="SimpleCache.FileDescriptorLimitStatus"
     enum="SimpleCache.FileDescriptorLimitStatus" expires_after="M77">
+  <obsolete>
+    Removed 2019-07-03
+  </obsolete>
   <owner>morlovich@chromium.org</owner>
   <summary>
     The result of trying to get the file descriptor limit. Emitted each time the
@@ -123554,6 +123705,9 @@
 </histogram>
 
 <histogram base="true" name="SimpleCache.GlobalOpenEntryCount">
+  <obsolete>
+    Removed 2019-07-03.
+  </obsolete>
   <owner>morlovich@chromium.org</owner>
   <summary>
     The number of open entries across all caches backed by the Simple Cache. An
@@ -160044,8 +160198,10 @@
       label="PageLoadMetrics for page loads that involved playing a media
              element."/>
   <affected-histogram name="PageLoad.Experimental.Bytes.Cache"/>
+  <affected-histogram name="PageLoad.Experimental.Bytes.Cache2"/>
   <affected-histogram name="PageLoad.Experimental.Bytes.Network"/>
   <affected-histogram name="PageLoad.Experimental.Bytes.Total"/>
+  <affected-histogram name="PageLoad.Experimental.Bytes.Total2"/>
 </histogram_suffixes>
 
 <histogram_suffixes name="PageLoadMetricsClientsMultiTabLoading" separator="."
@@ -160380,8 +160536,10 @@
       label="PageLoadMetrics that are a result of a navigation caused by a
              tab restore."/>
   <affected-histogram name="PageLoad.Experimental.Bytes.Cache"/>
+  <affected-histogram name="PageLoad.Experimental.Bytes.Cache2"/>
   <affected-histogram name="PageLoad.Experimental.Bytes.Network"/>
   <affected-histogram name="PageLoad.Experimental.Bytes.Total"/>
+  <affected-histogram name="PageLoad.Experimental.Bytes.Total2"/>
 </histogram_suffixes>
 
 <histogram_suffixes name="PageLoadMetricsLoadType" separator=".">
@@ -160402,8 +160560,10 @@
   <affected-histogram
       name="PageLoad.Clients.SubresourceFilter.ActivationDecision"/>
   <affected-histogram name="PageLoad.Experimental.Bytes.Cache"/>
+  <affected-histogram name="PageLoad.Experimental.Bytes.Cache2"/>
   <affected-histogram name="PageLoad.Experimental.Bytes.Network"/>
   <affected-histogram name="PageLoad.Experimental.Bytes.Total"/>
+  <affected-histogram name="PageLoad.Experimental.Bytes.Total2"/>
   <affected-histogram
       name="PageLoad.PaintTiming.NavigationToFirstContentfulPaint"/>
   <affected-histogram name="PageLoad.ParseTiming.NavigationToParseStart"/>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index 8a09e8f5..554d967d 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -5199,12 +5199,22 @@
     </summary>
   </metric>
   <metric name="Net.CacheBytes">
+    <obsolete>
+      Deprecated 06/2019 in favor of Net.CacheBytes2.
+    </obsolete>
     <summary>
       The total number of body bytes loaded from cache for all resources on the
       page. This is rounded down to the nearest exponential bucket (with a
       bucket spacing factor of 1.3).
     </summary>
   </metric>
+  <metric name="Net.CacheBytes2">
+    <summary>
+      The total number of body bytes loaded from cache for all resources on the
+      page. This includes the http and memory cache. This is rounded down to the
+      nearest exponential bucket (with a bucket spacing factor of 1.3).
+    </summary>
+  </metric>
   <metric name="Net.DownstreamKbpsEstimate.OnNavigationStart">
     <owner>tbansal@chromium.org</owner>
     <summary>
diff --git a/tools/perf/cli_tools/pinboard/pinboard.py b/tools/perf/cli_tools/pinboard/pinboard.py
index ebe810e..9d9c0c2 100644
--- a/tools/perf/cli_tools/pinboard/pinboard.py
+++ b/tools/perf/cli_tools/pinboard/pinboard.py
@@ -88,20 +88,24 @@
           universal_newlines=True).strip()
     logging.info(output)
     assert 'https://pinpoint' in output
-    item['jobs'].append({'id': output.split('/')[-1], 'status': 'running'})
+    item['jobs'].append({'id': output.split('/')[-1], 'status': 'queued'})
   state.append(item)
   state.sort(key=lambda p: p['timestamp'])  # Keep items sorted by date.
 
 
+def IsJobFinished(job):
+  return job['status'] in ['completed', 'failed']
+
+
 def CollectPinpointResults(state):
   """Check the status of pinpoint jobs and collect their results."""
   # First iterate over all running jobs, and update their status.
   for item in state:
-    running = [job['id'] for job in item['jobs'] if job['status'] == 'running']
-    if not running:
+    active = [job['id'] for job in item['jobs'] if not IsJobFinished(job)]
+    if not active:
       continue
     cmd = ['vpython', PINPOINT_CLI, 'status']
-    cmd.extend(running)
+    cmd.extend(active)
     output = subprocess.check_output(cmd, universal_newlines=True)
     updates = dict(line.split(': ', 1) for line in output.splitlines())
     logging.info('Got job updates: %s.', updates)
@@ -117,7 +121,7 @@
     if not os.path.exists(output_file):
       cmd = ['vpython', PINPOINT_CLI, 'get-csv', '--output', output_file, '--']
       job_ids = [j['id'] for j in item['jobs'] if j['status'] == 'completed']
-      logging.info('Getting csv data for job ids: %s.', job_ids)
+      logging.info('Getting csv data for commit: %s.', item['revision'])
       subprocess.check_output(cmd + job_ids)
 
 
@@ -248,8 +252,8 @@
 
 
 def _SkipProcessing(item):
-  """Return True if some jobs have not finished or all failed."""
-  return (any(job['status'] == 'running' for job in item['jobs']) or
+  """Return True if not all jobs have finished or all have failed."""
+  return (not all(IsJobFinished(job) for job in item['jobs']) or
           all(job['status'] == 'failed' for job in item['jobs']))
 
 
diff --git a/tools/perf/cli_tools/pinboard/pinboard_unittest.py b/tools/perf/cli_tools/pinboard/pinboard_unittest.py
index 0eb3d6d..cb2e710 100644
--- a/tools/perf/cli_tools/pinboard/pinboard_unittest.py
+++ b/tools/perf/cli_tools/pinboard/pinboard_unittest.py
@@ -54,8 +54,8 @@
     self.assertEqual(state, [{
         'revision': '2a66bac4',
         'timestamp': '2019-03-17T23:50:16-07:00',
-        'jobs': [{'id': '14b4c451f40000', 'status': 'running'},
-                 {'id': '11fae481f40000', 'status': 'running'}]}])
+        'jobs': [{'id': '14b4c451f40000', 'status': 'queued'},
+                 {'id': '11fae481f40000', 'status': 'queued'}]}])
 
   def testCollectPinpointResults(self):
     state = [
diff --git a/tools/perf/cli_tools/pinpoint_cli/commands.py b/tools/perf/cli_tools/pinpoint_cli/commands.py
index c2ce907..530be16 100644
--- a/tools/perf/cli_tools/pinpoint_cli/commands.py
+++ b/tools/perf/cli_tools/pinpoint_cli/commands.py
@@ -4,6 +4,7 @@
 
 import csv
 import json
+import logging
 import ntpath
 import posixpath
 import sys
@@ -48,7 +49,11 @@
       for change_id, isolate_hash in job_results.IterTestOutputIsolates(
           job, only_differences):
         print '- isolate: %s ...' % isolate_hash
-        histograms = isolate_service.RetrieveFile(isolate_hash, results_file)
+        try:
+          histograms = isolate_service.RetrieveFile(isolate_hash, results_file)
+        except KeyError:
+          logging.warning('Skipping over isolate, results not found.')
+          continue
         for row in histograms_df.IterRows(json.loads(histograms)):
           writer.writerow((job_id, change_id, isolate_hash) + row)
           num_rows += 1
diff --git a/tools/traffic_annotation/auditor/BUILD.gn b/tools/traffic_annotation/auditor/BUILD.gn
index 8c9f65c5..4432ad9a 100644
--- a/tools/traffic_annotation/auditor/BUILD.gn
+++ b/tools/traffic_annotation/auditor/BUILD.gn
@@ -95,8 +95,7 @@
     "tests/annotations_sample1.xml",
     "tests/annotations_sample2.xml",
     "tests/annotations_sample3.xml",
-    "tests/extractor_outputs/bad_assignment1.txt",
-    "tests/extractor_outputs/bad_assignment2.txt",
+    "tests/extractor_outputs/bad_assignment.txt",
     "tests/extractor_outputs/bad_call.txt",
     "tests/extractor_outputs/bad_syntax_annotation1.txt",
     "tests/extractor_outputs/bad_syntax_annotation2.txt",
diff --git a/tools/traffic_annotation/auditor/instance.cc b/tools/traffic_annotation/auditor/instance.cc
index 256d6d9a..0408518 100644
--- a/tools/traffic_annotation/auditor/instance.cc
+++ b/tools/traffic_annotation/auditor/instance.cc
@@ -130,14 +130,13 @@
     const std::vector<std::string>& serialized_lines,
     int start_line,
     int end_line) {
-  if (end_line - start_line < 7) {
+  if (end_line - start_line < 6) {
     return AuditorResult(AuditorResult::Type::ERROR_FATAL,
                          "Not enough lines to deserialize annotation.");
   }
 
   // Extract header lines.
   const std::string& file_path = serialized_lines[start_line++];
-  const std::string& function_context = serialized_lines[start_line++];
   int line_number;
   base::StringToInt(serialized_lines[start_line++], &line_number);
   std::string function_type = serialized_lines[start_line++];
@@ -196,7 +195,6 @@
   traffic_annotation::NetworkTrafficAnnotation_TrafficSource* src =
       proto.mutable_source();
   src->set_file(file_path);
-  src->set_function(function_context);
   src->set_line(line_number);
   proto.set_unique_id(unique_id);
   second_id_hash_code = TrafficAnnotationAuditor::ComputeHashValue(second_id);
@@ -645,7 +643,6 @@
 CallInstance::CallInstance(const CallInstance& other)
     : file_path(other.file_path),
       line_number(other.line_number),
-      function_context(other.function_context),
       function_name(other.function_name),
       is_annotated(other.is_annotated) {}
 
@@ -653,13 +650,12 @@
     const std::vector<std::string>& serialized_lines,
     int start_line,
     int end_line) {
-  if (end_line - start_line != 5) {
+  if (end_line - start_line != 4) {
     return AuditorResult(AuditorResult::Type::ERROR_FATAL,
                          "Not enough lines to deserialize call.");
   }
 
   file_path = serialized_lines[start_line++];
-  function_context = serialized_lines[start_line++];
   int line_number_int;
   base::StringToInt(serialized_lines[start_line++], &line_number_int);
   line_number = static_cast<uint32_t>(line_number_int);
@@ -673,20 +669,17 @@
 AssignmentInstance::AssignmentInstance() : line_number(0) {}
 
 AssignmentInstance::AssignmentInstance(const AssignmentInstance& other)
-    : file_path(other.file_path),
-      line_number(other.line_number),
-      function_context(other.function_context) {}
+    : file_path(other.file_path), line_number(other.line_number) {}
 
 AuditorResult AssignmentInstance::Deserialize(
     const std::vector<std::string>& serialized_lines,
     int start_line,
     int end_line) {
-  if (end_line - start_line != 3) {
+  if (end_line - start_line != 2) {
     return AuditorResult(AuditorResult::Type::ERROR_FATAL,
                          "Not enough lines to deserialize assignment.");
   }
   file_path = serialized_lines[start_line++];
-  function_context = serialized_lines[start_line++];
   int line_number_int;
   base::StringToInt(serialized_lines[start_line++], &line_number_int);
   line_number = static_cast<uint32_t>(line_number_int);
diff --git a/tools/traffic_annotation/auditor/instance.h b/tools/traffic_annotation/auditor/instance.h
index 688b649..74e003ce 100644
--- a/tools/traffic_annotation/auditor/instance.h
+++ b/tools/traffic_annotation/auditor/instance.h
@@ -156,9 +156,6 @@
   std::string file_path;
   uint32_t line_number;
 
-  // Name of the function in which the call happens.
-  std::string function_context;
-
   // Name of the function that may need annotation.
   std::string function_name;
 
@@ -187,9 +184,6 @@
 
   std::string file_path;
   uint32_t line_number;
-
-  // Name of the function in which assignment happens.
-  std::string function_context;
 };
 
 #endif  // TOOLS_TRAFFIC_ANNOTATION_AUDITOR_INSTANCE_H_
diff --git a/tools/traffic_annotation/auditor/tests/extractor_outputs/bad_assignment1.txt b/tools/traffic_annotation/auditor/tests/extractor_outputs/bad_assignment.txt
similarity index 92%
rename from tools/traffic_annotation/auditor/tests/extractor_outputs/bad_assignment1.txt
rename to tools/traffic_annotation/auditor/tests/extractor_outputs/bad_assignment.txt
index e884c2d5..9065624 100644
--- a/tools/traffic_annotation/auditor/tests/extractor_outputs/bad_assignment1.txt
+++ b/tools/traffic_annotation/auditor/tests/extractor_outputs/bad_assignment.txt
@@ -1,2 +1 @@
-components/download/internal/proto_conversions.cc
-267
\ No newline at end of file
+components/download/internal/proto_conversions.cc
\ No newline at end of file
diff --git a/tools/traffic_annotation/auditor/tests/extractor_outputs/bad_assignment2.txt b/tools/traffic_annotation/auditor/tests/extractor_outputs/bad_assignment2.txt
deleted file mode 100644
index 56e27a45..0000000
--- a/tools/traffic_annotation/auditor/tests/extractor_outputs/bad_assignment2.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-components/download/internal/proto_conversions.cc
-download::ProtoConversions::EntryFromProto
\ No newline at end of file
diff --git a/tools/traffic_annotation/auditor/tests/extractor_outputs/bad_call.txt b/tools/traffic_annotation/auditor/tests/extractor_outputs/bad_call.txt
index ea130c4..3d66333 100644
--- a/tools/traffic_annotation/auditor/tests/extractor_outputs/bad_call.txt
+++ b/tools/traffic_annotation/auditor/tests/extractor_outputs/bad_call.txt
@@ -1,4 +1,3 @@
 headless/public/util/http_url_fetcher.cc
-headless::HttpURLFetcher::Delegate::Delegate
 net::URLRequestContext::CreateRequest
 1
\ No newline at end of file
diff --git a/tools/traffic_annotation/auditor/tests/extractor_outputs/bad_syntax_annotation1.txt b/tools/traffic_annotation/auditor/tests/extractor_outputs/bad_syntax_annotation1.txt
index dc3f1819..b6e63052 100644
--- a/tools/traffic_annotation/auditor/tests/extractor_outputs/bad_syntax_annotation1.txt
+++ b/tools/traffic_annotation/auditor/tests/extractor_outputs/bad_syntax_annotation1.txt
@@ -1,5 +1,4 @@
 chrome/browser/supervised_user/legacy/supervised_user_refresh_token_fetcher.cc
-OnGetTokenSuccess
 166
 Definition
 supervised_user_refresh_token_fetcher
diff --git a/tools/traffic_annotation/auditor/tests/extractor_outputs/bad_syntax_annotation2.txt b/tools/traffic_annotation/auditor/tests/extractor_outputs/bad_syntax_annotation2.txt
index 22c1b2c..78a286a 100644
--- a/tools/traffic_annotation/auditor/tests/extractor_outputs/bad_syntax_annotation2.txt
+++ b/tools/traffic_annotation/auditor/tests/extractor_outputs/bad_syntax_annotation2.txt
@@ -1,5 +1,4 @@
 chrome/browser/supervised_user/legacy/supervised_user_refresh_token_fetcher.cc
-OnGetTokenSuccess
 166
 Definition
 supervised_user_refresh_token_fetcher
diff --git a/tools/traffic_annotation/auditor/tests/extractor_outputs/bad_syntax_annotation3.txt b/tools/traffic_annotation/auditor/tests/extractor_outputs/bad_syntax_annotation3.txt
index b469160..44487d2 100644
--- a/tools/traffic_annotation/auditor/tests/extractor_outputs/bad_syntax_annotation3.txt
+++ b/tools/traffic_annotation/auditor/tests/extractor_outputs/bad_syntax_annotation3.txt
@@ -1,5 +1,4 @@
 chrome/browser/supervised_user/legacy/supervised_user_refresh_token_fetcher.cc
-OnGetTokenSuccess
 166
 Definition
 supervised_user_refresh_token_fetcher
diff --git a/tools/traffic_annotation/auditor/tests/extractor_outputs/bad_syntax_annotation4.txt b/tools/traffic_annotation/auditor/tests/extractor_outputs/bad_syntax_annotation4.txt
index ff9b95d..7511728 100644
--- a/tools/traffic_annotation/auditor/tests/extractor_outputs/bad_syntax_annotation4.txt
+++ b/tools/traffic_annotation/auditor/tests/extractor_outputs/bad_syntax_annotation4.txt
@@ -1,5 +1,4 @@
 chrome/browser/supervised_user/legacy/supervised_user_refresh_token_fetcher.cc
-OnGetTokenSuccess
 166
 Definition
 supervised_user_refresh_token_fetcher
diff --git a/tools/traffic_annotation/auditor/tests/extractor_outputs/fatal_annotation1.txt b/tools/traffic_annotation/auditor/tests/extractor_outputs/fatal_annotation1.txt
index bb6ddef9..7194718 100644
--- a/tools/traffic_annotation/auditor/tests/extractor_outputs/fatal_annotation1.txt
+++ b/tools/traffic_annotation/auditor/tests/extractor_outputs/fatal_annotation1.txt
@@ -1,5 +1,4 @@
 chrome/browser/supervised_user/legacy/supervised_user_refresh_token_fetcher.cc
-OnGetTokenSuccess
 Definition
 supervised_user_refresh_token_fetcher
 
diff --git a/tools/traffic_annotation/auditor/tests/extractor_outputs/fatal_annotation2.txt b/tools/traffic_annotation/auditor/tests/extractor_outputs/fatal_annotation2.txt
index 2637577..4ab9a44 100644
--- a/tools/traffic_annotation/auditor/tests/extractor_outputs/fatal_annotation2.txt
+++ b/tools/traffic_annotation/auditor/tests/extractor_outputs/fatal_annotation2.txt
@@ -1,5 +1,4 @@
 chrome/browser/supervised_user/legacy/supervised_user_refresh_token_fetcher.cc
-OnGetTokenSuccess
 122
 definition
 supervised_user_refresh_token_fetcher
diff --git a/tools/traffic_annotation/auditor/tests/extractor_outputs/fatal_annotation3.txt b/tools/traffic_annotation/auditor/tests/extractor_outputs/fatal_annotation3.txt
index 7e89f6f..7bd3bf9 100644
--- a/tools/traffic_annotation/auditor/tests/extractor_outputs/fatal_annotation3.txt
+++ b/tools/traffic_annotation/auditor/tests/extractor_outputs/fatal_annotation3.txt
@@ -1,5 +1,4 @@
 chrome/browser/supervised_user/legacy/supervised_user_refresh_token_fetcher.cc
-OnGetTokenSuccess
 122
 definition
 supervised_user_refresh_token_fetcher
diff --git a/tools/traffic_annotation/auditor/tests/extractor_outputs/good_assignment.txt b/tools/traffic_annotation/auditor/tests/extractor_outputs/good_assignment.txt
index 67a84a98..be3fad0 100644
--- a/tools/traffic_annotation/auditor/tests/extractor_outputs/good_assignment.txt
+++ b/tools/traffic_annotation/auditor/tests/extractor_outputs/good_assignment.txt
@@ -1,3 +1,2 @@
 components/download/internal/background_service/proto_conversions.cc
-download::ProtoConversions::EntryFromProto
 267
\ No newline at end of file
diff --git a/tools/traffic_annotation/auditor/tests/extractor_outputs/good_branched_completing_annotation.txt b/tools/traffic_annotation/auditor/tests/extractor_outputs/good_branched_completing_annotation.txt
index 03fce93..1800c14 100644
--- a/tools/traffic_annotation/auditor/tests/extractor_outputs/good_branched_completing_annotation.txt
+++ b/tools/traffic_annotation/auditor/tests/extractor_outputs/good_branched_completing_annotation.txt
@@ -1,5 +1,4 @@
 chrome/service/cloud_print/cloud_print_url_fetcher.cc
-cloud_print::CloudPrintURLFetcher::StartRequestHelper
 265
 BranchedCompleting
 cloud_print
diff --git a/tools/traffic_annotation/auditor/tests/extractor_outputs/good_call.txt b/tools/traffic_annotation/auditor/tests/extractor_outputs/good_call.txt
index e74c34d2..7162c390 100644
--- a/tools/traffic_annotation/auditor/tests/extractor_outputs/good_call.txt
+++ b/tools/traffic_annotation/auditor/tests/extractor_outputs/good_call.txt
@@ -1,5 +1,4 @@
 headless/public/util/http_url_fetcher.cc
-headless::HttpURLFetcher::Delegate::Delegate
 100
 net::URLRequestContext::CreateRequest
 1
\ No newline at end of file
diff --git a/tools/traffic_annotation/auditor/tests/extractor_outputs/good_complete_annotation.txt b/tools/traffic_annotation/auditor/tests/extractor_outputs/good_complete_annotation.txt
index 0e878a2..c74390d 100644
--- a/tools/traffic_annotation/auditor/tests/extractor_outputs/good_complete_annotation.txt
+++ b/tools/traffic_annotation/auditor/tests/extractor_outputs/good_complete_annotation.txt
@@ -1,5 +1,4 @@
 chrome/browser/supervised_user/legacy/supervised_user_refresh_token_fetcher.cc
-OnGetTokenSuccess
 166
 Definition
 supervised_user_refresh_token_fetcher
diff --git a/tools/traffic_annotation/auditor/tests/extractor_outputs/good_completing_annotation.txt b/tools/traffic_annotation/auditor/tests/extractor_outputs/good_completing_annotation.txt
index dcd5297..df296ee 100644
--- a/tools/traffic_annotation/auditor/tests/extractor_outputs/good_completing_annotation.txt
+++ b/tools/traffic_annotation/auditor/tests/extractor_outputs/good_completing_annotation.txt
@@ -1,5 +1,4 @@
 chrome/service/cloud_print/cloud_print_url_fetcher.cc
-cloud_print::CloudPrintURLFetcher::StartRequestHelper
 265
 Completing
 cloud_print
diff --git a/tools/traffic_annotation/auditor/tests/extractor_outputs/good_partial_annotation.txt b/tools/traffic_annotation/auditor/tests/extractor_outputs/good_partial_annotation.txt
index 07422ab..176d562 100644
--- a/tools/traffic_annotation/auditor/tests/extractor_outputs/good_partial_annotation.txt
+++ b/tools/traffic_annotation/auditor/tests/extractor_outputs/good_partial_annotation.txt
@@ -1,5 +1,4 @@
 components/browsing_data/core/counters/history_counter.cc
-browsing_data::HistoryCounter::Count
 98
 Partial
 web_history_counter
diff --git a/tools/traffic_annotation/auditor/tests/extractor_outputs/good_test_annotation.txt b/tools/traffic_annotation/auditor/tests/extractor_outputs/good_test_annotation.txt
index 07bd917..24821ff 100644
--- a/tools/traffic_annotation/auditor/tests/extractor_outputs/good_test_annotation.txt
+++ b/tools/traffic_annotation/auditor/tests/extractor_outputs/good_test_annotation.txt
@@ -1,5 +1,4 @@
 google_apis/drive/request_sender_unittest.cc
-google_apis::(anonymous namespace)::RequestSenderTest::RequestSenderTest
 67
 Definition
 test
diff --git a/tools/traffic_annotation/auditor/tests/extractor_outputs/missing_annotation.txt b/tools/traffic_annotation/auditor/tests/extractor_outputs/missing_annotation.txt
index 2efb3c3..670ffb0 100644
--- a/tools/traffic_annotation/auditor/tests/extractor_outputs/missing_annotation.txt
+++ b/tools/traffic_annotation/auditor/tests/extractor_outputs/missing_annotation.txt
@@ -1,5 +1,4 @@
 net/url_request/url_request_context.cc
-net::URLRequestContext::CreateRequest
 120
 Definition
 missing
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_auditor_unittest.cc b/tools/traffic_annotation/auditor/traffic_annotation_auditor_unittest.cc
index 7b0d3ad..4dbd6c2 100644
--- a/tools/traffic_annotation/auditor/traffic_annotation_auditor_unittest.cc
+++ b/tools/traffic_annotation/auditor/traffic_annotation_auditor_unittest.cc
@@ -334,7 +334,6 @@
     EXPECT_EQ(annotation.proto.source().file(),
               "chrome/browser/supervised_user/legacy/"
               "supervised_user_refresh_token_fetcher.cc");
-    EXPECT_EQ(annotation.proto.source().function(), "OnGetTokenSuccess");
     EXPECT_EQ(annotation.proto.source().line(), 166);
     EXPECT_EQ(annotation.proto.semantics().sender(), "Supervised Users");
     EXPECT_EQ(annotation.proto.policy().cookies_allowed(), 1);
@@ -365,8 +364,6 @@
 
     EXPECT_EQ(call.file_path, "headless/public/util/http_url_fetcher.cc");
     EXPECT_EQ(call.line_number, 100u);
-    EXPECT_EQ(call.function_context,
-              "headless::HttpURLFetcher::Delegate::Delegate");
     EXPECT_EQ(call.function_name, "net::URLRequestContext::CreateRequest");
     EXPECT_EQ(call.is_annotated, true);
   }
@@ -381,8 +378,7 @@
 
   Assignmentample test_cases[] = {
       {"good_assignment.txt", AuditorResult::Type::RESULT_OK},
-      {"bad_assignment1.txt", AuditorResult::Type::ERROR_FATAL},
-      {"bad_assignment2.txt", AuditorResult::Type::ERROR_FATAL},
+      {"bad_assignment.txt", AuditorResult::Type::ERROR_FATAL},
   };
 
   for (const auto& test_case : test_cases) {
diff --git a/tools/traffic_annotation/bin/README.md b/tools/traffic_annotation/bin/README.md
index 86b3073..516d5d6 100644
--- a/tools/traffic_annotation/bin/README.md
+++ b/tools/traffic_annotation/bin/README.md
@@ -74,5 +74,5 @@
 The following two lines will be updated by the above script, and the modified
 README should be committed along with the updated .sha1 checksums.
 
-CLANG_REVISION = '360094'
-LASTCHANGE=ecda211dff8f3722704938f87637e0df657d15f1-refs/heads/master@{#659930}
+CLANG_REVISION = 'd874c057bc2361da5157553e1e2178f43c3ade1a'
+LASTCHANGE=5a2618740eb68a63b73a40f08a13b1e337cb6399-refs/heads/master@{#674114}
diff --git a/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1 b/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1
index 36278a7b..dacd92d 100644
--- a/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1
+++ b/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1
@@ -1 +1 @@
-73004f4964def13577f9d060d77908d51c30d521
\ No newline at end of file
+24a6a97630bc133de57c4812af3abca8763b5a7f
\ No newline at end of file
diff --git a/tools/traffic_annotation/bin/linux64/traffic_annotation_extractor.sha1 b/tools/traffic_annotation/bin/linux64/traffic_annotation_extractor.sha1
index a9a4ec87..ec1fc1e 100644
--- a/tools/traffic_annotation/bin/linux64/traffic_annotation_extractor.sha1
+++ b/tools/traffic_annotation/bin/linux64/traffic_annotation_extractor.sha1
@@ -1 +1 @@
-c4e2a772fbab2f1f7e47cf8f4f23425933f8cd0f
\ No newline at end of file
+8618305abe807cbeefaaa512e47796f89116bf98
\ No newline at end of file
diff --git a/tools/traffic_annotation/bin/win32/traffic_annotation_auditor.exe.sha1 b/tools/traffic_annotation/bin/win32/traffic_annotation_auditor.exe.sha1
index 8e82538..76a77f3 100644
--- a/tools/traffic_annotation/bin/win32/traffic_annotation_auditor.exe.sha1
+++ b/tools/traffic_annotation/bin/win32/traffic_annotation_auditor.exe.sha1
@@ -1 +1 @@
-e3c00e2607fbe0d5758e60bc42c6802feacdea08
\ No newline at end of file
+fe1e664643c009ca4c16fbe3cabe34a206ca50ee
\ No newline at end of file
diff --git a/tools/traffic_annotation/bin/win32/traffic_annotation_extractor.exe.sha1 b/tools/traffic_annotation/bin/win32/traffic_annotation_extractor.exe.sha1
index 688de3b..14ce2aec 100644
--- a/tools/traffic_annotation/bin/win32/traffic_annotation_extractor.exe.sha1
+++ b/tools/traffic_annotation/bin/win32/traffic_annotation_extractor.exe.sha1
@@ -1 +1 @@
-eac43e1fb9f3fb1a300515061ad9daef6d51839d
\ No newline at end of file
+76bd7403ff65eeeb27c7c56dda2688e3d9319053
\ No newline at end of file
diff --git a/tools/traffic_annotation/scripts/extractor.py b/tools/traffic_annotation/scripts/extractor.py
index b2572af..aaead59 100755
--- a/tools/traffic_annotation/scripts/extractor.py
+++ b/tools/traffic_annotation/scripts/extractor.py
@@ -54,13 +54,6 @@
       file_path: Path to the file that contains this annotation.
     """
     self.file_path = file_path
-    # TODO(crbug/966883): Remove function_name from here and from the clang
-    # tool's output.
-    #
-    # |function_name| is not supported, but keep it in the output for
-    # compatibility with the clang tool. Use an obviously wrong function name
-    # in case this details ends up in auditor output.
-    self.function_name = "XXX_UNIMPLEMENTED_XXX"
     self.line_number = line_number
     self.type_name = type_name
     self.unique_id = unique_id
@@ -88,7 +81,6 @@
     return "\n".join(map(str, [
         "==== NEW ANNOTATION ====",
         self.file_path,
-        self.function_name,
         self.line_number,
         self.type_name,
         self.unique_id,
diff --git a/tools/traffic_annotation/scripts/test_data/valid_file-stdout.txt b/tools/traffic_annotation/scripts/test_data/valid_file-stdout.txt
index b98d267..825fcc9 100644
--- a/tools/traffic_annotation/scripts/test_data/valid_file-stdout.txt
+++ b/tools/traffic_annotation/scripts/test_data/valid_file-stdout.txt
@@ -1,6 +1,5 @@
 ==== NEW ANNOTATION ====
 valid_file.cc
-XXX_UNIMPLEMENTED_XXX
 14
 Definition
 id1
@@ -26,7 +25,6 @@
 ==== ANNOTATION ENDS ====
 ==== NEW ANNOTATION ====
 valid_file.cc
-XXX_UNIMPLEMENTED_XXX
 36
 Partial
 id2
@@ -42,7 +40,6 @@
 ==== ANNOTATION ENDS ====
 ==== NEW ANNOTATION ====
 valid_file.cc
-XXX_UNIMPLEMENTED_XXX
 46
 Completing
 id3
@@ -62,7 +59,6 @@
 ==== ANNOTATION ENDS ====
 ==== NEW ANNOTATION ====
 valid_file.cc
-XXX_UNIMPLEMENTED_XXX
 61
 BranchedCompleting
 id4
@@ -77,7 +73,6 @@
 ==== ANNOTATION ENDS ====
 ==== NEW ANNOTATION ====
 valid_file.cc
-XXX_UNIMPLEMENTED_XXX
 126
 Mutable
 
@@ -86,7 +81,6 @@
 ==== ANNOTATION ENDS ====
 ==== NEW ANNOTATION ====
 valid_file.cc
-XXX_UNIMPLEMENTED_XXX
 86
 Definition
 test
@@ -95,7 +89,6 @@
 ==== ANNOTATION ENDS ====
 ==== NEW ANNOTATION ====
 valid_file.cc
-XXX_UNIMPLEMENTED_XXX
 88
 Partial
 test_partial
diff --git a/tools/traffic_annotation/traffic_annotation.proto b/tools/traffic_annotation/traffic_annotation.proto
index d00be7e..65bc32b 100644
--- a/tools/traffic_annotation/traffic_annotation.proto
+++ b/tools/traffic_annotation/traffic_annotation.proto
@@ -38,12 +38,6 @@
     // specified.
     string file = 1;
 
-    // Function name where the network request is instantiated.
-    // This is typically filled by the extractor and does not need to be
-    // specified in the source code. For manual whitelisting this needs to be
-    // specified.
-    string function = 2;
-
     // __LINE__ in file, where the AuditPolicy object is instantiated.
     // This is typically filled by the extractor and does not need to be
     // specified in the source code.
diff --git a/ui/aura/client/drag_drop_client.h b/ui/aura/client/drag_drop_client.h
index 8e96348..8de8940 100644
--- a/ui/aura/client/drag_drop_client.h
+++ b/ui/aura/client/drag_drop_client.h
@@ -32,7 +32,7 @@
   // applied at the end of the drag drop session. |screen_location| is in
   // screen coordinates. At most one drag and drop operation is allowed.
   // It must not start drag operation while |IsDragDropInProgress| returns true.
-  virtual int StartDragAndDrop(const ui::OSExchangeData& data,
+  virtual int StartDragAndDrop(std::unique_ptr<ui::OSExchangeData> data,
                                aura::Window* root_window,
                                aura::Window* source_window,
                                const gfx::Point& screen_location,
diff --git a/ui/aura/client/drag_drop_delegate.h b/ui/aura/client/drag_drop_delegate.h
index 0310433..304b1a6 100644
--- a/ui/aura/client/drag_drop_delegate.h
+++ b/ui/aura/client/drag_drop_delegate.h
@@ -7,6 +7,7 @@
 
 #include "ui/aura/aura_export.h"
 #include "ui/aura/window.h"
+#include "ui/base/dragdrop/os_exchange_data.h"
 
 namespace ui {
 class DropTargetEvent;
@@ -35,8 +36,13 @@
   virtual void OnDragExited() = 0;
 
   // Invoked during a drag and drop session when OnDragUpdated returns a valid
-  // operation and the user release the mouse.
-  virtual int OnPerformDrop(const ui::DropTargetEvent& event) = 0;
+  // operation and the user release the mouse. This function gets the ownership
+  // of underlying OSExchangeData. A reference to this same OSExchangeData is
+  // also stored in the DropTargetEvent. Implementor of this function should be
+  // aware of keeping the OSExchageData alive until it wants to access it
+  // through the parameter or the stored reference in DropTargetEvent.
+  virtual int OnPerformDrop(const ui::DropTargetEvent& event,
+                            std::unique_ptr<ui::OSExchangeData> data) = 0;
 
  protected:
   virtual ~DragDropDelegate() {}
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h
index 04e153e9..83fd231 100644
--- a/ui/compositor/compositor.h
+++ b/ui/compositor/compositor.h
@@ -64,7 +64,6 @@
 }
 
 namespace viz {
-class FrameSinkManagerImpl;
 class ContextProvider;
 class HostFrameSinkManager;
 class LocalSurfaceIdAllocation;
@@ -115,9 +114,6 @@
   // Allocate a new client ID for the display compositor.
   virtual viz::FrameSinkId AllocateFrameSinkId() = 0;
 
-  // Gets the frame sink manager.
-  virtual viz::FrameSinkManagerImpl* GetFrameSinkManager() = 0;
-
   // Gets the frame sink manager host instance.
   virtual viz::HostFrameSinkManager* GetHostFrameSinkManager() = 0;
 
diff --git a/ui/compositor/host/host_context_factory_private.cc b/ui/compositor/host/host_context_factory_private.cc
index 0ff1e052..faf99a2 100644
--- a/ui/compositor/host/host_context_factory_private.cc
+++ b/ui/compositor/host/host_context_factory_private.cc
@@ -297,16 +297,6 @@
   }
 }
 
-viz::FrameSinkManagerImpl* HostContextFactoryPrivate::GetFrameSinkManager() {
-  // When running with viz there is no FrameSinkManagerImpl in the browser
-  // process. FrameSinkManagerImpl runs in the GPU process instead. Anything in
-  // the browser process that relies FrameSinkManagerImpl or SurfaceManager
-  // internal state needs to change. See https://crbug.com/787097 and
-  // https://crbug.com/760181 for more context.
-  NOTREACHED();
-  return nullptr;
-}
-
 HostContextFactoryPrivate::CompositorData::CompositorData() = default;
 HostContextFactoryPrivate::CompositorData::CompositorData(
     CompositorData&& other) = default;
diff --git a/ui/compositor/host/host_context_factory_private.h b/ui/compositor/host/host_context_factory_private.h
index dc31ab80..ef9b2e44b 100644
--- a/ui/compositor/host/host_context_factory_private.h
+++ b/ui/compositor/host/host_context_factory_private.h
@@ -83,7 +83,6 @@
   void IssueExternalBeginFrame(Compositor* compositor,
                                const viz::BeginFrameArgs& args) override;
   void SetOutputIsSecure(Compositor* compositor, bool secure) override;
-  viz::FrameSinkManagerImpl* GetFrameSinkManager() override;
   void AddVSyncParameterObserver(
       Compositor* compositor,
       viz::mojom::VSyncParameterObserverPtr observer) override;
diff --git a/ui/compositor/test/in_process_context_factory.cc b/ui/compositor/test/in_process_context_factory.cc
index b89f035..18f9108 100644
--- a/ui/compositor/test/in_process_context_factory.cc
+++ b/ui/compositor/test/in_process_context_factory.cc
@@ -261,8 +261,8 @@
       &shared_bitmap_manager_, renderer_settings_, compositor->frame_sink_id(),
       std::move(display_output_surface), std::move(scheduler),
       compositor->task_runner());
-  GetFrameSinkManager()->RegisterBeginFrameSource(begin_frame_source.get(),
-                                                  compositor->frame_sink_id());
+  frame_sink_manager_->RegisterBeginFrameSource(begin_frame_source.get(),
+                                                compositor->frame_sink_id());
   // Note that we are careful not to destroy a prior |data->begin_frame_source|
   // until we have reset |data->display|.
   data->begin_frame_source = std::move(begin_frame_source);
@@ -270,7 +270,7 @@
   auto* display = per_compositor_data_[compositor.get()]->display.get();
   auto layer_tree_frame_sink = std::make_unique<viz::DirectLayerTreeFrameSink>(
       compositor->frame_sink_id(), GetHostFrameSinkManager(),
-      GetFrameSinkManager(), display, nullptr /* display_client */,
+      frame_sink_manager_, display, nullptr /* display_client */,
       context_provider, shared_worker_context_provider_,
       compositor->task_runner(), &gpu_memory_buffer_manager_);
   compositor->SetLayerTreeFrameSink(std::move(layer_tree_frame_sink));
@@ -323,7 +323,7 @@
   if (it == per_compositor_data_.end())
     return;
   PerCompositorData* data = it->second.get();
-  GetFrameSinkManager()->UnregisterBeginFrameSource(
+  frame_sink_manager_->UnregisterBeginFrameSource(
       data->begin_frame_source.get());
   DCHECK(data);
 #if !defined(GPU_SURFACE_HANDLE_IS_ACCELERATED_WINDOW)
@@ -389,10 +389,6 @@
   observer_list_.RemoveObserver(observer);
 }
 
-viz::FrameSinkManagerImpl* InProcessContextFactory::GetFrameSinkManager() {
-  return frame_sink_manager_;
-}
-
 SkMatrix44 InProcessContextFactory::GetOutputColorMatrix(
     Compositor* compositor) const {
   auto iter = per_compositor_data_.find(compositor);
diff --git a/ui/compositor/test/in_process_context_factory.h b/ui/compositor/test/in_process_context_factory.h
index 0e35ab59..86a3c075 100644
--- a/ui/compositor/test/in_process_context_factory.h
+++ b/ui/compositor/test/in_process_context_factory.h
@@ -21,10 +21,6 @@
 #include "services/viz/privileged/interfaces/compositing/vsync_parameter_observer.mojom.h"
 #include "ui/compositor/compositor.h"
 
-namespace cc {
-class FrameSinkManagerImpl;
-}
-
 namespace viz {
 class HostFrameSinkManager;
 }
@@ -43,6 +39,10 @@
                           viz::FrameSinkManagerImpl* frame_sink_manager);
   ~InProcessContextFactory() override;
 
+  viz::FrameSinkManagerImpl* GetFrameSinkManager() {
+    return frame_sink_manager_;
+  }
+
   // If true (the default) an OutputSurface is created that does not display
   // anything. Set to false if you want to see results on the screen.
   void set_use_test_surface(bool use_test_surface) {
@@ -96,7 +96,6 @@
   void AddObserver(ContextFactoryObserver* observer) override;
   void RemoveObserver(ContextFactoryObserver* observer) override;
   bool SyncTokensRequiredForDisplayCompositor() override;
-  viz::FrameSinkManagerImpl* GetFrameSinkManager() override;
 
   SkMatrix44 GetOutputColorMatrix(Compositor* compositor) const;
   void ResetOutputColorMatrixToIdentity(ui::Compositor* compositor);
diff --git a/ui/display/manager/content_protection_manager.cc b/ui/display/manager/content_protection_manager.cc
index a23c5d3..3081b70 100644
--- a/ui/display/manager/content_protection_manager.cc
+++ b/ui/display/manager/content_protection_manager.cc
@@ -228,14 +228,25 @@
   KillTasks();
 }
 
-void ContentProtectionManager::ToggleDisplaySecurityPolling() {
-  const bool polling = security_timer_.IsRunning();
+bool ContentProtectionManager::ShouldPollDisplaySecurity() const {
+  const auto displays = layout_manager_->GetDisplayStates();
+  if (std::all_of(displays.begin(), displays.end(),
+                  [](const DisplaySnapshot* display) {
+                    return display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL;
+                  })) {
+    return false;
+  }
 
   const auto protections = AggregateContentProtections();
-  const bool should_poll =
-      std::any_of(protections.begin(), protections.end(), [](const auto& pair) {
-        return pair.second != CONTENT_PROTECTION_METHOD_NONE;
-      });
+  return std::any_of(protections.begin(), protections.end(),
+                     [](const auto& pair) {
+                       return pair.second != CONTENT_PROTECTION_METHOD_NONE;
+                     });
+}
+
+void ContentProtectionManager::ToggleDisplaySecurityPolling() {
+  const bool polling = security_timer_.IsRunning();
+  const bool should_poll = ShouldPollDisplaySecurity();
 
   if (polling && !should_poll) {
     security_timer_.Stop();
diff --git a/ui/display/manager/content_protection_manager.h b/ui/display/manager/content_protection_manager.h
index cd7d704f..6364e93 100644
--- a/ui/display/manager/content_protection_manager.h
+++ b/ui/display/manager/content_protection_manager.h
@@ -143,6 +143,8 @@
   void OnDisplayModeChangeFailed(const DisplayConfigurator::DisplayStateList&,
                                  MultipleDisplayState) override;
 
+  bool ShouldPollDisplaySecurity() const;
+
   // Toggles timer for periodic security queries given latest client requests.
   void ToggleDisplaySecurityPolling();
 
diff --git a/ui/display/manager/content_protection_manager_unittest.cc b/ui/display/manager/content_protection_manager_unittest.cc
index df288150..d0c4798 100644
--- a/ui/display/manager/content_protection_manager_unittest.cc
+++ b/ui/display/manager/content_protection_manager_unittest.cc
@@ -635,5 +635,41 @@
             observer.security_changes());
 }
 
+TEST_F(ContentProtectionManagerTest, NoSecurityPollingIfInternalDisplayOnly) {
+  UpdateDisplays(1);
+  TestObserver observer(&manager_);
+
+  EXPECT_EQ(SecurityChanges({{kDisplayIds[0], true}}),
+            observer.security_changes());
+  observer.Reset();
+
+  auto id = manager_.RegisterClient();
+  EXPECT_TRUE(id);
+
+  native_display_delegate_.set_run_async(true);
+
+  manager_.ApplyContentProtection(
+      id, kDisplayIds[0], CONTENT_PROTECTION_METHOD_HDCP,
+      base::BindOnce(
+          &ContentProtectionManagerTest::ApplyContentProtectionCallback,
+          base::Unretained(this)));
+
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(observer.security_changes().empty());
+
+  // Timer should not be running unless there are external displays.
+  EXPECT_FALSE(TriggerDisplaySecurityTimeout());
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(SecurityChanges(), observer.security_changes());
+
+  manager_.UnregisterClient(id);
+
+  EXPECT_FALSE(TriggerDisplaySecurityTimeout());
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(SecurityChanges(), observer.security_changes());
+}
+
 }  // namespace test
 }  // namespace display
diff --git a/ui/login/display_manager.js b/ui/login/display_manager.js
index c4b6028c..c79f49ab 100644
--- a/ui/login/display_manager.js
+++ b/ui/login/display_manager.js
@@ -61,6 +61,7 @@
 /** @const */ var ACCELERATOR_SEND_FEEDBACK = "send_feedback";
 
 /* Signin UI state constants. Used to control header bar UI. */
+/* TODO(https://crbug.com/981544): Sync with login_types.h */
 /** @const */ var SIGNIN_UI_STATE = {
   HIDDEN: 0,
   GAIA_SIGNIN: 1,
diff --git a/ui/native_theme/native_theme.cc b/ui/native_theme/native_theme.cc
index 3d01013..104b7d3 100644
--- a/ui/native_theme/native_theme.cc
+++ b/ui/native_theme/native_theme.cc
@@ -10,7 +10,6 @@
 #include "base/command_line.h"
 #include "ui/base/ui_base_switches.h"
 #include "ui/native_theme/dark_mode_observer.h"
-#include "ui/native_theme/native_theme_observer.h"
 
 namespace ui {
 
@@ -86,4 +85,31 @@
   set_dark_mode(is_dark_mode);
   NotifyObservers();
 }
+
+NativeTheme::ColorSchemeNativeThemeObserver::ColorSchemeNativeThemeObserver(
+    NativeTheme* theme_to_update)
+    : theme_to_update_(theme_to_update) {}
+
+NativeTheme::ColorSchemeNativeThemeObserver::~ColorSchemeNativeThemeObserver() =
+    default;
+
+void NativeTheme::ColorSchemeNativeThemeObserver::OnNativeThemeUpdated(
+    ui::NativeTheme* observed_theme) {
+  bool is_dark_mode = observed_theme->SystemDarkModeEnabled();
+  bool is_high_contrast = observed_theme->UsesHighContrastColors();
+  bool notify_observers = false;
+
+  if (theme_to_update_->SystemDarkModeEnabled() != is_dark_mode) {
+    theme_to_update_->set_dark_mode(is_dark_mode);
+    notify_observers = true;
+  }
+  if (theme_to_update_->UsesHighContrastColors() != is_high_contrast) {
+    theme_to_update_->set_high_contrast(is_high_contrast);
+    notify_observers = true;
+  }
+
+  if (notify_observers)
+    theme_to_update_->NotifyObservers();
+}
+
 }  // namespace ui
diff --git a/ui/native_theme/native_theme.h b/ui/native_theme/native_theme.h
index 68d9f2a..6f0ee21 100644
--- a/ui/native_theme/native_theme.h
+++ b/ui/native_theme/native_theme.h
@@ -16,6 +16,7 @@
 #include "ui/gfx/native_widget_types.h"
 #include "ui/native_theme/caption_style.h"
 #include "ui/native_theme/native_theme_export.h"
+#include "ui/native_theme/native_theme_observer.h"
 
 namespace gfx {
 class Rect;
@@ -24,7 +25,6 @@
 
 namespace ui {
 class DarkModeObserver;
-class NativeThemeObserver;
 
 // This class supports drawing UI controls (like buttons, text fields, lists,
 // comboboxes, etc) that look like the native UI controls of the underlying
@@ -434,6 +434,25 @@
     is_high_contrast_ = is_high_contrast;
   }
 
+  // Allows one native theme to observe changes in another. For example, the
+  // web native theme for Windows observes the corresponding ui native theme in
+  // order to receive changes regarding the state of dark mode/high contrast.
+  class NATIVE_THEME_EXPORT ColorSchemeNativeThemeObserver
+      : public NativeThemeObserver {
+   public:
+    ColorSchemeNativeThemeObserver(NativeTheme* theme_to_update);
+    ~ColorSchemeNativeThemeObserver() override;
+
+   private:
+    // ui::NativeThemeObserver:
+    void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) override;
+
+    // The theme that gets updated when OnNativeThemeUpdated() is called.
+    NativeTheme* const theme_to_update_;
+
+    DISALLOW_COPY_AND_ASSIGN(ColorSchemeNativeThemeObserver);
+  };
+
  private:
   // DarkModeObserver callback.
   void OnParentDarkModeChanged(bool is_dark_mode);
diff --git a/ui/native_theme/native_theme_aura.h b/ui/native_theme/native_theme_aura.h
index 6ce6a8a4..5c08f42 100644
--- a/ui/native_theme/native_theme_aura.h
+++ b/ui/native_theme/native_theme_aura.h
@@ -24,7 +24,7 @@
   static NativeThemeAura* instance();
   static NativeThemeAura* web_instance();
 
-  // Overridden from NativeThemeBase:
+  // NativeThemeBase:
   SkColor GetSystemColor(ColorId color_id) const override;
   void PaintMenuPopupBackground(
       cc::PaintCanvas* canvas,
diff --git a/ui/native_theme/native_theme_win.cc b/ui/native_theme/native_theme_win.cc
index e74d07035..8e17360 100644
--- a/ui/native_theme/native_theme_win.cc
+++ b/ui/native_theme/native_theme_win.cc
@@ -254,11 +254,17 @@
         GetProcAddress(theme_dll_, "CloseThemeData"));
   }
 
+  // If there's no sequenced task runner handle, we can't be called back for
+  // dark mode changes. This generally happens in tests. As a result, ignore
+  // dark mode in this case.
   if (!IsForcedDarkMode() && !IsForcedHighContrast() &&
       base::SequencedTaskRunnerHandle::IsSet()) {
-    // If there's no sequenced task runner handle, we can't be called back for
-    // dark mode changes. This generally happens in tests. As a result, ignore
-    // dark mode in this case.
+    // Add the web native theme as an observer to stay in sync with dark mode/
+    // high contrast changes.
+    color_scheme_observer_ =
+        std::make_unique<NativeTheme::ColorSchemeNativeThemeObserver>(
+            NativeTheme::GetInstanceForWeb());
+    AddObserver(color_scheme_observer_.get());
 
     // Dark Mode currently targets UWP apps, which means Win32 apps need to use
     // alternate, less reliable means of detecting the state. The following
@@ -270,7 +276,6 @@
             L"Themes\\Personalize",
             KEY_READ | KEY_NOTIFY) == ERROR_SUCCESS;
     if (key_open_succeeded) {
-      NativeTheme::GetInstanceForWeb()->SetDarkModeParent(this);
       UpdateDarkModeStatus();
       RegisterThemeRegkeyObserver();
     }
diff --git a/ui/native_theme/native_theme_win.h b/ui/native_theme/native_theme_win.h
index 6794de1d..9a17b16 100644
--- a/ui/native_theme/native_theme_win.h
+++ b/ui/native_theme/native_theme_win.h
@@ -329,6 +329,11 @@
   gfx::ScopedSysColorChangeListener color_change_listener_;
   mutable std::map<int, SkColor> system_colors_;
 
+  // Used to notify the web native theme of changes to dark mode and high
+  // contrast.
+  std::unique_ptr<NativeTheme::ColorSchemeNativeThemeObserver>
+      color_scheme_observer_;
+
   DISALLOW_COPY_AND_ASSIGN(NativeThemeWin);
 };
 
diff --git a/ui/native_theme/test_native_theme.cc b/ui/native_theme/test_native_theme.cc
index 200eb212..dcc5f85 100644
--- a/ui/native_theme/test_native_theme.cc
+++ b/ui/native_theme/test_native_theme.cc
@@ -38,7 +38,7 @@
 }
 
 bool TestNativeTheme::UsesHighContrastColors() const {
-  return false;
+  return high_contrast_;
 }
 
 bool TestNativeTheme::SystemDarkModeEnabled() const {
diff --git a/ui/native_theme/test_native_theme.h b/ui/native_theme/test_native_theme.h
index bdfc278..73b8a45 100644
--- a/ui/native_theme/test_native_theme.h
+++ b/ui/native_theme/test_native_theme.h
@@ -32,9 +32,13 @@
   bool SystemDarkModeEnabled() const override;
 
   void SetDarkMode(bool dark_mode) { dark_mode_ = dark_mode; }
+  void SetUsesHighContrastColors(bool high_contrast) {
+    high_contrast_ = high_contrast;
+  }
 
  private:
   bool dark_mode_ = false;
+  bool high_contrast_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(TestNativeTheme);
 };
diff --git a/ui/views/cocoa/drag_drop_client_mac.h b/ui/views/cocoa/drag_drop_client_mac.h
index f1e51a6..608e73a 100644
--- a/ui/views/cocoa/drag_drop_client_mac.h
+++ b/ui/views/cocoa/drag_drop_client_mac.h
@@ -44,7 +44,7 @@
   // Initiates a drag and drop session. Returns the drag operation that was
   // applied at the end of the drag drop session.
   void StartDragAndDrop(View* view,
-                        const ui::OSExchangeData& data,
+                        std::unique_ptr<ui::OSExchangeData> data,
                         int operation,
                         ui::DragDropTypes::DragEventSource source);
 
diff --git a/ui/views/cocoa/drag_drop_client_mac.mm b/ui/views/cocoa/drag_drop_client_mac.mm
index f24d82f..16ed882 100644
--- a/ui/views/cocoa/drag_drop_client_mac.mm
+++ b/ui/views/cocoa/drag_drop_client_mac.mm
@@ -27,12 +27,10 @@
 
 void DragDropClientMac::StartDragAndDrop(
     View* view,
-    const ui::OSExchangeData& data,
+    std::unique_ptr<ui::OSExchangeData> data,
     int operation,
     ui::DragDropTypes::DragEventSource source) {
-  // TODO(avi): Why must this data be cloned?
-  exchange_data_ =
-      std::make_unique<ui::OSExchangeData>(data.provider().Clone());
+  exchange_data_ = std::move(data);
   source_operation_ = operation;
   is_drag_source_ = true;
 
diff --git a/ui/views/cocoa/drag_drop_client_mac_unittest.mm b/ui/views/cocoa/drag_drop_client_mac_unittest.mm
index c4084bc..10ad4b6 100644
--- a/ui/views/cocoa/drag_drop_client_mac_unittest.mm
+++ b/ui/views/cocoa/drag_drop_client_mac_unittest.mm
@@ -245,12 +245,12 @@
   EXPECT_TRUE(ns_window_host_->IsMouseCaptureActive());
 
   // Create the drop data
-  OSExchangeData data;
+  std::unique_ptr<OSExchangeData> data(std::make_unique<OSExchangeData>());
   const base::string16& text = ASCIIToUTF16("text");
-  data.SetString(text);
-  data.provider().SetDragImage(gfx::test::CreateImageSkia(100, 100),
-                               gfx::Vector2d());
-  SetData(data);
+  data->SetString(text);
+  data->provider().SetDragImage(gfx::test::CreateImageSkia(100, 100),
+                                gfx::Vector2d());
+  SetData(*data.get());
 
   // There's no way to cleanly stop NSDraggingSession inside unit tests, so just
   // don't start it at all.
@@ -265,7 +265,7 @@
 
   // It will call ReleaseCapture().
   drag_drop_client()->StartDragAndDrop(
-      target_, data, 0, ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
+      target_, std::move(data), 0, ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
 
   // The capture should be released.
   EXPECT_FALSE(ns_window_host_->IsMouseCaptureActive());
diff --git a/ui/views/controls/button/menu_button_unittest.cc b/ui/views/controls/button/menu_button_unittest.cc
index 18665c52d..f296f95a 100644
--- a/ui/views/controls/button/menu_button_unittest.cc
+++ b/ui/views/controls/button/menu_button_unittest.cc
@@ -243,7 +243,7 @@
   ~TestDragDropClient() override;
 
   // aura::client::DragDropClient:
-  int StartDragAndDrop(const ui::OSExchangeData& data,
+  int StartDragAndDrop(std::unique_ptr<ui::OSExchangeData> data,
                        aura::Window* root_window,
                        aura::Window* source_window,
                        const gfx::Point& screen_location,
@@ -273,7 +273,7 @@
 TestDragDropClient::~TestDragDropClient() = default;
 
 int TestDragDropClient::StartDragAndDrop(
-    const ui::OSExchangeData& data,
+    std::unique_ptr<ui::OSExchangeData> data,
     aura::Window* root_window,
     aura::Window* source_window,
     const gfx::Point& screen_location,
diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc
index 093adf8b..8aa0da1 100644
--- a/ui/views/controls/menu/menu_controller.cc
+++ b/ui/views/controls/menu/menu_controller.cc
@@ -1407,16 +1407,17 @@
   item->PaintButton(&canvas, MenuItemView::PB_FOR_DRAG);
   gfx::ImageSkia image(gfx::ImageSkiaRep(canvas.GetBitmap(), raster_scale));
 
-  OSExchangeData data;
-  item->GetDelegate()->WriteDragData(item, &data);
-  data.provider().SetDragImage(image, press_loc.OffsetFromOrigin());
+  std::unique_ptr<OSExchangeData> data(std::make_unique<OSExchangeData>());
+  item->GetDelegate()->WriteDragData(item, data.get());
+  data->provider().SetDragImage(image, press_loc.OffsetFromOrigin());
 
   StopScrolling();
   int drag_ops = item->GetDelegate()->GetDragOperations(item);
   did_initiate_drag_ = true;
   base::WeakPtr<MenuController> this_ref = AsWeakPtr();
   // TODO(varunjain): Properly determine and send DRAG_EVENT_SOURCE below.
-  item->GetWidget()->RunShellDrag(nullptr, data, widget_loc, drag_ops,
+  item->GetWidget()->RunShellDrag(nullptr, std::move(data), widget_loc,
+                                  drag_ops,
                                   ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
   // MenuController may have been deleted so check before accessing member
   // variables.
diff --git a/ui/views/controls/menu/menu_controller_unittest.cc b/ui/views/controls/menu/menu_controller_unittest.cc
index 3175143..c458d54 100644
--- a/ui/views/controls/menu/menu_controller_unittest.cc
+++ b/ui/views/controls/menu/menu_controller_unittest.cc
@@ -184,7 +184,7 @@
   ~TestDragDropClient() override = default;
 
   // aura::client::DragDropClient:
-  int StartDragAndDrop(const ui::OSExchangeData& data,
+  int StartDragAndDrop(std::unique_ptr<ui::OSExchangeData> data,
                        aura::Window* root_window,
                        aura::Window* source_window,
                        const gfx::Point& screen_location,
@@ -205,7 +205,7 @@
 };
 
 int TestDragDropClient::StartDragAndDrop(
-    const ui::OSExchangeData& data,
+    std::unique_ptr<ui::OSExchangeData> data,
     aura::Window* root_window,
     aura::Window* source_window,
     const gfx::Point& screen_location,
diff --git a/ui/views/drag_utils.h b/ui/views/drag_utils.h
index e6f778e..d8c1be0 100644
--- a/ui/views/drag_utils.h
+++ b/ui/views/drag_utils.h
@@ -6,6 +6,7 @@
 #define UI_VIEWS_DRAG_UTILS_H_
 
 #include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/dragdrop/os_exchange_data.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/views/views_export.h"
 
@@ -13,16 +14,12 @@
 class Point;
 }
 
-namespace ui {
-class OSExchangeData;
-}
-
 namespace views {
 class Widget;
 
 // Starts a drag operation. This blocks until the drag operation completes.
 VIEWS_EXPORT void RunShellDrag(gfx::NativeView view,
-                               const ui::OSExchangeData& data,
+                               std::unique_ptr<ui::OSExchangeData> data,
                                const gfx::Point& location,
                                int operation,
                                ui::DragDropTypes::DragEventSource source);
diff --git a/ui/views/drag_utils_aura.cc b/ui/views/drag_utils_aura.cc
index 27577e0..3142d9c0f 100644
--- a/ui/views/drag_utils_aura.cc
+++ b/ui/views/drag_utils_aura.cc
@@ -12,7 +12,7 @@
 namespace views {
 
 void RunShellDrag(gfx::NativeView view,
-                  const ui::OSExchangeData& data,
+                  std::unique_ptr<ui::OSExchangeData> data,
                   const gfx::Point& location,
                   int operation,
                   ui::DragDropTypes::DragEventSource source) {
@@ -20,8 +20,9 @@
   wm::ConvertPointToScreen(view, &screen_location);
   aura::Window* root_window = view->GetRootWindow();
   if (aura::client::GetDragDropClient(root_window)) {
-    aura::client::GetDragDropClient(root_window)->StartDragAndDrop(
-        data, root_window, view, screen_location, operation, source);
+    aura::client::GetDragDropClient(root_window)
+        ->StartDragAndDrop(std::move(data), root_window, view, screen_location,
+                           operation, source);
   }
 }
 
diff --git a/ui/views/drag_utils_mac.mm b/ui/views/drag_utils_mac.mm
index 4d512b1f..59dc6ea 100644
--- a/ui/views/drag_utils_mac.mm
+++ b/ui/views/drag_utils_mac.mm
@@ -7,7 +7,7 @@
 namespace views {
 
 void RunShellDrag(gfx::NativeView view,
-                  const ui::OSExchangeData& data,
+                  std::unique_ptr<ui::OSExchangeData> data,
                   const gfx::Point& location,
                   int operation,
                   ui::DragDropTypes::DragEventSource source) {
diff --git a/ui/views/view.cc b/ui/views/view.cc
index 29bf95bf..4e233e53 100644
--- a/ui/views/view.cc
+++ b/ui/views/view.cc
@@ -2848,14 +2848,15 @@
   if (widget->dragged_view())
     return false;
 
-  OSExchangeData data;
-  WriteDragData(press_pt, &data);
+  std::unique_ptr<OSExchangeData> data(std::make_unique<OSExchangeData>());
+  WriteDragData(press_pt, data.get());
 
   // Message the RootView to do the drag and drop. That way if we're removed
   // the RootView can detect it and avoid calling us back.
   gfx::Point widget_location(event.location());
   ConvertPointToWidget(this, &widget_location);
-  widget->RunShellDrag(this, data, widget_location, drag_operations, source);
+  widget->RunShellDrag(this, std::move(data), widget_location, drag_operations,
+                       source);
   // WARNING: we may have been deleted.
   return true;
 }
diff --git a/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc b/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc
index ecd4604..0d545f2 100644
--- a/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc
+++ b/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc
@@ -679,11 +679,11 @@
     aura::client::DragDropDelegate* delegate =
         aura::client::GetDragDropDelegate(target_window_);
     if (delegate) {
-      ui::OSExchangeData data(
+      auto data(std::make_unique<ui::OSExchangeData>(
           std::make_unique<ui::OSExchangeDataProviderAuraX11>(
-              xwindow_, target_current_context_->fetched_targets()));
+              xwindow_, target_current_context_->fetched_targets())));
 
-      ui::DropTargetEvent event(data,
+      ui::DropTargetEvent event(*data.get(),
                                 gfx::PointF(target_window_location_),
                                 gfx::PointF(target_window_root_location_),
                                 target_current_context_->GetDragOperation());
@@ -698,7 +698,7 @@
         UMA_HISTOGRAM_COUNTS_1M("Event.DragDrop.ExternalOriginDrop", 1);
       }
 
-      drag_operation = delegate->OnPerformDrop(event);
+      drag_operation = delegate->OnPerformDrop(event, std::move(data));
     }
 
     target_window_->RemoveObserver(this);
@@ -729,7 +729,7 @@
 }
 
 int DesktopDragDropClientAuraX11::StartDragAndDrop(
-    const ui::OSExchangeData& data,
+    std::unique_ptr<ui::OSExchangeData> data,
     aura::Window* root_window,
     aura::Window* source_window,
     const gfx::Point& screen_location,
@@ -748,7 +748,7 @@
   drag_operation_ = operation;
   negotiated_operation_ = ui::DragDropTypes::DRAG_NONE;
 
-  const ui::OSExchangeData::Provider* provider = &data.provider();
+  const ui::OSExchangeData::Provider* provider = &data->provider();
   source_provider_ = static_cast<const ui::OSExchangeDataProviderAuraX11*>(
       provider);
 
diff --git a/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h b/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h
index de85508..fea36f36 100644
--- a/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h
+++ b/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h
@@ -82,7 +82,7 @@
   void OnSelectionNotify(const XSelectionEvent& xselection);
 
   // Overridden from aura::client::DragDropClient:
-  int StartDragAndDrop(const ui::OSExchangeData& data,
+  int StartDragAndDrop(std::unique_ptr<ui::OSExchangeData> data,
                        aura::Window* root_window,
                        aura::Window* source_window,
                        const gfx::Point& screen_location,
diff --git a/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc b/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc
index ef13a2b4..df07559 100644
--- a/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc
+++ b/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc
@@ -361,20 +361,17 @@
   ~DesktopDragDropClientAuraX11Test() override = default;
 
   int StartDragAndDrop() {
-    ui::OSExchangeData data;
-    data.SetString(base::ASCIIToUTF16("Test"));
+    auto data(std::make_unique<ui::OSExchangeData>());
+    data->SetString(base::ASCIIToUTF16("Test"));
     SkBitmap drag_bitmap;
     drag_bitmap.allocN32Pixels(10, 10);
     drag_bitmap.eraseARGB(0xFF, 0, 0, 0);
     gfx::ImageSkia drag_image(gfx::ImageSkia::CreateFrom1xBitmap(drag_bitmap));
-    data.provider().SetDragImage(drag_image, gfx::Vector2d());
+    data->provider().SetDragImage(drag_image, gfx::Vector2d());
 
     return client_->StartDragAndDrop(
-        data,
-        widget_->GetNativeWindow()->GetRootWindow(),
-        widget_->GetNativeWindow(),
-        gfx::Point(),
-        ui::DragDropTypes::DRAG_COPY,
+        std::move(data), widget_->GetNativeWindow()->GetRootWindow(),
+        widget_->GetNativeWindow(), gfx::Point(), ui::DragDropTypes::DRAG_COPY,
         ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
   }
 
@@ -806,7 +803,8 @@
     ++num_exits_;
   }
 
-  int OnPerformDrop(const ui::DropTargetEvent& event) override {
+  int OnPerformDrop(const ui::DropTargetEvent& event,
+                    std::unique_ptr<OSExchangeData> data) override {
     ++num_drops_;
     last_event_mouse_position_ = event.location();
     last_event_flags_ = event.flags();
@@ -836,15 +834,12 @@
   ~DesktopDragDropClientAuraX11ChromeSourceTargetTest() override = default;
 
   int StartDragAndDrop() {
-    ui::OSExchangeData data;
-    data.SetString(base::ASCIIToUTF16("Test"));
+    auto data(std::make_unique<ui::OSExchangeData>());
+    data->SetString(base::ASCIIToUTF16("Test"));
 
     return client_->StartDragAndDrop(
-        data,
-        widget_->GetNativeWindow()->GetRootWindow(),
-        widget_->GetNativeWindow(),
-        gfx::Point(),
-        ui::DragDropTypes::DRAG_COPY,
+        std::move(data), widget_->GetNativeWindow()->GetRootWindow(),
+        widget_->GetNativeWindow(), gfx::Point(), ui::DragDropTypes::DRAG_COPY,
         ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
   }
 
diff --git a/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc b/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc
index dfe5f9a..7f08e6a 100644
--- a/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc
+++ b/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc
@@ -53,7 +53,7 @@
 }
 
 int DesktopDragDropClientOzone::StartDragAndDrop(
-    const ui::OSExchangeData& data,
+    std::unique_ptr<ui::OSExchangeData> data,
     aura::Window* root_window,
     aura::Window* source_window,
     const gfx::Point& root_location,
@@ -81,7 +81,7 @@
       cursor_manager_->GetInitializedCursor(ui::CursorType::kGrabbing));
 
   drag_handler_->StartDrag(
-      data, operation, cursor_client->GetCursor(),
+      *data.get(), operation, cursor_client->GetCursor(),
       base::BindOnce(&DesktopDragDropClientOzone::OnDragSessionClosed,
                      base::Unretained(this)));
   in_move_loop_ = true;
@@ -234,7 +234,8 @@
   std::unique_ptr<ui::DropTargetEvent> event =
       CreateDropTargetEvent(last_drag_point_);
   if (drag_drop_delegate_ && event)
-    drag_operation_ = drag_drop_delegate_->OnPerformDrop(*event);
+    drag_operation_ = drag_drop_delegate_->OnPerformDrop(
+        *event, std::move(os_exchange_data_));
   DragDropSessionCompleted();
 }
 
diff --git a/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.h b/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.h
index e31f41b..05b2fd2 100644
--- a/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.h
+++ b/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.h
@@ -40,7 +40,7 @@
   ~DesktopDragDropClientOzone() override;
 
   // Overridden from aura::client::DragDropClient:
-  int StartDragAndDrop(const ui::OSExchangeData& data,
+  int StartDragAndDrop(std::unique_ptr<ui::OSExchangeData> data,
                        aura::Window* root_window,
                        aura::Window* source_window,
                        const gfx::Point& root_location,
diff --git a/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc b/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc
index 2c829dc..b2c6b75 100644
--- a/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc
+++ b/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc
@@ -30,7 +30,7 @@
 }
 
 int DesktopDragDropClientWin::StartDragAndDrop(
-    const ui::OSExchangeData& data,
+    std::unique_ptr<ui::OSExchangeData> data,
     aura::Window* root_window,
     aura::Window* source_window,
     const gfx::Point& screen_location,
@@ -43,8 +43,8 @@
 
   drag_source_ = ui::DragSourceWin::Create();
   Microsoft::WRL::ComPtr<ui::DragSourceWin> drag_source_copy = drag_source_;
-  drag_source_copy->set_data(&data);
-  ui::OSExchangeDataProviderWin::GetDataObjectImpl(data)
+  drag_source_copy->set_data(data.get());
+  ui::OSExchangeDataProviderWin::GetDataObjectImpl(*data.get())
       ->set_in_drag_loop(true);
 
   DWORD effect;
@@ -53,7 +53,8 @@
                             ui::DragDropTypes::DRAG_EVENT_SOURCE_COUNT);
 
   HRESULT result = DoDragDrop(
-      ui::OSExchangeDataProviderWin::GetIDataObject(data), drag_source_.Get(),
+      ui::OSExchangeDataProviderWin::GetIDataObject(*data.get()),
+      drag_source_.Get(),
       ui::DragDropTypes::DragOperationToDropEffect(operation), &effect);
   drag_source_copy->set_data(nullptr);
 
diff --git a/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h b/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h
index 25845e08..70e5950f 100644
--- a/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h
+++ b/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h
@@ -34,7 +34,7 @@
   ~DesktopDragDropClientWin() override;
 
   // Overridden from aura::client::DragDropClient:
-  int StartDragAndDrop(const ui::OSExchangeData& data,
+  int StartDragAndDrop(std::unique_ptr<ui::OSExchangeData> data,
                        aura::Window* root_window,
                        aura::Window* source_window,
                        const gfx::Point& screen_location,
diff --git a/ui/views/widget/desktop_aura/desktop_drop_target_win.cc b/ui/views/widget/desktop_aura/desktop_drop_target_win.cc
index 898eacde..052d82cb 100644
--- a/ui/views/widget/desktop_aura/desktop_drop_target_win.cc
+++ b/ui/views/widget/desktop_aura/desktop_drop_target_win.cc
@@ -98,7 +98,7 @@
   DragDropDelegate* delegate;
   Translate(data_object, key_state, position, effect, &data, &event, &delegate);
   if (delegate) {
-    drag_operation = delegate->OnPerformDrop(*event);
+    drag_operation = delegate->OnPerformDrop(*event, std::move(data));
     DragDropClient* client = aura::client::GetDragDropClient(root_window_);
     if (client && !client->IsDragDropInProgress() &&
         drag_operation != ui::DragDropTypes::DRAG_NONE) {
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
index 8556940..626aa32f 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
@@ -888,11 +888,12 @@
 
 void DesktopNativeWidgetAura::RunShellDrag(
     View* view,
-    const ui::OSExchangeData& data,
+    std::unique_ptr<ui::OSExchangeData> data,
     const gfx::Point& location,
     int operation,
     ui::DragDropTypes::DragEventSource source) {
-  views::RunShellDrag(content_window_, data, location, operation, source);
+  views::RunShellDrag(content_window_, std::move(data), location, operation,
+                      source);
 }
 
 void DesktopNativeWidgetAura::SchedulePaintInRect(const gfx::Rect& rect) {
@@ -1196,7 +1197,9 @@
   drop_helper_->OnDragExit();
 }
 
-int DesktopNativeWidgetAura::OnPerformDrop(const ui::DropTargetEvent& event) {
+int DesktopNativeWidgetAura::OnPerformDrop(
+    const ui::DropTargetEvent& event,
+    std::unique_ptr<ui::OSExchangeData> data) {
   DCHECK(drop_helper_.get() != nullptr);
   if (ShouldActivate())
     Activate();
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
index 5d45002..478ed52 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
@@ -168,7 +168,7 @@
   void SetAspectRatio(const gfx::SizeF& aspect_ratio) override;
   void FlashFrame(bool flash_frame) override;
   void RunShellDrag(View* view,
-                    const ui::OSExchangeData& data,
+                    std::unique_ptr<ui::OSExchangeData> data,
                     const gfx::Point& location,
                     int operation,
                     ui::DragDropTypes::DragEventSource source) override;
@@ -238,7 +238,8 @@
   void OnDragEntered(const ui::DropTargetEvent& event) override;
   int OnDragUpdated(const ui::DropTargetEvent& event) override;
   void OnDragExited() override;
-  int OnPerformDrop(const ui::DropTargetEvent& event) override;
+  int OnPerformDrop(const ui::DropTargetEvent& event,
+                    std::unique_ptr<ui::OSExchangeData> data) override;
 
   // Overridden from aura::WindowTreeHostObserver:
   void OnHostCloseRequested(aura::WindowTreeHost* host) override;
diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc
index cab2854..274aece 100644
--- a/ui/views/widget/native_widget_aura.cc
+++ b/ui/views/widget/native_widget_aura.cc
@@ -689,12 +689,12 @@
 }
 
 void NativeWidgetAura::RunShellDrag(View* view,
-                                    const ui::OSExchangeData& data,
+                                    std::unique_ptr<ui::OSExchangeData> data,
                                     const gfx::Point& location,
                                     int operation,
                                     ui::DragDropTypes::DragEventSource source) {
   if (window_)
-    views::RunShellDrag(window_, data, location, operation, source);
+    views::RunShellDrag(window_, std::move(data), location, operation, source);
 }
 
 void NativeWidgetAura::SchedulePaintInRect(const gfx::Rect& rect) {
@@ -1032,7 +1032,8 @@
   drop_helper_->OnDragExit();
 }
 
-int NativeWidgetAura::OnPerformDrop(const ui::DropTargetEvent& event) {
+int NativeWidgetAura::OnPerformDrop(const ui::DropTargetEvent& event,
+                                    std::unique_ptr<ui::OSExchangeData> data) {
   DCHECK(drop_helper_.get() != nullptr);
   return drop_helper_->OnDrop(event.data(), event.location(),
       last_drop_operation_);
diff --git a/ui/views/widget/native_widget_aura.h b/ui/views/widget/native_widget_aura.h
index 686840f..e1e0bad1 100644
--- a/ui/views/widget/native_widget_aura.h
+++ b/ui/views/widget/native_widget_aura.h
@@ -133,7 +133,7 @@
   void SetAspectRatio(const gfx::SizeF& aspect_ratio) override;
   void FlashFrame(bool flash_frame) override;
   void RunShellDrag(View* view,
-                    const ui::OSExchangeData& data,
+                    std::unique_ptr<ui::OSExchangeData> data,
                     const gfx::Point& location,
                     int operation,
                     ui::DragDropTypes::DragEventSource source) override;
@@ -209,7 +209,8 @@
   void OnDragEntered(const ui::DropTargetEvent& event) override;
   int OnDragUpdated(const ui::DropTargetEvent& event) override;
   void OnDragExited() override;
-  int OnPerformDrop(const ui::DropTargetEvent& event) override;
+  int OnPerformDrop(const ui::DropTargetEvent& event,
+                    std::unique_ptr<ui::OSExchangeData> data) override;
 
  protected:
   ~NativeWidgetAura() override;
diff --git a/ui/views/widget/native_widget_mac.h b/ui/views/widget/native_widget_mac.h
index c03b37c..995b76e4 100644
--- a/ui/views/widget/native_widget_mac.h
+++ b/ui/views/widget/native_widget_mac.h
@@ -150,7 +150,7 @@
   void SetAspectRatio(const gfx::SizeF& aspect_ratio) override;
   void FlashFrame(bool flash_frame) override;
   void RunShellDrag(View* view,
-                    const ui::OSExchangeData& data,
+                    std::unique_ptr<ui::OSExchangeData> data,
                     const gfx::Point& location,
                     int operation,
                     ui::DragDropTypes::DragEventSource source) override;
diff --git a/ui/views/widget/native_widget_mac.mm b/ui/views/widget/native_widget_mac.mm
index 4a441b8..0c3fbdbf 100644
--- a/ui/views/widget/native_widget_mac.mm
+++ b/ui/views/widget/native_widget_mac.mm
@@ -556,12 +556,12 @@
 }
 
 void NativeWidgetMac::RunShellDrag(View* view,
-                                   const ui::OSExchangeData& data,
+                                   std::unique_ptr<ui::OSExchangeData> data,
                                    const gfx::Point& location,
                                    int operation,
                                    ui::DragDropTypes::DragEventSource source) {
-  ns_window_host_->drag_drop_client()->StartDragAndDrop(view, data, operation,
-                                                        source);
+  ns_window_host_->drag_drop_client()->StartDragAndDrop(view, std::move(data),
+                                                        operation, source);
 }
 
 void NativeWidgetMac::SchedulePaintInRect(const gfx::Rect& rect) {
diff --git a/ui/views/widget/native_widget_private.h b/ui/views/widget/native_widget_private.h
index 03a5e9b..b4f8732a 100644
--- a/ui/views/widget/native_widget_private.h
+++ b/ui/views/widget/native_widget_private.h
@@ -204,7 +204,7 @@
   virtual void SetAspectRatio(const gfx::SizeF& aspect_ratio) = 0;
   virtual void FlashFrame(bool flash) = 0;
   virtual void RunShellDrag(View* view,
-                            const ui::OSExchangeData& data,
+                            std::unique_ptr<ui::OSExchangeData> data,
                             const gfx::Point& location,
                             int operation,
                             ui::DragDropTypes::DragEventSource source) = 0;
diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc
index aa80b44..8bb11af 100644
--- a/ui/views/widget/widget.cc
+++ b/ui/views/widget/widget.cc
@@ -807,7 +807,7 @@
 }
 
 void Widget::RunShellDrag(View* view,
-                          const ui::OSExchangeData& data,
+                          std::unique_ptr<ui::OSExchangeData> data,
                           const gfx::Point& location,
                           int operation,
                           ui::DragDropTypes::DragEventSource source) {
@@ -818,7 +818,8 @@
     observer.OnWidgetDragWillStart(this);
 
   WidgetDeletionObserver widget_deletion_observer(this);
-  native_widget_->RunShellDrag(view, data, location, operation, source);
+  native_widget_->RunShellDrag(view, std::move(data), location, operation,
+                               source);
 
   // The widget may be destroyed during the drag operation.
   if (!widget_deletion_observer.IsWidgetAlive())
diff --git a/ui/views/widget/widget.h b/ui/views/widget/widget.h
index 5c275ae..e33b6cd 100644
--- a/ui/views/widget/widget.h
+++ b/ui/views/widget/widget.h
@@ -626,7 +626,7 @@
   // OnDragDone() is called on it. |location| is in the widget's coordinate
   // system.
   void RunShellDrag(View* view,
-                    const ui::OSExchangeData& data,
+                    std::unique_ptr<ui::OSExchangeData> data,
                     const gfx::Point& location,
                     int operation,
                     ui::DragDropTypes::DragEventSource source);