diff --git a/DEPS b/DEPS
index 826a91d..ae40dd9 100644
--- a/DEPS
+++ b/DEPS
@@ -179,7 +179,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '72b2be2e56ffc63418db01b5858ade3fae92ff39',
+  'angle_revision': '0cb09633d68c9b6d922206214b99284c21305fb0',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -187,7 +187,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '94e600d98301661502135a89db1fb0cc7caae5e9',
+  'pdfium_revision': '44d038359f4ee991e42da983a15c012c2b13b638',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -230,7 +230,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': 'c98b1ee7e410b2fb2f7dc9e2eb01804cf7c94fcb',
+  'catapult_revision': 'a5c8651cfccb3c3ee2849a92acbf2719011d59fc',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -298,7 +298,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.
-  'shaderc_revision': '9bd9f4b3ed6446fcee87ab60e254fda8e39c9882',
+  'shaderc_revision': 'f28d5287c68b526e61e4f3c4b6098e751b4b5b6d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -306,7 +306,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.
-  'quiche_revision': '13753e667da5dac41768857b2e1c6dc077917317',
+  'quiche_revision': 'b5a8b9ebfa6e9fa50120c847d22e3b703a08174a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ios_webkit
   # and whatever else without interference from each other.
@@ -862,7 +862,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '68efdcdaefe26eae9bf3c14cf9cd59e06000e71b',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '973a36942fb66975502627ad17c25012b1addce6',
       'condition': 'checkout_linux',
   },
 
@@ -1280,7 +1280,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'b78fa92a51140e60da2c3657c28efa26a7fbfda1',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '8fac64fcd1ec3895f089cdd30344a295d567cd72',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1532,7 +1532,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@1f4ca326d0db23bfe3e747bbc35f2c18adb4cffe',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@6f8624c5117eeb4fd232b4855e8a74f04f4f8469',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/WATCHLISTS b/WATCHLISTS
index 363fbfdd..7452a20 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -1532,6 +1532,12 @@
       'filepath': 'chrome/(browser|common|renderer)/safe_browsing/|'\
                   'components/safe_browsing/',
     },
+    'safety_tips': {
+      'filepath': 'chrome/browser/component_updater/safety_tips_.*'\
+                  '|chrome/browser/lookalikes/'\
+                  '|chrome/browser/resources/safety_tips'\
+                  '|chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view.*',
+    },
     'sampling_profiler': {
       'filepath': 'base/profiler/'\
                   '|chrome/common/profiler/'\
@@ -2496,7 +2502,8 @@
                      'sergeyu@chromium.org',
                      'spang+watch@chromium.org',
                      'wez@chromium.org'],
-    'page_info' : ['permissions-reviews@chromium.org'],
+    'page_info' : ['permissions-reviews@chromium.org',
+                   'jdeblasio+watch@chromium.org'],
     'page_load_metrics' : ['bmcquade+watch@chromium.org',
                            'csharrison+watch@chromium.org',
                            'loading-reviews+metrics@chromium.org',
@@ -2543,6 +2550,7 @@
                       'timvolodine@chromium.org',
                       'vakh+watch@chromium.org',
                       'xinghuilu+watch@chromium.org'],
+    'safety_tips': ['jdeblasio+watch@chromium.org'],
     'sampling_profiler': ['wittman+watch@chromium.org'],
     'screen_orientation': ['mlamouri+watch-screen-orientation@chromium.org'],
     'security': ['security-watchlist@chromium.org'],
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index 3061536..bced5247 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -89,8 +89,6 @@
 #include "content/public/common/web_preferences.h"
 #include "media/mojo/buildflags.h"
 #include "mojo/public/cpp/bindings/pending_associated_receiver.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "net/android/network_library.h"
 #include "net/http/http_util.h"
 #include "net/ssl/ssl_cert_request_info.h"
diff --git a/android_webview/browser/aw_content_browser_client.h b/android_webview/browser/aw_content_browser_client.h
index e710f90..d943ae21 100644
--- a/android_webview/browser/aw_content_browser_client.h
+++ b/android_webview/browser/aw_content_browser_client.h
@@ -15,6 +15,8 @@
 #include "base/memory/ref_counted.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/web_contents.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
 #include "storage/browser/quota/quota_settings.h"
diff --git a/android_webview/browser/aw_download_manager_delegate.cc b/android_webview/browser/aw_download_manager_delegate.cc
index 6d1b422..dae5bff 100644
--- a/android_webview/browser/aw_download_manager_delegate.cc
+++ b/android_webview/browser/aw_download_manager_delegate.cc
@@ -6,62 +6,14 @@
 
 #include "android_webview/browser/aw_content_browser_client.h"
 #include "android_webview/browser/aw_contents_client_bridge.h"
-#include "base/files/file_path.h"
-#include "base/task/post_task.h"
-#include "components/download/public/common/download_danger_type.h"
-#include "components/download/public/common/download_item.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_contents.h"
 
 namespace android_webview {
 
-namespace {
-
-void DownloadStartingOnUIThread(content::WebContents* web_contents,
-                                const GURL& url,
-                                const std::string& user_agent,
-                                const std::string& content_disposition,
-                                const std::string& mime_type,
-                                int64_t content_length) {
-  AwContentsClientBridge* client =
-      AwContentsClientBridge::FromWebContents(web_contents);
-  if (!client)
-    return;
-  client->NewDownload(url, user_agent, content_disposition, mime_type,
-                      content_length);
-}
-
-}  // namespace
-
-AwDownloadManagerDelegate::~AwDownloadManagerDelegate() {}
-
-bool AwDownloadManagerDelegate::DetermineDownloadTarget(
-    download::DownloadItem* item,
-    const content::DownloadTargetCallback& callback) {
-  // Note this cancel is independent of the URLRequest cancel in
-  // AwResourceDispatcherHostDelegate::DownloadStarting. The request
-  // could have already finished by the time DownloadStarting is called.
-  callback.Run(base::FilePath() /* Empty file path for cancel */,
-               download::DownloadItem::TARGET_DISPOSITION_OVERWRITE,
-               download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, base::FilePath(),
-               download::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED);
-  return true;
-}
-
-bool AwDownloadManagerDelegate::ShouldCompleteDownload(
-    download::DownloadItem* item,
-    base::OnceClosure complete_callback) {
-  NOTREACHED();
-  return true;
-}
-
-bool AwDownloadManagerDelegate::ShouldOpenDownload(
-    download::DownloadItem* item,
-    const content::DownloadOpenDelayedCallback& callback) {
-  NOTREACHED();
-  return true;
-}
+AwDownloadManagerDelegate::AwDownloadManagerDelegate() = default;
+AwDownloadManagerDelegate::~AwDownloadManagerDelegate() = default;
 
 bool AwDownloadManagerDelegate::InterceptDownloadIfApplicable(
     const GURL& url,
@@ -72,25 +24,24 @@
     int64_t content_length,
     bool is_transient,
     content::WebContents* web_contents) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   if (!web_contents)
-    return false;
+    return true;
+
+  AwContentsClientBridge* client =
+      AwContentsClientBridge::FromWebContents(web_contents);
+  if (!client)
+    return true;
 
   std::string aw_user_agent = web_contents->GetUserAgentOverride();
   if (aw_user_agent.empty()) {
     // use default user agent if nothing is provided
     aw_user_agent = user_agent.empty() ? GetUserAgent() : user_agent;
   }
-  base::PostTask(FROM_HERE, {content::BrowserThread::UI},
-                 base::BindOnce(&DownloadStartingOnUIThread, web_contents, url,
-                                aw_user_agent, content_disposition, mime_type,
-                                content_length));
-  return true;
-}
 
-void AwDownloadManagerDelegate::GetNextId(
-    const content::DownloadIdCallback& callback) {
-  static uint32_t next_id = download::DownloadItem::kInvalidId + 1;
-  callback.Run(next_id++);
+  client->NewDownload(url, aw_user_agent, content_disposition, mime_type,
+                      content_length);
+  return true;
 }
 
 }  // namespace android_webview
diff --git a/android_webview/browser/aw_download_manager_delegate.h b/android_webview/browser/aw_download_manager_delegate.h
index 351e733..25337e39 100644
--- a/android_webview/browser/aw_download_manager_delegate.h
+++ b/android_webview/browser/aw_download_manager_delegate.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/macros.h"
 #include "base/supports_user_data.h"
 #include "content/public/browser/download_manager_delegate.h"
 
@@ -23,17 +24,10 @@
 class AwDownloadManagerDelegate : public content::DownloadManagerDelegate,
                                   public base::SupportsUserData::Data {
  public:
+  AwDownloadManagerDelegate();
   ~AwDownloadManagerDelegate() override;
 
   // content::DownloadManagerDelegate implementation.
-  bool DetermineDownloadTarget(
-      download::DownloadItem* item,
-      const content::DownloadTargetCallback& callback) override;
-  bool ShouldCompleteDownload(download::DownloadItem* item,
-                              base::OnceClosure complete_callback) override;
-  bool ShouldOpenDownload(
-      download::DownloadItem* item,
-      const content::DownloadOpenDelayedCallback& callback) override;
   bool InterceptDownloadIfApplicable(
       const GURL& url,
       const std::string& user_agent,
@@ -43,7 +37,9 @@
       int64_t content_length,
       bool is_transient,
       content::WebContents* web_contents) override;
-  void GetNextId(const content::DownloadIdCallback& callback) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AwDownloadManagerDelegate);
 };
 
 }  // namespace android_webview
diff --git a/android_webview/browser/gfx/surfaces_instance.cc b/android_webview/browser/gfx/surfaces_instance.cc
index dd8bafd..1841ddc 100644
--- a/android_webview/browser/gfx/surfaces_instance.cc
+++ b/android_webview/browser/gfx/surfaces_instance.cc
@@ -123,7 +123,9 @@
       shared_context_state_ = base::MakeRefCounted<gpu::SharedContextState>(
           share_group_, gl_surface_, std::move(gl_context),
           false /* use_virtualized_gl_contexts */,
-          base::BindOnce(&OnContextLost), vulkan_context_provider.get());
+          base::BindOnce(&OnContextLost),
+          GpuServiceWebView::GetInstance()->gpu_preferences().gr_context_type,
+          vulkan_context_provider.get());
       if (!enable_vulkan) {
         auto feature_info = base::MakeRefCounted<gpu::gles2::FeatureInfo>(
             workarounds, GpuServiceWebView::GetInstance()->gpu_feature_info());
diff --git a/ash/accelerators/accelerator_confirmation_dialog.cc b/ash/accelerators/accelerator_confirmation_dialog.cc
index 55c00b2e..cd0d2cf 100644
--- a/ash/accelerators/accelerator_confirmation_dialog.cc
+++ b/ash/accelerators/accelerator_confirmation_dialog.cc
@@ -25,9 +25,11 @@
 AcceleratorConfirmationDialog::AcceleratorConfirmationDialog(
     int window_title_text_id,
     int dialog_text_id,
-    base::OnceClosure on_accept_callback)
+    base::OnceClosure on_accept_callback,
+    base::OnceClosure on_cancel_callback)
     : window_title_(l10n_util::GetStringUTF16(window_title_text_id)),
-      on_accept_callback_(std::move(on_accept_callback)) {
+      on_accept_callback_(std::move(on_accept_callback)),
+      on_cancel_callback_(std::move(on_cancel_callback)) {
   DialogDelegate::set_button_label(
       ui::DIALOG_BUTTON_OK, l10n_util::GetStringUTF16(IDS_ASH_CONTINUE_BUTTON));
 
@@ -64,6 +66,11 @@
   return true;
 }
 
+bool AcceleratorConfirmationDialog::Cancel() {
+  std::move(on_cancel_callback_).Run();
+  return true;
+}
+
 ui::ModalType AcceleratorConfirmationDialog::GetModalType() const {
   return ui::MODAL_TYPE_SYSTEM;
 }
diff --git a/ash/accelerators/accelerator_confirmation_dialog.h b/ash/accelerators/accelerator_confirmation_dialog.h
index cd9afbf..42641d55 100644
--- a/ash/accelerators/accelerator_confirmation_dialog.h
+++ b/ash/accelerators/accelerator_confirmation_dialog.h
@@ -19,11 +19,13 @@
  public:
   AcceleratorConfirmationDialog(int window_title_text_id,
                                 int dialog_text_id,
-                                base::OnceClosure on_accept_callback);
+                                base::OnceClosure on_accept_callback,
+                                base::OnceClosure on_cancel_callback);
   ~AcceleratorConfirmationDialog() override;
 
   // views::DialogDelegateView:
   bool Accept() override;
+  bool Cancel() override;
   ui::ModalType GetModalType() const override;
   base::string16 GetWindowTitle() const override;
 
@@ -32,6 +34,7 @@
  private:
   const base::string16 window_title_;
   base::OnceClosure on_accept_callback_;
+  base::OnceClosure on_cancel_callback_;
 
   base::WeakPtrFactory<AcceleratorConfirmationDialog> weak_ptr_factory_{this};
 
diff --git a/ash/accelerators/accelerator_controller_impl.cc b/ash/accelerators/accelerator_controller_impl.cc
index 4a5953710..e5e4084 100644
--- a/ash/accelerators/accelerator_controller_impl.cc
+++ b/ash/accelerators/accelerator_controller_impl.cc
@@ -136,6 +136,20 @@
 constexpr base::TimeDelta kVolumeAdjustTimeout =
     base::TimeDelta::FromSeconds(2);
 
+// These values are written to logs.  New enum values can be added, but existing
+// enums must never be renumbered or deleted and reused.
+// Records the result of triggering the rotation accelerator.
+enum class RotationAcceleratorAction {
+  kCancelledDialog = 0,
+  kAcceptedDialog = 1,
+  kAlreadyAcceptedDialog = 2,
+  kMaxValue = kAlreadyAcceptedDialog,
+};
+
+void RecordRotationAcceleratorAction(const RotationAcceleratorAction& action) {
+  UMA_HISTOGRAM_ENUMERATION("Ash.Accelerators.Rotation.Usage", action);
+}
+
 void RecordTabletVolumeAdjustTypeHistogram(TabletModeVolumeAdjustType type) {
   UMA_HISTOGRAM_ENUMERATION(kTabletCountOfVolumeAdjustType, type);
 }
@@ -529,6 +543,18 @@
       display::Display::RotationSource::USER);
 }
 
+void OnRotationDialogAccepted() {
+  RecordRotationAcceleratorAction(RotationAcceleratorAction::kAcceptedDialog);
+  RotateScreen();
+  Shell::Get()
+      ->accessibility_controller()
+      ->SetDisplayRotationAcceleratorDialogBeenAccepted();
+}
+
+void OnRotationDialogCancelled() {
+  RecordRotationAcceleratorAction(RotationAcceleratorAction::kCancelledDialog);
+}
+
 // Rotates the screen.
 void HandleRotateScreen() {
   if (Shell::Get()->display_manager()->IsInUnifiedMode())
@@ -543,13 +569,11 @@
   if (!dialog_ever_accepted) {
     Shell::Get()->accelerator_controller()->MaybeShowConfirmationDialog(
         IDS_ASH_ROTATE_SCREEN_TITLE, IDS_ASH_ROTATE_SCREEN_BODY,
-        base::BindOnce([]() {
-          RotateScreen();
-          Shell::Get()
-              ->accessibility_controller()
-              ->SetDisplayRotationAcceleratorDialogBeenAccepted();
-        }));
+        base::BindOnce(&OnRotationDialogAccepted),
+        base::BindOnce(&OnRotationDialogCancelled));
   } else {
+    RecordRotationAcceleratorAction(
+        RotationAcceleratorAction::kAlreadyAcceptedDialog);
     RotateScreen();
   }
 }
@@ -1074,7 +1098,8 @@
               ->accessibility_controller()
               ->SetDockedMagnifierAcceleratorDialogAccepted();
           SetDockedMagnifierEnabled(true);
-        }));
+        }),
+        base::DoNothing());
   } else {
     SetDockedMagnifierEnabled(!current_enabled);
   }
@@ -1139,7 +1164,8 @@
               ->accessibility_controller()
               ->SetHighContrastAcceleratorDialogAccepted();
           SetHighContrastEnabled(true);
-        }));
+        }),
+        base::DoNothing());
   } else {
     SetHighContrastEnabled(!current_enabled);
   }
@@ -1163,7 +1189,8 @@
               ->accessibility_controller()
               ->SetScreenMagnifierAcceleratorDialogAccepted();
           SetFullscreenMagnifierEnabled(true);
-        }));
+        }),
+        base::DoNothing());
   } else {
     SetFullscreenMagnifierEnabled(!current_enabled);
   }
@@ -2137,13 +2164,15 @@
 void AcceleratorControllerImpl::MaybeShowConfirmationDialog(
     int window_title_text_id,
     int dialog_text_id,
-    base::OnceClosure on_accept_callback) {
+    base::OnceClosure on_accept_callback,
+    base::OnceClosure on_cancel_callback) {
   // An active dialog exists already.
   if (confirmation_dialog_)
     return;
 
   auto* dialog = new AcceleratorConfirmationDialog(
-      window_title_text_id, dialog_text_id, std::move(on_accept_callback));
+      window_title_text_id, dialog_text_id, std::move(on_accept_callback),
+      std::move(on_cancel_callback));
   confirmation_dialog_ = dialog->GetWeakPtr();
 }
 
diff --git a/ash/accelerators/accelerator_controller_impl.h b/ash/accelerators/accelerator_controller_impl.h
index d2c36991..6c32b835 100644
--- a/ash/accelerators/accelerator_controller_impl.h
+++ b/ash/accelerators/accelerator_controller_impl.h
@@ -195,11 +195,12 @@
   // users would be aware of the shortcut they have just enabled, and to prevent
   // users from accidentally triggering the feature. The dialog is currently
   // shown when enabling the following features: high contrast, full screen
-  // magnifier and docked magnifier. The shown dialog is stored as a weak
-  // pointer in the variable |confirmation_dialog_| below.
+  // magnifier, docked magnifier and screen rotation. The shown dialog is stored
+  // as a weak pointer in the variable |confirmation_dialog_| below.
   void MaybeShowConfirmationDialog(int window_title_text_id,
                                    int dialog_text_id,
-                                   base::OnceClosure on_accept_callback);
+                                   base::OnceClosure on_accept_callback,
+                                   base::OnceClosure on_cancel_callback);
 
   // Read the side volume button location info from local file under
   // kSideVolumeButtonLocationFilePath, parse and write it into
diff --git a/ash/accessibility/accessibility_controller_impl.cc b/ash/accessibility/accessibility_controller_impl.cc
index ca5b347..81eebe36 100644
--- a/ash/accessibility/accessibility_controller_impl.cc
+++ b/ash/accessibility/accessibility_controller_impl.cc
@@ -95,7 +95,7 @@
     prefs::kScreenMagnifierAcceleratorDialogHasBeenAccepted,
     prefs::kDockedMagnifierAcceleratorDialogHasBeenAccepted,
     prefs::kDictationAcceleratorDialogHasBeenAccepted,
-    prefs::kDisplayRotationAcceleratorDialogHasBeenAccepted,
+    prefs::kDisplayRotationAcceleratorDialogHasBeenAccepted2,
 };
 
 // Returns true if |pref_service| is the one used for the signin screen.
@@ -266,93 +266,121 @@
 
 // static
 void AccessibilityControllerImpl::RegisterProfilePrefs(
-    PrefRegistrySimple* registry,
-    bool for_test) {
-  if (for_test) {
-    // In tests there is no remote pref service. Make ash own the prefs.
-    registry->RegisterBooleanPref(prefs::kAccessibilityAutoclickEnabled, false);
-    registry->RegisterIntegerPref(
-        prefs::kAccessibilityAutoclickDelayMs,
-        static_cast<int>(
-            AutoclickController::GetDefaultAutoclickDelay().InMilliseconds()));
-    registry->RegisterIntegerPref(prefs::kAccessibilityAutoclickEventType,
-                                  static_cast<int>(kDefaultAutoclickEventType));
-    registry->RegisterBooleanPref(
-        prefs::kAccessibilityAutoclickRevertToLeftClick, true);
-    registry->RegisterBooleanPref(
-        prefs::kAccessibilityAutoclickStabilizePosition, false);
-    registry->RegisterIntegerPref(
-        prefs::kAccessibilityAutoclickMovementThreshold,
-        kDefaultAutoclickMovementThreshold);
-    registry->RegisterIntegerPref(
-        prefs::kAccessibilityAutoclickMenuPosition,
-        static_cast<int>(kDefaultAutoclickMenuPosition));
-    registry->RegisterBooleanPref(prefs::kAccessibilityCaretHighlightEnabled,
-                                  false);
-    registry->RegisterBooleanPref(prefs::kAccessibilityCursorHighlightEnabled,
-                                  false);
-    registry->RegisterBooleanPref(prefs::kAccessibilityDictationEnabled, false);
-    registry->RegisterBooleanPref(prefs::kAccessibilityFocusHighlightEnabled,
-                                  false);
-    registry->RegisterBooleanPref(prefs::kAccessibilityHighContrastEnabled,
-                                  false);
-    registry->RegisterBooleanPref(prefs::kAccessibilityLargeCursorEnabled,
-                                  false);
-    registry->RegisterIntegerPref(prefs::kAccessibilityLargeCursorDipSize,
-                                  kDefaultLargeCursorSize);
-    registry->RegisterBooleanPref(prefs::kAccessibilityMonoAudioEnabled, false);
-    registry->RegisterBooleanPref(prefs::kAccessibilityScreenMagnifierEnabled,
-                                  false);
-    registry->RegisterDoublePref(prefs::kAccessibilityScreenMagnifierScale,
-                                 1.0);
-    registry->RegisterBooleanPref(prefs::kAccessibilitySpokenFeedbackEnabled,
-                                  false);
-    registry->RegisterBooleanPref(prefs::kAccessibilitySelectToSpeakEnabled,
-                                  false);
-    registry->RegisterBooleanPref(prefs::kAccessibilityStickyKeysEnabled,
-                                  false);
-    registry->RegisterBooleanPref(prefs::kAccessibilitySwitchAccessEnabled,
-                                  false);
-    registry->RegisterListPref(prefs::kAccessibilitySwitchAccessSelectKeyCodes,
-                               base::Value(std::vector<base::Value>()));
-    registry->RegisterIntegerPref(
-        prefs::kAccessibilitySwitchAccessSelectSetting,
-        kSwitchAccessAssignmentNone);
-    registry->RegisterListPref(prefs::kAccessibilitySwitchAccessNextKeyCodes,
-                               base::Value(std::vector<base::Value>()));
-    registry->RegisterIntegerPref(prefs::kAccessibilitySwitchAccessNextSetting,
-                                  kSwitchAccessAssignmentNone);
-    registry->RegisterListPref(
-        prefs::kAccessibilitySwitchAccessPreviousKeyCodes,
-        base::Value(std::vector<base::Value>()));
-    registry->RegisterIntegerPref(
-        prefs::kAccessibilitySwitchAccessPreviousSetting,
-        kSwitchAccessAssignmentNone);
-    registry->RegisterBooleanPref(
-        prefs::kAccessibilitySwitchAccessAutoScanEnabled, false);
-    registry->RegisterIntegerPref(
-        prefs::kAccessibilitySwitchAccessAutoScanSpeedMs,
-        kDefaultSwitchAccessAutoScanSpeed.InMilliseconds());
-    registry->RegisterIntegerPref(
-        prefs::kAccessibilitySwitchAccessAutoScanKeyboardSpeedMs,
-        kDefaultSwitchAccessAutoScanSpeed.InMilliseconds());
-    registry->RegisterBooleanPref(prefs::kAccessibilityVirtualKeyboardEnabled,
-                                  false);
-    registry->RegisterBooleanPref(
-        prefs::kHighContrastAcceleratorDialogHasBeenAccepted, false);
-    registry->RegisterBooleanPref(
-        prefs::kScreenMagnifierAcceleratorDialogHasBeenAccepted, false);
-    registry->RegisterBooleanPref(
-        prefs::kDockedMagnifierAcceleratorDialogHasBeenAccepted, false);
-    registry->RegisterBooleanPref(
-        prefs::kDictationAcceleratorDialogHasBeenAccepted, false);
-    registry->RegisterBooleanPref(
-        prefs::kDisplayRotationAcceleratorDialogHasBeenAccepted, false);
-    return;
-  }
+    PrefRegistrySimple* registry) {
+  registry->RegisterBooleanPref(
+      prefs::kAccessibilityAutoclickEnabled, false,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterIntegerPref(
+      prefs::kAccessibilityAutoclickDelayMs, kDefaultAutoclickDelayMs,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterIntegerPref(
+      prefs::kAccessibilityAutoclickEventType,
+      static_cast<int>(kDefaultAutoclickEventType),
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterBooleanPref(
+      prefs::kAccessibilityAutoclickRevertToLeftClick, true,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterBooleanPref(
+      prefs::kAccessibilityAutoclickStabilizePosition, false,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterIntegerPref(
+      prefs::kAccessibilityAutoclickMovementThreshold,
+      kDefaultAutoclickMovementThreshold,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterIntegerPref(
+      prefs::kAccessibilityAutoclickMenuPosition,
+      static_cast<int>(kDefaultAutoclickMenuPosition),
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterBooleanPref(
+      prefs::kAccessibilityCaretHighlightEnabled, false,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterBooleanPref(
+      prefs::kAccessibilityCursorHighlightEnabled, false,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterBooleanPref(
+      prefs::kAccessibilityDictationEnabled, false,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterBooleanPref(
+      prefs::kAccessibilityFocusHighlightEnabled, false,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterBooleanPref(
+      prefs::kAccessibilityHighContrastEnabled, false,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterBooleanPref(
+      prefs::kAccessibilityLargeCursorEnabled, false,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterIntegerPref(prefs::kAccessibilityLargeCursorDipSize,
+                                kDefaultLargeCursorSize);
+  registry->RegisterBooleanPref(
+      prefs::kAccessibilityMonoAudioEnabled, false,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterBooleanPref(
+      prefs::kAccessibilityScreenMagnifierCenterFocus, true,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterBooleanPref(
+      prefs::kAccessibilityScreenMagnifierEnabled, false,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterDoublePref(prefs::kAccessibilityScreenMagnifierScale,
+                               std::numeric_limits<double>::min());
+  registry->RegisterBooleanPref(prefs::kAccessibilitySpokenFeedbackEnabled,
+                                false);
+  registry->RegisterBooleanPref(
+      prefs::kAccessibilitySelectToSpeakEnabled, false,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterBooleanPref(
+      prefs::kAccessibilityStickyKeysEnabled, false,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterBooleanPref(
+      prefs::kAccessibilitySwitchAccessEnabled, false,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterListPref(prefs::kAccessibilitySwitchAccessSelectKeyCodes,
+                             base::Value(std::vector<base::Value>()),
+                             user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterIntegerPref(
+      prefs::kAccessibilitySwitchAccessSelectSetting,
+      kSwitchAccessAssignmentNone,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterListPref(prefs::kAccessibilitySwitchAccessNextKeyCodes,
+                             base::Value(std::vector<base::Value>()),
+                             user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterIntegerPref(
+      prefs::kAccessibilitySwitchAccessNextSetting, kSwitchAccessAssignmentNone,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterListPref(prefs::kAccessibilitySwitchAccessPreviousKeyCodes,
+                             base::Value(std::vector<base::Value>()),
+                             user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterIntegerPref(
+      prefs::kAccessibilitySwitchAccessPreviousSetting,
+      kSwitchAccessAssignmentNone,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterBooleanPref(
+      prefs::kAccessibilitySwitchAccessAutoScanEnabled, false,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterIntegerPref(
+      prefs::kAccessibilitySwitchAccessAutoScanSpeedMs,
+      kDefaultSwitchAccessAutoScanSpeed.InMilliseconds(),
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterIntegerPref(
+      prefs::kAccessibilitySwitchAccessAutoScanKeyboardSpeedMs,
+      kDefaultSwitchAccessAutoScanSpeed.InMilliseconds(),
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterBooleanPref(
+      prefs::kAccessibilityVirtualKeyboardEnabled, false,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterBooleanPref(
+      prefs::kHighContrastAcceleratorDialogHasBeenAccepted, false);
+  registry->RegisterBooleanPref(
+      prefs::kScreenMagnifierAcceleratorDialogHasBeenAccepted, false);
+  registry->RegisterBooleanPref(
+      prefs::kDockedMagnifierAcceleratorDialogHasBeenAccepted, false);
+  registry->RegisterBooleanPref(
+      prefs::kDictationAcceleratorDialogHasBeenAccepted, false);
+  registry->RegisterBooleanPref(
+      prefs::kDisplayRotationAcceleratorDialogHasBeenAccepted2, false);
 
-  // In production the prefs are owned by chrome.
-  // TODO(jamescook): Move ownership to ash.
+  registry->RegisterBooleanPref(
+      prefs::kShouldAlwaysShowAccessibilityMenu, false,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
 }
 
 void AccessibilityControllerImpl::Shutdown() {
@@ -407,7 +435,7 @@
     HasDisplayRotationAcceleratorDialogBeenAccepted() const {
   return active_user_prefs_ &&
          active_user_prefs_->GetBoolean(
-             prefs::kDisplayRotationAcceleratorDialogHasBeenAccepted);
+             prefs::kDisplayRotationAcceleratorDialogHasBeenAccepted2);
 }
 
 void AccessibilityControllerImpl::
@@ -415,7 +443,7 @@
   if (!active_user_prefs_)
     return;
   active_user_prefs_->SetBoolean(
-      prefs::kDisplayRotationAcceleratorDialogHasBeenAccepted, true);
+      prefs::kDisplayRotationAcceleratorDialogHasBeenAccepted2, true);
   active_user_prefs_->CommitPendingWrite();
 }
 
@@ -549,7 +577,8 @@
           controller->SetDictationAcceleratorDialogAccepted();
           // If they accept, try again to set dictation_enabled to true
           controller->SetDictationEnabled(true);
-        }));
+        }),
+        base::DoNothing());
     return;
   }
   active_user_prefs_->SetBoolean(prefs::kAccessibilityDictationEnabled,
diff --git a/ash/accessibility/accessibility_controller_impl.h b/ash/accessibility/accessibility_controller_impl.h
index 6ea690d..d20b4e8 100644
--- a/ash/accessibility/accessibility_controller_impl.h
+++ b/ash/accessibility/accessibility_controller_impl.h
@@ -54,7 +54,7 @@
   ~AccessibilityControllerImpl() override;
 
   // See Shell::RegisterProfilePrefs().
-  static void RegisterProfilePrefs(PrefRegistrySimple* registry, bool for_test);
+  static void RegisterProfilePrefs(PrefRegistrySimple* registry);
 
   void Shutdown();
 
diff --git a/ash/ash_prefs.cc b/ash/ash_prefs.cc
index 22bf7c1c..9d2f14c 100644
--- a/ash/ash_prefs.cc
+++ b/ash/ash_prefs.cc
@@ -32,12 +32,12 @@
 
 // Registers prefs whose default values are same in user and signin prefs.
 void RegisterProfilePrefs(PrefRegistrySimple* registry, bool for_test) {
-  AccessibilityControllerImpl::RegisterProfilePrefs(registry, for_test);
+  AccessibilityControllerImpl::RegisterProfilePrefs(registry);
   AppListControllerImpl::RegisterProfilePrefs(registry);
   AssistantController::RegisterProfilePrefs(registry);
   BluetoothPowerController::RegisterProfilePrefs(registry);
   CapsLockNotificationController::RegisterProfilePrefs(registry, for_test);
-  DockedMagnifierControllerImpl::RegisterProfilePrefs(registry, for_test);
+  DockedMagnifierControllerImpl::RegisterProfilePrefs(registry);
   LoginScreenController::RegisterProfilePrefs(registry, for_test);
   LogoutButtonTray::RegisterProfilePrefs(registry);
   MediaControllerImpl::RegisterProfilePrefs(registry);
@@ -64,12 +64,12 @@
 
 void RegisterSigninProfilePrefs(PrefRegistrySimple* registry, bool for_test) {
   RegisterProfilePrefs(registry, for_test);
-  PowerPrefs::RegisterSigninProfilePrefs(registry, for_test);
+  PowerPrefs::RegisterSigninProfilePrefs(registry);
 }
 
 void RegisterUserProfilePrefs(PrefRegistrySimple* registry, bool for_test) {
   RegisterProfilePrefs(registry, for_test);
-  PowerPrefs::RegisterUserProfilePrefs(registry, for_test);
+  PowerPrefs::RegisterUserProfilePrefs(registry);
 }
 
 }  // namespace ash
diff --git a/ash/display/display_prefs.cc b/ash/display/display_prefs.cc
index 89f2cb1..17ed16d 100644
--- a/ash/display/display_prefs.cc
+++ b/ash/display/display_prefs.cc
@@ -761,22 +761,14 @@
 
 // static
 void DisplayPrefs::RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
-  registry->RegisterDictionaryPref(prefs::kSecondaryDisplays,
-                                   PrefRegistry::PUBLIC);
-  registry->RegisterDictionaryPref(prefs::kDisplayProperties,
-                                   PrefRegistry::PUBLIC);
-  registry->RegisterStringPref(prefs::kDisplayPowerState, kDisplayPowerAllOn,
-                               PrefRegistry::PUBLIC);
-  registry->RegisterDictionaryPref(prefs::kDisplayRotationLock,
-                                   PrefRegistry::PUBLIC);
-  registry->RegisterDictionaryPref(prefs::kDisplayTouchAssociations,
-                                   PrefRegistry::PUBLIC);
-  registry->RegisterDictionaryPref(prefs::kDisplayTouchPortAssociations,
-                                   PrefRegistry::PUBLIC);
-  registry->RegisterListPref(prefs::kExternalDisplayMirrorInfo,
-                             PrefRegistry::PUBLIC);
-  registry->RegisterDictionaryPref(prefs::kDisplayMixedMirrorModeParams,
-                                   PrefRegistry::PUBLIC);
+  registry->RegisterDictionaryPref(prefs::kSecondaryDisplays);
+  registry->RegisterDictionaryPref(prefs::kDisplayProperties);
+  registry->RegisterStringPref(prefs::kDisplayPowerState, kDisplayPowerAllOn);
+  registry->RegisterDictionaryPref(prefs::kDisplayRotationLock);
+  registry->RegisterDictionaryPref(prefs::kDisplayTouchAssociations);
+  registry->RegisterDictionaryPref(prefs::kDisplayTouchPortAssociations);
+  registry->RegisterListPref(prefs::kExternalDisplayMirrorInfo);
+  registry->RegisterDictionaryPref(prefs::kDisplayMixedMirrorModeParams);
 }
 
 DisplayPrefs::DisplayPrefs(PrefService* local_state)
diff --git a/ash/magnifier/docked_magnifier_controller_impl.cc b/ash/magnifier/docked_magnifier_controller_impl.cc
index 68d0111..a0da631 100644
--- a/ash/magnifier/docked_magnifier_controller_impl.cc
+++ b/ash/magnifier/docked_magnifier_controller_impl.cc
@@ -151,17 +151,10 @@
 
 // static
 void DockedMagnifierControllerImpl::RegisterProfilePrefs(
-    PrefRegistrySimple* registry,
-    bool for_test) {
-  if (for_test) {
-    // In tests there is no remote pref service. Make ash own the prefs.
-    // TODO(xiyuan): move ownership to ash.
-    registry->RegisterBooleanPref(prefs::kDockedMagnifierEnabled, false,
-                                  PrefRegistry::PUBLIC);
-  }
-
+    PrefRegistrySimple* registry) {
+  registry->RegisterBooleanPref(prefs::kDockedMagnifierEnabled, false);
   registry->RegisterDoublePref(prefs::kDockedMagnifierScale,
-                               kDefaultMagnifierScale, PrefRegistry::PUBLIC);
+                               kDefaultMagnifierScale);
 }
 
 bool DockedMagnifierControllerImpl::GetEnabled() const {
diff --git a/ash/magnifier/docked_magnifier_controller_impl.h b/ash/magnifier/docked_magnifier_controller_impl.h
index cd5a78e..ccf05a5 100644
--- a/ash/magnifier/docked_magnifier_controller_impl.h
+++ b/ash/magnifier/docked_magnifier_controller_impl.h
@@ -62,7 +62,7 @@
   // the magnifier viewport.
   static constexpr int kScreenHeightDivisor = 3;
 
-  static void RegisterProfilePrefs(PrefRegistrySimple* registry, bool for_test);
+  static void RegisterProfilePrefs(PrefRegistrySimple* registry);
 
   // Get the Docked Magnifier settings for the current active user prefs.
   bool GetEnabled() const;
diff --git a/ash/media/media_controller_impl.cc b/ash/media/media_controller_impl.cc
index edaaec0..b2352c04 100644
--- a/ash/media/media_controller_impl.cc
+++ b/ash/media/media_controller_impl.cc
@@ -46,8 +46,7 @@
 
 // static
 void MediaControllerImpl::RegisterProfilePrefs(PrefRegistrySimple* registry) {
-  registry->RegisterBooleanPref(prefs::kLockScreenMediaControlsEnabled, true,
-                                PrefRegistry::PUBLIC);
+  registry->RegisterBooleanPref(prefs::kLockScreenMediaControlsEnabled, true);
 }
 
 bool MediaControllerImpl::AreLockScreenMediaKeysEnabled() const {
diff --git a/ash/public/cpp/ash_pref_names.cc b/ash/public/cpp/ash_pref_names.cc
index 6818f39..c9b4443 100644
--- a/ash/public/cpp/ash_pref_names.cc
+++ b/ash/public/cpp/ash_pref_names.cc
@@ -144,8 +144,9 @@
     "settings.a11y.dictation_accelerator_dialog_has_been_accepted";
 // A boolean pref which indicates whether the display rotation confirmation
 // dialog has ever been shown.
-const char kDisplayRotationAcceleratorDialogHasBeenAccepted[] =
-    "settings.a11y.display_rotation_accelerator_dialog_has_been_accepted";
+// Renamed 10/2019 to force reset the pref to false.
+const char kDisplayRotationAcceleratorDialogHasBeenAccepted2[] =
+    "settings.a11y.display_rotation_accelerator_dialog_has_been_accepted2";
 
 // A dictionary pref that stores the mixed mirror mode parameters.
 const char kDisplayMixedMirrorModeParams[] =
diff --git a/ash/public/cpp/ash_pref_names.h b/ash/public/cpp/ash_pref_names.h
index 2b3413a..f0b8158 100644
--- a/ash/public/cpp/ash_pref_names.h
+++ b/ash/public/cpp/ash_pref_names.h
@@ -59,6 +59,8 @@
     kDictationAcceleratorDialogHasBeenAccepted[];
 ASH_PUBLIC_EXPORT extern const char
     kDisplayRotationAcceleratorDialogHasBeenAccepted[];
+ASH_PUBLIC_EXPORT extern const char
+    kDisplayRotationAcceleratorDialogHasBeenAccepted2[];
 
 ASH_PUBLIC_EXPORT extern const char kDisplayMixedMirrorModeParams[];
 ASH_PUBLIC_EXPORT extern const char kDisplayPowerState[];
diff --git a/ash/shelf/shelf_controller.cc b/ash/shelf/shelf_controller.cc
index 5e4fb227..8e6e13f2 100644
--- a/ash/shelf/shelf_controller.cc
+++ b/ash/shelf/shelf_controller.cc
@@ -126,18 +126,15 @@
   // These prefs are public for ChromeLauncherController's OnIsSyncingChanged.
   // See the pref names definitions for explanations of the synced, local, and
   // per-display behaviors.
-  registry->RegisterStringPref(
-      prefs::kShelfAutoHideBehavior, kShelfAutoHideBehaviorNever,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
+  registry->RegisterStringPref(prefs::kShelfAutoHideBehavior,
+                               kShelfAutoHideBehaviorNever,
+                               user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
   registry->RegisterStringPref(prefs::kShelfAutoHideBehaviorLocal,
-                               std::string(), PrefRegistry::PUBLIC);
-  registry->RegisterStringPref(
-      prefs::kShelfAlignment, kShelfAlignmentBottom,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterStringPref(prefs::kShelfAlignmentLocal, std::string(),
-                               PrefRegistry::PUBLIC);
-  registry->RegisterDictionaryPref(prefs::kShelfPreferences,
-                                   PrefRegistry::PUBLIC);
+                               std::string());
+  registry->RegisterStringPref(prefs::kShelfAlignment, kShelfAlignmentBottom,
+                               user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterStringPref(prefs::kShelfAlignmentLocal, std::string());
+  registry->RegisterDictionaryPref(prefs::kShelfPreferences);
 }
 
 void ShelfController::OnActiveUserPrefServiceChanged(
diff --git a/ash/system/bluetooth/bluetooth_power_controller.cc b/ash/system/bluetooth/bluetooth_power_controller.cc
index 248d03e4..df5d3b51 100644
--- a/ash/system/bluetooth/bluetooth_power_controller.cc
+++ b/ash/system/bluetooth/bluetooth_power_controller.cc
@@ -70,8 +70,7 @@
 // static
 void BluetoothPowerController::RegisterProfilePrefs(
     PrefRegistrySimple* registry) {
-  registry->RegisterBooleanPref(prefs::kUserBluetoothAdapterEnabled, false,
-                                PrefRegistry::PUBLIC);
+  registry->RegisterBooleanPref(prefs::kUserBluetoothAdapterEnabled, false);
 }
 
 void BluetoothPowerController::StartWatchingActiveUserPrefsChanges() {
diff --git a/ash/system/message_center/message_center_controller.cc b/ash/system/message_center/message_center_controller.cc
index 6f47e3d..b32b4c9 100644
--- a/ash/system/message_center/message_center_controller.cc
+++ b/ash/system/message_center/message_center_controller.cc
@@ -34,10 +34,9 @@
 // static
 void MessageCenterController::RegisterProfilePrefs(
     PrefRegistrySimple* registry) {
-  registry->RegisterStringPref(
-      prefs::kMessageCenterLockScreenMode,
-      prefs::kMessageCenterLockScreenModeHide,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
+  registry->RegisterStringPref(prefs::kMessageCenterLockScreenMode,
+                               prefs::kMessageCenterLockScreenModeHide,
+                               user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
 }
 
 namespace {
diff --git a/ash/system/network/vpn_list_view.cc b/ash/system/network/vpn_list_view.cc
index 61162d5f..7592801 100644
--- a/ash/system/network/vpn_list_view.cc
+++ b/ash/system/network/vpn_list_view.cc
@@ -372,8 +372,7 @@
 }
 
 void VPNListView::RegisterProfilePrefs(PrefRegistrySimple* registry) {
-  registry->RegisterBooleanPref(prefs::kVpnConfigAllowed, true,
-                                PrefRegistry::PUBLIC);
+  registry->RegisterBooleanPref(prefs::kVpnConfigAllowed, true);
 }
 
 const char* VPNListView::GetClassName() const {
diff --git a/ash/system/night_light/night_light_controller_impl.cc b/ash/system/night_light/night_light_controller_impl.cc
index d9d0172..b3a3cb37 100644
--- a/ash/system/night_light/night_light_controller_impl.cc
+++ b/ash/system/night_light/night_light_controller_impl.cc
@@ -328,19 +328,15 @@
 // static
 void NightLightControllerImpl::RegisterProfilePrefs(
     PrefRegistrySimple* registry) {
-  registry->RegisterBooleanPref(prefs::kNightLightEnabled, false,
-                                PrefRegistry::PUBLIC);
+  registry->RegisterBooleanPref(prefs::kNightLightEnabled, false);
   registry->RegisterDoublePref(prefs::kNightLightTemperature,
-                               kDefaultColorTemperature, PrefRegistry::PUBLIC);
+                               kDefaultColorTemperature);
   registry->RegisterIntegerPref(prefs::kNightLightScheduleType,
-                                static_cast<int>(ScheduleType::kNone),
-                                PrefRegistry::PUBLIC);
+                                static_cast<int>(ScheduleType::kNone));
   registry->RegisterIntegerPref(prefs::kNightLightCustomStartTime,
-                                kDefaultStartTimeOffsetMinutes,
-                                PrefRegistry::PUBLIC);
+                                kDefaultStartTimeOffsetMinutes);
   registry->RegisterIntegerPref(prefs::kNightLightCustomEndTime,
-                                kDefaultEndTimeOffsetMinutes,
-                                PrefRegistry::PUBLIC);
+                                kDefaultEndTimeOffsetMinutes);
 
   // Non-public prefs, only meant to be used by ash.
   registry->RegisterDoublePref(prefs::kNightLightCachedLatitude, 0.0);
diff --git a/ash/system/palette/palette_tray.cc b/ash/system/palette/palette_tray.cc
index f32f725d..d425193 100644
--- a/ash/system/palette/palette_tray.cc
+++ b/ash/system/palette/palette_tray.cc
@@ -205,18 +205,17 @@
 
 // static
 void PaletteTray::RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
-  registry->RegisterBooleanPref(prefs::kHasSeenStylus, false,
-                                PrefRegistry::PUBLIC);
+  registry->RegisterBooleanPref(prefs::kHasSeenStylus, false);
 }
 
 // static
 void PaletteTray::RegisterProfilePrefs(PrefRegistrySimple* registry) {
   registry->RegisterBooleanPref(
       prefs::kEnableStylusTools, true,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
   registry->RegisterBooleanPref(
       prefs::kLaunchPaletteOnEjectEvent, true,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
 }
 
 bool PaletteTray::ContainsPointInScreen(const gfx::Point& point) {
diff --git a/ash/system/power/power_prefs.cc b/ash/system/power/power_prefs.cc
index 9b7a90d..90940081 100644
--- a/ash/system/power/power_prefs.cc
+++ b/ash/system/power/power_prefs.cc
@@ -70,69 +70,45 @@
 
 // Registers power prefs whose default values are the same in user prefs and
 // signin prefs.
-void RegisterProfilePrefs(PrefRegistrySimple* registry, bool for_test) {
-  registry->RegisterIntegerPref(prefs::kPowerAcScreenBrightnessPercent, -1,
-                                PrefRegistry::PUBLIC);
-  registry->RegisterIntegerPref(prefs::kPowerAcScreenDimDelayMs, 420000,
-                                PrefRegistry::PUBLIC);
-  registry->RegisterIntegerPref(prefs::kPowerAcScreenOffDelayMs, 450000,
-                                PrefRegistry::PUBLIC);
-  registry->RegisterIntegerPref(prefs::kPowerAcScreenLockDelayMs, 0,
-                                PrefRegistry::PUBLIC);
-  registry->RegisterIntegerPref(prefs::kPowerAcIdleWarningDelayMs, 0,
-                                PrefRegistry::PUBLIC);
-  registry->RegisterIntegerPref(prefs::kPowerAcIdleDelayMs, 510000,
-                                PrefRegistry::PUBLIC);
-  registry->RegisterIntegerPref(prefs::kPowerBatteryScreenBrightnessPercent, -1,
-                                PrefRegistry::PUBLIC);
-  registry->RegisterIntegerPref(prefs::kPowerBatteryScreenDimDelayMs, 300000,
-                                PrefRegistry::PUBLIC);
-  registry->RegisterIntegerPref(prefs::kPowerBatteryScreenOffDelayMs, 330000,
-                                PrefRegistry::PUBLIC);
-  registry->RegisterIntegerPref(prefs::kPowerBatteryScreenLockDelayMs, 0,
-                                PrefRegistry::PUBLIC);
-  registry->RegisterIntegerPref(prefs::kPowerBatteryIdleWarningDelayMs, 0,
-                                PrefRegistry::PUBLIC);
-  registry->RegisterIntegerPref(prefs::kPowerBatteryIdleDelayMs, 390000,
-                                PrefRegistry::PUBLIC);
-  registry->RegisterIntegerPref(prefs::kPowerLockScreenDimDelayMs, 30000,
-                                PrefRegistry::PUBLIC);
-  registry->RegisterIntegerPref(prefs::kPowerLockScreenOffDelayMs, 40000,
-                                PrefRegistry::PUBLIC);
-  registry->RegisterIntegerPref(prefs::kPowerAcIdleAction,
-                                chromeos::PowerPolicyController::ACTION_SUSPEND,
-                                PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(prefs::kPowerUseAudioActivity, true,
-                                PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(prefs::kPowerUseVideoActivity, true,
-                                PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(prefs::kPowerAllowWakeLocks, true,
-                                PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(prefs::kPowerAllowScreenWakeLocks, true,
-                                PrefRegistry::PUBLIC);
+void RegisterProfilePrefs(PrefRegistrySimple* registry) {
+  registry->RegisterIntegerPref(prefs::kPowerAcScreenBrightnessPercent, -1);
+  registry->RegisterIntegerPref(prefs::kPowerAcScreenDimDelayMs, 420000);
+  registry->RegisterIntegerPref(prefs::kPowerAcScreenOffDelayMs, 450000);
+  registry->RegisterIntegerPref(prefs::kPowerAcScreenLockDelayMs, 0);
+  registry->RegisterIntegerPref(prefs::kPowerAcIdleWarningDelayMs, 0);
+  registry->RegisterIntegerPref(prefs::kPowerAcIdleDelayMs, 510000);
+  registry->RegisterIntegerPref(prefs::kPowerBatteryScreenBrightnessPercent,
+                                -1);
+  registry->RegisterIntegerPref(prefs::kPowerBatteryScreenDimDelayMs, 300000);
+  registry->RegisterIntegerPref(prefs::kPowerBatteryScreenOffDelayMs, 330000);
+  registry->RegisterIntegerPref(prefs::kPowerBatteryScreenLockDelayMs, 0);
+  registry->RegisterIntegerPref(prefs::kPowerBatteryIdleWarningDelayMs, 0);
+  registry->RegisterIntegerPref(prefs::kPowerBatteryIdleDelayMs, 390000);
+  registry->RegisterIntegerPref(prefs::kPowerLockScreenDimDelayMs, 30000);
+  registry->RegisterIntegerPref(prefs::kPowerLockScreenOffDelayMs, 40000);
+  registry->RegisterIntegerPref(
+      prefs::kPowerAcIdleAction,
+      chromeos::PowerPolicyController::ACTION_SUSPEND);
+  registry->RegisterBooleanPref(prefs::kPowerUseAudioActivity, true);
+  registry->RegisterBooleanPref(prefs::kPowerUseVideoActivity, true);
+  registry->RegisterBooleanPref(prefs::kPowerAllowWakeLocks, true);
+  registry->RegisterBooleanPref(prefs::kPowerAllowScreenWakeLocks, true);
   registry->RegisterDoublePref(prefs::kPowerPresentationScreenDimDelayFactor,
-                               2.0, PrefRegistry::PUBLIC);
+                               2.0);
   registry->RegisterDoublePref(prefs::kPowerUserActivityScreenDimDelayFactor,
-                               2.0, PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(prefs::kPowerWaitForInitialUserActivity, false,
-                                PrefRegistry::PUBLIC);
+                               2.0);
+  registry->RegisterBooleanPref(prefs::kPowerWaitForInitialUserActivity, false);
   registry->RegisterBooleanPref(
-      prefs::kPowerForceNonzeroBrightnessForUserActivity, true,
-      PrefRegistry::PUBLIC);
+      prefs::kPowerForceNonzeroBrightnessForUserActivity, true);
   registry->RegisterBooleanPref(prefs::kPowerFastSuspendWhenBacklightsForcedOff,
-                                true, PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(prefs::kPowerSmartDimEnabled, true,
-                                PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(prefs::kPowerAlsLoggingEnabled, false,
-                                PrefRegistry::PUBLIC);
+                                true);
+  registry->RegisterBooleanPref(prefs::kPowerSmartDimEnabled, true);
+  registry->RegisterBooleanPref(prefs::kPowerAlsLoggingEnabled, false);
 
-  if (for_test) {
-    registry->RegisterBooleanPref(prefs::kAllowScreenLock, true,
-                                  PrefRegistry::PUBLIC);
-    registry->RegisterBooleanPref(
-        prefs::kEnableAutoScreenLock, false,
-        user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  }
+  registry->RegisterBooleanPref(prefs::kAllowScreenLock, true);
+  registry->RegisterBooleanPref(
+      prefs::kEnableAutoScreenLock, false,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
 }
 
 }  // namespace
@@ -162,56 +138,45 @@
 
 // static
 void PowerPrefs::RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
-  registry->RegisterBooleanPref(prefs::kPowerPeakShiftEnabled, false,
-                                PrefRegistry::PUBLIC);
-  registry->RegisterIntegerPref(prefs::kPowerPeakShiftBatteryThreshold, -1,
-                                PrefRegistry::PUBLIC);
-  registry->RegisterDictionaryPref(prefs::kPowerPeakShiftDayConfig,
-                                   PrefRegistry::PUBLIC);
+  registry->RegisterBooleanPref(prefs::kPowerPeakShiftEnabled, false);
+  registry->RegisterIntegerPref(prefs::kPowerPeakShiftBatteryThreshold, -1);
+  registry->RegisterDictionaryPref(prefs::kPowerPeakShiftDayConfig);
 
-  registry->RegisterBooleanPref(prefs::kBootOnAcEnabled, false,
-                                PrefRegistry::PUBLIC);
+  registry->RegisterBooleanPref(prefs::kBootOnAcEnabled, false);
 
-  registry->RegisterBooleanPref(prefs::kAdvancedBatteryChargeModeEnabled, false,
-                                PrefRegistry::PUBLIC);
-  registry->RegisterDictionaryPref(prefs::kAdvancedBatteryChargeModeDayConfig,
-                                   PrefRegistry::PUBLIC);
+  registry->RegisterBooleanPref(prefs::kAdvancedBatteryChargeModeEnabled,
+                                false);
+  registry->RegisterDictionaryPref(prefs::kAdvancedBatteryChargeModeDayConfig);
 
-  registry->RegisterIntegerPref(prefs::kBatteryChargeMode, -1,
-                                PrefRegistry::PUBLIC);
-  registry->RegisterIntegerPref(prefs::kBatteryChargeCustomStartCharging, -1,
-                                PrefRegistry::PUBLIC);
-  registry->RegisterIntegerPref(prefs::kBatteryChargeCustomStopCharging, -1,
-                                PrefRegistry::PUBLIC);
+  registry->RegisterIntegerPref(prefs::kBatteryChargeMode, -1);
+  registry->RegisterIntegerPref(prefs::kBatteryChargeCustomStartCharging, -1);
+  registry->RegisterIntegerPref(prefs::kBatteryChargeCustomStopCharging, -1);
 
-  registry->RegisterBooleanPref(prefs::kUsbPowerShareEnabled, true,
-                                PrefRegistry::PUBLIC);
+  registry->RegisterBooleanPref(prefs::kUsbPowerShareEnabled, true);
 }
 
 // static
-void PowerPrefs::RegisterSigninProfilePrefs(PrefRegistrySimple* registry,
-                                            bool for_test) {
-  RegisterProfilePrefs(registry, for_test);
+void PowerPrefs::RegisterSigninProfilePrefs(PrefRegistrySimple* registry) {
+  RegisterProfilePrefs(registry);
 
   registry->RegisterIntegerPref(
       prefs::kPowerBatteryIdleAction,
-      chromeos::PowerPolicyController::ACTION_SHUT_DOWN, PrefRegistry::PUBLIC);
+      chromeos::PowerPolicyController::ACTION_SHUT_DOWN);
   registry->RegisterIntegerPref(
       prefs::kPowerLidClosedAction,
-      chromeos::PowerPolicyController::ACTION_SHUT_DOWN, PrefRegistry::PUBLIC);
+      chromeos::PowerPolicyController::ACTION_SHUT_DOWN);
 }
 
 // static
-void PowerPrefs::RegisterUserProfilePrefs(PrefRegistrySimple* registry,
-                                          bool for_test) {
-  RegisterProfilePrefs(registry, for_test);
+void PowerPrefs::RegisterUserProfilePrefs(PrefRegistrySimple* registry) {
+  RegisterProfilePrefs(registry);
 
-  registry->RegisterIntegerPref(prefs::kPowerBatteryIdleAction,
-                                chromeos::PowerPolicyController::ACTION_SUSPEND,
-                                PrefRegistry::PUBLIC);
-  registry->RegisterIntegerPref(prefs::kPowerLidClosedAction,
-                                chromeos::PowerPolicyController::ACTION_SUSPEND,
-                                PrefRegistry::PUBLIC);
+  registry->RegisterIntegerPref(
+      prefs::kPowerBatteryIdleAction,
+      chromeos::PowerPolicyController::ACTION_SUSPEND);
+  registry->RegisterIntegerPref(
+      prefs::kPowerLidClosedAction,
+      chromeos::PowerPolicyController::ACTION_SUSPEND);
 }
 
 void PowerPrefs::ScreenIdleStateChanged(
diff --git a/ash/system/power/power_prefs.h b/ash/system/power/power_prefs.h
index 7671a402..589df769 100644
--- a/ash/system/power/power_prefs.h
+++ b/ash/system/power/power_prefs.h
@@ -45,12 +45,10 @@
   static void RegisterLocalStatePrefs(PrefRegistrySimple* registry);
 
   // Registers power prefs with default values applicable to the signin prefs.
-  static void RegisterSigninProfilePrefs(PrefRegistrySimple* registry,
-                                         bool for_test = false);
+  static void RegisterSigninProfilePrefs(PrefRegistrySimple* registry);
 
   // Registers power prefs with default values applicable to the user prefs.
-  static void RegisterUserProfilePrefs(PrefRegistrySimple* registry,
-                                       bool for_test = false);
+  static void RegisterUserProfilePrefs(PrefRegistrySimple* registry);
 
   void set_tick_clock_for_test(base::TickClock* clock) { tick_clock_ = clock; }
 
diff --git a/ash/system/session/logout_button_tray.cc b/ash/system/session/logout_button_tray.cc
index d66ecd6..5235519 100644
--- a/ash/system/session/logout_button_tray.cc
+++ b/ash/system/session/logout_button_tray.cc
@@ -56,10 +56,8 @@
 
 // static
 void LogoutButtonTray::RegisterProfilePrefs(PrefRegistrySimple* registry) {
-  registry->RegisterBooleanPref(prefs::kShowLogoutButtonInTray, false,
-                                PrefRegistry::PUBLIC);
-  registry->RegisterIntegerPref(prefs::kLogoutDialogDurationMs, 20000,
-                                PrefRegistry::PUBLIC);
+  registry->RegisterBooleanPref(prefs::kShowLogoutButtonInTray, false);
+  registry->RegisterIntegerPref(prefs::kLogoutDialogDurationMs, 20000);
 }
 
 void LogoutButtonTray::UpdateAfterShelfAlignmentChange() {
diff --git a/ash/touch/touch_devices_controller.cc b/ash/touch/touch_devices_controller.cc
index 2e1d531..4a45c3c 100644
--- a/ash/touch/touch_devices_controller.cc
+++ b/ash/touch/touch_devices_controller.cc
@@ -36,11 +36,9 @@
     PrefRegistrySimple* registry) {
   registry->RegisterBooleanPref(
       prefs::kTapDraggingEnabled, false,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF |
-          PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(prefs::kTouchpadEnabled, PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(prefs::kTouchscreenEnabled,
-                                PrefRegistry::PUBLIC);
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
+  registry->RegisterBooleanPref(prefs::kTouchpadEnabled, true);
+  registry->RegisterBooleanPref(prefs::kTouchscreenEnabled, true);
 }
 
 TouchDevicesController::TouchDevicesController() {
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index b0d706f..b1a8504c 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8899266194319676112
\ No newline at end of file
+8899236512803402976
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 3b033af..7427f4a 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-8899267142825427424
\ No newline at end of file
+8899240979698604064
\ No newline at end of file
diff --git a/cc/OWNERS b/cc/OWNERS
index 820c023..c5524c6 100644
--- a/cc/OWNERS
+++ b/cc/OWNERS
@@ -9,6 +9,7 @@
 enne@chromium.org
 danakj@chromium.org
 pdr@chromium.org
+wangxianzhu@chromium.org
 
 # mac-specific
 ccameron@chromium.org
@@ -30,6 +31,7 @@
 chrishtr@chromium.org
 weiliangc@chromium.org
 pdr@chromium.org
+wangxianzhu@chromium.org
 
 # animation
 flackr@chromium.org
diff --git a/cc/input/scrollbar_controller.cc b/cc/input/scrollbar_controller.cc
index 2f4221e..7018ba1d 100644
--- a/cc/input/scrollbar_controller.cc
+++ b/cc/input/scrollbar_controller.cc
@@ -25,7 +25,6 @@
     LayerTreeHostImpl* layer_tree_host_impl)
     : layer_tree_host_impl_(layer_tree_host_impl),
       scrollbar_scroll_is_active_(false),
-      currently_captured_scrollbar_(nullptr),
       last_known_pointer_position_(gfx::PointF(0, 0)),
       drag_processed_for_current_frame_(false),
       cancelable_autoscroll_task_(nullptr) {}
@@ -36,20 +35,34 @@
 }
 
 gfx::Vector2dF ScrollbarController::GetThumbRelativePoint(
+    const ScrollbarLayerImplBase* scrollbar,
     const gfx::PointF position_in_widget) {
   bool clipped;
   const gfx::PointF position_in_layer =
-      GetScrollbarRelativePosition(position_in_widget, &clipped);
+      GetScrollbarRelativePosition(scrollbar, position_in_widget, &clipped);
 
   if (clipped)
     return gfx::Vector2d(0, 0);
 
-  const gfx::RectF thumb_rect(
-      currently_captured_scrollbar_->ComputeThumbQuadRect());
+  const gfx::RectF thumb_rect(scrollbar->ComputeThumbQuadRect());
   DCHECK(thumb_rect.Contains(position_in_layer));
   return position_in_layer - gfx::PointF(thumb_rect.origin());
 }
 
+// Retrieves the ScrollbarLayerImplBase corresponding to the stashed ElementId.
+ScrollbarLayerImplBase* ScrollbarController::ScrollbarLayer() {
+  if (!captured_scrollbar_metadata_.has_value())
+    return nullptr;
+
+  const ScrollbarSet scrollbars = layer_tree_host_impl_->ScrollbarsFor(
+      captured_scrollbar_metadata_->scroll_element_id);
+  for (ScrollbarLayerImplBase* scrollbar : scrollbars) {
+    if (captured_scrollbar_metadata_->orientation == scrollbar->orientation())
+      return scrollbar;
+  }
+  return nullptr;
+}
+
 // Performs hit test and prepares scroll deltas that will be used by GSB and
 // GSU.
 InputHandlerPointerResult ScrollbarController::HandlePointerDown(
@@ -65,30 +78,32 @@
   if (!(layer_impl && layer_impl->ToScrollbarLayer()))
     return InputHandlerPointerResult();
 
-  currently_captured_scrollbar_ = layer_impl->ToScrollbarLayer();
+  const ScrollbarLayerImplBase* scrollbar = layer_impl->ToScrollbarLayer();
+  captured_scrollbar_metadata_ = CapturedScrollbarMetadata();
+  captured_scrollbar_metadata_->scroll_element_id =
+      scrollbar->scroll_element_id();
+  captured_scrollbar_metadata_->orientation = scrollbar->orientation();
+
   InputHandlerPointerResult scroll_result;
-  scroll_result.target_scroller =
-      currently_captured_scrollbar_->scroll_element_id();
+  scroll_result.target_scroller = scrollbar->scroll_element_id();
   scroll_result.type = PointerResultType::kScrollbarScroll;
   layer_tree_host_impl_->active_tree()->UpdateScrollbarGeometries();
   const ScrollbarPart scrollbar_part =
-      GetScrollbarPartFromPointerDown(position_in_widget);
+      GetScrollbarPartFromPointerDown(scrollbar, position_in_widget);
   scroll_result.scroll_offset = GetScrollOffsetForScrollbarPart(
-      scrollbar_part, currently_captured_scrollbar_->orientation(),
-      shift_modifier);
+      scrollbar, scrollbar_part, shift_modifier);
   last_known_pointer_position_ = position_in_widget;
   scrollbar_scroll_is_active_ = true;
   scroll_result.scroll_units = Granularity(scrollbar_part, shift_modifier);
   if (scrollbar_part == ScrollbarPart::THUMB) {
     drag_state_ = DragState();
     drag_state_->anchor_relative_to_thumb_ =
-        GetThumbRelativePoint(position_in_widget);
+        GetThumbRelativePoint(scrollbar, position_in_widget);
 
     // Record the current scroller offset. This will be needed to snap the
     // thumb back to its original position if the pointer moves too far away
     // from the track during a thumb drag.
-    drag_state_->scroll_position_at_start_ =
-        currently_captured_scrollbar_->current_pos();
+    drag_state_->scroll_position_at_start_ = scrollbar->current_pos();
   }
 
   if (!scroll_result.scroll_offset.IsZero()) {
@@ -97,13 +112,12 @@
     // have the potential of initiating an autoscroll (if held down for long
     // enough).
     DCHECK(scrollbar_part != ScrollbarPart::THUMB);
-    cancelable_autoscroll_task_ =
-        std::make_unique<base::CancelableClosure>(base::Bind(
-            &ScrollbarController::StartAutoScrollAnimation,
-            base::Unretained(this),
-            InitialDeltaToAutoscrollVelocity(scroll_result.scroll_offset),
-            currently_captured_scrollbar_->scroll_element_id(),
-            scrollbar_part));
+    cancelable_autoscroll_task_ = std::make_unique<base::CancelableClosure>(
+        base::Bind(&ScrollbarController::StartAutoScrollAnimation,
+                   base::Unretained(this),
+                   InitialDeltaToAutoscrollVelocity(
+                       scrollbar, scroll_result.scroll_offset),
+                   scrollbar, scrollbar_part));
     layer_tree_host_impl_->task_runner_provider()
         ->ImplThreadTaskRunner()
         ->PostDelayedTask(FROM_HERE, cancelable_autoscroll_task_->callback(),
@@ -113,24 +127,23 @@
 }
 
 bool ScrollbarController::SnapToDragOrigin(
+    const ScrollbarLayerImplBase* scrollbar,
     const gfx::PointF pointer_position_in_widget) {
   // Consult the ScrollbarTheme to check if thumb snapping is supported on the
   // current platform.
-  if (!currently_captured_scrollbar_->SupportsDragSnapBack())
+  if (!(scrollbar && scrollbar->SupportsDragSnapBack()))
     return false;
 
   bool clipped = false;
-  const gfx::PointF pointer_position_in_layer =
-      GetScrollbarRelativePosition(pointer_position_in_widget, &clipped);
+  const gfx::PointF pointer_position_in_layer = GetScrollbarRelativePosition(
+      scrollbar, pointer_position_in_widget, &clipped);
 
   if (clipped)
     return false;
 
   layer_tree_host_impl_->active_tree()->UpdateScrollbarGeometries();
-  const ScrollbarOrientation orientation =
-      currently_captured_scrollbar_->orientation();
-  const gfx::Rect forward_track_rect =
-      currently_captured_scrollbar_->ForwardTrackRect();
+  const ScrollbarOrientation orientation = scrollbar->orientation();
+  const gfx::Rect forward_track_rect = scrollbar->ForwardTrackRect();
 
   // When dragging the thumb, there needs to exist "gutters" on either side of
   // the track. The thickness of these gutters is a multiple of the track (or
@@ -146,7 +159,7 @@
   if (!track_thickness) {
     // For overlay scrollbars (or for tests that do not set up a track
     // thickness), use the thumb_thickness instead to determine the gutters.
-    const int thumb_thickness = currently_captured_scrollbar_->ThumbThickness();
+    const int thumb_thickness = scrollbar->ThumbThickness();
 
     // If the thumb doesn't have thickness, the gutters can't be determined.
     // Snapping shouldn't occur in this case.
@@ -188,62 +201,60 @@
   return ui::input_types::ScrollGranularity::kScrollByPixel;
 }
 
-float ScrollbarController::GetScrollDeltaForShiftClick() {
+float ScrollbarController::GetScrollDeltaForShiftClick(
+    const ScrollbarLayerImplBase* scrollbar) {
   layer_tree_host_impl_->active_tree()->UpdateScrollbarGeometries();
 
   bool clipped = false;
-  const gfx::PointF pointer_position_in_layer =
-      GetScrollbarRelativePosition(last_known_pointer_position_, &clipped);
+  const gfx::PointF pointer_position_in_layer = GetScrollbarRelativePosition(
+      scrollbar, last_known_pointer_position_, &clipped);
 
   if (clipped)
     return 0;
 
-  const ScrollbarOrientation orientation =
-      currently_captured_scrollbar_->orientation();
-  const float pointer_location = orientation == ScrollbarOrientation::VERTICAL
-                                     ? pointer_position_in_layer.y()
-                                     : pointer_position_in_layer.x();
+  const float pointer_location =
+      scrollbar->orientation() == ScrollbarOrientation::VERTICAL
+          ? pointer_position_in_layer.y()
+          : pointer_position_in_layer.x();
 
   // During a shift + click, the pointers current location (on the track) needs
   // to be considered as the center of the thumb and the thumb origin needs to
   // be calculated based on that. This will ensure that when shift + click is
   // processed, the thumb will be centered on the pointer.
-  const int thumb_length = currently_captured_scrollbar_->ThumbLength();
+  const int thumb_length = scrollbar->ThumbLength();
   const float desired_thumb_origin = pointer_location - thumb_length / 2.f;
 
-  const gfx::Rect thumb_rect(
-      currently_captured_scrollbar_->ComputeThumbQuadRect());
+  const gfx::Rect thumb_rect(scrollbar->ComputeThumbQuadRect());
   const float current_thumb_origin =
-      orientation == ScrollbarOrientation::VERTICAL ? thumb_rect.y()
-                                                    : thumb_rect.x();
+      scrollbar->orientation() == ScrollbarOrientation::VERTICAL
+          ? thumb_rect.y()
+          : thumb_rect.x();
 
   const float delta =
       round(std::abs(desired_thumb_origin - current_thumb_origin));
-  return delta * GetScrollerToScrollbarRatio();
+  return delta * GetScrollerToScrollbarRatio(scrollbar);
 }
 
 gfx::ScrollOffset ScrollbarController::GetScrollOffsetForDragPosition(
+    const ScrollbarLayerImplBase* scrollbar,
     const gfx::PointF pointer_position_in_widget) {
   layer_tree_host_impl_->active_tree()->UpdateScrollbarGeometries();
 
-  const ScrollbarOrientation orientation =
-      currently_captured_scrollbar_->orientation();
-  if (SnapToDragOrigin(pointer_position_in_widget)) {
-    const float delta = currently_captured_scrollbar_->current_pos() -
-                        drag_state_->scroll_position_at_start_;
-    return orientation == ScrollbarOrientation::VERTICAL
+  if (SnapToDragOrigin(scrollbar, pointer_position_in_widget)) {
+    const float delta =
+        scrollbar->current_pos() - drag_state_->scroll_position_at_start_;
+    return scrollbar->orientation() == ScrollbarOrientation::VERTICAL
                ? gfx::ScrollOffset(0, -delta)
                : gfx::ScrollOffset(-delta, 0);
   }
 
-  const gfx::Rect thumb_rect(
-      currently_captured_scrollbar_->ComputeThumbQuadRect());
+  const gfx::Rect thumb_rect(scrollbar->ComputeThumbQuadRect());
   const gfx::PointF drag_position_relative_to_layer =
       gfx::PointF(thumb_rect.origin()) + drag_state_->anchor_relative_to_thumb_;
 
   bool clipped = false;
-  const gfx::PointF pointer_position_in_layer =
-      GetScrollbarRelativePosition(pointer_position_in_widget, &clipped);
+  const gfx::PointF pointer_position_in_layer = GetScrollbarRelativePosition(
+      scrollbar, pointer_position_in_widget, &clipped);
 
   if (clipped)
     return gfx::ScrollOffset(0, 0);
@@ -252,8 +263,9 @@
   const gfx::Vector2dF pointer_delta =
       pointer_position_in_layer - drag_position_relative_to_layer;
 
-  float scaled_scroller_to_scrollbar_ratio = GetScrollerToScrollbarRatio();
-  float current_scroll_position = currently_captured_scrollbar_->current_pos();
+  float scaled_scroller_to_scrollbar_ratio =
+      GetScrollerToScrollbarRatio(scrollbar);
+  float current_scroll_position = scrollbar->current_pos();
 
   // Thumb position needs to be floored and Values between 0 and 1 are rounded
   // to one to match main thread per pixel behavior. Corresponding main thread
@@ -264,9 +276,10 @@
                        ? 1.0
                        : floorf(thumb_position);
 
-  float delta_in_orientation = orientation == ScrollbarOrientation::VERTICAL
-                                   ? pointer_delta.y()
-                                   : pointer_delta.x();
+  float delta_in_orientation =
+      scrollbar->orientation() == ScrollbarOrientation::VERTICAL
+          ? pointer_delta.y()
+          : pointer_delta.x();
 
   // This is effectively equal to delta_in_orientation *
   // scaled_scroller_to_scrollbar_ratio but is necessary due to truncated delta
@@ -280,7 +293,7 @@
   gfx::ScrollOffset scaled_thumb_drag_delta;
 
   // Scroll delta floored to match main thread per pixel behavior
-  orientation == ScrollbarOrientation::VERTICAL
+  scrollbar->orientation() == ScrollbarOrientation::VERTICAL
       ? scaled_thumb_drag_delta.set_y(floorf(scroll_delta))
       : scaled_thumb_drag_delta.set_x(floorf(scroll_delta));
 
@@ -297,7 +310,9 @@
   // If a thumb drag is not in progress or if a GSU was already produced for a
   // thumb drag in this frame, there's no point in continuing on. Please see the
   // header file for details.
-  if (!drag_state_.has_value() || drag_processed_for_current_frame_)
+  const ScrollbarLayerImplBase* scrollbar = ScrollbarLayer();
+  if (!scrollbar || !drag_state_.has_value() ||
+      drag_processed_for_current_frame_)
     return scroll_result;
 
   const ScrollNode* currently_scrolling_node =
@@ -312,7 +327,7 @@
 
   // If scroll_offset can't be consumed, there's no point in continuing on.
   const gfx::ScrollOffset scroll_offset(
-      GetScrollOffsetForDragPosition(position_in_widget));
+      GetScrollOffsetForDragPosition(scrollbar, position_in_widget));
   const gfx::Vector2dF clamped_scroll_offset(
       layer_tree_host_impl_->ComputeScrollDelta(
           *currently_scrolling_node, ScrollOffsetToVector2dF(scroll_offset)));
@@ -331,7 +346,8 @@
   return scroll_result;
 }
 
-float ScrollbarController::GetScrollerToScrollbarRatio() {
+float ScrollbarController::GetScrollerToScrollbarRatio(
+    const ScrollbarLayerImplBase* scrollbar) {
   // Calculating the delta by which the scroller layer should move when
   // dragging the thumb depends on the following factors:
   // - scrollbar_track_length
@@ -371,21 +387,19 @@
   //          |<- scrollbar_thumb_length ->|
   //
   layer_tree_host_impl_->active_tree()->UpdateScrollbarGeometries();
-  float scroll_layer_length =
-      currently_captured_scrollbar_->scroll_layer_length();
-  float scrollbar_track_length = currently_captured_scrollbar_->TrackLength();
-  gfx::Rect thumb_rect(currently_captured_scrollbar_->ComputeThumbQuadRect());
-  const ScrollbarOrientation orientation =
-      currently_captured_scrollbar_->orientation();
-  float scrollbar_thumb_length = orientation == ScrollbarOrientation::VERTICAL
-                                     ? thumb_rect.height()
-                                     : thumb_rect.width();
+  float scroll_layer_length = scrollbar->scroll_layer_length();
+  float scrollbar_track_length = scrollbar->TrackLength();
+  gfx::Rect thumb_rect(scrollbar->ComputeThumbQuadRect());
+  float scrollbar_thumb_length =
+      scrollbar->orientation() == ScrollbarOrientation::VERTICAL
+          ? thumb_rect.height()
+          : thumb_rect.width();
 
   const LayerImpl* owner_scroll_layer =
       layer_tree_host_impl_->active_tree()->ScrollableLayerByElementId(
-          currently_captured_scrollbar_->scroll_element_id());
+          scrollbar->scroll_element_id());
   const float viewport_length =
-      orientation == ScrollbarOrientation::VERTICAL
+      scrollbar->orientation() == ScrollbarOrientation::VERTICAL
           ? owner_scroll_layer->scroll_container_bounds().height()
           : (owner_scroll_layer->scroll_container_bounds().width());
 
@@ -402,19 +416,31 @@
   return scaled_scroller_to_scrollbar_ratio;
 }
 
+void ScrollbarController::ResetState() {
+  drag_processed_for_current_frame_ = false;
+  drag_state_ = base::nullopt;
+  autoscroll_state_ = base::nullopt;
+  captured_scrollbar_metadata_ = base::nullopt;
+}
+
+void ScrollbarController::DidUnregisterScrollbar(ElementId element_id) {
+  if (captured_scrollbar_metadata_.has_value() &&
+      captured_scrollbar_metadata_->scroll_element_id == element_id)
+    ResetState();
+}
+
 void ScrollbarController::RecomputeAutoscrollStateIfNeeded() {
-  if (!autoscroll_state_.has_value())
+  if (!autoscroll_state_.has_value() ||
+      !captured_scrollbar_metadata_.has_value())
     return;
 
   layer_tree_host_impl_->active_tree()->UpdateScrollbarGeometries();
-  const ScrollbarOrientation orientation =
-      currently_captured_scrollbar_->orientation();
-  const gfx::Rect thumb_quad =
-      currently_captured_scrollbar_->ComputeThumbQuadRect();
+  const ScrollbarLayerImplBase* scrollbar = ScrollbarLayer();
+  const gfx::Rect thumb_quad = scrollbar->ComputeThumbQuadRect();
 
   bool clipped;
-  gfx::PointF scroller_relative_position(
-      GetScrollbarRelativePosition(last_known_pointer_position_, &clipped));
+  gfx::PointF scroller_relative_position(GetScrollbarRelativePosition(
+      scrollbar, last_known_pointer_position_, &clipped));
 
   if (clipped)
     return;
@@ -425,7 +451,7 @@
   int thumb_start = 0;
   int thumb_end = 0;
   int pointer_position = 0;
-  if (orientation == ScrollbarOrientation::VERTICAL) {
+  if (scrollbar->orientation() == ScrollbarOrientation::VERTICAL) {
     thumb_start = thumb_quad.y();
     thumb_end = thumb_quad.y() + thumb_quad.height();
     pointer_position = scroller_relative_position.y();
@@ -451,48 +477,45 @@
   // always has a constant value to animate to (which is '0'. See the function
   // ScrollbarController::StartAutoScrollAnimation).
   if (autoscroll_state_->direction == AutoScrollDirection::AUTOSCROLL_FORWARD) {
-    const float scroll_layer_length =
-        currently_captured_scrollbar_->scroll_layer_length();
+    const float scroll_layer_length = scrollbar->scroll_layer_length();
     if (autoscroll_state_->scroll_layer_length != scroll_layer_length) {
       layer_tree_host_impl_->mutator_host()->ScrollAnimationAbort();
-      StartAutoScrollAnimation(
-          autoscroll_state_->velocity,
-          currently_captured_scrollbar_->scroll_element_id(),
-          autoscroll_state_->pressed_scrollbar_part);
+      StartAutoScrollAnimation(autoscroll_state_->velocity, scrollbar,
+                               autoscroll_state_->pressed_scrollbar_part);
     }
   }
 
   // The animations need to be aborted/restarted based on the pointer location
   // (i.e leaving/entering the track/arrows, reaching the track end etc). The
   // autoscroll_state_ however, needs to be reset on pointer changes.
-  const gfx::RectF scrollbar_part_rect(
-      GetRectForScrollbarPart(autoscroll_state_->pressed_scrollbar_part));
+  const gfx::RectF scrollbar_part_rect(GetRectForScrollbarPart(
+      scrollbar, autoscroll_state_->pressed_scrollbar_part));
   if (!scrollbar_part_rect.Contains(scroller_relative_position)) {
     // Stop animating if pointer moves outside the rect bounds.
     layer_tree_host_impl_->mutator_host()->ScrollAnimationAbort();
   } else if (scrollbar_part_rect.Contains(scroller_relative_position) &&
              !layer_tree_host_impl_->mutator_host()->IsElementAnimating(
-                 currently_captured_scrollbar_->scroll_element_id())) {
+                 scrollbar->scroll_element_id())) {
     // Start animating if pointer re-enters the bounds.
-    StartAutoScrollAnimation(autoscroll_state_->velocity,
-                             currently_captured_scrollbar_->scroll_element_id(),
+    StartAutoScrollAnimation(autoscroll_state_->velocity, scrollbar,
                              autoscroll_state_->pressed_scrollbar_part);
   }
 }
 
 // Helper to calculate the autoscroll velocity.
 float ScrollbarController::InitialDeltaToAutoscrollVelocity(
+    const ScrollbarLayerImplBase* scrollbar,
     gfx::ScrollOffset scroll_offset) const {
-  const float scroll_delta = currently_captured_scrollbar_->orientation() ==
-                                     ScrollbarOrientation::VERTICAL
-                                 ? scroll_offset.y()
-                                 : scroll_offset.x();
+  const float scroll_delta =
+      scrollbar->orientation() == ScrollbarOrientation::VERTICAL
+          ? scroll_offset.y()
+          : scroll_offset.x();
   return scroll_delta * kAutoscrollMultiplier;
 }
 
 void ScrollbarController::StartAutoScrollAnimation(
     const float velocity,
-    ElementId element_id,
+    const ScrollbarLayerImplBase* scrollbar,
     ScrollbarPart pressed_scrollbar_part) {
   // Autoscroll and thumb drag are mutually exclusive. Both can't be active at
   // the same time.
@@ -503,17 +526,14 @@
   // don't need to create any animation for it.
   ScrollTree& scroll_tree =
       layer_tree_host_impl_->active_tree()->property_trees()->scroll_tree;
-  ScrollNode* scroll_node = scroll_tree.FindNodeFromElementId(element_id);
+  ScrollNode* scroll_node =
+      scroll_tree.FindNodeFromElementId(scrollbar->scroll_element_id());
 
   if (!(scroll_node && scrollbar_scroll_is_active_))
     return;
 
   layer_tree_host_impl_->active_tree()->UpdateScrollbarGeometries();
-
-  // TODO(arakeri): The animation needs to be readjusted if the scroller length
-  // changes. Tracked here: crbug.com/972485
-  float scroll_layer_length =
-      currently_captured_scrollbar_->scroll_layer_length();
+  float scroll_layer_length = scrollbar->scroll_layer_length();
 
   gfx::ScrollOffset current_offset =
       scroll_tree.current_scroll_offset(scroll_node->element_id);
@@ -523,8 +543,7 @@
   // value indicates forwards scrolling.
   const float target_offset = velocity < 0 ? 0 : scroll_layer_length;
   const gfx::Vector2dF target_offset_vector =
-      currently_captured_scrollbar_->orientation() ==
-              ScrollbarOrientation::VERTICAL
+      scrollbar->orientation() == ScrollbarOrientation::VERTICAL
           ? gfx::Vector2dF(current_offset.x(), target_offset)
           : gfx::Vector2dF(target_offset, current_offset.y());
 
@@ -560,8 +579,7 @@
     cancelable_autoscroll_task_.reset();
   }
 
-  drag_state_ = base::nullopt;
-  autoscroll_state_ = base::nullopt;
+  ResetState();
   return scroll_result;
 }
 
@@ -580,6 +598,7 @@
 }
 
 int ScrollbarController::GetScrollDeltaForScrollbarPart(
+    const ScrollbarLayerImplBase* scrollbar,
     const ScrollbarPart scrollbar_part,
     const bool shift_modifier) {
   int scroll_delta = 0;
@@ -594,15 +613,14 @@
     case ScrollbarPart::BACK_TRACK:
     case ScrollbarPart::FORWARD_TRACK:
       if (shift_modifier) {
-        scroll_delta = GetScrollDeltaForShiftClick();
+        scroll_delta = GetScrollDeltaForShiftClick(scrollbar);
         break;
       }
       owner_scroll_layer =
           layer_tree_host_impl_->active_tree()->ScrollableLayerByElementId(
-              currently_captured_scrollbar_->scroll_element_id());
+              scrollbar->scroll_element_id());
       viewport_length =
-          currently_captured_scrollbar_->orientation() ==
-                  ScrollbarOrientation::VERTICAL
+          scrollbar->orientation() == ScrollbarOrientation::VERTICAL
               ? owner_scroll_layer->scroll_container_bounds().height()
               : (owner_scroll_layer->scroll_container_bounds().width());
       scroll_delta = viewport_length * kMinFractionToStepWhenPaging;
@@ -627,6 +645,7 @@
 }
 
 gfx::PointF ScrollbarController::GetScrollbarRelativePosition(
+    const ScrollbarLayerImplBase* scrollbar,
     const gfx::PointF position_in_widget,
     bool* clipped) {
   gfx::Transform inverse_screen_space_transform(
@@ -639,7 +658,7 @@
           ? 1.f / layer_tree_host_impl_->active_tree()->device_scale_factor()
           : 1.f;
   gfx::Transform scaled_screen_space_transform(
-      currently_captured_scrollbar_->ScreenSpaceTransform());
+      scrollbar->ScreenSpaceTransform());
   scaled_screen_space_transform.PostScale(scale, scale);
   if (!scaled_screen_space_transform.GetInverse(
           &inverse_screen_space_transform))
@@ -651,60 +670,61 @@
 
 // Determines the ScrollbarPart based on the position_in_widget.
 ScrollbarPart ScrollbarController::GetScrollbarPartFromPointerDown(
+    const ScrollbarLayerImplBase* scrollbar,
     const gfx::PointF position_in_widget) {
   // position_in_widget needs to be transformed and made relative to the
   // scrollbar layer because hit testing assumes layer relative coordinates.
   bool clipped = false;
 
   const gfx::PointF scroller_relative_position(
-      GetScrollbarRelativePosition(position_in_widget, &clipped));
+      GetScrollbarRelativePosition(scrollbar, position_in_widget, &clipped));
 
   if (clipped)
     return ScrollbarPart::NO_PART;
 
-  return currently_captured_scrollbar_->IdentifyScrollbarPart(
-      scroller_relative_position);
+  return scrollbar->IdentifyScrollbarPart(scroller_relative_position);
 }
 
 // Determines the corresponding rect for the given scrollbar part.
 gfx::Rect ScrollbarController::GetRectForScrollbarPart(
+    const ScrollbarLayerImplBase* scrollbar,
     const ScrollbarPart scrollbar_part) {
   if (scrollbar_part == ScrollbarPart::BACK_BUTTON)
-    return currently_captured_scrollbar_->BackButtonRect();
+    return scrollbar->BackButtonRect();
   if (scrollbar_part == ScrollbarPart::FORWARD_BUTTON)
-    return currently_captured_scrollbar_->ForwardButtonRect();
+    return scrollbar->ForwardButtonRect();
   if (scrollbar_part == ScrollbarPart::BACK_TRACK)
-    return currently_captured_scrollbar_->BackTrackRect();
+    return scrollbar->BackTrackRect();
   if (scrollbar_part == ScrollbarPart::FORWARD_TRACK)
-    return currently_captured_scrollbar_->ForwardTrackRect();
+    return scrollbar->ForwardTrackRect();
   return gfx::Rect(0, 0);
 }
 
 // Determines the scroll offsets based on the ScrollbarPart and the scrollbar
 // orientation.
 gfx::ScrollOffset ScrollbarController::GetScrollOffsetForScrollbarPart(
+    const ScrollbarLayerImplBase* scrollbar,
     const ScrollbarPart scrollbar_part,
-    const ScrollbarOrientation orientation,
     const bool shift_modifier) {
   float scroll_delta =
-      GetScrollDeltaForScrollbarPart(scrollbar_part, shift_modifier);
+      GetScrollDeltaForScrollbarPart(scrollbar, scrollbar_part, shift_modifier);
 
   // See CreateScrollStateForGesture for more information on how these values
   // will be interpreted.
   if (scrollbar_part == ScrollbarPart::BACK_BUTTON) {
-    return orientation == ScrollbarOrientation::VERTICAL
+    return scrollbar->orientation() == ScrollbarOrientation::VERTICAL
                ? gfx::ScrollOffset(0, -scroll_delta)   // Up arrow
                : gfx::ScrollOffset(-scroll_delta, 0);  // Left arrow
   } else if (scrollbar_part == ScrollbarPart::FORWARD_BUTTON) {
-    return orientation == ScrollbarOrientation::VERTICAL
+    return scrollbar->orientation() == ScrollbarOrientation::VERTICAL
                ? gfx::ScrollOffset(0, scroll_delta)   // Down arrow
                : gfx::ScrollOffset(scroll_delta, 0);  // Right arrow
   } else if (scrollbar_part == ScrollbarPart::BACK_TRACK) {
-    return orientation == ScrollbarOrientation::VERTICAL
+    return scrollbar->orientation() == ScrollbarOrientation::VERTICAL
                ? gfx::ScrollOffset(0, -scroll_delta)   // Track click up
                : gfx::ScrollOffset(-scroll_delta, 0);  // Track click left
   } else if (scrollbar_part == ScrollbarPart::FORWARD_TRACK) {
-    return orientation == ScrollbarOrientation::VERTICAL
+    return scrollbar->orientation() == ScrollbarOrientation::VERTICAL
                ? gfx::ScrollOffset(0, scroll_delta)   // Track click down
                : gfx::ScrollOffset(scroll_delta, 0);  // Track click right
   }
diff --git a/cc/input/scrollbar_controller.h b/cc/input/scrollbar_controller.h
index e1b13dc2..99fbf95 100644
--- a/cc/input/scrollbar_controller.h
+++ b/cc/input/scrollbar_controller.h
@@ -32,13 +32,11 @@
   // needed to determine whether we should set up the autoscrolling in the
   // forwards or the backwards direction.
   void StartAutoScrollAnimation(float velocity,
-                                ElementId element_id,
+                                const ScrollbarLayerImplBase* scrollbar,
                                 ScrollbarPart pressed_scrollbar_part);
   bool ScrollbarScrollIsActive() { return scrollbar_scroll_is_active_; }
-  ScrollbarOrientation orientation() {
-    return currently_captured_scrollbar_->orientation();
-  }
-
+  void DidUnregisterScrollbar(ElementId element_id);
+  ScrollbarLayerImplBase* ScrollbarLayer();
   void WillBeginImplFrame();
 
  private:
@@ -74,44 +72,61 @@
     float scroll_position_at_start_;
   };
 
+  struct CC_EXPORT CapturedScrollbarMetadata {
+    // Needed to retrieve the ScrollbarSet for a particular ElementId.
+    ElementId scroll_element_id;
+
+    // Needed to identify the correct scrollbar from the ScrollbarSet.
+    ScrollbarOrientation orientation;
+  };
+
   // Returns the DSF based on whether use-zoom-for-dsf is enabled.
   float ScreenSpaceScaleFactor() const;
 
   // Helper to convert scroll offset to autoscroll velocity.
-  float InitialDeltaToAutoscrollVelocity(gfx::ScrollOffset scroll_offset) const;
+  float InitialDeltaToAutoscrollVelocity(
+      const ScrollbarLayerImplBase* scrollbar,
+      gfx::ScrollOffset scroll_offset) const;
 
   // Returns the hit tested ScrollbarPart based on the position_in_widget.
   ScrollbarPart GetScrollbarPartFromPointerDown(
+      const ScrollbarLayerImplBase* scrollbar,
       const gfx::PointF position_in_widget);
 
   // Returns scroll offsets based on which ScrollbarPart was hit tested.
   gfx::ScrollOffset GetScrollOffsetForScrollbarPart(
+      const ScrollbarLayerImplBase* scrollbar,
       const ScrollbarPart scrollbar_part,
-      const ScrollbarOrientation orientation,
       const bool shift_modifier);
 
   // Returns the rect for the ScrollbarPart.
-  gfx::Rect GetRectForScrollbarPart(const ScrollbarPart scrollbar_part);
+  gfx::Rect GetRectForScrollbarPart(const ScrollbarLayerImplBase* scrollbar,
+                                    const ScrollbarPart scrollbar_part);
 
   LayerImpl* GetLayerHitByPoint(const gfx::PointF position_in_widget);
-  int GetScrollDeltaForScrollbarPart(const ScrollbarPart scrollbar_part,
+  int GetScrollDeltaForScrollbarPart(const ScrollbarLayerImplBase* scrollbar,
+                                     const ScrollbarPart scrollbar_part,
                                      const bool shift_modifier);
 
   // Makes position_in_widget relative to the scrollbar.
-  gfx::PointF GetScrollbarRelativePosition(const gfx::PointF position_in_widget,
-                                           bool* clipped);
+  gfx::PointF GetScrollbarRelativePosition(
+      const ScrollbarLayerImplBase* scrollbar,
+      const gfx::PointF position_in_widget,
+      bool* clipped);
 
   // Decides if the scroller should snap to the offset that it was originally at
   // (i.e the offset before the thumb drag).
-  bool SnapToDragOrigin(const gfx::PointF pointer_position_in_widget);
+  bool SnapToDragOrigin(const ScrollbarLayerImplBase* scrollbar,
+                        const gfx::PointF pointer_position_in_widget);
 
   // Decides whether a track autoscroll should be aborted (or restarted) due to
   // the thumb reaching the pointer or the pointer leaving (or re-entering) the
   // bounds.
   void RecomputeAutoscrollStateIfNeeded();
+  void ResetState();
 
   // Shift + click is expected to do a non-animated jump to a certain offset.
-  float GetScrollDeltaForShiftClick();
+  float GetScrollDeltaForShiftClick(const ScrollbarLayerImplBase* scrollbar);
 
   // Determines if the delta needs to be animated.
   ui::input_types::ScrollGranularity Granularity(
@@ -121,25 +136,29 @@
   // Calculates the scroll_offset based on position_in_widget and
   // drag_anchor_relative_to_thumb_.
   gfx::ScrollOffset GetScrollOffsetForDragPosition(
+      const ScrollbarLayerImplBase* scrollbar,
       const gfx::PointF pointer_position_in_widget);
 
   // Returns a Vector2dF for position_in_widget relative to the scrollbar thumb.
-  gfx::Vector2dF GetThumbRelativePoint(const gfx::PointF position_in_widget);
+  gfx::Vector2dF GetThumbRelativePoint(const ScrollbarLayerImplBase* scrollbar,
+                                       const gfx::PointF position_in_widget);
 
   // Returns the ratio of the scroller length to the scrollbar length. This is
   // needed to scale the scroll delta for thumb drag.
-  float GetScrollerToScrollbarRatio();
+  float GetScrollerToScrollbarRatio(const ScrollbarLayerImplBase* scrollbar);
   LayerTreeHostImpl* layer_tree_host_impl_;
 
   // Used to safeguard against firing GSE without firing GSB and GSU. For
   // example, if mouse is pressed outside the scrollbar but released after
   // moving inside the scrollbar, a GSE will get queued up without this flag.
   bool scrollbar_scroll_is_active_;
-  const ScrollbarLayerImplBase* currently_captured_scrollbar_;
 
   // This is relative to the RenderWidget's origin.
   gfx::PointF last_known_pointer_position_;
 
+  // Set only while interacting with the scrollbar (eg: drag, click etc).
+  base::Optional<CapturedScrollbarMetadata> captured_scrollbar_metadata_;
+
   // Holds information pertaining to autoscrolling. This member is empty if and
   // only if an autoscroll is *not* in progress.
   base::Optional<AutoScrollState> autoscroll_state_;
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index 063e39f..5aa9981 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -1213,18 +1213,14 @@
     layer_tree_host_->property_trees()->needs_rebuild = true;
 }
 
-#if DCHECK_IS_ON()
 std::string Layer::DebugName() const {
   return inputs_.client ? inputs_.client->LayerDebugName(this) : "";
 }
-#endif
 
 std::string Layer::ToString() const {
   return base::StringPrintf(
       "layer_id: %d\n"
-#if DCHECK_IS_ON()
       "  name: %s\n"
-#endif
       "  Bounds: %s\n"
       "  ElementId: %s\n"
       "  OffsetToTransformParent: %s\n"
@@ -1235,9 +1231,7 @@
       "  scroll_tree_index: %d\n"
       "  transform_tree_index: %d\n",
       id(),
-#if DCHECK_IS_ON()
       DebugName().c_str(),
-#endif
       bounds().ToString().c_str(), element_id().ToString().c_str(),
       offset_to_transform_parent().ToString().c_str(),
       position().ToString().c_str(), scrollable(), clip_tree_index(),
diff --git a/cc/layers/layer.h b/cc/layers/layer.h
index 054f388..d4654c48 100644
--- a/cc/layers/layer.h
+++ b/cc/layers/layer.h
@@ -689,10 +689,8 @@
     return should_check_backface_visibility_;
   }
 
-#if DCHECK_IS_ON()
   // For debugging, containing information about the associated DOM, etc.
   std::string DebugName() const;
-#endif
 
   std::string ToString() const;
 
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index add3fa4..6aaed1eb 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -1051,6 +1051,8 @@
         ::switches::kUseVulkan,
         use_gpu ? ::switches::kVulkanImplementationNameNative
                 : ::switches::kVulkanImplementationNameSwiftshader);
+    command_line->AppendSwitchASCII(
+        ::switches::kGrContextType, ::switches::kGrContextTypeVulkan);
   }
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
diff --git a/cc/test/pixel_test.cc b/cc/test/pixel_test.cc
index aedf872..dbcdcd03 100644
--- a/cc/test/pixel_test.cc
+++ b/cc/test/pixel_test.cc
@@ -260,6 +260,8 @@
         ::switches::kUseVulkan,
         use_gpu ? ::switches::kVulkanImplementationNameNative
                 : ::switches::kVulkanImplementationNameSwiftshader);
+    command_line->AppendSwitchASCII(
+        ::switches::kGrContextType, ::switches::kGrContextTypeVulkan);
   }
   // Set up the GPU service.
   gpu_service_holder_ = viz::TestGpuServiceHolder::GetInstance();
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 11b0fd4d..49782ad3 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -5321,9 +5321,10 @@
                                                        scrollbar_opacity);
 }
 
-void LayerTreeHostImpl::UnregisterScrollbarAnimationController(
+void LayerTreeHostImpl::DidUnregisterScrollbarLayer(
     ElementId scroll_element_id) {
   scrollbar_animation_controllers_.erase(scroll_element_id);
+  scrollbar_controller_->DidUnregisterScrollbar(scroll_element_id);
 }
 
 ScrollbarAnimationController*
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 4242cd1..6d810d4 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -448,7 +448,7 @@
 
   void RegisterScrollbarAnimationController(ElementId scroll_element_id,
                                             float initial_opacity);
-  void UnregisterScrollbarAnimationController(ElementId scroll_element_id);
+  void DidUnregisterScrollbarLayer(ElementId scroll_element_id);
   ScrollbarAnimationController* ScrollbarAnimationControllerForElementId(
       ElementId scroll_element_id) const;
   void FlashAllScrollbars(bool did_scroll);
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 986eca85..c468bc24 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -12392,7 +12392,7 @@
   // scrollbar_2_animation_controller, then mouse up should not cause crash.
   host_impl_->MouseMoveAt(gfx::Point(40, 150));
   host_impl_->MouseDown(gfx::PointF(40, 150), /*shift_modifier*/ false);
-  host_impl_->UnregisterScrollbarAnimationController(root_scroll->element_id());
+  host_impl_->DidUnregisterScrollbarLayer(root_scroll->element_id());
   host_impl_->MouseUp(gfx::PointF(40, 150));
 }
 
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index 27812c1..a3cbca6 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -1918,7 +1918,7 @@
       scrollbar_ids.vertical == Layer::INVALID_ID) {
     element_id_to_scrollbar_layer_ids_.erase(scroll_element_id);
     if (IsActiveTree()) {
-      host_impl_->UnregisterScrollbarAnimationController(scroll_element_id);
+      host_impl_->DidUnregisterScrollbarLayer(scroll_element_id);
     }
   }
 }
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 63f3ee4b..c08b023d 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -18,6 +18,7 @@
 import("//chrome/android/feed/feed_java_sources.gni")
 import("//chrome/android/modules/chrome_feature_module_tmpl.gni")
 import("//chrome/android/monochrome_android_manifest_jinja_variables.gni")
+import("//chrome/browser/share/android/java_sources.gni")
 import("//chrome/chrome_paks.gni")
 import("//chrome/common/features.gni")
 import("//chrome/process_version_rc_template.gni")  # For branding_file_path.
@@ -478,6 +479,10 @@
   ]
 
   processor_args_javac = [ "dagger.fastInit=enabled" ]
+
+  # TODO(gayane): Instead of adding source files, add it as a separate
+  # dependency when circular deps is resolved.
+  java_files += share_java_sources
 }
 
 generate_locale_config_srcjar("chrome_locale_config") {
@@ -811,6 +816,7 @@
     "//components/invalidation/impl:java",
     "//components/invalidation/impl:javatests",
     "//components/location/android:location_java",
+    "//components/metrics:metrics_java",
     "//components/minidump_uploader:minidump_uploader_java",
     "//components/minidump_uploader:minidump_uploader_javatests",
     "//components/navigation_interception/android:navigation_interception_java",
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index b1dc7d3e..b5a7857c 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -870,6 +870,23 @@
             </intent-filter>
           </activity>
 
+          <activity
+            android:name="org.chromium.chrome.browser.share.qrcode.QrCodeShareActivity"
+            android:icon="@drawable/ic_launcher"
+            android:label="@string/qr_code_share_icon_label"
+            android:enabled="false"
+            android:excludeFromRecents="true"
+            android:exported="true"
+            android:noHistory="true"
+            android:theme="@android:style/Theme.NoDisplay"
+            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" >
+            <intent-filter>
+                <action android:name="android.intent.action.SEND" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:mimeType="text/plain" />
+            </intent-filter>
+          </activity>
+
         <!-- Activity for dispatching intents to Instant Apps. -->
         <activity
             android:name="org.chromium.chrome.browser.instantapps.AuthenticatedProxyActivity"
diff --git a/chrome/android/java/DEPS b/chrome/android/java/DEPS
index b95d98e..3353989f 100644
--- a/chrome/android/java/DEPS
+++ b/chrome/android/java/DEPS
@@ -2,6 +2,7 @@
   "-chrome/android/features/keyboard_accessory/internal",
 
   "+chrome/browser/android/thin_webview/java",
+  "+chrome/browser/share/android",
   "+chrome/browser/ui/android/widget",
   "+chrome/browser/download/android/java",
   "+chrome/browser/util/android/java",
diff --git a/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected b/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected
index 90ad9b3..0a3e31e 100644
--- a/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected
+++ b/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected
@@ -181,6 +181,22 @@
         android:excludeFromRecents="true"
         android:exported="true"
         android:icon="@drawable/ic_launcher"
+        android:label="@string/qr_code_share_icon_label"
+        android:name="org.chromium.chrome.browser.share.qrcode.QrCodeShareActivity"
+        android:noHistory="true"
+        android:theme="@android:style/Theme.NoDisplay">
+      <intent-filter>
+        <action android:name="android.intent.action.SEND"/>
+        <category android:name="android.intent.category.DEFAULT"/>
+        <data android:mimeType="text/plain"/>
+      </intent-filter>
+    </activity>
+    <activity
+        android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
+        android:enabled="false"
+        android:excludeFromRecents="true"
+        android:exported="true"
+        android:icon="@drawable/ic_launcher"
         android:label="@string/send_tab_to_self_share_activity_title"
         android:name="org.chromium.chrome.browser.send_tab_to_self.SendTabToSelfShareActivity"
         android:noHistory="true"
diff --git a/chrome/android/java/res/values-v26/styles.xml b/chrome/android/java/res/values-v26/styles.xml
index 0ca9d99..c227823b 100644
--- a/chrome/android/java/res/values-v26/styles.xml
+++ b/chrome/android/java/res/values-v26/styles.xml
@@ -8,10 +8,5 @@
         <item name="android:statusBarColor">@color/modern_primary_color</item>
         <item name="android:windowLightStatusBar">@bool/window_light_status_bar</item>
     </style>
-
-    <style name="Theme.Chromium.Preferences" parent="Base.V21.Theme.Chromium.Preferences">
-        <item name="android:statusBarColor">@color/modern_primary_color</item>
-        <item name="android:windowLightStatusBar">@bool/window_light_status_bar</item>
-    </style>
 </resources>
 
diff --git a/chrome/android/java/res/values-v28/styles.xml b/chrome/android/java/res/values-v28/styles.xml
new file mode 100644
index 0000000..0f2fe63
--- /dev/null
+++ b/chrome/android/java/res/values-v28/styles.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2019 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file. -->
+
+<resources>
+    <!-- The windowLightStatusBar attribute was added in API 23, but we avoid using it via XML prior
+         to 28 due to: https://crbug.com/884144 and https://crbug.com/1014844 -->
+    <style name="Theme.Chromium.Preferences" parent="Base.V21.Theme.Chromium.Preferences">
+        <item name="android:statusBarColor">@color/modern_primary_color</item>
+        <item name="android:windowLightStatusBar">@bool/window_light_status_bar</item>
+    </style>
+</resources>
+
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index f5724cb..551961fb 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -254,7 +254,16 @@
          There are two possible layouts for splash screens, which is chosen based on whether an
          icon was auto-generated by Chrome and whether the icon is bigger than a threshold. -->
     <dimen name="webapp_home_screen_icon_size">48dp</dimen>
-    <dimen name="webapk_adaptive_icon_size">108dp</dimen>
+    <!-- The Android Spec
+         (https://developer.android.com/guide/practices/ui_guidelines/icon_design_adaptive)
+         states that the adaptive icon should be 108dp. It also states that the safe zone should
+         be a circle with diameter being ~61% (66dp/108dp) of width.
+         The Web Spec (https://www.w3.org/TR/appmanifest/#icon-masks), however, states that the
+         safe zone should be a circle with diameter being 80% of width.
+         To bridge the difference in safe zone size percentage, we have to add a 15% padding on
+         each size of orignal image. As a result, the ideal adaptive icon size for WebAPK is
+         83dp -->
+    <dimen name="webapk_adaptive_icon_size">83dp</dimen>
 
     <dimen name="webapk_badge_icon_size">24dp</dimen>
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
index 52788e2..de6da0a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -319,6 +319,7 @@
     public static final String SERVICE_WORKER_PAYMENT_APPS = "ServiceWorkerPaymentApps";
     public static final String SETTINGS_MODERN_STATUS_BAR = "SettingsModernStatusBar";
     public static final String SHARED_CLIPBOARD_UI = "SharedClipboardUI";
+    public static final String SHARING_QR_CODE_ANDROID = "SharingQrCodeAndroid";
     public static final String SHOPPING_ASSIST = "ShoppingAssist";
     public static final String SHOW_TRUSTED_PUBLISHER_URL = "ShowTrustedPublisherURL";
     public static final String SPANNABLE_INLINE_AUTOCOMPLETE = "SpannableInlineAutocomplete";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/Preferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/Preferences.java
index f05a178..088f15a4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/Preferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/Preferences.java
@@ -292,9 +292,8 @@
      * Set device status bar to match the activity background color, if supported.
      */
     private void setStatusBarColor() {
-        // On O+, the status bar color is already set via the XML theme. We avoid setting status bar
-        // color via XML pre-O due to: https://crbug.com/884144.
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) return;
+        // On P+, the status bar color is set via the XML theme.
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) return;
 
         // Kill switch included due to past crashes when programmatically setting status bar color:
         // https://crbug.com/880694.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareMenuActionHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareMenuActionHandler.java
index a5c5fbd..65c81d3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareMenuActionHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareMenuActionHandler.java
@@ -16,6 +16,7 @@
 import org.chromium.chrome.browser.offlinepages.OfflinePageUtils;
 import org.chromium.chrome.browser.printing.PrintShareActivity;
 import org.chromium.chrome.browser.send_tab_to_self.SendTabToSelfShareActivity;
+import org.chromium.chrome.browser.share.qrcode.QrCodeShareActivity;
 import org.chromium.chrome.browser.tab.SadTab;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.util.ChromeFileProvider;
@@ -79,6 +80,10 @@
            classesToEnable.add(SendTabToSelfShareActivity.class);
         }
 
+        if (QrCodeShareActivity.featureIsAvailable()) {
+            classesToEnable.add(QrCodeShareActivity.class);
+        }
+
         if (!classesToEnable.isEmpty()) {
             OptionalShareTargetsManager.getInstance().enableOptionalShareActivities(activity,
                     classesToEnable,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/IdentityDiscController.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/IdentityDiscController.java
index 4e810da..0d571157 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/IdentityDiscController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/IdentityDiscController.java
@@ -22,6 +22,7 @@
 import org.chromium.chrome.browser.signin.ProfileDataCache;
 import org.chromium.chrome.browser.signin.SigninManager;
 import org.chromium.chrome.browser.sync.ProfileSyncService;
+import org.chromium.components.feature_engagement.EventConstants;
 import org.chromium.components.feature_engagement.FeatureConstants;
 import org.chromium.components.feature_engagement.Tracker;
 import org.chromium.components.signin.ChromeSigninController;
@@ -132,7 +133,7 @@
     private void showIdentityDisc(String accountName) {
         Drawable profileImage = mProfileDataCache.getProfileDataOrDefault(accountName).getImage();
         mToolbarManager.enableExperimentalButton(view -> {
-            RecordUserAction.record("MobileToolbarIdentityDiscTap");
+            recordIdentityDiscUsed();
             PreferencesLauncher.launchSettingsPage(mContext, SyncAndServicesPreferences.class);
         }, profileImage, R.string.accessibility_toolbar_btn_identity_disc);
     }
@@ -208,4 +209,15 @@
                 R.string.iph_identity_disc_accessibility_text,
                 () -> { tracker.dismissed(FeatureConstants.IDENTITY_DISC_FEATURE); });
     }
+
+    /**
+     * Records IdentityDisc usage with feature engagement tracker. This signal can be used to decide
+     * whether to show in-product help.
+     */
+    private void recordIdentityDiscUsed() {
+        Profile profile = Profile.getLastUsedProfile();
+        Tracker tracker = TrackerFactory.getTrackerForProfile(profile);
+        tracker.notifyEvent(EventConstants.IDENTITY_DISC_USED);
+        RecordUserAction.record("MobileToolbarIdentityDiscTap");
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/IncognitoSwitchViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/IncognitoSwitchViewBinder.java
index 58ca5bdb..8f1d8e23e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/IncognitoSwitchViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/IncognitoSwitchViewBinder.java
@@ -37,6 +37,11 @@
                     : R.string.accessibility_tab_switcher_standard_stack_selected;
             incognitoSwitch.announceForAccessibility(
                     incognitoSwitch.getResources().getString(stackAnnouncementId));
+            final int descriptionResId = isIncognito
+                    ? R.string.accessibility_tabstrip_btn_incognito_toggle_incognito
+                    : R.string.accessibility_tabstrip_btn_incognito_toggle_standard;
+            incognitoSwitch.setContentDescription(
+                    incognitoSwitch.getResources().getString(descriptionResId));
         } else if (IS_VISIBLE == propertyKey) {
             incognitoSwitch.setVisibility(model.get(IS_VISIBLE) ? View.VISIBLE : View.GONE);
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java
index 00663b64..ac492bc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java
@@ -96,7 +96,11 @@
 
             @Override
             public void onDestroyed(Tab tab) {
-                if (mLastActivityTab == tab) mLastActivityTab = null;
+                if (mLastActivityTab != tab) return;
+                mLastActivityTab = null;
+
+                // Remove the suppressed sheet if its lifecycle is tied to the tab being destroyed.
+                clearRequestsAndHide();
             }
         };
 
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 8f9c72e..e44e11d 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -3319,13 +3319,13 @@
       </message>
 
       <!-- Undo Bar -->
-      <message name="IDS_UNDO_BAR_CLOSE_MESSAGE" desc="Message shown when you can undo a tab close action.">
+      <message name="IDS_UNDO_BAR_CLOSE_MESSAGE" desc="Message shown when you can undo a tab close action. This message is short for a sentence &quot;TAB_TITLE has been closed&quot;, not a noun &quot;TAB_TITLE, which is a closed tab&quot;.">
         Closed <ph name="TAB_TITLE">%1$s<ex>YouTube</ex></ph>
       </message>
       <message name="IDS_UNDO_BAR_CLOSE_ALL_MESSAGE" desc="Message shown when you can undo a close all tabs action.">
         <ph name="TAB_COUNT">%1$s<ex>3</ex></ph> tabs closed
       </message>
-      <message name="IDS_DELETE_MESSAGE" desc="Message shown or announced when an item has been deleted.">
+      <message name="IDS_DELETE_MESSAGE" desc="Message shown or announced when an item has been deleted. This message is short for a sentence &quot;ITEM_TITLE has been deleted&quot;, not a noun &quot;ITEM_TITLE, which is a deleted item&quot;.">
         Deleted <ph name="ITEM_TITLE">%1$s<ex>YouTube</ex></ph>
       </message>
       <message name="IDS_UNDO_BAR_MULTIPLE_DELETE_MESSAGE" desc="Message shown when you can undo several bookmark delete actions.">
@@ -3988,6 +3988,11 @@
         Extra ICU
       </message>
 
+      <!-- QR Code -->
+      <message name="IDS_QR_CODE_SHARE_ICON_LABEL" desc="Icon label for sharing qith QR Code activity.">
+        QR Code
+      </message>
+
     </messages>
   </release>
 </grit>
diff --git a/chrome/android/java/strings/android_chrome_strings_grd/IDS_DELETE_MESSAGE.png.sha1 b/chrome/android/java/strings/android_chrome_strings_grd/IDS_DELETE_MESSAGE.png.sha1
new file mode 100644
index 0000000..ff31d40
--- /dev/null
+++ b/chrome/android/java/strings/android_chrome_strings_grd/IDS_DELETE_MESSAGE.png.sha1
@@ -0,0 +1 @@
+7c9381271c9468bb3ba325db05aaddc2f2754b31
\ No newline at end of file
diff --git a/chrome/android/java/strings/android_chrome_strings_grd/IDS_QR_CODE_SHARE_ICON_LABEL.png.sha1 b/chrome/android/java/strings/android_chrome_strings_grd/IDS_QR_CODE_SHARE_ICON_LABEL.png.sha1
new file mode 100644
index 0000000..3e577ec
--- /dev/null
+++ b/chrome/android/java/strings/android_chrome_strings_grd/IDS_QR_CODE_SHARE_ICON_LABEL.png.sha1
@@ -0,0 +1 @@
+4cd4c6bd343baba8d302ee5fc63b84df556119a4
\ No newline at end of file
diff --git a/chrome/android/java/strings/android_chrome_strings_grd/IDS_UNDO_BAR_CLOSE_MESSAGE.png.sha1 b/chrome/android/java/strings/android_chrome_strings_grd/IDS_UNDO_BAR_CLOSE_MESSAGE.png.sha1
new file mode 100644
index 0000000..0290ceb
--- /dev/null
+++ b/chrome/android/java/strings/android_chrome_strings_grd/IDS_UNDO_BAR_CLOSE_MESSAGE.png.sha1
@@ -0,0 +1 @@
+bcb0e0e95ee9be840733608d1b43ee5177f502d9
\ No newline at end of file
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/BackgroundMetricsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/BackgroundMetricsTest.java
index 16091f9..29f0d888c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/BackgroundMetricsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/BackgroundMetricsTest.java
@@ -23,6 +23,7 @@
 import org.chromium.chrome.browser.init.EmptyBrowserParts;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.components.metrics.MetricsSwitches;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
 
@@ -33,7 +34,7 @@
  */
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.
-Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, "force-enable-metrics-reporting"})
+Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, MetricsSwitches.FORCE_ENABLE_METRICS_REPORTING})
 public final class BackgroundMetricsTest {
     // Note: these rules might conflict and so calls to their methods must be handled carefully.
     @Rule
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/test/MockCertVerifierRuleAndroid.java b/chrome/android/javatests/src/org/chromium/chrome/browser/test/MockCertVerifierRuleAndroid.java
index 657808a..230a0395 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/test/MockCertVerifierRuleAndroid.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/test/MockCertVerifierRuleAndroid.java
@@ -25,17 +25,26 @@
     @Override
     protected void before() {
         mNativeLibraryTestRule.loadNativeLibraryNoBrowserProcess();
-        mNativePtr = nativeInit(mResult);
+        mNativePtr = nativeInit();
+        nativeSetResult(mNativePtr, mResult);
         nativeSetUp(mNativePtr);
     }
 
+    public void setResult(int result) {
+        mResult = result;
+        if (mNativePtr != 0) {
+            nativeSetResult(mNativePtr, result);
+        }
+    }
+
     @Override
     protected void after() {
         nativeTearDown(mNativePtr);
         mNativePtr = 0;
     }
 
-    private static native long nativeInit(int result);
+    private static native long nativeInit();
     private native void nativeSetUp(long nativeMockCertVerifierRuleAndroid);
+    private native void nativeSetResult(long nativeMockCertVerifierRuleAndroid, int result);
     private native void nativeTearDown(long nativeMockCertVerifierRuleAndroid);
 }
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 42b899b..1bdf5f97 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -672,6 +672,22 @@
     "media/cast_mirroring_service_host.h",
     "media/cast_remoting_connector.cc",
     "media/cast_remoting_connector.h",
+    "media/history/media_history_engagement_table.cc",
+    "media/history/media_history_engagement_table.h",
+    "media/history/media_history_keyed_service.cc",
+    "media/history/media_history_keyed_service.h",
+    "media/history/media_history_keyed_service_factory.cc",
+    "media/history/media_history_keyed_service_factory.h",
+    "media/history/media_history_origin_table.cc",
+    "media/history/media_history_origin_table.h",
+    "media/history/media_history_playback_table.cc",
+    "media/history/media_history_playback_table.h",
+    "media/history/media_history_store.cc",
+    "media/history/media_history_store.h",
+    "media/history/media_history_table_base.cc",
+    "media/history/media_history_table_base.h",
+    "media/history/media_player_watchtime.cc",
+    "media/history/media_player_watchtime.h",
     "media/media_access_handler.cc",
     "media/media_access_handler.h",
     "media/media_device_id_salt.cc",
@@ -2855,6 +2871,7 @@
       "//chrome/browser/android/thin_webview/internal",
       "//chrome/browser/android/webapk:proto",
       "//chrome/browser/notifications/scheduler/public",
+      "//chrome/browser/share",
       "//chrome/services/media_gallery_util/public/cpp",
       "//components/autofill_assistant/browser",
       "//components/cdm/browser",
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index 9a3c136..d597ef2 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -13,6 +13,7 @@
 #include "base/metrics/field_trial_params.h"
 #include "base/stl_util.h"
 #include "chrome/android/chrome_jni_headers/ChromeFeatureList_jni.h"
+#include "chrome/browser/share/features.h"
 #include "chrome/browser/sharing/shared_clipboard/feature_flags.h"
 #include "chrome/common/chrome_features.h"
 #include "components/autofill/core/common/autofill_features.h"
@@ -169,6 +170,7 @@
     &kServiceManagerForDownload,
     &kSettingsModernStatusBar,
     &kSharedClipboardUI,
+    &kSharingQrCodeAndroid,
     &kShoppingAssist,
     &kSpannableInlineAutocomplete,
     &kSpecialLocaleWrapper,
diff --git a/chrome/browser/android/metrics/BUILD.gn b/chrome/browser/android/metrics/BUILD.gn
index 8016d2d..f4698a6 100644
--- a/chrome/browser/android/metrics/BUILD.gn
+++ b/chrome/browser/android/metrics/BUILD.gn
@@ -43,6 +43,7 @@
       "//base:base_java_test_support",
       "//chrome/android:chrome_java",
       "//chrome/test/android:chrome_java_test_support",
+      "//components/metrics:metrics_java",
       "//content/public/test/android:content_java_test_support",
       "//third_party/android_support_test_runner:rules_java",
       "//third_party/android_support_test_runner:runner_java",
diff --git a/chrome/browser/android/metrics/javatests/src/org/chromium/chrome/browser/metrics/UkmTest.java b/chrome/browser/android/metrics/javatests/src/org/chromium/chrome/browser/metrics/UkmTest.java
index 8026c3d..96f91e4 100644
--- a/chrome/browser/android/metrics/javatests/src/org/chromium/chrome/browser/metrics/UkmTest.java
+++ b/chrome/browser/android/metrics/javatests/src/org/chromium/chrome/browser/metrics/UkmTest.java
@@ -25,6 +25,7 @@
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.util.ChromeTabUtils;
+import org.chromium.components.metrics.MetricsSwitches;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 
 /**
@@ -32,7 +33,7 @@
  */
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.
-Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, "force-enable-metrics-reporting"})
+Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, MetricsSwitches.FORCE_ENABLE_METRICS_REPORTING})
 public class UkmTest {
     @Rule
     public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
diff --git a/chrome/browser/android/ssl/mock_cert_verifier_rule_android.cc b/chrome/browser/android/ssl/mock_cert_verifier_rule_android.cc
index b7f5787..2d4fe60a 100644
--- a/chrome/browser/android/ssl/mock_cert_verifier_rule_android.cc
+++ b/chrome/browser/android/ssl/mock_cert_verifier_rule_android.cc
@@ -7,11 +7,16 @@
 #include "base/command_line.h"
 #include "chrome/android/test_support_jni_headers/MockCertVerifierRuleAndroid_jni.h"
 
-jlong JNI_MockCertVerifierRuleAndroid_Init(JNIEnv* env, jint result) {
-  return reinterpret_cast<intptr_t>(new MockCertVerifierRuleAndroid(result));
+jlong JNI_MockCertVerifierRuleAndroid_Init(JNIEnv* env) {
+  return reinterpret_cast<intptr_t>(new MockCertVerifierRuleAndroid());
 }
 
-MockCertVerifierRuleAndroid::MockCertVerifierRuleAndroid(int result) {
+MockCertVerifierRuleAndroid::MockCertVerifierRuleAndroid() = default;
+
+void MockCertVerifierRuleAndroid::SetResult(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& obj,
+    int result) {
   mock_cert_verifier_.mock_cert_verifier()->set_default_result(result);
 }
 
diff --git a/chrome/browser/android/ssl/mock_cert_verifier_rule_android.h b/chrome/browser/android/ssl/mock_cert_verifier_rule_android.h
index 5b286e1b..2d5dcd7 100644
--- a/chrome/browser/android/ssl/mock_cert_verifier_rule_android.h
+++ b/chrome/browser/android/ssl/mock_cert_verifier_rule_android.h
@@ -12,8 +12,12 @@
 // Enables tests to force certificate verification results.
 class MockCertVerifierRuleAndroid {
  public:
-  // |result| is the certificate verification result to force.
-  MockCertVerifierRuleAndroid(int result);
+  MockCertVerifierRuleAndroid();
+
+  // Sets the certificate verification result to force.
+  void SetResult(JNIEnv* env,
+                 const base::android::JavaParamRef<jobject>& obj,
+                 int result);
 
   void SetUp(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
   void TearDown(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
diff --git a/chrome/browser/autofill/autofill_browsertest.cc b/chrome/browser/autofill/autofill_browsertest.cc
index 2e976262..a2be371 100644
--- a/chrome/browser/autofill/autofill_browsertest.cc
+++ b/chrome/browser/autofill/autofill_browsertest.cc
@@ -41,12 +41,14 @@
 #include "components/autofill/core/common/autofill_features.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/test/accessibility_notification_waiter.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_renderer_host.h"
 #include "content/public/test/test_utils.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/events/keycodes/keyboard_codes.h"
 
 using base::ASCIIToUTF16;
@@ -556,4 +558,170 @@
             static_cast<int>(personal_data_manager()->GetProfiles().size()));
 }
 
+// Accessibility Tests //
+class AutofillAccessibilityTest : public AutofillTest {
+ protected:
+  AutofillAccessibilityTest() {}
+
+  // Returns true if kAutofillAvailable state is present AND  kAutoComplete
+  // string attribute is missing; only one should be set at any given time.
+  // Returns false otherwise.
+  bool AutofillIsAvailable(const ui::AXNodeData& data) {
+    if (data.HasState(ax::mojom::State::kAutofillAvailable) &&
+        !data.HasStringAttribute(ax::mojom::StringAttribute::kAutoComplete)) {
+      return true;
+    }
+    return false;
+  }
+
+  // Returns true if kAutocomplete string attribute is present AND
+  // kAutofillAvailable state is missing; only one should be set at any given
+  // time. Returns false otherwise.
+  bool AutocompleteIsAvailable(const ui::AXNodeData& data) {
+    if (data.HasStringAttribute(ax::mojom::StringAttribute::kAutoComplete) &&
+        !data.HasState(ax::mojom::State::kAutofillAvailable)) {
+      return true;
+    }
+    return false;
+  }
+};
+
+// Test that autofill available state is correctly set on accessibility node.
+IN_PROC_BROWSER_TEST_F(AutofillAccessibilityTest, TestAutofillState) {
+  // Navigate to url.
+  GURL url =
+      embedded_test_server()->GetURL("/autofill/duplicate_profiles_test.html");
+  NavigateParams params(browser(), url, ui::PAGE_TRANSITION_LINK);
+  params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
+  ui_test_utils::NavigateToURL(&params);
+
+  // Enable accessibility.
+  content::EnableAccessibilityForWebContents(web_contents());
+  content::AccessibilityNotificationWaiter layout_waiter_one(
+      web_contents(), ui::kAXModeComplete, ax::mojom::Event::kLayoutComplete);
+  layout_waiter_one.WaitForNotification();
+
+  // Focus target form field.
+  const std::string focus_name_first_js =
+      "document.getElementById('NAME_FIRST').focus();";
+  ASSERT_TRUE(content::ExecuteScript(web_contents(), focus_name_first_js));
+
+  // Assert that autofill is not yet available for target form field.
+  // Loop while criteria is not met.
+  ui::AXNodeData node_data;
+  std::string node_name;
+  const ax::mojom::Role target_role = ax::mojom::Role::kTextField;
+  const std::string target_name = "First Name:";
+  while (!(node_data.role == target_role && node_name == target_name &&
+           !AutofillIsAvailable(node_data))) {
+    content::WaitForAccessibilityTreeToChange(web_contents());
+    node_data = content::GetFocusedAccessibilityNodeInfo(web_contents());
+    node_name = node_data.GetStringAttribute(ax::mojom::StringAttribute::kName);
+  }
+  // Sanity check.
+  ASSERT_FALSE(AutofillIsAvailable(node_data));
+
+  // Fill form and submit.
+  FormMap data;
+  data["NAME_FIRST"] = "Bob";
+  data["NAME_LAST"] = "Smith";
+  data["ADDRESS_HOME_LINE1"] = "1234 H St.";
+  data["ADDRESS_HOME_CITY"] = "Mountain View";
+  data["EMAIL_ADDRESS"] = "bsmith@example.com";
+  data["ADDRESS_HOME_STATE"] = "CA";
+  data["ADDRESS_HOME_ZIP"] = "94043";
+  data["ADDRESS_HOME_COUNTRY"] = "United States";
+  data["PHONE_HOME_WHOLE_NUMBER"] = "408-871-4567";
+  FillFormAndSubmit("duplicate_profiles_test.html", data);
+  ASSERT_EQ(1u, personal_data_manager()->GetProfiles().size());
+
+  // Reload page.
+  ui_test_utils::NavigateToURL(&params);
+  content::AccessibilityNotificationWaiter layout_waiter_two(
+      web_contents(), ui::kAXModeComplete, ax::mojom::Event::kLayoutComplete);
+  layout_waiter_two.WaitForNotification();
+
+  // Focus target form field.
+  ASSERT_TRUE(content::ExecuteScript(web_contents(), focus_name_first_js));
+
+  // Assert that autofill is now available for target form field.
+  // Loop while criteria is not met.
+  while (!(node_data.role == target_role && node_name == target_name &&
+           AutofillIsAvailable(node_data))) {
+    content::WaitForAccessibilityTreeToChange(web_contents());
+    node_data = content::GetFocusedAccessibilityNodeInfo(web_contents());
+    node_name = node_data.GetStringAttribute(ax::mojom::StringAttribute::kName);
+  }
+  // Sanity check.
+  ASSERT_TRUE(AutofillIsAvailable(node_data));
+}
+
+// Test that autocomplete available string attribute is correctly set on
+// accessibility node. Test autocomplete in this file since it uses the same
+// infrastructure as autofill.
+IN_PROC_BROWSER_TEST_F(AutofillAccessibilityTest, TestAutocompleteState) {
+  // Navigate to url.
+  GURL url =
+      embedded_test_server()->GetURL("/autofill/duplicate_profiles_test.html");
+  NavigateParams params(browser(), url, ui::PAGE_TRANSITION_LINK);
+  params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
+  ui_test_utils::NavigateToURL(&params);
+
+  // Enable accessibility.
+  content::EnableAccessibilityForWebContents(web_contents());
+  content::AccessibilityNotificationWaiter layout_waiter_one(
+      web_contents(), ui::kAXModeComplete, ax::mojom::Event::kLayoutComplete);
+  layout_waiter_one.WaitForNotification();
+
+  // Focus target form field.
+  const std::string focus_name_first_js =
+      "document.getElementById('NAME_FIRST').focus();";
+  ASSERT_TRUE(content::ExecuteScript(web_contents(), focus_name_first_js));
+
+  // Assert that autocomplete is not yet available for target form field.
+  // Loop while criteria is not met.
+  ui::AXNodeData node_data;
+  std::string node_name;
+  const ax::mojom::Role target_role = ax::mojom::Role::kTextField;
+  const std::string target_name = "First Name:";
+  while (!(node_data.role == target_role && node_name == target_name &&
+           !AutocompleteIsAvailable(node_data))) {
+    content::WaitForAccessibilityTreeToChange(web_contents());
+    node_data = content::GetFocusedAccessibilityNodeInfo(web_contents());
+    node_name = node_data.GetStringAttribute(ax::mojom::StringAttribute::kName);
+  }
+  // Sanity check.
+  ASSERT_FALSE(AutocompleteIsAvailable(node_data));
+
+  // Partially fill form. This should not set autofill state, but rather,
+  // autocomplete state.
+  FormMap data;
+  data["NAME_FIRST"] = "Bob";
+  data["NAME_LAST"] = "Smith";
+  FillFormAndSubmit("duplicate_profiles_test.html", data);
+  // Since we didn't fill the entire form, we should not have increased the
+  // number of autofill profiles.
+  ASSERT_EQ(0u, personal_data_manager()->GetProfiles().size());
+
+  // Reload page.
+  ui_test_utils::NavigateToURL(&params);
+  content::AccessibilityNotificationWaiter layout_waiter_two(
+      web_contents(), ui::kAXModeComplete, ax::mojom::Event::kLayoutComplete);
+  layout_waiter_two.WaitForNotification();
+
+  // Focus target form field.
+  ASSERT_TRUE(content::ExecuteScript(web_contents(), focus_name_first_js));
+
+  // Assert that autocomplete is now available for target form field.
+  // Loop while criteria is not met.
+  while (!(node_data.role == target_role && node_name == target_name &&
+           AutocompleteIsAvailable(node_data))) {
+    content::WaitForAccessibilityTreeToChange(web_contents());
+    node_data = content::GetFocusedAccessibilityNodeInfo(web_contents());
+    node_name = node_data.GetStringAttribute(ax::mojom::StringAttribute::kName);
+  }
+  // Sanity check.
+  ASSERT_TRUE(AutocompleteIsAvailable(node_data));
+}
+
 }  // namespace autofill
diff --git a/chrome/browser/chromeos/android_sms/android_sms_pairing_state_tracker_impl.cc b/chrome/browser/chromeos/android_sms/android_sms_pairing_state_tracker_impl.cc
index e827319..39cf00e 100644
--- a/chrome/browser/chromeos/android_sms/android_sms_pairing_state_tracker_impl.cc
+++ b/chrome/browser/chromeos/android_sms/android_sms_pairing_state_tracker_impl.cc
@@ -49,7 +49,7 @@
 
 void AndroidSmsPairingStateTrackerImpl::AttemptFetchMessagesPairingState() {
   GetCookieManager()->GetCookieList(
-      GetPairingUrl(), net::CookieOptions(),
+      GetPairingUrl(), net::CookieOptions::MakeAllInclusive(),
       base::BindOnce(&AndroidSmsPairingStateTrackerImpl::OnCookiesRetrieved,
                      base::Unretained(this)));
 }
diff --git a/chrome/browser/chromeos/login/quick_unlock/pin_storage_prefs.cc b/chrome/browser/chromeos/login/quick_unlock/pin_storage_prefs.cc
index c294eace..aff57d26 100644
--- a/chrome/browser/chromeos/login/quick_unlock/pin_storage_prefs.cc
+++ b/chrome/browser/chromeos/login/quick_unlock/pin_storage_prefs.cc
@@ -16,9 +16,7 @@
 
 // static
 void PinStoragePrefs::RegisterProfilePrefs(PrefRegistrySimple* registry) {
-  // Mark it as PUBLIC so ash could access this pref.
-  registry->RegisterStringPref(ash::prefs::kQuickUnlockPinSalt, "",
-                               PrefRegistry::PUBLIC);
+  registry->RegisterStringPref(ash::prefs::kQuickUnlockPinSalt, "");
   registry->RegisterStringPref(prefs::kQuickUnlockPinSecret, "");
 }
 
diff --git a/chrome/browser/chromeos/login/ui/oobe_dialog_size_utils.cc b/chrome/browser/chromeos/login/ui/oobe_dialog_size_utils.cc
index 33896a4..39036ff 100644
--- a/chrome/browser/chromeos/login/ui/oobe_dialog_size_utils.cc
+++ b/chrome/browser/chromeos/login/ui/oobe_dialog_size_utils.cc
@@ -10,6 +10,7 @@
 namespace {
 
 constexpr gfx::Size kMaxDialogSize{768, 768};
+constexpr int kDialogHeightForWidePadding = 640;
 constexpr gfx::Size kMinDialogSize{464, 464};
 constexpr gfx::Insets kMinMargins{48, 48};
 
@@ -17,7 +18,8 @@
 
 void CalculateOobeDialogBounds(const gfx::Rect& host_bounds,
                                int shelf_height,
-                               gfx::Rect* result) {
+                               gfx::Rect* result,
+                               OobeDialogPaddingMode* result_padding) {
   // Area to position dialog.
   gfx::Rect available_area = host_bounds;
   available_area.Inset(0, 0, 0, shelf_height);
@@ -36,6 +38,14 @@
   // Center dialog within an available area.
   *result = available_area;
   result->ClampToCenteredSize(dialog_size);
+  if (!result_padding)
+    return;
+  if ((result->width() >= kMaxDialogSize.width()) &&
+      (result->height() >= kDialogHeightForWidePadding)) {
+    *result_padding = OobeDialogPaddingMode::PADDING_WIDE;
+  } else {
+    *result_padding = OobeDialogPaddingMode::PADDING_NARROW;
+  }
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/ui/oobe_dialog_size_utils.h b/chrome/browser/chromeos/login/ui/oobe_dialog_size_utils.h
index 5e841da5..e5f9b3c 100644
--- a/chrome/browser/chromeos/login/ui/oobe_dialog_size_utils.h
+++ b/chrome/browser/chromeos/login/ui/oobe_dialog_size_utils.h
@@ -10,12 +10,24 @@
 
 namespace chromeos {
 
+// Enum that specifies how inner padding of OOBE dialog should be calculated.
+enum class OobeDialogPaddingMode {
+  // Oobe dialog is displayed full screen, padding will be calculated
+  // via css depending on media size.
+  PADDING_AUTO,
+  // Oobe dialog have enough free space around and should use wide padding.
+  PADDING_WIDE,
+  // Oobe dialog is positioned in limited space and should use narrow padding.
+  PADDING_NARROW
+};
+
 // Position OOBE dialog according to specs inside |host_bounds| excluding shelf.
 // |host_bounds| is in coordinates of oobe dialog widget. |result| is
 // in the same coordinates of |host_bounds|.
 void CalculateOobeDialogBounds(const gfx::Rect& host_bounds,
                                int shelf_height,
-                               gfx::Rect* result);
+                               gfx::Rect* result,
+                               OobeDialogPaddingMode* result_padding);
 
 }  // namespace chromeos
 
diff --git a/chrome/browser/chromeos/login/ui/oobe_dialog_size_utils_unittest.cc b/chrome/browser/chromeos/login/ui/oobe_dialog_size_utils_unittest.cc
index c12bb68..96d47a5 100644
--- a/chrome/browser/chromeos/login/ui/oobe_dialog_size_utils_unittest.cc
+++ b/chrome/browser/chromeos/login/ui/oobe_dialog_size_utils_unittest.cc
@@ -76,66 +76,82 @@
 TEST_F(OobeDialogSizeUtilsTest, Chromebook) {
   gfx::Rect usual_device(1200, 800);
   gfx::Rect dialog;
+  OobeDialogPaddingMode padding;
 
-  CalculateOobeDialogBounds(usual_device, kShelfHeight, &dialog);
+  CalculateOobeDialogBounds(usual_device, kShelfHeight, &dialog, &padding);
   ValidateDialog(SizeWithoutShelf(usual_device), dialog);
+  EXPECT_EQ(padding, OobeDialogPaddingMode::PADDING_WIDE);
 }
 
 // We have plenty of space on the screen, but virtual keyboard takes some space.
 TEST_F(OobeDialogSizeUtilsTest, ChromebookVirtualKeyboard) {
   gfx::Rect usual_device_with_keyboard(1200, 800 - kVirtualKeyboardHeight);
   gfx::Rect dialog;
+  OobeDialogPaddingMode padding;
 
-  CalculateOobeDialogBounds(usual_device_with_keyboard, 0, &dialog);
+  CalculateOobeDialogBounds(usual_device_with_keyboard, 0, &dialog, &padding);
   ValidateDialog(usual_device_with_keyboard, dialog);
+  EXPECT_EQ(padding, OobeDialogPaddingMode::PADDING_NARROW);
 }
 
 // Tablet device can have smaller screen size.
 TEST_F(OobeDialogSizeUtilsTest, TabletHorizontal) {
   gfx::Rect tablet_device(1080, 675);
   gfx::Rect dialog;
+  OobeDialogPaddingMode padding;
 
-  CalculateOobeDialogBounds(tablet_device, kShelfHeight, &dialog);
+  CalculateOobeDialogBounds(tablet_device, kShelfHeight, &dialog, &padding);
   ValidateDialog(SizeWithoutShelf(tablet_device), dialog);
+  EXPECT_EQ(padding, OobeDialogPaddingMode::PADDING_NARROW);
 }
 
-// Tablet device in horizontal mode with virtual keyboard have restricted space.
+// Tablet device in horizontal mode with virtual keyboard have restricted
+// vertical space.
 TEST_F(OobeDialogSizeUtilsTest, TabletHorizontalVirtualKeyboard) {
   gfx::Rect tablet_device(1080, 675 - kVirtualKeyboardHeight);
   gfx::Rect dialog;
+  OobeDialogPaddingMode padding;
 
-  CalculateOobeDialogBounds(tablet_device, 0, &dialog);
+  CalculateOobeDialogBounds(tablet_device, 0, &dialog, &padding);
   ValidateDialog(tablet_device, dialog);
+  EXPECT_EQ(padding, OobeDialogPaddingMode::PADDING_NARROW);
 }
 
-// Tablet device in horizontal mode with docked magnifier have restricted space.
+// Tablet device in horizontal mode with docked magnifier have restricted
+// vertical space.
 TEST_F(OobeDialogSizeUtilsTest, TabletHorizontalDockedMagnifier) {
   gfx::Rect tablet_device(0, 0, 1080, 675 - kDockedMagnifierHeight);
   gfx::Rect dialog;
+  OobeDialogPaddingMode padding;
 
-  CalculateOobeDialogBounds(tablet_device, 0, &dialog);
+  CalculateOobeDialogBounds(tablet_device, 0, &dialog, &padding);
   ValidateDialog(tablet_device, dialog);
+  EXPECT_EQ(padding, OobeDialogPaddingMode::PADDING_NARROW);
 }
 
 // Tablet device in horizontal mode with virtual keyboard and docked
-// magnifier results in very few space.
+// magnifier results in very few vertical space.
 TEST_F(OobeDialogSizeUtilsTest, TabletHorizontalVirtualKeyboardMagnifier) {
   gfx::Rect tablet_device(
       0, 0, 1080, 675 - kVirtualKeyboardHeight - kDockedMagnifierHeight);
 
   gfx::Rect dialog;
+  OobeDialogPaddingMode padding;
 
-  CalculateOobeDialogBounds(tablet_device, 0, &dialog);
+  CalculateOobeDialogBounds(tablet_device, 0, &dialog, &padding);
   ValidateDialog(tablet_device, dialog);
+  EXPECT_EQ(padding, OobeDialogPaddingMode::PADDING_NARROW);
 }
 
 // Tablet in vertical mode puts some strain on dialog width.
 TEST_F(OobeDialogSizeUtilsTest, TabletVertical) {
   gfx::Rect tablet_device(675, 1080);
   gfx::Rect dialog;
+  OobeDialogPaddingMode padding;
 
-  CalculateOobeDialogBounds(tablet_device, kShelfHeight, &dialog);
+  CalculateOobeDialogBounds(tablet_device, kShelfHeight, &dialog, &padding);
   ValidateDialog(SizeWithoutShelf(tablet_device), dialog);
+  EXPECT_EQ(padding, OobeDialogPaddingMode::PADDING_NARROW);
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.cc b/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.cc
index 33c023ef..d1e07e4 100644
--- a/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.cc
+++ b/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/ui/ash/ash_util.h"
 #include "chrome/browser/ui/ash/login_screen_client.h"
 #include "chrome/browser/ui/webui/chrome_web_contents_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/core_oobe_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
 #include "components/web_modal/web_contents_modal_dialog_manager.h"
@@ -43,6 +44,18 @@
 constexpr char kAppLaunchBailout[] = "app_launch_bailout";
 constexpr char kCancel[] = "cancel";
 
+CoreOobeView::DialogPaddingMode ConvertDialogPaddingMode(
+    OobeDialogPaddingMode padding) {
+  switch (padding) {
+    case OobeDialogPaddingMode::PADDING_AUTO:
+      return CoreOobeView::DialogPaddingMode::MODE_AUTO;
+    case OobeDialogPaddingMode::PADDING_WIDE:
+      return CoreOobeView::DialogPaddingMode::MODE_WIDE;
+    case OobeDialogPaddingMode::PADDING_NARROW:
+      return CoreOobeView::DialogPaddingMode::MODE_NARROW;
+  }
+}
+
 }  // namespace
 
 class OobeWebDialogView : public views::WebDialogView {
@@ -124,6 +137,8 @@
     Layout();
   }
 
+  OobeDialogPaddingMode padding() { return padding_; }
+
   // views::WidgetDelegateView:
   ui::ModalType GetModalType() const override { return ui::MODAL_TYPE_WINDOW; }
 
@@ -131,14 +146,18 @@
 
   void Layout() override {
     if (fullscreen_) {
-      oobe_view_->SetBoundsRect(GetContentsBounds());
+      for (views::View* child : children()) {
+        child->SetBoundsRect(GetContentsBounds());
+      }
+      padding_ = OobeDialogPaddingMode::PADDING_AUTO;
       return;
     }
 
     gfx::Rect bounds;
     const int shelf_height =
         has_shelf_ ? ash::ShelfConfig::Get()->shelf_size() : 0;
-    CalculateOobeDialogBounds(GetContentsBounds(), shelf_height, &bounds);
+    CalculateOobeDialogBounds(GetContentsBounds(), shelf_height, &bounds,
+                              &padding_);
 
     for (views::View* child : children()) {
       child->SetBoundsRect(bounds);
@@ -155,6 +174,9 @@
   // space).
   bool has_shelf_ = true;
 
+  // Tracks dialog margins after last size calculations.
+  OobeDialogPaddingMode padding_ = OobeDialogPaddingMode::PADDING_AUTO;
+
   DISALLOW_COPY_AND_ASSIGN(LayoutWidgetDelegateView);
 };
 
@@ -308,6 +330,8 @@
   layout_view_->SetHasShelf(
       !ChromeKeyboardControllerClient::Get()->is_keyboard_visible());
 
+  dialog_view_->AddObserver(this);
+
   extensions::ChromeExtensionWebContentsObserver::CreateForWebContents(
       dialog_view_->web_contents());
 
@@ -321,6 +345,7 @@
 }
 
 OobeUIDialogDelegate::~OobeUIDialogDelegate() {
+  dialog_view_->RemoveObserver(this);
   if (captive_portal_delegate_)
     captive_portal_delegate_->Close();
   if (controller_)
@@ -460,6 +485,13 @@
   return true;
 }
 
+void OobeUIDialogDelegate::OnViewBoundsChanged(views::View* observed_view) {
+  if (!widget_)
+    return;
+  GetOobeUI()->GetCoreOobeView()->SetDialogPaddingMode(
+      ConvertDialogPaddingMode(layout_view_->padding()));
+}
+
 void OobeUIDialogDelegate::OnKeyboardVisibilityChanged(bool visible) {
   if (!widget_)
     return;
diff --git a/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.h b/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.h
index 1eb1d42a..59a05a2 100644
--- a/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.h
+++ b/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.h
@@ -16,6 +16,7 @@
 #include "chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.h"
 #include "chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.h"
 #include "components/web_modal/web_contents_modal_dialog_host.h"
+#include "ui/views/view_observer.h"
 #include "ui/web_dialogs/web_dialog_delegate.h"
 
 namespace content {
@@ -27,6 +28,7 @@
 }
 
 namespace views {
+class View;
 class WebDialogView;
 class Widget;
 }  // namespace views
@@ -48,7 +50,8 @@
 //   clientView---->Widget's view hierarchy
 class OobeUIDialogDelegate : public ui::WebDialogDelegate,
                              public ChromeKeyboardControllerClient::Observer,
-                             public CaptivePortalWindowProxy::Observer {
+                             public CaptivePortalWindowProxy::Observer,
+                             public views::ViewObserver {
  public:
   explicit OobeUIDialogDelegate(base::WeakPtr<LoginDisplayHostMojo> controller);
   ~OobeUIDialogDelegate() override;
@@ -100,6 +103,9 @@
   std::vector<ui::Accelerator> GetAccelerators() override;
   bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
 
+  // views::ViewObserver:
+  void OnViewBoundsChanged(views::View* observed_view) override;
+
   // ChromeKeyboardControllerClient::Observer:
   void OnKeyboardVisibilityChanged(bool visible) override;
 
diff --git a/chrome/browser/chromeos/net/wake_on_wifi_connection_observer.h b/chrome/browser/chromeos/net/wake_on_wifi_connection_observer.h
index 7711d3a1..8c21df2 100644
--- a/chrome/browser/chromeos/net/wake_on_wifi_connection_observer.h
+++ b/chrome/browser/chromeos/net/wake_on_wifi_connection_observer.h
@@ -9,7 +9,6 @@
 #include "base/macros.h"
 #include "chrome/browser/chromeos/net/wake_on_wifi_manager.h"
 #include "components/gcm_driver/gcm_connection_observer.h"
-#include "content/public/browser/notification_observer.h"
 #include "net/base/ip_endpoint.h"
 
 class Profile;
@@ -23,6 +22,10 @@
 // associated with a profile.
 class WakeOnWifiConnectionObserver : public gcm::GCMConnectionObserver {
  public:
+  WakeOnWifiConnectionObserver(Profile* profile,
+                               bool wifi_properties_received,
+                               WakeOnWifiManager::WakeOnWifiFeature feature,
+                               NetworkDeviceHandler* network_device_handler);
   ~WakeOnWifiConnectionObserver() override;
 
   // Handles the case when the wifi properties have been received along with
@@ -45,12 +48,6 @@
                            TestWakeOnWifiPacketRemove);
   FRIEND_TEST_ALL_PREFIXES(WakeOnWifiObserverTest, TestWakeOnWifiNoneAdd);
   FRIEND_TEST_ALL_PREFIXES(WakeOnWifiObserverTest, TestWakeOnWifiNoneRemove);
-  friend class WakeOnWifiManager;
-
-  WakeOnWifiConnectionObserver(Profile* profile,
-                               bool wifi_properties_received,
-                               WakeOnWifiManager::WakeOnWifiFeature feature,
-                               NetworkDeviceHandler* network_device_handler);
 
   void AddWakeOnPacketConnection();
   void RemoveWakeOnPacketConnection();
diff --git a/chrome/browser/chromeos/net/wake_on_wifi_manager.cc b/chrome/browser/chromeos/net/wake_on_wifi_manager.cc
index 3ccea59..c552a535 100644
--- a/chrome/browser/chromeos/net/wake_on_wifi_manager.cc
+++ b/chrome/browser/chromeos/net/wake_on_wifi_manager.cc
@@ -13,10 +13,11 @@
 #include "base/memory/ptr_util.h"
 #include "base/system/sys_info.h"
 #include "base/values.h"
-#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/net/wake_on_wifi_connection_observer.h"
 #include "chrome/browser/gcm/gcm_profile_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/login/login_state/login_state.h"
 #include "chromeos/network/device_state.h"
@@ -27,8 +28,6 @@
 #include "components/gcm_driver/gcm_driver.h"
 #include "components/gcm_driver/gcm_profile_service.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_source.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 
 namespace chromeos {
@@ -94,12 +93,7 @@
 
   g_wake_on_wifi_manager = this;
 
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_PROFILE_ADDED,
-                 content::NotificationService::AllBrowserContextsAndSources());
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_PROFILE_DESTROYED,
-                 content::NotificationService::AllBrowserContextsAndSources());
+  g_browser_process->profile_manager()->AddObserver(this);
 
   NetworkHandler::Get()->network_state_handler()->AddObserver(this, FROM_HERE);
 
@@ -107,13 +101,13 @@
 }
 
 WakeOnWifiManager::~WakeOnWifiManager() {
-  DCHECK(g_wake_on_wifi_manager);
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  g_browser_process->profile_manager()->RemoveObserver(this);
   if (current_feature_ != NOT_SUPPORTED) {
     NetworkHandler::Get()->network_state_handler()->RemoveObserver(this,
                                                                    FROM_HERE);
   }
-  g_wake_on_wifi_manager = NULL;
+  DCHECK_EQ(this, g_wake_on_wifi_manager);
+  g_wake_on_wifi_manager = nullptr;
 }
 
 void WakeOnWifiManager::OnPreferenceChanged(
@@ -141,21 +135,21 @@
   return current_feature_ != NOT_SUPPORTED && current_feature_ != INVALID;
 }
 
-void WakeOnWifiManager::Observe(int type,
-                                const content::NotificationSource& source,
-                                const content::NotificationDetails& details) {
-  switch (type) {
-    case chrome::NOTIFICATION_PROFILE_ADDED: {
-      OnProfileAdded(content::Source<Profile>(source).ptr());
-      break;
-    }
-    case chrome::NOTIFICATION_PROFILE_DESTROYED: {
-      OnProfileDestroyed(content::Source<Profile>(source).ptr());
-      break;
-    }
-    default:
-      NOTREACHED();
-  }
+void WakeOnWifiManager::OnProfileAdded(Profile* profile) {
+  auto result = connection_observers_.find(profile);
+
+  // Only add the profile if it is not already present.
+  if (result != connection_observers_.end())
+    return;
+
+  connection_observers_[profile] =
+      std::make_unique<WakeOnWifiConnectionObserver>(
+          profile, wifi_properties_received_, current_feature_,
+          NetworkHandler::Get()->network_device_handler());
+
+  gcm::GCMProfileServiceFactory::GetForProfile(profile)
+      ->driver()
+      ->WakeFromSuspendForHeartbeat(IsWakeOnPacketEnabled(current_feature_));
 }
 
 void WakeOnWifiManager::DeviceListChanged() {
@@ -222,8 +216,8 @@
     connection_observers_.clear();
     NetworkHandler::Get()->network_state_handler()->RemoveObserver(this,
                                                                    FROM_HERE);
-    registrar_.RemoveAll();
     extension_event_observer_.reset();
+    g_browser_process->profile_manager()->RemoveObserver(this);
 
     return;
   }
@@ -249,26 +243,4 @@
   }
 }
 
-void WakeOnWifiManager::OnProfileAdded(Profile* profile) {
-  auto result = connection_observers_.find(profile);
-
-  // Only add the profile if it is not already present.
-  if (result != connection_observers_.end())
-    return;
-
-  connection_observers_[profile] =
-      base::WrapUnique(new WakeOnWifiConnectionObserver(
-          profile, wifi_properties_received_, current_feature_,
-          NetworkHandler::Get()->network_device_handler()));
-
-  gcm::GCMProfileServiceFactory::GetForProfile(profile)
-      ->driver()
-      ->WakeFromSuspendForHeartbeat(
-          IsWakeOnPacketEnabled(current_feature_));
-}
-
-void WakeOnWifiManager::OnProfileDestroyed(Profile* profile) {
-  connection_observers_.erase(profile);
-}
-
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/net/wake_on_wifi_manager.h b/chrome/browser/chromeos/net/wake_on_wifi_manager.h
index 2e0a46c..bbef9745 100644
--- a/chrome/browser/chromeos/net/wake_on_wifi_manager.h
+++ b/chrome/browser/chromeos/net/wake_on_wifi_manager.h
@@ -7,13 +7,11 @@
 
 #include <map>
 
-#include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/chromeos/power/extension_event_observer.h"
+#include "chrome/browser/profiles/profile_manager_observer.h"
 #include "chromeos/network/network_state_handler_observer.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
 
 class Profile;
 
@@ -31,7 +29,7 @@
 // servers and sending that connection information down to shill.  This class is
 // owned by ChromeBrowserMainPartsChromeos.  This class is also NOT thread-safe
 // and should only be called on the UI thread.
-class WakeOnWifiManager : public content::NotificationObserver,
+class WakeOnWifiManager : public ProfileManagerObserver,
                           public NetworkStateHandlerObserver {
  public:
   enum WakeOnWifiFeature {
@@ -57,21 +55,14 @@
   // have not yet determined whether wake-on-wifi features are supported.
   bool WakeOnWifiSupported();
 
-  // content::NotificationObserver override.
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
+  // ProfileManagerObserver:
+  void OnProfileAdded(Profile* profile) override;
 
-  // NetworkStateHandlerObserver overrides.
+  // NetworkStateHandlerObserver:
   void DeviceListChanged() override;
   void DevicePropertiesUpdated(const DeviceState* device) override;
 
  private:
-  FRIEND_TEST_ALL_PREFIXES(WakeOnWifiObserverTest, TestWakeOnWifiPacketAdd);
-  FRIEND_TEST_ALL_PREFIXES(WakeOnWifiObserverTest, TestWakeOnWifiPacketRemove);
-  FRIEND_TEST_ALL_PREFIXES(WakeOnWifiObserverTest, TestWakeOnWifiNoneAdd);
-  FRIEND_TEST_ALL_PREFIXES(WakeOnWifiObserverTest, TestWakeOnWifiNoneRemove);
-
   // Sends the user's preference to shill, updates the timer used by the GCM
   // client to send heartbeats, and tells |extension_event_observer_| to block
   // (or not block) suspends based on the value of |current_feature_|.
@@ -84,10 +75,6 @@
   void GetDevicePropertiesCallback(const std::string& device_path,
                                    const base::DictionaryValue& properties);
 
-  // Called when a Profile is added or destroyed.
-  void OnProfileAdded(Profile* profile);
-  void OnProfileDestroyed(Profile* profile);
-
   WakeOnWifiFeature current_feature_;
 
   // Set to true once we have received the properties for the wifi device from
@@ -99,8 +86,6 @@
 
   std::unique_ptr<ExtensionEventObserver> extension_event_observer_;
 
-  content::NotificationRegistrar registrar_;
-
   base::WeakPtrFactory<WakeOnWifiManager> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(WakeOnWifiManager);
diff --git a/chrome/browser/chromeos/policy/login_policy_test_base.h b/chrome/browser/chromeos/policy/login_policy_test_base.h
index 0b278876..9793024f 100644
--- a/chrome/browser/chromeos/policy/login_policy_test_base.h
+++ b/chrome/browser/chromeos/policy/login_policy_test_base.h
@@ -23,6 +23,7 @@
 
 // This class can be used to implement tests which need policy to be set prior
 // to login.
+// TODO (crbug/1014663): Deprecate this class in favor of LoggedInUserMixin.
 class LoginPolicyTestBase : public chromeos::OobeBaseTest {
  protected:
   LoginPolicyTestBase();
diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc
index 8f3d38c6..848a5a21 100644
--- a/chrome/browser/chromeos/preferences.cc
+++ b/chrome/browser/chromeos/preferences.cc
@@ -220,136 +220,6 @@
   registry->RegisterBooleanPref(prefs::kAppReinstallRecommendationEnabled,
                                 false);
 
-  // TODO(jamescook): Move ownership and registration into ash. This will need
-  // changes to policy::RecommendationRestorer which requires that prefs are
-  // available immediately during startup.
-  registry->RegisterBooleanPref(
-      ash::prefs::kAccessibilityStickyKeysEnabled, false,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(
-      ash::prefs::kAccessibilityLargeCursorEnabled, false,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterIntegerPref(ash::prefs::kAccessibilityLargeCursorDipSize,
-                                ash::kDefaultLargeCursorSize,
-                                PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(ash::prefs::kAccessibilitySpokenFeedbackEnabled,
-                                false, PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(
-      ash::prefs::kAccessibilityHighContrastEnabled, false,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(
-      ash::prefs::kHighContrastAcceleratorDialogHasBeenAccepted, false,
-      PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(ash::prefs::kDockedMagnifierEnabled, false,
-                                PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(
-      ash::prefs::kDockedMagnifierAcceleratorDialogHasBeenAccepted, false,
-      PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(
-      ash::prefs::kAccessibilityScreenMagnifierCenterFocus, true,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
-  registry->RegisterBooleanPref(
-      ash::prefs::kScreenMagnifierAcceleratorDialogHasBeenAccepted, false,
-      PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(
-      ash::prefs::kDictationAcceleratorDialogHasBeenAccepted, false,
-      PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(
-      ash::prefs::kDisplayRotationAcceleratorDialogHasBeenAccepted, false,
-      PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(
-      ash::prefs::kAccessibilityScreenMagnifierEnabled, false,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(
-      ash::prefs::kAccessibilityDictationEnabled, false,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterDoublePref(ash::prefs::kAccessibilityScreenMagnifierScale,
-                               std::numeric_limits<double>::min(),
-                               PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(
-      ash::prefs::kAccessibilityAutoclickEnabled, false,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterIntegerPref(
-      ash::prefs::kAccessibilityAutoclickDelayMs, ash::kDefaultAutoclickDelayMs,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterIntegerPref(
-      ash::prefs::kAccessibilityAutoclickEventType,
-      static_cast<int>(ash::kDefaultAutoclickEventType),
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(
-      ash::prefs::kAccessibilityAutoclickRevertToLeftClick, true,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(
-      ash::prefs::kAccessibilityAutoclickStabilizePosition, false,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterIntegerPref(
-      ash::prefs::kAccessibilityAutoclickMovementThreshold,
-      ash::kDefaultAutoclickMovementThreshold,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterIntegerPref(
-      ash::prefs::kAccessibilityAutoclickMenuPosition,
-      static_cast<int>(ash::kDefaultAutoclickMenuPosition),
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(
-      ash::prefs::kAccessibilityVirtualKeyboardEnabled, false,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(
-      ash::prefs::kAccessibilityMonoAudioEnabled, false,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(
-      ash::prefs::kAccessibilityCaretHighlightEnabled, false,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(
-      ash::prefs::kAccessibilityCursorHighlightEnabled, false,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(
-      ash::prefs::kAccessibilityFocusHighlightEnabled, false,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(
-      ash::prefs::kAccessibilitySelectToSpeakEnabled, false,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(
-      ash::prefs::kAccessibilitySwitchAccessEnabled, false,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterListPref(
-      ash::prefs::kAccessibilitySwitchAccessSelectKeyCodes,
-      base::Value(std::vector<base::Value>()),
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterIntegerPref(
-      ash::prefs::kAccessibilitySwitchAccessSelectSetting,
-      ash::kSwitchAccessAssignmentNone,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterListPref(
-      ash::prefs::kAccessibilitySwitchAccessNextKeyCodes,
-      base::Value(std::vector<base::Value>()),
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterIntegerPref(
-      ash::prefs::kAccessibilitySwitchAccessNextSetting,
-      ash::kSwitchAccessAssignmentNone,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterListPref(
-      ash::prefs::kAccessibilitySwitchAccessPreviousKeyCodes,
-      base::Value(std::vector<base::Value>()),
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterIntegerPref(
-      ash::prefs::kAccessibilitySwitchAccessPreviousSetting,
-      ash::kSwitchAccessAssignmentNone,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(
-      ash::prefs::kAccessibilitySwitchAccessAutoScanEnabled, false,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterIntegerPref(
-      ash::prefs::kAccessibilitySwitchAccessAutoScanSpeedMs,
-      ash::kDefaultSwitchAccessAutoScanSpeed.InMilliseconds(),
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterIntegerPref(
-      ash::prefs::kAccessibilitySwitchAccessAutoScanKeyboardSpeedMs,
-      ash::kDefaultSwitchAccessAutoScanSpeed.InMilliseconds(),
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(
-      ash::prefs::kShouldAlwaysShowAccessibilityMenu, false,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
-
   registry->RegisterIntegerPref(
       prefs::kMouseSensitivity,
       3,
@@ -387,8 +257,7 @@
   registry->RegisterIntegerPref(
       prefs::kLanguageRemapSearchKeyTo,
       static_cast<int>(ui::chromeos::ModifierKey::kSearchKey),
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF |
-          PrefRegistry::PUBLIC);  // Used in ash.
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
   registry->RegisterIntegerPref(
       prefs::kLanguageRemapControlKeyTo,
       static_cast<int>(ui::chromeos::ModifierKey::kControlKey),
@@ -451,14 +320,6 @@
   registry->RegisterBooleanPref(prefs::kRestoreLastLockScreenNote, true);
   registry->RegisterDictionaryPref(prefs::kNoteTakingAppsLockScreenToastShown);
 
-  // TODO(warx): Move prefs::kAllowScreenLock and prefs::kEnableAutoScreenLock
-  // registration to ash, which requires refactoring in SessionControllerClient.
-  registry->RegisterBooleanPref(ash::prefs::kAllowScreenLock, true,
-                                PrefRegistry::PUBLIC);
-  registry->RegisterBooleanPref(
-      ash::prefs::kEnableAutoScreenLock, false,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-
   // We don't sync wake-on-wifi related prefs because they are device specific.
   registry->RegisterBooleanPref(prefs::kWakeOnWifiDarkConnect, true);
 
@@ -545,16 +406,16 @@
   // Text-to-speech prefs.
   registry->RegisterDictionaryPref(
       prefs::kTextToSpeechLangToVoiceName,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterDoublePref(
-      prefs::kTextToSpeechRate, blink::mojom::kSpeechSynthesisDefaultRate,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterDoublePref(
-      prefs::kTextToSpeechPitch, blink::mojom::kSpeechSynthesisDefaultPitch,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterDoublePref(
-      prefs::kTextToSpeechVolume, blink::mojom::kSpeechSynthesisDefaultVolume,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterDoublePref(prefs::kTextToSpeechRate,
+                               blink::mojom::kSpeechSynthesisDefaultRate,
+                               user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterDoublePref(prefs::kTextToSpeechPitch,
+                               blink::mojom::kSpeechSynthesisDefaultPitch,
+                               user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterDoublePref(prefs::kTextToSpeechVolume,
+                               blink::mojom::kSpeechSynthesisDefaultVolume,
+                               user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
 
   // By default showing Sync Consent is set to true. It can changed by policy.
   registry->RegisterBooleanPref(prefs::kEnableSyncConsent, true);
diff --git a/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc b/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc
index c308c7a..157f15df 100644
--- a/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc
+++ b/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc
@@ -56,7 +56,6 @@
 
     host_resolver()->AddRule("*", "127.0.0.1");
     content::SetupCrossSiteRedirector(embedded_test_server());
-    ASSERT_TRUE(embedded_test_server()->Start());
   }
 
  protected:
@@ -445,9 +444,10 @@
 
 IN_PROC_BROWSER_TEST_P(CrossOriginReadBlockingExtensionAllowlistingTest,
                        FromDeclarativeContentScript_NoSniffXml) {
-  // Load the test extension.
+  ASSERT_TRUE(embedded_test_server()->Start());
   GURL cross_site_resource(
       embedded_test_server()->GetURL("cross-site.com", "/nosniff.xml"));
+
   ASSERT_TRUE(InstallExtension(cross_site_resource));
 
   // Test case #1: Declarative script injected after a browser-initiated
@@ -506,7 +506,7 @@
 // See also https://crbug.com/846346.
 IN_PROC_BROWSER_TEST_P(CrossOriginReadBlockingExtensionAllowlistingTest,
                        FromProgrammaticContentScript_NoSniffXml) {
-  // Load the test extension.
+  ASSERT_TRUE(embedded_test_server()->Start());
   ASSERT_TRUE(InstallExtension());
 
   // Navigate to a fetch-initiator.com page.
@@ -534,7 +534,7 @@
 // covered by the extension permissions.
 IN_PROC_BROWSER_TEST_P(CrossOriginReadBlockingExtensionAllowlistingTest,
                        FromProgrammaticContentScript_NoPermissionToTarget) {
-  // Load the test extension.
+  ASSERT_TRUE(embedded_test_server()->Start());
   ASSERT_TRUE(InstallExtension());
 
   // Navigate to a fetch-initiator.com page.
@@ -562,7 +562,7 @@
 // https://crbug.com/918660.
 IN_PROC_BROWSER_TEST_P(CrossOriginReadBlockingExtensionAllowlistingTest,
                        FromProgrammaticContentScript_SameOrigin) {
-  // Load the test extension.
+  ASSERT_TRUE(embedded_test_server()->Start());
   ASSERT_TRUE(InstallExtension());
 
   // Navigate to a fetch-initiator.com page.
@@ -591,7 +591,7 @@
 // reported to LogInitiatorSchemeBypassingDocumentBlocking.
 IN_PROC_BROWSER_TEST_P(CrossOriginReadBlockingExtensionAllowlistingTest,
                        FromProgrammaticContentScript_AllowedTextResource) {
-  // Load the test extension.
+  ASSERT_TRUE(embedded_test_server()->Start());
   ASSERT_TRUE(InstallExtension());
 
   // Navigate to a fetch-initiator.com page.
@@ -624,7 +624,7 @@
 // reported to LogInitiatorSchemeBypassingDocumentBlocking.
 IN_PROC_BROWSER_TEST_P(CrossOriginReadBlockingExtensionAllowlistingTest,
                        FromProgrammaticContentScript_EmptyAndBlocked) {
-  // Load the test extension.
+  ASSERT_TRUE(embedded_test_server()->Start());
   ASSERT_TRUE(InstallExtension());
 
   // Navigate to a fetch-initiator.com page.
@@ -653,7 +653,7 @@
 // requests that aren't from content scripts.
 IN_PROC_BROWSER_TEST_F(CrossOriginReadBlockingExtensionTest,
                        FromBackgroundPage_NoSniffXml) {
-  // Load the test extension.
+  ASSERT_TRUE(embedded_test_server()->Start());
   ASSERT_TRUE(InstallExtension());
 
   // Performs a cross-origin XHR from the background page.
@@ -670,7 +670,7 @@
 // relaxed CORB processing.
 IN_PROC_BROWSER_TEST_F(CrossOriginReadBlockingExtensionTest,
                        FromForegroundPage_NoSniffXml) {
-  // Load the test extension.
+  ASSERT_TRUE(embedded_test_server()->Start());
   ASSERT_TRUE(InstallExtension());
 
   // Navigate a tab to an extension page.
@@ -712,7 +712,7 @@
 // back to the network).
 IN_PROC_BROWSER_TEST_F(CrossOriginReadBlockingExtensionTest,
                        FromServiceWorker_NoSniffXml) {
-  // Load the test extension.
+  ASSERT_TRUE(embedded_test_server()->Start());
   ASSERT_TRUE(InstallExtension());
 
   // Register the service worker which injects "SERVICE WORKER INTERCEPT: "
@@ -823,7 +823,7 @@
 
 IN_PROC_BROWSER_TEST_F(CrossOriginReadBlockingExtensionTest,
                        ProgrammaticContentScriptVsWebUI) {
-  // Load the test extension.
+  ASSERT_TRUE(embedded_test_server()->Start());
   ASSERT_TRUE(InstallExtension());
 
   // Try to inject a content script just as we are about to commit a WebUI page.
@@ -919,7 +919,7 @@
 
 IN_PROC_BROWSER_TEST_P(CrossOriginReadBlockingExtensionAllowlistingTest,
                        ProgrammaticContentScriptVsAppCache) {
-  // Load the test extension.
+  ASSERT_TRUE(embedded_test_server()->Start());
   ASSERT_TRUE(InstallExtension());
 
   // Set up http server serving files from content/test/data (which conveniently
@@ -1014,6 +1014,8 @@
 
 IN_PROC_BROWSER_TEST_F(CrossOriginReadBlockingExtensionTest,
                        WebViewContentScript) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
   // Load the test app.
   const Extension* app = InstallApp();
   ASSERT_TRUE(app);
@@ -1071,7 +1073,7 @@
 
 IN_PROC_BROWSER_TEST_P(CrossOriginReadBlockingExtensionAllowlistingTest,
                        OriginHeaderInCrossOriginGetRequest) {
-  // Load the test extension.
+  ASSERT_TRUE(embedded_test_server()->Start());
   ASSERT_TRUE(InstallExtension());
 
   // Navigate to a fetch-initiator.com page.
@@ -1124,7 +1126,7 @@
 
 IN_PROC_BROWSER_TEST_P(CrossOriginReadBlockingExtensionAllowlistingTest,
                        OriginHeaderInCrossOriginPostRequest) {
-  // Load the test extension.
+  ASSERT_TRUE(embedded_test_server()->Start());
   ASSERT_TRUE(InstallExtension());
 
   // Navigate to a fetch-initiator.com page.
@@ -1169,7 +1171,7 @@
 
 IN_PROC_BROWSER_TEST_P(CrossOriginReadBlockingExtensionAllowlistingTest,
                        OriginHeaderInSameOriginPostRequest) {
-  // Load the test extension.
+  ASSERT_TRUE(embedded_test_server()->Start());
   ASSERT_TRUE(InstallExtension());
 
   // Navigate to a fetch-initiator.com page.
@@ -1255,6 +1257,76 @@
                    testing::Pair("Sec-Fetch-Site", expected_sec_fetch_site)}));
 }
 
+IN_PROC_BROWSER_TEST_P(CrossOriginReadBlockingExtensionAllowlistingTest,
+                       CorsFromContentScript) {
+  std::string cors_resource_path = "/cors-subresource-to-intercept";
+  net::test_server::ControllableHttpResponse cors_request(
+      embedded_test_server(), cors_resource_path);
+  ASSERT_TRUE(embedded_test_server()->Start());
+  ASSERT_TRUE(InstallExtension());
+
+  // Navigate to test page.
+  GURL page_url = GetTestPageUrl("fetch-initiator.com");
+  url::Origin page_origin = url::Origin::Create(page_url);
+  std::string page_origin_string = page_origin.Serialize();
+  ui_test_utils::NavigateToURL(browser(), page_url);
+  ASSERT_EQ(page_url,
+            active_web_contents()->GetMainFrame()->GetLastCommittedURL());
+  ASSERT_EQ(page_origin,
+            active_web_contents()->GetMainFrame()->GetLastCommittedOrigin());
+
+  // Inject a content script that performs a cross-origin GET XHR.
+  content::DOMMessageQueue message_queue;
+  GURL cors_resource_url(
+      embedded_test_server()->GetURL("cross-site.com", cors_resource_path));
+  EXPECT_TRUE(ExecuteContentScript(active_web_contents(),
+                                   CreateFetchScript(cors_resource_url)));
+
+  // Verify the request headers (e.g. Origin and Sec-Fetch-Site headers).
+  cors_request.WaitForRequest();
+  if (IsExtensionAllowlisted()) {
+    // Content scripts of allowlisted extensions should be exempted from CORS,
+    // based on the websites the extension has permission for, via extension
+    // manifest.  Therefore, there should be no "Origin" header.
+    EXPECT_THAT(
+        cors_request.http_request()->headers,
+        testing::Not(testing::Contains(testing::Pair("Origin", testing::_))));
+  } else {
+#if 0
+    // TODO(lukasza): https://crbug.com/920638:
+    //
+    // Content scripts of non-allowlisted extensions should participate in
+    // regular CORS, just as if the request was issued from the webpage that the
+    // content script got injected into.  Therefore we should expect the Origin
+    // header to be present and have the right value.
+    EXPECT_THAT(
+        cors_request.http_request()->headers,
+        testing::Contains(testing::Pair("Origin", page_origin_string.c_str())));
+#endif
+  }
+
+  // Respond with Access-Control-Allow-Origin that matches the origin of the web
+  // page.
+  cors_request.Send("HTTP/1.1 200 OK\r\n");
+  cors_request.Send("Content-Type: text/xml; charset=utf-8\r\n");
+  cors_request.Send("X-Content-Type-Options: nosniff\r\n");
+  cors_request.Send("Access-Control-Allow-Origin: " + page_origin_string +
+                    "\r\n");
+  cors_request.Send("\r\n");
+  cors_request.Send("cors-allowed-body");
+  cors_request.Done();
+
+  // Verify that no CORB blocking occurred.
+  //
+  // CORB blocks responses based on Access-Control-Allow-Origin, oblivious to
+  // whether the Origin request header was present (and/or if the extension is
+  // exempted from CORS).  The Access-Control-Allow-Origin header is compared
+  // with the request_initiator of the fetch (the origin of |page_url|) and the
+  // test responds with "*" which matches all origins.
+  std::string fetch_result = PopString(&message_queue);
+  EXPECT_EQ("cors-allowed-body", fetch_result);
+}
+
 INSTANTIATE_TEST_SUITE_P(Allowlisted,
                          CrossOriginReadBlockingExtensionAllowlistingTest,
                          ::testing::Values(AllowlistingParam::kAllowlisted));
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index ead7d2a..a39d61d 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1424,8 +1424,8 @@
   },
   {
     "name": "enable-lookalike-url-navigation-suggestions",
-    "owners": [ "jdeblasio", "meacer" ],
-    "expiry_milestone": 78
+    "owners": [ "jdeblasio", "meacer", "livvielin" ],
+    "expiry_milestone": 81
   },
   {
     "name": "enable-mark-http-as",
diff --git a/chrome/browser/installable/installable_manager.cc b/chrome/browser/installable/installable_manager.cc
index 92268c4e..7768051f 100644
--- a/chrome/browser/installable/installable_manager.cc
+++ b/chrome/browser/installable/installable_manager.cc
@@ -44,20 +44,18 @@
 
 // This constant is the smallest possible adaptive launcher icon size for any
 // device density.
-// The adaptive icon size guide states that an adaptive launcher icon should be
-// 108dp.
-// (https://developer.android.com/guide/practices/ui_guidelines/icon_design_adaptive)
-// For a manifest to be valid, we do NOT need an maskable icon to be
-// 108dp for the device's screen density. Instead, we only need the maskable
-// icon be larger than (or equal to) 108dp in the smallest screen density (that
-// is the mdpi screen density). For mdpi devices, 1dp is 1px. Therefore, we have
-// 108px here.
+// The ideal icon size is 83dp (see documentation for
+// R.dimen.webapk_adaptive_icon_size for discussion of maskable icon size). For
+// a manifest to be valid, we do NOT need an maskable icon to be 83dp for the
+// device's screen density. Instead, we only need the maskable icon be larger
+// than (or equal to) 83dp in the smallest screen density (that is the mdpi
+// screen density). For mdpi devices, 1dp is 1px. Therefore, we have 83px here.
 // Requiring the minimum icon size (in pixel) independent of the device's screen
 // density is because we use mipmap-anydpi-v26 to specify adaptive launcher
 // icon, and it will make the icon adaptive as long as there is one usable
 // maskable icon (if that icon is of wrong size, it'll be automatically
 // resized).
-const int kMinimumPrimaryAdaptiveLauncherIconSizeInPx = 108;
+const int kMinimumPrimaryAdaptiveLauncherIconSizeInPx = 83;
 
 #if !defined(OS_ANDROID)
 const int kMinimumBadgeIconSizeInPx = 72;
diff --git a/chrome/browser/installable/installable_manager_unittest.cc b/chrome/browser/installable/installable_manager_unittest.cc
index b7f1bdc3..02c3104 100644
--- a/chrome/browser/installable/installable_manager_unittest.cc
+++ b/chrome/browser/installable/installable_manager_unittest.cc
@@ -219,7 +219,7 @@
 
   blink::Manifest::ImageResource maskable_icon;
   maskable_icon.type = base::ASCIIToUTF16("image/png");
-  maskable_icon.sizes.push_back(gfx::Size(107, 107));
+  maskable_icon.sizes.push_back(gfx::Size(82, 82));
   maskable_icon.purpose.push_back(IconPurpose::MASKABLE);
   manifest.icons.push_back(maskable_icon);
   EXPECT_FALSE(IsManifestValid(manifest, true, true));
@@ -227,14 +227,14 @@
 
   // When preferring maskable icons, the maskable icon is smaller than required.
   manifest.icons[0].sizes[0] = gfx::Size(144, 144);
-  manifest.icons[1].sizes[0] = gfx::Size(107, 107);
+  manifest.icons[1].sizes[0] = gfx::Size(82, 82);
   EXPECT_TRUE(IsManifestValid(manifest, true, true));
   EXPECT_EQ(NO_ERROR_DETECTED, GetErrorCode());
 
   // When preferring maskable icons, the maskable icon satisfies the size
   // requirement though the non maskable one doesn't
   manifest.icons[0].sizes[0] = gfx::Size(1, 1);
-  manifest.icons[1].sizes[0] = gfx::Size(108, 108);
+  manifest.icons[1].sizes[0] = gfx::Size(83, 83);
   EXPECT_TRUE(IsManifestValid(manifest, true, true));
   EXPECT_EQ(NO_ERROR_DETECTED, GetErrorCode());
 }
diff --git a/chrome/browser/media/history/media_history_engagement_table.cc b/chrome/browser/media/history/media_history_engagement_table.cc
new file mode 100644
index 0000000..0380433
--- /dev/null
+++ b/chrome/browser/media/history/media_history_engagement_table.cc
@@ -0,0 +1,45 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media/history/media_history_engagement_table.h"
+
+#include "base/strings/stringprintf.h"
+#include "sql/statement.h"
+
+namespace media_history {
+
+MediaHistoryEngagementTable::MediaHistoryEngagementTable(
+    scoped_refptr<base::UpdateableSequencedTaskRunner> db_task_runner)
+    : MediaHistoryTableBase(std::move(db_task_runner)) {}
+
+MediaHistoryEngagementTable::~MediaHistoryEngagementTable() = default;
+
+sql::InitStatus MediaHistoryEngagementTable::CreateTableIfNonExistent() {
+  if (!CanAccessDatabase())
+    return sql::INIT_FAILURE;
+
+  bool success = DB()->Execute(
+      "CREATE TABLE IF NOT EXISTS mediaEngagement("
+      "origin_id INTEGER PRIMARY KEY,"
+      "last_updated INTEGER,"
+      "visits INTEGER,"
+      "playbacks INTEGER,"
+      "last_playback_time REAL,"
+      "has_high_score INTEGER,"
+      "CONSTRAINT fk_origin "
+      "FOREIGN KEY (origin_id) "
+      "REFERENCES origin(id) "
+      "ON DELETE CASCADE"
+      ")");
+
+  if (!success) {
+    ResetDB();
+    LOG(ERROR) << "Failed to create media history engagement table.";
+    return sql::INIT_FAILURE;
+  }
+
+  return sql::INIT_OK;
+}
+
+}  // namespace media_history
\ No newline at end of file
diff --git a/chrome/browser/media/history/media_history_engagement_table.h b/chrome/browser/media/history/media_history_engagement_table.h
new file mode 100644
index 0000000..3067cda
--- /dev/null
+++ b/chrome/browser/media/history/media_history_engagement_table.h
@@ -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.
+
+#ifndef CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_ENGAGEMENT_TABLE_H_
+#define CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_ENGAGEMENT_TABLE_H_
+
+#include "base/updateable_sequenced_task_runner.h"
+#include "chrome/browser/media/history/media_history_table_base.h"
+#include "sql/init_status.h"
+#include "url/origin.h"
+
+namespace media_history {
+
+class MediaHistoryEngagementTable : public MediaHistoryTableBase {
+ public:
+  struct MediaEngagementScore {
+    MediaEngagementScore();
+
+    url::Origin& origin;
+    base::TimeDelta last_updated;  // timestamp (epoch seconds)
+    int visits;
+    int playbacks;
+    base::TimeDelta last_playback_time;
+    bool has_high_score;
+  };
+
+ private:
+  friend class MediaHistoryStoreInternal;
+
+  explicit MediaHistoryEngagementTable(
+      scoped_refptr<base::UpdateableSequencedTaskRunner> db_task_runner);
+  ~MediaHistoryEngagementTable() override;
+
+  // MediaHistoryTableBase:
+  sql::InitStatus CreateTableIfNonExistent() override;
+
+  DISALLOW_COPY_AND_ASSIGN(MediaHistoryEngagementTable);
+};
+
+}  // namespace media_history
+
+#endif  // CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_ENGAGEMENT_TABLE_H_
diff --git a/chrome/browser/media/history/media_history_keyed_service.cc b/chrome/browser/media/history/media_history_keyed_service.cc
new file mode 100644
index 0000000..cc59e08e
--- /dev/null
+++ b/chrome/browser/media/history/media_history_keyed_service.cc
@@ -0,0 +1,32 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media/history/media_history_keyed_service.h"
+
+#include "base/task/post_task.h"
+#include "chrome/browser/media/history/media_history_keyed_service_factory.h"
+#include "content/public/browser/browser_context.h"
+
+namespace media_history {
+
+MediaHistoryKeyedService::MediaHistoryKeyedService(
+    content::BrowserContext* browser_context) {
+  DCHECK(!browser_context->IsOffTheRecord());
+
+  auto db_task_runner = base::CreateUpdateableSequencedTaskRunner(
+      {base::ThreadPool(), base::MayBlock(), base::TaskPriority::USER_VISIBLE,
+       base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
+
+  media_history_store_ = std::make_unique<MediaHistoryStore>(
+      Profile::FromBrowserContext(browser_context), std::move(db_task_runner));
+}
+
+// static
+MediaHistoryKeyedService* MediaHistoryKeyedService::Get(Profile* profile) {
+  return MediaHistoryKeyedServiceFactory::GetForProfile(profile);
+}
+
+MediaHistoryKeyedService::~MediaHistoryKeyedService() = default;
+
+}  // namespace media_history
diff --git a/chrome/browser/media/history/media_history_keyed_service.h b/chrome/browser/media/history/media_history_keyed_service.h
new file mode 100644
index 0000000..14a7420
--- /dev/null
+++ b/chrome/browser/media/history/media_history_keyed_service.h
@@ -0,0 +1,34 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_KEYED_SERVICE_H_
+#define CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_KEYED_SERVICE_H_
+
+#include "base/macros.h"
+#include "chrome/browser/media/history/media_history_store.h"
+#include "components/keyed_service/core/keyed_service.h"
+
+namespace content {
+class BrowserContext;
+}  // namespace content
+
+namespace media_history {
+
+class MediaHistoryKeyedService : public KeyedService {
+ public:
+  explicit MediaHistoryKeyedService(content::BrowserContext* browser_context);
+  ~MediaHistoryKeyedService() override;
+
+  // Returns the instance attached to the given |profile|.
+  static MediaHistoryKeyedService* Get(Profile* profile);
+
+ private:
+  std::unique_ptr<MediaHistoryStore> media_history_store_;
+
+  DISALLOW_COPY_AND_ASSIGN(MediaHistoryKeyedService);
+};
+
+}  // namespace media_history
+
+#endif  // CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_KEYED_SERVICE_H_
diff --git a/chrome/browser/media/history/media_history_keyed_service_factory.cc b/chrome/browser/media/history/media_history_keyed_service_factory.cc
new file mode 100644
index 0000000..1cfcdd5
--- /dev/null
+++ b/chrome/browser/media/history/media_history_keyed_service_factory.cc
@@ -0,0 +1,50 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media/history/media_history_keyed_service_factory.h"
+
+#include "base/logging.h"
+#include "chrome/browser/media/history/media_history_keyed_service.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "content/public/browser/browser_context.h"
+
+namespace media_history {
+
+// static
+MediaHistoryKeyedService* MediaHistoryKeyedServiceFactory::GetForProfile(
+    Profile* profile) {
+  if (profile->IsOffTheRecord())
+    return nullptr;
+
+  return static_cast<MediaHistoryKeyedService*>(
+      GetInstance()->GetServiceForBrowserContext(profile, true));
+}
+
+// static
+MediaHistoryKeyedServiceFactory*
+MediaHistoryKeyedServiceFactory::GetInstance() {
+  static base::NoDestructor<MediaHistoryKeyedServiceFactory> factory;
+  return factory.get();
+}
+
+MediaHistoryKeyedServiceFactory::MediaHistoryKeyedServiceFactory()
+    : BrowserContextKeyedServiceFactory(
+          "MediaHistoryKeyedService",
+          BrowserContextDependencyManager::GetInstance()) {}
+
+MediaHistoryKeyedServiceFactory::~MediaHistoryKeyedServiceFactory() = default;
+
+bool MediaHistoryKeyedServiceFactory::ServiceIsCreatedWithBrowserContext()
+    const {
+  return true;
+}
+
+KeyedService* MediaHistoryKeyedServiceFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  DCHECK(!context->IsOffTheRecord());
+
+  return new MediaHistoryKeyedService(context);
+}
+
+}  // namespace media_history
diff --git a/chrome/browser/media/history/media_history_keyed_service_factory.h b/chrome/browser/media/history/media_history_keyed_service_factory.h
new file mode 100644
index 0000000..7bf349b2
--- /dev/null
+++ b/chrome/browser/media/history/media_history_keyed_service_factory.h
@@ -0,0 +1,45 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_KEYED_SERVICE_FACTORY_H_
+#define CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_KEYED_SERVICE_FACTORY_H_
+
+#include "base/no_destructor.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+class KeyedService;
+class Profile;
+
+namespace content {
+class BrowserContext;
+}  // namespace content
+
+namespace media_history {
+
+class MediaHistoryKeyedService;
+
+class MediaHistoryKeyedServiceFactory
+    : public BrowserContextKeyedServiceFactory {
+ public:
+  static MediaHistoryKeyedService* GetForProfile(Profile* profile);
+  static MediaHistoryKeyedServiceFactory* GetInstance();
+
+ protected:
+  bool ServiceIsCreatedWithBrowserContext() const override;
+
+ private:
+  friend class base::NoDestructor<MediaHistoryKeyedServiceFactory>;
+
+  MediaHistoryKeyedServiceFactory();
+  ~MediaHistoryKeyedServiceFactory() override;
+
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const override;
+
+  DISALLOW_COPY_AND_ASSIGN(MediaHistoryKeyedServiceFactory);
+};
+
+}  // namespace media_history
+
+#endif  // CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_KEYED_SERVICE_FACTORY_H_
diff --git a/chrome/browser/media/history/media_history_keyed_service_factory_unittest.cc b/chrome/browser/media/history/media_history_keyed_service_factory_unittest.cc
new file mode 100644
index 0000000..3c47996d
--- /dev/null
+++ b/chrome/browser/media/history/media_history_keyed_service_factory_unittest.cc
@@ -0,0 +1,29 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media/history/media_history_keyed_service_factory.h"
+
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/test/browser_task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media_history {
+
+class MediaHistoryKeyedServiceFactoryUnitTest : public testing::Test {
+ public:
+  MediaHistoryKeyedServiceFactoryUnitTest() = default;
+
+ private:
+  content::BrowserTaskEnvironment task_environment_;
+};
+
+TEST_F(MediaHistoryKeyedServiceFactoryUnitTest, GetForOTRProfile) {
+  TestingProfile profile;
+  Profile* otr_profile = profile.GetOffTheRecordProfile();
+
+  EXPECT_EQ(nullptr,
+            MediaHistoryKeyedServiceFactory::GetForProfile(otr_profile));
+}
+
+}  // namespace media_history
diff --git a/chrome/browser/media/history/media_history_origin_table.cc b/chrome/browser/media/history/media_history_origin_table.cc
new file mode 100644
index 0000000..f9adf85
--- /dev/null
+++ b/chrome/browser/media/history/media_history_origin_table.cc
@@ -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.
+
+#include "chrome/browser/media/history/media_history_origin_table.h"
+
+#include "base/strings/stringprintf.h"
+#include "sql/statement.h"
+
+namespace media_history {
+
+MediaHistoryOriginTable::MediaHistoryOriginTable(
+    scoped_refptr<base::UpdateableSequencedTaskRunner> db_task_runner)
+    : MediaHistoryTableBase(std::move(db_task_runner)) {}
+
+MediaHistoryOriginTable::~MediaHistoryOriginTable() = default;
+
+sql::InitStatus MediaHistoryOriginTable::CreateTableIfNonExistent() {
+  if (!CanAccessDatabase())
+    return sql::INIT_FAILURE;
+
+  bool success = DB()->Execute(
+      "CREATE TABLE IF NOT EXISTS origin("
+      "id INTEGER PRIMARY KEY AUTOINCREMENT,"
+      "origin TEXT NOT NULL UNIQUE)");
+
+  if (!success) {
+    ResetDB();
+    LOG(ERROR) << "Failed to create media history origin table.";
+    return sql::INIT_FAILURE;
+  }
+
+  return sql::INIT_OK;
+}
+
+void MediaHistoryOriginTable::CreateOriginId(const std::string& origin) {
+  if (!CanAccessDatabase())
+    return;
+
+  if (!DB()->BeginTransaction()) {
+    LOG(ERROR) << "Failed to begin the transaction to create an origin ID.";
+    return;
+  }
+
+  // Insert the origin into the table if it does not exist.
+  sql::Statement statement(
+      DB()->GetCachedStatement(SQL_FROM_HERE,
+                               "INSERT OR IGNORE INTO origin"
+                               "(origin) "
+                               "VALUES (?)"));
+  statement.BindString(0, origin);
+  if (!statement.Run()) {
+    DB()->RollbackTransaction();
+    LOG(ERROR) << "Failed to create the origin ID.";
+    return;
+  }
+
+  DB()->CommitTransaction();
+}
+
+}  // namespace media_history
diff --git a/chrome/browser/media/history/media_history_origin_table.h b/chrome/browser/media/history/media_history_origin_table.h
new file mode 100644
index 0000000..2ecb1e0
--- /dev/null
+++ b/chrome/browser/media/history/media_history_origin_table.h
@@ -0,0 +1,32 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_ORIGIN_TABLE_H_
+#define CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_ORIGIN_TABLE_H_
+
+#include "base/updateable_sequenced_task_runner.h"
+#include "chrome/browser/media/history/media_history_table_base.h"
+#include "sql/init_status.h"
+
+namespace media_history {
+
+class MediaHistoryOriginTable : public MediaHistoryTableBase {
+ private:
+  friend class MediaHistoryStoreInternal;
+
+  explicit MediaHistoryOriginTable(
+      scoped_refptr<base::UpdateableSequencedTaskRunner> db_task_runner);
+  ~MediaHistoryOriginTable() override;
+
+  // MediaHistoryTableBase:
+  sql::InitStatus CreateTableIfNonExistent() override;
+
+  void CreateOriginId(const std::string& origin);
+
+  DISALLOW_COPY_AND_ASSIGN(MediaHistoryOriginTable);
+};
+
+}  // namespace media_history
+
+#endif  // CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_ORIGIN_TABLE_H_
diff --git a/chrome/browser/media/history/media_history_playback_table.cc b/chrome/browser/media/history/media_history_playback_table.cc
new file mode 100644
index 0000000..6014d97
--- /dev/null
+++ b/chrome/browser/media/history/media_history_playback_table.cc
@@ -0,0 +1,115 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media/history/media_history_playback_table.h"
+
+#include "base/strings/stringprintf.h"
+#include "base/updateable_sequenced_task_runner.h"
+#include "chrome/browser/media/history/media_player_watchtime.h"
+#include "content/public/browser/media_player_id.h"
+#include "sql/statement.h"
+
+namespace media_history {
+
+MediaHistoryPlaybackTable::MediaHistoryPlaybackTable(
+    scoped_refptr<base::UpdateableSequencedTaskRunner> db_task_runner)
+    : MediaHistoryTableBase(std::move(db_task_runner)) {}
+
+MediaHistoryPlaybackTable::~MediaHistoryPlaybackTable() = default;
+
+sql::InitStatus MediaHistoryPlaybackTable::CreateTableIfNonExistent() {
+  if (!CanAccessDatabase())
+    return sql::INIT_FAILURE;
+
+  bool success = DB()->Execute(
+      "CREATE TABLE IF NOT EXISTS playback("
+      "id INTEGER PRIMARY KEY AUTOINCREMENT,"
+      "origin_id INTEGER NOT NULL,"
+      "url TEXT,"
+      "timestamp_ms INTEGER,"
+      "has_audio INTEGER,"
+      "has_video INTEGER,"
+      "watchtime_ms INTEGER,"
+      "CONSTRAINT fk_origin "
+      "FOREIGN KEY (origin_id) "
+      "REFERENCES origin(id) "
+      "ON DELETE CASCADE"
+      ")");
+
+  if (success) {
+    success = DB()->Execute(
+        "CREATE INDEX IF NOT EXISTS origin_id_index ON "
+        "playback (origin_id)");
+  }
+
+  if (success) {
+    success = DB()->Execute(
+        "CREATE INDEX IF NOT EXISTS timestamp_index ON "
+        "playback (timestamp_ms)");
+  }
+
+  if (!success) {
+    ResetDB();
+    LOG(ERROR) << "Failed to create media history playback table.";
+    return sql::INIT_FAILURE;
+  }
+
+  return sql::INIT_OK;
+}
+
+void MediaHistoryPlaybackTable::SavePlayback(
+    const content::MediaPlayerId& id,
+    const content::MediaPlayerWatchtime& watchtime) {
+  if (!CanAccessDatabase())
+    return;
+
+  if (!DB()->BeginTransaction())
+    return;
+
+  sql::Statement statement(DB()->GetCachedStatement(
+      SQL_FROM_HERE,
+      "INSERT INTO playback "
+      "(origin_id, has_audio, has_video, watchtime_ms, url, timestamp_ms) "
+      "VALUES ((SELECT id FROM origin WHERE origin = ?), ?, ?, ?, ?, ?)"));
+  statement.BindString(0, watchtime.origin);
+  statement.BindBool(1, watchtime.has_audio);
+  statement.BindBool(2, watchtime.has_video);
+  statement.BindInt(3, watchtime.cumulative_watchtime.InMilliseconds());
+  statement.BindString(4, watchtime.url);
+  statement.BindInt(5, watchtime.last_timestamp.InMilliseconds());
+  if (!statement.Run()) {
+    DB()->RollbackTransaction();
+    return;
+  }
+
+  DB()->CommitTransaction();
+}
+
+MediaHistoryPlaybackTable::MediaHistoryPlaybacks
+MediaHistoryPlaybackTable::GetRecentPlaybacks(int num_results) {
+  MediaHistoryPlaybacks results;
+
+  sql::Statement statement(
+      DB()->GetCachedStatement(SQL_FROM_HERE,
+                               "SELECT id, origin_id, has_audio, has_video, "
+                               "watchtime_ms, timestamp_ms"
+                               "FROM playback ORDER BY id DESC"
+                               "LIMIT ?"));
+  statement.BindInt(0, num_results);
+
+  while (statement.Step()) {
+    MediaHistoryPlaybackTable::MediaHistoryPlayback playback;
+    playback.has_audio = statement.ColumnInt(2);
+    playback.has_video = statement.ColumnInt(3);
+    playback.watchtime =
+        base::TimeDelta::FromMilliseconds(statement.ColumnInt(4));
+    playback.timestamp =
+        base::TimeDelta::FromMilliseconds(statement.ColumnInt(5));
+    results.push_back(playback);
+  }
+
+  return results;
+}
+
+}  // namespace media_history
diff --git a/chrome/browser/media/history/media_history_playback_table.h b/chrome/browser/media/history/media_history_playback_table.h
new file mode 100644
index 0000000..1deb140
--- /dev/null
+++ b/chrome/browser/media/history/media_history_playback_table.h
@@ -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.
+
+#ifndef CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_PLAYBACK_TABLE_H_
+#define CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_PLAYBACK_TABLE_H_
+
+#include "chrome/browser/media/history/media_history_table_base.h"
+#include "sql/init_status.h"
+
+namespace base {
+class UpdateableSequencedTaskRunner;
+}  // namespace base
+
+namespace content {
+struct MediaPlayerId;
+struct MediaPlayerWatchtime;
+}  // namespace content
+
+namespace media_history {
+
+class MediaHistoryPlaybackTable : public MediaHistoryTableBase {
+ public:
+  struct MediaHistoryPlayback {
+    MediaHistoryPlayback() = default;
+
+    bool has_audio;
+    bool has_video;
+    base::TimeDelta watchtime;
+    base::TimeDelta timestamp;
+  };
+
+  using MediaHistoryPlaybacks = std::vector<MediaHistoryPlayback>;
+
+ private:
+  friend class MediaHistoryStoreInternal;
+
+  explicit MediaHistoryPlaybackTable(
+      scoped_refptr<base::UpdateableSequencedTaskRunner> db_task_runner);
+  ~MediaHistoryPlaybackTable() override;
+
+  // MediaHistoryTableBase:
+  sql::InitStatus CreateTableIfNonExistent() override;
+
+  void SavePlayback(const content::MediaPlayerId& id,
+                    const content::MediaPlayerWatchtime& watchtime);
+
+  // Returns |num_results| playbacks sorted by time with the
+  // newest first.
+  MediaHistoryPlaybacks GetRecentPlaybacks(int num_results);
+
+  DISALLOW_COPY_AND_ASSIGN(MediaHistoryPlaybackTable);
+};
+
+}  // namespace media_history
+
+#endif  // CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_PLAYBACK_TABLE_H_
diff --git a/chrome/browser/media/history/media_history_store.cc b/chrome/browser/media/history/media_history_store.cc
new file mode 100644
index 0000000..1cebe6e
--- /dev/null
+++ b/chrome/browser/media/history/media_history_store.cc
@@ -0,0 +1,168 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media/history/media_history_store.h"
+
+#include "chrome/browser/media/history/media_player_watchtime.h"
+#include "content/public/browser/media_player_id.h"
+
+namespace {
+
+constexpr int kCurrentVersionNumber = 1;
+constexpr int kCompatibleVersionNumber = 1;
+
+constexpr base::FilePath::CharType kMediaHistoryDatabaseName[] =
+    FILE_PATH_LITERAL("Media History");
+
+}  // namespace
+
+int GetCurrentVersion() {
+  return kCurrentVersionNumber;
+}
+
+namespace media_history {
+
+// Refcounted as it is created, initialized and destroyed on a different thread
+// from the DB sequence provided to the constructor of this class that is
+// required for all methods performing database access.
+class MediaHistoryStoreInternal
+    : public base::RefCountedThreadSafe<MediaHistoryStoreInternal> {
+ private:
+  friend class base::RefCountedThreadSafe<MediaHistoryStoreInternal>;
+  friend class MediaHistoryStore;
+
+  explicit MediaHistoryStoreInternal(
+      Profile* profile,
+      scoped_refptr<base::UpdateableSequencedTaskRunner> db_task_runner);
+  virtual ~MediaHistoryStoreInternal();
+
+  void SavePlayback(const content::MediaPlayerId& id,
+                    const content::MediaPlayerWatchtime& watchtime);
+
+ private:
+  // Opens the database file from the profile path. Separated from the
+  // constructor to ease construction/destruction of this object on one thread
+  // and database access on the DB sequence of |db_task_runner_|.
+  void Initialize();
+  sql::InitStatus CreateOrUpgradeIfNeeded();
+  sql::InitStatus InitializeTables();
+  void CreateOriginId(const std::string& origin);
+
+  scoped_refptr<base::UpdateableSequencedTaskRunner> db_task_runner_;
+  base::FilePath db_path_;
+  std::unique_ptr<sql::Database> db_;
+  sql::MetaTable meta_table_;
+  scoped_refptr<MediaHistoryEngagementTable> engagement_table_;
+  scoped_refptr<MediaHistoryOriginTable> origin_table_;
+  scoped_refptr<MediaHistoryPlaybackTable> playback_table_;
+  bool initialization_successful_;
+
+  DISALLOW_COPY_AND_ASSIGN(MediaHistoryStoreInternal);
+};
+
+MediaHistoryStoreInternal::MediaHistoryStoreInternal(
+    Profile* profile,
+    scoped_refptr<base::UpdateableSequencedTaskRunner> db_task_runner)
+    : db_task_runner_(db_task_runner),
+      db_path_(profile->GetPath().Append(kMediaHistoryDatabaseName)),
+      engagement_table_(new MediaHistoryEngagementTable(db_task_runner_)),
+      origin_table_(new MediaHistoryOriginTable(db_task_runner_)),
+      playback_table_(new MediaHistoryPlaybackTable(db_task_runner_)),
+      initialization_successful_(false) {}
+
+MediaHistoryStoreInternal::~MediaHistoryStoreInternal() {
+  db_task_runner_->ReleaseSoon(FROM_HERE, std::move(engagement_table_));
+  db_task_runner_->ReleaseSoon(FROM_HERE, std::move(origin_table_));
+  db_task_runner_->ReleaseSoon(FROM_HERE, std::move(playback_table_));
+  db_task_runner_->DeleteSoon(FROM_HERE, std::move(db_));
+}
+
+void MediaHistoryStoreInternal::SavePlayback(
+    const content::MediaPlayerId& id,
+    const content::MediaPlayerWatchtime& watchtime) {
+  DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
+  if (!initialization_successful_)
+    return;
+
+  CreateOriginId(watchtime.origin);
+  db_task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&MediaHistoryPlaybackTable::SavePlayback,
+                                playback_table_, id, watchtime));
+}
+
+void MediaHistoryStoreInternal::Initialize() {
+  DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
+  db_ = std::make_unique<sql::Database>();
+  db_->set_histogram_tag("MediaHistory");
+
+  bool success = db_->Open(db_path_);
+  DCHECK(success);
+
+  db_->Preload();
+
+  meta_table_.Init(db_.get(), GetCurrentVersion(), kCompatibleVersionNumber);
+  sql::InitStatus status = CreateOrUpgradeIfNeeded();
+  if (status != sql::INIT_OK) {
+    LOG(ERROR) << "Failed to create or update the media history store.";
+    return;
+  }
+
+  status = InitializeTables();
+  if (status != sql::INIT_OK) {
+    LOG(ERROR) << "Failed to initialize the media history store tables.";
+    return;
+  }
+
+  initialization_successful_ = true;
+}
+
+sql::InitStatus MediaHistoryStoreInternal::CreateOrUpgradeIfNeeded() {
+  if (!db_)
+    return sql::INIT_FAILURE;
+
+  int cur_version = meta_table_.GetVersionNumber();
+  if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) {
+    LOG(WARNING) << "Media history database is too new.";
+    return sql::INIT_TOO_NEW;
+  }
+
+  LOG_IF(WARNING, cur_version < GetCurrentVersion())
+      << "Media history database version " << cur_version
+      << " is too old to handle.";
+
+  return sql::INIT_OK;
+}
+
+sql::InitStatus MediaHistoryStoreInternal::InitializeTables() {
+  DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
+  sql::InitStatus status = engagement_table_->Initialize(db_.get());
+  if (status == sql::INIT_OK)
+    status = origin_table_->Initialize(db_.get());
+  if (status == sql::INIT_OK)
+    status = playback_table_->Initialize(db_.get());
+
+  return status;
+}
+
+void MediaHistoryStoreInternal::CreateOriginId(const std::string& origin) {
+  DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
+  if (!initialization_successful_)
+    return;
+
+  db_task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&MediaHistoryOriginTable::CreateOriginId,
+                                origin_table_, origin));
+}
+
+MediaHistoryStore::MediaHistoryStore(
+    Profile* profile,
+    scoped_refptr<base::UpdateableSequencedTaskRunner> db_task_runner)
+    : db_(new MediaHistoryStoreInternal(profile, db_task_runner)) {
+  db_task_runner->PostTask(
+      FROM_HERE, base::BindOnce(&MediaHistoryStoreInternal::Initialize, db_));
+}
+
+MediaHistoryStore::~MediaHistoryStore() {}
+
+}  // namespace media_history
diff --git a/chrome/browser/media/history/media_history_store.h b/chrome/browser/media/history/media_history_store.h
new file mode 100644
index 0000000..ab41389
--- /dev/null
+++ b/chrome/browser/media/history/media_history_store.h
@@ -0,0 +1,42 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_STORE_H_
+#define CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_STORE_H_
+
+#include <memory>
+
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/updateable_sequenced_task_runner.h"
+#include "chrome/browser/media/history/media_history_engagement_table.h"
+#include "chrome/browser/media/history/media_history_origin_table.h"
+#include "chrome/browser/media/history/media_history_playback_table.h"
+#include "chrome/browser/profiles/profile.h"
+#include "sql/database.h"
+#include "sql/init_status.h"
+#include "sql/meta_table.h"
+
+namespace sql {
+class Database;
+}
+
+namespace media_history {
+
+class MediaHistoryStoreInternal;
+
+class MediaHistoryStore {
+ public:
+  MediaHistoryStore(
+      Profile* profile,
+      scoped_refptr<base::UpdateableSequencedTaskRunner> db_task_runner);
+  ~MediaHistoryStore();
+
+ private:
+  scoped_refptr<MediaHistoryStoreInternal> db_;
+};
+
+}  // namespace media_history
+
+#endif  // CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_STORE_H_
diff --git a/chrome/browser/media/history/media_history_store_unittest.cc b/chrome/browser/media/history/media_history_store_unittest.cc
new file mode 100644
index 0000000..80d525f
--- /dev/null
+++ b/chrome/browser/media/history/media_history_store_unittest.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 "chrome/browser/media/history/media_history_store.h"
+
+#include "base/files/file_path.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/task/post_task.h"
+#include "base/task/thread_pool/pooled_sequenced_task_runner.h"
+#include "base/test/test_timeouts.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/test/browser_task_environment.h"
+#include "content/public/test/test_utils.h"
+#include "sql/database.h"
+#include "sql/statement.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media_history {
+
+class MediaHistoryStoreUnitTest : public testing::Test {
+ public:
+  MediaHistoryStoreUnitTest() = default;
+  void SetUp() override {
+    // Set up the profile.
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    TestingProfile::Builder profile_builder;
+    profile_builder.SetPath(temp_dir_.GetPath());
+
+    // Set up the media history store.
+    scoped_refptr<base::UpdateableSequencedTaskRunner> task_runner =
+        base::CreateUpdateableSequencedTaskRunner(
+            {base::ThreadPool(), base::MayBlock(),
+             base::WithBaseSyncPrimitives()});
+    media_history_store_ = std::make_unique<MediaHistoryStore>(
+        profile_builder.Build().get(), task_runner);
+
+    // Sleep the thread to allow the media history store to asynchronously
+    // create the database and tables before proceeding with the tests and
+    // tearing down the temporary directory.
+    content::RunAllTasksUntilIdle();
+
+    // Set up the local DB connection used for assertions.
+    base::FilePath db_file =
+        temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Media History"));
+    EXPECT_TRUE(db_.Open(db_file));
+  }
+
+ protected:
+  sql::Database& GetDB() { return db_; }
+  content::BrowserTaskEnvironment task_environment_;
+
+ private:
+  sql::Database db_;
+  std::unique_ptr<MediaHistoryStore> media_history_store_;
+  base::ScopedTempDir temp_dir_;
+};
+
+TEST_F(MediaHistoryStoreUnitTest, CreateDatabaseTables) {
+  ASSERT_TRUE(GetDB().DoesTableExist("mediaEngagement"));
+  ASSERT_TRUE(GetDB().DoesTableExist("origin"));
+  ASSERT_TRUE(GetDB().DoesTableExist("playback"));
+}
+
+}  // namespace media_history
diff --git a/chrome/browser/media/history/media_history_table_base.cc b/chrome/browser/media/history/media_history_table_base.cc
new file mode 100644
index 0000000..31539bb
--- /dev/null
+++ b/chrome/browser/media/history/media_history_table_base.cc
@@ -0,0 +1,44 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media/history/media_history_table_base.h"
+
+#include "base/updateable_sequenced_task_runner.h"
+
+namespace media_history {
+
+base::UpdateableSequencedTaskRunner* MediaHistoryTableBase::GetTaskRunner() {
+  return db_task_runner_.get();
+}
+
+MediaHistoryTableBase::MediaHistoryTableBase(
+    scoped_refptr<base::UpdateableSequencedTaskRunner> db_task_runner)
+    : db_task_runner_(std::move(db_task_runner)), db_(nullptr) {}
+
+MediaHistoryTableBase::~MediaHistoryTableBase() = default;
+
+sql::InitStatus MediaHistoryTableBase::Initialize(sql::Database* db) {
+  DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
+  DCHECK(db);
+
+  db_ = db;
+  return CreateTableIfNonExistent();
+}
+
+sql::Database* MediaHistoryTableBase::DB() {
+  DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
+  return db_;
+}
+
+void MediaHistoryTableBase::ResetDB() {
+  DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
+  db_ = nullptr;
+}
+
+bool MediaHistoryTableBase::CanAccessDatabase() {
+  DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
+  return db_;
+}
+
+}  // namespace media_history
diff --git a/chrome/browser/media/history/media_history_table_base.h b/chrome/browser/media/history/media_history_table_base.h
new file mode 100644
index 0000000..a94f1961
--- /dev/null
+++ b/chrome/browser/media/history/media_history_table_base.h
@@ -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.
+
+#ifndef CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_TABLE_BASE_H_
+#define CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_TABLE_BASE_H_
+
+#include "base/memory/ref_counted.h"
+#include "sql/init_status.h"
+
+namespace base {
+class UpdateableSequencedTaskRunner;
+}  // namespace base
+
+namespace sql {
+class Database;
+}  // namespace sql
+
+namespace media_history {
+
+// Base class for all tables in the MediaHistoryTableBase.
+class MediaHistoryTableBase
+    : public base::RefCountedThreadSafe<MediaHistoryTableBase> {
+ protected:
+  explicit MediaHistoryTableBase(
+      scoped_refptr<base::UpdateableSequencedTaskRunner> db_task_runner);
+  virtual ~MediaHistoryTableBase();
+
+  // Returns a UpdateableSequencedTaskRunner that is used to run tasks on the DB
+  // sequence.
+  base::UpdateableSequencedTaskRunner* GetTaskRunner();
+
+  // DB sequence functions.
+  virtual sql::InitStatus CreateTableIfNonExistent() = 0;
+  sql::InitStatus Initialize(sql::Database* db);
+  sql::Database* DB();
+  void ResetDB();
+  bool CanAccessDatabase();
+
+ private:
+  friend class base::RefCountedThreadSafe<MediaHistoryTableBase>;
+
+  scoped_refptr<base::UpdateableSequencedTaskRunner> db_task_runner_;
+  sql::Database* db_;
+
+  DISALLOW_COPY_AND_ASSIGN(MediaHistoryTableBase);
+};
+
+}  // namespace media_history
+
+#endif  // CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_TABLE_BASE_H_
diff --git a/chrome/browser/media/history/media_player_watchtime.cc b/chrome/browser/media/history/media_player_watchtime.cc
new file mode 100644
index 0000000..bbf0132
--- /dev/null
+++ b/chrome/browser/media/history/media_player_watchtime.cc
@@ -0,0 +1,21 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media/history/media_player_watchtime.h"
+
+namespace content {
+
+MediaPlayerWatchtime::MediaPlayerWatchtime(bool has_audio,
+                                           bool has_video,
+                                           base::TimeDelta cumulative_watchtime,
+                                           base::TimeDelta last_timestamp)
+    : has_audio(has_audio),
+      has_video(has_video),
+      cumulative_watchtime(cumulative_watchtime),
+      last_timestamp(last_timestamp) {}
+
+MediaPlayerWatchtime::MediaPlayerWatchtime(const MediaPlayerWatchtime& other) =
+    default;
+
+}  // namespace content
diff --git a/chrome/browser/media/history/media_player_watchtime.h b/chrome/browser/media/history/media_player_watchtime.h
new file mode 100644
index 0000000..4622c33
--- /dev/null
+++ b/chrome/browser/media/history/media_player_watchtime.h
@@ -0,0 +1,32 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MEDIA_HISTORY_MEDIA_PLAYER_WATCHTIME_H_
+#define CHROME_BROWSER_MEDIA_HISTORY_MEDIA_PLAYER_WATCHTIME_H_
+
+#include <string>
+
+#include "base/time/time.h"
+
+namespace content {
+
+struct MediaPlayerWatchtime {
+  MediaPlayerWatchtime(bool has_audio,
+                       bool has_video,
+                       base::TimeDelta cumulative_watchtime,
+                       base::TimeDelta last_timestamp);
+  MediaPlayerWatchtime(const MediaPlayerWatchtime& other);
+  ~MediaPlayerWatchtime() = default;
+
+  bool has_audio;
+  bool has_video;
+  base::TimeDelta cumulative_watchtime;
+  base::TimeDelta last_timestamp;
+  std::string origin;
+  std::string url;
+};
+
+}  // namespace content
+
+#endif  // CHROME_BROWSER_MEDIA_HISTORY_MEDIA_PLAYER_WATCHTIME_H_
diff --git a/chrome/browser/net/samesite_cookies_policy_browsertest.cc b/chrome/browser/net/samesite_cookies_policy_browsertest.cc
new file mode 100644
index 0000000..f11897c
--- /dev/null
+++ b/chrome/browser/net/samesite_cookies_policy_browsertest.cc
@@ -0,0 +1,207 @@
+// 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 <memory>
+
+#include "base/command_line.h"
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/policy/policy_test_utils.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "components/policy/core/common/policy_map.h"
+#include "components/policy/policy_constants.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/test_utils.h"
+#include "net/base/features.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace policy {
+
+namespace {
+const char kURL[] = "http://example.com";
+}  // namespace
+
+// Test fixture that enables (if param is true) and disables (if param is false)
+// SameSite-by-default and Cookies-without-SameSite-must-be-Secure, to test the
+// policies that override those features, under both conditions.
+class SameSiteCookiesPolicyTest : public PolicyTest,
+                                  public ::testing::WithParamInterface<bool> {
+ public:
+  SameSiteCookiesPolicyTest() {
+    std::vector<base::Feature> samesite_features = {
+        net::features::kSameSiteByDefaultCookies,
+        net::features::kCookiesWithoutSameSiteMustBeSecure};
+    if (AreSameSiteFeaturesEnabled()) {
+      feature_list_.InitWithFeatures(samesite_features /* enabled */, {});
+    } else {
+      feature_list_.InitWithFeatures({}, samesite_features /* disabled */);
+    }
+  }
+
+  ~SameSiteCookiesPolicyTest() = default;
+
+ protected:
+  bool AreSameSiteFeaturesEnabled() { return GetParam(); }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_P(SameSiteCookiesPolicyTest,
+                       DefaultLegacyCookieAccessSettingIsAllow) {
+  PolicyMap policies;
+  // Set a policy to allow Legacy access for all cookies.
+  SetPolicy(&policies, key::kLegacySameSiteCookieBehaviorEnabled,
+            std::make_unique<base::Value>(1));
+  UpdateProviderPolicy(policies);
+
+  GURL url(kURL);
+  Profile* profile = browser()->profile();
+
+  // No cookies at startup
+  ASSERT_TRUE(content::GetCookies(profile, url).empty());
+
+  // Set a cookie from a same-site context. The cookie does not specify
+  // SameSite, so it may default to Lax if the SameSite features are enabled.
+  // Since the context used is same-site, it should always work.
+  EXPECT_TRUE(content::SetCookie(
+      profile, url, "samesite-unspecified=1",
+      net::CookieOptions::SameSiteCookieContext::SAME_SITE_LAX));
+  EXPECT_EQ("samesite-unspecified=1", content::GetCookies(profile, url));
+
+  // Overwrite the cookie from a cross-site context. Because we have a policy
+  // that allows Legacy access for all domains, this will work even if the
+  // SameSite features are enabled. (It works regardless, if they are disabled.)
+  EXPECT_TRUE(content::SetCookie(
+      profile, url, "samesite-unspecified=2",
+      net::CookieOptions::SameSiteCookieContext::CROSS_SITE));
+  // Cookie has the new value because we were able to successfully overwrite it.
+  EXPECT_EQ("samesite-unspecified=2", content::GetCookies(profile, url));
+  // Fetching the cookies from a cross-site context also works because of the
+  // policy.
+  EXPECT_EQ(
+      "samesite-unspecified=2",
+      content::GetCookies(
+          profile, url, net::CookieOptions::SameSiteCookieContext::CROSS_SITE));
+}
+
+IN_PROC_BROWSER_TEST_P(SameSiteCookiesPolicyTest,
+                       DefaultLegacyCookieAccessSettingIsBlock) {
+  PolicyMap policies;
+  // Set a policy to block Legacy access for all cookies.
+  SetPolicy(&policies, key::kLegacySameSiteCookieBehaviorEnabled,
+            std::make_unique<base::Value>(2));
+  UpdateProviderPolicy(policies);
+
+  GURL url(kURL);
+  Profile* profile = browser()->profile();
+
+  // No cookies at startup
+  ASSERT_TRUE(content::GetCookies(profile, url).empty());
+
+  // Set a cookie from a same-site context. The cookie does not specify
+  // SameSite, so it may default to Lax if the SameSite features are enabled.
+  // Since the context used is same-site, it should always work.
+  EXPECT_TRUE(content::SetCookie(
+      profile, url, "samesite-unspecified=1",
+      net::CookieOptions::SameSiteCookieContext::SAME_SITE_LAX));
+  EXPECT_EQ("samesite-unspecified=1", content::GetCookies(profile, url));
+
+  // Overwrite the cookie from a cross-site context. Because we have a policy
+  // that blocks Legacy access for all domains, this will not work even if the
+  // SameSite features are disabled. (It doesn't work regardless, if they are
+  // enabled.)
+  EXPECT_FALSE(content::SetCookie(
+      profile, url, "samesite-unspecified=2",
+      net::CookieOptions::SameSiteCookieContext::CROSS_SITE));
+  // Cookie still has the previous value because re-setting it failed.
+  EXPECT_EQ("samesite-unspecified=1", content::GetCookies(profile, url));
+  // Fetching the unspecified-samesite cookie from a cross-site context does not
+  // work because of the policy.
+  EXPECT_EQ("", content::GetCookies(
+                    profile, url,
+                    net::CookieOptions::SameSiteCookieContext::CROSS_SITE));
+}
+
+IN_PROC_BROWSER_TEST_P(SameSiteCookiesPolicyTest,
+                       AllowLegacyCookieAccessForDomain) {
+  GURL legacy_allowed_domain_url(kURL);
+  GURL other_domain_url("http://other-domain.example");
+
+  // Set a policy to allow Legacy cookie access for one domain only.
+  auto policy_value = std::make_unique<base::Value>(base::Value::Type::LIST);
+  policy_value->Append(legacy_allowed_domain_url.host());
+
+  PolicyMap policies;
+  // Set a policy to allow Legacy access for the given domain only.
+  SetPolicy(&policies, key::kLegacySameSiteCookieBehaviorEnabledForDomainList,
+            std::move(policy_value));
+  UpdateProviderPolicy(policies);
+
+  Profile* profile = browser()->profile();
+
+  // No cookies at startup
+  ASSERT_TRUE(content::GetCookies(profile, legacy_allowed_domain_url).empty());
+  ASSERT_TRUE(content::GetCookies(profile, other_domain_url).empty());
+
+  // Set a cookie from a same-site context. The cookie does not specify
+  // SameSite, so it may default to Lax if the SameSite features are enabled.
+  // Since the context used is same-site, it should always work.
+  EXPECT_TRUE(content::SetCookie(
+      profile, legacy_allowed_domain_url, "samesite-unspecified=1",
+      net::CookieOptions::SameSiteCookieContext::SAME_SITE_LAX));
+  EXPECT_EQ("samesite-unspecified=1",
+            content::GetCookies(profile, legacy_allowed_domain_url));
+  // Do the same on the other domain...
+  EXPECT_TRUE(content::SetCookie(
+      profile, other_domain_url, "samesite-unspecified=1",
+      net::CookieOptions::SameSiteCookieContext::SAME_SITE_LAX));
+  EXPECT_EQ("samesite-unspecified=1",
+            content::GetCookies(profile, other_domain_url));
+
+  // Overwrite the cookie from a cross-site context. Because we have a policy
+  // that allows Legacy access for one domain but not the other, this will work
+  // on the policy-specified domain even if SameSite features are enabled, but
+  // it will not work for the other domain. (It works regardless, if they are
+  // disabled.)
+  EXPECT_TRUE(content::SetCookie(
+      profile, legacy_allowed_domain_url, "samesite-unspecified=2",
+      net::CookieOptions::SameSiteCookieContext::CROSS_SITE));
+  EXPECT_EQ("samesite-unspecified=2",
+            content::GetCookies(profile, legacy_allowed_domain_url));
+  EXPECT_EQ("samesite-unspecified=2",
+            content::GetCookies(
+                profile, legacy_allowed_domain_url,
+                net::CookieOptions::SameSiteCookieContext::CROSS_SITE));
+  // For the domain that is not Legacy by policy, we expect it to work only if
+  // the SameSite features are disabled.
+  if (AreSameSiteFeaturesEnabled()) {
+    EXPECT_FALSE(content::SetCookie(
+        profile, other_domain_url, "samesite-unspecified=2",
+        net::CookieOptions::SameSiteCookieContext::CROSS_SITE));
+    EXPECT_EQ("samesite-unspecified=1",
+              content::GetCookies(profile, other_domain_url));
+    EXPECT_EQ("", content::GetCookies(
+                      profile, other_domain_url,
+                      net::CookieOptions::SameSiteCookieContext::CROSS_SITE));
+  } else {
+    EXPECT_TRUE(content::SetCookie(
+        profile, other_domain_url, "samesite-unspecified=2",
+        net::CookieOptions::SameSiteCookieContext::CROSS_SITE));
+    EXPECT_EQ("samesite-unspecified=2",
+              content::GetCookies(profile, other_domain_url));
+    EXPECT_EQ("samesite-unspecified=2",
+              content::GetCookies(
+                  profile, other_domain_url,
+                  net::CookieOptions::SameSiteCookieContext::CROSS_SITE));
+  }
+}
+
+INSTANTIATE_TEST_SUITE_P(/* no label */,
+                         SameSiteCookiesPolicyTest,
+                         ::testing::Bool());
+
+}  // namespace policy
diff --git a/chrome/browser/page_load_metrics/observers/subresource_loading_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/subresource_loading_page_load_metrics_observer.cc
index 83b486a..25f526f 100644
--- a/chrome/browser/page_load_metrics/observers/subresource_loading_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/subresource_loading_page_load_metrics_observer.cc
@@ -13,7 +13,9 @@
 #include "components/page_load_metrics/browser/page_load_tracker.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
+#include "net/cookies/cookie_options.h"
 #include "third_party/blink/public/common/mime_util/mime_util.h"
 
 namespace {
@@ -38,6 +40,17 @@
     const GURL& currently_committed_url,
     bool started_in_foreground) {
   navigation_start_ = base::Time::Now();
+
+  CheckForCookiesOnURL(navigation_handle->GetWebContents()->GetBrowserContext(),
+                       currently_committed_url);
+  return CONTINUE_OBSERVING;
+}
+
+page_load_metrics::PageLoadMetricsObserver::ObservePolicy
+SubresourceLoadingPageLoadMetricsObserver::OnRedirect(
+    content::NavigationHandle* navigation_handle) {
+  CheckForCookiesOnURL(navigation_handle->GetWebContents()->GetBrowserContext(),
+                       navigation_handle->GetURL());
   return CONTINUE_OBSERVING;
 }
 
@@ -107,6 +120,25 @@
   }
 }
 
+void SubresourceLoadingPageLoadMetricsObserver::CheckForCookiesOnURL(
+    content::BrowserContext* browser_context,
+    const GURL& url) {
+  content::StoragePartition* partition =
+      content::BrowserContext::GetStoragePartitionForSite(browser_context, url);
+
+  partition->GetCookieManagerForBrowserProcess()->GetCookieList(
+      url, net::CookieOptions::MakeAllInclusive(),
+      base::BindOnce(&SubresourceLoadingPageLoadMetricsObserver::OnCookieResult,
+                     weak_factory_.GetWeakPtr()));
+}
+
+void SubresourceLoadingPageLoadMetricsObserver::OnCookieResult(
+    const net::CookieStatusList& cookies,
+    const net::CookieStatusList& excluded_cookies) {
+  mainframe_had_cookies_ =
+      mainframe_had_cookies_.value_or(false) || !cookies.empty();
+}
+
 void SubresourceLoadingPageLoadMetricsObserver::OnResourceDataUseObserved(
     content::RenderFrameHost* rfh,
     const std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr>&
@@ -141,6 +173,12 @@
   // TODO(crbug.com/995437): Add UKM for data saver users once all metrics
   // are in place.
 
+  if (mainframe_had_cookies_.has_value()) {
+    UMA_HISTOGRAM_BOOLEAN(
+        "PageLoad.Clients.SubresourceLoading.MainFrameHadCookies",
+        mainframe_had_cookies_.value());
+  }
+
   if (min_days_since_last_visit_to_origin_.has_value()) {
     int days_since_last_visit = min_days_since_last_visit_to_origin_.value();
 
diff --git a/chrome/browser/page_load_metrics/observers/subresource_loading_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/subresource_loading_page_load_metrics_observer.h
index 0a5dc301..4b9f7d3 100644
--- a/chrome/browser/page_load_metrics/observers/subresource_loading_page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/subresource_loading_page_load_metrics_observer.h
@@ -15,8 +15,14 @@
 #include "base/time/time.h"
 #include "components/history/core/browser/history_types.h"
 #include "components/page_load_metrics/browser/page_load_metrics_observer.h"
+#include "net/cookies/canonical_cookie.h"
 #include "url/gurl.h"
 
+namespace content {
+class BrowserContext;
+class NavigationHandle;
+}  // namespace content
+
 // Records metrics related to loading of subresources on a page.
 class SubresourceLoadingPageLoadMetricsObserver
     : public page_load_metrics::PageLoadMetricsObserver {
@@ -32,10 +38,23 @@
  private:
   void RecordMetrics();
 
+  // Starts an async call to the cookie manager to determine if there are likely
+  // to be cookies set on a mainframe request. This is called on navigation
+  // start and redirects but should not be called on commit because it'll get
+  // cookies from the mainframe response, if any.
+  void CheckForCookiesOnURL(content::BrowserContext* browser_context,
+                            const GURL& url);
+
+  // Used as a callback for the cookie manager query.
+  void OnCookieResult(const net::CookieStatusList& cookies,
+                      const net::CookieStatusList& excluded_cookies);
+
   // page_load_metrics::PageLoadMetricsObserver:
   ObservePolicy OnStart(content::NavigationHandle* navigation_handle,
                         const GURL& currently_committed_url,
                         bool started_in_foreground) override;
+  ObservePolicy OnRedirect(
+      content::NavigationHandle* navigation_handle) override;
   ObservePolicy OnCommit(content::NavigationHandle* navigation_handle,
                          ukm::SourceId source_id) override;
   ObservePolicy FlushMetricsOnAppEnterBackground(
@@ -61,6 +80,11 @@
   // a response from the history service but was no previous visit.
   base::Optional<int> min_days_since_last_visit_to_origin_;
 
+  // Set to true if any main frame request in the redirect chain had cookies set
+  // on the request. Set to false if there were no cookies set. Not set if we
+  // didn't get a response from the CookieManager before recording metrics.
+  base::Optional<bool> mainframe_had_cookies_;
+
   // Task tracker for calls for the history service.
   base::CancelableTaskTracker task_tracker_;
 
diff --git a/chrome/browser/page_load_metrics/observers/subresource_loading_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/subresource_loading_page_load_metrics_observer_browsertest.cc
index 65384618..759280a 100644
--- a/chrome/browser/page_load_metrics/observers/subresource_loading_page_load_metrics_observer_browsertest.cc
+++ b/chrome/browser/page_load_metrics/observers/subresource_loading_page_load_metrics_observer_browsertest.cc
@@ -27,15 +27,24 @@
         "chrome/test/data/subresource_loading");
     ASSERT_TRUE(embedded_test_server()->Start());
   }
+
+  void NavigateToPath(const std::string& path) {
+    ui_test_utils::NavigateToURL(
+        browser(), embedded_test_server()->GetURL("origin.com", path));
+    base::RunLoop().RunUntilIdle();
+  }
+
+  void NavigateAway() {
+    ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL));
+    base::RunLoop().RunUntilIdle();
+  }
 };
 
 IN_PROC_BROWSER_TEST_F(SubresourceLoadingPageLoadMetricsObserverBrowserTest,
                        BeforeFCPPlumbing) {
-  GURL url = embedded_test_server()->GetURL("origin.com", "/index.html");
-
   base::HistogramTester histogram_tester;
-  ui_test_utils::NavigateToURL(browser(), url);
-  ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL));
+  NavigateToPath("/index.html");
+  NavigateAway();
 
   histogram_tester.ExpectUniqueSample(
       "PageLoad.Clients.SubresourceLoading.LoadedCSSJSBeforeFCP.Noncached", 2,
@@ -44,21 +53,17 @@
 
 IN_PROC_BROWSER_TEST_F(SubresourceLoadingPageLoadMetricsObserverBrowserTest,
                        HistoryPlumbing) {
-  GURL url = embedded_test_server()->GetURL("origin.com", "/index.html");
-
   base::HistogramTester histogram_tester;
-  ui_test_utils::NavigateToURL(browser(), url);
-  base::RunLoop().RunUntilIdle();
-  ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL));
+  NavigateToPath("/index.html");
+  NavigateAway();
   histogram_tester.ExpectUniqueSample(
       "PageLoad.Clients.SubresourceLoading.HasPreviousVisitToOrigin", false, 1);
   histogram_tester.ExpectTotalCount(
       "PageLoad.Clients.SubresourceLoading.DaysSinceLastVisitToOrigin", 0);
 
   // Revisit and expect a 0 days-ago entry.
-  ui_test_utils::NavigateToURL(browser(), url);
-  base::RunLoop().RunUntilIdle();
-  ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL));
+  NavigateToPath("/index.html");
+  NavigateAway();
   histogram_tester.ExpectBucketCount(
       "PageLoad.Clients.SubresourceLoading.HasPreviousVisitToOrigin", true, 1);
   histogram_tester.ExpectBucketCount(
@@ -66,3 +71,41 @@
   histogram_tester.ExpectUniqueSample(
       "PageLoad.Clients.SubresourceLoading.DaysSinceLastVisitToOrigin", 0, 1);
 }
+
+IN_PROC_BROWSER_TEST_F(SubresourceLoadingPageLoadMetricsObserverBrowserTest,
+                       MainFrameHadCookies_None) {
+  base::HistogramTester histogram_tester;
+  NavigateToPath("/index.html");
+  NavigateAway();
+
+  histogram_tester.ExpectUniqueSample(
+      "PageLoad.Clients.SubresourceLoading.MainFrameHadCookies", false, 1);
+}
+
+IN_PROC_BROWSER_TEST_F(SubresourceLoadingPageLoadMetricsObserverBrowserTest,
+                       MainFrameHadCookies_CookiesOnNextPageLoad) {
+  base::HistogramTester histogram_tester;
+  NavigateToPath("/set_cookies.html");
+  NavigateToPath("/index.html");
+  NavigateAway();
+
+  histogram_tester.ExpectBucketCount(
+      "PageLoad.Clients.SubresourceLoading.MainFrameHadCookies", true, 1);
+  // From the first page load.
+  histogram_tester.ExpectBucketCount(
+      "PageLoad.Clients.SubresourceLoading.MainFrameHadCookies", false, 1);
+}
+
+IN_PROC_BROWSER_TEST_F(SubresourceLoadingPageLoadMetricsObserverBrowserTest,
+                       MainFrameHadCookies_CookiesOnRedirect) {
+  base::HistogramTester histogram_tester;
+  NavigateToPath("/set_cookies.html");
+  NavigateToPath("/redirect_to_index.html");
+  NavigateAway();
+
+  histogram_tester.ExpectBucketCount(
+      "PageLoad.Clients.SubresourceLoading.MainFrameHadCookies", true, 1);
+  // From the first page load.
+  histogram_tester.ExpectBucketCount(
+      "PageLoad.Clients.SubresourceLoading.MainFrameHadCookies", false, 1);
+}
diff --git a/chrome/browser/page_load_metrics/observers/subresource_loading_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/subresource_loading_page_load_metrics_observer_unittest.cc
index b75685f6..d77c551 100644
--- a/chrome/browser/page_load_metrics/observers/subresource_loading_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/subresource_loading_page_load_metrics_observer_unittest.cc
@@ -406,3 +406,14 @@
   tester()->histogram_tester().ExpectUniqueSample(
       "PageLoad.Clients.SubresourceLoading.DaysSinceLastVisitToOrigin", 1, 1);
 }
+
+// The rest of cookie testing is done in
+// SubresourceLoadingPageLoadMetricsObserverBrowserTest.
+TEST_F(SubresourceLoadingPageLoadMetricsObserverTest, HadCookies_None) {
+  StartTest(true /* data_saver_enabled */);
+
+  tester()->NavigateToUntrackedUrl();
+
+  tester()->histogram_tester().ExpectTotalCount(
+      "PageLoad.Clients.SubresourceLoading.MainFrameHadCookies", 0);
+}
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index 5ff167b..1a1dd382 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -226,6 +226,11 @@
   { key::kDefaultImagesSetting,
     prefs::kManagedDefaultImagesSetting,
     base::Value::Type::INTEGER },
+#if !defined(OS_ANDROID)
+  { key::kDefaultInsecureContentSetting,
+    prefs::kManagedDefaultInsecureContentSetting,
+    base::Value::Type::INTEGER },
+#endif  // !defined(OS_ANDROID)
   { key::kLegacySameSiteCookieBehaviorEnabled,
     prefs::kManagedDefaultLegacyCookieAccessSetting,
     base::Value::Type::INTEGER },
@@ -250,6 +255,14 @@
   { key::kImagesBlockedForUrls,
     prefs::kManagedImagesBlockedForUrls,
     base::Value::Type::LIST },
+#if !defined(OS_ANDROID)
+  { key::kInsecureContentAllowedForUrls,
+    prefs::kManagedInsecureContentAllowedForUrls,
+    base::Value::Type::LIST },
+  { key::kInsecureContentBlockedForUrls,
+    prefs::kManagedInsecureContentBlockedForUrls,
+    base::Value::Type::LIST },
+#endif  // !defined(OS_ANDROID)
   { key::kJavaScriptAllowedForUrls,
     prefs::kManagedJavaScriptAllowedForUrls,
     base::Value::Type::LIST },
diff --git a/chrome/browser/policy/e2e_test/tests/__init__.py b/chrome/browser/policy/e2e_test/tests/__init__.py
index 7a4fc23c..a30f476 100644
--- a/chrome/browser/policy/e2e_test/tests/__init__.py
+++ b/chrome/browser/policy/e2e_test/tests/__init__.py
@@ -5,6 +5,7 @@
 from allow_deleting_browser_history.allow_deleting_browser_history import *
 from apps_shortcut.apps_shortcut import *
 from bookmarkbar_enabled.bookmarkbar_enabled import *
+from cloud_management_enrollment_token.cloud_management_enrollment_token import *
 from default_search_provider.default_search_provider import *
 from extension_blacklist.extension_blacklist import *
 from extension_forcelist.extension_forcelist import *
diff --git a/chrome/browser/policy/e2e_test/tests/cloud_management_enrollment_token/__init__.py b/chrome/browser/policy/e2e_test/tests/cloud_management_enrollment_token/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/chrome/browser/policy/e2e_test/tests/cloud_management_enrollment_token/__init__.py
diff --git a/chrome/browser/policy/e2e_test/tests/cloud_management_enrollment_token/cloud_enrollment_webdriver.py b/chrome/browser/policy/e2e_test/tests/cloud_management_enrollment_token/cloud_enrollment_webdriver.py
new file mode 100644
index 0000000..2811adf
--- /dev/null
+++ b/chrome/browser/policy/e2e_test/tests/cloud_management_enrollment_token/cloud_enrollment_webdriver.py
@@ -0,0 +1,40 @@
+# 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 os
+from absl import app
+import time
+from selenium import webdriver
+import test_util
+
+
+def main(argv):
+  options = webdriver.ChromeOptions()
+  # Add option for enrolling to the dev DMServer
+  options.add_argument(
+      "device-management-url=https://crosman-qa.sandbox.google.com/devicemanagement/data/api"
+  )
+  os.environ["CHROME_LOG_FILE"] = r"c:\temp\chrome_log.txt"
+  driver = test_util.create_chrome_webdriver(chrome_options=options)
+
+  # Give some time for browser to enroll
+  time.sleep(10)
+
+  try:
+    # Verify Policy status legend in chrome://policy page
+    policy_url = "chrome://policy"
+    driver.get(policy_url)
+    driver.find_element_by_id('reload-policies').click
+    print driver.find_element_by_class_name('legend').text
+    print driver.find_element_by_class_name('machine-enrollment-name').text
+    print driver.find_element_by_class_name('machine-enrollment-token').text
+    print driver.find_element_by_class_name('status').text
+  except Exception as error:
+    print error
+  finally:
+    driver.quit()
+
+
+if __name__ == '__main__':
+  app.run(main)
diff --git a/chrome/browser/policy/e2e_test/tests/cloud_management_enrollment_token/cloud_management_enrollment_token.py b/chrome/browser/policy/e2e_test/tests/cloud_management_enrollment_token/cloud_management_enrollment_token.py
new file mode 100644
index 0000000..3a32099a
--- /dev/null
+++ b/chrome/browser/policy/e2e_test/tests/cloud_management_enrollment_token/cloud_management_enrollment_token.py
@@ -0,0 +1,37 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+
+from infra import ChromeEnterpriseTestCase
+from chrome_ent_test.infra.core import before_all, category, environment, test
+
+
+@category("chrome_only")
+@environment(file="../policy_test.asset.textpb")
+class CloudManagementEnrollmentTokenTest(ChromeEnterpriseTestCase):
+  """Test the CloudManagementEnrollmentToken policy:
+  https://cloud.google.com/docs/chrome-enterprise/policies/?policy=CloudManagementEnrollmentToken."""
+
+  @before_all
+  def setup(self):
+    self.InstallChrome('client2012')
+    self.InstallWebDriver('client2012')
+
+  @test
+  def test_browser_enrolled(self):
+    token = '4841902b-07f7-491f-b29d-154c4bab9555'
+    self.SetPolicy('win2012-dc', r'CloudManagementEnrollmentToken', token,
+                   'String')
+    self.RunCommand('client2012', 'gpupdate /force')
+
+    local_dir = os.path.dirname(os.path.abspath(__file__))
+
+    output = self.RunWebDriverTest(
+        'client2012', os.path.join(local_dir, 'cloud_enrollment_webdriver.py'))
+    # Verify CBCM status legend
+    self.assertIn('Machine policies', output)
+    self.assertIn('CLIENT2012', output)
+    self.assertIn(token, output)
+    self.assertIn('Policy cache OK', output)
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 674e90b..a960db92 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -235,6 +235,7 @@
 #endif  // defined(OS_ANDROID)
 
 #if defined(OS_CHROMEOS)
+#include "ash/public/cpp/ash_pref_names.h"
 #include "ash/public/cpp/ash_prefs.h"
 #include "chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_manager.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
@@ -501,6 +502,12 @@
 const char kDataReductionProxySavingsClearedNegativeSystemClock[] =
     "data_reduction.savings_cleared_negative_system_clock";
 
+#if defined(OS_CHROMEOS)
+// Deprecated 10/2019
+const char kDisplayRotationAcceleratorDialogHasBeenAccepted[] =
+    "settings.a11y.display_rotation_accelerator_dialog_has_been_accepted";
+#endif  // defined(OS_CHROMEOS)
+
 // Register prefs used only for migration (clearing or moving to a new key).
 void RegisterProfilePrefsForMigration(
     user_prefs::PrefRegistrySyncable* registry) {
@@ -581,6 +588,11 @@
   registry->RegisterStringPref(kGoogleServicesUserAccountId, std::string());
   registry->RegisterInt64Pref(
       kDataReductionProxySavingsClearedNegativeSystemClock, 0);
+
+#if defined(OS_CHROMEOS)
+  registry->RegisterBooleanPref(
+      kDisplayRotationAcceleratorDialogHasBeenAccepted, false);
+#endif  // defined(OS_CHROMEOS)
 }
 
 }  // namespace
@@ -1204,4 +1216,8 @@
 
   // Added 10/2019.
   syncer::DeviceInfoPrefs::MigrateRecentLocalCacheGuidsPref(profile_prefs);
+#if defined(OS_CHROMEOS)
+  // Added 10/2019.
+  profile_prefs->ClearPref(kDisplayRotationAcceleratorDialogHasBeenAccepted);
+#endif  // defined(OS_CHROMEOS)
 }
diff --git a/chrome/browser/resources/chromeos/chromevox/BUILD.gn b/chrome/browser/resources/chromeos/chromevox/BUILD.gn
index 5210a02c..f222e54 100644
--- a/chrome/browser/resources/chromeos/chromevox/BUILD.gn
+++ b/chrome/browser/resources/chromeos/chromevox/BUILD.gn
@@ -630,6 +630,7 @@
       "cvox2/background/download_handler_test.extjs",
       "cvox2/background/editing_test.extjs",
       "cvox2/background/i_search_test.extjs",
+      "cvox2/background/keyboard_handler_test.extjs",
       "cvox2/background/language_switching_test.extjs",
       "cvox2/background/live_regions_test.extjs",
       "cvox2/background/log_store_test.extjs",
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/keyboard_handler.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/keyboard_handler.js
index 8770d37e..484dfb4 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/keyboard_handler.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/keyboard_handler.js
@@ -35,7 +35,8 @@
   /**
    * Handles key down events.
    * @param {Event} evt The key down event to process.
-   * @return {boolean} True if the default action should be performed.
+   * @return {boolean} This value has no effect since we ignore it in
+   *     SpokenFeedbackEventRewriterDelegate::HandleKeyboardEvent.
    */
   onKeyDown: function(evt) {
     EventSourceState.set(EventSourceType.STANDARD_KEYBOARD);
@@ -49,7 +50,12 @@
     // commands.
     if (!MathHandler.onKeyDown(evt) ||
         !cvox.ChromeVoxKbHandler.basicKeyDownActionsListener(evt) ||
-        evt.metaKey || evt.keyCode == 91) {
+        // We natively always capture Search, so we have to be very careful to
+        // either eat it here or re-inject it; otherwise, some components, like
+        // ARC++ with TalkBack never get it. We only want to re-inject when
+        // ChromeVox has no range.
+        (ChromeVoxState.instance.currentRange &&
+         (evt.metaKey || evt.keyCode == 91))) {
       evt.preventDefault();
       evt.stopPropagation();
       this.eatenKeyDowns_.add(evt.keyCode);
@@ -60,7 +66,8 @@
   /**
    * Handles key up events.
    * @param {Event} evt The key down event to process.
-   * @return {boolean} True if the default action should be performed.
+   * @return {boolean} This value has no effect since we ignore it in
+   *     SpokenFeedbackEventRewriterDelegate::HandleKeyboardEvent.
    */
   onKeyUp: function(evt) {
     // Reset pass through mode once a keyup (not involving the pass through key)
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/keyboard_handler_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/keyboard_handler_test.extjs
new file mode 100644
index 0000000..9a0ef7c
--- /dev/null
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/keyboard_handler_test.extjs
@@ -0,0 +1,44 @@
+// 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 test fixture.
+GEN_INCLUDE(['../../testing/chromevox_next_e2e_test_base.js']);
+
+/**
+ * Test fixture for ChromeVox KeyboardHandler.
+ * @constructor
+ * @extends {ChromeVoxE2ETest}
+ */
+function ChromeVoxBackgroundKeyboardHandlerTest() {
+  ChromeVoxNextE2ETest.call(this);
+}
+
+ChromeVoxBackgroundKeyboardHandlerTest.prototype = {
+  __proto__: ChromeVoxNextE2ETest.prototype,
+
+  /** @override */
+  setUp: function() {
+    window.keyboardHandler = new BackgroundKeyboardHandler();
+  }
+};
+
+TEST_F('ChromeVoxBackgroundKeyboardHandlerTest', 'SearchGetsPassedThrough',
+  function() {
+    this.runWithLoadedTree('<p>test</p>', function() {
+      // A Search keydown gets eaten.
+      var searchDown = {};
+      searchDown.preventDefault = this.newCallback();
+      searchDown.stopPropagation = this.newCallback();
+      searchDown.metaKey = true;
+      keyboardHandler.onKeyDown(searchDown);
+      assertEquals(1, keyboardHandler.eatenKeyDowns_.size);
+
+      // A Search keydown does not get eaten when there's no range.
+      ChromeVoxState.instance.setCurrentRange(null);
+      var searchDown2 = {};
+      searchDown2.metaKey = true;
+      keyboardHandler.onKeyDown(searchDown2);
+      assertEquals(1, keyboardHandler.eatenKeyDowns_.size);
+    });
+});
diff --git a/chrome/browser/resources/chromeos/login/cr_ui.js b/chrome/browser/resources/chromeos/login/cr_ui.js
index 61cb01e9..48de3c2 100644
--- a/chrome/browser/resources/chromeos/login/cr_ui.js
+++ b/chrome/browser/resources/chromeos/login/cr_ui.js
@@ -381,6 +381,14 @@
   };
 
   /**
+   * Sets the hint for calculating OOBE dialog margins.
+   * @param {OobeTypes.DialogPaddingMode} mode.
+   */
+  Oobe.setDialogPaddingMode = function(mode) {
+    Oobe.getInstance().setDialogPaddingMode(mode);
+  };
+
+  /**
    * Get the primary display's name.
    *
    * Same as the displayInfo.name parameter returned by
diff --git a/chrome/browser/resources/chromeos/login/discover/discover_app.js b/chrome/browser/resources/chromeos/login/discover/discover_app.js
index c24b76a..6f663418 100644
--- a/chrome/browser/resources/chromeos/login/discover/discover_app.js
+++ b/chrome/browser/resources/chromeos/login/discover/discover_app.js
@@ -33,6 +33,7 @@
     setClientAreaSize: function(data) {},
     setLabelText: function(data) {},
     setShelfHeight: function(data) {},
+    setDialogPaddingMode: function(data) {},
     setVirtualKeyboardShown: function(data) {},
     showAPIKeysNotice: function(data) {},
     showOobeUI: function(data) {},
diff --git a/chrome/browser/resources/chromeos/login/oobe_types.js b/chrome/browser/resources/chromeos/login/oobe_types.js
index 62d42db..d7ff60a 100644
--- a/chrome/browser/resources/chromeos/login/oobe_types.js
+++ b/chrome/browser/resources/chromeos/login/oobe_types.js
@@ -134,3 +134,13 @@
  * }}
  */
 OobeTypes.SecurityTokenPinDialogParameters;
+
+/**
+ * Specifies the mechanism for calculating oobe-dialog inner padding.
+ * @enum {string}
+ */
+OobeTypes.DialogPaddingMode = {
+  AUTO: 'auto',
+  NARROW: 'narrow',
+  WIDE: 'wide',
+};
diff --git a/chrome/browser/resources/print_preview/data/destination.js b/chrome/browser/resources/print_preview/data/destination.js
index 761891d5..ef23d35 100644
--- a/chrome/browser/resources/print_preview/data/destination.js
+++ b/chrome/browser/resources/print_preview/data/destination.js
@@ -268,7 +268,9 @@
    *            capabilities: ?print_preview.Cdd,
    *            displayName: string,
    *            extensionId: string,
-   *            extensionName: string}}
+   *            extensionName: string,
+   *            icon: (string | undefined)
+   *          }}
    */
   let RecentDestination;
 
@@ -287,6 +289,7 @@
       displayName: destination.displayName || '',
       extensionId: destination.extensionId || '',
       extensionName: destination.extensionName || '',
+      icon: destination.icon || '',
     };
   }
 
diff --git a/chrome/browser/resources/print_preview/ui/destination_select.html b/chrome/browser/resources/print_preview/ui/destination_select.html
index 2438ba0e4..7824a9f 100644
--- a/chrome/browser/resources/print_preview/ui/destination_select.html
+++ b/chrome/browser/resources/print_preview/ui/destination_select.html
@@ -38,7 +38,8 @@
     </style>
     <select class="md-select" aria-label$="[[i18n(destinationLabel)]]"
         style="background-image:
-            [[getBackgroundImages_(destination.icon, destinationState, dark)]];"
+            [[getBackgroundImages_(selectedValue, destination,
+                                   destinationState, dark)]];"
         disabled$="[[disabled]]"
         value="{{selectedValue::change}}">
       <template is="dom-repeat" items="[[recentDestinationList]]">
diff --git a/chrome/browser/resources/print_preview/ui/destination_select.js b/chrome/browser/resources/print_preview/ui/destination_select.js
index d725445..5dc16ae8 100644
--- a/chrome/browser/resources/print_preview/ui/destination_select.js
+++ b/chrome/browser/resources/print_preview/ui/destination_select.js
@@ -59,12 +59,54 @@
   },
 
   /**
-   * @param {string} icon The icon set and icon to obtain.
-   * @return {string} An inline svg corresponding to |icon| and the image for
-   *     the dropdown arrow.
+   * Returns the iconset and icon for the selected printer. If printer details
+   * have not yet been retrieved from the backend, attempts to return an
+   * appropriate icon early based on the printer's sticky information.
+   * @return {string} The iconset and icon for the current selection.
    * @private
    */
-  getBackgroundImages_: function(icon) {
+  getDestinationIcon_: function() {
+    if (!this.selectedValue) {
+      return '';
+    }
+
+    // If the destination matches the selected value, pull the icon from the
+    // destination.
+    if (this.destination && this.destination.key === this.selectedValue) {
+      return this.destination.icon;
+    }
+
+    // Check for the Docs or Save as PDF ids first.
+    const keyParams = this.selectedValue.split('/');
+    if (keyParams[0] === print_preview.Destination.GooglePromotedId.DOCS) {
+      return 'print-preview:save-to-drive';
+    }
+    if (keyParams[0] ===
+        print_preview.Destination.GooglePromotedId.SAVE_AS_PDF) {
+      return 'cr:insert-drive-file';
+    }
+
+    // Otherwise, must be in the recent list.
+    const recent = this.recentDestinationList.find(d => {
+      return print_preview.createRecentDestinationKey(d) === this.selectedValue;
+    });
+    if (recent && recent.icon) {
+      return recent.icon;
+    }
+
+    // The key/recent destinations don't have information about what icon to
+    // use, so just return the generic print icon for now. It will be updated
+    // when the destination is set.
+    return 'print-preview:print';
+  },
+
+  /**
+   * @return {string} An inline svg corresponding to the icon for the current
+   *     destination and the image for the dropdown arrow.
+   * @private
+   */
+  getBackgroundImages_: function() {
+    const icon = this.getDestinationIcon_();
     if (!icon) {
       return '';
     }
diff --git a/chrome/browser/resources/print_preview/ui/pages_settings.js b/chrome/browser/resources/print_preview/ui/pages_settings.js
index 176161f..c25f952 100644
--- a/chrome/browser/resources/print_preview/ui/pages_settings.js
+++ b/chrome/browser/resources/print_preview/ui/pages_settings.js
@@ -247,6 +247,11 @@
         }
       }
     }
+
+    // Page numbers should be sorted to match the order of the pages in the
+    // rendered PDF.
+    pages.sort((left, right) => left - right);
+
     this.errorState_ = PagesInputErrorState.NO_ERROR;
     this.pagesToPrint_ = pages;
   },
diff --git a/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html b/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html
index f19b104..6622b41 100644
--- a/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html
+++ b/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html
@@ -241,7 +241,7 @@
       <div slot="dialog-title">[[dialogTitle]]</div>
       <div slot="dialog-body">
         <paper-spinner-lite active></paper-spinner-lite>
-        <div id="configuringMessage">$i18n{printerConfiguringMessage}</div>
+        <div id="configuringMessage"></div>
       </div>
       <div slot="dialog-buttons">
         <cr-button class="cancel-button" on-click="onCloseConfiguringTap_">
diff --git a/chrome/browser/safe_browsing/download_protection/multipart_uploader.cc b/chrome/browser/safe_browsing/download_protection/multipart_uploader.cc
index 1a06d75..10ec364 100644
--- a/chrome/browser/safe_browsing/download_protection/multipart_uploader.cc
+++ b/chrome/browser/safe_browsing/download_protection/multipart_uploader.cc
@@ -63,7 +63,9 @@
 void MultipartUploadRequest::Start() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  SendRequest();
+  // TODO(crbug.com/1015974): Re-enable this.
+  base::PostTask(FROM_HERE, {content::BrowserThread::UI},
+                 base::BindOnce(std::move(callback_), /*success=*/false, ""));
 }
 
 std::string MultipartUploadRequest::GenerateRequestBody(
diff --git a/chrome/browser/safe_browsing/download_protection/multipart_uploader_unittest.cc b/chrome/browser/safe_browsing/download_protection/multipart_uploader_unittest.cc
index ef4f4cf..6b1d2a4 100644
--- a/chrome/browser/safe_browsing/download_protection/multipart_uploader_unittest.cc
+++ b/chrome/browser/safe_browsing/download_protection/multipart_uploader_unittest.cc
@@ -62,7 +62,8 @@
             expected_body);
 }
 
-TEST_F(MultipartUploadRequestTest, RetriesCorrectly) {
+// TODO(crbug.com/1015974): Re-enable this test.
+TEST_F(MultipartUploadRequestTest, DISABLED_RetriesCorrectly) {
   MockMultipartUploadRequest mock_request;
 
   EXPECT_CALL(mock_request, SendRequest())
diff --git a/chrome/browser/share/BUILD.gn b/chrome/browser/share/BUILD.gn
new file mode 100644
index 0000000..d35da0b
--- /dev/null
+++ b/chrome/browser/share/BUILD.gn
@@ -0,0 +1,13 @@
+# 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("share") {
+  sources = [
+    "features.cc",
+    "features.h",
+  ]
+  deps = [
+    "//base",
+  ]
+}
diff --git a/chrome/browser/share/DEPS b/chrome/browser/share/DEPS
new file mode 100644
index 0000000..7a55c73
--- /dev/null
+++ b/chrome/browser/share/DEPS
@@ -0,0 +1,7 @@
+include_rules = [
+  # TODO(gayane): Remove this dependency when ShareActivity is moved to chrome/browser/share.
+  "+chrome/android/java/src/org/chromium/chrome/browser/share",
+
+  "+chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java",
+  "+chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java"
+]
\ No newline at end of file
diff --git a/chrome/browser/share/OWNERS b/chrome/browser/share/OWNERS
new file mode 100644
index 0000000..f8e745b
--- /dev/null
+++ b/chrome/browser/share/OWNERS
@@ -0,0 +1,3 @@
+file://components/send_tab_to_self/OWNERS
+
+# COMPONENT: UI>Browser>Sharing
\ No newline at end of file
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/qrcode/QrCodeShareActivity.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/qrcode/QrCodeShareActivity.java
new file mode 100644
index 0000000..e3aca2cc
--- /dev/null
+++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/qrcode/QrCodeShareActivity.java
@@ -0,0 +1,23 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.share.qrcode;
+
+import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.ChromeFeatureList;
+import org.chromium.chrome.browser.share.ShareActivity;
+
+/**
+ * A simple activity that shows sharing QR code option in share menu.
+ */
+public class QrCodeShareActivity extends ShareActivity {
+    @Override
+    protected void handleShareAction(ChromeActivity triggeringActivity) {
+        // TODO(crbug.com/993920): Open QR code share/scan activity.
+    }
+
+    public static boolean featureIsAvailable() {
+        return ChromeFeatureList.isEnabled(ChromeFeatureList.SHARING_QR_CODE_ANDROID);
+    }
+}
\ No newline at end of file
diff --git a/chrome/browser/share/android/java_sources.gni b/chrome/browser/share/android/java_sources.gni
new file mode 100644
index 0000000..a42bc950
--- /dev/null
+++ b/chrome/browser/share/android/java_sources.gni
@@ -0,0 +1,6 @@
+# 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.
+
+# TODO(gayane): This should be a separate build target when circular dependencies are removed.
+share_java_sources = [ "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/qrcode/QrCodeShareActivity.java" ]
diff --git a/chrome/browser/share/features.cc b/chrome/browser/share/features.cc
new file mode 100644
index 0000000..3aa97e3
--- /dev/null
+++ b/chrome/browser/share/features.cc
@@ -0,0 +1,8 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/share/features.h"
+
+const base::Feature kSharingQrCodeAndroid{"SharingQrCodeAndroid",
+                                          base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/browser/share/features.h b/chrome/browser/share/features.h
new file mode 100644
index 0000000..7393317
--- /dev/null
+++ b/chrome/browser/share/features.h
@@ -0,0 +1,13 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SHARE_FEATURES_H_
+#define CHROME_BROWSER_SHARE_FEATURES_H_
+
+#include "base/feature_list.h"
+
+// Feature flag to enable sharing and scanning QR Code on Android.
+extern const base::Feature kSharingQrCodeAndroid;
+
+#endif  // CHROME_BROWSER_SHARE_FEATURES_H_
diff --git a/chrome/browser/supervised_user/logged_in_user_mixin.h b/chrome/browser/supervised_user/logged_in_user_mixin.h
index 17c2dfc..9e4e553 100644
--- a/chrome/browser/supervised_user/logged_in_user_mixin.h
+++ b/chrome/browser/supervised_user/logged_in_user_mixin.h
@@ -20,6 +20,14 @@
 // Compound mixin class for easily logging in as regular or child accounts for
 // browser tests. Initiates other mixins required to log in users, sets up their
 // user policies and gaia auth.
+// To use:
+// * Make your browser test class inherit from MixinBasedInProcessBrowserTest.
+// * Instantiate this class while passing in the inherited mixin_host_ member to
+// the constructor.
+// Note: the desired LogInType must be known at construction time.
+// * Pass the inherited embedded_test_server() into the constructor
+// as well.
+// * Call LogInUser() or SetUpOnMainThreadHelper() to log in.
 class LoggedInUserMixin {
  public:
   enum class LogInType { kRegular, kChild };
diff --git a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillMediator.java b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillMediator.java
index 718024a..efdc77b 100644
--- a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillMediator.java
+++ b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillMediator.java
@@ -17,6 +17,7 @@
 import androidx.annotation.Px;
 
 import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.chrome.browser.touch_to_fill.TouchToFillComponent.UserAction;
 import org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CredentialProperties;
 import org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.HeaderProperties;
 import org.chromium.chrome.browser.touch_to_fill.data.Credential;
@@ -37,6 +38,7 @@
             "PasswordManager.TouchToFill.DismissalReason";
     static final String UMA_TOUCH_TO_FILL_CREDENTIAL_INDEX =
             "PasswordManager.TouchToFill.CredentialIndex";
+    static final String UMA_TOUCH_TO_FILL_USER_ACTION = "PasswordManager.TouchToFill.UserAction";
 
     private TouchToFillComponent.Delegate mDelegate;
     private PropertyModel mModel;
@@ -84,7 +86,6 @@
 
     private void onSelectedCredential(Credential credential) {
         mModel.set(VISIBLE, false);
-        mDelegate.onCredentialSelected(credential);
         if (mCredentials.size() > 1) {
             // We only record this histogram in case multiple credentials were shown to the user.
             // Otherwise the single credential case where position should always be 0 will dominate
@@ -92,6 +93,10 @@
             RecordHistogram.recordCount100Histogram(
                     UMA_TOUCH_TO_FILL_CREDENTIAL_INDEX, mCredentials.indexOf(credential));
         }
+
+        RecordHistogram.recordEnumeratedHistogram(UMA_TOUCH_TO_FILL_USER_ACTION,
+                UserAction.SELECT_CREDENTIAL, UserAction.MAX_VALUE + 1);
+        mDelegate.onCredentialSelected(credential);
     }
 
     public void onDismissed(@StateChangeReason int reason) {
@@ -99,11 +104,15 @@
         mModel.set(VISIBLE, false);
         RecordHistogram.recordEnumeratedHistogram(
                 UMA_TOUCH_TO_FILL_DISMISSAL_REASON, reason, StateChangeReason.MAX_VALUE + 1);
+        RecordHistogram.recordEnumeratedHistogram(
+                UMA_TOUCH_TO_FILL_USER_ACTION, UserAction.DISMISS, UserAction.MAX_VALUE + 1);
         mDelegate.onDismissed();
     }
 
     private void onManagePasswordSelected() {
         mModel.set(VISIBLE, false);
+        RecordHistogram.recordEnumeratedHistogram(UMA_TOUCH_TO_FILL_USER_ACTION,
+                UserAction.SELECT_MANAGE_PASSWORDS, UserAction.MAX_VALUE + 1);
         mDelegate.onManagePasswordsSelected();
     }
 }
diff --git a/chrome/browser/touch_to_fill/android/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillComponent.java b/chrome/browser/touch_to_fill/android/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillComponent.java
index 9852b74..f2dcf4a 100644
--- a/chrome/browser/touch_to_fill/android/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillComponent.java
+++ b/chrome/browser/touch_to_fill/android/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillComponent.java
@@ -7,12 +7,15 @@
 import android.content.Context;
 import android.graphics.Bitmap;
 
+import androidx.annotation.IntDef;
 import androidx.annotation.Px;
 
 import org.chromium.base.Callback;
 import org.chromium.chrome.browser.touch_to_fill.data.Credential;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetController;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.List;
 
 /**
@@ -21,6 +24,22 @@
  */
 public interface TouchToFillComponent {
     /**
+     * The different reasons that the sheet's state can change.
+     *
+     * These values are persisted to logs. Entries should not be renumbered and numeric values
+     * should never be reused. Needs to stay in sync with TouchToFill.UserAction in enums.xml.
+     */
+    @IntDef({UserAction.SELECT_CREDENTIAL, UserAction.DISMISS, UserAction.SELECT_MANAGE_PASSWORDS,
+            UserAction.MAX_VALUE})
+    @Retention(RetentionPolicy.SOURCE)
+    @interface UserAction {
+        int SELECT_CREDENTIAL = 0;
+        int DISMISS = 1;
+        int SELECT_MANAGE_PASSWORDS = 2;
+        int MAX_VALUE = SELECT_MANAGE_PASSWORDS;
+    }
+
+    /**
      * This delegate is called when the TouchToFill component is interacted with (e.g. dismissed or
      * a suggestion was selected).
      */
diff --git a/chrome/browser/touch_to_fill/android/junit/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillControllerTest.java b/chrome/browser/touch_to_fill/android/junit/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillControllerTest.java
index c01d046..3fe8cd9 100644
--- a/chrome/browser/touch_to_fill/android/junit/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillControllerTest.java
+++ b/chrome/browser/touch_to_fill/android/junit/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillControllerTest.java
@@ -46,6 +46,7 @@
 import org.chromium.base.metrics.test.ShadowRecordHistogram;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.JniMocker;
+import org.chromium.chrome.browser.touch_to_fill.TouchToFillComponent.UserAction;
 import org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.ItemType;
 import org.chromium.chrome.browser.touch_to_fill.data.Credential;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet;
@@ -104,6 +105,7 @@
 
     @Before
     public void setUp() {
+        ShadowRecordHistogram.reset();
         mMediator.initialize(mMockDelegate, mModel, DESIRED_FAVICON_SIZE);
     }
 
@@ -212,6 +214,10 @@
         assertThat(RecordHistogram.getHistogramTotalCountForTesting(
                            TouchToFillMediator.UMA_TOUCH_TO_FILL_CREDENTIAL_INDEX),
                 is(0));
+        assertThat(RecordHistogram.getHistogramValueCountForTesting(
+                           TouchToFillMediator.UMA_TOUCH_TO_FILL_USER_ACTION,
+                           UserAction.SELECT_CREDENTIAL),
+                is(1));
     }
 
     @Test
@@ -226,6 +232,10 @@
         assertThat(RecordHistogram.getHistogramValueCountForTesting(
                            TouchToFillMediator.UMA_TOUCH_TO_FILL_CREDENTIAL_INDEX, 1),
                 is(1));
+        assertThat(RecordHistogram.getHistogramValueCountForTesting(
+                           TouchToFillMediator.UMA_TOUCH_TO_FILL_USER_ACTION,
+                           UserAction.SELECT_CREDENTIAL),
+                is(1));
     }
 
     @Test
@@ -238,6 +248,9 @@
                            TouchToFillMediator.UMA_TOUCH_TO_FILL_DISMISSAL_REASON,
                            BottomSheet.StateChangeReason.BACK_PRESS),
                 is(1));
+        assertThat(RecordHistogram.getHistogramValueCountForTesting(
+                           TouchToFillMediator.UMA_TOUCH_TO_FILL_USER_ACTION, UserAction.DISMISS),
+                is(1));
     }
 
     @Test
@@ -247,6 +260,10 @@
         mModel.get(ON_CLICK_MANAGE).run();
         verify(mMockDelegate).onManagePasswordsSelected();
         assertThat(mModel.get(VISIBLE), is(false));
+        assertThat(RecordHistogram.getHistogramValueCountForTesting(
+                           TouchToFillMediator.UMA_TOUCH_TO_FILL_USER_ACTION,
+                           UserAction.SELECT_MANAGE_PASSWORDS),
+                is(1));
     }
 
     /**
diff --git a/chrome/browser/ui/ash/screen_rotation_interactive_uitest.cc b/chrome/browser/ui/ash/screen_rotation_interactive_uitest.cc
index 399b8e4..6cdac1d 100644
--- a/chrome/browser/ui/ash/screen_rotation_interactive_uitest.cc
+++ b/chrome/browser/ui/ash/screen_rotation_interactive_uitest.cc
@@ -37,7 +37,7 @@
     ash::ShellTestApi().SetTabletModeEnabledForTest(true);
     auto* pref = browser()->profile()->GetPrefs();
     pref->SetBoolean(
-        ash::prefs::kDisplayRotationAcceleratorDialogHasBeenAccepted, true);
+        ash::prefs::kDisplayRotationAcceleratorDialogHasBeenAccepted2, true);
 
     int additional_browsers = std::get<0>(GetParam()) - 1;
     ntp_page_ = std::get<1>(GetParam());
diff --git a/chrome/browser/ui/views/hover_button.cc b/chrome/browser/ui/views/hover_button.cc
index ce6288c..3a6af1242 100644
--- a/chrome/browser/ui/views/hover_button.cc
+++ b/chrome/browser/ui/views/hover_button.cc
@@ -71,6 +71,27 @@
 
 }  // namespace
 
+SingleLineStyledLabelWrapper::SingleLineStyledLabelWrapper(
+    const base::string16& title) {
+  auto title_label = std::make_unique<views::StyledLabel>(title, nullptr);
+  // Size without a maximum width to get a single line label.
+  title_label->SizeToFit(0);
+  label_ = AddChildView(std::move(title_label));
+}
+
+views::StyledLabel* SingleLineStyledLabelWrapper::label() {
+  return label_;
+}
+
+void SingleLineStyledLabelWrapper::OnBoundsChanged(
+    const gfx::Rect& previous_bounds) {
+  // Vertically center its child manually since it doesn't have a LayoutManager.
+  DCHECK(label_);
+
+  int y_center = (height() - label_->size().height()) / 2;
+  label_->SetPosition(gfx::Point(GetLocalBounds().x(), y_center));
+}
+
 HoverButton::HoverButton(views::ButtonListener* button_listener,
                          const base::string16& text)
     : views::LabelButton(/*button_listener*/ nullptr,
@@ -174,17 +195,8 @@
                         row_height);
   icon_view_ = grid_layout->AddView(std::move(icon_view), 1, num_labels);
 
-  auto title_label = std::make_unique<views::StyledLabel>(title, nullptr);
-  // Size without a maximum width to get a single line label.
-  title_label->SizeToFit(0);
-  // |views::StyledLabel|s are all multi-line. With a layout manager,
-  // |StyledLabel| will try use the available space to size itself, and long
-  // titles will wrap to the next line (for smaller |HoverButton|s, this will
-  // also cover up |subtitle_|). Wrap it in a parent view with no layout manager
-  // to ensure it keeps its original size set by SizeToFit() above. Long titles
-  // will then be truncated.
-  auto title_wrapper = std::make_unique<views::View>();
-  title_ = title_wrapper->AddChildView(std::move(title_label));
+  auto title_wrapper = std::make_unique<SingleLineStyledLabelWrapper>(title);
+  title_ = title_wrapper->label();
   // Hover the whole button when hovering |title_|. This is OK because |title_|
   // will never have a link in it.
   title_wrapper->set_can_process_events_within_subtree(false);
@@ -315,17 +327,6 @@
   return ink_drop;
 }
 
-void HoverButton::Layout() {
-  LabelButton::Layout();
-
-  // Vertically center |title_| manually since it doesn't have a LayoutManager.
-  if (title_) {
-    DCHECK(title_->parent());
-    int y_center = title_->parent()->height() / 2 - title_->size().height() / 2;
-    title_->SetPosition(gfx::Point(title_->x(), y_center));
-  }
-}
-
 views::View* HoverButton::GetTooltipHandlerForPoint(const gfx::Point& point) {
   if (!HitTestPoint(point))
     return nullptr;
diff --git a/chrome/browser/ui/views/hover_button.h b/chrome/browser/ui/views/hover_button.h
index 636149b6..e76fa09 100644
--- a/chrome/browser/ui/views/hover_button.h
+++ b/chrome/browser/ui/views/hover_button.h
@@ -30,6 +30,27 @@
 
 class PageInfoBubbleViewBrowserTest;
 
+// A special class used for wrapping a single line styled label.
+// |views::StyledLabel|s are all multi-line. With a layout manager,
+// |StyledLabel| will try use the available space to size itself, and long
+// titles will wrap to the next line (for smaller |HoverButton|s, this will
+// also cover up |subtitle_|). Wrap it in a parent view with no layout manager
+// to ensure it keeps its original size set by SizeToFit(). Long titles
+// will then be truncated.
+class SingleLineStyledLabelWrapper : public views::View {
+ public:
+  explicit SingleLineStyledLabelWrapper(const base::string16& title);
+  ~SingleLineStyledLabelWrapper() override = default;
+
+  // views::View
+  void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
+
+  views::StyledLabel* label();
+
+ private:
+  views::StyledLabel* label_;
+};
+
 // A button taking the full width of its parent that shows a background color
 // when hovered over.
 // TODO (cyan): HoverButton should extend ButtonListener.
@@ -108,7 +129,6 @@
   void StateChanged(ButtonState old_state) override;
   SkColor GetInkDropBaseColor() const override;
   std::unique_ptr<views::InkDrop> CreateInkDrop() override;
-  void Layout() override;
   views::View* GetTooltipHandlerForPoint(const gfx::Point& point) override;
   void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
 
diff --git a/chrome/browser/ui/views/infobars/infobar_view.cc b/chrome/browser/ui/views/infobars/infobar_view.cc
index 7054bb0..2bbfc8e0 100644
--- a/chrome/browser/ui/views/infobars/infobar_view.cc
+++ b/chrome/browser/ui/views/infobars/infobar_view.cc
@@ -215,8 +215,8 @@
     const SkColor color =
         GetColor(ThemeProperties::COLOR_TOOLBAR_CONTENT_AREA_SEPARATOR);
     const gfx::Rect local_bounds = GetLocalBounds();
-    canvas->DrawLine(gfx::Point(local_bounds.x(), local_bounds.y()),
-                     gfx::Point(local_bounds.right(), local_bounds.y()), color);
+    canvas->DrawSharpLine({local_bounds.x(), local_bounds.y()},
+                          {local_bounds.right(), local_bounds.y()}, color);
   }
 }
 
diff --git a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
index 676f914..63c4d1c 100644
--- a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
@@ -556,6 +556,25 @@
   SetShelfHeight(ash::ShelfConfig::Get()->shelf_size());
 }
 
+void CoreOobeHandler::SetDialogPaddingMode(
+    CoreOobeView::DialogPaddingMode mode) {
+  std::string padding;
+  switch (mode) {
+    case CoreOobeView::DialogPaddingMode::MODE_AUTO:
+      padding = "auto";
+      break;
+    case CoreOobeView::DialogPaddingMode::MODE_NARROW:
+      padding = "narrow";
+      break;
+    case CoreOobeView::DialogPaddingMode::MODE_WIDE:
+      padding = "wide";
+      break;
+    default:
+      NOTREACHED();
+  }
+  CallJS("cr.ui.Oobe.setDialogPaddingMode", padding);
+}
+
 void CoreOobeHandler::OnOobeConfigurationChanged() {
   base::Value configuration(base::Value::Type::DICTIONARY);
   chromeos::configuration::FilterConfiguration(
diff --git a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.h b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.h
index 2785f22..0687932 100644
--- a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.h
@@ -39,6 +39,17 @@
 
 class CoreOobeView {
  public:
+  // Enum that specifies how inner padding of OOBE dialog should be calculated.
+  enum class DialogPaddingMode {
+    // Oobe dialog is displayed full screen, padding will be calculated
+    // via css depending on media size.
+    MODE_AUTO,
+    // Oobe dialog have enough free space around and should use wide padding.
+    MODE_WIDE,
+    // Oobe dialog is positioned in limited space and should use narrow padding.
+    MODE_NARROW,
+  };
+
   virtual ~CoreOobeView() {}
 
   virtual void ShowSignInError(int login_attempts,
@@ -60,6 +71,7 @@
   virtual void SetVirtualKeyboardShown(bool shown) = 0;
   virtual void SetClientAreaSize(int width, int height) = 0;
   virtual void SetShelfHeight(int height) = 0;
+  virtual void SetDialogPaddingMode(DialogPaddingMode mode) = 0;
   virtual void ShowDeviceResetScreen() = 0;
   virtual void ShowEnableDebuggingScreen() = 0;
   virtual void InitDemoModeDetection() = 0;
@@ -140,6 +152,7 @@
   void SetVirtualKeyboardShown(bool displayed) override;
   void SetClientAreaSize(int width, int height) override;
   void SetShelfHeight(int height) override;
+  void SetDialogPaddingMode(CoreOobeView::DialogPaddingMode mode) override;
   void ShowDeviceResetScreen() override;
   void ShowEnableDebuggingScreen() override;
   void ShowActiveDirectoryPasswordChangeScreen(
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
index ea89ae0..da7467ea 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -443,11 +443,7 @@
       GaiaUrls::GetInstance()->gaia_url(), gaps_cookie_value, base::Time::Now(),
       base::nullopt /* server_time */));
 
-  net::CookieOptions options;
-  options.set_include_httponly();
-  // Permit it to set a SameSite cookie if it wants to.
-  options.set_same_site_cookie_context(
-      net::CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT);
+  const net::CookieOptions options = net::CookieOptions::MakeAllInclusive();
   partition->GetCookieManagerForBrowserProcess()->SetCanonicalCookie(
       *cc.get(), "https", options, std::move(callback));
 }
@@ -894,9 +890,8 @@
   if (!partition)
     return;
 
-  net::CookieOptions cookie_options;
-  cookie_options.set_include_httponly();
-
+  const net::CookieOptions cookie_options =
+      net::CookieOptions::MakeAllInclusive();
   partition->GetCookieManagerForBrowserProcess()->GetCookieList(
       GaiaUrls::GetInstance()->gaia_url(), cookie_options,
       base::BindOnce(&GaiaScreenHandler::OnGetCookiesForCompleteAuthentication,
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 286577d..1df604d 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1002,6 +1002,7 @@
       "../browser/net/proxy_test_utils.cc",
       "../browser/net/proxy_test_utils.h",
       "../browser/net/reporting_browsertest.cc",
+      "../browser/net/samesite_cookies_policy_browsertest.cc",
       "../browser/net/system_network_context_manager_browsertest.cc",
       "../browser/net/variations_http_headers_browsertest.cc",
       "../browser/net/websocket_browsertest.cc",
@@ -3010,6 +3011,8 @@
     "../browser/mac/keystone_glue_unittest.mm",
     "../browser/media/android/router/media_router_android_unittest.cc",
     "../browser/media/cast_mirroring_service_host_unittest.cc",
+    "../browser/media/history/media_history_keyed_service_factory_unittest.cc",
+    "../browser/media/history/media_history_store_unittest.cc",
     "../browser/media/media_engagement_contents_observer_unittest.cc",
     "../browser/media/media_engagement_preloaded_list_unittest.cc",
     "../browser/media/media_engagement_score_unittest.cc",
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index 5ed8f45b..bf065e83 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -1602,6 +1602,24 @@
     "note": "TODO(bartfab): Flag this with can_be_recommended when http://crbug.com/106682 is fixed."
   },
 
+  "DefaultInsecureContentSetting": {
+    "os": ["win", "linux", "mac", "chromeos"],
+    "test_policy": { "DefaultInsecureContentSetting": 2 },
+    "pref_mappings": [
+      { "pref": "profile.managed_default_content_settings.insecure_content",
+        "indicator_selector": "[content-setting=mixed-script]",
+        "indicator_tests": [
+          { "policy": { "DefaultInsecureContentSetting": 2 },
+            "value": "block"},
+          { "policy": { "DefaultInsecureContentSetting": 3 },
+            "value": "ask"}
+        ]
+      }
+    ],
+
+    "note": "TODO(bartfab): Flag this with can_be_recommended when http://crbug.com/106682 is fixed."
+  },
+
   "DefaultJavaScriptSetting": {
     "os": ["win", "linux", "mac", "chromeos"],
     "test_policy": { "DefaultJavaScriptSetting": 2 },
@@ -1948,6 +1966,38 @@
     "note": "TODO(bartfab): Flag this with can_be_recommended when http://crbug.com/106682 is fixed."
   },
 
+  "InsecureContentAllowedForUrls": {
+    "os": ["win", "linux", "mac", "chromeos"],
+    "test_policy": { "InsecureContentAllowedForUrls": ["[*.]google.com"] },
+    "pref_mappings": [
+      { "pref": "profile.managed_insecure_content_allowed_for_urls",
+        "indicator_test_setup_js": "document.querySelector('button.exceptions-list-button[contentType=mixed-script]').click();",
+        "indicator_selector": "[content-exception=mixed-script]",
+        "indicator_tests": [
+          { "policy": { "InsecureContentAllowedForUrls": ["[*.]google.com"] } }
+        ]
+      }
+    ],
+
+    "note": "TODO(bartfab): Flag this with can_be_recommended when http://crbug.com/106682 is fixed."
+  },
+
+  "InsecureContentBlockedForUrls": {
+    "os": ["win", "linux", "mac", "chromeos"],
+    "test_policy": { "InsecureContentBlockedForUrls": ["[*.]google.com"] },
+    "pref_mappings": [
+      { "pref": "profile.managed_insecure_content_blocked_for_urls",
+        "indicator_test_setup_js": "document.querySelector('button.exceptions-list-button[contentType=mixed-script]').click();",
+        "indicator_selector": "[content-exception=mixed-script]",
+        "indicator_tests": [
+          { "policy": { "InsecureContentBlockedForUrls": ["[*.]google.com"] } }
+        ]
+      }
+    ],
+
+    "note": "TODO(bartfab): Flag this with can_be_recommended when http://crbug.com/106682 is fixed."
+  },
+
   "JavaScriptAllowedForUrls": {
     "os": ["win", "linux", "mac", "chromeos"],
     "test_policy": { "JavaScriptAllowedForUrls": ["[*.]google.com"] },
diff --git a/chrome/test/data/subresource_loading/redirect_to_index.html b/chrome/test/data/subresource_loading/redirect_to_index.html
new file mode 100644
index 0000000..559efcd
--- /dev/null
+++ b/chrome/test/data/subresource_loading/redirect_to_index.html
@@ -0,0 +1,3 @@
+<html>
+  <h1>Test Page for SubresourceLoadingPageLoadMetricsObserverBrowserTest</h1>
+</html>
diff --git a/chrome/test/data/subresource_loading/redirect_to_index.html.mock-http-headers b/chrome/test/data/subresource_loading/redirect_to_index.html.mock-http-headers
new file mode 100644
index 0000000..e8f719f
--- /dev/null
+++ b/chrome/test/data/subresource_loading/redirect_to_index.html.mock-http-headers
@@ -0,0 +1,2 @@
+HTTP/1.1 307 Temporary Redirect
+Location: /index.html
diff --git a/chrome/test/data/subresource_loading/set_cookies.html b/chrome/test/data/subresource_loading/set_cookies.html
new file mode 100644
index 0000000..b6d12319
--- /dev/null
+++ b/chrome/test/data/subresource_loading/set_cookies.html
@@ -0,0 +1,12 @@
+<html>
+  <head>
+    <script>
+      document.cookie = "username=Alice";
+    </script>
+  </head>
+
+  <h1>Test Page for SubresourceLoadingPageLoadMetricsObserverBrowserTest</h1>
+  <p>
+    Sets a cookie for this domain.
+  </p>
+</html>
diff --git a/chrome/test/data/webui/cr_components/network_config_test.js b/chrome/test/data/webui/cr_components/network_config_test.js
index a915475..edeb63f 100644
--- a/chrome/test/data/webui/cr_components/network_config_test.js
+++ b/chrome/test/data/webui/cr_components/network_config_test.js
@@ -32,7 +32,7 @@
     networkConfig = document.createElement('network-config');
     networkConfig.type = OncMojo.getNetworkTypeString(type);
     if (security !== undefined) {
-      networkConfig.securityType = security;
+      networkConfig.securityType_ = security;
     }
   }
 
@@ -209,7 +209,7 @@
         assertEquals('ethernetguid', networkConfig.guid);
         assertEquals(
             chromeos.networkConfig.mojom.SecurityType.kNone,
-            networkConfig.securityType);
+            networkConfig.securityType_);
         let outer = networkConfig.$$('#outer');
         assertFalse(!!outer);
       });
@@ -229,7 +229,7 @@
         assertEquals('eapguid', networkConfig.guid);
         assertEquals(
             chromeos.networkConfig.mojom.SecurityType.kWpaEap,
-            networkConfig.securityType);
+            networkConfig.securityType_);
         assertEquals(
             'PEAP',
             networkConfig.managedProperties.typeProperties.ethernet.eap.outer
diff --git a/chrome/test/data/webui/print_preview/destination_select_test.js b/chrome/test/data/webui/print_preview/destination_select_test.js
new file mode 100644
index 0000000..e734773f
--- /dev/null
+++ b/chrome/test/data/webui/print_preview/destination_select_test.js
@@ -0,0 +1,140 @@
+// 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.
+
+cr.define('destination_select_test', function() {
+  /** @enum {string} */
+  const TestNames = {
+    ChangeIcon: 'change icon',
+  };
+
+  const suiteName = 'DestinationSelectTest';
+  suite(suiteName, function() {
+    /** @type {?PrintPreviewDestinationSelectElement} */
+    let destinationSelect = null;
+
+    const account = 'foo@chromium.org';
+
+    /** @override */
+    setup(function() {
+      PolymerTest.clearBody();
+
+      destinationSelect =
+          document.createElement('print-preview-destination-select');
+      destinationSelect.activeUser = account;
+      destinationSelect.appKioskMode = false;
+      destinationSelect.disabled = false;
+      destinationSelect.noDestinations = false;
+      destinationSelect.recentDestinationList = [
+        // Local printer without stickied icon
+        {
+          id: 'ID1',
+          origin: print_preview.DestinationOrigin.LOCAL,
+          account: '',
+          capabilities: null,
+          displayName: 'One',
+          extensionId: '',
+          extensionName: ''
+        },
+        // Shared cloud printer with stickied icon
+        {
+          id: 'ID2',
+          origin: print_preview.DestinationOrigin.COOKIES,
+          account: account,
+          capabilities: null,
+          displayName: 'Two',
+          extensionId: '',
+          extensionName: '',
+          icon: 'print-preview:printer-shared'
+        },
+        // Shared cloud printer without stickied icon
+        {
+          id: 'ID3',
+          origin: print_preview.DestinationOrigin.COOKIES,
+          account: account,
+          capabilities: null,
+          displayName: 'Three',
+          extensionId: '',
+          extensionName: ''
+        },
+      ];
+
+      document.body.appendChild(destinationSelect);
+    });
+
+    function compareIcon(selectEl, expectedIcon) {
+      const icon = selectEl.style['background-image'].replace(/ /gi, '');
+      const expected = getSelectDropdownBackground(
+          destinationSelect.meta_.byKey('print-preview'), expectedIcon,
+          destinationSelect);
+      assertEquals(expected, icon);
+    }
+
+    test(assert(TestNames.ChangeIcon), function() {
+      const destination = new print_preview.Destination(
+          'ID1', print_preview.DestinationType.LOCAL,
+          print_preview.DestinationOrigin.LOCAL, 'One',
+          print_preview.DestinationConnectionStatus.ONLINE);
+      destinationSelect.destination = destination;
+      destinationSelect.updateDestination();
+      const selectEl = destinationSelect.$$('.md-select');
+      compareIcon(selectEl, 'print');
+      const driveId = print_preview.Destination.GooglePromotedId.DOCS;
+      const cookieOrigin = print_preview.DestinationOrigin.COOKIES;
+
+      return print_preview_test_utils
+          .selectOption(
+              destinationSelect, `${driveId}/${cookieOrigin}/${account}`)
+          .then(() => {
+            // Icon updates early based on the ID.
+            compareIcon(selectEl, 'save-to-drive');
+
+            // Update the destination.
+            destinationSelect.destination =
+                print_preview_test_utils.getGoogleDriveDestination(account);
+
+            // Still Save to Drive icon.
+            compareIcon(selectEl, 'save-to-drive');
+
+            // Select a destination that has a sticky icon value.
+            return print_preview_test_utils.selectOption(
+                destinationSelect, `ID2/${cookieOrigin}/${account}`);
+          })
+          .then(() => {
+            // Should already be updated.
+            compareIcon(selectEl, 'printer-shared');
+
+            // Update destination.
+            destinationSelect.destination = new print_preview.Destination(
+                'ID2', print_preview.DestinationType.GOOGLE,
+                print_preview.DestinationOrigin.COOKIES, 'Two',
+                print_preview.DestinationConnectionStatus.ONLINE,
+                {account: account});
+            compareIcon(selectEl, 'printer-shared');
+
+            // Select a destination that doesn't have a sticky icon value.
+            return print_preview_test_utils.selectOption(
+                destinationSelect, `ID3/${cookieOrigin}/${account}`);
+          })
+          .then(() => {
+            // Falls back to normal printer icon.
+            compareIcon(selectEl, 'print');
+
+            // Update destination.
+            destinationSelect.destination = new print_preview.Destination(
+                'ID3', print_preview.DestinationType.GOOGLE,
+                print_preview.DestinationOrigin.COOKIES, 'Three',
+                print_preview.DestinationConnectionStatus.ONLINE,
+                {account: account});
+
+            // Icon updates based on full destination information.
+            compareIcon(selectEl, 'printer-shared');
+          });
+    });
+  });
+
+  return {
+    suiteName: suiteName,
+    TestNames: TestNames,
+  };
+});
diff --git a/chrome/test/data/webui/print_preview/destination_settings_test.js b/chrome/test/data/webui/print_preview/destination_settings_test.js
index 16a68d3..21355b2 100644
--- a/chrome/test/data/webui/print_preview/destination_settings_test.js
+++ b/chrome/test/data/webui/print_preview/destination_settings_test.js
@@ -200,7 +200,7 @@
       let options =
           destinationSettings.$.destinationSelect.shadowRoot.querySelectorAll(
               'option:not([hidden])');
-      // assertEquals(expectedDestinations.length + 1, options.length);
+      assertEquals(expectedDestinations.length + 1, options.length);
       expectedDestinations.forEach((expectedValue, index) => {
         assertEquals(expectedValue, options[index].value);
       });
diff --git a/chrome/test/data/webui/print_preview/pages_settings_test.js b/chrome/test/data/webui/print_preview/pages_settings_test.js
index 3d60c84..b90500c 100644
--- a/chrome/test/data/webui/print_preview/pages_settings_test.js
+++ b/chrome/test/data/webui/print_preview/pages_settings_test.js
@@ -150,6 +150,17 @@
       await setCustomInput('1,2,3\u30011\u300156');
       validateState(
           [1, 2, 3, 56], [{from: 1, to: 3}, {from: 56, to: 56}], '', false);
+
+      // https://crbug.com/1015145
+      // Tests that the pages gets sorted for an unsorted input.
+      await setCustomInput('89-91, 3, 6, 46, 1, 4, 2-3');
+      validateState(
+          [1, 2, 3, 4, 6, 46, 89, 90, 91],
+          [
+            {from: 1, to: 4}, {from: 6, to: 6}, {from: 46, to: 46},
+            {from: 89, to: 91}
+          ],
+          '', false);
     });
 
     // Tests that the correct error messages are shown for different user
diff --git a/chrome/test/data/webui/print_preview/print_preview_ui_browsertest.js b/chrome/test/data/webui/print_preview/print_preview_ui_browsertest.js
index 4f626c1..d2a1c83 100644
--- a/chrome/test/data/webui/print_preview/print_preview_ui_browsertest.js
+++ b/chrome/test/data/webui/print_preview/print_preview_ui_browsertest.js
@@ -1333,6 +1333,32 @@
 });
 
 // eslint-disable-next-line no-var
+var PrintPreviewDestinationSelectTest = class extends PrintPreviewTest {
+  /** @override */
+  get browsePreload() {
+    return 'chrome://print/ui/destination_select.html';
+  }
+
+  /** @override */
+  get extraLibraries() {
+    return super.extraLibraries.concat([
+      '../test_util.js',
+      'print_preview_test_utils.js',
+      'destination_select_test.js',
+    ]);
+  }
+
+  /** @override */
+  get suiteName() {
+    return destination_select_test.suiteName;
+  }
+};
+
+TEST_F('PrintPreviewDestinationSelectTest', 'ChangeIcon', function() {
+  this.runMochaTest(destination_select_test.TestNames.ChangeIcon);
+});
+
+// eslint-disable-next-line no-var
 var PrintPreviewDestinationSettingsTest = class extends PrintPreviewTest {
   /** @override */
   get browsePreload() {
diff --git a/chromecast/browser/webview/proto/webview.proto b/chromecast/browser/webview/proto/webview.proto
index efba971..7975683 100644
--- a/chromecast/browser/webview/proto/webview.proto
+++ b/chromecast/browser/webview/proto/webview.proto
@@ -67,6 +67,7 @@
 message InputEvent {
   int32 event_type = 1;
   int32 flags = 2;
+  // Event timestamps are in monotonically increasing microseconds.
   int64 timestamp = 3;
   KeyInput key = 4;
   TouchInput touch = 5;
diff --git a/chromeos/network/network_state_handler.cc b/chromeos/network/network_state_handler.cc
index f5144ab..4b30533 100644
--- a/chromeos/network/network_state_handler.cc
+++ b/chromeos/network/network_state_handler.cc
@@ -1369,12 +1369,14 @@
   bool sort_networks = false;
   bool notify_default = network->path() == default_network_path_;
   bool notify_connection_state = false;
+  bool notify_active = false;
 
   if (key == shill::kStateProperty || key == shill::kVisibleProperty) {
     network_list_sorted_ = false;
     if (ConnectionStateChanged(network, prev_connection_state,
                                prev_is_captive_portal)) {
       notify_connection_state = true;
+      notify_active = true;
       if (notify_default)
         notify_default = VerifyDefaultNetworkConnectionStateChange(network);
       // If the default network connection state changed, sort networks now
@@ -1395,7 +1397,6 @@
   if (request_update)
     RequestUpdateForNetwork(service_path);
 
-  bool notify_active = false;
   std::string value_str;
   value.GetAsString(&value_str);
   if (key == shill::kSignalStrengthProperty || key == shill::kWifiBSsid ||
diff --git a/components/arc/session/arc_vm_client_adapter.cc b/components/arc/session/arc_vm_client_adapter.cc
index 528679b4..faa0d73 100644
--- a/components/arc/session/arc_vm_client_adapter.cc
+++ b/components/arc/session/arc_vm_client_adapter.cc
@@ -24,6 +24,7 @@
 #include "base/process/launch.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/system/sys_info.h"
 #include "base/task/post_task.h"
@@ -191,6 +192,7 @@
 
 std::vector<std::string> GenerateKernelCmdline(
     const StartParams& start_params,
+    const UpgradeParams& upgrade_params,
     const FileSystemStatus& file_system_status,
     bool is_dev_mode,
     bool is_host_on_vm,
@@ -218,8 +220,25 @@
       "androidboot.boottime_offset=" + MonotonicTimestamp(),
       // TODO(yusukes): remove this once arcvm supports SELinux.
       "androidboot.selinux=permissive",
-  };
 
+      // Since we don't do mini VM yet, set not only |start_params| but also
+      // |upgrade_params| here for now.
+      base::StringPrintf("androidboot.disable_boot_completed=%d",
+                         upgrade_params.skip_boot_completed_broadcast),
+      base::StringPrintf("androidboot.copy_packages_cache=%d",
+                         static_cast<int>(upgrade_params.packages_cache_mode)),
+      base::StringPrintf("androidboot.skip_gms_core_cache=%d",
+                         upgrade_params.skip_gms_core_cache),
+      base::StringPrintf("androidboot.arc_demo_mode=%d",
+                         upgrade_params.is_demo_session),
+      base::StringPrintf(
+          "androidboot.supervision.transition=%d",
+          static_cast<int>(upgrade_params.supervision_transition)),
+  };
+  // TODO(yusukes): Check if we need to set ro.serialno, ro.boot.serialno,
+  // ro.boot.container_boot_type, and ro.boot.enable_adb_sideloading for ARCVM.
+
+  // Conditionally sets some properties based on |start_params|.
   switch (start_params.play_store_auto_update) {
     case StartParams::PlayStoreAutoUpdate::AUTO_UPDATE_DEFAULT:
       break;
@@ -231,6 +250,17 @@
       break;
   }
 
+  // Conditionally sets more properties based on |upgrade_params|.
+  if (!upgrade_params.locale.empty()) {
+    result.push_back("androidboot.locale=" + upgrade_params.locale);
+    if (!upgrade_params.preferred_languages.empty()) {
+      result.push_back(
+          "androidboot.preferred_languages=" +
+          base::JoinString(upgrade_params.preferred_languages, ","));
+    }
+  }
+
+  // TODO(yusukes): Handle |demo_session_apps_path| in |upgrade_params|.
   return result;
 }
 
@@ -479,11 +509,10 @@
         base::SysInfo::NumberOfProcessors() - start_params_.num_cores_disabled;
     DCHECK_LT(0, cpus);
 
-    // TODO(yusukes): Use |params| for generating kernel command line too.
     DCHECK(is_dev_mode_);
     std::vector<std::string> kernel_cmdline = GenerateKernelCmdline(
-        start_params_, file_system_status, *is_dev_mode_, is_host_on_vm_,
-        version_info::GetChannelString(channel_));
+        start_params_, params, file_system_status, *is_dev_mode_,
+        is_host_on_vm_, version_info::GetChannelString(channel_));
     auto start_request =
         CreateStartArcVmRequest(user_id_hash_, cpus, data_disk_path,
                                 file_system_status, std::move(kernel_cmdline));
diff --git a/components/autofill/core/browser/autofill_external_delegate.cc b/components/autofill/core/browser/autofill_external_delegate.cc
index a5507ab..0e0c7c1 100644
--- a/components/autofill/core/browser/autofill_external_delegate.cc
+++ b/components/autofill/core/browser/autofill_external_delegate.cc
@@ -132,6 +132,7 @@
   InsertDataListValues(&suggestions);
 
   if (suggestions.empty()) {
+    OnAutofillAvailabilityEvent(mojom::AutofillState::kNoSuggestions);
     // No suggestions, any popup currently showing is obsolete.
     manager_->client()->HideAutofillPopup();
     return;
@@ -170,6 +171,10 @@
 }
 
 void AutofillExternalDelegate::OnPopupShown() {
+  // If a popup was shown, then we showed either autofill or autocomplete.
+  OnAutofillAvailabilityEvent(
+      has_autofill_suggestions_ ? mojom::AutofillState::kAutofillAvailable
+                                : mojom::AutofillState::kAutocompleteAvailable);
   manager_->DidShowSuggestions(has_autofill_suggestions_, query_form_,
                                query_field_);
 
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc
index a23e3c53..6575002 100644
--- a/components/autofill/core/browser/autofill_manager.cc
+++ b/components/autofill/core/browser/autofill_manager.cc
@@ -1375,9 +1375,6 @@
     int query_id,
     bool autoselect_first_suggestion,
     const std::vector<Suggestion>& suggestions) {
-  external_delegate_->OnAutofillAvailabilityEvent(
-      !suggestions.empty() ? mojom::AutofillState::kAutocompleteAvailable
-                           : mojom::AutofillState::kNoSuggestions);
   external_delegate_->OnSuggestionsReturned(query_id, suggestions,
                                             autoselect_first_suggestion);
 }
diff --git a/components/autofill/core/browser/autofill_manager.h b/components/autofill/core/browser/autofill_manager.h
index f5a8765..d0954dea 100644
--- a/components/autofill/core/browser/autofill_manager.h
+++ b/components/autofill/core/browser/autofill_manager.h
@@ -670,6 +670,8 @@
                            CreditCardSelectedFormEvents);
   FRIEND_TEST_ALL_PREFIXES(AutofillMetricsIFrameTest,
                            CreditCardFilledFormEvents);
+  FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest,
+                           CreditCardUnmaskingPreflightCall);
   FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, CreditCardGetRealPanDuration);
   FRIEND_TEST_ALL_PREFIXES(AutofillMetricsIFrameTest,
                            CreditCardWillSubmitFormEvents);
diff --git a/components/autofill/core/browser/autofill_metrics.cc b/components/autofill/core/browser/autofill_metrics.cc
index 9e40dc2..f8e1702 100644
--- a/components/autofill/core/browser/autofill_metrics.cc
+++ b/components/autofill/core/browser/autofill_metrics.cc
@@ -934,6 +934,16 @@
 }
 
 // static
+void AutofillMetrics::LogUserPerceivedLatencyOnCardSelection(
+    PreflightCallEvent event,
+    bool fido_auth_enabled) {
+  std::string histogram_name =
+      "Autofill.BetterAuth.UserPerceivedLatencyOnCardSelection.";
+  histogram_name += fido_auth_enabled ? "OptedIn" : "OptedOut";
+  base::UmaHistogramEnumeration(histogram_name, event);
+}
+
+// static
 void AutofillMetrics::LogUnmaskPromptEvent(UnmaskPromptEvent event) {
   UMA_HISTOGRAM_ENUMERATION("Autofill.UnmaskPrompt.Events", event,
                             NUM_UNMASK_PROMPT_EVENTS);
diff --git a/components/autofill/core/browser/autofill_metrics.h b/components/autofill/core/browser/autofill_metrics.h
index bf71f97..02613f6b 100644
--- a/components/autofill/core/browser/autofill_metrics.h
+++ b/components/autofill/core/browser/autofill_metrics.h
@@ -685,6 +685,20 @@
     NUM_UNMASK_PROMPT_EVENTS,
   };
 
+  // Events related to user-perceived latency due to GetDetailsForGetRealPan
+  // call.
+  enum class PreflightCallEvent {
+    // Returned before card chosen.
+    kPreflightCallReturnedBeforeCardChosen = 0,
+    // Did not return before card was chosen. When opted-in, this means
+    // the UI had to wait for the call to return. When opted-out, this means we
+    // did not offer to opt-in.
+    kCardChosenBeforePreflightCallReturned = 1,
+    // Preflight call was irrelevant; skipped waiting.
+    kDidNotChooseMaskedCard = 2,
+    kMaxValue = kDidNotChooseMaskedCard,
+  };
+
   // Possible results of Payments RPCs.
   enum PaymentsRpcResult {
     // Request succeeded.
@@ -1041,6 +1055,11 @@
   // GetDetailsForGetRealPan).
   static void LogCardUnmaskPreflightDuration(const base::TimeDelta& duration);
 
+  // Logs the existence of any user-perceived latency between selecting a Google
+  // Payments server card and seeing a card unmask prompt.
+  static void LogUserPerceivedLatencyOnCardSelection(PreflightCallEvent event,
+                                                     bool fido_auth_enabled);
+
   // Logs |event| to the unmask prompt events histogram.
   static void LogUnmaskPromptEvent(UnmaskPromptEvent event);
 
diff --git a/components/autofill/core/browser/autofill_metrics_unittest.cc b/components/autofill/core/browser/autofill_metrics_unittest.cc
index 81d944bd..6bb4553 100644
--- a/components/autofill/core/browser/autofill_metrics_unittest.cc
+++ b/components/autofill/core/browser/autofill_metrics_unittest.cc
@@ -413,16 +413,19 @@
 }
 
 void AutofillMetricsTest::SetFidoEligibility(bool is_verifiable) {
+  CreditCardAccessManager* access_manager =
+      autofill_manager_->credit_card_access_manager();
 #if !defined(OS_IOS)
   static_cast<TestCreditCardFIDOAuthenticator*>(
-      autofill_manager_->credit_card_access_manager()
-          ->GetOrCreateFIDOAuthenticator())
+      access_manager->GetOrCreateFIDOAuthenticator())
       ->SetUserVerifiable(is_verifiable);
 #endif
-  autofill_manager_->credit_card_access_manager()
-      ->can_fetch_unmask_details_.Signal();
-  autofill_manager_->credit_card_access_manager()->is_user_verifiable_ =
-      base::nullopt;
+  static_cast<payments::TestPaymentsClient*>(
+      autofill_client_.GetPaymentsClient())
+      ->AllowFidoRegistration(true);
+  access_manager->is_authentication_in_progress_ = false;
+  access_manager->can_fetch_unmask_details_.Signal();
+  access_manager->is_user_verifiable_ = base::nullopt;
 }
 
 void AutofillMetricsTest::OnDidGetRealPan(
@@ -4360,6 +4363,11 @@
     SetFidoEligibility(true);
     autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form,
                                           form.fields[0]);
+    std::string guid(
+        "10000000-0000-0000-0000-000000000002");  // masked server card
+    autofill_manager_->FillOrPreviewForm(
+        AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.back(),
+        autofill_manager_->MakeFrontendID(guid, std::string()));
     // Preflight call is made only if a masked server card is available and the
     // user is eligible for FIDO authentication (except iOS).
 #if defined(OS_IOS)
@@ -4381,6 +4389,11 @@
     SetFidoEligibility(true);
     autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form,
                                           form.fields[0]);
+    std::string guid(
+        "10000000-0000-0000-0000-000000000002");  // masked server card
+    autofill_manager_->FillOrPreviewForm(
+        AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.back(),
+        autofill_manager_->MakeFrontendID(guid, std::string()));
     // Preflight call is made only if a masked server card is available and the
     // user is eligible for FIDO authentication (except iOS).
 #if defined(OS_IOS)
diff --git a/components/autofill/core/browser/payments/credit_card_access_manager.cc b/components/autofill/core/browser/payments/credit_card_access_manager.cc
index 5e9a1ee..ad6eab0e 100644
--- a/components/autofill/core/browser/payments/credit_card_access_manager.cc
+++ b/components/autofill/core/browser/payments/credit_card_access_manager.cc
@@ -261,13 +261,28 @@
     const CreditCard* card,
     base::WeakPtr<Accessor> accessor,
     const base::TimeTicks& form_parsed_timestamp) {
+  // Return error if authentication is already in progress or card is nullptr.
   if (is_authentication_in_progress_ || !card) {
     accessor->OnCreditCardFetched(/*did_succeed=*/false, nullptr);
     return;
   }
 
+  // Latency metrics should only be logged if the user is verifiable and the
+  // flag is turned on. If flag is turned off, then |is_user_verifiable_| is not
+  // set.
+#if !defined(OS_IOS)
+  bool should_log_latency_metrics = is_user_verifiable_.value_or(false);
+#endif
+  // Return immediately if local card and log that unmask details were ignored.
   if (card->record_type() != CreditCard::MASKED_SERVER_CARD) {
     accessor->OnCreditCardFetched(/*did_succeed=*/true, card);
+#if !defined(OS_IOS)
+    if (should_log_latency_metrics) {
+      AutofillMetrics::LogUserPerceivedLatencyOnCardSelection(
+          AutofillMetrics::PreflightCallEvent::kDidNotChooseMaskedCard,
+          GetOrCreateFIDOAuthenticator()->IsUserOptedIn());
+    }
+#endif
     return;
   }
 
@@ -276,7 +291,21 @@
   form_parsed_timestamp_ = form_parsed_timestamp;
   is_authentication_in_progress_ = true;
 
-  if (AuthenticationRequiresUnmaskDetails()) {
+  bool get_unmask_details_returned =
+      ready_to_start_authentication_.IsSignaled();
+  // Logging metrics.
+#if !defined(OS_IOS)
+  if (should_log_latency_metrics) {
+    AutofillMetrics::LogUserPerceivedLatencyOnCardSelection(
+        get_unmask_details_returned
+            ? AutofillMetrics::PreflightCallEvent::
+                  kPreflightCallReturnedBeforeCardChosen
+            : AutofillMetrics::PreflightCallEvent::
+                  kCardChosenBeforePreflightCallReturned,
+        GetOrCreateFIDOAuthenticator()->IsUserOptedIn());
+  }
+#endif
+  if (AuthenticationRequiresUnmaskDetails() && !get_unmask_details_returned) {
     // Wait for |ready_to_start_authentication_| to be signaled by
     // OnDidGetUnmaskDetails() or until timeout before calling Authenticate().
     base::PostTaskAndReplyWithResult(
@@ -285,7 +314,7 @@
         base::BindOnce(&CreditCardAccessManager::Authenticate,
                        weak_ptr_factory_.GetWeakPtr()));
   } else {
-    Authenticate();
+    Authenticate(get_unmask_details_returned);
   }
 }
 
@@ -315,7 +344,7 @@
 #endif
 }
 
-void CreditCardAccessManager::Authenticate(bool did_get_unmask_details) {
+void CreditCardAccessManager::Authenticate(bool get_unmask_details_returned) {
   // Reset now that we have started authentication.
   ready_to_start_authentication_.Reset();
   unmask_details_request_in_progress_ = false;
@@ -323,7 +352,7 @@
   // Do not use FIDO if card is not listed in unmask details, as each Card must
   // be CVC authed at least once per device.
   bool card_is_eligible_for_fido =
-      did_get_unmask_details &&
+      get_unmask_details_returned &&
       unmask_details_.unmask_auth_method ==
           AutofillClient::UnmaskAuthMethod::FIDO &&
       unmask_details_.fido_eligible_card_ids.find(card_->server_id()) !=
diff --git a/components/autofill/core/browser/payments/credit_card_access_manager.h b/components/autofill/core/browser/payments/credit_card_access_manager.h
index 96dc2f43..bf3dca51 100644
--- a/components/autofill/core/browser/payments/credit_card_access_manager.h
+++ b/components/autofill/core/browser/payments/credit_card_access_manager.h
@@ -131,10 +131,12 @@
   void OnDidGetUnmaskDetails(AutofillClient::PaymentsRpcResult result,
                              AutofillClient::UnmaskDetails& unmask_details);
 
-  // Calls either CreditCardFIDOAuthenticator::Authenticate() or
-  // CreditCardCVCAuthenticator::Authenticate() depending on the response
-  // contained in |unmask_details_|.
-  void Authenticate(bool did_get_unmask_details = false);
+  // If OnDidGetUnmaskDetails() was invoked by PaymentsClient, then
+  // |get_unmask_details_returned| should be set to true. Based on the
+  // contents of |unmask_details_|, either FIDO authentication or CVC
+  // authentication will be prompted. If |get_unmask_details_returned| is false,
+  // then only CVC authentication will be prompted.
+  void Authenticate(bool get_unmask_details_returned = false);
 
   // CreditCardCVCAuthenticator::Requester:
   void OnCVCAuthenticationComplete(
diff --git a/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc b/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
index b48f0bd..becaca5f 100644
--- a/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
+++ b/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
@@ -191,11 +191,15 @@
     return credit_card_access_manager_->is_authentication_in_progress();
   }
 
-  void ResetPreflightCallLimiter() {
+  void ResetFetchCreditCard() {
+    // Resets all variables related to credit card fetching.
+    credit_card_access_manager_->is_authentication_in_progress_ = false;
     credit_card_access_manager_->can_fetch_unmask_details_.Signal();
     credit_card_access_manager_->is_user_verifiable_ = base::nullopt;
   }
 
+  void ClearCards() { personal_data_manager_.ClearCreditCards(); }
+
   void CreateLocalCard(std::string guid, std::string number = std::string()) {
     CreditCard local_card = CreditCard();
     test::SetCreditCardInfo(&local_card, "Elvis Presley", number.c_str(),
@@ -203,7 +207,6 @@
     local_card.set_guid(guid);
     local_card.set_record_type(CreditCard::LOCAL_CARD);
 
-    personal_data_manager_.ClearCreditCards();
     personal_data_manager_.AddCreditCard(local_card);
   }
 
@@ -215,7 +218,6 @@
     masked_server_card.set_guid(guid);
     masked_server_card.set_record_type(CreditCard::MASKED_SERVER_CARD);
 
-    personal_data_manager_.ClearCreditCards();
     personal_data_manager_.AddServerCreditCard(masked_server_card);
   }
 
@@ -286,6 +288,7 @@
   }
 
   void SetUserOptedIn(bool user_is_opted_in) {
+    scoped_feature_list_.Reset();
     scoped_feature_list_.InitAndEnableFeature(
         features::kAutofillCreditCardAuthentication);
     ::autofill::prefs::SetCreditCardFIDOAuthEnabled(autofill_client_.GetPrefs(),
@@ -522,11 +525,12 @@
   {
     // Create local card and set user as eligible for FIDO auth.
     base::HistogramTester histogram_tester;
+    ClearCards();
     CreateLocalCard(kTestGUID, kTestNumber);
 #if !defined(OS_IOS)
     GetFIDOAuthenticator()->SetUserVerifiable(true);
 #endif
-    ResetPreflightCallLimiter();
+    ResetFetchCreditCard();
 
     credit_card_access_manager_->PrepareToFetchCreditCard();
     InvokeUnmaskDetailsTimeout();
@@ -540,11 +544,12 @@
   {
     // Create server card and set user as ineligible for FIDO auth.
     base::HistogramTester histogram_tester;
+    ClearCards();
     CreateServerCard(kTestGUID, kTestNumber);
 #if !defined(OS_IOS)
     GetFIDOAuthenticator()->SetUserVerifiable(false);
 #endif
-    ResetPreflightCallLimiter();
+    ResetFetchCreditCard();
 
     credit_card_access_manager_->PrepareToFetchCreditCard();
     InvokeUnmaskDetailsTimeout();
@@ -558,11 +563,12 @@
   {
     // Create server card and set user as eligible for FIDO auth.
     base::HistogramTester histogram_tester;
+    ClearCards();
     CreateServerCard(kTestGUID, kTestNumber);
 #if !defined(OS_IOS)
     GetFIDOAuthenticator()->SetUserVerifiable(true);
 #endif
-    ResetPreflightCallLimiter();
+    ResetFetchCreditCard();
 
     credit_card_access_manager_->PrepareToFetchCreditCard();
     InvokeUnmaskDetailsTimeout();
@@ -686,6 +692,86 @@
   EXPECT_EQ(ASCIIToUTF16(kTestNumber), accessor_->number());
 }
 
+// Ensures that FetchCreditCard() returns the full PAN upon a successful
+// WebAuthn verification and response from payments.
+TEST_F(CreditCardAccessManagerTest,
+       Metrics_LoggingExistenceOfUserPerceivedLatency) {
+  // Setting up a FIDO-enabled user with a local card and a server card.
+  std::string server_guid = "00000000-0000-0000-0000-000000000001";
+  std::string local_guid = "00000000-0000-0000-0000-000000000003";
+  CreateServerCard(server_guid, "4594299181086168");
+  CreateLocalCard(local_guid, "4409763681177079");
+  CreditCard* server_card =
+      credit_card_access_manager_->GetCreditCard(server_guid);
+  CreditCard* local_card =
+      credit_card_access_manager_->GetCreditCard(local_guid);
+  GetFIDOAuthenticator()->SetUserVerifiable(true);
+
+  for (bool user_is_opted_in : {true, false}) {
+    std::string histogram_name =
+        "Autofill.BetterAuth.UserPerceivedLatencyOnCardSelection.";
+    histogram_name += user_is_opted_in ? "OptedIn" : "OptedOut";
+    SetUserOptedIn(user_is_opted_in);
+
+    {
+      // Preflight call ignored because local card was chosen.
+      base::HistogramTester histogram_tester;
+
+      ResetFetchCreditCard();
+      credit_card_access_manager_->PrepareToFetchCreditCard();
+      WaitForCallbacks();
+
+      credit_card_access_manager_->FetchCreditCard(local_card,
+                                                   accessor_->GetWeakPtr());
+      WaitForCallbacks();
+
+      histogram_tester.ExpectUniqueSample(
+          histogram_name,
+          AutofillMetrics::PreflightCallEvent::kDidNotChooseMaskedCard, 1);
+    }
+
+    {
+      // Preflight call returned after card was chosen.
+      base::HistogramTester histogram_tester;
+      payments_client_->ShouldReturnUnmaskDetailsImmediately(false);
+
+      ResetFetchCreditCard();
+      credit_card_access_manager_->PrepareToFetchCreditCard();
+      credit_card_access_manager_->FetchCreditCard(server_card,
+                                                   accessor_->GetWeakPtr());
+      WaitForCallbacks();
+
+      histogram_tester.ExpectUniqueSample(
+          histogram_name,
+          AutofillMetrics::PreflightCallEvent::
+              kCardChosenBeforePreflightCallReturned,
+          1);
+    }
+
+    {
+      // Preflight call returned before card was chosen.
+      base::HistogramTester histogram_tester;
+      // This is important because CreditCardFIDOAuthenticator will update the
+      // opted-in pref according to GetDetailsForGetRealPan response.
+      payments_client_->AllowFidoRegistration(!user_is_opted_in);
+
+      ResetFetchCreditCard();
+      credit_card_access_manager_->PrepareToFetchCreditCard();
+      WaitForCallbacks();
+
+      credit_card_access_manager_->FetchCreditCard(server_card,
+                                                   accessor_->GetWeakPtr());
+      WaitForCallbacks();
+
+      histogram_tester.ExpectUniqueSample(
+          histogram_name,
+          AutofillMetrics::PreflightCallEvent::
+              kPreflightCallReturnedBeforeCardChosen,
+          1);
+    }
+  }
+}
+
 #if defined(OS_ANDROID)
 // Ensures that the WebAuthn enrollment prompt is invoked after user opts in.
 TEST_F(CreditCardAccessManagerTest, FIDOEnrollmentSuccess_Android) {
diff --git a/components/autofill/core/browser/payments/test_payments_client.cc b/components/autofill/core/browser/payments/test_payments_client.cc
index deee534..144de65 100644
--- a/components/autofill/core/browser/payments/test_payments_client.cc
+++ b/components/autofill/core/browser/payments/test_payments_client.cc
@@ -35,7 +35,8 @@
 
 void TestPaymentsClient::GetUnmaskDetails(GetUnmaskDetailsCallback callback,
                                           const std::string& app_locale) {
-  std::move(callback).Run(AutofillClient::SUCCESS, unmask_details_);
+  if (should_return_unmask_details_)
+    std::move(callback).Run(AutofillClient::SUCCESS, unmask_details_);
 }
 
 void TestPaymentsClient::GetUploadDetails(
@@ -78,13 +79,20 @@
                           "this is display text");
 }
 
+void TestPaymentsClient::ShouldReturnUnmaskDetailsImmediately(
+    bool should_return_unmask_details) {
+  should_return_unmask_details_ = should_return_unmask_details;
+}
+
 void TestPaymentsClient::AllowFidoRegistration(bool offer_fido_opt_in) {
+  should_return_unmask_details_ = true;
   unmask_details_.offer_fido_opt_in = offer_fido_opt_in;
 }
 
 void TestPaymentsClient::AddFidoEligibleCard(std::string server_id,
                                              std::string credential_id,
                                              std::string relying_party_id) {
+  should_return_unmask_details_ = true;
   unmask_details_.offer_fido_opt_in = false;
   unmask_details_.unmask_auth_method = AutofillClient::UnmaskAuthMethod::FIDO;
   unmask_details_.fido_eligible_card_ids.insert(server_id);
diff --git a/components/autofill/core/browser/payments/test_payments_client.h b/components/autofill/core/browser/payments/test_payments_client.h
index f996c94..03ffcc0 100644
--- a/components/autofill/core/browser/payments/test_payments_client.h
+++ b/components/autofill/core/browser/payments/test_payments_client.h
@@ -56,6 +56,10 @@
       const std::vector<MigratableCreditCard>& migratable_credit_cards,
       MigrateCardsCallback callback) override;
 
+  // Some metrics are affected by the latency of GetUnmaskDetails, so it is
+  // useful to control whether or not GetUnmaskDetails() is responded to.
+  void ShouldReturnUnmaskDetailsImmediately(bool should_return_unmask_details);
+
   void AllowFidoRegistration(bool offer_fido_opt_in = true);
 
   void AddFidoEligibleCard(std::string server_id,
@@ -92,6 +96,9 @@
 
  private:
   std::string server_id_;
+  // Some metrics are affected by the latency of GetUnmaskDetails, so it is
+  // useful to control whether or not GetUnmaskDetails() is responded to.
+  bool should_return_unmask_details_ = true;
   AutofillClient::UnmaskDetails unmask_details_;
   std::vector<std::pair<int, int>> supported_card_bin_ranges_;
   std::vector<AutofillProfile> upload_details_addresses_;
diff --git a/components/content_settings/core/browser/content_settings_policy_provider.cc b/components/content_settings/core/browser/content_settings_policy_provider.cc
index f87f391e..0a2b7407 100644
--- a/components/content_settings/core/browser/content_settings_policy_provider.cc
+++ b/components/content_settings/core/browser/content_settings_policy_provider.cc
@@ -44,6 +44,10 @@
          CONTENT_SETTING_ALLOW},
         {prefs::kManagedImagesBlockedForUrls, CONTENT_SETTINGS_TYPE_IMAGES,
          CONTENT_SETTING_BLOCK},
+        {prefs::kManagedInsecureContentAllowedForUrls,
+         CONTENT_SETTINGS_TYPE_MIXEDSCRIPT, CONTENT_SETTING_ALLOW},
+        {prefs::kManagedInsecureContentBlockedForUrls,
+         CONTENT_SETTINGS_TYPE_MIXEDSCRIPT, CONTENT_SETTING_BLOCK},
         {prefs::kManagedJavaScriptAllowedForUrls,
          CONTENT_SETTINGS_TYPE_JAVASCRIPT, CONTENT_SETTING_ALLOW},
         {prefs::kManagedJavaScriptBlockedForUrls,
@@ -92,6 +96,8 @@
          prefs::kManagedDefaultMediaStreamSetting},
         {CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
          prefs::kManagedDefaultMediaStreamSetting},
+        {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT,
+         prefs::kManagedDefaultInsecureContentSetting},
         {CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
          prefs::kManagedDefaultNotificationsSetting},
         {CONTENT_SETTINGS_TYPE_PLUGINS, prefs::kManagedDefaultPluginsSetting},
@@ -112,6 +118,8 @@
   registry->RegisterListPref(prefs::kManagedCookiesSessionOnlyForUrls);
   registry->RegisterListPref(prefs::kManagedImagesAllowedForUrls);
   registry->RegisterListPref(prefs::kManagedImagesBlockedForUrls);
+  registry->RegisterListPref(prefs::kManagedInsecureContentAllowedForUrls);
+  registry->RegisterListPref(prefs::kManagedInsecureContentBlockedForUrls);
   registry->RegisterListPref(prefs::kManagedJavaScriptAllowedForUrls);
   registry->RegisterListPref(prefs::kManagedJavaScriptBlockedForUrls);
   registry->RegisterListPref(prefs::kManagedNotificationsAllowedForUrls);
@@ -135,6 +143,8 @@
                                 CONTENT_SETTING_DEFAULT);
   registry->RegisterIntegerPref(prefs::kManagedDefaultImagesSetting,
                                 CONTENT_SETTING_DEFAULT);
+  registry->RegisterIntegerPref(prefs::kManagedDefaultInsecureContentSetting,
+                                CONTENT_SETTING_DEFAULT);
   registry->RegisterIntegerPref(prefs::kManagedDefaultJavaScriptSetting,
                                 CONTENT_SETTING_DEFAULT);
   registry->RegisterIntegerPref(prefs::kManagedDefaultNotificationsSetting,
@@ -168,6 +178,10 @@
       prefs::kManagedCookiesSessionOnlyForUrls, callback);
   pref_change_registrar_.Add(prefs::kManagedImagesAllowedForUrls, callback);
   pref_change_registrar_.Add(prefs::kManagedImagesBlockedForUrls, callback);
+  pref_change_registrar_.Add(prefs::kManagedInsecureContentAllowedForUrls,
+                             callback);
+  pref_change_registrar_.Add(prefs::kManagedInsecureContentBlockedForUrls,
+                             callback);
   pref_change_registrar_.Add(prefs::kManagedJavaScriptAllowedForUrls, callback);
   pref_change_registrar_.Add(prefs::kManagedJavaScriptBlockedForUrls, callback);
   pref_change_registrar_.Add(
@@ -194,6 +208,8 @@
   pref_change_registrar_.Add(
       prefs::kManagedDefaultGeolocationSetting, callback);
   pref_change_registrar_.Add(prefs::kManagedDefaultImagesSetting, callback);
+  pref_change_registrar_.Add(prefs::kManagedDefaultInsecureContentSetting,
+                             callback);
   pref_change_registrar_.Add(prefs::kManagedDefaultJavaScriptSetting, callback);
   pref_change_registrar_.Add(
       prefs::kManagedDefaultNotificationsSetting, callback);
@@ -470,6 +486,8 @@
       name == prefs::kManagedCookiesSessionOnlyForUrls ||
       name == prefs::kManagedImagesAllowedForUrls ||
       name == prefs::kManagedImagesBlockedForUrls ||
+      name == prefs::kManagedInsecureContentAllowedForUrls ||
+      name == prefs::kManagedInsecureContentBlockedForUrls ||
       name == prefs::kManagedJavaScriptAllowedForUrls ||
       name == prefs::kManagedJavaScriptBlockedForUrls ||
       name == prefs::kManagedNotificationsAllowedForUrls ||
diff --git a/components/content_settings/core/common/pref_names.cc b/components/content_settings/core/common/pref_names.cc
index 42751eee..59280df 100644
--- a/components/content_settings/core/common/pref_names.cc
+++ b/components/content_settings/core/common/pref_names.cc
@@ -33,6 +33,8 @@
     "profile.managed_default_content_settings.geolocation";
 const char kManagedDefaultImagesSetting[] =
     "profile.managed_default_content_settings.images";
+const char kManagedDefaultInsecureContentSetting[] =
+    "profile.managed_default_content_settings.insecure_content";
 const char kManagedDefaultJavaScriptSetting[] =
     "profile.managed_default_content_settings.javascript";
 const char kManagedDefaultNotificationsSetting[] =
@@ -64,6 +66,10 @@
     "profile.managed_images_allowed_for_urls";
 const char kManagedImagesBlockedForUrls[] =
     "profile.managed_images_blocked_for_urls";
+const char kManagedInsecureContentAllowedForUrls[] =
+    "profile.managed_insecure_content_allowed_for_urls";
+const char kManagedInsecureContentBlockedForUrls[] =
+    "profile.managed_insecure_content_blocked_for_urls";
 const char kManagedJavaScriptAllowedForUrls[] =
     "profile.managed_javascript_allowed_for_urls";
 const char kManagedJavaScriptBlockedForUrls[] =
diff --git a/components/content_settings/core/common/pref_names.h b/components/content_settings/core/common/pref_names.h
index 6b843a97..a4c4bffd 100644
--- a/components/content_settings/core/common/pref_names.h
+++ b/components/content_settings/core/common/pref_names.h
@@ -24,6 +24,7 @@
 extern const char kManagedDefaultAdsSetting[];
 extern const char kManagedDefaultCookiesSetting[];
 extern const char kManagedDefaultImagesSetting[];
+extern const char kManagedDefaultInsecureContentSetting[];
 extern const char kManagedDefaultJavaScriptSetting[];
 extern const char kManagedDefaultPluginsSetting[];
 extern const char kManagedDefaultPopupsSetting[];
@@ -39,6 +40,8 @@
 extern const char kManagedCookiesSessionOnlyForUrls[];
 extern const char kManagedImagesAllowedForUrls[];
 extern const char kManagedImagesBlockedForUrls[];
+extern const char kManagedInsecureContentAllowedForUrls[];
+extern const char kManagedInsecureContentBlockedForUrls[];
 extern const char kManagedJavaScriptAllowedForUrls[];
 extern const char kManagedJavaScriptBlockedForUrls[];
 extern const char kManagedPluginsAllowedForUrls[];
diff --git a/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/EventConstants.java b/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/EventConstants.java
index 5d1bac86..5bec4673 100644
--- a/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/EventConstants.java
+++ b/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/EventConstants.java
@@ -160,6 +160,9 @@
     /** User has finished drop-to-merge to create a group. */
     public static final String TAB_DRAG_AND_DROP_TO_GROUP = "tab_drag_and_drop_to_group";
 
+    /** User has tapped on Identity Disc. */
+    public static final String IDENTITY_DISC_USED = "identity_disc_used";
+
     /**
      * Do not instantiate.
      */
diff --git a/components/metrics/BUILD.gn b/components/metrics/BUILD.gn
index 3ad286428..9a41034 100644
--- a/components/metrics/BUILD.gn
+++ b/components/metrics/BUILD.gn
@@ -5,6 +5,10 @@
 import("//build/config/jumbo.gni")
 import("//testing/test.gni")
 
+if (is_android) {
+  import("//build/config/android/rules.gni")
+}
+
 static_library("demographic_metrics_provider") {
   sources = [
     "demographic_metrics_provider.cc",
@@ -169,6 +173,24 @@
   }
 }
 
+if (is_android) {
+  java_cpp_strings("java_switches_srcjar") {
+    # External code should depend on ":metrics_java" instead.
+    visibility = [ ":*" ]
+    sources = [
+      "//components/metrics/metrics_switches.cc",
+    ]
+    template =
+        "//components/metrics/android/java_templates/MetricsSwitches.java.tmpl"
+  }
+
+  android_library("metrics_java") {
+    # Right now, this only includes the Java switches. But if we need more Java
+    # files, they should be added here as necessary.
+    srcjar_deps = [ ":java_switches_srcjar" ]
+  }
+}
+
 # The component metrics provider is a separate target because it depends upon
 # (the large) component_updater code, and is not needed for some entities that
 # depend on :metrics.
diff --git a/components/metrics/android/java_templates/MetricsSwitches.java.tmpl b/components/metrics/android/java_templates/MetricsSwitches.java.tmpl
new file mode 100644
index 0000000..54e7a747
--- /dev/null
+++ b/components/metrics/android/java_templates/MetricsSwitches.java.tmpl
@@ -0,0 +1,16 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.metrics;
+
+/**
+ * Contains command line switches that are specific to the metrics component.
+ */
+public final class MetricsSwitches {{
+
+{NATIVE_STRINGS}
+
+    // Prevents instantiation.
+    private MetricsSwitches() {{}}
+}}
diff --git a/components/omnibox/browser/BUILD.gn b/components/omnibox/browser/BUILD.gn
index 8992ebf6..edcd9b5 100644
--- a/components/omnibox/browser/BUILD.gn
+++ b/components/omnibox/browser/BUILD.gn
@@ -210,6 +210,7 @@
 
   public_deps = [
     "//base",
+    "//base:i18n",
     "//components/history/core/browser",
     "//components/omnibox/common",
     "//components/omnibox/resources:omnibox_resources",
@@ -220,7 +221,6 @@
   deps = [
     ":buildflags",
     ":in_memory_url_index_cache_proto",
-    "//base:i18n",
     "//components/bookmarks/browser",
     "//components/component_updater",
     "//components/favicon/core",
@@ -467,3 +467,13 @@
     "//third_party/metrics_proto:metrics_proto",
   ]
 }
+
+fuzzer_test("omnibox_view_fuzzer") {
+  sources = [
+    "omnibox_view_fuzzer.cc",
+  ]
+  deps = [
+    ":browser",
+    "//base",
+  ]
+}
diff --git a/components/omnibox/browser/autocomplete_match.cc b/components/omnibox/browser/autocomplete_match.cc
index 6206d3f..f868951 100644
--- a/components/omnibox/browser/autocomplete_match.cc
+++ b/components/omnibox/browser/autocomplete_match.cc
@@ -1078,8 +1078,9 @@
     contents = ellipsis + contents;
     // If the first class is not already NONE, prepend a NONE class for the new
     // ellipsis.
-    if (contents_class[0].offset == 0 &&
-        contents_class[0].style != ACMatchClassification::NONE) {
+    if (contents_class.empty() ||
+        (contents_class[0].offset == 0 &&
+         contents_class[0].style != ACMatchClassification::NONE)) {
       contents_class.insert(contents_class.begin(),
                             {0, ACMatchClassification::NONE});
     }
diff --git a/components/omnibox/browser/autocomplete_match_unittest.cc b/components/omnibox/browser/autocomplete_match_unittest.cc
index 601d5a260..ef832fab 100644
--- a/components/omnibox/browser/autocomplete_match_unittest.cc
+++ b/components/omnibox/browser/autocomplete_match_unittest.cc
@@ -137,6 +137,11 @@
        // should prepend ellipsis, and offset remainder
        {{0, ACMatchClassification::NONE}, {2, ACMatchClassification::MATCH}},
        {{0, ACMatchClassification::NONE}, {6, ACMatchClassification::MATCH}}},
+      {"90123456",
+       "... 90123456",
+       // should prepend ellipsis
+       {},
+       {{0, ACMatchClassification::NONE}}},
   };
   for (const auto& test_case : cases) {
     AutocompleteMatch match;
diff --git a/components/omnibox/browser/omnibox_view_fuzzer.cc b/components/omnibox/browser/omnibox_view_fuzzer.cc
new file mode 100644
index 0000000..2884d8bb
--- /dev/null
+++ b/components/omnibox/browser/omnibox_view_fuzzer.cc
@@ -0,0 +1,18 @@
+// 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/omnibox/browser/omnibox_view.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/strings/string16.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  // This fuzzer creates a random UTF16 string to represent clipboard contents.
+  base::string16 s(reinterpret_cast<const base::string16::value_type*>(data),
+                   size / sizeof(base::string16::value_type));
+  OmniboxView::SanitizeTextForPaste(s);
+  return 0;
+}
diff --git a/components/page_info_strings_grdp/OWNERS b/components/page_info_strings_grdp/OWNERS
index 12441de..151f4bde 100644
--- a/components/page_info_strings_grdp/OWNERS
+++ b/components/page_info_strings_grdp/OWNERS
@@ -1,2 +1,5 @@
 file://chrome/browser/ui/page_info/OWNERS
 # COMPONENT: UI>Browser>Bubbles>PageInfo
+
+# Translation screenshots:
+per-file *.png.sha1=*
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index c2ab204c8..8ca3a7e 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -492,6 +492,7 @@
       'policies': [
         'DefaultCookiesSetting',
         'DefaultImagesSetting',
+        'DefaultInsecureContentSetting',
         'DefaultJavaScriptSetting',
         'DefaultPluginsSetting',
         'DefaultPopupsSetting',
@@ -507,6 +508,8 @@
         'CookiesSessionOnlyForUrls',
         'ImagesAllowedForUrls',
         'ImagesBlockedForUrls',
+        'InsecureContentAllowedForUrls',
+        'InsecureContentBlockedForUrls',
         'JavaScriptAllowedForUrls',
         'JavaScriptBlockedForUrls',
         'KeygenAllowedForUrls',
@@ -18540,6 +18543,83 @@
       If this policy is set to True, when an external protocol confirmation is shown, the user may choose to "Always open" the protocol without future confirmation prompts.
 
       If this policy is set to False or not set, the "Always open" checkbox is not displayed and the user will be prompted each time an external protocol is invoked.'''
+    },
+    {
+      'name': 'DefaultInsecureContentSetting',
+      'owners': ['carlosil@chromium.org', 'estark@chromium.org'],
+      'type': 'int-enum',
+      'schema': {
+        'type': 'integer',
+        'enum': [ 2, 3 ],
+      },
+      'items': [
+        {
+          'name': 'BlockInsecureContent',
+          'value': 2,
+          'caption': '''Do not allow any site to load blockable mixed content''',
+        },
+        {
+          'name': 'AllowExceptionsInsecureContent',
+          'value': 3,
+          'caption': '''Allow users to add exceptions to allow blockable mixed content''',
+        },
+      ],
+      'supported_on': ['chrome.*:79-', 'chrome_os:79-'],
+      'features': {
+        'dynamic_refresh': True,
+        'per_profile': True,
+      },
+      'example_value': 2,
+      'id': 633,
+      'caption': '''Control use of insecure content exceptions''',
+      'tags': [],
+      'desc': '''Allows you to set whether users can add exceptions to allow mixed content for specific sites.
+
+          This policy can be overridden for specific URL patterns using the 'InsecureContentAllowedForUrls' and 'InsecureContentBlockedForUrls' policies.
+
+          If this policy is left not set, users will be allowed to add exceptions to allow blockable mixed content"''',
+    },
+    {
+      'name': 'InsecureContentAllowedForUrls',
+      'owners': ['carlosil@chromium.org', 'estark@chromium.org'],
+      'type': 'list',
+      'schema': {
+        'type': 'array',
+        'items': { 'type': 'string' },
+      },
+      'supported_on': ['chrome.*:79-', 'chrome_os:79-'],
+      'features': {
+        'dynamic_refresh': True,
+        'per_profile': True,
+      },
+      'example_value': ['https://www.example.com', '[*.]example.edu'],
+      'id': 634,
+      'caption': '''Allow insecure content on these sites''',
+      'tags': [],
+      'desc': '''Allows you to set a list of url patterns that specify sites which are allowed to display blockable (i.e. active) mixed content (i.e. HTTP content on HTTPS sites).
+
+          If this policy is left not set blockable mixed content will be blocked, but users will be allowed to set exceptions to allow it for specific sites.''',
+    },
+    {
+      'name': 'InsecureContentBlockedForUrls',
+      'owners': ['carlosil@chromium.org', 'estark@chromium.org'],
+      'type': 'list',
+      'schema': {
+        'type': 'array',
+        'items': { 'type': 'string' },
+      },
+      'supported_on': ['chrome.*:79-', 'chrome_os:79-'],
+      'features': {
+        'dynamic_refresh': True,
+        'per_profile': True,
+      },
+      'example_value': ['https://www.example.com', '[*.]example.edu'],
+      'id': 635,
+      'caption': '''Block insecure content on these sites''',
+      'tags': [],
+      'desc': '''Allows you to set a list of url patterns that specify sites which are not allowed to display blockable (i.e. active) mixed content (i.e. HTTP content on HTTPS sites).
+
+          If this policy is left not set blockable mixed content will be blocked, but users will be allowed to set exceptions to allow it for specific sites.''',
     }
   ],
 
@@ -19362,6 +19442,6 @@
   ],
   'placeholders': [],
   'deleted_policy_ids': [412, 546, 562, 569],
-  'highest_id_currently_used': 632,
+  'highest_id_currently_used': 635,
   'highest_atomic_group_id_currently_used': 38
 }
diff --git a/components/security_interstitials_strings_grdp/OWNERS b/components/security_interstitials_strings_grdp/OWNERS
index 5643d3a..c1db7f01 100644
--- a/components/security_interstitials_strings_grdp/OWNERS
+++ b/components/security_interstitials_strings_grdp/OWNERS
@@ -1,2 +1,5 @@
 file://components/security_interstitials/OWNERS
 # COMPONENT: Services>Safebrowsing
+
+# Translation screenshots:
+per-file *.png.sha1=*
diff --git a/components/security_state_strings_grdp/IDS_SECURITY_TAB_SAFETY_TIP_BAD_REPUTATION_DESCRIPTION.png.sha1 b/components/security_state_strings_grdp/IDS_SECURITY_TAB_SAFETY_TIP_BAD_REPUTATION_DESCRIPTION.png.sha1
new file mode 100644
index 0000000..2bcccb5
--- /dev/null
+++ b/components/security_state_strings_grdp/IDS_SECURITY_TAB_SAFETY_TIP_BAD_REPUTATION_DESCRIPTION.png.sha1
@@ -0,0 +1 @@
+4cac9b5f4f523d130b9c666ea7978a6ccd2c29d1
\ No newline at end of file
diff --git a/components/security_state_strings_grdp/IDS_SECURITY_TAB_SAFETY_TIP_BAD_REPUTATION_SUMMARY.png.sha1 b/components/security_state_strings_grdp/IDS_SECURITY_TAB_SAFETY_TIP_BAD_REPUTATION_SUMMARY.png.sha1
new file mode 100644
index 0000000..2bcccb5
--- /dev/null
+++ b/components/security_state_strings_grdp/IDS_SECURITY_TAB_SAFETY_TIP_BAD_REPUTATION_SUMMARY.png.sha1
@@ -0,0 +1 @@
+4cac9b5f4f523d130b9c666ea7978a6ccd2c29d1
\ No newline at end of file
diff --git a/components/security_state_strings_grdp/IDS_SECURITY_TAB_SAFETY_TIP_LOOKALIKE_DESCRIPTION.png.sha1 b/components/security_state_strings_grdp/IDS_SECURITY_TAB_SAFETY_TIP_LOOKALIKE_DESCRIPTION.png.sha1
new file mode 100644
index 0000000..c4ba84f
--- /dev/null
+++ b/components/security_state_strings_grdp/IDS_SECURITY_TAB_SAFETY_TIP_LOOKALIKE_DESCRIPTION.png.sha1
@@ -0,0 +1 @@
+9459e00d739be97acb35e43a6d3b4d1b34dece2d
\ No newline at end of file
diff --git a/components/security_state_strings_grdp/IDS_SECURITY_TAB_SAFETY_TIP_LOOKALIKE_SUMMARY.png.sha1 b/components/security_state_strings_grdp/IDS_SECURITY_TAB_SAFETY_TIP_LOOKALIKE_SUMMARY.png.sha1
new file mode 100644
index 0000000..c4ba84f
--- /dev/null
+++ b/components/security_state_strings_grdp/IDS_SECURITY_TAB_SAFETY_TIP_LOOKALIKE_SUMMARY.png.sha1
@@ -0,0 +1 @@
+9459e00d739be97acb35e43a6d3b4d1b34dece2d
\ No newline at end of file
diff --git a/components/security_state_strings_grdp/IDS_SECURITY_TAB_SAFETY_TIP_TITLE.png.sha1 b/components/security_state_strings_grdp/IDS_SECURITY_TAB_SAFETY_TIP_TITLE.png.sha1
new file mode 100644
index 0000000..2bcccb5
--- /dev/null
+++ b/components/security_state_strings_grdp/IDS_SECURITY_TAB_SAFETY_TIP_TITLE.png.sha1
@@ -0,0 +1 @@
+4cac9b5f4f523d130b9c666ea7978a6ccd2c29d1
\ No newline at end of file
diff --git a/components/security_state_strings_grdp/OWNERS b/components/security_state_strings_grdp/OWNERS
index 6d3f89e..943b24e 100644
--- a/components/security_state_strings_grdp/OWNERS
+++ b/components/security_state_strings_grdp/OWNERS
@@ -1,2 +1,5 @@
 file://components/security_state/OWNERS
 # COMPONENT: Internals>PageSecurityState
+
+# Translation screenshots:
+per-file *.png.sha1=*
diff --git a/components/services/leveldb/BUILD.gn b/components/services/leveldb/BUILD.gn
index 624c887..e2091e68 100644
--- a/components/services/leveldb/BUILD.gn
+++ b/components/services/leveldb/BUILD.gn
@@ -12,7 +12,6 @@
 
   public_deps = [
     "//components/services/leveldb/public/cpp",
-    "//components/services/leveldb/public/mojom",
     "//components/services/storage",
   ]
 
diff --git a/components/services/leveldb/leveldb_database_impl.cc b/components/services/leveldb/leveldb_database_impl.cc
index cac018c2..45dee3b3 100644
--- a/components/services/leveldb/leveldb_database_impl.cc
+++ b/components/services/leveldb/leveldb_database_impl.cc
@@ -112,46 +112,6 @@
           std::move(callback), base::SequencedTaskRunnerHandle::Get()));
 }
 
-void LevelDBDatabaseImpl::Write(
-    std::vector<mojom::BatchedOperationPtr> operations,
-    StatusCallback callback) {
-  RunDatabaseTask(
-      base::BindOnce(
-          [](std::vector<mojom::BatchedOperationPtr> operations,
-             const storage::DomStorageDatabase& db) {
-            WriteBatch batch;
-            for (auto& op : operations) {
-              switch (op->type) {
-                case mojom::BatchOperationType::PUT_KEY: {
-                  if (op->value) {
-                    batch.Put(GetSliceFor(op->key), GetSliceFor(*(op->value)));
-                  } else {
-                    batch.Put(GetSliceFor(op->key), Slice());
-                  }
-                  break;
-                }
-                case mojom::BatchOperationType::DELETE_KEY: {
-                  batch.Delete(GetSliceFor(op->key));
-                  break;
-                }
-                case mojom::BatchOperationType::DELETE_PREFIXED_KEY: {
-                  db.DeletePrefixed(op->key, &batch);
-                  break;
-                }
-                case mojom::BatchOperationType::COPY_PREFIXED_KEY: {
-                  // DCHECK is fine here since browser code is the only caller.
-                  DCHECK(op->value);
-                  db.CopyPrefixed(op->key, *(op->value), &batch);
-                  break;
-                }
-              }
-            }
-            return db.Commit(&batch);
-          },
-          std::move(operations)),
-      std::move(callback));
-}
-
 void LevelDBDatabaseImpl::Get(const std::vector<uint8_t>& key,
                               GetCallback callback) {
   struct GetResult {
@@ -192,6 +152,21 @@
                   std::move(callback));
 }
 
+void LevelDBDatabaseImpl::RunBatchDatabaseTasks(
+    std::vector<BatchDatabaseTask> tasks,
+    base::OnceCallback<void(leveldb::Status)> callback) {
+  RunDatabaseTask(base::BindOnce(
+                      [](std::vector<BatchDatabaseTask> tasks,
+                         const storage::DomStorageDatabase& db) {
+                        leveldb::WriteBatch batch;
+                        for (auto& task : tasks)
+                          std::move(task).Run(&batch, db);
+                        return db.Commit(&batch);
+                      },
+                      std::move(tasks)),
+                  std::move(callback));
+}
+
 void LevelDBDatabaseImpl::OnDatabaseOpened(
     StatusCallback callback,
     base::SequenceBound<storage::DomStorageDatabase> database,
diff --git a/components/services/leveldb/leveldb_database_impl.h b/components/services/leveldb/leveldb_database_impl.h
index 0268502..7b4c8da 100644
--- a/components/services/leveldb/leveldb_database_impl.h
+++ b/components/services/leveldb/leveldb_database_impl.h
@@ -12,8 +12,8 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/sequenced_task_runner.h"
 #include "base/threading/sequence_bound.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "base/unguessable_token.h"
-#include "components/services/leveldb/public/mojom/leveldb.mojom.h"
 #include "components/services/storage/dom_storage/dom_storage_database.h"
 #include "third_party/leveldatabase/src/include/leveldb/cache.h"
 #include "third_party/leveldatabase/src/include/leveldb/db.h"
@@ -71,9 +71,6 @@
 
   void RewriteDB(StatusCallback callback);
 
-  void Write(std::vector<mojom::BatchedOperationPtr> operations,
-             StatusCallback callback);
-
   using GetCallback =
       base::OnceCallback<void(Status status, const std::vector<uint8_t>&)>;
   void Get(const std::vector<uint8_t>& key, GetCallback callback);
@@ -110,6 +107,13 @@
     }
   }
 
+  using BatchDatabaseTask =
+      base::OnceCallback<void(leveldb::WriteBatch*,
+                              const storage::DomStorageDatabase&)>;
+  void RunBatchDatabaseTasks(
+      std::vector<BatchDatabaseTask> tasks,
+      base::OnceCallback<void(leveldb::Status)> callback);
+
  private:
   void OnDatabaseOpened(
       StatusCallback callback,
diff --git a/components/services/leveldb/public/cpp/BUILD.gn b/components/services/leveldb/public/cpp/BUILD.gn
index 24e3edb..ed0e4a2 100644
--- a/components/services/leveldb/public/cpp/BUILD.gn
+++ b/components/services/leveldb/public/cpp/BUILD.gn
@@ -10,7 +10,6 @@
 
   deps = [
     "//base",
-    "//components/services/leveldb/public/mojom",
     "//third_party/leveldatabase",
   ]
 }
diff --git a/components/services/leveldb/public/mojom/BUILD.gn b/components/services/leveldb/public/mojom/BUILD.gn
deleted file mode 100644
index 64342215..0000000
--- a/components/services/leveldb/public/mojom/BUILD.gn
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//mojo/public/tools/bindings/mojom.gni")
-
-mojom("mojom") {
-  sources = [
-    "leveldb.mojom",
-  ]
-}
diff --git a/components/services/leveldb/public/mojom/OWNERS b/components/services/leveldb/public/mojom/OWNERS
deleted file mode 100644
index 08850f4..0000000
--- a/components/services/leveldb/public/mojom/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/components/services/leveldb/public/mojom/leveldb.mojom b/components/services/leveldb/public/mojom/leveldb.mojom
deleted file mode 100644
index 146d254e..0000000
--- a/components/services/leveldb/public/mojom/leveldb.mojom
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module leveldb.mojom;
-
-enum BatchOperationType {
-  PUT_KEY,
-  DELETE_KEY,
-  DELETE_PREFIXED_KEY,
-  // |key| is source prefixed key, |value| is destination prefixed key.
-  COPY_PREFIXED_KEY
-};
-
-// TODO(dmurph): change to a union type for value population.
-struct BatchedOperation {
-  BatchOperationType type;
-  array<uint8> key;
-  // Populated for operations of types PUT_KEY and COPY_PREFIXED_KEY.
-  array<uint8>? value;
-};
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
index 97ff0d9f..c892197 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
@@ -216,7 +216,10 @@
   void ScheduleDelayedWork();
   void PerformDelayedWork();
 
-  bool is_using_vulkan() const { return !!vulkan_context_provider_; }
+  bool is_using_vulkan() const {
+    return !!vulkan_context_provider_ &&
+           gpu_preferences_.gr_context_type == gpu::GrContextType::kVulkan;
+  }
 
   SkSurface* output_sk_surface() const {
     return scoped_output_device_paint_->sk_surface();
diff --git a/components/viz/service/gl/gpu_service_impl.h b/components/viz/service/gl/gpu_service_impl.h
index d0887e9e..0281fb23 100644
--- a/components/viz/service/gl/gpu_service_impl.h
+++ b/components/viz/service/gl/gpu_service_impl.h
@@ -255,7 +255,10 @@
   }
 
 #if BUILDFLAG(ENABLE_VULKAN)
-  bool is_using_vulkan() const { return !!vulkan_context_provider_; }
+  bool is_using_vulkan() const {
+    return !!vulkan_context_provider_ &&
+           gpu_preferences_.gr_context_type == gpu::GrContextType::kVulkan;
+  }
   VulkanContextProvider* vulkan_context_provider() {
     return vulkan_context_provider_.get();
   }
diff --git a/content/browser/dom_storage/dom_storage_browsertest.cc b/content/browser/dom_storage/dom_storage_browsertest.cc
index 769047c..ed163c8 100644
--- a/content/browser/dom_storage/dom_storage_browsertest.cc
+++ b/content/browser/dom_storage/dom_storage_browsertest.cc
@@ -9,7 +9,6 @@
 #include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "components/services/leveldb/public/cpp/util.h"
-#include "components/services/leveldb/public/mojom/leveldb.mojom.h"
 #include "content/browser/dom_storage/dom_storage_context_wrapper.h"
 #include "content/browser/dom_storage/dom_storage_database.h"
 #include "content/browser/dom_storage/dom_storage_task_runner.h"
diff --git a/content/browser/dom_storage/dom_storage_context_wrapper.h b/content/browser/dom_storage/dom_storage_context_wrapper.h
index 5ab6db92..5a038517 100644
--- a/content/browser/dom_storage/dom_storage_context_wrapper.h
+++ b/content/browser/dom_storage/dom_storage_context_wrapper.h
@@ -15,7 +15,6 @@
 #include "base/memory/weak_ptr.h"
 #include "base/synchronization/lock.h"
 #include "base/thread_annotations.h"
-#include "components/services/leveldb/public/mojom/leveldb.mojom.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/dom_storage_context.h"
 #include "mojo/public/cpp/bindings/message.h"
diff --git a/content/browser/dom_storage/local_storage_context_mojo.cc b/content/browser/dom_storage/local_storage_context_mojo.cc
index 3bbab90..9295482f 100644
--- a/content/browser/dom_storage/local_storage_context_mojo.cc
+++ b/content/browser/dom_storage/local_storage_context_mojo.cc
@@ -28,7 +28,6 @@
 #include "build/build_config.h"
 #include "components/services/leveldb/leveldb_database_impl.h"
 #include "components/services/leveldb/public/cpp/util.h"
-#include "components/services/leveldb/public/mojom/leveldb.mojom.h"
 #include "components/services/storage/dom_storage/dom_storage_database.h"
 #include "content/browser/dom_storage/dom_storage_database.h"
 #include "content/browser/dom_storage/dom_storage_types.h"
diff --git a/content/browser/dom_storage/local_storage_context_mojo.h b/content/browser/dom_storage/local_storage_context_mojo.h
index fb5e6390..8bfb4a3 100644
--- a/content/browser/dom_storage/local_storage_context_mojo.h
+++ b/content/browser/dom_storage/local_storage_context_mojo.h
@@ -19,7 +19,6 @@
 #include "base/trace_event/memory_allocator_dump.h"
 #include "base/trace_event/memory_dump_provider.h"
 #include "components/services/leveldb/leveldb_database_impl.h"
-#include "components/services/leveldb/public/mojom/leveldb.mojom.h"
 #include "components/services/storage/dom_storage/dom_storage_database.h"
 #include "content/browser/dom_storage/dom_storage_task_runner.h"
 #include "content/common/content_export.h"
diff --git a/content/browser/dom_storage/session_storage_area_impl_unittest.cc b/content/browser/dom_storage/session_storage_area_impl_unittest.cc
index e7058d9..3441afc 100644
--- a/content/browser/dom_storage/session_storage_area_impl_unittest.cc
+++ b/content/browser/dom_storage/session_storage_area_impl_unittest.cc
@@ -18,7 +18,6 @@
 #include "base/threading/thread.h"
 #include "components/services/leveldb/leveldb_database_impl.h"
 #include "components/services/leveldb/public/cpp/util.h"
-#include "components/services/leveldb/public/mojom/leveldb.mojom.h"
 #include "content/browser/dom_storage/session_storage_data_map.h"
 #include "content/browser/dom_storage/session_storage_metadata.h"
 #include "content/browser/dom_storage/test/storage_area_test_util.h"
@@ -69,23 +68,25 @@
     leveldb_database_->Put(StdStringToUint8Vector("map-0-key1"),
                            StdStringToUint8Vector("data1"), base::DoNothing());
 
-    std::vector<leveldb::mojom::BatchedOperationPtr> save_operations =
+    std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask> save_tasks =
         metadata_.SetupNewDatabase();
     auto map_id = metadata_.RegisterNewMap(
         metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_), test_origin1_,
-        &save_operations);
+        &save_tasks);
     DCHECK(map_id->KeyPrefix() == StdStringToUint8Vector("map-0-"));
-    leveldb_database_->Write(std::move(save_operations), base::DoNothing());
+    leveldb_database_->RunBatchDatabaseTasks(std::move(save_tasks),
+                                             base::DoNothing());
   }
   ~SessionStorageAreaImplTest() override = default;
 
   scoped_refptr<SessionStorageMetadata::MapData> RegisterNewAreaMap(
       SessionStorageMetadata::NamespaceEntry namespace_entry,
       const url::Origin& origin) {
-    std::vector<leveldb::mojom::BatchedOperationPtr> save_operations;
+    std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask> save_tasks;
     auto map_data =
-        metadata_.RegisterNewMap(namespace_entry, origin, &save_operations);
-    leveldb_database_->Write(std::move(save_operations), base::DoNothing());
+        metadata_.RegisterNewMap(namespace_entry, origin, &save_tasks);
+    leveldb_database_->RunBatchDatabaseTasks(std::move(save_tasks),
+                                             base::DoNothing());
     return map_data;
   }
 
@@ -211,12 +212,12 @@
       GetRegisterNewAreaMapCallback());
 
   // Perform a shallow clone.
-  std::vector<leveldb::mojom::BatchedOperationPtr> save_operations;
+  std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask> save_tasks;
   metadata_.RegisterShallowClonedNamespace(
       metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_),
-      metadata_.GetOrCreateNamespaceEntry(test_namespace_id2_),
-      &save_operations);
-  leveldb_database_->Write(std::move(save_operations), base::DoNothing());
+      metadata_.GetOrCreateNamespaceEntry(test_namespace_id2_), &save_tasks);
+  leveldb_database_->RunBatchDatabaseTasks(std::move(save_tasks),
+                                           base::DoNothing());
   auto ss_leveldb_impl2 = ss_leveldb_impl1->Clone(
       metadata_.GetOrCreateNamespaceEntry(test_namespace_id2_));
 
@@ -320,12 +321,12 @@
       GetRegisterNewAreaMapCallback());
 
   // Perform a shallow clone.
-  std::vector<leveldb::mojom::BatchedOperationPtr> save_operations;
+  std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask> save_tasks;
   metadata_.RegisterShallowClonedNamespace(
       metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_),
-      metadata_.GetOrCreateNamespaceEntry(test_namespace_id2_),
-      &save_operations);
-  leveldb_database_->Write(std::move(save_operations), base::DoNothing());
+      metadata_.GetOrCreateNamespaceEntry(test_namespace_id2_), &save_tasks);
+  leveldb_database_->RunBatchDatabaseTasks(std::move(save_tasks),
+                                           base::DoNothing());
   auto ss_leveldb_impl2 = ss_leveldb_impl1->Clone(
       metadata_.GetOrCreateNamespaceEntry(test_namespace_id2_));
 
@@ -411,12 +412,12 @@
       GetRegisterNewAreaMapCallback());
 
   // Perform a shallow clone.
-  std::vector<leveldb::mojom::BatchedOperationPtr> save_operations;
+  std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask> save_tasks;
   metadata_.RegisterShallowClonedNamespace(
       metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_),
-      metadata_.GetOrCreateNamespaceEntry(test_namespace_id2_),
-      &save_operations);
-  leveldb_database_->Write(std::move(save_operations), base::DoNothing());
+      metadata_.GetOrCreateNamespaceEntry(test_namespace_id2_), &save_tasks);
+  leveldb_database_->RunBatchDatabaseTasks(std::move(save_tasks),
+                                           base::DoNothing());
   auto ss_leveldb_impl2 = ss_leveldb_impl1->Clone(
       metadata_.GetOrCreateNamespaceEntry(test_namespace_id2_));
 
diff --git a/content/browser/dom_storage/session_storage_context_mojo.cc b/content/browser/dom_storage/session_storage_context_mojo.cc
index e492418..359a022 100644
--- a/content/browser/dom_storage/session_storage_context_mojo.cc
+++ b/content/browser/dom_storage/session_storage_context_mojo.cc
@@ -26,7 +26,6 @@
 #include "build/build_config.h"
 #include "components/services/leveldb/leveldb_database_impl.h"
 #include "components/services/leveldb/public/cpp/util.h"
-#include "components/services/leveldb/public/mojom/leveldb.mojom.h"
 #include "components/services/storage/dom_storage/dom_storage_database.h"
 #include "content/browser/dom_storage/dom_storage_types.h"
 #include "content/browser/dom_storage/session_storage_area_impl.h"
@@ -211,16 +210,16 @@
         DCHECK_EQ(connection_state_, CONNECTION_FINISHED);
         // The namespace exists on disk but is not in-use, so do the appropriate
         // metadata operations to clone the namespace and set up the new object.
-        std::vector<leveldb::mojom::BatchedOperationPtr> save_operations;
+        std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask> save_tasks;
         auto source_namespace_entry =
             metadata_.GetOrCreateNamespaceEntry(clone_from_namespace_id);
         auto namespace_entry =
             metadata_.GetOrCreateNamespaceEntry(clone_to_namespace_id);
-        metadata_.RegisterShallowClonedNamespace(
-            source_namespace_entry, namespace_entry, &save_operations);
+        metadata_.RegisterShallowClonedNamespace(source_namespace_entry,
+                                                 namespace_entry, &save_tasks);
         if (database_) {
-          database_->Write(
-              std::move(save_operations),
+          database_->RunBatchDatabaseTasks(
+              std::move(save_tasks),
               base::BindOnce(&SessionStorageContextMojo::OnCommitResult,
                              weak_ptr_factory_.GetWeakPtr()));
         }
@@ -321,11 +320,11 @@
   } else {
     // If we don't have the namespace loaded, then we can delete it all
     // using the metadata.
-    std::vector<leveldb::mojom::BatchedOperationPtr> delete_operations;
-    metadata_.DeleteArea(namespace_id, origin, &delete_operations);
+    std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask> tasks;
+    metadata_.DeleteArea(namespace_id, origin, &tasks);
     if (database_) {
-      database_->Write(
-          std::move(delete_operations),
+      database_->RunBatchDatabaseTasks(
+          std::move(tasks),
           base::BindOnce(&SessionStorageContextMojo::OnCommitResultWithCallback,
                          weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
     } else {
@@ -459,16 +458,17 @@
     }
     namespaces_to_delete.push_back(namespace_id);
   }
-  std::vector<leveldb::mojom::BatchedOperationPtr> delete_operations;
-  for (const auto& namespace_id : namespaces_to_delete) {
-    metadata_.DeleteNamespace(namespace_id, &delete_operations);
+  std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask> save_tasks;
+  for (const auto& namespace_id : namespaces_to_delete)
+    metadata_.DeleteNamespace(namespace_id, &save_tasks);
+
+  if (database_) {
+    database_->RunBatchDatabaseTasks(
+        std::move(save_tasks),
+        base::BindOnce(&SessionStorageContextMojo::OnCommitResult,
+                       weak_ptr_factory_.GetWeakPtr()));
   }
 
-  if (!delete_operations.empty()) {
-    database_->Write(std::move(delete_operations),
-                     base::BindOnce(&SessionStorageContextMojo::OnCommitResult,
-                                    weak_ptr_factory_.GetWeakPtr()));
-  }
   protected_namespaces_from_scavenge_.clear();
   if (done)
     std::move(done).Run();
@@ -545,14 +545,15 @@
 SessionStorageContextMojo::RegisterNewAreaMap(
     SessionStorageMetadata::NamespaceEntry namespace_entry,
     const url::Origin& origin) {
-  std::vector<leveldb::mojom::BatchedOperationPtr> save_operations;
+  std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask> save_tasks;
   scoped_refptr<SessionStorageMetadata::MapData> map_entry =
-      metadata_.RegisterNewMap(namespace_entry, origin, &save_operations);
+      metadata_.RegisterNewMap(namespace_entry, origin, &save_tasks);
 
   if (database_) {
-    database_->Write(std::move(save_operations),
-                     base::BindOnce(&SessionStorageContextMojo::OnCommitResult,
-                                    weak_ptr_factory_.GetWeakPtr()));
+    database_->RunBatchDatabaseTasks(
+        std::move(save_tasks),
+        base::BindOnce(&SessionStorageContextMojo::OnCommitResult,
+                       weak_ptr_factory_.GetWeakPtr()));
   }
   return map_entry;
 }
@@ -618,7 +619,7 @@
     SessionStorageMetadata::NamespaceEntry source_namespace_entry,
     const std::string& new_namespace_id,
     const SessionStorageNamespaceImplMojo::OriginAreas& clone_from_areas) {
-  std::vector<leveldb::mojom::BatchedOperationPtr> save_operations;
+  std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask> save_tasks;
 
   bool found = false;
   auto it = namespaces_.find(new_namespace_id);
@@ -634,11 +635,12 @@
   DCHECK_EQ(connection_state_, CONNECTION_FINISHED);
   auto namespace_entry = metadata_.GetOrCreateNamespaceEntry(new_namespace_id);
   metadata_.RegisterShallowClonedNamespace(source_namespace_entry,
-                                           namespace_entry, &save_operations);
+                                           namespace_entry, &save_tasks);
   if (database_) {
-    database_->Write(std::move(save_operations),
-                     base::BindOnce(&SessionStorageContextMojo::OnCommitResult,
-                                    weak_ptr_factory_.GetWeakPtr()));
+    database_->RunBatchDatabaseTasks(
+        std::move(save_tasks),
+        base::BindOnce(&SessionStorageContextMojo::OnCommitResult,
+                       weak_ptr_factory_.GetWeakPtr()));
   }
 
   if (found) {
@@ -669,12 +671,13 @@
 void SessionStorageContextMojo::DoDatabaseDelete(
     const std::string& namespace_id) {
   DCHECK_EQ(connection_state_, CONNECTION_FINISHED);
-  std::vector<leveldb::mojom::BatchedOperationPtr> delete_operations;
-  metadata_.DeleteNamespace(namespace_id, &delete_operations);
+  std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask> tasks;
+  metadata_.DeleteNamespace(namespace_id, &tasks);
   if (database_) {
-    database_->Write(std::move(delete_operations),
-                     base::BindOnce(&SessionStorageContextMojo::OnCommitResult,
-                                    weak_ptr_factory_.GetWeakPtr()));
+    database_->RunBatchDatabaseTasks(
+        std::move(tasks),
+        base::BindOnce(&SessionStorageContextMojo::OnCommitResult,
+                       weak_ptr_factory_.GetWeakPtr()));
   }
 }
 
@@ -811,10 +814,10 @@
     ValueAndStatus version,
     KeyValuePairsAndStatus namespaces,
     ValueAndStatus next_map_id) {
-  std::vector<leveldb::mojom::BatchedOperationPtr> migration_operations;
+  std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask> migration_tasks;
 
   MetadataParseResult version_parse =
-      ParseDatabaseVersion(std::move(version), &migration_operations);
+      ParseDatabaseVersion(std::move(version), &migration_tasks);
   if (version_parse.open_result != OpenResult::kSuccess) {
     LogDatabaseOpenResult(version_parse.open_result);
     DeleteAndRecreateDatabase(version_parse.histogram_name);
@@ -822,7 +825,7 @@
   }
 
   MetadataParseResult namespaces_parse =
-      ParseNamespaces(std::move(namespaces), std::move(migration_operations));
+      ParseNamespaces(std::move(namespaces), std::move(migration_tasks));
   if (namespaces_parse.open_result != OpenResult::kSuccess) {
     LogDatabaseOpenResult(namespaces_parse.open_result);
     DeleteAndRecreateDatabase(namespaces_parse.histogram_name);
@@ -843,10 +846,11 @@
 SessionStorageContextMojo::MetadataParseResult
 SessionStorageContextMojo::ParseDatabaseVersion(
     ValueAndStatus version,
-    std::vector<leveldb::mojom::BatchedOperationPtr>* migration_operations) {
+    std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask>*
+        migration_tasks) {
   if (version.status.ok()) {
     if (!metadata_.ParseDatabaseVersion(std::move(version.value),
-                                        migration_operations)) {
+                                        migration_tasks)) {
       return {OpenResult::kInvalidVersion,
               "SessionStorageContext.OpenResultAfterInvalidVersion"};
     }
@@ -856,7 +860,7 @@
 
   if (version.status.IsNotFound()) {
     // treat as v0 or new database
-    metadata_.ParseDatabaseVersion(base::nullopt, migration_operations);
+    metadata_.ParseDatabaseVersion(base::nullopt, migration_tasks);
     return {OpenResult::kSuccess, ""};
   }
 
@@ -872,7 +876,8 @@
 SessionStorageContextMojo::MetadataParseResult
 SessionStorageContextMojo::ParseNamespaces(
     KeyValuePairsAndStatus namespaces,
-    std::vector<leveldb::mojom::BatchedOperationPtr> migration_operations) {
+    std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask>
+        migration_tasks) {
   DCHECK_EQ(connection_state_, CONNECTION_IN_PROGRESS);
 
   if (!namespaces.status.ok()) {
@@ -885,7 +890,7 @@
   }
 
   bool parsing_success = metadata_.ParseNamespaces(
-      std::move(namespaces.key_value_pairs), &migration_operations);
+      std::move(namespaces.key_value_pairs), &migration_tasks);
 
   if (!parsing_success) {
     UMA_HISTOGRAM_ENUMERATION(
@@ -896,13 +901,13 @@
             "SessionStorageContext.OpenResultAfterReadNamespacesError"};
   }
 
-  if (!migration_operations.empty()) {
+  if (!migration_tasks.empty()) {
     // In tests this write may happen synchronously, which is problematic since
     // the OnCommitResult callback can be invoked before the database is fully
     // initialized. There's no harm in deferring in other situations, so we just
     // always defer here.
-    database_->Write(
-        std::move(migration_operations),
+    database_->RunBatchDatabaseTasks(
+        std::move(migration_tasks),
         base::BindOnce(
             [](base::OnceCallback<void(leveldb::Status)> callback,
                scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
diff --git a/content/browser/dom_storage/session_storage_context_mojo.h b/content/browser/dom_storage/session_storage_context_mojo.h
index 6613b02..0d12606 100644
--- a/content/browser/dom_storage/session_storage_context_mojo.h
+++ b/content/browser/dom_storage/session_storage_context_mojo.h
@@ -234,10 +234,12 @@
   };
   MetadataParseResult ParseDatabaseVersion(
       ValueAndStatus version,
-      std::vector<leveldb::mojom::BatchedOperationPtr>* migration_operations);
+      std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask>*
+          migration_tasks);
   MetadataParseResult ParseNamespaces(
       KeyValuePairsAndStatus namespaces,
-      std::vector<leveldb::mojom::BatchedOperationPtr> migration_operations);
+      std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask>
+          migration_tasks);
   MetadataParseResult ParseNextMapId(ValueAndStatus next_map_id);
 
   void OnConnectionFinished();
diff --git a/content/browser/dom_storage/session_storage_metadata.cc b/content/browser/dom_storage/session_storage_metadata.cc
index 89e75800..f615399 100644
--- a/content/browser/dom_storage/session_storage_metadata.cc
+++ b/content/browser/dom_storage/session_storage_metadata.cc
@@ -8,15 +8,14 @@
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
+#include "components/services/leveldb/leveldb_database_impl.h"
 #include "components/services/leveldb/public/cpp/util.h"
 #include "third_party/blink/public/common/dom_storage/session_storage_namespace_id.h"
 #include "url/gurl.h"
 
 namespace content {
+
 namespace {
-using leveldb::mojom::BatchedOperation;
-using leveldb::mojom::BatchOperationType;
-using leveldb::mojom::BatchedOperationPtr;
 
 // Example layout of the database:
 // | key                                    | value              |
@@ -54,6 +53,7 @@
 std::vector<uint8_t> NumberToValue(int64_t map_number) {
   return leveldb::StdStringToUint8Vector(base::NumberToString(map_number));
 }
+
 }  // namespace
 
 constexpr const int64_t SessionStorageMetadata::kMinSessionStorageSchemaVersion;
@@ -75,30 +75,30 @@
 
 SessionStorageMetadata::~SessionStorageMetadata() {}
 
-std::vector<leveldb::mojom::BatchedOperationPtr>
+std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask>
 SessionStorageMetadata::SetupNewDatabase() {
   next_map_id_ = 0;
   next_map_id_from_namespaces_ = 0;
   namespace_origin_map_.clear();
 
-  std::vector<leveldb::mojom::BatchedOperationPtr> operations;
-  operations.reserve(2);
-  operations.push_back(BatchedOperation::New(
-      BatchOperationType::PUT_KEY,
-      std::vector<uint8_t>(std::begin(kDatabaseVersionBytes),
-                           std::end(kDatabaseVersionBytes)),
-      LatestDatabaseVersionAsVector()));
-  operations.push_back(
-      BatchedOperation::New(BatchOperationType::PUT_KEY,
-                            std::vector<uint8_t>(std::begin(kNextMapIdKeyBytes),
-                                                 std::end(kNextMapIdKeyBytes)),
-                            NumberToValue(next_map_id_)));
-  return operations;
+  std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask> tasks;
+  tasks.push_back(base::BindOnce(
+      [](int64_t next_map_id, leveldb::WriteBatch* batch,
+         const storage::DomStorageDatabase& db) {
+        batch->Put(
+            leveldb_env::MakeSlice(base::make_span(kDatabaseVersionBytes)),
+            leveldb_env::MakeSlice(LatestDatabaseVersionAsVector()));
+        batch->Put(leveldb_env::MakeSlice(base::make_span(kNextMapIdKeyBytes)),
+                   leveldb_env::MakeSlice(NumberToValue(next_map_id)));
+      },
+      next_map_id_));
+  return tasks;
 }
 
 bool SessionStorageMetadata::ParseDatabaseVersion(
     base::Optional<std::vector<uint8_t>> value,
-    std::vector<leveldb::mojom::BatchedOperationPtr>* upgrade_operations) {
+    std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask>*
+        upgrade_tasks) {
   if (!value) {
     initial_database_version_from_disk_ = 0;
   } else {
@@ -112,17 +112,19 @@
   }
   if (initial_database_version_from_disk_ < kMinSessionStorageSchemaVersion)
     return false;
-  upgrade_operations->push_back(BatchedOperation::New(
-      BatchOperationType::PUT_KEY,
-      std::vector<uint8_t>(std::begin(kDatabaseVersionBytes),
-                           std::end(kDatabaseVersionBytes)),
-      LatestDatabaseVersionAsVector()));
+  upgrade_tasks->push_back(base::BindOnce(
+      [](leveldb::WriteBatch* batch, const storage::DomStorageDatabase& db) {
+        batch->Put(
+            leveldb_env::MakeSlice(base::make_span(kDatabaseVersionBytes)),
+            leveldb_env::MakeSlice(LatestDatabaseVersionAsVector()));
+      }));
   return true;
 }
 
 bool SessionStorageMetadata::ParseNamespaces(
     std::vector<storage::DomStorageDatabase::KeyValuePair> values,
-    std::vector<leveldb::mojom::BatchedOperationPtr>* upgrade_operations) {
+    std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask>*
+        upgrade_tasks) {
   namespace_origin_map_.clear();
   next_map_id_from_namespaces_ = 0;
   // Since the data is ordered, all namespace data is in one spot. This keeps a
@@ -223,18 +225,20 @@
   // Namespace metadata migration.
   DCHECK_NE(kInvalidDatabaseVersion, initial_database_version_from_disk_);
   if (initial_database_version_from_disk_ == 0) {
+    std::vector<storage::DomStorageDatabase::Key> prefix_keys_to_delete;
+    for (const auto& entry : maps)
+      prefix_keys_to_delete.push_back(entry.second->KeyPrefix());
     // Remove the dummy 'namespaces-' entry.
-    upgrade_operations->push_back(BatchedOperation::New(
-        BatchOperationType::DELETE_KEY,
-        std::vector<uint8_t>(std::begin(kNamespacePrefixBytes),
-                             std::end(kNamespacePrefixBytes)),
-        base::nullopt));
-    // Remove all the refcount storage.
-    for (const auto& map_pair : maps) {
-      upgrade_operations->push_back(
-          BatchedOperation::New(BatchOperationType::DELETE_KEY,
-                                map_pair.second->KeyPrefix(), base::nullopt));
-    }
+    upgrade_tasks->push_back(base::BindOnce(
+        [](std::vector<storage::DomStorageDatabase::Key> prefix_keys_to_delete,
+           leveldb::WriteBatch* batch, const storage::DomStorageDatabase& db) {
+          batch->Delete(
+              leveldb_env::MakeSlice(base::make_span(kNamespacePrefixBytes)));
+          // Remove all the refcount storage.
+          for (const auto& key : prefix_keys_to_delete)
+            batch->Delete(leveldb_env::MakeSlice(key));
+        },
+        std::move(prefix_keys_to_delete)));
   }
 
   return true;
@@ -257,17 +261,10 @@
 SessionStorageMetadata::RegisterNewMap(
     NamespaceEntry namespace_entry,
     const url::Origin& origin,
-    std::vector<leveldb::mojom::BatchedOperationPtr>* save_operations) {
+    std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask>* save_tasks) {
   auto new_map_data = base::MakeRefCounted<MapData>(next_map_id_, origin);
   ++next_map_id_;
 
-  save_operations->push_back(BatchedOperation::New(
-      BatchOperationType::PUT_KEY,
-      std::vector<uint8_t>(
-          SessionStorageMetadata::kNextMapIdKeyBytes,
-          std::end(SessionStorageMetadata::kNextMapIdKeyBytes)),
-      NumberToValue(next_map_id_)));
-
   std::map<url::Origin, scoped_refptr<MapData>>& namespace_origins =
       namespace_entry->second;
   auto namespace_it = namespace_origins.find(origin);
@@ -286,8 +283,16 @@
   }
   new_map_data->IncReferenceCount();
 
-  save_operations->push_back(BatchedOperation::New(
-      BatchOperationType::PUT_KEY, GetAreaKey(namespace_entry->first, origin),
+  save_tasks->push_back(base::BindOnce(
+      [](int64_t new_map_id, storage::DomStorageDatabase::Key origin_key,
+         storage::DomStorageDatabase::Value origin_map_number,
+         leveldb::WriteBatch* batch, const storage::DomStorageDatabase& db) {
+        batch->Put(leveldb_env::MakeSlice(base::make_span(kNextMapIdKeyBytes)),
+                   leveldb_env::MakeSlice(NumberToValue(new_map_id)));
+        batch->Put(leveldb_env::MakeSlice(origin_key),
+                   leveldb_env::MakeSlice(origin_map_number));
+      },
+      next_map_id_, GetAreaKey(namespace_entry->first, origin),
       new_map_data->MapNumberAsBytes()));
 
   return new_map_data;
@@ -296,8 +301,8 @@
 void SessionStorageMetadata::RegisterShallowClonedNamespace(
     NamespaceEntry source_namespace,
     NamespaceEntry destination_namespace,
-    std::vector<leveldb::mojom::BatchedOperationPtr>* save_operations) {
-  DCHECK(save_operations);
+    std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask>* save_tasks) {
+  DCHECK(save_tasks);
   std::map<url::Origin, scoped_refptr<MapData>>& source_origins =
       source_namespace->second;
   std::map<url::Origin, scoped_refptr<MapData>>& destination_origins =
@@ -305,50 +310,61 @@
   DCHECK_EQ(0ul, destination_origins.size())
       << "The destination already has data.";
 
-  save_operations->reserve(save_operations->size() + source_origins.size());
+  std::vector<storage::DomStorageDatabase::KeyValuePair> new_entries;
   for (const auto& origin_map_pair : source_origins) {
     destination_origins.emplace(std::piecewise_construct,
                                 std::forward_as_tuple(origin_map_pair.first),
                                 std::forward_as_tuple(origin_map_pair.second));
     origin_map_pair.second->IncReferenceCount();
-
-    save_operations->push_back(BatchedOperation::New(
-        BatchOperationType::PUT_KEY,
+    new_entries.emplace_back(
         GetAreaKey(destination_namespace->first, origin_map_pair.first),
-        origin_map_pair.second->MapNumberAsBytes()));
+        origin_map_pair.second->MapNumberAsBytes());
   }
+
+  save_tasks->push_back(base::BindOnce(
+      [](std::vector<storage::DomStorageDatabase::KeyValuePair> new_entries,
+         leveldb::WriteBatch* batch, const storage::DomStorageDatabase&) {
+        for (const auto& entry : new_entries)
+          batch->Put(leveldb_env::MakeSlice(entry.key),
+                     leveldb_env::MakeSlice(entry.value));
+      },
+      std::move(new_entries)));
 }
 
 void SessionStorageMetadata::DeleteNamespace(
     const std::string& namespace_id,
-    std::vector<BatchedOperationPtr>* delete_operations) {
+    std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask>* save_tasks) {
+  std::vector<storage::DomStorageDatabase::Key> prefixes_to_delete;
   auto it = namespace_origin_map_.find(namespace_id);
   if (it == namespace_origin_map_.end())
     return;
 
-  delete_operations->push_back(
-      BatchedOperation::New(BatchOperationType::DELETE_PREFIXED_KEY,
-                            GetNamespacePrefix(namespace_id), base::nullopt));
+  prefixes_to_delete.push_back(GetNamespacePrefix(namespace_id));
 
   const std::map<url::Origin, scoped_refptr<MapData>>& origins = it->second;
   for (const auto& origin_map_pair : origins) {
     MapData* map_data = origin_map_pair.second.get();
     DCHECK_GT(map_data->ReferenceCount(), 0);
     map_data->DecReferenceCount();
-    if (map_data->ReferenceCount() == 0) {
-      delete_operations->push_back(
-          BatchedOperation::New(BatchOperationType::DELETE_PREFIXED_KEY,
-                                map_data->KeyPrefix(), base::nullopt));
-    }
+    if (map_data->ReferenceCount() == 0)
+      prefixes_to_delete.push_back(map_data->KeyPrefix());
   }
 
   namespace_origin_map_.erase(it);
+
+  save_tasks->push_back(base::BindOnce(
+      [](std::vector<storage::DomStorageDatabase::Key> prefixes_to_delete,
+         leveldb::WriteBatch* batch, const storage::DomStorageDatabase& db) {
+        for (const auto& prefix : prefixes_to_delete)
+          db.DeletePrefixed(prefix, batch);
+      },
+      std::move(prefixes_to_delete)));
 }
 
 void SessionStorageMetadata::DeleteArea(
     const std::string& namespace_id,
     const url::Origin& origin,
-    std::vector<BatchedOperationPtr>* delete_operations) {
+    std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask>* save_tasks) {
   auto ns_entry = namespace_origin_map_.find(namespace_id);
   if (ns_entry == namespace_origin_map_.end())
     return;
@@ -359,18 +375,24 @@
 
   MapData* map_data = origin_map_it->second.get();
 
-  delete_operations->push_back(
-      BatchedOperation::New(BatchOperationType::DELETE_KEY,
-                            GetAreaKey(namespace_id, origin), base::nullopt));
-
+  storage::DomStorageDatabase::Key area_key = GetAreaKey(namespace_id, origin);
+  std::vector<storage::DomStorageDatabase::Key> prefixes_to_delete;
   DCHECK_GT(map_data->ReferenceCount(), 0);
   map_data->DecReferenceCount();
-  if (map_data->ReferenceCount() == 0) {
-    delete_operations->push_back(
-        BatchedOperation::New(BatchOperationType::DELETE_PREFIXED_KEY,
-                              map_data->KeyPrefix(), base::nullopt));
-  }
+  if (map_data->ReferenceCount() == 0)
+    prefixes_to_delete.push_back(map_data->KeyPrefix());
+
   ns_entry->second.erase(origin_map_it);
+
+  save_tasks->push_back(base::BindOnce(
+      [](const storage::DomStorageDatabase::Key& area_key,
+         std::vector<storage::DomStorageDatabase::Key> prefixes_to_delete,
+         leveldb::WriteBatch* batch, const storage::DomStorageDatabase& db) {
+        batch->Delete(leveldb_env::MakeSlice(area_key));
+        for (const auto& prefix : prefixes_to_delete)
+          db.DeletePrefixed(prefix, batch);
+      },
+      area_key, std::move(prefixes_to_delete)));
 }
 
 SessionStorageMetadata::NamespaceEntry
diff --git a/content/browser/dom_storage/session_storage_metadata.h b/content/browser/dom_storage/session_storage_metadata.h
index 326edadd..5aac60bd 100644
--- a/content/browser/dom_storage/session_storage_metadata.h
+++ b/content/browser/dom_storage/session_storage_metadata.h
@@ -10,7 +10,7 @@
 #include <vector>
 
 #include "base/memory/ref_counted.h"
-#include "components/services/leveldb/public/mojom/leveldb.mojom.h"
+#include "components/services/leveldb/leveldb_database_impl.h"
 #include "components/services/storage/dom_storage/dom_storage_database.h"
 #include "content/common/content_export.h"
 #include "url/origin.h"
@@ -86,29 +86,33 @@
   ~SessionStorageMetadata();
 
   // For a new database, this saves the database version, clears the metadata,
-  // and returns the operations to save to disk.
-  std::vector<leveldb::mojom::BatchedOperationPtr> SetupNewDatabase();
+  // and returns the operations needed to save to disk.
+  std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask>
+  SetupNewDatabase();
 
   // This parses the database version from the bytes that were stored on
   // disk, or if there was no version saved then passes a base::nullopt. This
-  // call is not necessary on new databases. The |upgrade_operations| are
-  // populated with any operations needed to upgrade the databases versioning
-  // metadata. Note this is different than the namespaces metadata, which will
-  // be upgraded in ParseNamespaces.
-  // Returns if the parsing is correct and we support the version read.
+  // call is not necessary on new databases. The |upgrade_tasks| are populated
+  // with any tasks needed to upgrade the databases versioning metadata. Note
+  // this is different than the namespaces metadata, which will be upgraded in
+  // ParseNamespaces.
+  //
+  // Returns |true| if the parsing is correct and we support the version read.
   bool ParseDatabaseVersion(
       base::Optional<std::vector<uint8_t>> value,
-      std::vector<leveldb::mojom::BatchedOperationPtr>* upgrade_operations);
+      std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask>*
+          upgrade_tasks);
 
   // Parses all namespaces and maps, and stores all metadata locally. This
   // invalidates all NamespaceEntry and MapData objects. If there is a parsing
   // error, the namespaces will be cleared.If the version given to
   // |ParseDatabaseVersion| is an older version, any namespace metadata upgrades
-  // will be populated in |upgrade_operations|. This call is not necessary on
-  // new databases.
+  // will be populated in |upgrade_tasks|. This call is not necessary on new
+  // databases.
   bool ParseNamespaces(
       std::vector<storage::DomStorageDatabase::KeyValuePair> values,
-      std::vector<leveldb::mojom::BatchedOperationPtr>* upgrade_operations);
+      std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask>*
+          upgrade_tasks);
 
   // Parses the next map id from the given bytes. If that fails, then it uses
   // the next available id from parsing the namespaces. This call is not
@@ -116,41 +120,44 @@
   void ParseNextMapId(const std::vector<uint8_t>& map_id);
 
   // Creates new map data for the given namespace-origin area. If the area
-  // entry exists, then it will decrement the refcount of the old map. The
-  // |save_operations| save the new or modified area entry, as well as saving
-  // the next available map id.
-  // Note: It is invalid to call this method for an area that has a map with
+  // entry exists, then it will decrement the refcount of the old map. Tasks
+  // appended to |*save_tasks| if run will save the new or modified area entry
+  // to disk, as well as saving the next available map id.
+  //
+  // NOTE: It is invalid to call this method for an area that has a map with
   // only one reference.
   scoped_refptr<MapData> RegisterNewMap(
       NamespaceEntry namespace_entry,
       const url::Origin& origin,
-      std::vector<leveldb::mojom::BatchedOperationPtr>* save_operations);
+      std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask>* save_tasks);
 
   // Registers an origin-map in the |destination_namespace| from every
   // origin-map in the |source_namespace|. The |destination_namespace| must have
   // no origin-maps. All maps in the destination namespace are the same maps as
   // the source namespace. All database operations to save the namespace origin
-  // metadata are put in |save_operations|.
+  // metadata are put in |save_tasks|.
   void RegisterShallowClonedNamespace(
       NamespaceEntry source_namespace,
       NamespaceEntry destination_namespace,
-      std::vector<leveldb::mojom::BatchedOperationPtr>* save_operations);
+      std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask>* save_tasks);
 
-  // Deletes the given namespace any any maps that no longer have any
+  // Deletes the given namespace and any maps that no longer have any
   // references. This will invalidate all NamespaceEntry objects for the
   // |namespace_id|, and can invalidate any MapData objects whose reference
-  // count hits zero.
+  // count hits zero. Appends operations to |*save_tasks| which will commit the
+  // deletions to disk if run.
   void DeleteNamespace(
       const std::string& namespace_id,
-      std::vector<leveldb::mojom::BatchedOperationPtr>* delete_operations);
+      std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask>* save_tasks);
 
-  // This removes the metadata entry for this namespace-origin area. If the map
-  // at this entry isn't reference by any other area (refcount hits 0), then
-  // this will delete that map on disk and invalidate that MapData.
+  // This returns a BatchDatabaseTask to remove the metadata entry for this
+  // namespace-origin area. If the map at this entry isn't referenced by any
+  // other area (refcount hits 0), then the task will also delete that map on
+  // disk and invalidate that MapData.
   void DeleteArea(
       const std::string& namespace_id,
       const url::Origin& origin,
-      std::vector<leveldb::mojom::BatchedOperationPtr>* delete_operations);
+      std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask>* save_tasks);
 
   NamespaceEntry GetOrCreateNamespaceEntry(const std::string& namespace_id);
 
diff --git a/content/browser/dom_storage/session_storage_metadata_unittest.cc b/content/browser/dom_storage/session_storage_metadata_unittest.cc
index 2532993..36713c6 100644
--- a/content/browser/dom_storage/session_storage_metadata_unittest.cc
+++ b/content/browser/dom_storage/session_storage_metadata_unittest.cc
@@ -84,16 +84,17 @@
         }));
     loop.Run();
 
-    std::vector<leveldb::mojom::BatchedOperationPtr> migration_operations;
+    std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask>
+        migration_tasks;
     EXPECT_TRUE(
-        metadata->ParseDatabaseVersion(version_value, &migration_operations));
-    EXPECT_TRUE(migration_operations.empty());
+        metadata->ParseDatabaseVersion(version_value, &migration_tasks));
+    EXPECT_TRUE(migration_tasks.empty());
 
     metadata->ParseNextMapId(next_map_id_value);
 
     EXPECT_TRUE(metadata->ParseNamespaces(std::move(namespace_entries),
-                                          &migration_operations));
-    EXPECT_TRUE(migration_operations.empty());
+                                          &migration_tasks));
+    EXPECT_TRUE(migration_tasks.empty());
   }
 
   void SetupTestData() {
@@ -162,14 +163,16 @@
     return contents;
   }
 
-  void WriteBatch(std::vector<leveldb::mojom::BatchedOperationPtr> operations,
-                  base::OnceCallback<void(leveldb::Status)> callback) {
+  void RunBatch(
+      std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask> tasks,
+      base::OnceCallback<void(leveldb::Status)> callback) {
     base::RunLoop loop;
-    database_->Write(std::move(operations),
-                     base::BindLambdaForTesting([&](leveldb::Status status) {
-                       std::move(callback).Run(status);
-                       loop.Quit();
-                     }));
+    database_->RunBatchDatabaseTasks(
+        std::move(tasks),
+        base::BindLambdaForTesting([&](leveldb::Status status) {
+          std::move(callback).Run(status);
+          loop.Quit();
+        }));
     loop.Run();
   }
 
@@ -189,11 +192,11 @@
 
 TEST_F(SessionStorageMetadataTest, SaveNewMetadata) {
   SessionStorageMetadata metadata;
-  std::vector<leveldb::mojom::BatchedOperationPtr> operations =
+  std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask> tasks =
       metadata.SetupNewDatabase();
 
   leveldb::Status status;
-  WriteBatch(std::move(operations), base::BindOnce(&ErrorCallback, &status));
+  RunBatch(std::move(tasks), base::BindOnce(&ErrorCallback, &status));
   EXPECT_TRUE(status.ok());
 
   auto contents = GetDatabaseContents();
@@ -238,10 +241,9 @@
   SessionStorageMetadata metadata;
   ReadMetadataFromDatabase(&metadata);
 
-  std::vector<leveldb::mojom::BatchedOperationPtr> operations;
+  std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask> tasks;
   auto ns1_entry = metadata.GetOrCreateNamespaceEntry(test_namespace1_id_);
-  auto map_data =
-      metadata.RegisterNewMap(ns1_entry, test_origin1_, &operations);
+  auto map_data = metadata.RegisterNewMap(ns1_entry, test_origin1_, &tasks);
   ASSERT_TRUE(map_data);
 
   // Verify in-memory metadata is correct.
@@ -253,7 +255,7 @@
                    ->ReferenceCount());
 
   leveldb::Status status;
-  WriteBatch(std::move(operations), base::BindOnce(&ErrorCallback, &status));
+  RunBatch(std::move(tasks), base::BindOnce(&ErrorCallback, &status));
   EXPECT_TRUE(status.ok());
 
   // Verify metadata was written to disk.
@@ -273,12 +275,11 @@
   auto ns1_entry = metadata.GetOrCreateNamespaceEntry(test_namespace1_id_);
   auto ns3_entry = metadata.GetOrCreateNamespaceEntry(test_namespace3_id_);
 
-  std::vector<leveldb::mojom::BatchedOperationPtr> operations;
-  metadata.RegisterShallowClonedNamespace(ns1_entry, ns3_entry, &operations);
+  std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask> tasks;
+  metadata.RegisterShallowClonedNamespace(ns1_entry, ns3_entry, &tasks);
 
   leveldb::Status status;
-  ;
-  WriteBatch(std::move(operations), base::BindOnce(&ErrorCallback, &status));
+  RunBatch(std::move(tasks), base::BindOnce(&ErrorCallback, &status));
   EXPECT_TRUE(status.ok());
 
   // Verify in-memory metadata is correct.
@@ -310,10 +311,10 @@
   SessionStorageMetadata metadata;
   ReadMetadataFromDatabase(&metadata);
 
-  std::vector<leveldb::mojom::BatchedOperationPtr> operations;
-  metadata.DeleteNamespace(test_namespace1_id_, &operations);
+  std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask> tasks;
+  metadata.DeleteNamespace(test_namespace1_id_, &tasks);
   leveldb::Status status;
-  WriteBatch(std::move(operations), base::BindOnce(&ErrorCallback, &status));
+  RunBatch(std::move(tasks), base::BindOnce(&ErrorCallback, &status));
   EXPECT_TRUE(status.ok());
 
   EXPECT_FALSE(
@@ -344,10 +345,10 @@
   ReadMetadataFromDatabase(&metadata);
 
   // First delete an area with a shared map.
-  std::vector<leveldb::mojom::BatchedOperationPtr> operations;
-  metadata.DeleteArea(test_namespace1_id_, test_origin1_, &operations);
+  std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask> tasks;
+  metadata.DeleteArea(test_namespace1_id_, test_origin1_, &tasks);
   leveldb::Status status;
-  WriteBatch(std::move(operations), base::BindOnce(&ErrorCallback, &status));
+  RunBatch(std::move(tasks), base::BindOnce(&ErrorCallback, &status));
   EXPECT_TRUE(status.ok());
 
   // Verify in-memory metadata is correct.
@@ -372,9 +373,9 @@
   EXPECT_TRUE(base::Contains(contents, StdStringToUint8Vector("map-4-key1")));
 
   // Now delete an area with a unique map.
-  operations.clear();
-  metadata.DeleteArea(test_namespace2_id_, test_origin2_, &operations);
-  WriteBatch(std::move(operations), base::BindOnce(&ErrorCallback, &status));
+  tasks.clear();
+  metadata.DeleteArea(test_namespace2_id_, test_origin2_, &tasks);
+  RunBatch(std::move(tasks), base::BindOnce(&ErrorCallback, &status));
   EXPECT_TRUE(status.ok());
 
   // Verify in-memory metadata is correct.
@@ -448,6 +449,23 @@
   std::vector<uint8_t> namespaces_prefix_key_;
 };
 
+struct BatchCollector : public leveldb::WriteBatch::Handler {
+ public:
+  BatchCollector() = default;
+  ~BatchCollector() override = default;
+
+  void Put(const leveldb::Slice& key, const leveldb::Slice& value) override {
+    new_entries.emplace(key.ToString(), value.ToString());
+  }
+
+  void Delete(const leveldb::Slice& key) override {
+    deleted_keys.push_back(key.ToString());
+  }
+
+  std::map<std::string, std::string> new_entries;
+  std::vector<std::string> deleted_keys;
+};
+
 TEST_F(SessionStorageMetadataMigrationTest, MigrateV0ToV1) {
   base::string16 key = base::ASCIIToUTF16("key");
   base::string16 value = base::ASCIIToUTF16("value");
@@ -468,11 +486,10 @@
   std::string db_value;
   leveldb::Status s = db()->Get(options, leveldb::Slice("version"), &db_value);
   EXPECT_TRUE(s.IsNotFound());
-  std::vector<leveldb::mojom::BatchedOperationPtr> migration_operations;
-  EXPECT_TRUE(
-      metadata.ParseDatabaseVersion(base::nullopt, &migration_operations));
-  EXPECT_FALSE(migration_operations.empty());
-  EXPECT_EQ(1ul, migration_operations.size());
+  std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask> migration_tasks;
+  EXPECT_TRUE(metadata.ParseDatabaseVersion(base::nullopt, &migration_tasks));
+  EXPECT_FALSE(migration_tasks.empty());
+  EXPECT_EQ(1ul, migration_tasks.size());
 
   // Grab the next map id, verify it doesn't crash.
   s = db()->Get(options, leveldb::Slice("next-map-id"), &db_value);
@@ -493,26 +510,24 @@
     EXPECT_TRUE(it->status().ok());
   }
 
-  EXPECT_TRUE(
-      metadata.ParseNamespaces(std::move(values), &migration_operations));
-  EXPECT_FALSE(migration_operations.empty());
-  EXPECT_EQ(3ul, migration_operations.size());
+  EXPECT_TRUE(metadata.ParseNamespaces(std::move(values), &migration_tasks));
+  EXPECT_EQ(2ul, migration_tasks.size());
 
-  EXPECT_TRUE(base::Contains(
-      migration_operations,
-      leveldb::mojom::BatchedOperation::New(
-          leveldb::mojom::BatchOperationType::PUT_KEY,
-          StdStringToUint8Vector("version"), StdStringToUint8Vector("1"))));
-  EXPECT_TRUE(
-      base::Contains(migration_operations,
-                     leveldb::mojom::BatchedOperation::New(
-                         leveldb::mojom::BatchOperationType::DELETE_KEY,
-                         StdStringToUint8Vector("map-0-"), base::nullopt)));
-  EXPECT_TRUE(
-      base::Contains(migration_operations,
-                     leveldb::mojom::BatchedOperation::New(
-                         leveldb::mojom::BatchOperationType::DELETE_KEY,
-                         StdStringToUint8Vector("namespace-"), base::nullopt)));
+  leveldb::WriteBatch batch;
+  storage::DomStorageDatabase* null_db = nullptr;
+
+  // Run the tasks on our local batch object. Note that these migration tasks
+  // only manipulate |batch|, so it's safe enough to pass them a reference to a
+  // null database.
+  for (auto& task : migration_tasks)
+    std::move(task).Run(&batch, *null_db);
+
+  BatchCollector collector;
+  batch.Iterate(&collector);
+  EXPECT_EQ(1u, collector.new_entries.size());
+  EXPECT_EQ("1", collector.new_entries["version"]);
+  EXPECT_THAT(collector.deleted_keys,
+              testing::ElementsAre("namespace-", "map-0-"));
 }
 
 }  // namespace
diff --git a/content/browser/dom_storage/session_storage_namespace_impl_mojo_unittest.cc b/content/browser/dom_storage/session_storage_namespace_impl_mojo_unittest.cc
index 48af5b0..a42987a 100644
--- a/content/browser/dom_storage/session_storage_namespace_impl_mojo_unittest.cc
+++ b/content/browser/dom_storage/session_storage_namespace_impl_mojo_unittest.cc
@@ -68,10 +68,11 @@
         test_origin3_(url::Origin::Create(GURL("https://host3.com/"))) {}
   ~SessionStorageNamespaceImplMojoTest() override = default;
 
-  void WriteBatch(std::vector<leveldb::mojom::BatchedOperationPtr> operations) {
+  void RunBatch(
+      std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask> tasks) {
     base::RunLoop loop(base::RunLoop::Type::kNestableTasksAllowed);
-    database_->Write(
-        std::move(operations),
+    database_->RunBatchDatabaseTasks(
+        std::move(tasks),
         base::BindLambdaForTesting([&](leveldb::Status) { loop.Quit(); }));
     loop.Run();
   }
@@ -86,12 +87,11 @@
     loop.Run();
 
     metadata_.SetupNewDatabase();
-    std::vector<leveldb::mojom::BatchedOperationPtr> save_operations;
+    std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask> save_tasks;
     auto entry = metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_);
-    auto map_id =
-        metadata_.RegisterNewMap(entry, test_origin1_, &save_operations);
+    auto map_id = metadata_.RegisterNewMap(entry, test_origin1_, &save_tasks);
     DCHECK(map_id->KeyPrefix() == StdStringToUint8Vector("map-0-"));
-    WriteBatch(std::move(save_operations));
+    RunBatch(std::move(save_tasks));
 
     // Put some data in one of the maps.
     base::RunLoop put_loop;
@@ -156,10 +156,10 @@
   scoped_refptr<SessionStorageMetadata::MapData> RegisterNewAreaMap(
       NamespaceEntry namespace_entry,
       const url::Origin& origin) {
-    std::vector<leveldb::mojom::BatchedOperationPtr> save_operations;
+    std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask> save_tasks;
     auto map_data =
-        metadata_.RegisterNewMap(namespace_entry, origin, &save_operations);
-    WriteBatch(std::move(save_operations));
+        metadata_.RegisterNewMap(namespace_entry, origin, &save_tasks);
+    RunBatch(std::move(save_tasks));
     return map_data;
   }
 
@@ -168,12 +168,12 @@
       const std::string& destination_namespace,
       const SessionStorageNamespaceImplMojo::OriginAreas& areas_to_clone)
       override {
-    std::vector<leveldb::mojom::BatchedOperationPtr> save_operations;
+    std::vector<leveldb::LevelDBDatabaseImpl::BatchDatabaseTask> save_tasks;
     auto namespace_entry =
         metadata_.GetOrCreateNamespaceEntry(destination_namespace);
     metadata_.RegisterShallowClonedNamespace(source_namespace, namespace_entry,
-                                             &save_operations);
-    WriteBatch(std::move(save_operations));
+                                             &save_tasks);
+    RunBatch(std::move(save_tasks));
 
     auto it = namespaces_.find(destination_namespace);
     if (it == namespaces_.end()) {
diff --git a/content/browser/dom_storage/storage_area_impl.h b/content/browser/dom_storage/storage_area_impl.h
index 5b5b3a1..16b6d47 100644
--- a/content/browser/dom_storage/storage_area_impl.h
+++ b/content/browser/dom_storage/storage_area_impl.h
@@ -15,7 +15,6 @@
 #include "base/macros.h"
 #include "base/optional.h"
 #include "base/time/time.h"
-#include "components/services/leveldb/public/mojom/leveldb.mojom.h"
 #include "components/services/storage/dom_storage/dom_storage_database.h"
 #include "content/common/content_export.h"
 #include "mojo/public/cpp/bindings/pending_associated_remote.h"
diff --git a/content/browser/dom_storage/storage_area_impl_unittest.cc b/content/browser/dom_storage/storage_area_impl_unittest.cc
index 1d7cf8c7..6a29429 100644
--- a/content/browser/dom_storage/storage_area_impl_unittest.cc
+++ b/content/browser/dom_storage/storage_area_impl_unittest.cc
@@ -18,7 +18,6 @@
 #include "base/threading/thread.h"
 #include "components/services/leveldb/leveldb_database_impl.h"
 #include "components/services/leveldb/public/cpp/util.h"
-#include "components/services/leveldb/public/mojom/leveldb.mojom.h"
 #include "components/services/storage/dom_storage/dom_storage_database.h"
 #include "content/browser/dom_storage/test/storage_area_test_util.h"
 #include "content/public/test/browser_task_environment.h"
diff --git a/content/browser/dom_storage/test/storage_area_test_util.h b/content/browser/dom_storage/test/storage_area_test_util.h
index af76250..e6446c4 100644
--- a/content/browser/dom_storage/test/storage_area_test_util.h
+++ b/content/browser/dom_storage/test/storage_area_test_util.h
@@ -9,7 +9,6 @@
 
 #include "base/callback.h"
 #include "base/optional.h"
-#include "components/services/leveldb/public/mojom/leveldb.mojom.h"
 #include "mojo/public/cpp/bindings/associated_receiver.h"
 #include "mojo/public/cpp/bindings/pending_associated_remote.h"
 #include "mojo/public/cpp/bindings/remote.h"
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index 7665f43d..8f409051 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -144,8 +144,8 @@
   // of ProactivelySwapBrowsingInstance experiment doesn't include them. The
   // cost of getting a new process on same-site navigation would (probably?) be
   // too high.
-  if (SiteInstanceImpl::IsSameWebSite(current_instance->GetIsolationContext(),
-                                      current_url, dest_url, true)) {
+  if (SiteInstanceImpl::IsSameSite(current_instance->GetIsolationContext(),
+                                   current_url, dest_url, true)) {
     return false;
   }
 
@@ -1088,13 +1088,6 @@
   proxy_hosts_.erase(site_instance->GetId());
 }
 
-bool RenderFrameHostManager::ShouldTransitionCrossSite() {
-  // False in single-process mode, which does not support cross-process
-  // navigations or OOPIFs.
-  return !base::CommandLine::ForCurrentProcess()->HasSwitch(
-      switches::kSingleProcess);
-}
-
 bool RenderFrameHostManager::ShouldSwapBrowsingInstancesForNavigation(
     const GURL& current_effective_url,
     bool current_is_view_source_mode,
@@ -1103,15 +1096,13 @@
     bool new_is_view_source_mode,
     bool is_failure) const {
   // A subframe must stay in the same BrowsingInstance as its parent.
-  // TODO(nasko): Ensure that SiteInstance swap is still triggered for subframes
-  // in the cases covered by the rest of the checks in this method.
   if (!frame_tree_node_->IsMainFrame())
     return false;
 
   // If the navigation has resulted in an error page, do not swap
   // BrowsingInstance and keep the error page in a related SiteInstance. If
-  // later a reload of this navigation is successful, it  will correctly
-  // create a new BrowsingInstance.
+  // later a reload of this navigation is successful, it will correctly
+  // create a new BrowsingInstance if needed.
   if (is_failure && SiteIsolationPolicy::IsErrorPageIsolationEnabled(
                         frame_tree_node_->IsMainFrame())) {
     return false;
@@ -1126,12 +1117,12 @@
 
   // Check for reasons to swap processes even if we are in a process model that
   // doesn't usually swap (e.g., process-per-tab).  Any time we return true,
-  // the new_entry will be rendered in a new SiteInstance AND BrowsingInstance.
+  // the new URL will be rendered in a new SiteInstance AND BrowsingInstance.
   BrowserContext* browser_context =
       delegate_->GetControllerForRenderManager().GetBrowserContext();
 
-  // Don't force a new BrowsingInstance for debug URLs that are handled in the
-  // renderer process, like javascript: or chrome://crash.
+  // Don't force a new BrowsingInstance for URLs that are handled in the
+  // renderer process, like javascript: or debug URLs like chrome://crash.
   if (IsRendererDebugURL(new_effective_url))
     return false;
 
@@ -1269,7 +1260,7 @@
   // RenderFrameHost was swapped in at the beginning of the navigation. See
   // https://crbug.com/766630.
   NavigationEntry* current_entry =
-      delegate_->GetLastCommittedNavigationEntryForRenderManager();
+      delegate_->GetControllerForRenderManager().GetLastCommittedEntry();
   bool current_is_view_source_mode = current_entry
                                          ? current_entry->IsViewSourceMode()
                                          : dest_is_view_source_mode;
@@ -1280,12 +1271,10 @@
       dest_is_view_source_mode, is_failure);
   SiteInstanceDescriptor new_instance_descriptor =
       SiteInstanceDescriptor(current_instance);
-  if (ShouldTransitionCrossSite() || force_swap) {
-    new_instance_descriptor = DetermineSiteInstanceForURL(
-        dest_url, source_instance, current_instance, dest_instance, transition,
-        is_failure, dest_is_restore, dest_is_view_source_mode, force_swap,
-        was_server_redirect);
-  }
+  new_instance_descriptor = DetermineSiteInstanceForURL(
+      dest_url, source_instance, current_instance, dest_instance, transition,
+      is_failure, dest_is_restore, dest_is_view_source_mode, force_swap,
+      was_server_redirect);
 
   scoped_refptr<SiteInstance> new_instance =
       ConvertToSiteInstance(new_instance_descriptor, candidate_instance);
@@ -1399,8 +1388,8 @@
       delegate_->GetControllerForRenderManager();
   BrowserContext* browser_context = controller.GetBrowserContext();
 
-  // If the entry has an instance already we should use it, unless it is no
-  // longer suitable.
+  // If the entry has an instance already we should usually use it, unless it is
+  // no longer suitable.
   if (dest_instance) {
     // When error page isolation is enabled, don't reuse |dest_instance| if it's
     // an error page SiteInstance, but the navigation will no longer fail.
@@ -1436,9 +1425,10 @@
 
   // If a swap is required, we need to force the SiteInstance AND
   // BrowsingInstance to be different ones, using CreateForURL.
-  if (force_browsing_instance_swap)
+  if (force_browsing_instance_swap) {
     return SiteInstanceDescriptor(browser_context, dest_url,
                                   SiteInstanceRelation::UNRELATED);
+  }
 
   // If error page navigations should be isolated, ensure a dedicated
   // SiteInstance is used for them.
@@ -1452,21 +1442,21 @@
                                   SiteInstanceRelation::RELATED);
   }
 
+  // TODO(https://crbug.com/566091): Don't create OOPIFs on the NTP.  Remove
+  // this when the NTP supports OOPIFs or is otherwise omitted from site
+  // isolation policy.
   if (!frame_tree_node_->IsMainFrame()) {
     SiteInstance* parent_site_instance =
         frame_tree_node_->parent()->current_frame_host()->GetSiteInstance();
-    // TEMPORARY HACK: Don't create OOPIFs on the NTP.  Remove this when the NTP
-    // supports OOPIFs or is otherwise omitted from site isolation policy.
-    // See https://crbug.com/566091.
     if (GetContentClient()->browser()->ShouldStayInParentProcessForNTP(
             dest_url, parent_site_instance)) {
       return SiteInstanceDescriptor(parent_site_instance);
     }
   }
 
-  // If we haven't used our SiteInstance (and thus RVH) yet, then we can use it
-  // for this entry.  We won't commit the SiteInstance to this site until the
-  // navigation commits (in DidNavigate), unless the navigation entry was
+  // If we haven't used our SiteInstance yet, then we can use it for this
+  // entry.  We won't commit the SiteInstance to this site until the response
+  // is received (in OnResponseStarted), unless the navigation entry was
   // restored or it's a Web UI as described below.
   if (!current_instance_impl->HasSite()) {
     // If we've already created a SiteInstance for our destination, we don't
@@ -1493,19 +1483,21 @@
 
     // For extensions, Web UI URLs (such as the new tab page), and apps we do
     // not want to use the |current_instance_impl| if it has no site, since it
-    // will have a RenderProcessHost of PRIV_NORMAL. Create a new SiteInstance
+    // will have a non-privileged RenderProcessHost. Create a new SiteInstance
     // for this URL instead (with the correct process type).
-    if (current_instance_impl->HasWrongProcessForURL(dest_url))
+    if (current_instance_impl->HasWrongProcessForURL(dest_url)) {
       return SiteInstanceDescriptor(browser_context, dest_url,
                                     SiteInstanceRelation::RELATED);
+    }
 
     // View-source URLs must use a new SiteInstance and BrowsingInstance.
     // TODO(nasko): This is the same condition as later in the function. This
     // should be taken into account when refactoring this method as part of
     // http://crbug.com/123007.
-    if (dest_is_view_source_mode)
+    if (dest_is_view_source_mode) {
       return SiteInstanceDescriptor(browser_context, dest_url,
                                     SiteInstanceRelation::UNRELATED);
+    }
 
     // If we are navigating from a blank SiteInstance to a WebUI, make sure we
     // create a new SiteInstance.
@@ -1592,7 +1584,6 @@
 
   // Shortcut some common cases for reusing an existing frame's SiteInstance.
   // There are several reasons for this:
-  // - looking at the main frame and openers is required for TDI mode.
   // - with hosted apps, this allows same-site, non-app subframes to be kept
   //   inside the hosted app process.
   // - this avoids putting same-site iframes into different processes after
@@ -1854,7 +1845,7 @@
   // In the common case, we use the RenderFrameHost's last successful URL. Thus,
   // we compare against the last successful commit when deciding whether to swap
   // this time.
-  if (SiteInstanceImpl::IsSameWebSite(
+  if (SiteInstanceImpl::IsSameSite(
           candidate->GetSiteInstance()->GetIsolationContext(),
           candidate->last_successful_url(), dest_url,
           should_compare_effective_urls)) {
@@ -1865,7 +1856,7 @@
   // example, "about:blank"). If so, examine the replicated origin to determine
   // the site.
   if (!candidate->GetLastCommittedOrigin().opaque() &&
-      SiteInstanceImpl::IsSameWebSite(
+      SiteInstanceImpl::IsSameSite(
           candidate->GetSiteInstance()->GetIsolationContext(),
           GURL(candidate->GetLastCommittedOrigin().Serialize()), dest_url,
           should_compare_effective_urls)) {
@@ -2465,8 +2456,8 @@
   // This is done in ~FrameTreeNode, but this is needed here as well. For
   // instance if the user navigates from A(B) to C and B is deleted after C
   // commits, then the last committed navigation entry wouldn't match anymore.
-  NavigationEntryImpl* navigation_entry = static_cast<NavigationEntryImpl*>(
-      delegate_->GetLastCommittedNavigationEntryForRenderManager());
+  NavigationEntryImpl* navigation_entry =
+      delegate_->GetControllerForRenderManager().GetLastCommittedEntry();
   if (navigation_entry) {
     render_frame_host_->frame_tree_node()->PruneChildFrameNavigationEntries(
         navigation_entry);
diff --git a/content/browser/frame_host/render_frame_host_manager.h b/content/browser/frame_host/render_frame_host_manager.h
index 5166fca..b4a3aa5 100644
--- a/content/browser/frame_host/render_frame_host_manager.h
+++ b/content/browser/frame_host/render_frame_host_manager.h
@@ -147,11 +147,6 @@
         RenderFrameHost* new_host) = 0;
     virtual NavigationControllerImpl& GetControllerForRenderManager() = 0;
 
-    // Returns the navigation entry of the current navigation, or NULL if there
-    // is none.
-    virtual NavigationEntry*
-    GetLastCommittedNavigationEntryForRenderManager() = 0;
-
     // Returns the interstitial page showing in the delegate, or null if there
     // is none.
     virtual InterstitialPageImpl* GetInterstitialForRenderManager() = 0;
@@ -590,11 +585,6 @@
   // Delete a RenderFrameProxyHost owned by this object.
   void DeleteRenderFrameProxyHost(SiteInstance* site_instance);
 
-  // Returns whether this tab should transition to a new renderer for
-  // cross-site URLs.  Enabled unless we see the --single-process command line
-  // switch.
-  bool ShouldTransitionCrossSite();
-
   // Returns true if for the navigation from |current_effective_url| to
   // |new_effective_url|, a new SiteInstance and BrowsingInstance should be
   // created (even if we are in a process model that doesn't usually swap).
@@ -605,7 +595,7 @@
   // should be the same as |new_is_view_source_mode|.
   //
   // We use the effective URL here, since that's what is used in the
-  // SiteInstance's site and when we later call IsSameWebSite.  If there is no
+  // SiteInstance's site and when we later call IsSameSite.  If there is no
   // current NavigationEntry, check the current SiteInstance's site, which might
   // already be committed to a Web UI URL (such as the NTP).
   bool ShouldSwapBrowsingInstancesForNavigation(
diff --git a/content/browser/loader/cross_site_document_blocking_browsertest.cc b/content/browser/loader/cross_site_document_blocking_browsertest.cc
index e46dbf3..8889d278 100644
--- a/content/browser/loader/cross_site_document_blocking_browsertest.cc
+++ b/content/browser/loader/cross_site_document_blocking_browsertest.cc
@@ -1516,7 +1516,7 @@
     // Sanity check of test setup - the 2 https servers should be cross-site
     // (the second server should have a different hostname because of the call
     // to SetSSLConfig with CERT_COMMON_NAME_IS_DOMAIN argument).
-    ASSERT_FALSE(SiteInstanceImpl::IsSameWebSite(
+    ASSERT_FALSE(SiteInstanceImpl::IsSameSite(
         IsolationContext(shell()->web_contents()->GetBrowserContext()),
         GetURLOnServiceWorkerServer("/"), GetURLOnCrossOriginServer("/"),
         true /* should_use_effective_urls */));
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index 9c480f8..a6b226c 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -300,7 +300,8 @@
       bool is_main_frame,
       mojo::PendingReceiver<network::mojom::URLLoaderFactory>
           proxied_factory_receiver,
-      network::mojom::URLLoaderFactoryPtrInfo proxied_factory_info,
+      mojo::PendingRemote<network::mojom::URLLoaderFactory>
+          proxied_factory_remote,
       std::set<std::string> known_schemes,
       bool bypass_redirect_checks,
       const base::WeakPtr<NavigationURLLoaderImpl>& owner)
@@ -310,7 +311,7 @@
         owner_(owner),
         response_loader_binding_(this),
         proxied_factory_receiver_(std::move(proxied_factory_receiver)),
-        proxied_factory_info_(std::move(proxied_factory_info)),
+        proxied_factory_remote_(std::move(proxied_factory_remote)),
         known_schemes_(std::move(known_schemes)),
         bypass_redirect_checks_(bypass_redirect_checks),
         browser_context_(browser_context) {}
@@ -385,9 +386,9 @@
         std::move(network_loader_factory_info));
     if (needs_loader_factory_interceptor &&
         g_loader_factory_interceptor.Get()) {
-      network::mojom::URLLoaderFactoryPtr factory;
+      mojo::PendingRemote<network::mojom::URLLoaderFactory> factory;
       mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver =
-          mojo::MakeRequest(&factory);
+          factory.InitWithNewPipeAndPassReceiver();
       g_loader_factory_interceptor.Get().Run(&receiver);
       network_loader_factory_->Clone(std::move(receiver));
       network_loader_factory_ =
@@ -688,13 +689,13 @@
       }
 
       if (g_loader_factory_interceptor.Get()) {
-        network::mojom::URLLoaderFactoryPtr factory_ptr;
+        mojo::PendingRemote<network::mojom::URLLoaderFactory> factory_remote;
         mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver =
-            mojo::MakeRequest(&factory_ptr);
+            factory_remote.InitWithNewPipeAndPassReceiver();
         g_loader_factory_interceptor.Get().Run(&receiver);
         factory->Clone(std::move(receiver));
         factory = base::MakeRefCounted<network::WrapperSharedURLLoaderFactory>(
-            std::move(factory_ptr));
+            std::move(factory_remote));
       }
     } else {
       default_loader_used_ = true;
@@ -705,11 +706,11 @@
       // interceptors isn't used and the URL is either a data URL or has a
       // scheme which is handled by the network service.
       if (proxied_factory_receiver_.is_valid()) {
-        DCHECK(proxied_factory_info_.is_valid());
+        DCHECK(proxied_factory_remote_.is_valid());
         // We don't worry about reconnection since it's a single navigation.
         network_loader_factory_->Clone(std::move(proxied_factory_receiver_));
         factory = base::MakeRefCounted<network::WrapperSharedURLLoaderFactory>(
-            std::move(proxied_factory_info_));
+            std::move(proxied_factory_remote_));
       } else {
         factory = network_loader_factory_;
       }
@@ -1187,14 +1188,14 @@
 
   // Before creating this URLLoaderRequestController on UI thread, the embedder
   // may have elected to proxy the URLLoaderFactory receiver, in which case
-  // these fields will contain input (info) and output (receiver) endpoints for
-  // the proxy. If this controller is handling a receiver for which proxying is
-  // supported, receivers will be plumbed through these endpoints.
+  // these fields will contain input (remote) and output (receiver) endpoints
+  // for the proxy. If this controller is handling a receiver for which proxying
+  // is supported, receivers will be plumbed through these endpoints.
   //
   // Note that these are only used for receivers that go to the Network Service.
   mojo::PendingReceiver<network::mojom::URLLoaderFactory>
       proxied_factory_receiver_;
-  network::mojom::URLLoaderFactoryPtrInfo proxied_factory_info_;
+  mojo::PendingRemote<network::mojom::URLLoaderFactory> proxied_factory_remote_;
 
   // The schemes that this loader can use. For anything else we'll try external
   // protocol handlers.
@@ -1283,7 +1284,7 @@
                                 std::move(factory_receiver));
   }
 
-  network::mojom::URLLoaderFactoryPtrInfo proxied_factory_info;
+  mojo::PendingRemote<network::mojom::URLLoaderFactory> proxied_factory_remote;
   mojo::PendingReceiver<network::mojom::URLLoaderFactory>
       proxied_factory_receiver;
   mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>
@@ -1314,7 +1315,7 @@
     }
     if (use_proxy) {
       proxied_factory_receiver = std::move(factory_receiver);
-      proxied_factory_info = std::move(pending_factory);
+      proxied_factory_remote = std::move(pending_factory);
     }
 
     const std::string storage_domain;
@@ -1376,7 +1377,7 @@
   request_controller_ = std::make_unique<URLLoaderRequestController>(
       std::move(initial_interceptors), std::move(new_request), browser_context,
       request_info->common_params->url, request_info->is_main_frame,
-      std::move(proxied_factory_receiver), std::move(proxied_factory_info),
+      std::move(proxied_factory_receiver), std::move(proxied_factory_remote),
       std::move(known_schemes), bypass_redirect_checks,
       weak_factory_.GetWeakPtr());
   request_controller_->Start(
diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.cc b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
index 8b5df1c..ca8f0e74 100644
--- a/content/browser/service_worker/service_worker_fetch_dispatcher.cc
+++ b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
@@ -680,13 +680,13 @@
 
   // Create the network factory.
   scoped_refptr<network::SharedURLLoaderFactory> factory;
-  network::mojom::URLLoaderFactoryPtr network_factory;
-  auto factory_request = mojo::MakeRequest(&network_factory);
+  mojo::PendingRemote<network::mojom::URLLoaderFactory> network_factory;
 
-  base::PostTask(FROM_HERE, {BrowserThread::UI},
-                 base::BindOnce(&CreateNetworkFactoryForNavigationPreloadOnUI,
-                                frame_tree_node_id, std::move(context_wrapper),
-                                mojo::MakeRequest(&network_factory)));
+  base::PostTask(
+      FROM_HERE, {BrowserThread::UI},
+      base::BindOnce(&CreateNetworkFactoryForNavigationPreloadOnUI,
+                     frame_tree_node_id, std::move(context_wrapper),
+                     network_factory.InitWithNewPipeAndPassReceiver()));
   factory = base::MakeRefCounted<network::WrapperSharedURLLoaderFactory>(
       std::move(network_factory));
 
diff --git a/content/browser/site_instance_impl.cc b/content/browser/site_instance_impl.cc
index 47a94666..1d7865f 100644
--- a/content/browser/site_instance_impl.cc
+++ b/content/browser/site_instance_impl.cc
@@ -524,7 +524,7 @@
 bool SiteInstanceImpl::IsSameSiteWithURL(const GURL& url) {
   if (IsDefaultSiteInstance()) {
     // about:blank URLs should always be considered same site just like they are
-    // in IsSameWebSite().
+    // in IsSameSite().
     if (url.IsAboutBlank())
       return true;
 
@@ -541,9 +541,8 @@
            !browsing_instance_->HasSiteInstance(url);
   }
 
-  return SiteInstanceImpl::IsSameWebSite(
-      GetIsolationContext(), site_, url,
-      true /* should_compare_effective_urls */);
+  return SiteInstanceImpl::IsSameSite(GetIsolationContext(), site_, url,
+                                      true /* should_compare_effective_urls */);
 }
 
 bool SiteInstanceImpl::IsOriginalUrlSameSite(
@@ -552,15 +551,15 @@
   if (IsDefaultSiteInstance())
     return IsSameSiteWithURL(dest_url);
 
-  return IsSameWebSite(GetIsolationContext(), original_url_, dest_url,
-                       should_compare_effective_urls);
+  return IsSameSite(GetIsolationContext(), original_url_, dest_url,
+                    should_compare_effective_urls);
 }
 
 // static
-bool SiteInstanceImpl::IsSameWebSite(const IsolationContext& isolation_context,
-                                     const GURL& real_src_url,
-                                     const GURL& real_dest_url,
-                                     bool should_compare_effective_urls) {
+bool SiteInstanceImpl::IsSameSite(const IsolationContext& isolation_context,
+                                  const GURL& real_src_url,
+                                  const GURL& real_dest_url,
+                                  bool should_compare_effective_urls) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   BrowserContext* browser_context =
       isolation_context.browser_or_resource_context().ToBrowserContext();
diff --git a/content/browser/site_instance_impl.h b/content/browser/site_instance_impl.h
index 79fa3347..5784da18 100644
--- a/content/browser/site_instance_impl.h
+++ b/content/browser/site_instance_impl.h
@@ -71,10 +71,10 @@
   // without converting them to effective URLs first.  This is useful for
   // avoiding OOPIFs when otherwise same-site URLs may look cross-site via
   // their effective URLs.
-  static bool IsSameWebSite(const IsolationContext& isolation_context,
-                            const GURL& src_url,
-                            const GURL& dest_url,
-                            bool should_compare_effective_urls);
+  static bool IsSameSite(const IsolationContext& isolation_context,
+                         const GURL& src_url,
+                         const GURL& dest_url,
+                         bool should_compare_effective_urls);
 
   // SiteInstance interface overrides.
   int32_t GetId() override;
diff --git a/content/browser/site_instance_impl_unittest.cc b/content/browser/site_instance_impl_unittest.cc
index 120619bd..f605946 100644
--- a/content/browser/site_instance_impl_unittest.cc
+++ b/content/browser/site_instance_impl_unittest.cc
@@ -50,11 +50,9 @@
 
 using IsolatedOriginSource = ChildProcessSecurityPolicy::IsolatedOriginSource;
 
-bool IsSameWebSite(BrowserContext* context,
-                   const GURL& url1,
-                   const GURL& url2) {
-  return SiteInstanceImpl::IsSameWebSite(IsolationContext(context), url1, url2,
-                                         true /* should_use_effective_urls */);
+bool IsSameSite(BrowserContext* context, const GURL& url1, const GURL& url2) {
+  return SiteInstanceImpl::IsSameSite(IsolationContext(context), url1, url2,
+                                      true /* should_use_effective_urls */);
 }
 
 }  // namespace
@@ -537,7 +535,7 @@
 // Test of distinguishing URLs from different sites.  Most of this logic is
 // tested in RegistryControlledDomainTest.  This test focuses on URLs with
 // different schemes or ports.
-TEST_F(SiteInstanceTest, IsSameWebSite) {
+TEST_F(SiteInstanceTest, IsSameSite) {
   TestBrowserContext context;
   GURL url_foo = GURL("http://foo/a.html");
   GURL url_foo2 = GURL("http://foo/b.html");
@@ -547,58 +545,57 @@
   GURL url_blank = GURL(url::kAboutBlankURL);
 
   // Same scheme and port -> same site.
-  EXPECT_TRUE(IsSameWebSite(&context, url_foo, url_foo2));
+  EXPECT_TRUE(IsSameSite(&context, url_foo, url_foo2));
 
   // Different scheme -> different site.
-  EXPECT_FALSE(IsSameWebSite(&context, url_foo, url_foo_https));
+  EXPECT_FALSE(IsSameSite(&context, url_foo, url_foo_https));
 
   // Different port -> same site.
   // (Changes to document.domain make renderer ignore the port.)
-  EXPECT_TRUE(IsSameWebSite(&context, url_foo, url_foo_port));
+  EXPECT_TRUE(IsSameSite(&context, url_foo, url_foo_port));
 
   // JavaScript links should be considered same site for anything.
-  EXPECT_TRUE(IsSameWebSite(&context, url_javascript, url_foo));
-  EXPECT_TRUE(IsSameWebSite(&context, url_javascript, url_foo_https));
-  EXPECT_TRUE(IsSameWebSite(&context, url_javascript, url_foo_port));
+  EXPECT_TRUE(IsSameSite(&context, url_javascript, url_foo));
+  EXPECT_TRUE(IsSameSite(&context, url_javascript, url_foo_https));
+  EXPECT_TRUE(IsSameSite(&context, url_javascript, url_foo_port));
 
   // Navigating to a blank page is considered the same site.
-  EXPECT_TRUE(IsSameWebSite(&context, url_foo, url_blank));
-  EXPECT_TRUE(IsSameWebSite(&context, url_foo_https, url_blank));
-  EXPECT_TRUE(IsSameWebSite(&context, url_foo_port, url_blank));
+  EXPECT_TRUE(IsSameSite(&context, url_foo, url_blank));
+  EXPECT_TRUE(IsSameSite(&context, url_foo_https, url_blank));
+  EXPECT_TRUE(IsSameSite(&context, url_foo_port, url_blank));
 
   // Navigating from a blank site is not considered to be the same site.
-  EXPECT_FALSE(IsSameWebSite(&context, url_blank, url_foo));
-  EXPECT_FALSE(IsSameWebSite(&context, url_blank, url_foo_https));
-  EXPECT_FALSE(IsSameWebSite(&context, url_blank, url_foo_port));
+  EXPECT_FALSE(IsSameSite(&context, url_blank, url_foo));
+  EXPECT_FALSE(IsSameSite(&context, url_blank, url_foo_https));
+  EXPECT_FALSE(IsSameSite(&context, url_blank, url_foo_port));
 
   DrainMessageLoop();
 }
 
 // Test that two file URLs are considered same-site if they have the same path,
 // even if they have different fragments.
-TEST_F(SiteInstanceTest, IsSameWebSiteForFileURLs) {
+TEST_F(SiteInstanceTest, IsSameSiteForFileURLs) {
   TestBrowserContext context;
 
   // Two identical file URLs should be same-site.
-  EXPECT_TRUE(IsSameWebSite(&context, GURL("file:///foo/bar.html"),
-                            GURL("file:///foo/bar.html")));
+  EXPECT_TRUE(IsSameSite(&context, GURL("file:///foo/bar.html"),
+                         GURL("file:///foo/bar.html")));
 
   // File URLs with the same path but different fragment are considered
   // same-site.
-  EXPECT_TRUE(IsSameWebSite(&context, GURL("file:///foo/bar.html"),
-                            GURL("file:///foo/bar.html#baz")));
-  EXPECT_TRUE(IsSameWebSite(&context, GURL("file:///foo/bar.html#baz"),
-                            GURL("file:///foo/bar.html")));
-  EXPECT_TRUE(IsSameWebSite(&context, GURL("file:///foo/bar.html#baz"),
-                            GURL("file:///foo/bar.html#qux")));
-  EXPECT_TRUE(
-      IsSameWebSite(&context, GURL("file:///#abc"), GURL("file:///#def")));
+  EXPECT_TRUE(IsSameSite(&context, GURL("file:///foo/bar.html"),
+                         GURL("file:///foo/bar.html#baz")));
+  EXPECT_TRUE(IsSameSite(&context, GURL("file:///foo/bar.html#baz"),
+                         GURL("file:///foo/bar.html")));
+  EXPECT_TRUE(IsSameSite(&context, GURL("file:///foo/bar.html#baz"),
+                         GURL("file:///foo/bar.html#qux")));
+  EXPECT_TRUE(IsSameSite(&context, GURL("file:///#abc"), GURL("file:///#def")));
 
   // Other cases are cross-site.
-  EXPECT_FALSE(IsSameWebSite(&context, GURL("file:///foo.html"),
-                             GURL("file:///foo/bar.html")));
+  EXPECT_FALSE(IsSameSite(&context, GURL("file:///foo.html"),
+                          GURL("file:///foo/bar.html")));
   EXPECT_FALSE(
-      IsSameWebSite(&context, GURL("file:///#bar"), GURL("file:///foo/#bar")));
+      IsSameSite(&context, GURL("file:///#bar"), GURL("file:///foo/#bar")));
 }
 
 // Test to ensure that there is only one SiteInstance per site in a given
@@ -909,7 +906,7 @@
 
 // Check that an URL is considered same-site with blob: and filesystem: URLs
 // with a matching inner origin.  See https://crbug.com/726370.
-TEST_F(SiteInstanceTest, IsSameWebsiteForNestedURLs) {
+TEST_F(SiteInstanceTest, IsSameSiteForNestedURLs) {
   TestBrowserContext context;
   GURL foo_url("http://foo.com/");
   GURL bar_url("http://bar.com/");
@@ -918,34 +915,34 @@
   GURL fs_foo_url("filesystem:http://foo.com/path/");
   GURL fs_bar_url("filesystem:http://bar.com/path/");
 
-  EXPECT_TRUE(IsSameWebSite(&context, foo_url, blob_foo_url));
-  EXPECT_TRUE(IsSameWebSite(&context, blob_foo_url, foo_url));
-  EXPECT_FALSE(IsSameWebSite(&context, foo_url, blob_bar_url));
-  EXPECT_FALSE(IsSameWebSite(&context, blob_foo_url, bar_url));
+  EXPECT_TRUE(IsSameSite(&context, foo_url, blob_foo_url));
+  EXPECT_TRUE(IsSameSite(&context, blob_foo_url, foo_url));
+  EXPECT_FALSE(IsSameSite(&context, foo_url, blob_bar_url));
+  EXPECT_FALSE(IsSameSite(&context, blob_foo_url, bar_url));
 
-  EXPECT_TRUE(IsSameWebSite(&context, foo_url, fs_foo_url));
-  EXPECT_TRUE(IsSameWebSite(&context, fs_foo_url, foo_url));
-  EXPECT_FALSE(IsSameWebSite(&context, foo_url, fs_bar_url));
-  EXPECT_FALSE(IsSameWebSite(&context, fs_foo_url, bar_url));
+  EXPECT_TRUE(IsSameSite(&context, foo_url, fs_foo_url));
+  EXPECT_TRUE(IsSameSite(&context, fs_foo_url, foo_url));
+  EXPECT_FALSE(IsSameSite(&context, foo_url, fs_bar_url));
+  EXPECT_FALSE(IsSameSite(&context, fs_foo_url, bar_url));
 
-  EXPECT_TRUE(IsSameWebSite(&context, blob_foo_url, fs_foo_url));
-  EXPECT_FALSE(IsSameWebSite(&context, blob_foo_url, fs_bar_url));
-  EXPECT_FALSE(IsSameWebSite(&context, blob_foo_url, blob_bar_url));
-  EXPECT_FALSE(IsSameWebSite(&context, fs_foo_url, fs_bar_url));
+  EXPECT_TRUE(IsSameSite(&context, blob_foo_url, fs_foo_url));
+  EXPECT_FALSE(IsSameSite(&context, blob_foo_url, fs_bar_url));
+  EXPECT_FALSE(IsSameSite(&context, blob_foo_url, blob_bar_url));
+  EXPECT_FALSE(IsSameSite(&context, fs_foo_url, fs_bar_url));
 
   // Verify that the scheme and ETLD+1 are used for comparison.
   GURL www_bar_url("http://www.bar.com/");
   GURL bar_org_url("http://bar.org/");
   GURL https_bar_url("https://bar.com/");
-  EXPECT_TRUE(IsSameWebSite(&context, www_bar_url, bar_url));
-  EXPECT_TRUE(IsSameWebSite(&context, www_bar_url, blob_bar_url));
-  EXPECT_TRUE(IsSameWebSite(&context, www_bar_url, fs_bar_url));
-  EXPECT_FALSE(IsSameWebSite(&context, bar_org_url, bar_url));
-  EXPECT_FALSE(IsSameWebSite(&context, bar_org_url, blob_bar_url));
-  EXPECT_FALSE(IsSameWebSite(&context, bar_org_url, fs_bar_url));
-  EXPECT_FALSE(IsSameWebSite(&context, https_bar_url, bar_url));
-  EXPECT_FALSE(IsSameWebSite(&context, https_bar_url, blob_bar_url));
-  EXPECT_FALSE(IsSameWebSite(&context, https_bar_url, fs_bar_url));
+  EXPECT_TRUE(IsSameSite(&context, www_bar_url, bar_url));
+  EXPECT_TRUE(IsSameSite(&context, www_bar_url, blob_bar_url));
+  EXPECT_TRUE(IsSameSite(&context, www_bar_url, fs_bar_url));
+  EXPECT_FALSE(IsSameSite(&context, bar_org_url, bar_url));
+  EXPECT_FALSE(IsSameSite(&context, bar_org_url, blob_bar_url));
+  EXPECT_FALSE(IsSameSite(&context, bar_org_url, fs_bar_url));
+  EXPECT_FALSE(IsSameSite(&context, https_bar_url, bar_url));
+  EXPECT_FALSE(IsSameSite(&context, https_bar_url, blob_bar_url));
+  EXPECT_FALSE(IsSameSite(&context, https_bar_url, fs_bar_url));
 }
 
 TEST_F(SiteInstanceTest, StrictOriginIsolation) {
@@ -958,7 +955,7 @@
   TestBrowserContext browser_context;
   IsolationContext isolation_context(&browser_context);
 
-  EXPECT_FALSE(IsSameWebSite(context(), isolated1_foo_url, isolated2_foo_url));
+  EXPECT_FALSE(IsSameSite(context(), isolated1_foo_url, isolated2_foo_url));
   EXPECT_NE(
       SiteInstanceImpl::GetSiteForURL(isolation_context, isolated1_foo_url),
       SiteInstanceImpl::GetSiteForURL(isolation_context, isolated2_foo_url));
@@ -1025,7 +1022,7 @@
   auto* policy = ChildProcessSecurityPolicyImpl::GetInstance();
 
   EXPECT_FALSE(IsIsolatedOrigin(isolated_foo_url));
-  EXPECT_TRUE(IsSameWebSite(context(), foo_url, isolated_foo_url));
+  EXPECT_TRUE(IsSameSite(context(), foo_url, isolated_foo_url));
 
   policy->AddIsolatedOrigins({url::Origin::Create(isolated_foo_url)},
                              IsolatedOriginSource::TEST);
@@ -1046,21 +1043,20 @@
                              IsolatedOriginSource::TEST);
   EXPECT_TRUE(IsIsolatedOrigin(isolated_bar_url));
 
-  // IsSameWebSite should compare origins rather than sites if either URL is an
+  // IsSameSite should compare origins rather than sites if either URL is an
   // isolated origin.
-  EXPECT_FALSE(IsSameWebSite(context(), foo_url, isolated_foo_url));
-  EXPECT_FALSE(IsSameWebSite(context(), isolated_foo_url, foo_url));
-  EXPECT_FALSE(IsSameWebSite(context(), isolated_foo_url, isolated_bar_url));
-  EXPECT_TRUE(IsSameWebSite(context(), isolated_foo_url, isolated_foo_url));
+  EXPECT_FALSE(IsSameSite(context(), foo_url, isolated_foo_url));
+  EXPECT_FALSE(IsSameSite(context(), isolated_foo_url, foo_url));
+  EXPECT_FALSE(IsSameSite(context(), isolated_foo_url, isolated_bar_url));
+  EXPECT_TRUE(IsSameSite(context(), isolated_foo_url, isolated_foo_url));
 
   // Ensure blob and filesystem URLs with isolated origins are compared
   // correctly.
   GURL isolated_blob_foo_url("blob:http://isolated.foo.com/uuid");
-  EXPECT_TRUE(
-      IsSameWebSite(context(), isolated_foo_url, isolated_blob_foo_url));
+  EXPECT_TRUE(IsSameSite(context(), isolated_foo_url, isolated_blob_foo_url));
   GURL isolated_filesystem_foo_url("filesystem:http://isolated.foo.com/bar/");
   EXPECT_TRUE(
-      IsSameWebSite(context(), isolated_foo_url, isolated_filesystem_foo_url));
+      IsSameSite(context(), isolated_foo_url, isolated_filesystem_foo_url));
 
   // The site URL for an isolated origin should be the full origin rather than
   // eTLD+1.
@@ -1197,8 +1193,8 @@
   EXPECT_TRUE(SiteInstanceImpl::DoesSiteRequireDedicatedProcess(
       isolation_context, foo_isolated_url));
 
-  EXPECT_TRUE(IsSameWebSite(context(), isolated_url, foo_isolated_url));
-  EXPECT_TRUE(IsSameWebSite(context(), foo_isolated_url, isolated_url));
+  EXPECT_TRUE(IsSameSite(context(), isolated_url, foo_isolated_url));
+  EXPECT_TRUE(IsSameSite(context(), foo_isolated_url, isolated_url));
 
   // Don't try to match subdomains on IP addresses.
   GURL isolated_ip("http://127.0.0.1");
@@ -1248,16 +1244,16 @@
   EXPECT_TRUE(SiteInstanceImpl::DoesSiteRequireDedicatedProcess(
       isolation_context, baz_isolated_foo_url));
 
-  EXPECT_FALSE(IsSameWebSite(context(), foo_url, isolated_foo_url));
-  EXPECT_FALSE(IsSameWebSite(context(), isolated_foo_url, foo_url));
-  EXPECT_FALSE(IsSameWebSite(context(), foo_url, bar_isolated_foo_url));
-  EXPECT_FALSE(IsSameWebSite(context(), bar_isolated_foo_url, foo_url));
-  EXPECT_TRUE(IsSameWebSite(context(), bar_isolated_foo_url, isolated_foo_url));
-  EXPECT_TRUE(IsSameWebSite(context(), isolated_foo_url, bar_isolated_foo_url));
+  EXPECT_FALSE(IsSameSite(context(), foo_url, isolated_foo_url));
+  EXPECT_FALSE(IsSameSite(context(), isolated_foo_url, foo_url));
+  EXPECT_FALSE(IsSameSite(context(), foo_url, bar_isolated_foo_url));
+  EXPECT_FALSE(IsSameSite(context(), bar_isolated_foo_url, foo_url));
+  EXPECT_TRUE(IsSameSite(context(), bar_isolated_foo_url, isolated_foo_url));
+  EXPECT_TRUE(IsSameSite(context(), isolated_foo_url, bar_isolated_foo_url));
   EXPECT_TRUE(
-      IsSameWebSite(context(), bar_isolated_foo_url, baz_isolated_foo_url));
+      IsSameSite(context(), bar_isolated_foo_url, baz_isolated_foo_url));
   EXPECT_TRUE(
-      IsSameWebSite(context(), baz_isolated_foo_url, bar_isolated_foo_url));
+      IsSameSite(context(), baz_isolated_foo_url, bar_isolated_foo_url));
 
   // Cleanup.
   policy->RemoveIsolatedOriginForTesting(url::Origin::Create(isolated_foo_url));
@@ -1298,14 +1294,14 @@
   EXPECT_TRUE(SiteInstanceImpl::DoesSiteRequireDedicatedProcess(
       isolation_context, qux_baz_bar_foo_url));
 
-  EXPECT_TRUE(IsSameWebSite(context(), foo_url, bar_foo_url));
-  EXPECT_FALSE(IsSameWebSite(context(), foo_url, baz_bar_foo_url));
-  EXPECT_FALSE(IsSameWebSite(context(), foo_url, qux_baz_bar_foo_url));
+  EXPECT_TRUE(IsSameSite(context(), foo_url, bar_foo_url));
+  EXPECT_FALSE(IsSameSite(context(), foo_url, baz_bar_foo_url));
+  EXPECT_FALSE(IsSameSite(context(), foo_url, qux_baz_bar_foo_url));
 
-  EXPECT_FALSE(IsSameWebSite(context(), bar_foo_url, baz_bar_foo_url));
-  EXPECT_FALSE(IsSameWebSite(context(), bar_foo_url, qux_baz_bar_foo_url));
+  EXPECT_FALSE(IsSameSite(context(), bar_foo_url, baz_bar_foo_url));
+  EXPECT_FALSE(IsSameSite(context(), bar_foo_url, qux_baz_bar_foo_url));
 
-  EXPECT_TRUE(IsSameWebSite(context(), baz_bar_foo_url, qux_baz_bar_foo_url));
+  EXPECT_TRUE(IsSameSite(context(), baz_bar_foo_url, qux_baz_bar_foo_url));
 
   // Cleanup.
   policy->RemoveIsolatedOriginForTesting(url::Origin::Create(foo_url));
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index e22c515d0..be5287c 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -13547,8 +13547,8 @@
 // Verify the feature where hidden tabs with crashed subframes are marked for
 // reload.  This avoids showing crashed subframes if a hidden tab is eventually
 // shown.  See https://crbug.com/841572.
-// crbug.com/1010119, fails on win.
-#if defined(OS_WIN)
+// crbug.com/1010119, fails on win. crbug.com/1015971, fails on Linux.
+#if defined(OS_WIN) || defined(OS_LINUX)
 #define MAYBE_ReloadHiddenTabWithCrashedSubframe \
   DISABLED_ReloadHiddenTabWithCrashedSubframe
 #else
diff --git a/content/browser/sms/sms_browsertest.cc b/content/browser/sms/sms_browsertest.cc
index a99c5b1..e341215 100644
--- a/content/browser/sms/sms_browsertest.cc
+++ b/content/browser/sms/sms_browsertest.cc
@@ -137,55 +137,143 @@
   ExpectOutcomeUKM(url, blink::SMSReceiverOutcome::kSuccess);
 }
 
-IN_PROC_BROWSER_TEST_F(SmsBrowserTest, AtMostOnePendingSmsRequest) {
+IN_PROC_BROWSER_TEST_F(SmsBrowserTest, AtMostOneSmsRequestPerOrigin) {
   GURL url = GetTestUrl(nullptr, "simple_page.html");
   EXPECT_TRUE(NavigateToURL(shell(), url));
 
   shell()->web_contents()->SetDelegate(&delegate_);
 
   EXPECT_CALL(delegate_, CreateSmsPrompt(_, _, _, _, _))
-      .WillOnce(
-          Invoke([&](RenderFrameHost*, const url::Origin&, const std::string&,
-                     base::OnceClosure on_confirm,
-                     base::OnceClosure) { std::move(on_confirm).Run(); }));
+      .WillOnce(Invoke([](RenderFrameHost*, const url::Origin&,
+                          const std::string&, base::OnceClosure on_confirm,
+                          base::OnceClosure) { std::move(on_confirm).Run(); }));
 
   auto* provider = new NiceMock<MockSmsProvider>();
   BrowserMainLoop::GetInstance()->SetSmsProviderForTesting(
       base::WrapUnique(provider));
 
   std::string script = R"(
-    navigator.sms.receive().then(({content}) => { first = content; });
-    navigator.sms.receive().catch(e => e.name);
+    (async () => {
+      let firstRequest = navigator.sms.receive().catch(e => {
+        return e.name;
+      });
+      let secondRequest = navigator.sms.receive().then(({content}) => {
+        return content;
+      });
+      return Promise.all([firstRequest, secondRequest]);
+    }) ();
   )";
 
-  base::RunLoop loop;
-
-  EXPECT_CALL(*provider, Retrieve()).WillOnce(Invoke([&loop]() {
-    loop.Quit();
-  }));
+  EXPECT_CALL(*provider, Retrieve())
+      .WillOnce(Return())
+      .WillOnce(Invoke([&url, &provider]() {
+        provider->NotifyReceive(url::Origin::Create(url), "", "hello");
+      }));
 
   // Wait for UKM to be recorded to avoid race condition.
   base::RunLoop ukm_loop1;
   ukm_recorder()->SetOnAddEntryCallback(Entry::kEntryName,
                                         ukm_loop1.QuitClosure());
 
-  EXPECT_EQ("AbortError", EvalJs(shell(), script));
+  EXPECT_EQ(ListValueOf("AbortError", "hello"), EvalJs(shell(), script));
 
-  loop.Run();
   ukm_loop1.Run();
 
-  ExpectOutcomeUKM(url, blink::SMSReceiverOutcome::kCancelled);
+  ASSERT_FALSE(provider->HasObservers());
 
-  // Wait for UKM to be recorded to avoid race condition.
-  base::RunLoop ukm_loop2;
-  ukm_recorder()->SetOnAddEntryCallback(Entry::kEntryName,
-                                        ukm_loop2.QuitClosure());
+  ExpectOutcomeUKM(url, blink::SMSReceiverOutcome::kSuccess);
+}
 
-  provider->NotifyReceive(url::Origin::Create(url), "", "hello");
+IN_PROC_BROWSER_TEST_F(SmsBrowserTest, AtMostOneSmsRequestPerOriginPerTab) {
+  auto* provider = new NiceMock<MockSmsProvider>();
+  BrowserMainLoop::GetInstance()->SetSmsProviderForTesting(
+      base::WrapUnique(provider));
 
-  EXPECT_EQ("hello", EvalJs(shell(), "first"));
+  Shell* tab1 = CreateBrowser();
+  Shell* tab2 = CreateBrowser();
 
-  ukm_loop2.Run();
+  GURL url = GetTestUrl(nullptr, "simple_page.html");
+
+  EXPECT_TRUE(NavigateToURL(tab1, url));
+  EXPECT_TRUE(NavigateToURL(tab2, url));
+
+  tab1->web_contents()->SetDelegate(&delegate_);
+  tab2->web_contents()->SetDelegate(&delegate_);
+
+  EXPECT_CALL(*provider, Retrieve()).Times(3);
+
+  // Make 1 request on tab1 that is expected to be cancelled when the 2nd
+  // request is made.
+  EXPECT_TRUE(ExecJs(tab1, R"(
+       var firstRequest = navigator.sms.receive().catch(e => {
+         return e.name;
+       });
+     )"));
+
+  // Make 1 request on tab2 to verify requests on tab1 have no affect on tab2.
+  EXPECT_TRUE(ExecJs(tab2, R"(
+        var request = navigator.sms.receive().then(({content}) => {
+          return content;
+        });
+     )"));
+
+  // Make a 2nd request on tab1 to verify the 1st request gets cancelled when
+  // the 2nd request is made.
+  EXPECT_TRUE(ExecJs(tab1, R"(
+        var secondRequest = navigator.sms.receive().then(({content}) => {
+          return content;
+        });
+     )"));
+
+  EXPECT_EQ("AbortError", EvalJs(tab1, "firstRequest"));
+
+  ASSERT_TRUE(provider->HasObservers());
+
+  {
+    base::RunLoop ukm_loop;
+
+    EXPECT_CALL(delegate_, CreateSmsPrompt(_, _, _, _, _))
+        .WillOnce(
+            Invoke([](RenderFrameHost*, const url::Origin&, const std::string&,
+                      base::OnceClosure on_confirm,
+                      base::OnceClosure) { std::move(on_confirm).Run(); }));
+
+    // Wait for UKM to be recorded to avoid race condition.
+    ukm_recorder()->SetOnAddEntryCallback(Entry::kEntryName,
+                                          ukm_loop.QuitClosure());
+
+    provider->NotifyReceive(url::Origin::Create(url), "", "hello1");
+
+    ukm_loop.Run();
+  }
+
+  EXPECT_EQ("hello1", EvalJs(tab2, "request"));
+
+  ASSERT_TRUE(provider->HasObservers());
+
+  ExpectOutcomeUKM(url, blink::SMSReceiverOutcome::kSuccess);
+
+  ukm_recorder()->Purge();
+
+  {
+    base::RunLoop ukm_loop;
+
+    EXPECT_CALL(delegate_, CreateSmsPrompt(_, _, _, _, _))
+        .WillOnce(
+            Invoke([](RenderFrameHost*, const url::Origin&, const std::string&,
+                      base::OnceClosure on_confirm,
+                      base::OnceClosure) { std::move(on_confirm).Run(); }));
+
+    // Wait for UKM to be recorded to avoid race condition.
+    ukm_recorder()->SetOnAddEntryCallback(Entry::kEntryName,
+                                          ukm_loop.QuitClosure());
+
+    provider->NotifyReceive(url::Origin::Create(url), "", "hello2");
+
+    ukm_loop.Run();
+  }
+
+  EXPECT_EQ("hello2", EvalJs(tab1, "secondRequest"));
 
   ASSERT_FALSE(provider->HasObservers());
 
diff --git a/content/browser/sms/sms_provider_android_unittest.cc b/content/browser/sms/sms_provider_android_unittest.cc
index 2fd4b61f..4b41ea6 100644
--- a/content/browser/sms/sms_provider_android_unittest.cc
+++ b/content/browser/sms/sms_provider_android_unittest.cc
@@ -62,6 +62,12 @@
         base::android::ConvertUTF8ToJavaString(env, sms));
   }
 
+  void TriggerTimeout() {
+    JNIEnv* env = base::android::AttachCurrentThread();
+    Java_FakeSmsRetrieverClient_triggerTimeout(env,
+                                               j_fake_sms_retriever_client_);
+  }
+
   SmsProviderAndroid& provider() { return provider_; }
 
   NiceMock<MockObserver>* observer() { return &observer_; }
@@ -99,4 +105,28 @@
   TriggerSms(good_sms);
 }
 
+TEST_F(SmsProviderAndroidTest, TaskTimedOut) {
+  std::string test_url = "https://www.google.com?otp=123";
+
+  EXPECT_CALL(*observer(), OnReceive(_, _, _)).Times(0);
+  provider().Retrieve();
+  TriggerTimeout();
+}
+
+TEST_F(SmsProviderAndroidTest, OneObserverTwoTasks) {
+  std::string test_url = "https://www.google.com?otp=123";
+  std::string expected_sms = "Hi \nFor: " + test_url;
+
+  EXPECT_CALL(*observer(),
+              OnReceive(Origin::Create(GURL(test_url)), _, expected_sms));
+
+  // Two tasks for when 1 request gets aborted but the task is still triggered.
+  provider().Retrieve();
+  provider().Retrieve();
+
+  // First timeout should be ignored.
+  TriggerTimeout();
+  TriggerSms(expected_sms);
+}
+
 }  // namespace content
diff --git a/content/browser/sms/sms_service.cc b/content/browser/sms/sms_service.cc
index db09f78..9976d6a 100644
--- a/content/browser/sms/sms_service.cc
+++ b/content/browser/sms/sms_service.cc
@@ -6,6 +6,7 @@
 
 #include <iterator>
 #include <queue>
+#include <string>
 #include <utility>
 
 #include "base/bind.h"
@@ -59,12 +60,10 @@
 void SmsService::Receive(ReceiveCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (callback_) {
-    std::move(callback).Run(blink::mojom::SmsStatus::kCancelled, base::nullopt);
-    return;
+    std::move(callback_).Run(SmsStatus::kCancelled, base::nullopt);
+    sms_provider_->RemoveObserver(this);
   }
 
-  DCHECK(!sms_);
-
   start_time_ = base::TimeTicks::Now();
 
   sms_provider_->AddObserver(this);
diff --git a/content/browser/sms/sms_service_unittest.cc b/content/browser/sms/sms_service_unittest.cc
index 440d703..9247c9f5 100644
--- a/content/browser/sms/sms_service_unittest.cc
+++ b/content/browser/sms/sms_service_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/sms/sms_service.h"
 
+#include <string>
 #include <utility>
 
 #include "base/bind.h"
@@ -262,7 +263,7 @@
   EXPECT_EQ(SmsStatus::kSuccess, sms_status);
 }
 
-TEST_F(SmsServiceTest, AtMostOnePendingSmsRequest) {
+TEST_F(SmsServiceTest, AtMostOneSmsRequestPerOrigin) {
   NavigateAndCommit(GURL(kTestUrl));
 
   Service service(web_contents());
@@ -274,15 +275,19 @@
 
   base::RunLoop sms1_loop, sms2_loop;
 
-  // Expects only one CreateSmsDialog() and OnReceive() call to be made since at
-  // most one sms request can be pending.
-  service.CreateSmsPrompt(main_rfh(), true);
+  // Expect SMS Prompt to be created once.
+  EXPECT_CALL(*service.delegate(), CreateSmsPrompt(main_rfh(), _, _, _, _))
+      .WillOnce(
+          Invoke([](RenderFrameHost*, const Origin& origin, const std::string&,
+                    base::OnceClosure on_confirm, base::OnceClosure on_cancel) {
+            std::move(on_confirm).Run();
+          }));
 
-  // Expects only one Retrieve() call to be made since at most one sms request
-  // can be pending.
-  EXPECT_CALL(*service.provider(), Retrieve()).Times(1);
+  EXPECT_CALL(*service.provider(), Retrieve())
+      .WillOnce(Return())
+      .WillOnce(Invoke(
+          [&service]() { service.NotifyReceive(GURL(kTestUrl), "second"); }));
 
-  // Make the first SMS request.
   service.MakeRequest(
       BindLambdaForTesting([&sms_status1, &response1, &sms1_loop](
                                SmsStatus status, const Optional<string>& sms) {
@@ -291,8 +296,8 @@
         sms1_loop.Quit();
       }));
 
-  // Make the second SMS request, and it will be canceled because the first SMS
-  // request is still pending.
+  // Make the 2nd SMS request which will cancel the 1st request because only
+  // one request can be pending per origin per tab.
   service.MakeRequest(
       BindLambdaForTesting([&sms_status2, &response2, &sms2_loop](
                                SmsStatus status, const Optional<string>& sms) {
@@ -301,18 +306,69 @@
         sms2_loop.Quit();
       }));
 
+  sms1_loop.Run();
   sms2_loop.Run();
 
-  EXPECT_EQ(base::nullopt, response2);
-  EXPECT_EQ(SmsStatus::kCancelled, sms_status2);
+  EXPECT_EQ(base::nullopt, response1);
+  EXPECT_EQ(SmsStatus::kCancelled, sms_status1);
 
-  // Delivers the first SMS.
-  service.NotifyReceive(GURL(kTestUrl), "first");
+  EXPECT_EQ("second", response2.value());
+  EXPECT_EQ(SmsStatus::kSuccess, sms_status2);
+}
+
+TEST_F(SmsServiceTest, SecondRequestDuringPrompt) {
+  NavigateAndCommit(GURL(kTestUrl));
+
+  Service service(web_contents());
+
+  SmsStatus sms_status1;
+  Optional<string> response1;
+  SmsStatus sms_status2;
+  Optional<string> response2;
+  base::OnceClosure prompt_confirm;
+
+  base::RunLoop sms1_loop, sms2_loop;
+
+  // Expect SMS Prompt to be created once.
+  EXPECT_CALL(*service.delegate(), CreateSmsPrompt(main_rfh(), _, _, _, _))
+      .WillOnce(Invoke([&](RenderFrameHost*, const Origin& origin,
+                           const std::string&, base::OnceClosure on_confirm,
+                           base::OnceClosure on_cancel) {
+        prompt_confirm = std::move(on_confirm);
+        sms1_loop.Quit();
+      }));
+
+  EXPECT_CALL(*service.provider(), Retrieve())
+      .WillOnce(Invoke(
+          [&service]() { service.NotifyReceive(GURL(kTestUrl), "second"); }))
+      .WillOnce(Return());
+
+  // First request.
+  service.MakeRequest(
+      BindLambdaForTesting([&sms_status1, &response1, &prompt_confirm](
+                               SmsStatus status, const Optional<string>& sms) {
+        sms_status1 = status;
+        response1 = sms;
+        std::move(prompt_confirm).Run();
+      }));
+
+  // Make second request before confirming prompt.
+  service.MakeRequest(
+      BindLambdaForTesting([&sms_status2, &response2, &sms2_loop](
+                               SmsStatus status, const Optional<string>& sms) {
+        sms_status2 = status;
+        response2 = sms;
+        sms2_loop.Quit();
+      }));
 
   sms1_loop.Run();
+  sms2_loop.Run();
 
-  EXPECT_EQ("first", response1.value());
-  EXPECT_EQ(SmsStatus::kSuccess, sms_status1);
+  EXPECT_EQ(base::nullopt, response1);
+  EXPECT_EQ(SmsStatus::kCancelled, sms_status1);
+
+  EXPECT_EQ("second", response2.value());
+  EXPECT_EQ(SmsStatus::kSuccess, sms_status2);
 }
 
 TEST_F(SmsServiceTest, CleansUp) {
@@ -401,8 +457,8 @@
   }));
 
   EXPECT_CALL(*service.delegate(), CreateSmsPrompt(main_rfh(), _, _, _, _))
-      .WillOnce(Invoke([&](RenderFrameHost*, const Origin&, const std::string&,
-                           base::OnceClosure, base::OnceClosure on_cancel) {
+      .WillOnce(Invoke([](RenderFrameHost*, const Origin&, const std::string&,
+                          base::OnceClosure, base::OnceClosure on_cancel) {
         // Simulates the user pressing "Cancel".
         std::move(on_cancel).Run();
       }));
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index c0542f59..8539522 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -6555,11 +6555,6 @@
   return CreateWebUI(url);
 }
 
-NavigationEntry*
-    WebContentsImpl::GetLastCommittedNavigationEntryForRenderManager() {
-  return controller_.GetLastCommittedEntry();
-}
-
 InterstitialPageImpl* WebContentsImpl::GetInterstitialForRenderManager() {
   return interstitial_page_;
 }
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 75d84cde..00784b2 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -861,7 +861,6 @@
       RenderFrameHost* old_host,
       RenderFrameHost* new_host) override;
   NavigationControllerImpl& GetControllerForRenderManager() override;
-  NavigationEntry* GetLastCommittedNavigationEntryForRenderManager() override;
   InterstitialPageImpl* GetInterstitialForRenderManager() override;
   bool FocusLocationBarByDefault() override;
   void SetFocusToLocationBar() override;
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index 7070753..741dd4e 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -504,7 +504,6 @@
   import_dirs = [ "//mojo/services" ]
 
   public_deps = [
-    "//components/services/leveldb/public/mojom",
     "//components/tracing/common:interfaces",
     "//content/public/common:interfaces",
     "//content/public/common:resource_type_bindings",
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/sms/Fakes.java b/content/public/android/javatests/src/org/chromium/content/browser/sms/Fakes.java
index 0769aa4..62d2e87 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/sms/Fakes.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/sms/Fakes.java
@@ -57,6 +57,24 @@
             return Tasks.forResult(null);
         }
 
+        @CalledByNative("FakeSmsRetrieverClient")
+        private Task<Void> triggerTimeout() {
+            Wrappers.SmsReceiverContext context = super.getContext();
+            if (context == null) {
+                Log.v(TAG, "FakeSmsRetrieverClient.triggerTimeout failed: no context was set");
+                return Tasks.forResult(null);
+            }
+
+            Intent intent = new Intent(SmsRetriever.SMS_RETRIEVED_ACTION);
+            Bundle bundle = new Bundle();
+            bundle.putParcelable(SmsRetriever.EXTRA_STATUS, new Status(CommonStatusCodes.TIMEOUT));
+            intent.putExtras(bundle);
+
+            BroadcastReceiver receiver = context.getRegisteredReceiver();
+            receiver.onReceive(context, intent);
+            return Tasks.forResult(null);
+        }
+
         // ---------------------------------------------------------------------
         // SmsRetrieverClient overrides:
 
diff --git a/content/public/test/browser_test_base.cc b/content/public/test/browser_test_base.cc
index 135a130..0aa69c07 100644
--- a/content/public/test/browser_test_base.cc
+++ b/content/public/test/browser_test_base.cc
@@ -252,6 +252,8 @@
     if (command_line->HasSwitch(switches::kUseVulkan)) {
       command_line->AppendSwitchASCII(
           switches::kUseVulkan, switches::kVulkanImplementationNameSwiftshader);
+      command_line->AppendSwitchASCII(
+          switches::kGrContextType, switches::kGrContextTypeVulkan);
     }
 #endif
   }
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index 0c99317..6412ca48 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -1791,17 +1791,17 @@
   return message.compare("\"SUCCESS\"") == 0;
 }
 
-std::string GetCookies(BrowserContext* browser_context, const GURL& url) {
+std::string GetCookies(BrowserContext* browser_context,
+                       const GURL& url,
+                       net::CookieOptions::SameSiteCookieContext context) {
   std::string cookies;
   base::RunLoop run_loop;
   mojo::Remote<network::mojom::CookieManager> cookie_manager;
   BrowserContext::GetDefaultStoragePartition(browser_context)
       ->GetNetworkContext()
       ->GetCookieManager(cookie_manager.BindNewPipeAndPassReceiver());
-  // Allow access to SameSite cookies in tests.
   net::CookieOptions options;
-  options.set_same_site_cookie_context(
-      net::CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT);
+  options.set_same_site_cookie_context(context);
   cookie_manager->GetCookieList(
       url, options,
       base::BindOnce(
@@ -1846,7 +1846,8 @@
 
 bool SetCookie(BrowserContext* browser_context,
                const GURL& url,
-               const std::string& value) {
+               const std::string& value,
+               net::CookieOptions::SameSiteCookieContext context) {
   bool result = false;
   base::RunLoop run_loop;
   mojo::Remote<network::mojom::CookieManager> cookie_manager;
@@ -1859,8 +1860,7 @@
 
   net::CookieOptions options;
   options.set_include_httponly();
-  options.set_same_site_cookie_context(
-      net::CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT);
+  options.set_same_site_cookie_context(context);
   cookie_manager->SetCanonicalCookie(
       *cc.get(), url.scheme(), options,
       base::BindOnce(
diff --git a/content/public/test/browser_test_utils.h b/content/public/test/browser_test_utils.h
index 2a5239c0..f3aa02f 100644
--- a/content/public/test/browser_test_utils.h
+++ b/content/public/test/browser_test_utils.h
@@ -821,18 +821,28 @@
 bool ExecuteWebUIResourceTest(WebContents* web_contents,
                               const std::vector<int>& js_resource_ids);
 
-// Returns the serialized cookie string for the given url.
-std::string GetCookies(BrowserContext* browser_context, const GURL& url);
+// Returns the serialized cookie string for the given url. Uses a strictly
+// same-site SameSiteCookieContext by default, which gets cookies regardless of
+// their SameSite attribute.
+std::string GetCookies(
+    BrowserContext* browser_context,
+    const GURL& url,
+    net::CookieOptions::SameSiteCookieContext context =
+        net::CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT);
 
 // Returns the canonical cookies for the given url.
 std::vector<net::CanonicalCookie> GetCanonicalCookies(
     BrowserContext* browser_context,
     const GURL& url);
 
-// Sets a cookie for the given url. Returns true on success.
+// Sets a cookie for the given url. Uses a strictly same-site
+// SameSiteCookieContext by default, which gets cookies regardless of their
+// SameSite attribute. Returns true on success.
 bool SetCookie(BrowserContext* browser_context,
                const GURL& url,
-               const std::string& value);
+               const std::string& value,
+               net::CookieOptions::SameSiteCookieContext context =
+                   net::CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT);
 
 // Fetch the histograms data from other processes. This should be called after
 // the test code has been executed but before performing assertions.
diff --git a/content/renderer/loader/web_worker_fetch_context_impl.cc b/content/renderer/loader/web_worker_fetch_context_impl.cc
index cd6f553..ab6286e6 100644
--- a/content/renderer/loader/web_worker_fetch_context_impl.cc
+++ b/content/renderer/loader/web_worker_fetch_context_impl.cc
@@ -104,7 +104,8 @@
   }
 
   void SetServiceWorkerURLLoaderFactory(
-      network::mojom::URLLoaderFactoryPtr service_worker_loader_factory) {
+      mojo::PendingRemote<network::mojom::URLLoaderFactory>
+          service_worker_loader_factory) {
     if (!service_worker_loader_factory) {
       service_worker_loader_factory_ = nullptr;
       return;
@@ -607,13 +608,14 @@
     return;
   if (GetControllerServiceWorkerMode() !=
       blink::mojom::ControllerServiceWorkerMode::kControlled) {
-    web_loader_factory_->SetServiceWorkerURLLoaderFactory(nullptr);
+    web_loader_factory_->SetServiceWorkerURLLoaderFactory(mojo::NullRemote());
     return;
   }
   if (!service_worker_container_host_)
     return;
 
-  network::mojom::URLLoaderFactoryPtr service_worker_url_loader_factory;
+  mojo::PendingRemote<network::mojom::URLLoaderFactory>
+      service_worker_url_loader_factory;
   mojo::PendingRemote<blink::mojom::ServiceWorkerContainerHost>
       service_worker_container_host;
   service_worker_container_host_->CloneContainerHost(
@@ -625,11 +627,12 @@
        base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
   task_runner->PostTask(
       FROM_HERE,
-      base::BindOnce(&CreateServiceWorkerSubresourceLoaderFactory,
-                     std::move(service_worker_container_host), client_id_,
-                     fallback_factory_->Clone(),
-                     mojo::MakeRequest(&service_worker_url_loader_factory),
-                     task_runner));
+      base::BindOnce(
+          &CreateServiceWorkerSubresourceLoaderFactory,
+          std::move(service_worker_container_host), client_id_,
+          fallback_factory_->Clone(),
+          service_worker_url_loader_factory.InitWithNewPipeAndPassReceiver(),
+          task_runner));
   web_loader_factory_->SetServiceWorkerURLLoaderFactory(
       std::move(service_worker_url_loader_factory));
 }
diff --git a/content/renderer/pepper/pepper_media_device_manager.cc b/content/renderer/pepper/pepper_media_device_manager.cc
index c0d486a..9b90bc4 100644
--- a/content/renderer/pepper/pepper_media_device_manager.cc
+++ b/content/renderer/pepper/pepper_media_device_manager.cc
@@ -273,8 +273,7 @@
 PepperMediaDeviceManager::GetMediaStreamDispatcherHost() {
   if (!dispatcher_host_) {
     CHECK(render_frame());
-    CHECK(render_frame()->GetRemoteInterfaces());
-    render_frame()->GetRemoteInterfaces()->GetInterface(
+    render_frame()->GetBrowserInterfaceBroker()->GetInterface(
         dispatcher_host_.BindNewPipeAndPassReceiver());
   }
   return dispatcher_host_.get();
@@ -294,8 +293,7 @@
 PepperMediaDeviceManager::GetMediaDevicesDispatcher() {
   if (!media_devices_dispatcher_) {
     CHECK(render_frame());
-    CHECK(render_frame()->GetRemoteInterfaces());
-    render_frame()->GetRemoteInterfaces()->GetInterface(
+    render_frame()->GetBrowserInterfaceBroker()->GetInterface(
         media_devices_dispatcher_.BindNewPipeAndPassReceiver());
   }
 
diff --git a/content/renderer/service_worker/service_worker_provider_context_unittest.cc b/content/renderer/service_worker/service_worker_provider_context_unittest.cc
index 18947e9..e62a299 100644
--- a/content/renderer/service_worker/service_worker_provider_context_unittest.cc
+++ b/content/renderer/service_worker/service_worker_provider_context_unittest.cc
@@ -276,8 +276,9 @@
   ServiceWorkerProviderContextTest() = default;
 
   void EnableNetworkService() {
-    network::mojom::URLLoaderFactoryPtr fake_loader_factory;
-    fake_loader_factory_.AddReceiver(MakeRequest(&fake_loader_factory));
+    mojo::PendingRemote<network::mojom::URLLoaderFactory> fake_loader_factory;
+    fake_loader_factory_.AddReceiver(
+        fake_loader_factory.InitWithNewPipeAndPassReceiver());
     loader_factory_ =
         base::MakeRefCounted<network::WrapperSharedURLLoaderFactory>(
             std::move(fake_loader_factory));
diff --git a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
index e34ee0e..2f124552 100644
--- a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
+++ b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
@@ -26,7 +26,6 @@
 #include "mojo/public/cpp/bindings/receiver_set.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
 #include "mojo/public/cpp/system/data_pipe_utils.h"
 #include "net/http/http_util.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
@@ -466,9 +465,10 @@
   ~ServiceWorkerSubresourceLoaderTest() override = default;
 
   void SetUp() override {
-    network::mojom::URLLoaderFactoryPtr fake_loader_factory;
-    mojo::MakeStrongBinding(std::make_unique<FakeNetworkURLLoaderFactory>(),
-                            MakeRequest(&fake_loader_factory));
+    mojo::PendingRemote<network::mojom::URLLoaderFactory> fake_loader_factory;
+    mojo::MakeSelfOwnedReceiver(
+        std::make_unique<FakeNetworkURLLoaderFactory>(),
+        fake_loader_factory.InitWithNewPipeAndPassReceiver());
     loader_factory_ =
         base::MakeRefCounted<network::WrapperSharedURLLoaderFactory>(
             std::move(fake_loader_factory));
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 644231b1..55e1e42 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -369,7 +369,6 @@
     ":content_test_mojo_bindings",
     "//base/third_party/dynamic_annotations",
     "//cc:test_support",
-    "//components/services/leveldb/public/mojom",
     "//components/viz/host",
     "//components/viz/service",
     "//content/app:both_for_content_tests",
diff --git a/fuchsia/base/fake_component_context.cc b/fuchsia/base/fake_component_context.cc
index b551d18b..2da4172 100644
--- a/fuchsia/base/fake_component_context.cc
+++ b/fuchsia/base/fake_component_context.cc
@@ -11,6 +11,7 @@
 #include <utility>
 
 #include "base/logging.h"
+#include "base/run_loop.h"
 
 namespace cr_fuchsia {
 
@@ -45,6 +46,9 @@
   NOTIMPLEMENTED() << " API: " << name;
 }
 
-FakeComponentContext::~FakeComponentContext() = default;
+FakeComponentContext::~FakeComponentContext() {
+  agent_services_.Unbind();
+  base::RunLoop().RunUntilIdle();
+}
 
 }  // namespace cr_fuchsia
diff --git a/gpu/command_buffer/service/gpu_switches.cc b/gpu/command_buffer/service/gpu_switches.cc
index 484a13d..35b0614 100644
--- a/gpu/command_buffer/service/gpu_switches.cc
+++ b/gpu/command_buffer/service/gpu_switches.cc
@@ -62,6 +62,11 @@
 // round intermediate values in ANGLE.
 const char kEmulateShaderPrecision[] = "emulate-shader-precision";
 
+// Selects the type of the GrContext.
+const char kGrContextType[] = "gr-context-type";
+const char kGrContextTypeGL[] = "gl";
+const char kGrContextTypeVulkan[] = "vulkan";
+const char kGrContextTypeMetal[] = "metal";
 // Enable Vulkan support and select Vulkan implementation, must also have
 // ENABLE_VULKAN defined.
 const char kUseVulkan[] = "use-vulkan";
diff --git a/gpu/command_buffer/service/gpu_switches.h b/gpu/command_buffer/service/gpu_switches.h
index e9b9fdf..3aa3fccd 100644
--- a/gpu/command_buffer/service/gpu_switches.h
+++ b/gpu/command_buffer/service/gpu_switches.h
@@ -28,6 +28,11 @@
 GPU_EXPORT extern const char kEnableThreadedTextureMailboxes[];
 GPU_EXPORT extern const char kGLShaderIntermOutput[];
 GPU_EXPORT extern const char kEmulateShaderPrecision[];
+GPU_EXPORT extern const char kGrContextType[];
+GPU_EXPORT extern const char kGrContextTypeGL[];
+GPU_EXPORT extern const char kGrContextTypeVulkan[];
+GPU_EXPORT extern const char kGrContextTypeMetal[];
+GPU_EXPORT extern const char kVulkanImplementationNameNative[];
 GPU_EXPORT extern const char kUseVulkan[];
 GPU_EXPORT extern const char kVulkanImplementationNameNative[];
 GPU_EXPORT extern const char kVulkanImplementationNameSwiftshader[];
diff --git a/gpu/command_buffer/service/raster_decoder_unittest.cc b/gpu/command_buffer/service/raster_decoder_unittest.cc
index 4d50d17..52844f9 100644
--- a/gpu/command_buffer/service/raster_decoder_unittest.cc
+++ b/gpu/command_buffer/service/raster_decoder_unittest.cc
@@ -296,7 +296,8 @@
 
     context_state_ = base::MakeRefCounted<SharedContextState>(
         std::move(share_group), std::move(surface), std::move(context),
-        false /* use_virtualized_gl_contexts */, base::DoNothing());
+        false /* use_virtualized_gl_contexts */, base::DoNothing(),
+        GpuPreferences().gr_context_type);
     context_state_->InitializeGrContext(workarounds, nullptr);
     context_state_->InitializeGL(GpuPreferences(), feature_info);
   }
diff --git a/gpu/command_buffer/service/raster_decoder_unittest_base.cc b/gpu/command_buffer/service/raster_decoder_unittest_base.cc
index 86f8509..135dc082 100644
--- a/gpu/command_buffer/service/raster_decoder_unittest_base.cc
+++ b/gpu/command_buffer/service/raster_decoder_unittest_base.cc
@@ -183,7 +183,7 @@
   shared_context_state_ = base::MakeRefCounted<SharedContextState>(
       new gl::GLShareGroup(), surface_, context_,
       feature_info()->workarounds().use_virtualized_gl_contexts,
-      base::DoNothing());
+      base::DoNothing(), GpuPreferences().gr_context_type);
 
   shared_context_state_->InitializeGL(GpuPreferences(), feature_info_);
 
diff --git a/gpu/command_buffer/service/service_utils.cc b/gpu/command_buffer/service/service_utils.cc
index b7e5ae0..e65a025 100644
--- a/gpu/command_buffer/service/service_utils.cc
+++ b/gpu/command_buffer/service/service_utils.cc
@@ -173,6 +173,34 @@
   }
   gpu_preferences.disable_vulkan_surface =
       command_line->HasSwitch(switches::kDisableVulkanSurface);
+  if (command_line->HasSwitch(switches::kGrContextType)) {
+    auto value = command_line->GetSwitchValueASCII(switches::kGrContextType);
+    if (value == switches::kGrContextTypeGL) {
+      gpu_preferences.gr_context_type = GrContextType::kGL;
+    } else if (value == switches::kGrContextTypeVulkan) {
+      DCHECK(gpu_preferences.use_vulkan != VulkanImplementationName::kNone)
+          << "GrContextType is Vulkan, but Vulkan is not enabled.";
+      gpu_preferences.gr_context_type = GrContextType::kVulkan;
+    } else if (value == switches::kGrContextTypeMetal) {
+#if defined(OS_MACOSX)
+      DCHECK(base::FeatureList::IsEnabled(features::kMetal))
+          << "GrContextType is Metal, but Metal is not enabled.";
+      gpu_preferences.gr_context_type = GrContextType::kMetal;
+#endif
+    } else {
+      NOTREACHED() << "Invalid GrContextType.";
+      gpu_preferences.gr_context_type = GrContextType::kGL;
+    }
+  } else {
+#if defined(OS_MACOSX)
+    gpu_preferences.gr_context_type =
+        base::FeatureList::IsEnabled(features::kMetal) ?
+            GrContextType::kMetal :
+            GrContextType::kGL;
+#else
+    gpu_preferences.gr_context_type = GrContextType::kGL;
+#endif
+  }
   return gpu_preferences;
 }
 
diff --git a/gpu/command_buffer/service/shared_context_state.cc b/gpu/command_buffer/service/shared_context_state.cc
index 37897dc..8f7c628 100644
--- a/gpu/command_buffer/service/shared_context_state.cc
+++ b/gpu/command_buffer/service/shared_context_state.cc
@@ -49,10 +49,12 @@
     scoped_refptr<gl::GLContext> context,
     bool use_virtualized_gl_contexts,
     base::OnceClosure context_lost_callback,
+    GrContextType gr_context_type,
     viz::VulkanContextProvider* vulkan_context_provider,
     viz::MetalContextProvider* metal_context_provider)
     : use_virtualized_gl_contexts_(use_virtualized_gl_contexts),
       context_lost_callback_(std::move(context_lost_callback)),
+      gr_context_type_(gr_context_type),
       vk_context_provider_(vulkan_context_provider),
       metal_context_provider_(metal_context_provider),
       share_group_(std::move(share_group)),
diff --git a/gpu/command_buffer/service/shared_context_state.h b/gpu/command_buffer/service/shared_context_state.h
index 8eaa2782..6ceaa8c6 100644
--- a/gpu/command_buffer/service/shared_context_state.h
+++ b/gpu/command_buffer/service/shared_context_state.h
@@ -16,6 +16,7 @@
 #include "build/build_config.h"
 #include "gpu/command_buffer/common/skia_utils.h"
 #include "gpu/command_buffer/service/gl_context_virtual_delegate.h"
+#include "gpu/config/gpu_preferences.h"
 #include "gpu/gpu_gles2_export.h"
 #include "third_party/skia/include/gpu/GrContext.h"
 #include "ui/gl/progress_reporter.h"
@@ -35,7 +36,6 @@
 class GpuDriverBugWorkarounds;
 class GpuProcessActivityFlags;
 class ServiceTransferCache;
-struct GpuPreferences;
 
 namespace gles2 {
 class FeatureInfo;
@@ -56,6 +56,7 @@
       scoped_refptr<gl::GLContext> context,
       bool use_virtualized_gl_contexts,
       base::OnceClosure context_lost_callback,
+      GrContextType gr_context_type = GrContextType::kGL,
       viz::VulkanContextProvider* vulkan_context_provider = nullptr,
       viz::MetalContextProvider* metal_context_provider = nullptr);
 
@@ -64,10 +65,15 @@
                            GpuProcessActivityFlags* activity_flags = nullptr,
                            gl::ProgressReporter* progress_reporter = nullptr);
   bool GrContextIsGL() const {
-    return !vk_context_provider_ && !metal_context_provider_;
+    return gr_context_type_ == GrContextType::kGL;
   }
-  bool GrContextIsVulkan() const { return vk_context_provider_; }
-  bool GrContextIsMetal() const { return metal_context_provider_; }
+  bool GrContextIsVulkan() const {
+    return vk_context_provider_ && gr_context_type_ == GrContextType::kVulkan;
+  }
+  bool GrContextIsMetal() const {
+    return metal_context_provider_ &&
+        gr_context_type_ == GrContextType::kMetal;
+  }
 
   bool InitializeGL(const GpuPreferences& gpu_preferences,
                     scoped_refptr<gles2::FeatureInfo> feature_info);
@@ -161,6 +167,7 @@
   bool use_virtualized_gl_contexts_ = false;
   bool support_vulkan_external_object_ = false;
   base::OnceClosure context_lost_callback_;
+  GrContextType gr_context_type_ = GrContextType::kGL;
   viz::VulkanContextProvider* const vk_context_provider_;
   viz::MetalContextProvider* const metal_context_provider_;
   GrContext* gr_context_ = nullptr;
diff --git a/gpu/command_buffer/tests/fuzzer_main.cc b/gpu/command_buffer/tests/fuzzer_main.cc
index f2f66e5..a6633813 100644
--- a/gpu/command_buffer/tests/fuzzer_main.cc
+++ b/gpu/command_buffer/tests/fuzzer_main.cc
@@ -376,7 +376,8 @@
     shared_context->MakeCurrent(surface_.get());
     context_state_ = base::MakeRefCounted<SharedContextState>(
         share_group_, surface_, std::move(shared_context),
-        config_.workarounds.use_virtualized_gl_contexts, base::DoNothing());
+        config_.workarounds.use_virtualized_gl_contexts, base::DoNothing(),
+        gpu_preferences_.gr_context_type);
     context_state_->InitializeGrContext(config_.workarounds, nullptr);
     context_state_->InitializeGL(gpu_preferences_, feature_info);
 
diff --git a/gpu/command_buffer/tests/webgpu_test.cc b/gpu/command_buffer/tests/webgpu_test.cc
index 99dfb66..db56128 100644
--- a/gpu/command_buffer/tests/webgpu_test.cc
+++ b/gpu/command_buffer/tests/webgpu_test.cc
@@ -44,6 +44,7 @@
   gpu_preferences.enable_webgpu = true;
 #if defined(OS_LINUX) && BUILDFLAG(USE_DAWN)
   gpu_preferences.use_vulkan = gpu::VulkanImplementationName::kNative;
+  gpu_preferences.gr_context_type = gpu::GrContextType::kVulkan;
 #endif
   gpu_service_holder_ =
       std::make_unique<viz::TestGpuServiceHolder>(gpu_preferences);
diff --git a/gpu/config/gpu_preferences.h b/gpu/config/gpu_preferences.h
index 656b72c..4a0b4052 100644
--- a/gpu/config/gpu_preferences.h
+++ b/gpu/config/gpu_preferences.h
@@ -37,6 +37,13 @@
   kLast = kSwiftshader,
 };
 
+enum class GrContextType : uint32_t {
+  kGL = 0,
+  kVulkan = 1,
+  kMetal = 2,
+  kLast = kMetal,
+};
+
 // NOTE: if you modify this structure then you must also modify the
 // following two files to keep them in sync:
 //   src/gpu/ipc/common/gpu_preferences.mojom
@@ -197,6 +204,9 @@
 
   // ===================================
   // Settings from //gpu/command_buffer/service/gpu_switches.h
+  // The type of the GrContext.
+  GrContextType gr_context_type = GrContextType::kGL;
+
   // Use Vulkan for rasterization and display compositing.
   VulkanImplementationName use_vulkan = VulkanImplementationName::kNone;
 
diff --git a/gpu/config/gpu_preferences_unittest.cc b/gpu/config/gpu_preferences_unittest.cc
index 35fc0b9..63669f57 100644
--- a/gpu/config/gpu_preferences_unittest.cc
+++ b/gpu/config/gpu_preferences_unittest.cc
@@ -69,6 +69,7 @@
   EXPECT_EQ(left.disable_oop_rasterization, right.disable_oop_rasterization);
   EXPECT_EQ(left.watchdog_starts_backgrounded,
             right.watchdog_starts_backgrounded);
+  EXPECT_EQ(left.gr_context_type, right.gr_context_type);
   EXPECT_EQ(left.use_vulkan, right.use_vulkan);
   EXPECT_EQ(left.enable_gpu_benchmarking_extension,
             right.enable_gpu_benchmarking_extension);
@@ -154,6 +155,9 @@
     GPU_PREFERENCES_FIELD(enable_oop_rasterization, true)
     GPU_PREFERENCES_FIELD(disable_oop_rasterization, true)
     GPU_PREFERENCES_FIELD(watchdog_starts_backgrounded, true)
+    GPU_PREFERENCES_FIELD_ENUM(gr_context_type,
+                               GrContextType::kVulkan,
+                               mojom::GrContextType::kVulkan)
     GPU_PREFERENCES_FIELD_ENUM(use_vulkan, VulkanImplementationName::kNative,
                                mojom::VulkanImplementationName::kNative)
     GPU_PREFERENCES_FIELD(enable_gpu_benchmarking_extension, true)
diff --git a/gpu/ipc/common/gpu_preferences.mojom b/gpu/ipc/common/gpu_preferences.mojom
index 3fd75af7..3e70fa78 100644
--- a/gpu/ipc/common/gpu_preferences.mojom
+++ b/gpu/ipc/common/gpu_preferences.mojom
@@ -19,6 +19,14 @@
   kLast = kSwiftshader,
 };
 
+// Corresponds to gpu::GrContextType.
+enum GrContextType {
+  kGL = 0,
+  kVulkan = 1,
+  kMetal = 2,
+  kLast = kMetal,
+};
+
 // gpu::GpuPreferences
 struct GpuPreferences {
   bool disable_accelerated_video_decode;
@@ -65,6 +73,7 @@
   bool disable_oop_rasterization;
   bool enable_oop_rasterization_ddl;
   bool watchdog_starts_backgrounded;
+  GrContextType gr_context_type;
   VulkanImplementationName use_vulkan;
   bool enforce_vulkan_protected_memory;
   bool disable_vulkan_surface;
diff --git a/gpu/ipc/common/gpu_preferences_mojom_traits.h b/gpu/ipc/common/gpu_preferences_mojom_traits.h
index a481a354..26ce310 100644
--- a/gpu/ipc/common/gpu_preferences_mojom_traits.h
+++ b/gpu/ipc/common/gpu_preferences_mojom_traits.h
@@ -19,6 +19,37 @@
 namespace mojo {
 
 template <>
+struct EnumTraits<gpu::mojom::GrContextType, gpu::GrContextType> {
+  static gpu::mojom::GrContextType ToMojom(gpu::GrContextType input) {
+    switch (input) {
+      case gpu::GrContextType::kGL:
+        return gpu::mojom::GrContextType::kGL;
+      case gpu::GrContextType::kVulkan:
+        return gpu::mojom::GrContextType::kVulkan;
+      case gpu::GrContextType::kMetal:
+        return gpu::mojom::GrContextType::kMetal;
+    }
+    NOTREACHED();
+    return gpu::mojom::GrContextType::kGL;
+  }
+  static bool FromMojom(gpu::mojom::GrContextType input,
+                        gpu::GrContextType* out) {
+    switch (input) {
+      case gpu::mojom::GrContextType::kGL:
+        *out = gpu::GrContextType::kGL;
+        return true;
+      case gpu::mojom::GrContextType::kVulkan:
+        *out = gpu::GrContextType::kVulkan;
+        return true;
+      case gpu::mojom::GrContextType::kMetal:
+        *out = gpu::GrContextType::kMetal;
+        return true;
+    }
+    return false;
+  }
+};
+
+template <>
 struct EnumTraits<gpu::mojom::VulkanImplementationName,
                   gpu::VulkanImplementationName> {
   static gpu::mojom::VulkanImplementationName ToMojom(
@@ -120,6 +151,8 @@
     out->disable_oop_rasterization = prefs.disable_oop_rasterization();
     out->enable_oop_rasterization_ddl = prefs.enable_oop_rasterization_ddl();
     out->watchdog_starts_backgrounded = prefs.watchdog_starts_backgrounded();
+    if (!prefs.ReadGrContextType(&out->gr_context_type))
+      return false;
     if (!prefs.ReadUseVulkan(&out->use_vulkan))
       return false;
     out->enforce_vulkan_protected_memory =
@@ -265,6 +298,9 @@
   static bool watchdog_starts_backgrounded(const gpu::GpuPreferences& prefs) {
     return prefs.watchdog_starts_backgrounded;
   }
+  static gpu::GrContextType gr_context_type(const gpu::GpuPreferences& prefs) {
+    return prefs.gr_context_type;
+  }
   static gpu::VulkanImplementationName use_vulkan(
       const gpu::GpuPreferences& prefs) {
     return prefs.use_vulkan;
diff --git a/gpu/ipc/in_process_command_buffer.cc b/gpu/ipc/in_process_command_buffer.cc
index 4b98aab3..5e8fb4ed 100644
--- a/gpu/ipc/in_process_command_buffer.cc
+++ b/gpu/ipc/in_process_command_buffer.cc
@@ -680,7 +680,8 @@
       if (!context_state_) {
         context_state_ = base::MakeRefCounted<SharedContextState>(
             gl_share_group_, surface_, real_context,
-            use_virtualized_gl_context_, base::DoNothing());
+            use_virtualized_gl_context_, base::DoNothing(),
+            task_executor_->gpu_preferences().gr_context_type);
         context_state_->InitializeGL(task_executor_->gpu_preferences(),
                                      context_group_->feature_info());
         context_state_->InitializeGrContext(workarounds, params.gr_shader_cache,
diff --git a/gpu/ipc/service/gpu_channel_manager.cc b/gpu/ipc/service/gpu_channel_manager.cc
index 1cacaa4c..155e6d8 100644
--- a/gpu/ipc/service/gpu_channel_manager.cc
+++ b/gpu/ipc/service/gpu_channel_manager.cc
@@ -481,6 +481,7 @@
       use_virtualized_gl_contexts,
       base::BindOnce(&GpuChannelManager::OnContextLost, base::Unretained(this),
                      /*synthetic_loss=*/false),
+      gpu_preferences_.gr_context_type,
       vulkan_context_provider_, metal_context_provider_);
 
   // OOP-R needs GrContext for raster tiles.
@@ -492,7 +493,7 @@
   need_gr_context |= features::IsUsingSkiaRenderer();
 
   if (need_gr_context) {
-    if (!vulkan_context_provider_ && !metal_context_provider_) {
+    if (gpu_preferences_.gr_context_type == gpu::GrContextType::kGL) {
       auto feature_info = base::MakeRefCounted<gles2::FeatureInfo>(
           gpu_driver_bug_workarounds(), gpu_feature_info());
       if (!shared_context_state_->InitializeGL(gpu_preferences_,
diff --git a/gpu/ipc/service/gpu_channel_manager.h b/gpu/ipc/service/gpu_channel_manager.h
index a8abfe5..6ef78ef 100644
--- a/gpu/ipc/service/gpu_channel_manager.h
+++ b/gpu/ipc/service/gpu_channel_manager.h
@@ -288,7 +288,8 @@
   scoped_refptr<SharedContextState> shared_context_state_;
 
   // With --enable-vulkan, |vulkan_context_provider_| will be set from
-  // viz::GpuServiceImpl. The raster decoders will use it for rasterization.
+  // viz::GpuServiceImpl. The raster decoders will use it for rasterization if
+  // --gr-context-type is also set to Vulkan.
   viz::VulkanContextProvider* vulkan_context_provider_ = nullptr;
 
   // If features::SkiaOnMetad, |metal_context_provider_| will be set from
diff --git a/gpu/ipc/service/gpu_init.cc b/gpu/ipc/service/gpu_init.cc
index 0aa6832..d7d124b8b 100644
--- a/gpu/ipc/service/gpu_init.cc
+++ b/gpu/ipc/service/gpu_init.cc
@@ -377,6 +377,9 @@
     }
   }
   if (!vulkan_implementation_) {
+    if (gpu_preferences_.gr_context_type == gpu::GrContextType::kVulkan) {
+      gpu_preferences_.gr_context_type = gpu::GrContextType::kGL;
+    }
     gpu_preferences_.use_vulkan = gpu::VulkanImplementationName::kNone;
     gpu_feature_info_.status_values[gpu::GPU_FEATURE_TYPE_VULKAN] =
         gpu::kGpuFeatureStatusDisabled;
diff --git a/infra/config/buckets/try.star b/infra/config/buckets/try.star
index 37613cc..847d6773 100644
--- a/infra/config/buckets/try.star
+++ b/infra/config/buckets/try.star
@@ -1415,6 +1415,10 @@
 )
 
 linux_builder(
+    name = 'linux-layout-tests-fragment-item',
+)
+
+linux_builder(
     name = 'linux_mojo',
     goma_backend = goma.backend.RBE_PROD,
 )
diff --git a/infra/config/consoles/luci.chromium.try.star b/infra/config/consoles/luci.chromium.try.star
index e536b3a..1685e7b 100644
--- a/infra/config/consoles/luci.chromium.try.star
+++ b/infra/config/consoles/luci.chromium.try.star
@@ -129,6 +129,7 @@
         'try/linux_chromium_tsan_rel_ng',
         'try/linux_chromium_ubsan_rel_ng',
         'try/linux_layout_tests_composite_after_paint',
+        'try/linux-layout-tests-fragment-item',
         'try/linux_layout_tests_layout_ng_disabled',
         'try/linux_mojo',
         'try/linux_mojo_chromeos',
diff --git a/infra/config/consoles/tryserver.chromium.linux.star b/infra/config/consoles/tryserver.chromium.linux.star
index 556dfef..cb67065 100644
--- a/infra/config/consoles/tryserver.chromium.linux.star
+++ b/infra/config/consoles/tryserver.chromium.linux.star
@@ -48,6 +48,7 @@
         'try/linux_chromium_tsan_rel_ng',
         'try/linux_chromium_ubsan_rel_ng',
         'try/linux_layout_tests_composite_after_paint',
+        'try/linux-layout-tests-fragment-item',
         'try/linux_layout_tests_layout_ng_disabled',
         'try/linux_mojo',
         'try/linux_mojo_chromeos',
diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg
index 9c94c98..689687b 100644
--- a/infra/config/generated/cr-buildbucket.cfg
+++ b/infra/config/generated/cr-buildbucket.cfg
@@ -13840,6 +13840,34 @@
       >
     >
     builders: <
+      name: "linux-layout-tests-fragment-item"
+      swarming_host: "chromium-swarm.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      dimensions: "builderless:1"
+      dimensions: "cores:8"
+      dimensions: "cpu:x86-64"
+      dimensions: "os:Ubuntu-16.04"
+      dimensions: "ssd:0"
+      recipe: <
+        name: "chromium_trybot"
+        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
+        cipd_version: "refs/heads/master"
+        properties_j: "$kitchen:{\"devshell\":true,\"git_auth\":true}"
+        properties_j: "mastername:\"tryserver.chromium.linux\""
+      >
+      execution_timeout_secs: 14400
+      expiration_secs: 7200
+      caches: <
+        name: "win_toolchain"
+        path: "win_toolchain"
+      >
+      build_numbers: YES
+      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
+      task_template_canary_percentage: <
+        value: 5
+      >
+    >
+    builders: <
       name: "linux-libfuzzer-asan-rel"
       swarming_host: "chromium-swarm.appspot.com"
       swarming_tags: "vpython:native-python-wrapper"
diff --git a/infra/config/generated/luci-milo-dev.cfg b/infra/config/generated/luci-milo-dev.cfg
index 5af9f567..340e802d 100644
--- a/infra/config/generated/luci-milo-dev.cfg
+++ b/infra/config/generated/luci-milo-dev.cfg
@@ -179,8 +179,6 @@
 consoles {
   id: "snapshots"
   builder_view_only: true
-  header_id: "chromium"
-  manifest_name: "REVISION"
   name: "Snapshot Builder"
   builders {
     name: "buildbucket/luci.chromium.cron/Snapshot Builder"
diff --git a/infra/config/generated/luci-milo.cfg b/infra/config/generated/luci-milo.cfg
index 66ad962e..27f24c0 100644
--- a/infra/config/generated/luci-milo.cfg
+++ b/infra/config/generated/luci-milo.cfg
@@ -8986,6 +8986,9 @@
     name: "buildbucket/luci.chromium.try/linux_layout_tests_composite_after_paint"
   >
   builders: <
+    name: "buildbucket/luci.chromium.try/linux-layout-tests-fragment-item"
+  >
+  builders: <
     name: "buildbucket/luci.chromium.try/linux_layout_tests_layout_ng_disabled"
   >
   builders: <
@@ -10474,6 +10477,9 @@
     name: "buildbucket/luci.chromium.try/linux_layout_tests_composite_after_paint"
   >
   builders: <
+    name: "buildbucket/luci.chromium.try/linux-layout-tests-fragment-item"
+  >
+  builders: <
     name: "buildbucket/luci.chromium.try/linux_layout_tests_layout_ng_disabled"
   >
   builders: <
diff --git a/infra/config/luci-milo-dev.cfg b/infra/config/luci-milo-dev.cfg
index 5af9f567..340e802d 100644
--- a/infra/config/luci-milo-dev.cfg
+++ b/infra/config/luci-milo-dev.cfg
@@ -179,8 +179,6 @@
 consoles {
   id: "snapshots"
   builder_view_only: true
-  header_id: "chromium"
-  manifest_name: "REVISION"
   name: "Snapshot Builder"
   builders {
     name: "buildbucket/luci.chromium.cron/Snapshot Builder"
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_impl_io_data.h b/ios/chrome/browser/browser_state/chrome_browser_state_impl_io_data.h
index 7803dfd..4a8e736 100644
--- a/ios/chrome/browser/browser_state/chrome_browser_state_impl_io_data.h
+++ b/ios/chrome/browser/browser_state/chrome_browser_state_impl_io_data.h
@@ -22,6 +22,7 @@
 class CookieStore;
 class HttpNetworkSession;
 class HttpTransactionFactory;
+class URLRequestJobFactoryImpl;
 }  // namespace net
 
 class ChromeBrowserStateImplIOData : public ChromeBrowserStateIOData {
@@ -129,7 +130,7 @@
 
   mutable std::unique_ptr<net::CookieStore> main_cookie_store_;
 
-  mutable std::unique_ptr<net::URLRequestJobFactory> main_job_factory_;
+  mutable std::unique_ptr<net::URLRequestJobFactoryImpl> main_job_factory_;
 
   // Parameters needed for isolated apps.
   base::FilePath profile_path_;
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_impl_io_data.mm b/ios/chrome/browser/browser_state/chrome_browser_state_impl_io_data.mm
index a1b3c61d..24b74bb 100644
--- a/ios/chrome/browser/browser_state/chrome_browser_state_impl_io_data.mm
+++ b/ios/chrome/browser/browser_state/chrome_browser_state_impl_io_data.mm
@@ -226,12 +226,9 @@
                                              std::move(main_backend));
   main_context->set_http_transaction_factory(main_http_factory_.get());
 
-  std::unique_ptr<net::URLRequestJobFactoryImpl> main_job_factory(
-      new net::URLRequestJobFactoryImpl());
-  InstallProtocolHandlers(main_job_factory.get(), protocol_handlers);
+  main_job_factory_ = std::make_unique<net::URLRequestJobFactoryImpl>();
+  InstallProtocolHandlers(main_job_factory_.get(), protocol_handlers);
 
-  main_job_factory_ = SetUpJobFactoryDefaults(std::move(main_job_factory),
-                                              main_context->network_delegate());
   main_context->set_job_factory(main_job_factory_.get());
 
   lazy_params_.reset();
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_io_data.h b/ios/chrome/browser/browser_state/chrome_browser_state_io_data.h
index 8b034f8d..3a4581d 100644
--- a/ios/chrome/browser/browser_state/chrome_browser_state_io_data.h
+++ b/ios/chrome/browser/browser_state/chrome_browser_state_io_data.h
@@ -166,10 +166,6 @@
   void InitializeOnUIThread(ios::ChromeBrowserState* browser_state);
   void ApplyProfileParamsToContext(net::URLRequestContext* context) const;
 
-  std::unique_ptr<net::URLRequestJobFactory> SetUpJobFactoryDefaults(
-      std::unique_ptr<net::URLRequestJobFactoryImpl> job_factory,
-      net::NetworkDelegate* network_delegate) const;
-
   // Called when the ChromeBrowserState is destroyed. |context_getters| must
   // include all URLRequestContextGetters that refer to the
   // ChromeBrowserStateIOData's URLRequestContexts. Triggers destruction of the
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_io_data.mm b/ios/chrome/browser/browser_state/chrome_browser_state_io_data.mm
index dbbf43f2..30fd161d 100644
--- a/ios/chrome/browser/browser_state/chrome_browser_state_io_data.mm
+++ b/ios/chrome/browser/browser_state/chrome_browser_state_io_data.mm
@@ -57,7 +57,6 @@
 #include "net/proxy_resolution/proxy_config_service_fixed.h"
 #include "net/proxy_resolution/proxy_resolution_service.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/data_protocol_handler.h"
 #include "net/url_request/report_sender.h"
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_context.h"
@@ -374,17 +373,6 @@
   context->set_http_user_agent_settings(chrome_http_user_agent_settings_.get());
 }
 
-std::unique_ptr<net::URLRequestJobFactory>
-ChromeBrowserStateIOData::SetUpJobFactoryDefaults(
-    std::unique_ptr<net::URLRequestJobFactoryImpl> job_factory,
-    net::NetworkDelegate* network_delegate) const {
-  bool set_protocol = job_factory->SetProtocolHandler(
-      url::kDataScheme, std::make_unique<net::DataProtocolHandler>());
-  DCHECK(set_protocol);
-
-  return job_factory;
-}
-
 void ChromeBrowserStateIOData::ShutdownOnUIThread(
     std::unique_ptr<IOSChromeURLRequestContextGetterVector> context_getters) {
   DCHECK_CURRENTLY_ON(web::WebThread::UI);
diff --git a/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_io_data.h b/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_io_data.h
index a7b6bfc4..16dd13c6 100644
--- a/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_io_data.h
+++ b/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_io_data.h
@@ -24,6 +24,7 @@
 class CookieStore;
 class HttpNetworkSession;
 class HttpTransactionFactory;
+class URLRequestJobFactoryImpl;
 }  // namespace net
 
 // OffTheRecordChromeBrowserState owns a
@@ -101,7 +102,7 @@
 
   mutable std::unique_ptr<net::CookieStore> main_cookie_store_;
 
-  mutable std::unique_ptr<net::URLRequestJobFactory> main_job_factory_;
+  mutable std::unique_ptr<net::URLRequestJobFactoryImpl> main_job_factory_;
 
   // Server bound certificates and cookies are persisted to the disk on iOS.
   base::FilePath cookie_path_;
diff --git a/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_io_data.mm b/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_io_data.mm
index efeda60..b22bf6d 100644
--- a/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_io_data.mm
+++ b/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_io_data.mm
@@ -186,11 +186,8 @@
 
   main_context->set_http_transaction_factory(main_http_factory_.get());
 
-  std::unique_ptr<net::URLRequestJobFactoryImpl> main_job_factory(
-      new net::URLRequestJobFactoryImpl());
+  main_job_factory_ = std::make_unique<net::URLRequestJobFactoryImpl>();
 
-  InstallProtocolHandlers(main_job_factory.get(), protocol_handlers);
-  main_job_factory_ = SetUpJobFactoryDefaults(std::move(main_job_factory),
-                                              main_context->network_delegate());
+  InstallProtocolHandlers(main_job_factory_.get(), protocol_handlers);
   main_context->set_job_factory(main_job_factory_.get());
 }
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index b658a9e..717843fa 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -564,6 +564,10 @@
      flag_descriptions::kSaveCardInfobarMessagesUIName,
      flag_descriptions::kSaveCardInfobarMessagesUIDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(kSaveCardInfobarMessagesUI)},
+    {"messages-translate-infobar",
+     flag_descriptions::kTranslateInfobarMessagesUIName,
+     flag_descriptions::kTranslateInfobarMessagesUIDescription,
+     flags_ui::kOsIos, FEATURE_VALUE_TYPE(kTranslateInfobarMessagesUI)},
 };
 
 // Add all switches from experimental flags to |command_line|.
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
index a7e7738..52e6d6b 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -365,6 +365,11 @@
 const char kToolbarNewTabButtonDescription[] =
     "When enabled, the bottom toolbar middle button opens a new tab";
 
+const char kTranslateInfobarMessagesUIName[] =
+    "Enable Translate Infobar Messages UI";
+const char kTranslateInfobarMessagesUIDescription[] =
+    "When enabled, the Translate Infobar uses the new Messages UI.";
+
 const char kUseDdljsonApiName[] = "Use new ddljson API for Doodles";
 const char kUseDdljsonApiDescription[] =
     "Enables the new ddljson API to fetch Doodles for the NTP.";
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
index 2aa9c79..341f119 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -320,6 +320,11 @@
 extern const char kToolbarNewTabButtonName[];
 extern const char kToolbarNewTabButtonDescription[];
 
+// Title and description for the flag to enable the Messages UI for Translate
+// Infobars.
+extern const char kTranslateInfobarMessagesUIName[];
+extern const char kTranslateInfobarMessagesUIDescription[];
+
 // Title and description for the flag to enable the ddljson Doodle API.
 extern const char kUseDdljsonApiName[];
 extern const char kUseDdljsonApiDescription[];
diff --git a/ios/chrome/browser/ui/badges/BUILD.gn b/ios/chrome/browser/ui/badges/BUILD.gn
index a2bca236..1f237ea 100644
--- a/ios/chrome/browser/ui/badges/BUILD.gn
+++ b/ios/chrome/browser/ui/badges/BUILD.gn
@@ -68,6 +68,7 @@
     ":badges",
     ":public",
     "//base",
+    "//ios/chrome/app/strings:ios_strings_grit",
     "//ios/chrome/browser/infobars:public",
     "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/commands",
@@ -80,6 +81,7 @@
     "//ios/chrome/browser/ui/util",
     "//ios/chrome/common/colors",
     "//ios/chrome/common/ui_util",
+    "//ui/base",
   ]
 }
 
diff --git a/ios/chrome/browser/ui/badges/badge_popup_menu_item.mm b/ios/chrome/browser/ui/badges/badge_popup_menu_item.mm
index 5cfc8d2..ca47755 100644
--- a/ios/chrome/browser/ui/badges/badge_popup_menu_item.mm
+++ b/ios/chrome/browser/ui/badges/badge_popup_menu_item.mm
@@ -9,6 +9,8 @@
 #import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h"
 #import "ios/chrome/common/colors/semantic_color_names.h"
 #import "ios/chrome/common/ui_util/constraints_ui_util.h"
+#include "ios/chrome/grit/ios_strings.h"
+#include "ui/base/l10n/l10n_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -49,11 +51,13 @@
     switch (badgeType) {
       case BadgeType::kBadgeTypePasswordSave:
         _actionIdentifier = PopupMenuActionShowSavePasswordOptions;
-        _title = @"Save Password";
+        _title = l10n_util::GetNSString(
+            IDS_IOS_PASSWORD_MANAGER_SAVE_PASSWORD_TITLE);
         break;
       case BadgeType::kBadgeTypePasswordUpdate:
         _actionIdentifier = PopupMenuActionShowUpdatePasswordOptions;
-        _title = @"Update Password";
+        _title = l10n_util::GetNSString(
+            IDS_IOS_PASSWORD_MANAGER_UPDATE_PASSWORD_TITLE);
         break;
       case BadgeType::kBadgeTypeSaveCard:
         _actionIdentifier = PopupMenuActionShowSaveCardOptions;
diff --git a/ios/chrome/browser/ui/infobars/infobar_feature.h b/ios/chrome/browser/ui/infobars/infobar_feature.h
index 516921c..ad30d3d 100644
--- a/ios/chrome/browser/ui/infobars/infobar_feature.h
+++ b/ios/chrome/browser/ui/infobars/infobar_feature.h
@@ -24,6 +24,12 @@
 // Use IsSaveCardInfobarMessagesUIEnabled() instead of this constant directly.
 extern const base::Feature kSaveCardInfobarMessagesUI;
 
+// Feature to choose whether Translate Infobar uses the new Messages UI or the
+// legacy one. In order for it to work, kInfobarUIReboot needs to also be
+// enabled.
+// Use IsTranslateInfobarMessagesUIEnabled() instead of this constant directly.
+extern const base::Feature kTranslateInfobarMessagesUI;
+
 // Whether the Messages Infobar UI is enabled.
 bool IsInfobarUIRebootEnabled();
 
@@ -33,4 +39,7 @@
 // Whether the SaveCard Infobar Messages UI is enabled.
 bool IsSaveCardInfobarMessagesUIEnabled();
 
+// Whether the Translate Infobar Messages UI is enabled.
+bool IsTranslateInfobarMessagesUIEnabled();
+
 #endif  // IOS_CHROME_BROWSER_UI_INFOBARS_INFOBAR_FEATURE_H_
diff --git a/ios/chrome/browser/ui/infobars/infobar_feature.mm b/ios/chrome/browser/ui/infobars/infobar_feature.mm
index fb24b3d..b311a8f 100644
--- a/ios/chrome/browser/ui/infobars/infobar_feature.mm
+++ b/ios/chrome/browser/ui/infobars/infobar_feature.mm
@@ -24,6 +24,13 @@
 const base::Feature kSaveCardInfobarMessagesUI{
     "SaveCardInfobarMessagesUI", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Feature enabled by default since it will always be guarded with
+// |kInfobarUIReboot|, meaning that if necessary, |kInfobarUIReboot| can be used
+// as a kill switch.
+// TODO(crbug.com/1014959): Enabled flag once feature is ready.
+const base::Feature kTranslateInfobarMessagesUI{
+    "TranslateInfobarMessagesUI", base::FEATURE_DISABLED_BY_DEFAULT};
+
 bool IsInfobarUIRebootEnabled() {
   return base::FeatureList::IsEnabled(kInfobarUIReboot);
 }
@@ -37,3 +44,8 @@
   return base::FeatureList::IsEnabled(kSaveCardInfobarMessagesUI) &&
          IsInfobarUIRebootEnabled();
 }
+
+bool IsTranslateInfobarMessagesUIEnabled() {
+  return base::FeatureList::IsEnabled(kTranslateInfobarMessagesUI) &&
+         IsInfobarUIRebootEnabled();
+}
diff --git a/ios/components/io_thread/ios_io_thread.mm b/ios/components/io_thread/ios_io_thread.mm
index 3d73a607..0c259a9 100644
--- a/ios/components/io_thread/ios_io_thread.mm
+++ b/ios/components/io_thread/ios_io_thread.mm
@@ -60,7 +60,6 @@
 #include "net/socket/tcp_client_socket.h"
 #include "net/spdy/spdy_session.h"
 #include "net/ssl/ssl_config_service_defaults.h"
-#include "net/url_request/data_protocol_handler.h"
 #include "net/url_request/static_http_user_agent_settings.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_builder.h"
@@ -360,11 +359,6 @@
 
   net::URLRequestJobFactoryImpl* system_job_factory =
       new net::URLRequestJobFactoryImpl();
-  // Data URLs are always loaded through the system request context on iOS
-  // (due to UIWebView limitations).
-  bool set_protocol = system_job_factory->SetProtocolHandler(
-      url::kDataScheme, std::make_unique<net::DataProtocolHandler>());
-  DCHECK(set_protocol);
   globals->system_url_request_job_factory.reset(system_job_factory);
   context->set_job_factory(globals->system_url_request_job_factory.get());
 
diff --git a/ios/net/protocol_handler_util.mm b/ios/net/protocol_handler_util.mm
index 32f99d2..3c37d9a 100644
--- a/ios/net/protocol_handler_util.mm
+++ b/ios/net/protocol_handler_util.mm
@@ -73,25 +73,6 @@
   NSURL* url = NSURLWithGURL(request->url());
   DCHECK(url);
 
-  // The default iOS stack returns a NSURLResponse when the request has a data
-  // scheme, and a NSHTTPURLResponse otherwise.
-  if (request->url().SchemeIs("data")) {
-    std::string mt;
-    request->GetMimeType(&mt);
-    NSString* mime_type = base::SysUTF8ToNSString(mt);
-    DCHECK(mime_type);
-    std::string cs;
-    request->GetCharset(&cs);
-    NSString* charset = base::SysUTF8ToNSString(cs);
-    DCHECK(charset);
-    // The default iOS stack computes the length of the decoded string. If we
-    // wanted to do that we would have to decode the string now. However, using
-    // the unknown length (-1) seems to be working.
-    return [[NSURLResponse alloc] initWithURL:url
-                                     MIMEType:mime_type
-                        expectedContentLength:-1
-                             textEncodingName:charset];
-  } else {
     // Iterate over all the headers and copy them.
     bool has_content_type_header = false;
     NSMutableDictionary* header_fields = [NSMutableDictionary dictionary];
@@ -180,7 +161,6 @@
                                         statusCode:request->GetResponseCode()
                                        HTTPVersion:version_string
                                       headerFields:header_fields];
-  }
 }
 
 void CopyHttpHeaders(NSURLRequest* in_request, URLRequest* out_request) {
diff --git a/ios/net/protocol_handler_util_unittest.mm b/ios/net/protocol_handler_util_unittest.mm
index df31ecf..263ef9e 100644
--- a/ios/net/protocol_handler_util_unittest.mm
+++ b/ios/net/protocol_handler_util_unittest.mm
@@ -16,7 +16,6 @@
 #include "net/base/upload_bytes_element_reader.h"
 #include "net/http/http_request_headers.h"
 #include "net/http/http_response_headers.h"
-#include "net/url_request/data_protocol_handler.h"
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_job.h"
 #include "net/url_request/url_request_job_factory.h"
@@ -44,8 +43,6 @@
 namespace {
 
 const char* kTextHtml = "text/html";
-const char* kTextPlain = "text/plain";
-const char* kAscii = "US-ASCII";
 
 class HeadersURLRequestJob : public URLRequestJob {
  public:
@@ -116,40 +113,9 @@
     // Ownership of the protocol handlers is transferred to the factory.
     job_factory_.SetProtocolHandler("http",
                                     base::WrapUnique(new NetProtocolHandler));
-    job_factory_.SetProtocolHandler("data",
-                                    base::WrapUnique(new DataProtocolHandler));
     request_context_->set_job_factory(&job_factory_);
   }
 
-  NSURLResponse* BuildDataURLResponse(const std::string& mime_type,
-                                      const std::string& encoding,
-                                      const std::string& content) {
-    // Build an URL in the form "data:<mime_type>;charset=<encoding>,<content>"
-    // The ';' is removed if mime_type or charset is empty.
-    std::string url_string = std::string("data:") + mime_type;
-    if (!encoding.empty())
-      url_string += ";charset=" + encoding;
-    url_string += ",";
-    GURL url(url_string);
-
-    std::unique_ptr<URLRequest> request(
-        request_context_->CreateRequest(url, DEFAULT_PRIORITY, this));
-    request->Start();
-    base::RunLoop loop;
-    loop.RunUntilIdle();
-    return GetNSURLResponseForRequest(request.get());
-  }
-
-  void CheckDataResponse(NSURLResponse* response,
-                         const std::string& mime_type,
-                         const std::string& encoding) {
-    EXPECT_NSEQ(base::SysUTF8ToNSString(mime_type), [response MIMEType]);
-    EXPECT_NSEQ(base::SysUTF8ToNSString(encoding), [response textEncodingName]);
-    // The response class must be NSURLResponse (and not NSHTTPURLResponse) when
-    // the scheme is "data".
-    EXPECT_TRUE([response isMemberOfClass:[NSURLResponse class]]);
-  }
-
   void OnResponseStarted(URLRequest* request, int net_error) override {}
   void OnReadCompleted(URLRequest* request, int bytes_read) override {}
 
@@ -161,16 +127,6 @@
 
 }  // namespace
 
-TEST_F(ProtocolHandlerUtilTest, GetResponseDataSchemeTest) {
-  NSURLResponse* response;
-  // MIME type and charset are correctly carried over.
-  response = BuildDataURLResponse("?mime=type'", "$(charset-*", "content");
-  CheckDataResponse(response, "?mime=type'", "$(charset-*");
-  // Missing values are treated as default values.
-  response = BuildDataURLResponse("", "", "content");
-  CheckDataResponse(response, kTextPlain, kAscii);
-}
-
 TEST_F(ProtocolHandlerUtilTest, GetResponseHttpTest) {
   // Create a request.
   GURL url(std::string("http://url"));
diff --git a/ios/web/shell/shell_url_request_context_getter.mm b/ios/web/shell/shell_url_request_context_getter.mm
index 798c1e2..a344270 100644
--- a/ios/web/shell/shell_url_request_context_getter.mm
+++ b/ios/web/shell/shell_url_request_context_getter.mm
@@ -33,7 +33,6 @@
 #include "net/proxy_resolution/proxy_resolution_service.h"
 #include "net/ssl/ssl_config_service_defaults.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/data_protocol_handler.h"
 #include "net/url_request/static_http_user_agent_settings.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_storage.h"
@@ -145,10 +144,6 @@
 
     std::unique_ptr<net::URLRequestJobFactoryImpl> job_factory(
         new net::URLRequestJobFactoryImpl());
-    bool set_protocol = job_factory->SetProtocolHandler(
-        "data", base::WrapUnique(new net::DataProtocolHandler));
-    DCHECK(set_protocol);
-
     storage_->set_job_factory(std::move(job_factory));
   }
 
diff --git a/ios/web_view/internal/web_view_url_request_context_getter.mm b/ios/web_view/internal/web_view_url_request_context_getter.mm
index 1d31b69..01b95af 100644
--- a/ios/web_view/internal/web_view_url_request_context_getter.mm
+++ b/ios/web_view/internal/web_view_url_request_context_getter.mm
@@ -32,7 +32,6 @@
 #include "net/proxy_resolution/proxy_resolution_service.h"
 #include "net/ssl/ssl_config_service_defaults.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/data_protocol_handler.h"
 #include "net/url_request/static_http_user_agent_settings.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_storage.h"
@@ -155,9 +154,6 @@
 
     std::unique_ptr<net::URLRequestJobFactoryImpl> job_factory(
         new net::URLRequestJobFactoryImpl());
-    bool set_protocol = job_factory->SetProtocolHandler(
-        "data", std::make_unique<net::DataProtocolHandler>());
-    DCHECK(set_protocol);
 
     storage_->set_job_factory(std::move(job_factory));
   }
diff --git a/media/blink/BUILD.gn b/media/blink/BUILD.gn
index 78f3e5f..7ec07f1 100644
--- a/media/blink/BUILD.gn
+++ b/media/blink/BUILD.gn
@@ -131,6 +131,8 @@
   ]
 
   sources = [
+    "blink_platform_with_task_environment.cc",
+    "blink_platform_with_task_environment.h",
     "buffered_data_source_host_impl_unittest.cc",
     "cache_util_unittest.cc",
     "interval_map_unittest.cc",
diff --git a/media/blink/blink_platform_with_task_environment.cc b/media/blink/blink_platform_with_task_environment.cc
new file mode 100644
index 0000000..0534e756
--- /dev/null
+++ b/media/blink/blink_platform_with_task_environment.cc
@@ -0,0 +1,31 @@
+// 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 "media/blink/blink_platform_with_task_environment.h"
+
+namespace media {
+
+BlinkPlatformWithTaskEnvironment::BlinkPlatformWithTaskEnvironment()
+    : task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME),
+      main_thread_scheduler_(
+          blink::scheduler::WebThreadScheduler::CreateMainThreadScheduler()) {}
+
+BlinkPlatformWithTaskEnvironment::~BlinkPlatformWithTaskEnvironment() {
+  main_thread_scheduler_->Shutdown();
+}
+
+blink::scheduler::WebThreadScheduler*
+BlinkPlatformWithTaskEnvironment::GetMainThreadScheduler() {
+  return main_thread_scheduler_.get();
+}
+
+// static
+base::test::TaskEnvironment*
+BlinkPlatformWithTaskEnvironment::GetTaskEnvironment() {
+  return &static_cast<BlinkPlatformWithTaskEnvironment*>(
+              blink::Platform::Current())
+              ->task_environment_;
+}
+
+}  // namespace media
diff --git a/media/blink/blink_platform_with_task_environment.h b/media/blink/blink_platform_with_task_environment.h
new file mode 100644
index 0000000..a279b2b
--- /dev/null
+++ b/media/blink/blink_platform_with_task_environment.h
@@ -0,0 +1,36 @@
+// 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 MEDIA_BLINK_BLINK_PLATFORM_WITH_TASK_ENVIRONMENT_H_
+#define MEDIA_BLINK_BLINK_PLATFORM_WITH_TASK_ENVIRONMENT_H_
+
+#include "base/macros.h"
+#include "base/test/task_environment.h"
+#include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
+#include "third_party/blink/public/web/blink.h"
+
+namespace media {
+
+// We must use a custom blink::Platform that ensures the main thread scheduler
+// knows about the TaskEnvironment.
+class BlinkPlatformWithTaskEnvironment : public blink::Platform {
+ public:
+  BlinkPlatformWithTaskEnvironment();
+  ~BlinkPlatformWithTaskEnvironment() override;
+
+  blink::scheduler::WebThreadScheduler* GetMainThreadScheduler();
+
+  // Returns |task_environment_| from the current blink::Platform.
+  static base::test::TaskEnvironment* GetTaskEnvironment();
+
+ private:
+  base::test::TaskEnvironment task_environment_;
+  std::unique_ptr<blink::scheduler::WebThreadScheduler> main_thread_scheduler_;
+
+  DISALLOW_COPY_AND_ASSIGN(BlinkPlatformWithTaskEnvironment);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_BLINK_BLINK_PLATFORM_WITH_TASK_ENVIRONMENT_H_
diff --git a/media/blink/run_all_unittests.cc b/media/blink/run_all_unittests.cc
index f2794df..7a5cdc3 100644
--- a/media/blink/run_all_unittests.cc
+++ b/media/blink/run_all_unittests.cc
@@ -5,13 +5,12 @@
 #include "base/bind.h"
 #include "base/macros.h"
 #include "base/test/launcher/unit_test_launcher.h"
-#include "base/test/task_environment.h"
 #include "base/test/test_suite.h"
 #include "build/build_config.h"
 #include "media/base/media.h"
+#include "media/blink/blink_platform_with_task_environment.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
 #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
-#include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
 #include "third_party/blink/public/web/blink.h"
 
 #if defined(OS_ANDROID)
@@ -25,6 +24,8 @@
 #if defined(V8_USE_EXTERNAL_STARTUP_DATA)
 #include "gin/v8_initializer.h"
 
+using media::BlinkPlatformWithTaskEnvironment;
+
 constexpr gin::V8Initializer::V8SnapshotFileType kSnapshotType =
 #if defined(USE_V8_CONTEXT_SNAPSHOT)
     gin::V8Initializer::V8SnapshotFileType::kWithAdditionalContext;
@@ -33,30 +34,6 @@
 #endif  // defined(USE_V8_CONTEXT_SNAPSHOT)
 #endif  // defined(V8_USE_EXTERNAL_STARTUP_DATA)
 
-// We must use a custom blink::Platform that ensures the main thread scheduler
-// knows about the TaskEnvironment.
-class BlinkPlatformWithTaskEnvironment : public blink::Platform {
- public:
-  BlinkPlatformWithTaskEnvironment()
-      : main_thread_scheduler_(
-            blink::scheduler::WebThreadScheduler::CreateMainThreadScheduler()) {
-  }
-
-  ~BlinkPlatformWithTaskEnvironment() override {
-    main_thread_scheduler_->Shutdown();
-  }
-
-  blink::scheduler::WebThreadScheduler* GetMainThreadScheduler() {
-    return main_thread_scheduler_.get();
-  }
-
- private:
-  base::test::TaskEnvironment task_environment_;
-  std::unique_ptr<blink::scheduler::WebThreadScheduler> main_thread_scheduler_;
-
-  DISALLOW_COPY_AND_ASSIGN(BlinkPlatformWithTaskEnvironment);
-};
-
 class MediaBlinkTestSuite : public base::TestSuite {
  public:
   MediaBlinkTestSuite(int argc, char** argv) : base::TestSuite(argc, argv) {}
diff --git a/media/gpu/BUILD.gn b/media/gpu/BUILD.gn
index ba1b90e..9c62828 100644
--- a/media/gpu/BUILD.gn
+++ b/media/gpu/BUILD.gn
@@ -181,6 +181,8 @@
       "windows/d3d11_video_decoder_client.h",
       "windows/d3d11_video_decoder_impl.cc",
       "windows/d3d11_video_decoder_impl.h",
+      "windows/d3d11_video_device_format_support.cc",
+      "windows/d3d11_video_device_format_support.h",
       "windows/d3d11_video_processor_proxy.cc",
       "windows/d3d11_video_processor_proxy.h",
       "windows/d3d11_vp9_accelerator.cc",
@@ -599,6 +601,7 @@
       "windows/d3d11_decryptor_unittest.cc",
       "windows/d3d11_texture_selector_unittest.cc",
       "windows/d3d11_video_decoder_unittest.cc",
+      "windows/d3d11_video_device_format_support_unittest.cc",
       "windows/d3d11_video_processor_proxy_unittest.cc",
       "windows/supported_profile_helpers_unittest.cc",
     ]
diff --git a/media/gpu/windows/d3d11_video_device_format_support.cc b/media/gpu/windows/d3d11_video_device_format_support.cc
new file mode 100644
index 0000000..7d888613
--- /dev/null
+++ b/media/gpu/windows/d3d11_video_device_format_support.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 "media/gpu/windows/d3d11_video_device_format_support.h"
+
+namespace media {
+
+FormatSupportChecker::FormatSupportChecker(ComD3D11Device device)
+    : device_(std::move(device)) {
+  DCHECK(device_);
+}
+
+FormatSupportChecker::~FormatSupportChecker() {
+  if (initialized_)
+    enumerator_.Reset();
+  device_.Reset();
+}
+
+bool FormatSupportChecker::Initialize() {
+  ComD3D11VideoDevice v_device;
+  if (!SUCCEEDED(device_.As(&v_device)))
+    return false;
+
+  // The values here should have _no_ effect on supported profiles, but they
+  // are needed anyway for initialization.
+  D3D11_VIDEO_PROCESSOR_CONTENT_DESC desc;
+  desc.InputFrameFormat = D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE;
+  desc.InputFrameRate.Numerator = 60;
+  desc.InputFrameRate.Denominator = 1;
+  desc.InputWidth = 1920;
+  desc.InputHeight = 1080;
+  desc.OutputFrameRate.Numerator = 60;
+  desc.OutputFrameRate.Denominator = 1;
+  desc.OutputWidth = 1920;
+  desc.OutputHeight = 1080;
+  desc.Usage = D3D11_VIDEO_USAGE_PLAYBACK_NORMAL;
+
+  if (!SUCCEEDED(v_device->CreateVideoProcessorEnumerator(&desc, &enumerator_)))
+    return false;
+
+  // Check that the |CheckFormatSupport| and |CheckVideoProcessorFormat| calls
+  // won't be failing
+  UINT unneeded = 0;
+  DXGI_FORMAT example = DXGI_FORMAT_NV12;
+  if (!SUCCEEDED(device_->CheckFormatSupport(example, &unneeded)))
+    return false;
+
+  if (!SUCCEEDED(enumerator_->CheckVideoProcessorFormat(example, &unneeded)))
+    return false;
+
+  initialized_ = true;
+  return true;
+}
+
+bool FormatSupportChecker::CheckOutputFormatSupport(DXGI_FORMAT format) {
+  DCHECK(initialized_);
+  UINT device = 0, enumerator = 0;
+  if (!SUCCEEDED(device_->CheckFormatSupport(format, &device)))
+    return false;
+  if (!SUCCEEDED(enumerator_->CheckVideoProcessorFormat(format, &enumerator)))
+    return false;
+
+  return (enumerator & D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_OUTPUT) &&
+         (device & D3D11_FORMAT_SUPPORT_VIDEO_PROCESSOR_OUTPUT);
+}
+
+}  // namespace media
diff --git a/media/gpu/windows/d3d11_video_device_format_support.h b/media/gpu/windows/d3d11_video_device_format_support.h
new file mode 100644
index 0000000..009e0a6
--- /dev/null
+++ b/media/gpu/windows/d3d11_video_device_format_support.h
@@ -0,0 +1,42 @@
+// 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 MEDIA_GPU_WINDOWS_D3D11_VIDEO_DEVICE_FORMAT_SUPPORT_H_
+#define MEDIA_GPU_WINDOWS_D3D11_VIDEO_DEVICE_FORMAT_SUPPORT_H_
+
+#include <d3d11_1.h>
+#include <vector>
+
+#include "base/optional.h"
+#include "media/base/media_log.h"
+#include "media/gpu/media_gpu_export.h"
+#include "media/gpu/windows/d3d11_com_defs.h"
+
+namespace media {
+
+// Helper class for Checking whether a video can be processed in any given
+// DXVI_FORMAT.
+class MEDIA_GPU_EXPORT FormatSupportChecker {
+ public:
+  explicit FormatSupportChecker(ComD3D11Device device);
+  ~FormatSupportChecker();
+
+  // Set up the device to be able to check format support.
+  // Returns false if there is a failure.
+  bool Initialize();
+
+  // Checks if the device's texture processing pipeline supports output textures
+  bool CheckOutputFormatSupport(DXGI_FORMAT format);
+
+ private:
+  ComD3D11Device device_;
+  ComD3D11VideoProcessorEnumerator enumerator_;
+  bool initialized_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(FormatSupportChecker);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_GPU_WINDOWS_D3D11_VIDEO_DEVICE_FORMAT_SUPPORT_H_
diff --git a/media/gpu/windows/d3d11_video_device_format_support_unittest.cc b/media/gpu/windows/d3d11_video_device_format_support_unittest.cc
new file mode 100644
index 0000000..d55572e
--- /dev/null
+++ b/media/gpu/windows/d3d11_video_device_format_support_unittest.cc
@@ -0,0 +1,106 @@
+// 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 <utility>
+
+#include "media/base/media_util.h"
+#include "media/base/win/d3d11_mocks.h"
+#include "media/gpu/windows/d3d11_video_device_format_support.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+using ::testing::Combine;
+using ::testing::DoAll;
+using ::testing::NiceMock;
+using ::testing::Return;
+using ::testing::SetArgPointee;
+using ::testing::Values;
+
+namespace media {
+
+class FormatSupportCheckerUnittest : public ::testing::Test {};
+
+TEST_F(FormatSupportCheckerUnittest, CheckInitializationCantCast) {
+  auto device = CreateD3D11Mock<NiceMock<D3D11DeviceMock>>();
+  auto vdevice = CreateD3D11Mock<NiceMock<D3D11VideoDeviceMock>>();
+  auto enumerator =
+      CreateD3D11Mock<NiceMock<D3D11VideoProcessorEnumeratorMock>>();
+
+  ON_CALL(*device.Get(), QueryInterface(IID_ID3D11VideoDevice, _))
+      .WillByDefault(SetComPointeeAndReturnOk<1>(vdevice.Get()));
+
+  EXPECT_CALL(*vdevice.Get(), CreateVideoProcessorEnumerator(_, _))
+      .WillOnce(SetComPointeeAndReturnOk<1>(enumerator.Get()));
+
+  EXPECT_CALL(*device.Get(), CheckFormatSupport(_, _)).WillOnce(Return(S_OK));
+
+  EXPECT_CALL(*enumerator.Get(), CheckVideoProcessorFormat(_, _))
+      .WillOnce(Return(S_OK));
+
+  FormatSupportChecker checker(device);
+  EXPECT_TRUE(checker.Initialize());
+}
+
+TEST_F(FormatSupportCheckerUnittest, CheckFormatSupportWorks) {
+  auto device = CreateD3D11Mock<NiceMock<D3D11DeviceMock>>();
+  auto vdevice = CreateD3D11Mock<NiceMock<D3D11VideoDeviceMock>>();
+  auto enumerator =
+      CreateD3D11Mock<NiceMock<D3D11VideoProcessorEnumeratorMock>>();
+
+  ON_CALL(*device.Get(), QueryInterface(IID_ID3D11VideoDevice, _))
+      .WillByDefault(SetComPointeeAndReturnOk<1>(vdevice.Get()));
+
+  EXPECT_CALL(*vdevice.Get(), CreateVideoProcessorEnumerator(_, _))
+      .WillOnce(SetComPointeeAndReturnOk<1>(enumerator.Get()));
+
+  EXPECT_CALL(*device.Get(), CheckFormatSupport(_, _)).WillOnce(Return(S_OK));
+
+  EXPECT_CALL(*enumerator.Get(), CheckVideoProcessorFormat(_, _))
+      .WillOnce(Return(S_OK));
+
+  FormatSupportChecker checker(device);
+  EXPECT_TRUE(checker.Initialize());
+
+  UINT enumerator_outcome = D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_OUTPUT;
+  UINT device_outcome = D3D11_FORMAT_SUPPORT_VIDEO_PROCESSOR_OUTPUT;
+  EXPECT_CALL(*enumerator.Get(), CheckVideoProcessorFormat(_, _))
+      .WillOnce(DoAll(SetArgPointee<1>(enumerator_outcome), Return(S_OK)));
+  EXPECT_CALL(*device.Get(), CheckFormatSupport(_, _))
+      .WillOnce(DoAll(SetArgPointee<1>(device_outcome), Return(S_OK)));
+
+  EXPECT_TRUE(checker.CheckOutputFormatSupport(DXGI_FORMAT_NV12));
+}
+
+TEST_F(FormatSupportCheckerUnittest, CheckFormatSupportRequiresBoth) {
+  auto device = CreateD3D11Mock<NiceMock<D3D11DeviceMock>>();
+  auto vdevice = CreateD3D11Mock<NiceMock<D3D11VideoDeviceMock>>();
+  auto enumerator =
+      CreateD3D11Mock<NiceMock<D3D11VideoProcessorEnumeratorMock>>();
+
+  ON_CALL(*device.Get(), QueryInterface(IID_ID3D11VideoDevice, _))
+      .WillByDefault(SetComPointeeAndReturnOk<1>(vdevice.Get()));
+
+  EXPECT_CALL(*vdevice.Get(), CreateVideoProcessorEnumerator(_, _))
+      .WillOnce(SetComPointeeAndReturnOk<1>(enumerator.Get()));
+
+  EXPECT_CALL(*device.Get(), CheckFormatSupport(_, _)).WillOnce(Return(S_OK));
+
+  EXPECT_CALL(*enumerator.Get(), CheckVideoProcessorFormat(_, _))
+      .WillOnce(Return(S_OK));
+
+  FormatSupportChecker checker(device);
+  EXPECT_TRUE(checker.Initialize());
+
+  UINT enumerator_outcome = D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_OUTPUT;
+  UINT device_outcome = 0;
+  EXPECT_CALL(*enumerator.Get(), CheckVideoProcessorFormat(_, _))
+      .WillOnce(DoAll(SetArgPointee<1>(enumerator_outcome), Return(S_OK)));
+  EXPECT_CALL(*device.Get(), CheckFormatSupport(_, _))
+      .WillOnce(DoAll(SetArgPointee<1>(device_outcome), Return(S_OK)));
+
+  EXPECT_FALSE(checker.CheckOutputFormatSupport(DXGI_FORMAT_NV12));
+}
+
+}  // namespace media
diff --git a/media/gpu/windows/dxva_video_decode_accelerator_win.cc b/media/gpu/windows/dxva_video_decode_accelerator_win.cc
index a5c986b..fe2c16de 100644
--- a/media/gpu/windows/dxva_video_decode_accelerator_win.cc
+++ b/media/gpu/windows/dxva_video_decode_accelerator_win.cc
@@ -50,6 +50,7 @@
 #include "media/base/win/mf_helpers.h"
 #include "media/base/win/mf_initializer.h"
 #include "media/filters/vp9_parser.h"
+#include "media/gpu/windows/d3d11_video_device_format_support.h"
 #include "media/gpu/windows/dxva_picture_buffer_win.h"
 #include "media/gpu/windows/supported_profile_helpers.h"
 #include "media/video/h264_parser.h"
@@ -881,19 +882,15 @@
   if (!options.ExtendedResourceSharing)
     support_copy_nv12_textures_ = false;
 
-  UINT nv12_format_support = 0;
-  hr =
-      D3D11Device()->CheckFormatSupport(DXGI_FORMAT_NV12, &nv12_format_support);
-  RETURN_ON_HR_FAILURE(hr, "Failed to check NV12 format support", false);
+  FormatSupportChecker checker(ShouldUseANGLEDevice() ? angle_device_
+                                                      : d3d11_device_);
+  RETURN_ON_FAILURE(checker.Initialize(), "Failed to check format supports!",
+                    false);
 
-  if (!(nv12_format_support & D3D11_FORMAT_SUPPORT_VIDEO_PROCESSOR_OUTPUT))
+  if (!checker.CheckOutputFormatSupport(DXGI_FORMAT_NV12))
     support_copy_nv12_textures_ = false;
 
-  UINT fp16_format_support = 0;
-  hr = D3D11Device()->CheckFormatSupport(DXGI_FORMAT_R16G16B16A16_FLOAT,
-                                         &fp16_format_support);
-  if (FAILED(hr) ||
-      !(fp16_format_support & D3D11_FORMAT_SUPPORT_VIDEO_PROCESSOR_OUTPUT))
+  if (!checker.CheckOutputFormatSupport(DXGI_FORMAT_R16G16B16A16_FLOAT))
     use_fp16_ = false;
 
   // Enable multithreaded mode on the device. This ensures that accesses to
diff --git a/media/gpu/windows/supported_profile_helpers.h b/media/gpu/windows/supported_profile_helpers.h
index 9c0d2d9..168b68a8 100644
--- a/media/gpu/windows/supported_profile_helpers.h
+++ b/media/gpu/windows/supported_profile_helpers.h
@@ -16,7 +16,6 @@
 #include "media/gpu/windows/d3d11_com_defs.h"
 #include "ui/gfx/geometry/rect.h"
 
-#include "ui/gfx/geometry/rect.h"
 
 namespace media {
 
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 5a1c624..8b5acb40 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -1791,8 +1791,6 @@
       "third_party/quiche/src/spdy/platform/api/spdy_string_piece.h",
       "third_party/quiche/src/spdy/platform/api/spdy_string_utils.h",
       "third_party/quiche/src/spdy/platform/api/spdy_unsafe_arena.h",
-      "url_request/data_protocol_handler.cc",
-      "url_request/data_protocol_handler.h",
       "url_request/redirect_info.cc",
       "url_request/redirect_info.h",
       "url_request/redirect_util.cc",
@@ -2853,6 +2851,8 @@
     "test/url_request/url_request_mock_data_job.h",
     "test/url_request/url_request_slow_download_job.cc",
     "test/url_request/url_request_slow_download_job.h",
+    "url_request/data_protocol_handler.cc",
+    "url_request/data_protocol_handler.h",
     "url_request/test_url_fetcher_factory.cc",
     "url_request/test_url_fetcher_factory.h",
     "url_request/url_request_test_util.cc",
diff --git a/net/http/http_basic_stream.cc b/net/http/http_basic_stream.cc
index d7cb43ea..b2bb7fd1 100644
--- a/net/http/http_basic_stream.cc
+++ b/net/http/http_basic_stream.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "base/bind.h"
 #include "net/http/http_raw_request_headers.h"
 #include "net/http/http_request_info.h"
 #include "net/http/http_response_body_drainer.h"
@@ -31,7 +32,10 @@
   state_.Initialize(request_info, priority, net_log);
   int ret = OK;
   if (!can_send_early) {
-    ret = parser()->ConfirmHandshake(std::move(callback));
+    // parser() cannot outlive |this|, so we can use base::Unretained().
+    ret = parser()->ConfirmHandshake(
+        base::BindOnce(&HttpBasicStream::OnHandshakeConfirmed,
+                       base::Unretained(this), std::move(callback)));
   }
   return ret;
 }
@@ -125,6 +129,14 @@
     return false;
   }
 
+  // If the request waited for handshake confirmation, shift |ssl_end| to
+  // include that time.
+  if (!load_timing_info->connect_timing.ssl_end.is_null() &&
+      !confirm_handshake_end_.is_null()) {
+    load_timing_info->connect_timing.ssl_end = confirm_handshake_end_;
+    load_timing_info->connect_timing.connect_end = confirm_handshake_end_;
+  }
+
   load_timing_info->receive_headers_start = parser()->response_start_time();
   return true;
 }
@@ -180,4 +192,15 @@
   request_headers_callback_ = std::move(callback);
 }
 
+void HttpBasicStream::OnHandshakeConfirmed(CompletionOnceCallback callback,
+                                           int rv) {
+  if (rv == OK) {
+    // Note this time is only recorded if ConfirmHandshake() completed
+    // asynchronously. If it was synchronous, GetLoadTimingInfo() assumes the
+    // handshake was already confirmed or there was nothing to confirm.
+    confirm_handshake_end_ = base::TimeTicks::Now();
+  }
+  std::move(callback).Run(rv);
+}
+
 }  // namespace net
diff --git a/net/http/http_basic_stream.h b/net/http/http_basic_stream.h
index 744b2f7..f5944f10 100644
--- a/net/http/http_basic_stream.h
+++ b/net/http/http_basic_stream.h
@@ -15,6 +15,7 @@
 #include <string>
 
 #include "base/macros.h"
+#include "base/time/time.h"
 #include "net/base/completion_once_callback.h"
 #include "net/base/net_export.h"
 #include "net/http/http_basic_state.h"
@@ -93,7 +94,10 @@
  private:
   HttpStreamParser* parser() const { return state_.parser(); }
 
+  void OnHandshakeConfirmed(CompletionOnceCallback callback, int rv);
+
   HttpBasicState state_;
+  base::TimeTicks confirm_handshake_end_;
   RequestHeadersCallback request_headers_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(HttpBasicStream);
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index 4db22adf..a648f73 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -544,6 +544,11 @@
 
   void CheckErrorIsPassedBack(int error, IoMode mode);
 
+  base::RepeatingClosure FastForwardByCallback(base::TimeDelta delta) {
+    return base::BindRepeating(&HttpNetworkTransactionTest::FastForwardBy,
+                               base::Unretained(this), delta);
+  }
+
   const CommonConnectJobParams dummy_connect_job_params_;
 
   // These clocks are defined here, even though they're only used in the
@@ -20605,6 +20610,7 @@
 }
 
 TEST_F(HttpNetworkTransactionTest, ZeroRTTDoesntConfirm) {
+  static const base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(10);
   HttpRequestInfo request;
   request.method = "GET";
   request.url = GURL("https://www.example.org/");
@@ -20626,7 +20632,9 @@
   StaticSocketDataProvider data(data_reads, data_writes);
   session_deps_.socket_factory->AddSocketDataProvider(&data);
   SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
+  ssl.connect_callback = FastForwardByCallback(kDelay);
   ssl.confirm = MockConfirm(SYNCHRONOUS, OK);
+  ssl.confirm_callback = FastForwardByCallback(kDelay);
   session_deps_.enable_early_data = true;
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
 
@@ -20636,6 +20644,7 @@
   auto trans =
       std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
 
+  base::TimeTicks start_time = base::TimeTicks::Now();
   int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
@@ -20652,12 +20661,22 @@
   ASSERT_FALSE(ssl.ConfirmDataConsumed());
   ASSERT_TRUE(ssl.WriteBeforeConfirm());
 
+  // The handshake time should include the time it took to run Connect(), but
+  // not ConfirmHandshake().
+  LoadTimingInfo load_timing_info;
+  EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
+  EXPECT_EQ(load_timing_info.connect_timing.connect_start, start_time);
+  EXPECT_EQ(load_timing_info.connect_timing.ssl_start, start_time);
+  EXPECT_EQ(load_timing_info.connect_timing.ssl_end, start_time + kDelay);
+  EXPECT_EQ(load_timing_info.connect_timing.connect_end, start_time + kDelay);
+
   trans.reset();
 
   session->CloseAllConnections();
 }
 
 TEST_F(HttpNetworkTransactionTest, ZeroRTTSyncConfirmSyncWrite) {
+  static const base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(10);
   HttpRequestInfo request;
   request.method = "POST";
   request.url = GURL("https://www.example.org/");
@@ -20681,7 +20700,9 @@
   StaticSocketDataProvider data(data_reads, data_writes);
   session_deps_.socket_factory->AddSocketDataProvider(&data);
   SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
+  ssl.connect_callback = FastForwardByCallback(kDelay);
   ssl.confirm = MockConfirm(SYNCHRONOUS, OK);
+  ssl.confirm_callback = FastForwardByCallback(kDelay);
   session_deps_.enable_early_data = true;
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
 
@@ -20691,6 +20712,7 @@
   auto trans =
       std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
 
+  base::TimeTicks start_time = base::TimeTicks::Now();
   int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
@@ -20706,6 +20728,17 @@
   // Check that the Write didn't get called before ConfirmHandshake completed.
   ASSERT_FALSE(ssl.WriteBeforeConfirm());
 
+  // The handshake time should include the time it took to run Connect(), but
+  // not ConfirmHandshake(). If ConfirmHandshake() returns synchronously, we
+  // assume the connection did not negotiate 0-RTT or the handshake was already
+  // confirmed.
+  LoadTimingInfo load_timing_info;
+  EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
+  EXPECT_EQ(load_timing_info.connect_timing.connect_start, start_time);
+  EXPECT_EQ(load_timing_info.connect_timing.ssl_start, start_time);
+  EXPECT_EQ(load_timing_info.connect_timing.ssl_end, start_time + kDelay);
+  EXPECT_EQ(load_timing_info.connect_timing.connect_end, start_time + kDelay);
+
   trans.reset();
 
   session->CloseAllConnections();
@@ -20766,6 +20799,7 @@
 }
 
 TEST_F(HttpNetworkTransactionTest, ZeroRTTAsyncConfirmSyncWrite) {
+  static const base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(10);
   HttpRequestInfo request;
   request.method = "POST";
   request.url = GURL("https://www.example.org/");
@@ -20789,7 +20823,9 @@
   StaticSocketDataProvider data(data_reads, data_writes);
   session_deps_.socket_factory->AddSocketDataProvider(&data);
   SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
+  ssl.connect_callback = FastForwardByCallback(kDelay);
   ssl.confirm = MockConfirm(ASYNC, OK);
+  ssl.confirm_callback = FastForwardByCallback(kDelay);
   session_deps_.enable_early_data = true;
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
 
@@ -20799,6 +20835,7 @@
   auto trans =
       std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
 
+  base::TimeTicks start_time = base::TimeTicks::Now();
   int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
@@ -20814,6 +20851,16 @@
   // Check that the Write didn't get called before ConfirmHandshake completed.
   ASSERT_FALSE(ssl.WriteBeforeConfirm());
 
+  // The handshake time should include the time it took to run Connect() and
+  // ConfirmHandshake().
+  LoadTimingInfo load_timing_info;
+  EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
+  EXPECT_EQ(load_timing_info.connect_timing.connect_start, start_time);
+  EXPECT_EQ(load_timing_info.connect_timing.ssl_start, start_time);
+  EXPECT_EQ(load_timing_info.connect_timing.ssl_end, start_time + 2 * kDelay);
+  EXPECT_EQ(load_timing_info.connect_timing.connect_end,
+            start_time + 2 * kDelay);
+
   trans.reset();
 
   session->CloseAllConnections();
diff --git a/net/http/http_stream_factory_unittest.cc b/net/http/http_stream_factory_unittest.cc
index dc2f9e4..744631b 100644
--- a/net/http/http_stream_factory_unittest.cc
+++ b/net/http/http_stream_factory_unittest.cc
@@ -3461,7 +3461,6 @@
       {quic::PROTOCOL_QUIC_CRYPTO, quic::QUIC_VERSION_50},
       {quic::PROTOCOL_QUIC_CRYPTO, quic::QUIC_VERSION_49},
       {quic::PROTOCOL_QUIC_CRYPTO, quic::QUIC_VERSION_48},
-      {quic::PROTOCOL_QUIC_CRYPTO, quic::QUIC_VERSION_47},
       {quic::PROTOCOL_QUIC_CRYPTO, quic::QUIC_VERSION_43},
   };
   AlternativeServiceInfoVector alternatives =
diff --git a/net/log/net_log_event_type_list.h b/net/log/net_log_event_type_list.h
index ccd0b773..6f90279 100644
--- a/net/log/net_log_event_type_list.h
+++ b/net/log/net_log_event_type_list.h
@@ -2095,6 +2095,74 @@
 //  }
 EVENT_TYPE(QUIC_SESSION_MAX_STREAMS_FRAME_RECEIVED)
 
+// Session sent a PADDING frame.
+//  {
+//    "num_padding_bytes": <The number of padding bytes>
+//  }
+EVENT_TYPE(QUIC_SESSION_PADDING_FRAME_SENT)
+
+// Session received a PADDING frame.
+//  {
+//    "num_padding_bytes": <The number of padding bytes>
+//  }
+EVENT_TYPE(QUIC_SESSION_PADDING_FRAME_RECEIVED)
+
+// Session sent a NEW_CONNECITON_ID frame.
+//  {
+//    "connection_id": <The new connection id>
+//    "sequencer_number": <Connection id sequence number that specifies the
+//    order that connection ids must be used in.>
+//    "retire_prior_to": <retire prior to>
+//  }
+EVENT_TYPE(QUIC_SESSION_NEW_CONNECTION_ID_FRAME_SENT)
+
+// Session received a NEW_CONNECITON_ID frame.
+//  {
+//    "connection_id": <The new connection id>
+//    "sequence_number": <Connection id sequence number that specifies the
+//    order that connection ids must be used in.>
+//    "retire_prior_to": <retire prior to>
+//  }
+EVENT_TYPE(QUIC_SESSION_NEW_CONNECTION_ID_FRAME_RECEIVED)
+
+// Session sent a NEW_TOKEN frame.
+//  {
+//    "token": <String representation of the token>
+//  }
+EVENT_TYPE(QUIC_SESSION_NEW_TOKEN_FRAME_SENT)
+
+// Session received a NEW_TOKEN frame.
+//  {
+//    "token": <String representation of the token>
+//  }
+EVENT_TYPE(QUIC_SESSION_NEW_TOKEN_FRAME_RECEIVED)
+
+// Session sent a RETIRE_CONNECTION_ID frame.
+//  {
+//    "sequence_number": <Connection id sequence number that specifies the
+//    order that connection ids must be used in.>
+//  }
+EVENT_TYPE(QUIC_SESSION_RETIRE_CONNECTION_ID_FRAME_SENT)
+
+// Session received a RETIRE_CONNECTION_ID frame.
+//  {
+//    "sequence_number": <Connection id sequence number that specifies the
+//    order that connection ids must be used in.>
+//  }
+EVENT_TYPE(QUIC_SESSION_RETIRE_CONNECTION_ID_FRAME_RECEIVED)
+
+// Session sent a MESSAGE frame.
+//  {
+//    "message_length": <the length of the message>
+//  }
+EVENT_TYPE(QUIC_SESSION_MESSAGE_FRAME_SENT)
+
+// Session received a MESSAGE frame.
+//  {
+//    "message_length": <the length of the message>
+//  }
+EVENT_TYPE(QUIC_SESSION_MESSAGE_FRAME_RECEIVED)
+
 // ------------------------------------------------------------------------
 // QuicHttpStream
 // ------------------------------------------------------------------------
diff --git a/net/quic/quic_chromium_client_session.cc b/net/quic/quic_chromium_client_session.cc
index 5d985df8..4bd8ea2 100644
--- a/net/quic/quic_chromium_client_session.cc
+++ b/net/quic/quic_chromium_client_session.cc
@@ -784,13 +784,13 @@
       ignore_read_error_(false),
       headers_include_h2_stream_dependency_(
           headers_include_h2_stream_dependency &&
-          this->connection()->transport_version() >= quic::QUIC_VERSION_43) {
+          this->connection()->transport_version() >= quic::QUIC_VERSION_43),
+      max_allowed_push_id_(max_allowed_push_id) {
   // 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_));
   DCHECK(!(allow_port_migration_ && go_away_on_path_degrading_));
 
-  quic::QuicSpdyClientSessionBase::SetMaxAllowedPushId(max_allowed_push_id);
   default_network_ = default_network;
   auto* socket_raw = socket.get();
   sockets_.push_back(std::move(socket));
@@ -940,6 +940,7 @@
 }
 
 void QuicChromiumClientSession::Initialize() {
+  quic::QuicSpdyClientSessionBase::SetMaxAllowedPushId(max_allowed_push_id_);
   set_max_inbound_header_list_size(kQuicMaxHeaderListSize);
   quic::QuicSpdyClientSessionBase::Initialize();
   SetHpackEncoderDebugVisitor(std::make_unique<HpackEncoderDebugVisitor>());
diff --git a/net/quic/quic_chromium_client_session.h b/net/quic/quic_chromium_client_session.h
index b25c8cf..6602a6a 100644
--- a/net/quic/quic_chromium_client_session.h
+++ b/net/quic/quic_chromium_client_session.h
@@ -864,6 +864,8 @@
   bool headers_include_h2_stream_dependency_;
   Http2PriorityDependencies priority_dependency_state_;
 
+  quic::QuicStreamId max_allowed_push_id_;
+
   base::WeakPtrFactory<QuicChromiumClientSession> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(QuicChromiumClientSession);
diff --git a/net/quic/quic_connection_logger.cc b/net/quic/quic_connection_logger.cc
index 375069c3..f02720b8 100644
--- a/net/quic/quic_connection_logger.cc
+++ b/net/quic/quic_connection_logger.cc
@@ -304,6 +304,31 @@
   return dict;
 }
 
+base::Value NetLogQuicNewConnectionIdFrameParams(
+    const quic::QuicNewConnectionIdFrame* frame) {
+  base::Value dict(base::Value::Type::DICTIONARY);
+  dict.SetStringKey("connection_id", frame->connection_id.ToString());
+  dict.SetKey("sequence_number", NetLogNumberValue(frame->sequence_number));
+  dict.SetKey("retire_prior_to", NetLogNumberValue(frame->retire_prior_to));
+  return dict;
+}
+
+base::Value NetLogQuicRetireConnectionIdFrameParams(
+    const quic::QuicRetireConnectionIdFrame* frame) {
+  base::Value dict(base::Value::Type::DICTIONARY);
+  dict.SetKey("sequence_number", NetLogNumberValue(frame->sequence_number));
+  return dict;
+}
+
+base::Value NetLogQuicNewTokenFrameParams(
+    const quic::QuicNewTokenFrame* frame) {
+  base::Value dict(base::Value::Type::DICTIONARY);
+  dict.SetKey("token", NetLogBinaryValue(
+                           reinterpret_cast<const void*>(frame->token.data()),
+                           frame->token.length()));
+  return dict;
+}
+
 void UpdatePublicResetAddressMismatchHistogram(
     const IPEndPoint& server_hello_address,
     const IPEndPoint& public_reset_address) {
@@ -448,6 +473,9 @@
     return;
   switch (frame.type) {
     case quic::PADDING_FRAME:
+      net_log_.AddEventWithIntParams(
+          NetLogEventType::QUIC_SESSION_PADDING_FRAME_SENT, "num_padding_bytes",
+          frame.padding_frame.num_padding_bytes);
       break;
     case quic::STREAM_FRAME:
       net_log_.AddEvent(NetLogEventType::QUIC_SESSION_STREAM_FRAME_SENT, [&] {
@@ -510,6 +538,11 @@
       net_log_.AddEvent(NetLogEventType::QUIC_SESSION_MTU_DISCOVERY_FRAME_SENT);
       break;
     case quic::NEW_CONNECTION_ID_FRAME:
+      net_log_.AddEvent(
+          NetLogEventType::QUIC_SESSION_NEW_CONNECTION_ID_FRAME_SENT, [&] {
+            return NetLogQuicNewConnectionIdFrameParams(
+                frame.new_connection_id_frame);
+          });
       break;
     case quic::MAX_STREAMS_FRAME:
       net_log_.AddEvent(
@@ -543,6 +576,9 @@
           });
       break;
     case quic::MESSAGE_FRAME:
+      net_log_.AddEventWithIntParams(
+          NetLogEventType::QUIC_SESSION_MESSAGE_FRAME_SENT, "message_length",
+          frame.message_frame->message_length);
       break;
     case quic::CRYPTO_FRAME:
       net_log_.AddEvent(NetLogEventType::QUIC_SESSION_CRYPTO_FRAME_SENT, [&] {
@@ -551,8 +587,16 @@
       });
       break;
     case quic::NEW_TOKEN_FRAME:
+      net_log_.AddEvent(
+          NetLogEventType::QUIC_SESSION_NEW_TOKEN_FRAME_SENT,
+          [&] { return NetLogQuicNewTokenFrameParams(frame.new_token_frame); });
       break;
     case quic::RETIRE_CONNECTION_ID_FRAME:
+      net_log_.AddEvent(
+          NetLogEventType::QUIC_SESSION_RETIRE_CONNECTION_ID_FRAME_SENT, [&] {
+            return NetLogQuicRetireConnectionIdFrameParams(
+                frame.retire_connection_id_frame);
+          });
       break;
     default:
       DCHECK(false) << "Illegal frame type: " << frame.type;
@@ -846,6 +890,48 @@
   net_log_.AddEvent(NetLogEventType::QUIC_SESSION_PING_FRAME_RECEIVED);
 }
 
+void QuicConnectionLogger::OnPaddingFrame(const quic::QuicPaddingFrame& frame) {
+  if (!net_log_.IsCapturing())
+    return;
+  net_log_.AddEventWithIntParams(
+      NetLogEventType::QUIC_SESSION_PADDING_FRAME_RECEIVED, "num_padding_bytes",
+      frame.num_padding_bytes);
+}
+
+void QuicConnectionLogger::OnNewConnectionIdFrame(
+    const quic::QuicNewConnectionIdFrame& frame) {
+  if (!net_log_.IsCapturing())
+    return;
+  net_log_.AddEvent(
+      NetLogEventType::QUIC_SESSION_NEW_CONNECTION_ID_FRAME_RECEIVED,
+      [&] { return NetLogQuicNewConnectionIdFrameParams(&frame); });
+}
+
+void QuicConnectionLogger::OnNewTokenFrame(
+    const quic::QuicNewTokenFrame& frame) {
+  if (!net_log_.IsCapturing())
+    return;
+  net_log_.AddEvent(NetLogEventType::QUIC_SESSION_NEW_TOKEN_FRAME_RECEIVED,
+                    [&] { return NetLogQuicNewTokenFrameParams(&frame); });
+}
+
+void QuicConnectionLogger::OnRetireConnectionIdFrame(
+    const quic::QuicRetireConnectionIdFrame& frame) {
+  if (!net_log_.IsCapturing())
+    return;
+  net_log_.AddEvent(
+      NetLogEventType::QUIC_SESSION_RETIRE_CONNECTION_ID_FRAME_RECEIVED,
+      [&] { return NetLogQuicRetireConnectionIdFrameParams(&frame); });
+}
+
+void QuicConnectionLogger::OnMessageFrame(const quic::QuicMessageFrame& frame) {
+  if (!net_log_.IsCapturing())
+    return;
+  net_log_.AddEventWithIntParams(
+      NetLogEventType::QUIC_SESSION_MESSAGE_FRAME_RECEIVED, "message_length",
+      frame.message_length);
+}
+
 void QuicConnectionLogger::OnPublicResetPacket(
     const quic::QuicPublicResetPacket& packet) {
   UpdatePublicResetAddressMismatchHistogram(
diff --git a/net/quic/quic_connection_logger.h b/net/quic/quic_connection_logger.h
index 550266a..4eb35cd96 100644
--- a/net/quic/quic_connection_logger.h
+++ b/net/quic/quic_connection_logger.h
@@ -86,6 +86,13 @@
   void OnBlockedFrame(const quic::QuicBlockedFrame& frame) override;
   void OnGoAwayFrame(const quic::QuicGoAwayFrame& frame) override;
   void OnPingFrame(const quic::QuicPingFrame& frame) override;
+  void OnPaddingFrame(const quic::QuicPaddingFrame& frame) override;
+  void OnNewConnectionIdFrame(
+      const quic::QuicNewConnectionIdFrame& frame) override;
+  void OnNewTokenFrame(const quic::QuicNewTokenFrame& frame) override;
+  void OnRetireConnectionIdFrame(
+      const quic::QuicRetireConnectionIdFrame& frame) override;
+  void OnMessageFrame(const quic::QuicMessageFrame& frame) override;
   void OnPublicResetPacket(const quic::QuicPublicResetPacket& packet) override;
   void OnVersionNegotiationPacket(
       const quic::QuicVersionNegotiationPacket& packet) override;
diff --git a/net/quic/quic_flags_list.h b/net/quic/quic_flags_list.h
index a203f93..9501613 100644
--- a/net/quic/quic_flags_list.h
+++ b/net/quic/quic_flags_list.h
@@ -399,3 +399,8 @@
 QUIC_FLAG(bool,
           FLAGS_quic_reloadable_flag_quic_close_all_encryptions_levels,
           false)
+
+// If the bandwidth during ack aggregation is smaller than (estimated
+// bandwidth * this flag), consider the current aggregation completed
+// and starts a new one.
+QUIC_FLAG(double, FLAGS_quic_ack_aggregation_bandwidth_threshold, 1.0)
diff --git a/net/quic/quic_http_stream.cc b/net/quic/quic_http_stream.cc
index 5e8732c..1b27888 100644
--- a/net/quic/quic_http_stream.cc
+++ b/net/quic/quic_http_stream.cc
@@ -93,8 +93,6 @@
       return HttpResponseInfo::CONNECTION_INFO_QUIC_43;
     case quic::QUIC_VERSION_46:
       return HttpResponseInfo::CONNECTION_INFO_QUIC_46;
-    case quic::QUIC_VERSION_47:
-      return HttpResponseInfo::CONNECTION_INFO_QUIC_47;
     case quic::QUIC_VERSION_48:
       return HttpResponseInfo::CONNECTION_INFO_QUIC_48;
     case quic::QUIC_VERSION_49:
diff --git a/net/quic/quic_http_utils_test.cc b/net/quic/quic_http_utils_test.cc
index cdb73a8..88431995 100644
--- a/net/quic/quic_http_utils_test.cc
+++ b/net/quic/quic_http_utils_test.cc
@@ -45,20 +45,21 @@
   // versions are versions B and C. FilterSupportedAltSvcVersions
   // finds the intersection of the two sets ... version C.  Note that
   // as QUIC versions are defined/undefined, the exact version numbers
-  // used may need to change.
+  // used may need to change.  The actual version numbers are not
+  // important.
   quic::ParsedQuicVersionVector supported_versions = {
-      ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, quic::QUIC_VERSION_47),
+      ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, quic::QUIC_VERSION_48),
       ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, quic::QUIC_VERSION_43),
   };
 
-  std::vector<uint32_t> alt_svc_versions_google = {quic::QUIC_VERSION_47,
+  std::vector<uint32_t> alt_svc_versions_google = {quic::QUIC_VERSION_48,
                                                    quic::QUIC_VERSION_46};
   std::vector<uint32_t> alt_svc_versions_ietf = {
-      QuicVersionToQuicVersionLabel(quic::QUIC_VERSION_47),
+      QuicVersionToQuicVersionLabel(quic::QUIC_VERSION_48),
       QuicVersionToQuicVersionLabel(quic::QUIC_VERSION_46)};
 
   quic::ParsedQuicVersionVector supported_alt_svc_versions = {
-      ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, quic::QUIC_VERSION_47)};
+      ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, quic::QUIC_VERSION_48)};
   spdy::SpdyAltSvcWireFormat::AlternativeService altsvc;
 
   altsvc.protocol_id = "quic";
diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc
index 493cd30..d3aa05a1d 100644
--- a/net/socket/socket_test_util.cc
+++ b/net/socket/socket_test_util.cc
@@ -141,6 +141,12 @@
   DVLOG(1) << "Stage:   " << (r.sequence_number & ~MockRead::STOPLOOP) << stop;
 }
 
+void RunClosureIfNonNull(base::OnceClosure closure) {
+  if (!closure.is_null()) {
+    std::move(closure).Run();
+  }
+}
+
 }  // namespace
 
 MockConnect::MockConnect() : mode(ASYNC), result(OK) {
@@ -1520,6 +1526,7 @@
   data_->is_connect_data_consumed = true;
   if (data_->connect.result == OK)
     connected_ = true;
+  RunClosureIfNonNull(std::move(data_->connect_callback));
   if (data_->connect.mode == ASYNC) {
     RunCallbackAsync(std::move(callback), data_->connect.result);
     return ERR_IO_PENDING;
@@ -1543,6 +1550,7 @@
   DCHECK(stream_socket_->IsConnected());
   if (data_->is_confirm_data_consumed)
     return data_->confirm.result;
+  RunClosureIfNonNull(std::move(data_->confirm_callback));
   if (data_->confirm.mode == ASYNC) {
     RunCallbackAsync(
         base::BindOnce(&MockSSLClientSocket::RunConfirmHandshakeCallback,
diff --git a/net/socket/socket_test_util.h b/net/socket/socket_test_util.h
index 26690f97..df6e1170 100644
--- a/net/socket/socket_test_util.h
+++ b/net/socket/socket_test_util.h
@@ -475,9 +475,16 @@
 
   // Result for Connect().
   MockConnect connect;
+  // Callback to run when Connect() is called. This is called at most once per
+  // socket but is repeating because SSLSocketDataProvider is copyable.
+  base::RepeatingClosure connect_callback;
 
-  // Result for Confirm().
+  // Result for ConfirmHandshake().
   MockConfirm confirm;
+  // Callback to run when ConfirmHandshake() is called. This is called at most
+  // once per socket but is repeating because SSLSocketDataProvider is
+  // copyable.
+  base::RepeatingClosure confirm_callback;
 
   // Result for GetNegotiatedProtocol().
   NextProto next_proto;
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc
index cee53dd..05cc041 100644
--- a/net/socket/ssl_client_socket_unittest.cc
+++ b/net/socket/ssl_client_socket_unittest.cc
@@ -1972,9 +1972,9 @@
   // Issue a "hanging" Read first.
   TestCompletionCallback callback;
   scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(4096);
-  rv = Read(sock_.get(), buf.get(), 4096, callback.callback());
+  int read_rv = Read(sock_.get(), buf.get(), 4096, callback.callback());
   // We haven't written the request, so there should be no response yet.
-  ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
+  ASSERT_THAT(read_rv, IsError(ERR_IO_PENDING));
 
   // Write the request.
   // The request is padded with a User-Agent header to a size that causes the
@@ -1994,8 +1994,9 @@
   EXPECT_EQ(static_cast<int>(request_text.size()), rv);
 
   // Now get the Read result.
-  rv = WaitForReadCompletion(sock_.get(), buf.get(), 4096, &callback, rv);
-  EXPECT_GT(rv, 0);
+  read_rv =
+      WaitForReadCompletion(sock_.get(), buf.get(), 4096, &callback, read_rv);
+  EXPECT_GT(read_rv, 0);
 }
 
 // Attempts to Read() and Write() from an SSLClientSocketNSS in full duplex
diff --git a/net/spdy/spdy_http_stream.cc b/net/spdy/spdy_http_stream.cc
index 0d644da..368aff89 100644
--- a/net/spdy/spdy_http_stream.cc
+++ b/net/spdy/spdy_http_stream.cc
@@ -259,17 +259,29 @@
     if (!closed_stream_has_load_timing_info_)
       return false;
     *load_timing_info = closed_stream_load_timing_info_;
-    return true;
+  } else {
+    // If |stream_| has yet to be created, or does not yet have an ID, fail.
+    // The reused flag can only be correctly set once a stream has an ID.
+    // Streams get their IDs once the request has been successfully sent, so
+    // this does not behave that differently from other stream types.
+    if (!stream_ || stream_->stream_id() == 0)
+      return false;
+
+    if (!stream_->GetLoadTimingInfo(load_timing_info))
+      return false;
   }
 
-  // If |stream_| has yet to be created, or does not yet have an ID, fail.
-  // The reused flag can only be correctly set once a stream has an ID.  Streams
-  // get their IDs once the request has been successfully sent, so this does not
-  // behave that differently from other stream types.
-  if (!stream_ || stream_->stream_id() == 0)
-    return false;
+  // If the request waited for handshake confirmation, shift |ssl_end| to
+  // include that time.
+  if (!load_timing_info->connect_timing.ssl_end.is_null() &&
+      !stream_request_.confirm_handshake_end().is_null()) {
+    load_timing_info->connect_timing.ssl_end =
+        stream_request_.confirm_handshake_end();
+    load_timing_info->connect_timing.connect_end =
+        stream_request_.confirm_handshake_end();
+  }
 
-  return stream_->GetLoadTimingInfo(load_timing_info);
+  return true;
 }
 
 int SpdyHttpStream::SendRequest(const HttpRequestHeaders& request_headers,
diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc
index efbeb04..bdcecb6 100644
--- a/net/spdy/spdy_network_transaction_unittest.cc
+++ b/net/spdy/spdy_network_transaction_unittest.cc
@@ -87,7 +87,9 @@
 class SpdyNetworkTransactionTest : public TestWithTaskEnvironment {
  protected:
   SpdyNetworkTransactionTest()
-      : default_url_(kDefaultUrl),
+      : TestWithTaskEnvironment(
+            base::test::TaskEnvironment::TimeSource::MOCK_TIME),
+        default_url_(kDefaultUrl),
         host_port_pair_(HostPortPair::FromURL(default_url_)) {}
 
   ~SpdyNetworkTransactionTest() override {
@@ -561,6 +563,11 @@
     return session->stream_hi_water_mark_;
   }
 
+  base::RepeatingClosure FastForwardByCallback(base::TimeDelta delta) {
+    return base::BindRepeating(&SpdyNetworkTransactionTest::FastForwardBy,
+                               base::Unretained(this), delta);
+  }
+
   const GURL default_url_;
   const HostPortPair host_port_pair_;
   HttpRequestInfo request_;
@@ -9591,6 +9598,7 @@
 #endif  // BUILDFLAG(ENABLE_WEBSOCKETS)
 
 TEST_F(SpdyNetworkTransactionTest, ZeroRTTDoesntConfirm) {
+  static const base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(10);
   spdy::SpdySerializedFrame req(
       spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
   MockWrite writes[] = {CreateMockWrite(req, 0)};
@@ -9609,14 +9617,26 @@
   NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
                                      std::move(session_deps));
   auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
+  ssl_provider->connect_callback = FastForwardByCallback(kDelay);
   // Configure |ssl_provider| to fail if ConfirmHandshake is called. The request
   // should still succeed.
   ssl_provider->confirm = MockConfirm(SYNCHRONOUS, ERR_SSL_PROTOCOL_ERROR);
+  ssl_provider->confirm_callback = FastForwardByCallback(kDelay);
+  base::TimeTicks start_time = base::TimeTicks::Now();
   helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
   TransactionHelperResult out = helper.output();
   EXPECT_THAT(out.rv, IsOk());
   EXPECT_EQ("HTTP/1.1 200", out.status_line);
   EXPECT_EQ("hello!", out.response_data);
+
+  // The handshake time should include the time it took to run Connect(), but
+  // not ConfirmHandshake().
+  LoadTimingInfo load_timing_info;
+  EXPECT_TRUE(helper.trans()->GetLoadTimingInfo(&load_timing_info));
+  EXPECT_EQ(load_timing_info.connect_timing.connect_start, start_time);
+  EXPECT_EQ(load_timing_info.connect_timing.ssl_start, start_time);
+  EXPECT_EQ(load_timing_info.connect_timing.ssl_end, start_time + kDelay);
+  EXPECT_EQ(load_timing_info.connect_timing.connect_end, start_time + kDelay);
 }
 
 // Run multiple concurrent streams that don't require handshake confirmation.
@@ -9949,6 +9969,7 @@
 }
 
 TEST_F(SpdyNetworkTransactionTest, ZeroRTTSyncConfirmSyncWrite) {
+  static const base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(10);
   spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
       kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
   spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
@@ -9970,12 +9991,26 @@
   NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
                                      std::move(session_deps));
   auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
+  ssl_provider->connect_callback = FastForwardByCallback(kDelay);
   ssl_provider->confirm = MockConfirm(SYNCHRONOUS, OK);
+  ssl_provider->confirm_callback = FastForwardByCallback(kDelay);
+  base::TimeTicks start_time = base::TimeTicks::Now();
   helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
   TransactionHelperResult out = helper.output();
   EXPECT_THAT(out.rv, IsOk());
   EXPECT_EQ("HTTP/1.1 200", out.status_line);
   EXPECT_EQ("hello!", out.response_data);
+
+  // The handshake time should include the time it took to run Connect(), but
+  // not ConfirmHandshake(). If ConfirmHandshake() returns synchronously, we
+  // assume the connection did not negotiate 0-RTT or the handshake was already
+  // confirmed.
+  LoadTimingInfo load_timing_info;
+  EXPECT_TRUE(helper.trans()->GetLoadTimingInfo(&load_timing_info));
+  EXPECT_EQ(load_timing_info.connect_timing.connect_start, start_time);
+  EXPECT_EQ(load_timing_info.connect_timing.ssl_start, start_time);
+  EXPECT_EQ(load_timing_info.connect_timing.ssl_end, start_time + kDelay);
+  EXPECT_EQ(load_timing_info.connect_timing.connect_end, start_time + kDelay);
 }
 
 TEST_F(SpdyNetworkTransactionTest, ZeroRTTSyncConfirmAsyncWrite) {
@@ -10009,6 +10044,7 @@
 }
 
 TEST_F(SpdyNetworkTransactionTest, ZeroRTTAsyncConfirmSyncWrite) {
+  static const base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(10);
   spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
       kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
   spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
@@ -10030,12 +10066,25 @@
   NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
                                      std::move(session_deps));
   auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
+  ssl_provider->connect_callback = FastForwardByCallback(kDelay);
   ssl_provider->confirm = MockConfirm(ASYNC, OK);
+  ssl_provider->confirm_callback = FastForwardByCallback(kDelay);
+  base::TimeTicks start_time = base::TimeTicks::Now();
   helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
   TransactionHelperResult out = helper.output();
   EXPECT_THAT(out.rv, IsOk());
   EXPECT_EQ("HTTP/1.1 200", out.status_line);
   EXPECT_EQ("hello!", out.response_data);
+
+  // The handshake time should include the time it took to run Connect() and
+  // ConfirmHandshake().
+  LoadTimingInfo load_timing_info;
+  EXPECT_TRUE(helper.trans()->GetLoadTimingInfo(&load_timing_info));
+  EXPECT_EQ(load_timing_info.connect_timing.connect_start, start_time);
+  EXPECT_EQ(load_timing_info.connect_timing.ssl_start, start_time);
+  EXPECT_EQ(load_timing_info.connect_timing.ssl_end, start_time + 2 * kDelay);
+  EXPECT_EQ(load_timing_info.connect_timing.connect_end,
+            start_time + 2 * kDelay);
 }
 
 TEST_F(SpdyNetworkTransactionTest, ZeroRTTAsyncConfirmAsyncWrite) {
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc
index fc2cb7cd..0c07a22e 100644
--- a/net/spdy/spdy_session.cc
+++ b/net/spdy/spdy_session.cc
@@ -651,33 +651,44 @@
   type_ = type;
   session_ = session;
   url_ = SimplifyUrlForRequest(url);
-  can_send_early_ = can_send_early;
   priority_ = priority;
   socket_tag_ = socket_tag;
   net_log_ = net_log;
   callback_ = std::move(callback);
   traffic_annotation_ = MutableNetworkTrafficAnnotationTag(traffic_annotation);
 
-  next_state_ = STATE_WAIT_FOR_CONFIRMATION;
-  int rv = DoLoop(OK);
-  if (rv != OK)
+  // If early data is not allowed, confirm the handshake first.
+  int rv = OK;
+  if (!can_send_early) {
+    rv = session_->ConfirmHandshake(
+        base::BindOnce(&SpdyStreamRequest::OnConfirmHandshakeComplete,
+                       weak_ptr_factory_.GetWeakPtr()));
+  }
+  if (rv != OK) {
+    // If rv is ERR_IO_PENDING, OnConfirmHandshakeComplete() will call
+    // TryCreateStream() later.
     return rv;
+  }
 
   base::WeakPtr<SpdyStream> stream;
   rv = session->TryCreateStream(weak_ptr_factory_.GetWeakPtr(), &stream);
-  if (rv != OK)
+  if (rv != OK) {
+    // If rv is ERR_IO_PENDING, the SpdySession will call
+    // OnRequestCompleteSuccess() or OnRequestCompleteFailure() later.
     return rv;
+  }
 
   Reset();
   stream_ = stream;
-  return rv;
+  return OK;
 }
 
 void SpdyStreamRequest::CancelRequest() {
   if (session_)
     session_->CancelStreamRequest(weak_ptr_factory_.GetWeakPtr());
   Reset();
-  // Do this to cancel any pending CompleteStreamRequest() tasks.
+  // Do this to cancel any pending CompleteStreamRequest() and
+  // OnConfirmHandshakeComplete() tasks.
   weak_ptr_factory_.InvalidateWeakPtrs();
 }
 
@@ -732,74 +743,33 @@
   session_.reset();
   stream_.reset();
   url_ = GURL();
-  can_send_early_ = false;
   priority_ = MINIMUM_PRIORITY;
   socket_tag_ = SocketTag();
   net_log_ = NetLogWithSource();
   callback_.Reset();
   traffic_annotation_.reset();
-  next_state_ = STATE_NONE;
 }
 
-void SpdyStreamRequest::OnIOComplete(int rv) {
+void SpdyStreamRequest::OnConfirmHandshakeComplete(int rv) {
+  DCHECK_NE(ERR_IO_PENDING, rv);
   if (rv != OK) {
     OnRequestCompleteFailure(rv);
-  } else {
-    DoLoop(rv);
-  }
-}
-
-int SpdyStreamRequest::DoLoop(int rv) {
-  do {
-    State state = next_state_;
-    next_state_ = STATE_NONE;
-    switch (state) {
-      case STATE_WAIT_FOR_CONFIRMATION:
-        CHECK_EQ(OK, rv);
-        return DoWaitForConfirmation();
-        break;
-      case STATE_REQUEST_STREAM:
-        CHECK_EQ(OK, rv);
-        return DoRequestStream(rv);
-        break;
-      default:
-        NOTREACHED() << "next_state_: " << next_state_;
-        break;
-    }
-  } while (next_state_ != STATE_NONE && next_state_ && rv != ERR_IO_PENDING);
-  return rv;
-}
-
-int SpdyStreamRequest::DoWaitForConfirmation() {
-  if (can_send_early_) {
-    next_state_ = STATE_NONE;
-    return OK;
+    return;
   }
 
-  int rv = session_->ConfirmHandshake(base::BindOnce(
-      &SpdyStreamRequest::OnIOComplete, weak_ptr_factory_.GetWeakPtr()));
-  // If ConfirmHandshake returned synchronously, exit the state machine early
-  // so StartRequest can call TryCreateStream synchronously. Otherwise,
-  // TryCreateStream will be called asynchronously as part of the confirmation
-  // state machine.
-  next_state_ = rv == ERR_IO_PENDING ? STATE_REQUEST_STREAM : STATE_NONE;
-  return rv;
-}
-
-int SpdyStreamRequest::DoRequestStream(int rv) {
-  DCHECK_NE(ERR_IO_PENDING, rv);
-  next_state_ = STATE_NONE;
-  if (rv < 0)
-    return rv;
+  // ConfirmHandshake() completed asynchronously. Record the time so the caller
+  // can adjust LoadTimingInfo.
+  confirm_handshake_end_ = base::TimeTicks::Now();
 
   base::WeakPtr<SpdyStream> stream;
   rv = session_->TryCreateStream(weak_ptr_factory_.GetWeakPtr(), &stream);
   if (rv == OK) {
     OnRequestCompleteSuccess(stream);
   } else if (rv != ERR_IO_PENDING) {
+    // If rv is ERR_IO_PENDING, the SpdySession will call
+    // OnRequestCompleteSuccess() or OnRequestCompleteFailure() later.
     OnRequestCompleteFailure(rv);
   }
-  return rv;
 }
 
 // static
diff --git a/net/spdy/spdy_session.h b/net/spdy/spdy_session.h
index a93faf5..750e983 100644
--- a/net/spdy/spdy_session.h
+++ b/net/spdy/spdy_session.h
@@ -199,6 +199,12 @@
   // Calls CancelRequest().
   ~SpdyStreamRequest();
 
+  // Returns the time when ConfirmHandshake() completed, if this request had to
+  // wait for ConfirmHandshake().
+  base::TimeTicks confirm_handshake_end() const {
+    return confirm_handshake_end_;
+  }
+
   // Starts the request to create a stream. If OK is returned, then
   // ReleaseStream() may be called. If ERR_IO_PENDING is returned,
   // then when the stream is created, |callback| will be called, at
@@ -248,16 +254,7 @@
  private:
   friend class SpdySession;
 
-  enum State {
-    STATE_NONE,
-    STATE_WAIT_FOR_CONFIRMATION,
-    STATE_REQUEST_STREAM,
-  };
-
-  void OnIOComplete(int rv);
-  int DoLoop(int rv);
-  int DoWaitForConfirmation();
-  int DoRequestStream(int rv);
+  void OnConfirmHandshakeComplete(int rv);
 
   // Called by |session_| when the stream attempt has finished
   // successfully.
@@ -280,13 +277,12 @@
   base::WeakPtr<SpdySession> session_;
   base::WeakPtr<SpdyStream> stream_;
   GURL url_;
-  bool can_send_early_;
   RequestPriority priority_;
   SocketTag socket_tag_;
   NetLogWithSource net_log_;
   CompletionOnceCallback callback_;
   MutableNetworkTrafficAnnotationTag traffic_annotation_;
-  State next_state_;
+  base::TimeTicks confirm_handshake_end_;
 
   base::WeakPtrFactory<SpdyStreamRequest> weak_ptr_factory_{this};
 
diff --git a/net/url_request/data_protocol_handler.h b/net/url_request/data_protocol_handler.h
index c65758f..dcc9b99 100644
--- a/net/url_request/data_protocol_handler.h
+++ b/net/url_request/data_protocol_handler.h
@@ -15,8 +15,8 @@
 class URLRequestJob;
 
 // Implements a ProtocolHandler for Data jobs.
-class NET_EXPORT DataProtocolHandler
-    : public URLRequestJobFactory::ProtocolHandler {
+// TODO(mmenke): This class is now only used in tests. Remove it.
+class DataProtocolHandler : public URLRequestJobFactory::ProtocolHandler {
  public:
   DataProtocolHandler();
   URLRequestJob* MaybeCreateJob(
diff --git a/net/url_request/url_request_context_builder.cc b/net/url_request/url_request_context_builder.cc
index 7825bf23..8e04423 100644
--- a/net/url_request/url_request_context_builder.cc
+++ b/net/url_request/url_request_context_builder.cc
@@ -38,7 +38,6 @@
 #include "net/nqe/network_quality_estimator.h"
 #include "net/quic/quic_stream_factory.h"
 #include "net/ssl/ssl_config_service_defaults.h"
-#include "net/url_request/data_protocol_handler.h"
 #include "net/url_request/static_http_user_agent_settings.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_storage.h"
@@ -610,17 +609,13 @@
 
   URLRequestJobFactoryImpl* job_factory = new URLRequestJobFactoryImpl;
   // Adds caller-provided protocol handlers first so that these handlers are
-  // used over data/file/ftp handlers below.
+  // used over the ftp handler below.
   for (auto& scheme_handler : protocol_handlers_) {
     job_factory->SetProtocolHandler(scheme_handler.first,
                                     std::move(scheme_handler.second));
   }
   protocol_handlers_.clear();
 
-  if (data_enabled_)
-    job_factory->SetProtocolHandler(url::kDataScheme,
-                                    std::make_unique<DataProtocolHandler>());
-
 #if !BUILDFLAG(DISABLE_FTP_SUPPORT)
   if (ftp_enabled_) {
     storage->set_ftp_auth_cache(std::make_unique<FtpAuthCache>());
diff --git a/net/url_request/url_request_context_builder.h b/net/url_request/url_request_context_builder.h
index 203a6fe..a32278e 100644
--- a/net/url_request/url_request_context_builder.h
+++ b/net/url_request/url_request_context_builder.h
@@ -195,9 +195,6 @@
   void set_http_user_agent_settings(
       std::unique_ptr<HttpUserAgentSettings> http_user_agent_settings);
 
-  // Control support for data:// requests. By default it's disabled.
-  void set_data_enabled(bool enable) { data_enabled_ = enable; }
-
 #if !BUILDFLAG(DISABLE_FTP_SUPPORT)
   // Control support for ftp:// requests. By default it's disabled.
   void set_ftp_enabled(bool enable) { ftp_enabled_ = enable; }
@@ -357,8 +354,6 @@
   std::string user_agent_;
   std::unique_ptr<HttpUserAgentSettings> http_user_agent_settings_;
 
-  // Include support for data:// requests.
-  bool data_enabled_ = false;
 #if !BUILDFLAG(DISABLE_FTP_SUPPORT)
   // Include support for ftp:// requests.
   bool ftp_enabled_ = false;
diff --git a/sandbox/win/src/policy_engine_opcodes.h b/sandbox/win/src/policy_engine_opcodes.h
index 22d1ee2..3f9a69b 100644
--- a/sandbox/win/src/policy_engine_opcodes.h
+++ b/sandbox/win/src/policy_engine_opcodes.h
@@ -193,9 +193,7 @@
   uint32_t GetOptions() const { return options_; }
 
   // Sets the stored options such as kPolNegateEval.
-  void SetOptions(uint32_t options) {
-    options_ = base::checked_cast<uint16_t>(options);
-  }
+  void SetOptions(uint32_t options) { options_ = options; }
 
  private:
   static const size_t kArgumentCount = 4;  // The number of supported argument.
@@ -214,10 +212,7 @@
                             MatchContext* match);
   OpcodeID opcode_id_;
   int16_t parameter_;
-  // TODO(cpu): Making |options_| a uint32_t would avoid casting, but causes
-  // test failures.  Somewhere code is relying on the size of this struct.
-  // http://crbug.com/420296
-  uint16_t options_;
+  uint32_t options_;
   OpcodeArgument arguments_[PolicyOpcode::kArgumentCount];
 };
 
diff --git a/sandbox/win/src/policy_low_level.cc b/sandbox/win/src/policy_low_level.cc
index d2c9a6f..fd4e5576 100644
--- a/sandbox/win/src/policy_low_level.cc
+++ b/sandbox/win/src/policy_low_level.cc
@@ -113,10 +113,10 @@
       svc_opcode_count += op_count;
     }
 
-    current_buffer->opcode_count += svc_opcode_count;
-    size_t policy_byte_count =
+    current_buffer->opcode_count = svc_opcode_count;
+    size_t policy_buffers_occupied =
         (svc_opcode_count * sizeof(PolicyOpcode)) / sizeof(current_buffer[0]);
-    current_buffer = &current_buffer[policy_byte_count + 1];
+    current_buffer = &current_buffer[policy_buffers_occupied + 1];
   }
 
   return true;
diff --git a/sandbox/win/src/policy_low_level_unittest.cc b/sandbox/win/src/policy_low_level_unittest.cc
index 681ec38f..a91e9235 100644
--- a/sandbox/win/src/policy_low_level_unittest.cc
+++ b/sandbox/win/src/policy_low_level_unittest.cc
@@ -618,4 +618,50 @@
   EXPECT_EQ(POLICY_MATCH, result);
   EXPECT_EQ(ASK_BROKER, pol_ev_copy.GetAction());
 }
+
+TEST(PolicyEngineTest, PolicyGenDoneCalledTwice) {
+  SetupNtdllImports();
+  // The specific rules here are not important.
+  PolicyRule pr_orig(ASK_BROKER);
+  EXPECT_TRUE(pr_orig.AddStringMatch(IF, 0, L"hello.*", CASE_SENSITIVE));
+
+  PolicyRule pr_copy(pr_orig);
+  EXPECT_TRUE(pr_orig.AddStringMatch(IF_NOT, 0, L"*.txt", CASE_SENSITIVE));
+  EXPECT_TRUE(pr_copy.AddStringMatch(IF_NOT, 0, L"*.txt", CASE_SENSITIVE));
+
+  PolicyGlobal* policy = MakePolicyMemory();
+  LowLevelPolicy policyGen(policy);
+  EXPECT_TRUE(policyGen.AddRule(1, &pr_orig));
+  EXPECT_TRUE(policyGen.AddRule(2, &pr_copy));
+  EXPECT_TRUE(policyGen.Done());
+
+  // Obtain opcode counts.
+  size_t tc1 = policy->entry[1]->opcode_count;
+  size_t tc2 = policy->entry[2]->opcode_count;
+
+  // Call Done() again.
+  EXPECT_TRUE(policyGen.Done());
+
+  // Expect same opcode counts.
+  EXPECT_EQ(tc1, policy->entry[1]->opcode_count);
+  EXPECT_EQ(tc2, policy->entry[2]->opcode_count);
+
+  // Confirm the rules work as before.
+  const wchar_t* name = nullptr;
+  POLPARAMS_BEGIN(eval_params)
+    POLPARAM(name)
+  POLPARAMS_END;
+
+  PolicyResult result;
+  PolicyProcessor pol_ev_orig(policy->entry[1]);
+  name = L"domo.txt";
+  result = pol_ev_orig.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+
+  name = L"hello.bmp";
+  result = pol_ev_orig.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(POLICY_MATCH, result);
+  EXPECT_EQ(ASK_BROKER, pol_ev_orig.GetAction());
+}
+
 }  // namespace sandbox
diff --git a/services/network/public/cpp/wrapper_shared_url_loader_factory.h b/services/network/public/cpp/wrapper_shared_url_loader_factory.h
index cc96471..42a73ab 100644
--- a/services/network/public/cpp/wrapper_shared_url_loader_factory.h
+++ b/services/network/public/cpp/wrapper_shared_url_loader_factory.h
@@ -7,6 +7,7 @@
 
 #include "base/component_export.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/mojom/url_loader.mojom.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
@@ -32,19 +33,19 @@
 };
 
 // A SharedURLLoaderFactory implementation that wraps a
-// PtrTemplateType<network::mojom::URLLoaderFactory>.
-template <template <typename> class PtrTemplateType>
+// RemoteTemplateType<network::mojom::URLLoaderFactory>.
+template <template <typename> class RemoteTemplateType>
 class WrapperSharedURLLoaderFactoryBase
     : public network::SharedURLLoaderFactory {
  public:
-  using PtrType = PtrTemplateType<network::mojom::URLLoaderFactory>;
-  using PtrInfoType = typename PtrType::PtrInfoType;
+  using RemoteType = RemoteTemplateType<network::mojom::URLLoaderFactory>;
+  using PendingType = typename RemoteType::PendingType;
 
-  explicit WrapperSharedURLLoaderFactoryBase(PtrType factory_ptr)
-      : factory_ptr_(std::move(factory_ptr)) {}
+  explicit WrapperSharedURLLoaderFactoryBase(RemoteType factory_remote)
+      : factory_remote_(std::move(factory_remote)) {}
 
-  explicit WrapperSharedURLLoaderFactoryBase(PtrInfoType factory_ptr_info)
-      : factory_ptr_(std::move(factory_ptr_info)) {}
+  explicit WrapperSharedURLLoaderFactoryBase(PendingType pending_factory_remote)
+      : factory_remote_(std::move(pending_factory_remote)) {}
 
   // SharedURLLoaderFactory implementation:
 
@@ -56,36 +57,39 @@
                             network::mojom::URLLoaderClientPtr client,
                             const net::MutableNetworkTrafficAnnotationTag&
                                 traffic_annotation) override {
-    if (!factory_ptr_)
+    if (!factory_remote_)
       return;
-    factory_ptr_->CreateLoaderAndStart(std::move(loader), routing_id,
-                                       request_id, options, request,
-                                       std::move(client), traffic_annotation);
+    factory_remote_->CreateLoaderAndStart(
+        std::move(loader), routing_id, request_id, options, request,
+        std::move(client), traffic_annotation);
   }
 
   void Clone(mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver)
       override {
-    if (!factory_ptr_)
+    if (!factory_remote_)
       return;
-    factory_ptr_->Clone(std::move(receiver));
+    factory_remote_->Clone(std::move(receiver));
   }
 
   std::unique_ptr<network::SharedURLLoaderFactoryInfo> Clone() override {
-    network::mojom::URLLoaderFactoryPtrInfo factory_ptr_info;
-    if (factory_ptr_)
-      factory_ptr_->Clone(mojo::MakeRequest(&factory_ptr_info));
+    mojo::PendingRemote<network::mojom::URLLoaderFactory>
+        pending_factory_remote;
+    if (factory_remote_) {
+      factory_remote_->Clone(
+          pending_factory_remote.InitWithNewPipeAndPassReceiver());
+    }
     return std::make_unique<WrapperSharedURLLoaderFactoryInfo>(
-        std::move(factory_ptr_info));
+        std::move(pending_factory_remote));
   }
 
  private:
   ~WrapperSharedURLLoaderFactoryBase() override = default;
 
-  PtrType factory_ptr_;
+  RemoteType factory_remote_;
 };
 
 using WrapperSharedURLLoaderFactory =
-    WrapperSharedURLLoaderFactoryBase<mojo::InterfacePtr>;
+    WrapperSharedURLLoaderFactoryBase<mojo::Remote>;
 
 }  // namespace network
 
diff --git a/testing/android/native_test/native_test_launcher.cc b/testing/android/native_test/native_test_launcher.cc
index e03b9e2f..c66af52b 100644
--- a/testing/android/native_test/native_test_launcher.cc
+++ b/testing/android/native_test/native_test_launcher.cc
@@ -18,6 +18,7 @@
 #include "base/android/scoped_java_ref.h"
 #include "base/at_exit.h"
 #include "base/base_switches.h"
+#include "base/clang_coverage_buildflags.h"
 #include "base/command_line.h"
 #include "base/debug/debugger.h"
 #include "base/files/file_path.h"
@@ -32,6 +33,10 @@
 #include "testing/android/native_test/native_test_jni_headers/NativeTest_jni.h"
 #include "testing/android/native_test/native_test_util.h"
 
+#if BUILDFLAG(CLANG_COVERAGE)
+#include "base/test/clang_coverage.h"
+#endif
+
 using base::android::JavaParamRef;
 
 // The main function of the program to be wrapped as a test apk.
@@ -134,6 +139,11 @@
 
   ScopedMainEntryLogger scoped_main_entry_logger;
   main(argc, &argv[0]);
+
+// Explicitly write coverage data to LLVM profile file.
+#if BUILDFLAG(CLANG_COVERAGE)
+  base::WriteClangCoverageProfile();
+#endif
 }
 
 // TODO(nileshagrawal): now that we're using FIFO, test scripts can detect EOF.
diff --git a/testing/buildbot/chromium.dawn.json b/testing/buildbot/chromium.dawn.json
index b44bdc95..f6b63d725 100644
--- a/testing/buildbot/chromium.dawn.json
+++ b/testing/buildbot/chromium.dawn.json
@@ -143,15 +143,13 @@
       },
       {
         "args": [
-          "--additional-driver-flag",
-          "--enable-unsafe-webgpu",
-          "--additional-driver-flag",
-          "--disable-gpu-sandbox",
+          "--additional-driver-flag=--enable-unsafe-webgpu",
           "--driver-logging",
           "--ignore-default-expectations",
           "--additional-expectations=../../third_party/blink/web_tests/WebGPUExpectations",
           "--isolated-script-test-filter=wpt_internal/webgpu/*",
-          "--no-xvfb"
+          "--no-xvfb",
+          "--additional-driver-flag=--disable-gpu-sandbox"
         ],
         "isolate_name": "blink_web_tests_exparchive",
         "merge": {
@@ -314,15 +312,13 @@
       },
       {
         "args": [
-          "--additional-driver-flag",
-          "--enable-unsafe-webgpu",
-          "--additional-driver-flag",
-          "--disable-gpu-sandbox",
+          "--additional-driver-flag=--enable-unsafe-webgpu",
           "--driver-logging",
           "--ignore-default-expectations",
           "--additional-expectations=../../third_party/blink/web_tests/WebGPUExpectations",
           "--isolated-script-test-filter=wpt_internal/webgpu/*",
-          "--no-xvfb"
+          "--no-xvfb",
+          "--additional-driver-flag=--disable-gpu-sandbox"
         ],
         "isolate_name": "blink_web_tests_exparchive",
         "merge": {
@@ -688,14 +684,12 @@
       },
       {
         "args": [
-          "--additional-driver-flag",
-          "--enable-unsafe-webgpu",
-          "--additional-driver-flag",
-          "--disable-gpu-sandbox",
+          "--additional-driver-flag=--enable-unsafe-webgpu",
           "--driver-logging",
           "--ignore-default-expectations",
           "--additional-expectations=../../third_party/blink/web_tests/WebGPUExpectations",
-          "--isolated-script-test-filter=wpt_internal/webgpu/*"
+          "--isolated-script-test-filter=wpt_internal/webgpu/*",
+          "--platform=mac-mac10.13"
         ],
         "isolate_name": "blink_web_tests_exparchive",
         "merge": {
@@ -852,14 +846,12 @@
       },
       {
         "args": [
-          "--additional-driver-flag",
-          "--enable-unsafe-webgpu",
-          "--additional-driver-flag",
-          "--disable-gpu-sandbox",
+          "--additional-driver-flag=--enable-unsafe-webgpu",
           "--driver-logging",
           "--ignore-default-expectations",
           "--additional-expectations=../../third_party/blink/web_tests/WebGPUExpectations",
-          "--isolated-script-test-filter=wpt_internal/webgpu/*"
+          "--isolated-script-test-filter=wpt_internal/webgpu/*",
+          "--platform=mac-mac10.13"
         ],
         "isolate_name": "blink_web_tests_exparchive",
         "merge": {
@@ -1218,16 +1210,13 @@
       },
       {
         "args": [
-          "--additional-driver-flag",
-          "--enable-unsafe-webgpu",
-          "--additional-driver-flag",
-          "--disable-gpu-sandbox",
+          "--additional-driver-flag=--enable-unsafe-webgpu",
           "--driver-logging",
           "--ignore-default-expectations",
           "--additional-expectations=../../third_party/blink/web_tests/WebGPUExpectations",
-          "-t",
-          "Release_x64",
-          "--isolated-script-test-filter=wpt_internal/webgpu/*"
+          "--isolated-script-test-filter=wpt_internal/webgpu/*",
+          "--additional-driver-flag=--disable-gpu-sandbox",
+          "--target=Release_x64"
         ],
         "isolate_name": "blink_web_tests_exparchive",
         "merge": {
@@ -1389,16 +1378,13 @@
       },
       {
         "args": [
-          "--additional-driver-flag",
-          "--enable-unsafe-webgpu",
-          "--additional-driver-flag",
-          "--disable-gpu-sandbox",
+          "--additional-driver-flag=--enable-unsafe-webgpu",
           "--driver-logging",
           "--ignore-default-expectations",
           "--additional-expectations=../../third_party/blink/web_tests/WebGPUExpectations",
-          "-t",
-          "Release_x64",
-          "--isolated-script-test-filter=wpt_internal/webgpu/*"
+          "--isolated-script-test-filter=wpt_internal/webgpu/*",
+          "--additional-driver-flag=--disable-gpu-sandbox",
+          "--target=Release_x64"
         ],
         "isolate_name": "blink_web_tests_exparchive",
         "merge": {
@@ -1758,14 +1744,12 @@
       },
       {
         "args": [
-          "--additional-driver-flag",
-          "--enable-unsafe-webgpu",
-          "--additional-driver-flag",
-          "--disable-gpu-sandbox",
+          "--additional-driver-flag=--enable-unsafe-webgpu",
           "--driver-logging",
           "--ignore-default-expectations",
           "--additional-expectations=../../third_party/blink/web_tests/WebGPUExpectations",
-          "--isolated-script-test-filter=wpt_internal/webgpu/*"
+          "--isolated-script-test-filter=wpt_internal/webgpu/*",
+          "--additional-driver-flag=--disable-gpu-sandbox"
         ],
         "isolate_name": "blink_web_tests_exparchive",
         "merge": {
@@ -1927,14 +1911,12 @@
       },
       {
         "args": [
-          "--additional-driver-flag",
-          "--enable-unsafe-webgpu",
-          "--additional-driver-flag",
-          "--disable-gpu-sandbox",
+          "--additional-driver-flag=--enable-unsafe-webgpu",
           "--driver-logging",
           "--ignore-default-expectations",
           "--additional-expectations=../../third_party/blink/web_tests/WebGPUExpectations",
-          "--isolated-script-test-filter=wpt_internal/webgpu/*"
+          "--isolated-script-test-filter=wpt_internal/webgpu/*",
+          "--additional-driver-flag=--disable-gpu-sandbox"
         ],
         "isolate_name": "blink_web_tests_exparchive",
         "merge": {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index cb252a1..89117a3 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -105,6 +105,7 @@
           "--test-launcher-jobs=1",
           "--test-launcher-filter-file=../../testing/buildbot/filters/vulkan.content_browsertests.filter",
           "--enable-features=UseSkiaRenderer,UiGpuRasterization",
+          "--gr-context-type=vulkan",
           "--use-vulkan=swiftshader",
           "--enable-oop-rasterization",
           "--enable-gpu-rasterization",
@@ -170,6 +171,7 @@
           "--additional-driver-flag=--enable-features=UseSkiaRenderer",
           "--additional-driver-flag=--force-gpu-rasterization",
           "--additional-driver-flag=--enable-oop-rasterization",
+          "--additional-driver-flag=--gr-context-type=vulkan",
           "--additional-driver-flag=--use-vulkan=swiftshader",
           "--additional-driver-flag=--disable-vulkan-fallback-to-gl-for-testing",
           "--fuzzy-diff",
@@ -16486,6 +16488,7 @@
           "--additional-driver-flag=--enable-features=UseSkiaRenderer",
           "--additional-driver-flag=--force-gpu-rasterization",
           "--additional-driver-flag=--enable-oop-rasterization",
+          "--additional-driver-flag=--gr-context-type=vulkan",
           "--additional-driver-flag=--use-vulkan=swiftshader",
           "--additional-driver-flag=--disable-vulkan-fallback-to-gl-for-testing",
           "--fuzzy-diff",
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index ec6e3de..26192ada 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -6805,7 +6805,7 @@
           "--browser=android-chromium",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-vulkan=native --disable-vulkan-fallback-to-gl-for-testing --enable-features=UseSkiaRenderer --use-cmd-decoder=validating",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --gr-context-type=vulkan --use-vulkan=native --disable-vulkan-fallback-to-gl-for-testing --enable-features=UseSkiaRenderer --use-cmd-decoder=validating",
           "--dont-restore-color-profile-after-test",
           "--build-revision",
           "${got_revision}",
@@ -10078,6 +10078,7 @@
           "--test-launcher-jobs=1",
           "--test-launcher-filter-file=../../testing/buildbot/filters/vulkan.content_browsertests.filter",
           "--enable-features=UseSkiaRenderer,UiGpuRasterization",
+          "--gr-context-type=vulkan",
           "--use-vulkan=native",
           "--enable-oop-rasterization",
           "--enable-gpu-rasterization",
@@ -10387,6 +10388,7 @@
           "--additional-driver-flag=--force-gpu-rasterization",
           "--additional-driver-flag=--enable-oop-rasterization",
           "--additional-driver-flag=--disable-software-compositing-fallback",
+          "--additional-driver-flag=--gr-context-type=vulkan",
           "--additional-driver-flag=--use-vulkan=native",
           "--additional-driver-flag=--disable-vulkan-fallback-to-gl-for-testing",
           "--additional-driver-flag=--disable-headless-mode",
@@ -10427,7 +10429,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-vulkan=native --disable-vulkan-fallback-to-gl-for-testing --enable-features=UseSkiaRenderer --use-cmd-decoder=validating",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --gr-context-type=vulkan --use-vulkan=native --disable-vulkan-fallback-to-gl-for-testing --enable-features=UseSkiaRenderer --use-cmd-decoder=validating",
           "--dont-restore-color-profile-after-test",
           "--build-revision",
           "${got_revision}",
@@ -10474,6 +10476,7 @@
           "--test-launcher-jobs=1",
           "--test-launcher-filter-file=../../testing/buildbot/filters/vulkan.content_browsertests.filter",
           "--enable-features=UseSkiaRenderer,UiGpuRasterization",
+          "--gr-context-type=vulkan",
           "--use-vulkan=native",
           "--enable-oop-rasterization",
           "--enable-gpu-rasterization",
@@ -10783,6 +10786,7 @@
           "--additional-driver-flag=--force-gpu-rasterization",
           "--additional-driver-flag=--enable-oop-rasterization",
           "--additional-driver-flag=--disable-software-compositing-fallback",
+          "--additional-driver-flag=--gr-context-type=vulkan",
           "--additional-driver-flag=--use-vulkan=native",
           "--additional-driver-flag=--disable-vulkan-fallback-to-gl-for-testing",
           "--additional-driver-flag=--disable-headless-mode",
@@ -10823,7 +10827,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-vulkan=native --disable-vulkan-fallback-to-gl-for-testing --enable-features=UseSkiaRenderer --use-cmd-decoder=validating",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --gr-context-type=vulkan --use-vulkan=native --disable-vulkan-fallback-to-gl-for-testing --enable-features=UseSkiaRenderer --use-cmd-decoder=validating",
           "--dont-restore-color-profile-after-test",
           "--build-revision",
           "${got_revision}",
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index e84de2ef..f9a3281 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -4020,6 +4020,7 @@
           "--additional-driver-flag=--enable-features=UseSkiaRenderer",
           "--additional-driver-flag=--force-gpu-rasterization",
           "--additional-driver-flag=--enable-oop-rasterization",
+          "--additional-driver-flag=--gr-context-type=vulkan",
           "--additional-driver-flag=--use-vulkan=swiftshader",
           "--additional-driver-flag=--disable-vulkan-fallback-to-gl-for-testing",
           "--fuzzy-diff",
@@ -7564,6 +7565,7 @@
           "--additional-driver-flag=--enable-features=UseSkiaRenderer",
           "--additional-driver-flag=--force-gpu-rasterization",
           "--additional-driver-flag=--enable-oop-rasterization",
+          "--additional-driver-flag=--gr-context-type=vulkan",
           "--additional-driver-flag=--use-vulkan=swiftshader",
           "--additional-driver-flag=--disable-vulkan-fallback-to-gl-for-testing",
           "--fuzzy-diff",
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 0b81520..218c410f 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -11885,6 +11885,7 @@
           "--test-launcher-jobs=1",
           "--test-launcher-filter-file=../../testing/buildbot/filters/vulkan.content_browsertests.filter",
           "--enable-features=UseSkiaRenderer,UiGpuRasterization",
+          "--gr-context-type=vulkan",
           "--use-vulkan=swiftshader",
           "--enable-oop-rasterization",
           "--enable-gpu-rasterization",
diff --git a/testing/buildbot/generate_buildbot_json.py b/testing/buildbot/generate_buildbot_json.py
index 4dddfeb..453eee4 100755
--- a/testing/buildbot/generate_buildbot_json.py
+++ b/testing/buildbot/generate_buildbot_json.py
@@ -239,6 +239,16 @@
   def is_linux(self, tester_config):
     return tester_config.get('os_type') == 'linux'
 
+  def is_mac(self, tester_config):
+    return tester_config.get('os_type') == 'mac'
+
+  def is_win(self, tester_config):
+    return tester_config.get('os_type') == 'win'
+
+  def is_win64(self, tester_config):
+    return (tester_config.get('os_type') == 'win' and
+        tester_config.get('browser_config') == 'release_x64')
+
   def get_exception_for_test(self, test_name, test_config):
     # gtests may have both "test" and "name" fields, and usually, if the "name"
     # field is specified, it means that the same test is being repurposed
@@ -387,6 +397,9 @@
     add_conditional_args('linux_args', self.is_linux)
     add_conditional_args('android_args', self.is_android)
     add_conditional_args('chromeos_args', self.is_chromeos)
+    add_conditional_args('mac_args', self.is_mac)
+    add_conditional_args('win_args', self.is_win)
+    add_conditional_args('win64_args', self.is_win64)
 
     for key in additional_arg_keys or []:
       args.extend(generated_test.pop(key, []))
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index f542834..255bc00 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -2058,6 +2058,12 @@
           '--additional-driver-flag=--use-gpu-in-tests',
         ],
       },
+      # tryserver.chromium.linux
+      'linux-layout-tests-fragment-item': {
+        'args': [
+          '--additional-driver-flag=--enable-blink-features=LayoutNGFragmentItem',
+        ],
+      },
       # client.v8.fyi
       'V8 Blink Linux Debug': {
         'args': [
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index cfb4671..6815685 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -3390,6 +3390,7 @@
           '--additional-driver-flag=--force-gpu-rasterization',
           '--additional-driver-flag=--enable-oop-rasterization',
           '--additional-driver-flag=--disable-software-compositing-fallback',
+          '--additional-driver-flag=--gr-context-type=vulkan',
           '--additional-driver-flag=--use-vulkan=native',
           '--additional-driver-flag=--disable-vulkan-fallback-to-gl-for-testing',
           '--additional-driver-flag=--disable-headless-mode',
@@ -3650,6 +3651,7 @@
           '--test-launcher-jobs=1',
           '--test-launcher-filter-file=../../testing/buildbot/filters/vulkan.content_browsertests.filter',
           '--enable-features=UseSkiaRenderer,UiGpuRasterization',
+          '--gr-context-type=vulkan',
           '--use-vulkan=native',
           '--enable-oop-rasterization',
           '--enable-gpu-rasterization',
@@ -3671,6 +3673,7 @@
           '--test-launcher-jobs=1',
           '--test-launcher-filter-file=../../testing/buildbot/filters/vulkan.content_browsertests.filter',
           '--enable-features=UseSkiaRenderer,UiGpuRasterization',
+          '--gr-context-type=vulkan',
           '--use-vulkan=swiftshader',
           '--enable-oop-rasterization',
           '--enable-gpu-rasterization',
@@ -3878,7 +3881,7 @@
           '${got_revision}',
           '--test-machine-name',
           '${buildername}',
-          '--extra-browser-args=--use-vulkan=native --disable-vulkan-fallback-to-gl-for-testing --enable-features=UseSkiaRenderer --use-cmd-decoder=validating',
+          '--extra-browser-args=--gr-context-type=vulkan --use-vulkan=native --disable-vulkan-fallback-to-gl-for-testing --enable-features=UseSkiaRenderer --use-cmd-decoder=validating',
         ],
         'precommit_args': [
           # Gerrit issue ID
@@ -4117,35 +4120,22 @@
       'webgpu_blink_web_tests': {
         'name': 'webgpu_blink_web_tests',
         'args': [
-          '--additional-driver-flag', '--enable-unsafe-webgpu',
-          '--additional-driver-flag', '--disable-gpu-sandbox',
+          '--additional-driver-flag=--enable-unsafe-webgpu',
           '--driver-logging',
           '--ignore-default-expectations',
           '--additional-expectations=../../third_party/blink/web_tests/WebGPUExpectations',
           '--isolated-script-test-filter=wpt_internal/webgpu/*',
         ],
-        'linux_args': [ '--no-xvfb' ],
-        'merge': {
-          'args': [
-            '--verbose',
-          ],
-          'script': '//third_party/blink/tools/merge_web_test_results.py',
-        },
-        'isolate_name': 'blink_web_tests_exparchive',
-      },
-    },
-
-    'gpu_webgpu_integration_win_x64_isolated_scripts': {
-      'webgpu_blink_web_tests': {
-        'name': 'webgpu_blink_web_tests',
-        'args': [
-          '--additional-driver-flag', '--enable-unsafe-webgpu',
-          '--additional-driver-flag', '--disable-gpu-sandbox',
-          '--driver-logging',
-          '--ignore-default-expectations',
-          '--additional-expectations=../../third_party/blink/web_tests/WebGPUExpectations',
-          '-t', 'Release_x64',
-          '--isolated-script-test-filter=wpt_internal/webgpu/*',
+        'win_args': [ '--additional-driver-flag=--disable-gpu-sandbox' ],
+        'win64_args': [ '--target=Release_x64' ],
+        'mac_args': [
+          # These tests run on 10.14, but web_tests [ Mac ] expectations don't
+          # work correctly yet under 10.14. Pretend it's 10.13.
+          '--platform=mac-mac10.13'
+        ],
+        'linux_args': [
+          '--no-xvfb',
+          '--additional-driver-flag=--disable-gpu-sandbox',
         ],
         'merge': {
           'args': [
@@ -4795,6 +4785,7 @@
           '--additional-driver-flag=--enable-features=UseSkiaRenderer',
           '--additional-driver-flag=--force-gpu-rasterization',
           '--additional-driver-flag=--enable-oop-rasterization',
+          '--additional-driver-flag=--gr-context-type=vulkan',
           '--additional-driver-flag=--use-vulkan=swiftshader',
           '--additional-driver-flag=--disable-vulkan-fallback-to-gl-for-testing',
           '--fuzzy-diff',
@@ -5646,11 +5637,6 @@
       'gpu_webgpu_integration_isolated_scripts',
     ],
 
-    'gpu_dawn_deps_win_x64_isolated_scripts': [
-      'gpu_dawn_perf_smoke_isolated_scripts',
-      'gpu_webgpu_integration_win_x64_isolated_scripts',
-    ],
-
     'gpu_dawn_tot_isolated_scripts': [
       'gpu_dawn_perf_smoke_isolated_scripts',
     ],
diff --git a/testing/buildbot/tryserver.chromium.linux.json b/testing/buildbot/tryserver.chromium.linux.json
new file mode 100644
index 0000000..8b40c5d
--- /dev/null
+++ b/testing/buildbot/tryserver.chromium.linux.json
@@ -0,0 +1,35 @@
+{
+  "AAAAA1 AUTOGENERATED FILE DO NOT EDIT": {},
+  "AAAAA2 See generate_buildbot_json.py to make changes": {},
+  "linux-layout-tests-fragment-item": {
+    "additional_compile_targets": [
+      "blink_tests"
+    ],
+    "isolated_scripts": [
+      {
+        "args": [
+          "--num-retries=3",
+          "--additional-driver-flag=--enable-blink-features=LayoutNGFragmentItem"
+        ],
+        "isolate_name": "blink_web_tests_exparchive",
+        "merge": {
+          "args": [
+            "--verbose"
+          ],
+          "script": "//third_party/blink/tools/merge_web_test_results.py"
+        },
+        "name": "webkit_layout_tests",
+        "results_handler": "layout tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-16.04"
+            }
+          ],
+          "shards": 12
+        }
+      }
+    ]
+  }
+}
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index fdd023c..7a0259fc 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -1218,7 +1218,7 @@
         ],
         'test_suites': {
           'gtest_tests': 'gpu_dawn_integration_gtests',
-          'isolated_scripts': 'gpu_dawn_deps_win_x64_isolated_scripts',
+          'isolated_scripts': 'gpu_dawn_deps_isolated_scripts',
         },
       },
       'Dawn Win10 x64 DEPS Release (NVIDIA)': {
@@ -1229,7 +1229,7 @@
         ],
         'test_suites': {
           'gtest_tests': 'gpu_dawn_integration_gtests',
-          'isolated_scripts': 'gpu_dawn_deps_win_x64_isolated_scripts',
+          'isolated_scripts': 'gpu_dawn_deps_isolated_scripts',
         },
       },
       'Dawn Win10 x64 Release (Intel HD 630)': {
@@ -4423,6 +4423,22 @@
     },
   },
   {
+    'name': 'tryserver.chromium.linux',
+    'machines': {
+      'linux-layout-tests-fragment-item': {
+        'additional_compile_targets': [
+          'blink_tests',
+        ],
+        'mixins': [
+          'linux-xenial',
+        ],
+        'test_suites': {
+          'isolated_scripts': 'chromium_webkit_isolated_scripts',
+        },
+      },
+    },
+  },
+  {
     'name': 'tryserver.webrtc',
     'machines': {
       'android_chromium_compile': {
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index d0aa39bc..d384517e 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2961,6 +2961,28 @@
             ]
         }
     ],
+    "IdentityDiscIPH": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "IdentityDiscIPH",
+                    "params": {
+                        "availability": "any",
+                        "event_trigger": "name:iph_identity_disc_triggered;comparator:<1;window:360;storage:360",
+                        "event_used": "name:identity_disc_used;comparator:<1;window:90;storage:360",
+                        "session_rate": "<1"
+                    },
+                    "enable_features": [
+                        "IPH_IdentityDisc"
+                    ],
+                    "disable_features": []
+                }
+            ]
+        }
+    ],
     "ImprovedRecoveryComponent": [
         {
             "platforms": [
@@ -3269,8 +3291,8 @@
             ],
             "experiments": [
                 {
-                    "name": "Control_20190905",
-                    "disable_features": [
+                    "name": "Enabled_20190905",
+                    "enable_features": [
                         "LowerJavaScriptPriorityWhenForceDeferred"
                     ]
                 }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
index 32e6ad5..c78543d 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
@@ -1077,6 +1077,12 @@
   return GetLayoutBox()->IsAtomicInlineLevel() && GetLayoutBox()->IsInline();
 }
 
+bool NGBlockNode::MayHaveAspectRatio() const {
+  LayoutBox* layout_object = GetLayoutBox();
+  return layout_object->IsImage() || layout_object->IsVideo() ||
+         layout_object->IsCanvas();
+}
+
 bool NGBlockNode::UseLogicalBottomMarginEdgeForInlineBlockBaseline() const {
   auto* layout_box = DynamicTo<LayoutBlock>(GetLayoutBox());
   return layout_box &&
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_node.h b/third_party/blink/renderer/core/layout/ng/ng_block_node.h
index 306838b..e08df07 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_node.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_node.h
@@ -94,6 +94,7 @@
   bool ChildrenInline() const;
   bool IsInlineLevel() const;
   bool IsAtomicInlineLevel() const;
+  bool MayHaveAspectRatio() const;
 
   // Returns true if this node should fill the viewport.
   // This occurs when we are in quirks-mode and we are *not* OOF-positioned,
diff --git a/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc
index bbfc903..80895ae 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc
@@ -126,6 +126,22 @@
                                   LengthResolvePhase::kLayout);
 }
 
+bool NGFlexLayoutAlgorithm::IsItemCrossAxisLengthDefinite(
+    const NGBlockNode& child,
+    const Length& length) const {
+  // Inline min/max value of 'auto' for the cross-axis isn't definite here.
+  // Block value of 'auto' is always indefinite.
+  if (length.IsAuto())
+    return false;
+  // But anything else in the inline direction is definite.
+  if (!MainAxisIsInlineAxis(child))
+    return true;
+  // If we get here, cross axis is block axis.
+  return !BlockLengthUnresolvable(
+      BuildConstraintSpaceForDeterminingFlexBasis(child), length,
+      LengthResolvePhase::kLayout);
+}
+
 bool NGFlexLayoutAlgorithm::DoesItemCrossSizeComputeToAuto(
     const NGBlockNode& child) const {
   const ComputedStyle& child_style = child.Style();
@@ -364,6 +380,14 @@
                      min_max_sizes_in_main_axis_direction.max_size);
         content_size_suggestion -= main_axis_border_scrollbar_padding;
 
+        if (child.MayHaveAspectRatio()) {
+          content_size_suggestion =
+              AdjustChildSizeForAspectRatioCrossAxisMinAndMax(
+                  child, content_size_suggestion,
+                  min_max_sizes_in_cross_axis_direction.min_size,
+                  min_max_sizes_in_cross_axis_direction.max_size);
+        }
+
         LayoutUnit specified_size_suggestion(LayoutUnit::Max());
         // If the item’s computed main size property is definite, then the
         // specified size suggestion is that size.
@@ -423,6 +447,54 @@
   }
 }
 
+LayoutUnit
+NGFlexLayoutAlgorithm::AdjustChildSizeForAspectRatioCrossAxisMinAndMax(
+    const NGBlockNode& child,
+    LayoutUnit content_suggestion,
+    LayoutUnit cross_min,
+    LayoutUnit cross_max) {
+  DCHECK(child.MayHaveAspectRatio());
+  // Clamp content_suggestion by any definite min and max cross size properties
+  // converted through the aspect ratio.
+
+  base::Optional<LayoutUnit> computed_inline_size;
+  base::Optional<LayoutUnit> computed_block_size;
+  LogicalSize aspect_ratio;
+
+  child.IntrinsicSize(&computed_inline_size, &computed_block_size,
+                      &aspect_ratio);
+
+  // TODO(dgrogan): Should we quit here if only the denominator is 0?
+  if (aspect_ratio.inline_size == 0 || aspect_ratio.block_size == 0)
+    return content_suggestion;
+
+  double ratio = aspect_ratio.inline_size / aspect_ratio.block_size;
+
+  // Multiplying by ratio will take something in the item's block axis and
+  // convert it to the inline axis. We want to convert from cross size to main
+  // size. If block axis and cross axis are the same, then we already have what
+  // we need. Otherwise we need to use the reciprocal.
+  if (!MainAxisIsInlineAxis(child))
+    ratio = 1 / ratio;
+
+  const Length& cross_max_length = is_horizontal_flow_
+                                       ? child.Style().MaxHeight()
+                                       : child.Style().MaxWidth();
+  if (IsItemCrossAxisLengthDefinite(child, cross_max_length)) {
+    LayoutUnit max_main_length = LayoutUnit(cross_max * ratio);
+    content_suggestion = std::min(max_main_length, content_suggestion);
+  }
+
+  const Length& cross_min_length = is_horizontal_flow_
+                                       ? child.Style().MinHeight()
+                                       : child.Style().MinWidth();
+  if (IsItemCrossAxisLengthDefinite(child, cross_min_length)) {
+    LayoutUnit min_main_length = LayoutUnit(cross_min * ratio);
+    content_suggestion = std::max(min_main_length, content_suggestion);
+  }
+  return content_suggestion;
+}
+
 scoped_refptr<const NGLayoutResult> NGFlexLayoutAlgorithm::Layout() {
   border_box_size_ = container_builder_.InitialBorderBoxSize();
   content_box_size_ =
diff --git a/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h
index b9af9a2..bb90afa 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h
@@ -30,12 +30,19 @@
  private:
   bool DoesItemCrossSizeComputeToAuto(const NGBlockNode& child) const;
   bool IsItemMainSizeDefinite(const NGBlockNode& child) const;
+  bool IsItemCrossAxisLengthDefinite(const NGBlockNode& child,
+                                     const Length& length) const;
   bool ShouldItemShrinkToFit(const NGBlockNode& child) const;
   bool DoesItemStretch(const NGBlockNode& child) const;
   // This implements the first of the additional scenarios where a flex item
   // has definite sizes when it would not if it weren't a flex item.
   // https://drafts.csswg.org/css-flexbox/#definite-sizes
   bool WillChildCrossSizeBeContainerCrossSize(const NGBlockNode& child) const;
+  LayoutUnit AdjustChildSizeForAspectRatioCrossAxisMinAndMax(
+      const NGBlockNode& child,
+      LayoutUnit content_suggestion,
+      LayoutUnit cross_min,
+      LayoutUnit cross_max);
 
   bool IsColumnContainerMainSizeDefinite() const;
   bool IsContainerCrossSizeDefinite() const;
diff --git a/third_party/blink/renderer/core/paint/background_image_geometry.cc b/third_party/blink/renderer/core/paint/background_image_geometry.cc
index 0047b92c..a92ade1 100644
--- a/third_party/blink/renderer/core/paint/background_image_geometry.cc
+++ b/third_party/blink/renderer/core/paint/background_image_geometry.cc
@@ -373,6 +373,13 @@
   return LayoutSize(width, column_height);
 }
 
+bool BackgroundImageGeometry::ShouldUseFixedAttachment(
+    const FillLayer& fill_layer) {
+  // Solid color background should use default attachment.
+  return fill_layer.GetImage() &&
+         fill_layer.Attachment() == EFillAttachment::kFixed;
+}
+
 namespace {
 
 LayoutRect FixedAttachmentPositioningArea(const LayoutBoxModelObject& obj,
@@ -642,7 +649,7 @@
     LayoutRect& snapped_positioning_area,
     LayoutPoint& unsnapped_box_offset,
     LayoutPoint& snapped_box_offset) {
-  if (fill_layer.Attachment() == EFillAttachment::kFixed) {
+  if (ShouldUseFixedAttachment(fill_layer)) {
     // No snapping for fixed attachment.
     SetHasNonLocalGeometry();
     offset_in_background_ = LayoutPoint();
@@ -1029,7 +1036,7 @@
       unsnapped_dest_rect_ = snapped_dest_rect_ = LayoutRect();
   }
 
-  if (fill_layer.Attachment() == EFillAttachment::kFixed)
+  if (ShouldUseFixedAttachment(fill_layer))
     UseFixedAttachment(paint_rect.Location());
 
   // Clip the final output rect to the paint rect, maintaining snapping.
diff --git a/third_party/blink/renderer/core/paint/background_image_geometry.h b/third_party/blink/renderer/core/paint/background_image_geometry.h
index a5bc12b..cac45a75 100644
--- a/third_party/blink/renderer/core/paint/background_image_geometry.h
+++ b/third_party/blink/renderer/core/paint/background_image_geometry.h
@@ -95,6 +95,8 @@
   const ComputedStyle& ImageStyle() const;
   InterpolationQuality ImageInterpolationQuality() const;
 
+  static bool ShouldUseFixedAttachment(const FillLayer&);
+
  private:
   void SetSpaceSize(const LayoutSize& repeat_spacing) {
     repeat_spacing_ = repeat_spacing;
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc
index 6a0de25..5ee0bdf 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc
@@ -959,6 +959,59 @@
 }
 
 TEST_P(PaintLayerScrollableAreaTest,
+       ViewScrollWithSolidColorFixedAttachmentBackground) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      html, #fixed-background {
+        background: green fixed;
+      }
+      #fixed-background {
+        width: 200px;
+        height: 200px;
+        overflow: scroll;
+      }
+    </style>
+    <div id="fixed-background">
+      <div style="height: 3000px"></div>
+    </div>
+    <div style="height: 3000px"></div>
+  )HTML");
+
+  // Fixed-attachment solid-color background should be treated as default
+  // attachment.
+  EXPECT_EQ(kBackgroundPaintInScrollingContents,
+            GetLayoutView().GetBackgroundPaintLocation());
+  auto* fixed_background_div =
+      ToLayoutBox(GetLayoutObjectByElementId("fixed-background"));
+  EXPECT_EQ(kBackgroundPaintInScrollingContents,
+            fixed_background_div->GetBackgroundPaintLocation());
+  auto* div_scrollable_area = fixed_background_div->GetScrollableArea();
+  auto* view_scrollable_area = GetLayoutView().GetScrollableArea();
+
+  // Programmatically changing the view's scroll offset. Should invalidate all
+  // objects with fixed attachment background.
+  view_scrollable_area->SetScrollOffset(ScrollOffset(0, 1),
+                                        kProgrammaticScroll);
+  EXPECT_FALSE(fixed_background_div->ShouldDoFullPaintInvalidation());
+  EXPECT_FALSE(fixed_background_div->BackgroundNeedsFullPaintInvalidation());
+  EXPECT_FALSE(fixed_background_div->NeedsPaintPropertyUpdate());
+  EXPECT_FALSE(GetLayoutView().ShouldDoFullPaintInvalidation());
+  EXPECT_FALSE(GetLayoutView().BackgroundNeedsFullPaintInvalidation());
+  EXPECT_TRUE(GetLayoutView().NeedsPaintPropertyUpdate());
+  UpdateAllLifecyclePhasesForTest();
+
+  // Programmatically changing the div's scroll offset. Should invalidate the
+  // scrolled div with fixed attachment background.
+  div_scrollable_area->SetScrollOffset(ScrollOffset(0, 1), kProgrammaticScroll);
+  EXPECT_FALSE(fixed_background_div->ShouldDoFullPaintInvalidation());
+  EXPECT_FALSE(fixed_background_div->BackgroundNeedsFullPaintInvalidation());
+  EXPECT_TRUE(fixed_background_div->NeedsPaintPropertyUpdate());
+  EXPECT_FALSE(GetLayoutView().ShouldDoFullPaintInvalidation());
+  EXPECT_FALSE(GetLayoutView().BackgroundNeedsFullPaintInvalidation());
+  EXPECT_TRUE(GetLayoutView().NeedsPaintPropertyUpdate());
+}
+
+TEST_P(PaintLayerScrollableAreaTest,
        ViewScrollWithFixedAttachmentBackgroundPreferCompositingToLCDText) {
   GetDocument().GetFrame()->GetSettings()->SetPreferCompositingToLCDTextEnabled(
       true);
diff --git a/third_party/blink/renderer/core/paint/view_painter.cc b/third_party/blink/renderer/core/paint/view_painter.cc
index 69ff740..5d6bed5f 100644
--- a/third_party/blink/renderer/core/paint/view_painter.cc
+++ b/third_party/blink/renderer/core/paint/view_painter.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/paint/view_painter.h"
 
+#include "base/containers/adapters.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
 #include "third_party/blink/renderer/core/layout/layout_box.h"
@@ -270,14 +271,11 @@
 
   BackgroundImageGeometry geometry(layout_view_);
   BoxModelObjectPainter box_model_painter(layout_view_);
-  for (auto it = reversed_paint_list.rbegin(); it != reversed_paint_list.rend();
-       ++it) {
-    DCHECK((*it)->Clip() == EFillBox::kBorder);
+  for (const auto* fill_layer : base::Reversed(reversed_paint_list)) {
+    DCHECK(fill_layer->Clip() == EFillBox::kBorder);
 
-    bool should_paint_in_viewport_space =
-        (*it)->Attachment() == EFillAttachment::kFixed;
-    if (should_paint_in_viewport_space) {
-      box_model_painter.PaintFillLayer(paint_info, Color(), **it,
+    if (BackgroundImageGeometry::ShouldUseFixedAttachment(*fill_layer)) {
+      box_model_painter.PaintFillLayer(paint_info, Color(), *fill_layer,
                                        PhysicalRect(background_rect),
                                        kBackgroundBleedNone, geometry);
     } else {
@@ -285,7 +283,7 @@
       // TODO(trchen): We should be able to handle 3D-transformed root
       // background with slimming paint by using transform display items.
       context.ConcatCTM(transform.ToAffineTransform());
-      box_model_painter.PaintFillLayer(paint_info, Color(), **it,
+      box_model_painter.PaintFillLayer(paint_info, Color(), *fill_layer,
                                        PhysicalRect(paint_rect),
                                        kBackgroundBleedNone, geometry);
       context.Restore();
diff --git a/third_party/blink/renderer/core/style/computed_style_test.cc b/third_party/blink/renderer/core/style/computed_style_test.cc
index b4f0895..65bc397 100644
--- a/third_party/blink/renderer/core/style/computed_style_test.cc
+++ b/third_party/blink/renderer/core/style/computed_style_test.cc
@@ -30,8 +30,6 @@
 
 namespace blink {
 
-using namespace css_test_helpers;
-
 TEST(ComputedStyleTest, ShapeOutsideBoxEqual) {
   ShapeValue* shape1 = ShapeValue::CreateBoxShapeValue(CSSBoxType::kContent);
   ShapeValue* shape2 = ShapeValue::CreateBoxShapeValue(CSSBoxType::kContent);
@@ -452,7 +450,8 @@
 
 TEST(ComputedStyleTest, CustomPropertiesEqual_Values) {
   auto* document = MakeGarbageCollected<Document>();
-  RegisterProperty(*document, "--x", "<length>", "0px", false);
+  css_test_helpers::RegisterProperty(*document, "--x", "<length>", "0px",
+                                     false);
 
   scoped_refptr<ComputedStyle> style1 = ComputedStyle::Create();
   scoped_refptr<ComputedStyle> style2 = ComputedStyle::Create();
@@ -481,14 +480,15 @@
 
 TEST(ComputedStyleTest, CustomPropertiesEqual_Data) {
   auto* document = MakeGarbageCollected<Document>();
-  RegisterProperty(*document, "--x", "<length>", "0px", false);
+  css_test_helpers::RegisterProperty(*document, "--x", "<length>", "0px",
+                                     false);
 
   scoped_refptr<ComputedStyle> style1 = ComputedStyle::Create();
   scoped_refptr<ComputedStyle> style2 = ComputedStyle::Create();
 
-  auto value1 = CreateVariableData("foo");
-  auto value2 = CreateVariableData("bar");
-  auto value3 = CreateVariableData("foo");
+  auto value1 = css_test_helpers::CreateVariableData("foo");
+  auto value2 = css_test_helpers::CreateVariableData("bar");
+  auto value3 = css_test_helpers::CreateVariableData("foo");
 
   Vector<AtomicString> properties;
   properties.push_back("--x");
diff --git a/third_party/blink/renderer/core/style/style_variables_test.cc b/third_party/blink/renderer/core/style/style_variables_test.cc
index 8fa27e17..63b0797d 100644
--- a/third_party/blink/renderer/core/style/style_variables_test.cc
+++ b/third_party/blink/renderer/core/style/style_variables_test.cc
@@ -12,8 +12,6 @@
 namespace blink {
 namespace {
 
-using namespace css_test_helpers;
-
 class StyleVariablesTest : public PageTestBase {};
 
 TEST_F(StyleVariablesTest, EmptyEqual) {
@@ -25,8 +23,8 @@
 }
 
 TEST_F(StyleVariablesTest, Copy) {
-  auto foo_data = CreateVariableData("foo");
-  const CSSValue* foo_value = CreateCustomIdent("foo");
+  auto foo_data = css_test_helpers::CreateVariableData("foo");
+  const CSSValue* foo_value = css_test_helpers::CreateCustomIdent("foo");
 
   StyleVariables vars1;
   vars1.SetData("--x", foo_data);
@@ -40,8 +38,8 @@
 
 TEST_F(StyleVariablesTest, GetNames) {
   StyleVariables vars;
-  vars.SetData("--x", CreateVariableData("foo"));
-  vars.SetData("--y", CreateVariableData("bar"));
+  vars.SetData("--x", css_test_helpers::CreateVariableData("foo"));
+  vars.SetData("--y", css_test_helpers::CreateVariableData("bar"));
 
   HashSet<AtomicString> names = vars.GetNames();
   EXPECT_EQ(2u, names.size());
@@ -54,15 +52,15 @@
 TEST_F(StyleVariablesTest, IsEmptyData) {
   StyleVariables vars;
   EXPECT_TRUE(vars.IsEmpty());
-  vars.SetData("--x", CreateVariableData("foo"));
+  vars.SetData("--x", css_test_helpers::CreateVariableData("foo"));
   EXPECT_FALSE(vars.IsEmpty());
 }
 
 TEST_F(StyleVariablesTest, SetData) {
   StyleVariables vars;
 
-  auto foo = CreateVariableData("foo");
-  auto bar = CreateVariableData("bar");
+  auto foo = css_test_helpers::CreateVariableData("foo");
+  auto bar = css_test_helpers::CreateVariableData("bar");
 
   EXPECT_FALSE(vars.GetData("--x").has_value());
 
@@ -83,7 +81,7 @@
 }
 
 TEST_F(StyleVariablesTest, SingleDataSamePointer) {
-  auto data = CreateVariableData("foo");
+  auto data = css_test_helpers::CreateVariableData("foo");
   StyleVariables vars1;
   StyleVariables vars2;
   vars1.SetData("--x", data);
@@ -94,25 +92,25 @@
 TEST_F(StyleVariablesTest, SingleDataSameContent) {
   StyleVariables vars1;
   StyleVariables vars2;
-  vars1.SetData("--x", CreateVariableData("foo"));
-  vars2.SetData("--x", CreateVariableData("foo"));
+  vars1.SetData("--x", css_test_helpers::CreateVariableData("foo"));
+  vars2.SetData("--x", css_test_helpers::CreateVariableData("foo"));
   EXPECT_EQ(vars1, vars2);
 }
 
 TEST_F(StyleVariablesTest, SingleDataContentNotEqual) {
   StyleVariables vars1;
   StyleVariables vars2;
-  vars1.SetData("--x", CreateVariableData("foo"));
-  vars2.SetData("--x", CreateVariableData("bar"));
+  vars1.SetData("--x", css_test_helpers::CreateVariableData("foo"));
+  vars2.SetData("--x", css_test_helpers::CreateVariableData("bar"));
   EXPECT_NE(vars1, vars2);
 }
 
 TEST_F(StyleVariablesTest, DifferentDataSize) {
   StyleVariables vars1;
   StyleVariables vars2;
-  vars1.SetData("--x", CreateVariableData("foo"));
-  vars2.SetData("--x", CreateVariableData("bar"));
-  vars2.SetData("--y", CreateVariableData("foz"));
+  vars1.SetData("--x", css_test_helpers::CreateVariableData("foo"));
+  vars2.SetData("--x", css_test_helpers::CreateVariableData("bar"));
+  vars2.SetData("--y", css_test_helpers::CreateVariableData("foz"));
   EXPECT_NE(vars1, vars2);
 }
 
@@ -121,15 +119,15 @@
 TEST_F(StyleVariablesTest, IsEmptyValue) {
   StyleVariables vars;
   EXPECT_TRUE(vars.IsEmpty());
-  vars.SetValue("--x", CreateCustomIdent("foo"));
+  vars.SetValue("--x", css_test_helpers::CreateCustomIdent("foo"));
   EXPECT_FALSE(vars.IsEmpty());
 }
 
 TEST_F(StyleVariablesTest, SetValue) {
   StyleVariables vars;
 
-  const CSSValue* foo = CreateCustomIdent("foo");
-  const CSSValue* bar = CreateCustomIdent("bar");
+  const CSSValue* foo = css_test_helpers::CreateCustomIdent("foo");
+  const CSSValue* bar = css_test_helpers::CreateCustomIdent("bar");
 
   EXPECT_FALSE(vars.GetValue("--x").has_value());
 
@@ -150,7 +148,7 @@
 }
 
 TEST_F(StyleVariablesTest, SingleValueSamePointer) {
-  const CSSValue* foo = CreateCustomIdent("foo");
+  const CSSValue* foo = css_test_helpers::CreateCustomIdent("foo");
   StyleVariables vars1;
   StyleVariables vars2;
   vars1.SetValue("--x", foo);
@@ -161,25 +159,25 @@
 TEST_F(StyleVariablesTest, SingleValueSameContent) {
   StyleVariables vars1;
   StyleVariables vars2;
-  vars1.SetValue("--x", CreateCustomIdent("foo"));
-  vars2.SetValue("--x", CreateCustomIdent("foo"));
+  vars1.SetValue("--x", css_test_helpers::CreateCustomIdent("foo"));
+  vars2.SetValue("--x", css_test_helpers::CreateCustomIdent("foo"));
   EXPECT_EQ(vars1, vars2);
 }
 
 TEST_F(StyleVariablesTest, SingleValueContentNotEqual) {
   StyleVariables vars1;
   StyleVariables vars2;
-  vars1.SetValue("--x", CreateCustomIdent("foo"));
-  vars2.SetValue("--x", CreateCustomIdent("bar"));
+  vars1.SetValue("--x", css_test_helpers::CreateCustomIdent("foo"));
+  vars2.SetValue("--x", css_test_helpers::CreateCustomIdent("bar"));
   EXPECT_NE(vars1, vars2);
 }
 
 TEST_F(StyleVariablesTest, DifferentValueSize) {
   StyleVariables vars1;
   StyleVariables vars2;
-  vars1.SetValue("--x", CreateCustomIdent("foo"));
-  vars2.SetValue("--x", CreateCustomIdent("bar"));
-  vars2.SetValue("--y", CreateCustomIdent("foz"));
+  vars1.SetValue("--x", css_test_helpers::CreateCustomIdent("foo"));
+  vars2.SetValue("--x", css_test_helpers::CreateCustomIdent("bar"));
+  vars2.SetValue("--y", css_test_helpers::CreateCustomIdent("foz"));
   EXPECT_NE(vars1, vars2);
 }
 
diff --git a/third_party/blink/renderer/devtools/front_end/coverage/CoverageListView.js b/third_party/blink/renderer/devtools/front_end/coverage/CoverageListView.js
index 88ed965..497c69d0 100644
--- a/third_party/blink/renderer/devtools/front_end/coverage/CoverageListView.js
+++ b/third_party/blink/renderer/devtools/front_end/coverage/CoverageListView.js
@@ -302,26 +302,46 @@
         }
         break;
       case 'size':
-        cell.textContent = Number.withThousandsSeparator(this._coverageInfo.size() || 0);
+        const sizeSpan = cell.createChild('span');
+        sizeSpan.textContent = Number.withThousandsSeparator(this._coverageInfo.size() || 0);
+        UI.ARIAUtils.markAsHidden(sizeSpan);
+        UI.ARIAUtils.setAccessibleName(cell, ls`${this._coverageInfo.size() || 0} bytes`);
         break;
       case 'unusedSize':
         const unusedSize = this._coverageInfo.unusedSize() || 0;
         const unusedSizeSpan = cell.createChild('span');
         const unusedPercentsSpan = cell.createChild('span', 'percent-value');
         unusedSizeSpan.textContent = Number.withThousandsSeparator(unusedSize);
-        unusedPercentsSpan.textContent = Common.UIString('%.1f\xa0%%', unusedSize / this._coverageInfo.size() * 100);
+        const unusedPercentFormatted = ls`${this._percentageString(unusedSize, this._coverageInfo.size(), 1)}`;
+        unusedPercentsSpan.textContent = unusedPercentFormatted;
+        UI.ARIAUtils.markAsHidden(unusedPercentsSpan);
+        UI.ARIAUtils.markAsHidden(unusedSizeSpan);
+        UI.ARIAUtils.setAccessibleName(cell, ls`${unusedSize} bytes, ${unusedPercentFormatted}`);
         break;
       case 'bars':
         const barContainer = cell.createChild('div', 'bar-container');
         const unusedSizeBar = barContainer.createChild('div', 'bar bar-unused-size');
-        unusedSizeBar.style.width = (100 * this._coverageInfo.unusedSize() / this._maxSize).toFixed(4) + '%';
+        unusedSizeBar.style.width = this._percentageString(this._coverageInfo.unusedSize(), this._maxSize, 4);
         const usedSizeBar = barContainer.createChild('div', 'bar bar-used-size');
-        usedSizeBar.style.width = (100 * this._coverageInfo.usedSize() / this._maxSize).toFixed(4) + '%';
+        usedSizeBar.style.width = this._percentageString(this._coverageInfo.usedSize(), this._maxSize, 4);
+        const unusedPercent = this._percentageString(this._coverageInfo.unusedSize(), this._coverageInfo.size(), 1);
+        const usedPercent = this._percentageString(this._coverageInfo.usedSize(), this._maxSize, 1);
+        UI.ARIAUtils.setAccessibleName(barContainer, ls`${unusedPercent} of file unused, ${usedPercent} of file used`);
     }
     return cell;
   }
 
   /**
+   * @param {number} value
+   * @param {number} max
+   * @param {number} numDecimalPlaces
+   * @return {string}
+   */
+  _percentageString(value, max, numDecimalPlaces) {
+    return (value / max * 100).toFixed(numDecimalPlaces) + '%';
+  }
+
+  /**
    * @param {!Element} element
    * @param {string} textContent
    */
diff --git a/third_party/blink/renderer/devtools/front_end/coverage/coverage_strings.grdp b/third_party/blink/renderer/devtools/front_end/coverage/coverage_strings.grdp
index eeac010..f92d749 100644
--- a/third_party/blink/renderer/devtools/front_end/coverage/coverage_strings.grdp
+++ b/third_party/blink/renderer/devtools/front_end/coverage/coverage_strings.grdp
@@ -10,12 +10,18 @@
   <message name="IDS_DEVTOOLS_1a49594b5f00e4f511ae8935c027cd8e" desc="Text in Coverage List View of the Coverage tab">
     Unused Bytes
   </message>
+  <message name="IDS_DEVTOOLS_1b720c2038c3cf92379c5054abda47ae" desc="Accessible text for the visualization column of coverage tool. Contains percentage of unused bytes to used bytes.">
+    <ph name="UNUSEDPERCENT">$1s<ex>20%</ex></ph> of file unused, <ph name="USEDPERCENT">$2s<ex>80%</ex></ph> of file used
+  </message>
   <message name="IDS_DEVTOOLS_2adbfb69a37aa4a29ca846736d2111db" desc="Text in Coverage List View of the Coverage tab">
     JS (coarse)
   </message>
   <message name="IDS_DEVTOOLS_44ea86aada1381cf21cf9899b3dd32fe" desc="Label for the type filter in the Converage Panel">
     Filter coverage by type
   </message>
+  <message name="IDS_DEVTOOLS_6861e4e238e968ec0ee3e9d3cb3b893f" desc="Accessible text for the unused bytes column in the coverage tool that describes the total unused bytes and percentage of the file unused.">
+    <ph name="UNUSEDSIZE">$1s<ex>100000</ex></ph> bytes, <ph name="UNUSEDPERCENTFORMATED">$2s<ex>88%</ex></ph>
+  </message>
   <message name="IDS_DEVTOOLS_73af525212a812236f1a3618e9cfa717" desc="Tooltip text that appears when hovering over the largeicon download button in the Coverage View of the Coverage tab">
     Export...
   </message>
diff --git a/third_party/blink/renderer/devtools/front_end/langpacks/shared_strings.grdp b/third_party/blink/renderer/devtools/front_end/langpacks/shared_strings.grdp
index 981cbae..0cacd66 100644
--- a/third_party/blink/renderer/devtools/front_end/langpacks/shared_strings.grdp
+++ b/third_party/blink/renderer/devtools/front_end/langpacks/shared_strings.grdp
@@ -4,6 +4,9 @@
   <message name="IDS_DEVTOOLS_007c41a9025be2c8e14b496ed3ee00f8" desc="Text to save an item">
     Save…
   </message>
+  <message name="IDS_DEVTOOLS_03301bd5f0d1517cf88b2f8348b82dfc" desc="Accessible text for the value in bytes in memory allocation or coverage view.">
+    <ph name="THIS__COVERAGEINFO_SIZE_______">$1s<ex>12345</ex></ph> bytes
+  </message>
   <message name="IDS_DEVTOOLS_040c4b52a3c06c6067fac76c4c7c3a2c" desc="Title of the 'Network conditions' tool in the bottom drawer">
     Network conditions
   </message>
@@ -247,9 +250,6 @@
   <message name="IDS_DEVTOOLS_63a6a88c066880c5ac42394a22803ca6" desc="Text to refresh the page">
     Refresh
   </message>
-  <message name="IDS_DEVTOOLS_6525b37c568c526bde7c02fac8195c73" desc="Text for percentage">
-    <ph name="PERCENTAGE">$1.1f<ex>20.1</ex></ph> %%
-  </message>
   <message name="IDS_DEVTOOLS_65b4c7424dd695c30efa73da8396c90c" desc="Title of the Profiler tool">
     Profiler
   </message>
diff --git a/third_party/blink/renderer/devtools/front_end/mobile_throttling/ThrottlingSettingsTab.js b/third_party/blink/renderer/devtools/front_end/mobile_throttling/ThrottlingSettingsTab.js
index 44beae50..98ae6ee 100644
--- a/third_party/blink/renderer/devtools/front_end/mobile_throttling/ThrottlingSettingsTab.js
+++ b/third_party/blink/renderer/devtools/front_end/mobile_throttling/ThrottlingSettingsTab.js
@@ -138,33 +138,54 @@
     const content = editor.contentElement();
 
     const titles = content.createChild('div', 'conditions-edit-row');
-    titles.createChild('div', 'conditions-list-text conditions-list-title').textContent =
-        Common.UIString('Profile Name');
+    const nameLabel = titles.createChild('div', 'conditions-list-text conditions-list-title');
+    const nameStr = ls`Profile Name`;
+    nameLabel.textContent = nameStr;
     titles.createChild('div', 'conditions-list-separator conditions-list-separator-invisible');
-    titles.createChild('div', 'conditions-list-text').textContent = Common.UIString('Download');
+    const downloadLabel = titles.createChild('div', 'conditions-list-text');
+    const downloadStr = ls`Download`;
+    downloadLabel.textContent = downloadStr;
     titles.createChild('div', 'conditions-list-separator conditions-list-separator-invisible');
-    titles.createChild('div', 'conditions-list-text').textContent = Common.UIString('Upload');
+    const uploadLabel = titles.createChild('div', 'conditions-list-text');
+    const uploadStr = ls`Upload`;
+    uploadLabel.textContent = uploadStr;
     titles.createChild('div', 'conditions-list-separator conditions-list-separator-invisible');
-    titles.createChild('div', 'conditions-list-text').textContent = Common.UIString('Latency');
+    const latencyLabel = titles.createChild('div', 'conditions-list-text');
+    const latencyStr = ls`Latency`;
+    latencyLabel.textContent = latencyStr;
 
     const fields = content.createChild('div', 'conditions-edit-row');
-    fields.createChild('div', 'conditions-list-text conditions-list-title')
-        .appendChild(editor.createInput('title', 'text', '', titleValidator));
+    const nameInput = editor.createInput('title', 'text', '', titleValidator);
+    UI.ARIAUtils.setAccessibleName(nameInput, nameStr);
+    fields.createChild('div', 'conditions-list-text conditions-list-title').appendChild(nameInput);
     fields.createChild('div', 'conditions-list-separator conditions-list-separator-invisible');
 
     let cell = fields.createChild('div', 'conditions-list-text');
-    cell.appendChild(editor.createInput('download', 'text', Common.UIString('kb/s'), throughputValidator));
-    cell.createChild('div', 'conditions-edit-optional').textContent = Common.UIString('optional');
+    const downloadInput = editor.createInput('download', 'text', ls`kb/s`, throughputValidator);
+    cell.appendChild(downloadInput);
+    UI.ARIAUtils.setAccessibleName(downloadInput, downloadStr);
+    const downloadOptional = cell.createChild('div', 'conditions-edit-optional');
+    const optionalStr = ls`optional`;
+    downloadOptional.textContent = optionalStr;
+    UI.ARIAUtils.setDescription(downloadInput, optionalStr);
     fields.createChild('div', 'conditions-list-separator conditions-list-separator-invisible');
 
     cell = fields.createChild('div', 'conditions-list-text');
-    cell.appendChild(editor.createInput('upload', 'text', Common.UIString('kb/s'), throughputValidator));
-    cell.createChild('div', 'conditions-edit-optional').textContent = Common.UIString('optional');
+    const uploadInput = editor.createInput('upload', 'text', ls`kb/s`, throughputValidator);
+    UI.ARIAUtils.setAccessibleName(uploadInput, uploadStr);
+    cell.appendChild(uploadInput);
+    const uploadOptional = cell.createChild('div', 'conditions-edit-optional');
+    uploadOptional.textContent = optionalStr;
+    UI.ARIAUtils.setDescription(uploadInput, optionalStr);
     fields.createChild('div', 'conditions-list-separator conditions-list-separator-invisible');
 
     cell = fields.createChild('div', 'conditions-list-text');
-    cell.appendChild(editor.createInput('latency', 'text', Common.UIString('ms'), latencyValidator));
-    cell.createChild('div', 'conditions-edit-optional').textContent = Common.UIString('optional');
+    const latencyInput = editor.createInput('latency', 'text', ls`ms`, latencyValidator);
+    UI.ARIAUtils.setAccessibleName(latencyInput, latencyStr);
+    cell.appendChild(latencyInput);
+    const latencyOptional = cell.createChild('div', 'conditions-edit-optional');
+    latencyOptional.textContent = optionalStr;
+    UI.ARIAUtils.setDescription(latencyInput, optionalStr);
 
     return editor;
 
diff --git a/third_party/blink/renderer/devtools/front_end/profiler/profiler_strings.grdp b/third_party/blink/renderer/devtools/front_end/profiler/profiler_strings.grdp
index d5a959b..81163ae 100644
--- a/third_party/blink/renderer/devtools/front_end/profiler/profiler_strings.grdp
+++ b/third_party/blink/renderer/devtools/front_end/profiler/profiler_strings.grdp
@@ -12,9 +12,6 @@
   <message name="IDS_DEVTOOLS_030361ea56fa177ebcbefe708a45b0f2" desc="Text in Heap Snapshot Data Grids of a profiler tool">
     # Deleted
   </message>
-  <message name="IDS_DEVTOOLS_03301bd5f0d1517cf88b2f8348b82dfc" desc="Accessible text for the value in bytes of a Memory allocation.">
-    <ph name="VALUE">$1s<ex>12345</ex></ph> bytes
-  </message>
   <message name="IDS_DEVTOOLS_04042b5589b3d4fd4e1e7e44265ad247" desc="Total trend div title in Isolate Selector of a profiler tool">
     Total page JS heap size change trend over the last <ph name="TRENDINTERVALMINUTES">$1s<ex>3</ex></ph> minutes.
   </message>
diff --git a/third_party/blink/renderer/devtools/front_end/sdk/NetworkLog.js b/third_party/blink/renderer/devtools/front_end/sdk/NetworkLog.js
index 34c53a22a..fbdc51f 100644
--- a/third_party/blink/renderer/devtools/front_end/sdk/NetworkLog.js
+++ b/third_party/blink/renderer/devtools/front_end/sdk/NetworkLog.js
@@ -241,7 +241,7 @@
     const initiated = new Set();
     const networkManager = SDK.NetworkManager.forRequest(request);
     for (const otherRequest of this._requests) {
-      const otherRequestManager = SDK.NetworkManager.forRequest(request);
+      const otherRequestManager = SDK.NetworkManager.forRequest(otherRequest);
       if (networkManager === otherRequestManager && this._initiatorChain(otherRequest).has(request)) {
         initiated.add(otherRequest);
       }
@@ -265,6 +265,7 @@
 
     let checkRequest = request;
     do {
+      this._initializeInitiatorSymbolIfNeeded(checkRequest);
       if (checkRequest[_initiatorDataSymbol].chain) {
         initiatorChainCache.addAll(checkRequest[_initiatorDataSymbol].chain);
         break;
diff --git a/third_party/blink/renderer/devtools/front_end/timeline/timeline_strings.grdp b/third_party/blink/renderer/devtools/front_end/timeline/timeline_strings.grdp
index 3219d7d..de624f64 100644
--- a/third_party/blink/renderer/devtools/front_end/timeline/timeline_strings.grdp
+++ b/third_party/blink/renderer/devtools/front_end/timeline/timeline_strings.grdp
@@ -430,6 +430,9 @@
   <message name="IDS_DEVTOOLS_640d76ebf7917e7353ea0444790c9794" desc="Text in Timeline UIUtils of the Performance panel">
     Image Resize
   </message>
+  <message name="IDS_DEVTOOLS_6525b37c568c526bde7c02fac8195c73" desc="Number followed by percent sign">
+    <ph name="VALUE___THIS__GRANDTOTALTIME______">$1.1f<ex>20</ex></ph> %%
+  </message>
   <message name="IDS_DEVTOOLS_66f1aed235ade25269a561e81cbbb43a" desc="Text in Timeline UIUtils of the Performance panel">
     Scripting
   </message>
diff --git a/third_party/blink/renderer/devtools/scripts/check_localizable_resources.js b/third_party/blink/renderer/devtools/scripts/check_localizable_resources.js
index 706554e..48b5126 100644
--- a/third_party/blink/renderer/devtools/scripts/check_localizable_resources.js
+++ b/third_party/blink/renderer/devtools/scripts/check_localizable_resources.js
@@ -65,6 +65,7 @@
   const resourceAdded = await addResourcesToGRDP(keysToAddToGRD, keysToRemoveFromGRD);
   const resourceModified = await modifyResourcesInGRDP();
   const resourceRemoved = await removeResourcesFromGRDP(keysToRemoveFromGRD);
+  const shouldAddExampleTag = checkShouldAddExampleTag(keysToAddToGRD);
 
   if (!resourceAdded && !resourceRemoved && !resourceModified && existingError === '') {
     console.log('DevTools localizable resources checker passed.');
@@ -78,14 +79,29 @@
         `\nGrd/Grdp files have been updated. Please verify the updated grdp files and/or the <part> file references in ${
             localizationUtils.getRelativeFilePathFromSrc(localizationUtils.GRD_PATH)} are correct.`;
   }
-  if (resourceAdded)
+  if (resourceAdded) {
     message += '\nManually write a description for any new <message> entries.';
+    if (shouldAddExampleTag) {
+      message += ' Add example tag(s) <ex> for messages that contain placeholder(s)';
+    }
+    message += '\nFor more details, see devtools/docs/langpacks/grdp_files.md';
+  }
   if (resourceRemoved && duplicateRemoved(keysToRemoveFromGRD))
     message += '\nDuplicate <message> entries are removed. Please verify the retained descriptions are correct.';
+  message += '\n'
   message += '\nUse git status to see what has changed.';
   throw new Error(message);
 }
 
+function checkShouldAddExampleTag(keys) {
+  if (keys.size === 0) {
+    return false;
+  }
+  const stringObjs = [...keys.values()];
+  const stringsWithArgument = stringObjs.filter(stringObj => !!stringObj.arguments);
+  return stringsWithArgument.length > 0;
+}
+
 function duplicateRemoved(keysToRemoveFromGRD) {
   for (const [_, messages] of keysToRemoveFromGRD) {
     if (messages.length > 1)
diff --git a/third_party/blink/renderer/modules/wake_lock/README.md b/third_party/blink/renderer/modules/wake_lock/README.md
index 8c6e964..aba6793 100644
--- a/third_party/blink/renderer/modules/wake_lock/README.md
+++ b/third_party/blink/renderer/modules/wake_lock/README.md
@@ -4,21 +4,31 @@
 
 This directory contains an implementation of the [Wake Lock specification], a Web API that allows script authors to prevent both the screen from turning off ("screen wake locks") as well as the CPU from entering a deep power state ("system wake locks"). There are platform implementations for ChromeOS, Linux (X11), Mac, Android, and Windows.
 
-At the time of writing (August 2019), system wake lock requests are always denied, as allowing them depends on a proper permission model for the requests being figured out first.
+At the time of writing (October 2019), system wake lock requests are always denied, as allowing them depends on a proper permission model for the requests being figured out first.
 
 The code required to implement the Wake Lock API is spread across multiple Chromium subsystems: Blink, `//content`, `//services` and `//chrome`. This document focuses on the Blink part, and the other subsystems are mentioned when necessary but without much detail.
 
 ## High level overview
 
-Wake Lock's API surface is fairly small; the `WakeLock` IDL interface only has static methods, and there is no state that can be easily inspected. Additionally, all the parts that actually communicate with platform APIs are implemented elsewhere, so the Blink side only exposes the JavaScript API to script authors, validates API calls and manages [state records].
+Wake Lock's API surface is fairly small: `Navigator` and `WorkerNavigator` provide a `wakeLock` attribute that exposes the `WakeLock`, an interface with a single method to request a wake lock, and a `WakeLockSentinel` can be used to both release the requested lock and receive an event when it is released. All the parts that actually communicate with platform APIs are implemented elsewhere, so the Blink side only exposes the JavaScript API to script authors, validates API calls and manages [state records].
+
+Wake Lock usage in scripts looks like this:
+
+```javascript
+let lock = await navigator.wakeLock.request("screen");
+lock.addEventListener("release", (ev) => {
+  console.log(`${ev.target.type} wake lock released`);
+});
+lock.release();
+```
 
 The three main Blink classes implementing the spec are:
 
-* [`WakeLock`](wake_lock.h): implements the API bindings following the spec. Like its IDL counterpart, it only has static methods. Permission request and lock acquisition calls are all forwarded to `WakeLockController`.
-* [`WakeLockController`](wake_lock_controller.h): per-`ExecutionContext` class. It implements all permission management required by the spec, as well as the [Wake Lock management] tasks that apply to documents and/or workers (e.g. page visibility handling). Its `state_records_` array contains per-wake lock type `WakeLockStateRecord` instances, so all wake lock types are managed independently.
-* [`WakeLockStateRecord`](wake_lock_state_record.h): Owned by `WakeLockController`. This is an implementation of the [state records] Wake Lock concept in a per-type fashion. Like in the spec, it keeps track of all active locks of a certain type, and it is also responsible for communicating with the `//content` and `//services` layers to request and cancel wake locks.
+* [`WakeLock`](wake_lock.h): per-`Navigator`/`WorkerNavigator` class that implements the bindings for the `WakeLock` IDL interface. Its responsibilities also include performing permission requests and [Wake Lock management] tasks that apply to documents and/or workers (e.g. page visibility handling). Lock acquisition calls are all forwarded to `WakeLockManager`. Its `managers_` array contains per-wake lock type `WakeLockManager` instances, so all wake lock types are managed independently.
+* [`WakeLockManager`](wake_lock_manager.h): Owned by `WakeLock`. This is an implementation of the [state records] Wake Lock concept in a per-type fashion. Like in the spec, it keeps track of all active locks of a certain type, and it is also responsible for communicating with the `//content` and `//services` layers to request and cancel wake locks.
+* [`WakeLockSentinel`](wake_lock_sentinel.h): Owned by `WakeLockManager`. This is an implementation of the `WakeLockSentinel` IDL interface that is used to both release a lock requested by `WakeLock.request()` and receive a `release` event when it is released (either by `WakeLockSentinel.release()` or due to a platform event, such as a loss of context, or a page visibility change in the case of screen wake locks). This class is an event target, so it inherits from [`ActiveScriptWrappable`](../../bindings/core/v8/active_script_wrappable.h) to avoid being garbage-collected while there is pending activity.
 
-Furthermore, [`wake_lock.mojom`](../../../public/mojom/wake_lock/wake_lock.mojom) defines the Mojo interface implemented by `//content`'s [`WakeLockServiceImpl`](/content/browser/wake_lock/wake_lock_service_impl.h) that `WakeLockStateRecord` uses to obtain a [`device::mojom::blink::WakeLock`](/services/device/public/mojom/wake_lock.mojom) and request/cancel a wake lock.
+Furthermore, [`wake_lock.mojom`](../../../public/mojom/wake_lock/wake_lock.mojom) defines the Mojo interface implemented by `//content`'s [`WakeLockServiceImpl`](/content/browser/wake_lock/wake_lock_service_impl.h) that `WakeLockManager` uses to obtain a [`device::mojom::blink::WakeLock`](/services/device/public/mojom/wake_lock.mojom) and request/cancel a wake lock.
 
 The rest of the implementation is found in the following directories:
 
@@ -52,22 +62,18 @@
 This section describes how the classes described above interact when the following excerpt is run in the browser:
 
 ``` javascript
-const abortController = new AbortController();
-const lockPromise = WakeLock.request("screen", { signal: abortController.signal });
+const lock = await navigator.wakeLock.request("screen");
 ```
 
-1. `WakeLock::request()` performs all the validation steps described in [the spec](https://w3c.github.io/wake-lock/#request-static-method).
-1. Since an [AbortSignal] was passed in the JavaScript call, `WakeLock::request()` will call [`AbortSignal::AddAlgorithm()`](../../core/dom/abort_signal.h) and add `WakeLockController::ReleaseWakeLock()` to its list of algorithms [n.b. see below the section below for what happens if `abortController.abort()` is called].
-1. If all checks have passed, it calls `WakeLockController::From()` to either create or obtain a `WakeLockController` attached to the given execution context (i.e. a `Document` or `DedicatedWorkerGlobalScope`).
-1. `WakeLockController::RequestWakeLock()` is called, and `WakeLock::request()` then returns a promise. `RequestWakeLock()` is a small method that just verifies some invariants and calls `WakeLockController::ObtainPermission()`.
-1. `WakeLockController::ObtainPermission()` connects to the [permission service](../../../public/mojom/permissions/permission.mojom) and asynchronously requests permission for a screen wake lock.
+1. `WakeLock::request()` performs all the validation steps described in [the spec](https://w3c.github.io/wake-lock/#the-request-method). If all checks have passed, it creates a `ScriptPromiseResolver` and calls `WakeLock::DoRequest()`.
+1. `WakeLock::DoRequest()` simply forwards its arguments to `WakeLock::ObtainPermission()`. It exists as a separate method just to make writing unit tests easier, as we'd otherwise be unable to use our own `ScriptPromiseResolver`s in tests.
+1. `WakeLock::ObtainPermission()` connects to the [permission service](../../../public/mojom/permissions/permission.mojom) and asynchronously requests permission for a screen wake lock.
 1. In the browser process, the permission request bubbles up through `//content` and reaches `//chrome`'s [`WakeLockPermissionContext`](/chrome/browser/wake_lock/wake_lock_permission_context.cc), where `WakeLockPermissionContext::GetPermissionStatusInternal()` always grants `CONTENT_SETTINGS_TYPE_WAKE_LOCK_SCREEN` permission requests.
-1. Back in Blink, the permission request callback in this case is `WakeLockController::DidReceivePermissionResponse()`. It performs some sanity checks such as verifying the wake lock's corresponding [AbortSignal] has not been triggered. If any of the checks fail, the `ScriptPromiseResolver` instance created earlier by `WakeLock::request()` is rejected and we stop here. If everything went well, calls `WakeLockController::AcquireWakeLock()`.
-1. `WakeLockController::AcquireWakeLock()` is a wrapper that invokes `WakeLockStateRecord::AcquireWakeLock()`.
-1. If there are no existing screen wake locks, `WakeLockStateRecord::AcquireWakeLock()` will connect to the `WakeLockService` Mojo interface, invoke its `GetWakeLock()` method to obtain a `device::mojom::blink::WakeLock` and call its `RequestWakeLock()` method.
-1. Otherwise, if there is at least one existing screen lock, `WakeLockStateRecord::AcquireWakeLock()` will simply add the `ScriptPromiseResolver` to its set of [active locks].
+1. Back in Blink, the permission request callback in this case is `WakeLock::DidReceivePermissionResponse()`. It performs some sanity checks such as verifying if the page visibility changed while waiting for the permission request to be processed. If any of the checks fail, or if the permission request was denied, the `ScriptPromiseResolver` instance created earlier by `WakeLock::request()` is rejected and we stop here. If everything went well, `WakeLockManager::AcquireWakeLock()` is called.
+1. If there are no existing screen wake locks, `WakeLockManager::AcquireWakeLock()` will connect to the `WakeLockService` Mojo interface, invoke its `GetWakeLock()` method to obtain a `device::mojom::blink::WakeLock` and call its `RequestWakeLock()` method.
+1. `WakeLockManager::AcquireWakeLock()` creates a new `WakeLockSentinel` instance, passing `this` as the `WakeLockSentinel`'s `WakeLockManager`. This new `WakeLockSentinel` is added to its set of [active locks].
+1. The `ScriptPromiseResolver` created by `WakeLock::request()` is resolved with the new `WakeLockSentinel` object.
 
-[AbortSignal]: https://dom.spec.whatwg.org/#interface-AbortSignal
 [active locks]: https://w3c.github.io/wake-lock/#dfn-activelocks
 
 ### Wake Lock cancellation
@@ -75,17 +81,18 @@
 Given the excerpt below:
 
 ``` javascript
-const abortController = new AbortController();
-const lockPromise = WakeLock.request("screen", { signal: abortController.signal });
-abortController.abort();
+const lock = await navigator.wakeLock.request("screen");
+await lock.release();
 ```
 
-This section describes what happens when `abortController.abort()` is called.
+This section describes what happens when `lock.release()` is called.
 
-1. `abortController.abort()` causes `AbortSignal` to go through its list of algorithms, and `WakeLockController::ReleaseWakeLock()` is eventually called.
-1. `WakeLockController::ReleaseWakeLock()` itself is a small function that simply calls `WakeLockStateRecord::ReleaseWakeLock()`.
-1. `WakeLockStateRecord::ReleaseWakeLock()` implements the spec's [release wake lock algorithm]. One interesting aspect is that it rejects any `ScriptPromiseResolver` passed to it, even if it is not in its active locks list. This is caused by the fact that `WakeLock.request()` contains parallel steps, and script authors have access to the promise it returns before a lock has actually been requested and added to `WakeLockStateRecord`'s active locks list.
-1. If the given wake lock is in `WakeLockStateRecord`'s `active_locks_`, it will be removed and, if the list is empty, `WakeLockStateRecord` will communicate with its `device::mojom::blink::WakeLock` instance and call its `CancelWakeLock()` method.
+1. `lock.release()` results in a call to `WakeLockSentinel::release()`.
+1. `WakeLockSentinel::release()` calls `WakeLockSentinel::DoRelease()` and returns a resolved promise. `WakeLockSentinel::DoRelease()` exists as a separate method because it is also called directly by `WakeLockManager::ClearWakeLocks()` when an event such as a page visibility change causes all screen wake locks to be released.
+1. `WakeLockSentinel::DoRelease()` aborts early if its `manager_` member is not set. This can happen if `WakeLock::release()` has already been called before, or if `WakeLockManager::ClearWakeLocks()` has already released this `WakeLockSentinel`.
+1. `WakeLockSentinel::DoRelease()` calls `WakeLockManager::UnregisterSentinel()`.
+1. `WakeLockManager::UnregisterSentinel()` implements the spec's [release wake lock algorithm]. If the given `WakeLockSentinel` is in `WakeLockManager`'s `wake_lock_sentinels_`, it will be removed and, if the list is empty, `WakeLockManager` will communicate with its `device::mojom::blink::WakeLock` instance and call its `CancelWakeLock()` method.
+1. Back in `WakeLockSentinel::DoRelease()`, it then clears its `manager_` member, and dispatches a `release` event with itself as a target.
 
 [release wake lock algorithm]: https://w3c.github.io/wake-lock/#release-wake-lock-algorithm
 
@@ -95,7 +102,7 @@
 
 Video playback via the `<video>` tag currently uses a screen wake lock behind the scenes to prevent the screen from turning off while a video is being played. The implementation can be found in the [`VideoWakeLock`](../../core/html/media/video_wake_lock.h) class.
 
-This is an implementation detail, but the code handling wake locks in `VideoWakeLock` is similar to `WakeLockStateRecord`'s, where Blink needs to talk to `//content` to connect to a `WakeLockServiceImpl` and use that to get to a `device::mojom::blink::WakeLock`.
+This is an implementation detail, but the code handling wake locks in `VideoWakeLock` is similar to `WakeLockManager`'s, where Blink needs to talk to `//content` to connect to a `WakeLockServiceImpl` and use that to get to a `device::mojom::blink::WakeLock`.
 
 **Note:** when writing new code that uses Wake Locks in Blink, it is recommended to follow the same pattern outlined above. That is, connect to `WakeLockService` via the `//content` layer and request a `device::mojom::blink::WakeLock` via `WakeLockService::GetWakeLock()`. Do not go through the classes in this module, and [**do not connect to the Wake Lock services directly**](/docs/servicification.md#Frame-Scoped-Connections). See the example below:
 
@@ -124,7 +131,7 @@
 
 ## Permission Model
 
-The Wake Lock API spec checks for user activation in the context of [wake lock permission requests](https://w3c.github.io/wake-lock/#dfn-obtain-permission), either as a result of a call to either `WakeLock.requestPermission()` or `WakeLock.request()`. If a user agent is configured to prompt a user when a wake lock is requested, user activation is required, otherwise the request will be denied.
+The Wake Lock API spec checks for user activation in the context of [wake lock permission requests](https://w3c.github.io/wake-lock/#dfn-obtain-permission), as a result of a call to `WakeLock.request()`. If a user agent is configured to prompt a user when a wake lock is requested, user activation is required, otherwise the request will be denied.
 
 In the Chromium implementation, there currently is no "prompt" state, and no permission UI or settings: wake lock requests are either always granted or always denied:
 
diff --git a/third_party/blink/renderer/platform/exported/web_image.cc b/third_party/blink/renderer/platform/exported/web_image.cc
index cdedc8ea..1497323 100644
--- a/third_party/blink/renderer/platform/exported/web_image.cc
+++ b/third_party/blink/renderer/platform/exported/web_image.cc
@@ -46,7 +46,8 @@
   const bool data_complete = true;
   std::unique_ptr<ImageDecoder> decoder(ImageDecoder::Create(
       data, data_complete, ImageDecoder::kAlphaPremultiplied,
-      ImageDecoder::kDefaultBitDepth, ColorBehavior::Ignore()));
+      ImageDecoder::kDefaultBitDepth, ColorBehavior::Ignore(),
+      ImageDecoder::OverrideAllowDecodeToYuv::kDeny));
   if (!decoder || !decoder->IsSizeAvailable())
     return {};
 
diff --git a/third_party/blink/renderer/platform/graphics/compositing/layers_as_json.cc b/third_party/blink/renderer/platform/graphics/compositing/layers_as_json.cc
index 9391cf304..a8a47fc 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/layers_as_json.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/layers_as_json.cc
@@ -37,9 +37,7 @@
     json->SetInteger("ccLayerId", layer->id());
   }
 
-  json->SetString(
-      "name",
-      String(layer->GetLayerClientForTesting()->LayerDebugName(layer).c_str()));
+  json->SetString("name", String(layer->DebugName().c_str()));
 
   if (position != FloatPoint())
     json->SetArray("position", PointAsJSONArray(position));
diff --git a/third_party/blink/renderer/platform/graphics/image_decoder_wrapper.cc b/third_party/blink/renderer/platform/graphics/image_decoder_wrapper.cc
index 3b8f379..5a6dab4 100644
--- a/third_party/blink/renderer/platform/graphics/image_decoder_wrapper.cc
+++ b/third_party/blink/renderer/platform/graphics/image_decoder_wrapper.cc
@@ -287,6 +287,7 @@
   // The newly created decoder just grabbed the data.  No need to reset it.
   return ImageDecoder::Create(data_, all_data_received_, alpha_option_,
                               decoding_option_, decoder_color_behavior_,
+                              ImageDecoder::OverrideAllowDecodeToYuv::kDeny,
                               scaled_size_);
 }
 
diff --git a/third_party/blink/renderer/platform/graphics/image_frame_generator.cc b/third_party/blink/renderer/platform/graphics/image_frame_generator.cc
index 0deed33..93cf3c7 100644
--- a/third_party/blink/renderer/platform/graphics/image_frame_generator.cc
+++ b/third_party/blink/renderer/platform/graphics/image_frame_generator.cc
@@ -236,12 +236,6 @@
       ImageDecoder::kDefaultBitDepth, decoder_color_behavior_);
   DCHECK(decoder);
 
-  // Setting a dummy ImagePlanes object signals to the decoder that we want to
-  // do YUV decoding.
-  std::unique_ptr<ImagePlanes> dummy_image_planes =
-      std::make_unique<ImagePlanes>();
-  decoder->SetImagePlanes(std::move(dummy_image_planes));
-
   DCHECK(decoder->CanDecodeToYUV());
   *yuv_color_space = decoder->GetYUVColorSpace();
 
diff --git a/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.cc b/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.cc
index 2e1af0dc..8754726 100644
--- a/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.cc
@@ -27,11 +27,7 @@
   }
 
   String DebugName() const final {
-#if DCHECK_IS_ON()
     return String("ForeignLayer for ") + layer_->DebugName().c_str();
-#else
-    return "ForeignLayer";
-#endif
   }
 
   DOMNodeId OwnerNodeId() const final { return layer_->owner_node_id(); }
diff --git a/third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_reader.cc b/third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_reader.cc
index c4f15b9..5981558 100644
--- a/third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_reader.cc
+++ b/third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_reader.cc
@@ -528,7 +528,8 @@
     if (info_header_.compression == JPEG) {
       alternate_decoder_ = std::make_unique<JPEGImageDecoder>(
           parent_->GetAlphaOption(), parent_->GetColorBehavior(),
-          parent_->GetMaxDecodedBytes(), img_data_offset_);
+          parent_->GetMaxDecodedBytes(),
+          ImageDecoder::OverrideAllowDecodeToYuv::kDefault, img_data_offset_);
     } else {
       alternate_decoder_ = std::make_unique<PNGImageDecoder>(
           parent_->GetAlphaOption(), ImageDecoder::kDefaultBitDepth,
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 0571d11..75b889d 100644
--- a/third_party/blink/renderer/platform/image-decoders/image_decoder.cc
+++ b/third_party/blink/renderer/platform/image-decoders/image_decoder.cc
@@ -96,6 +96,7 @@
     AlphaOption alpha_option,
     HighBitDepthDecodingOption high_bit_depth_decoding_option,
     const ColorBehavior& color_behavior,
+    const OverrideAllowDecodeToYuv allow_decode_to_yuv,
     const SkISize& desired_size) {
   // At least kLongestSignatureLength bytes are needed to sniff the signature.
   if (data->size() < kLongestSignatureLength)
@@ -129,8 +130,8 @@
 
   std::unique_ptr<ImageDecoder> decoder;
   if (MatchesJPEGSignature(contents)) {
-    decoder.reset(
-        new JPEGImageDecoder(alpha_option, color_behavior, max_decoded_bytes));
+    decoder.reset(new JPEGImageDecoder(alpha_option, color_behavior,
+                                       max_decoded_bytes, allow_decode_to_yuv));
   } else if (MatchesPNGSignature(contents)) {
     decoder.reset(new PNGImageDecoder(alpha_option,
                                       high_bit_depth_decoding_option,
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 274c73c..f99b893 100644
--- a/third_party/blink/renderer/platform/image-decoders/image_decoder.h
+++ b/third_party/blink/renderer/platform/image-decoders/image_decoder.h
@@ -142,6 +142,13 @@
     kMaxValue = kWebPAnimationFormat,
   };
 
+  // Enforces YUV decoding to be disallowed in the image decoder. The default
+  // value defers to the YUV decoding decision to the decoder.
+  enum class OverrideAllowDecodeToYuv {
+    kDefault,
+    kDeny,
+  };
+
   virtual ~ImageDecoder() = default;
 
   // Returns a caller-owned decoder of the appropriate type.  Returns nullptr if
@@ -154,6 +161,8 @@
       AlphaOption,
       HighBitDepthDecodingOption,
       const ColorBehavior&,
+      const OverrideAllowDecodeToYuv allow_decode_to_yuv =
+          OverrideAllowDecodeToYuv::kDefault,
       const SkISize& desired_size = SkISize::MakeEmpty());
   static std::unique_ptr<ImageDecoder> Create(
       scoped_refptr<SharedBuffer> data,
@@ -161,10 +170,12 @@
       AlphaOption alpha_option,
       HighBitDepthDecodingOption high_bit_depth_decoding_option,
       const ColorBehavior& color_behavior,
+      const OverrideAllowDecodeToYuv allow_decode_to_yuv =
+          OverrideAllowDecodeToYuv::kDefault,
       const SkISize& desired_size = SkISize::MakeEmpty()) {
     return Create(SegmentReader::CreateFromSharedBuffer(std::move(data)),
                   data_complete, alpha_option, high_bit_depth_decoding_option,
-                  color_behavior, desired_size);
+                  color_behavior, allow_decode_to_yuv, desired_size);
   }
 
   virtual String FilenameExtension() const = 0;
@@ -364,7 +375,7 @@
     frame_buffer_cache_[0].SetMemoryAllocator(allocator);
   }
 
-  virtual bool CanDecodeToYUV() { return allow_decode_to_yuv_; }
+  bool CanDecodeToYUV() { return allow_decode_to_yuv_; }
   // Should only be called if CanDecodeToYuv() returns true, in which case
   // the subclass of ImageDecoder must override this method.
   virtual void DecodeToYUV() { NOTREACHED(); }
@@ -376,12 +387,13 @@
   ImageDecoder(AlphaOption alpha_option,
                HighBitDepthDecodingOption high_bit_depth_decoding_option,
                const ColorBehavior& color_behavior,
-               size_t max_decoded_bytes)
+               size_t max_decoded_bytes,
+               const bool allow_decode_to_yuv = false)
       : premultiply_alpha_(alpha_option == kAlphaPremultiplied),
         high_bit_depth_decoding_option_(high_bit_depth_decoding_option),
         color_behavior_(color_behavior),
         max_decoded_bytes_(max_decoded_bytes),
-        allow_decode_to_yuv_(false),
+        allow_decode_to_yuv_(allow_decode_to_yuv),
         purge_aggressively_(false) {}
 
   // Calculates the most recent frame whose image data may be needed in
diff --git a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc
index 142bc4d5..1831e476 100644
--- a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc
+++ b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc
@@ -448,17 +448,13 @@
 
         switch (info_.jpeg_color_space) {
           case JCS_YCbCr:
-            // libjpeg can convert YCbCr image pixels to RGB.
-            // TODO(crbug.com/919627): is the info_.scale_denom <= 8 actually
-            // needed?
-            info_.out_color_space = rgbOutputColorSpace();
-            if (decoder_->HasImagePlanes() && info_.scale_denom <= 8 &&
-                (YuvSubsampling(info_) != cc::YUVSubsampling::kUnknown))
+            if (decoder_->CanDecodeToYUV() &&
+                YuvSubsampling(info_) == cc::YUVSubsampling::k420)
               override_color_space = JCS_YCbCr;
-            break;
+            FALLTHROUGH;  // libjpeg can convert YCbCr image pixels to RGB.
           case JCS_GRAYSCALE:
+            FALLTHROUGH;  // libjpeg can convert GRAYSCALE image pixels to RGB.
           case JCS_RGB:
-            // libjpeg can convert GRAYSCALE image pixels to RGB.
             info_.out_color_space = rgbOutputColorSpace();
             break;
           case JCS_CMYK:
@@ -596,6 +592,9 @@
       }
       FALLTHROUGH;
       case JPEG_START_DECOMPRESS:
+        if (info_.out_color_space == JCS_YCbCr)
+          DCHECK(decoder_->HasImagePlanes());
+
         // Set parameters for decompression.
         // FIXME -- Should reset dct_method and dither mode for final pass
         // of progressive JPEG.
@@ -820,14 +819,20 @@
       ->Complete();
 }
 
-JPEGImageDecoder::JPEGImageDecoder(AlphaOption alpha_option,
-                                   const ColorBehavior& color_behavior,
-                                   size_t max_decoded_bytes,
-                                   size_t offset)
-    : ImageDecoder(alpha_option,
-                   ImageDecoder::kDefaultBitDepth,
-                   color_behavior,
-                   max_decoded_bytes),
+JPEGImageDecoder::JPEGImageDecoder(
+    AlphaOption alpha_option,
+    const ColorBehavior& color_behavior,
+    size_t max_decoded_bytes,
+    const OverrideAllowDecodeToYuv allow_decode_to_yuv,
+    size_t offset)
+    : ImageDecoder(
+          alpha_option,
+          ImageDecoder::kDefaultBitDepth,
+          color_behavior,
+          max_decoded_bytes,
+          // TODO(crbug.com/919627): replace kDefault case with runtime flag
+          (allow_decode_to_yuv == OverrideAllowDecodeToYuv::kDeny ? false
+                                                                  : false)),
       offset_(offset) {}
 
 JPEGImageDecoder::~JPEGImageDecoder() = default;
@@ -844,6 +849,17 @@
 }
 
 void JPEGImageDecoder::OnSetData(SegmentReader* data) {
+  // TODO(crbug.com/943519): Incremental YUV decoding is not currently
+  // supported.
+  if (IsAllDataReceived()) {
+    // TODO(crbug.com/919627): Right now |allow_decode_to_yuv_| is false by
+    // default and is only set true to for unit tests.
+    //
+    // Calling IsSizeAvailable() ensures the reader is created and the output
+    // color space is set.
+    allow_decode_to_yuv_ &=
+        IsSizeAvailable() && reader_->Info()->out_color_space == JCS_YCbCr;
+  }
   if (reader_)
     reader_->SetData(data);
 }
@@ -891,21 +907,6 @@
   return supported_decode_sizes_.IsEmpty();
 }
 
-bool JPEGImageDecoder::CanDecodeToYUV() {
-  // TODO(crbug.com/919627): Right now |allow_decode_to_yuv_| is false by
-  // default and is only set true for unit tests.
-  //
-  // Returning false here is a bit deceptive because the
-  // JPEG decoder does support YUV. But the rest of the infrastructure at levels
-  // above the decoder is not quite there yet to handle the resulting JPEG YUV
-  // data, so for now we disable that path.
-  //
-  // Calling IsSizeAvailable() ensures the reader is created and the output
-  // color space is set.
-  return allow_decode_to_yuv_ && IsSizeAvailable() &&
-         reader_->Info()->out_color_space == JCS_YCbCr;
-}
-
 void JPEGImageDecoder::DecodeToYUV() {
   DCHECK(HasImagePlanes());
   DCHECK(CanDecodeToYUV());
@@ -1029,6 +1030,8 @@
   JSAMPARRAY samples = reader->Samples();
   jpeg_decompress_struct* info = reader->Info();
 
+  DCHECK_EQ(info->out_color_space, JCS_YCbCr);
+
   JSAMPARRAY bufferraw[3];
   JSAMPROW bufferraw2[32];
   bufferraw[0] = &bufferraw2[0];   // Y channel rows (8 or 16)
diff --git a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.h b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.h
index 680103421..f3ce2085 100644
--- a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.h
+++ b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.h
@@ -39,6 +39,7 @@
   JPEGImageDecoder(AlphaOption,
                    const ColorBehavior&,
                    size_t max_decoded_bytes,
+                   const OverrideAllowDecodeToYuv allow_decode_to_yuv,
                    size_t offset = 0);
   ~JPEGImageDecoder() override;
 
@@ -49,7 +50,6 @@
   bool SetSize(unsigned width, unsigned height) override;
   IntSize DecodedYUVSize(int component) const override;
   size_t DecodedYUVWidthBytes(int component) const override;
-  bool CanDecodeToYUV() override;
   void DecodeToYUV() override;
   SkYUVColorSpace GetYUVColorSpace() const override;
   Vector<SkISize> GetSupportedDecodeSizes() const override;
diff --git a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc
index 8d9c85f4c..a82cb44e 100644
--- a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc
+++ b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc
@@ -52,7 +52,7 @@
 std::unique_ptr<JPEGImageDecoder> CreateJPEGDecoder(size_t max_decoded_bytes) {
   return std::make_unique<JPEGImageDecoder>(
       ImageDecoder::kAlphaNotPremultiplied, ColorBehavior::TransformToSRGB(),
-      max_decoded_bytes);
+      max_decoded_bytes, ImageDecoder::OverrideAllowDecodeToYuv::kDefault);
 }
 
 std::unique_ptr<ImageDecoder> CreateJPEGDecoder() {
@@ -89,8 +89,8 @@
 
   std::unique_ptr<JPEGImageDecoder> decoder =
       CreateJPEGDecoder(max_decoded_bytes);
-  decoder->SetData(data.get(), true);
   decoder->SetDecodeToYuvForTesting(true);
+  decoder->SetData(data.get(), true);
 
   // Setting a dummy ImagePlanes object signals to the decoder that we want to
   // do YUV decoding.
@@ -275,8 +275,8 @@
   ASSERT_TRUE(data);
 
   std::unique_ptr<JPEGImageDecoder> decoder = CreateJPEGDecoder(230 * 230 * 4);
-  decoder->SetData(data.get(), true);
   decoder->SetDecodeToYuvForTesting(true);
+  decoder->SetData(data.get(), true);
 
   std::unique_ptr<ImagePlanes> image_planes = std::make_unique<ImagePlanes>();
   decoder->SetImagePlanes(std::move(image_planes));
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 247f626a..b3e921a9 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2563,13 +2563,7 @@
 crbug.com/953847 [ Mac ] virtual/threaded/fast/scrolling/scrollbars/scrollbar-occluded-by-div.html [ Failure ]
 crbug.com/953847 [ Mac ] virtual/threaded/fast/scrolling/scrollbars/scrollbar-button-gesture-target.html [ Failure ]
 crbug.com/953847 [ Mac ] virtual/threaded/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Failure Timeout ]
-
-# Compositor threaded scrollbar scrolls parent of subscroller.
-# Note: even when fixed will still fail on Mac until crbug.com/953847
-# is addressed. Uncomment below line when fixing crbug.com/965829.
-#crbug.com/953847 [ Mac ] virtual/compositor_threaded_scrollbar_scrolling/fast/scrolling/scrollbars/scrollbar-button-gesture-target.html [ Failure ]
-crbug.com/987115 [ Win ] virtual/compositor_threaded_scrollbar_scrolling/fast/scrolling/scrollbars/scrollbar-button-gesture-target.html [ Failure Crash ]
-crbug.com/965829 [ Mac ] virtual/compositor_threaded_scrollbar_scrolling/fast/scrolling/scrollbars/scrollbar-button-gesture-target.html [ Failure ]
+crbug.com/953847 [ Mac ] virtual/compositor_threaded_scrollbar_scrolling/fast/scrolling/scrollbars/scrollbar-button-gesture-target.html [ Failure ]
 
 # 1px scroll offset difference for compositor threaded scrollbar scrolling on Linux.
 crbug.com/1009892 [ Win ] virtual/compositor_threaded_scrollbar_scrolling_hidpi_nozoomfordsf/fast/scrolling/scrollbars/mouse-scrolling-on-div-scrollbar.html [ Failure ]
@@ -5670,9 +5664,6 @@
 crbug.com/1002527 [ Debug ] fast/text/large-text-composed-char.html [ Pass Crash ]
 crbug.com/1002686 [ Mac10.13 ] virtual/threaded/http/tests/devtools/tracing/timeline-style/timeline-recalculate-styles.js [ Failure ]
 
-# Sheriff 2019-09-11
-crbug.com/1002828 [ Linux ] virtual/compositor_threaded_scrollbar_scrolling/fast/scrolling/scrollbars/scrollbar-button-gesture-target.html [ Pass Failure Crash ]
-
 # Tests fail because of scrollbar-width property
 crbug.com/1003055 external/wpt/css/css-scroll-snap/scroll-target-align-001.html [ Failure ]
 crbug.com/1003055 external/wpt/css/css-scroll-snap/scroll-target-align-002.html [ Failure ]
@@ -5772,3 +5763,6 @@
 crbug.com/996250 external/wpt/web-nfc/NFCReader_scan_iframe.https.html [ Timeout ]
 crbug.com/1015254 [ Mac ] external/wpt/pointerevents/extension/pointerevent_coalesced_events_attributes.html [ Pass Failure ]
 crbug.com/1015859 [ Linux ] http/tests/devtools/a11y-axe-core/performance/landing-page-a11y-test.js [ Pass Failure ]
+crbug.com/1015764 compositing/video/video-poster.html [ Pass Crash ]
+crbug.com/1015975 media/video-currentTime.html [ Pass Failure ]
+crbug.com/1015975 virtual/audio-service/media/video-currentTime.html [ Pass Failure ]
diff --git a/third_party/blink/web_tests/WebGPUExpectations b/third_party/blink/web_tests/WebGPUExpectations
index b396bc50..3361415 100644
--- a/third_party/blink/web_tests/WebGPUExpectations
+++ b/third_party/blink/web_tests/WebGPUExpectations
@@ -28,10 +28,8 @@
 #
 # Mac (Metal) specific
 #
-# TODO(crbug.com/1014785): Theses should be [ Mac ], but that doesn't work right now under the mac10.14 config that we run on dawn-mac-x64-deps-rel.
-#
 
-crbug.com/1014744 wpt_internal/webgpu/cts.html?q=cts:command_buffer/render/storeop:storeOp+controls+whether+1x1+drawn+quad+is+stored={"storeOp":"clear","expected":0} [ Failure ]
+crbug.com/1014744 [ Mac ] wpt_internal/webgpu/cts.html?q=cts:command_buffer/render/storeop:storeOp+controls+whether+1x1+drawn+quad+is+stored={"storeOp":"clear","expected":0} [ Failure ]
 
 #
 # Linux (Vulkan) specific
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 93d7205f..560154d 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
@@ -305831,7 +305831,9 @@
    "url/failure.html": [
     [
      "url/failure.html",
-     {}
+     {
+      "timeout": "long"
+     }
     ]
    ],
    "url/historical.any.js": [
@@ -443255,15 +443257,15 @@
    "support"
   ],
   "html/browsers/history/the-location-interface/location-protocol-setter-non-broken-weird-expected.txt": [
-   "16c1ec67cc915ab9e370b804d878eeeecdd137ca",
+   "9bef80c055c67c62ced74997b8cc399a1cddcf5a",
    "support"
   ],
   "html/browsers/history/the-location-interface/location-protocol-setter-non-broken-weird.html": [
-   "b7cac5e3c59b5066c8aea9f592eee57346d632b1",
+   "78ba5f6e401dadf43034c772118bba466e678131",
    "testharness"
   ],
   "html/browsers/history/the-location-interface/location-protocol-setter-non-broken.html": [
-   "ba28dc2025acf163c25c3cc7c93fbae58f081a23",
+   "32d1f1f314eb5051e75b2c6c995a18e3025db9f8",
    "testharness"
   ],
   "html/browsers/history/the-location-interface/location-protocol-setter-with-colon.sub.html": [
@@ -510887,7 +510889,7 @@
    "testharness"
   ],
   "url/failure.html": [
-   "13a90cc8d097c1631022d9cc1ec636fca19b256d",
+   "bebdb3dcc4df6ba11a16a1b2a2b450fb610c0f76",
    "testharness"
   ],
   "url/historical.any-expected.txt": [
@@ -510923,7 +510925,7 @@
    "support"
   ],
   "url/resources/urltestdata.json": [
-   "bf4e2a7833d17fab604eb634051e627887fe936a",
+   "32ed1959430c135bf5910b643e553296b8cd3a00",
    "support"
   ],
   "url/toascii.window-expected.txt": [
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-minimum-width-flex-items-009.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-minimum-width-flex-items-009.html
new file mode 100644
index 0000000..1700c4a4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-minimum-width-flex-items-009.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<title>CSS Flexible Box Test: Minimum width of flex items</title>
+<link rel="author" title="David Grogan" href="mailto:dgrogan@chromium.org" />
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com" />
+<link rel="help" href="http://www.w3.org/TR/css-flexbox-1/#min-size-auto" title="4.5. Implied Minimum Size of Flex Items" />
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht" />
+<meta name="assert" content="Implied minimum main content suggestion accounts for minimum cross size when items have an aspect ratio.">
+<style type="text/css">
+    #reference-overlapped-red {
+        position: absolute;
+        background-color: red;
+        width: 100px;
+        height: 100px;
+        z-index: -1;
+    }
+
+    #constrained-flex {
+        display: flex;
+        width: 10px;
+    }
+
+    #test-flex-item-overlapping-green {
+        min-height: 100px;
+    }
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+
+<div id="reference-overlapped-red"></div>
+<div id="constrained-flex">
+    <img id="test-flex-item-overlapping-green" src="support/60x60-green.png" />
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-minimum-width-flex-items-010.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-minimum-width-flex-items-010.html
new file mode 100644
index 0000000..8845b489
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-minimum-width-flex-items-010.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<title>CSS Flexible Box Test: Minimum width of flex items</title>
+<link rel="author" title="David Grogan" href="mailto:dgrogan@chromium.org" />
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com" />
+<link rel="help" href="http://www.w3.org/TR/css-flexbox-1/#min-size-auto" title="4.5. Implied Minimum Size of Flex Items" />
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht" />
+<meta name="assert" content="Implied minimum main content suggestion accounts for maximum cross size when items have an aspect ratio.">
+<style type="text/css">
+    #reference-overlapped-red {
+        position: absolute;
+        background-color: red;
+        width: 100px;
+        height: 100px;
+        z-index: -1;
+    }
+
+    #constrained-flex {
+        display: flex;
+        width: 10px;
+    }
+
+    #test-flex-item-overlapping-green {
+        max-height: 100px;
+    }
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+
+<div id="reference-overlapped-red"></div>
+<div id="constrained-flex">
+    <img id="test-flex-item-overlapping-green" src="support/200x200-green.png" />
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/support/200x200-green.png b/third_party/blink/web_tests/external/wpt/css/css-flexbox/support/200x200-green.png
index 1136e72..1dcc392a 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-flexbox/support/200x200-green.png
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/support/200x200-green.png
Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/history/the-location-interface/location-protocol-setter-non-broken-weird-expected.txt b/third_party/blink/web_tests/external/wpt/html/browsers/history/the-location-interface/location-protocol-setter-non-broken-weird-expected.txt
index 16c1ec67..9bef80c 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/history/the-location-interface/location-protocol-setter-non-broken-weird-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/history/the-location-interface/location-protocol-setter-non-broken-weird-expected.txt
@@ -3,7 +3,6 @@
 FAIL Set location.protocol to data Blocked a frame with origin "http://web-platform.test:8001" from accessing a cross-origin frame.
 FAIL Set location.protocol to file Failed to set the 'protocol' property on 'Location': 'file://web-platform.test:8001/common/blank.html' is not a valid URL.
 PASS Set location.protocol to ftp
-PASS Set location.protocol to gopher
 PASS Set location.protocol to http+x
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/history/the-location-interface/location-protocol-setter-non-broken-weird.html b/third_party/blink/web_tests/external/wpt/html/browsers/history/the-location-interface/location-protocol-setter-non-broken-weird.html
index b7cac5e..78ba5f6 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/history/the-location-interface/location-protocol-setter-non-broken-weird.html
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/history/the-location-interface/location-protocol-setter-non-broken-weird.html
@@ -17,7 +17,6 @@
     'data',
     'file',
     'ftp',
-    'gopher',
     'http+x'
   ].forEach((val, index) => {
     async_test((t) => {
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/history/the-location-interface/location-protocol-setter-non-broken.html b/third_party/blink/web_tests/external/wpt/html/browsers/history/the-location-interface/location-protocol-setter-non-broken.html
index ba28dc20..32d1f1f 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/history/the-location-interface/location-protocol-setter-non-broken.html
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/history/the-location-interface/location-protocol-setter-non-broken.html
@@ -12,7 +12,6 @@
     // 'mailto' opens an email client in Firefox...
     'file',
     'ftp',
-    'gopher',
     'http+x'
   ].forEach((val) => {
     async_test((t) => {
diff --git a/third_party/blink/web_tests/external/wpt/url/failure.html b/third_party/blink/web_tests/external/wpt/url/failure.html
index 13a90cc..bebdb3dc 100644
--- a/third_party/blink/web_tests/external/wpt/url/failure.html
+++ b/third_party/blink/web_tests/external/wpt/url/failure.html
@@ -1,6 +1,7 @@
 <!doctype html>
 <meta charset=utf-8>
 <title>Test URL parser failure consistency</title>
+<meta name=timeout content=long>
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <div id=log></div>
diff --git a/third_party/blink/web_tests/external/wpt/url/resources/urltestdata.json b/third_party/blink/web_tests/external/wpt/url/resources/urltestdata.json
index bf4e2a7..32ed1959 100644
--- a/third_party/blink/web_tests/external/wpt/url/resources/urltestdata.json
+++ b/third_party/blink/web_tests/external/wpt/url/resources/urltestdata.json
@@ -1076,15 +1076,15 @@
   {
     "input": "gopher:/example.com/",
     "base": "http://example.org/foo/bar",
-    "href": "gopher://example.com/",
-    "origin": "gopher://example.com",
+    "href": "gopher:/example.com/",
+    "origin": "null",
     "protocol": "gopher:",
     "username": "",
     "password": "",
-    "host": "example.com",
-    "hostname": "example.com",
+    "host": "",
+    "hostname": "",
     "port": "",
-    "pathname": "/",
+    "pathname": "/example.com/",
     "search": "",
     "hash": ""
   },
@@ -1241,15 +1241,15 @@
   {
     "input": "gopher:example.com/",
     "base": "http://example.org/foo/bar",
-    "href": "gopher://example.com/",
-    "origin": "gopher://example.com",
+    "href": "gopher:example.com/",
+    "origin": "null",
     "protocol": "gopher:",
     "username": "",
     "password": "",
-    "host": "example.com",
-    "hostname": "example.com",
+    "host": "",
+    "hostname": "",
     "port": "",
-    "pathname": "/",
+    "pathname": "example.com/",
     "search": "",
     "hash": ""
   },
@@ -2511,14 +2511,14 @@
   {
     "input": "gopher://foo:70/",
     "base": "about:blank",
-    "href": "gopher://foo/",
-    "origin": "gopher://foo",
+    "href": "gopher://foo:70/",
+    "origin": "null",
     "protocol": "gopher:",
     "username": "",
     "password": "",
-    "host": "foo",
+    "host": "foo:70",
     "hostname": "foo",
-    "port": "",
+    "port": "70",
     "pathname": "/",
     "search": "",
     "hash": ""
@@ -2527,7 +2527,7 @@
     "input": "gopher://foo:443/",
     "base": "about:blank",
     "href": "gopher://foo:443/",
-    "origin": "gopher://foo:443",
+    "origin": "null",
     "protocol": "gopher:",
     "username": "",
     "password": "",
@@ -2750,15 +2750,15 @@
   {
     "input": "gopher:/example.com/",
     "base": "about:blank",
-    "href": "gopher://example.com/",
-    "origin": "gopher://example.com",
+    "href": "gopher:/example.com/",
+    "origin": "null",
     "protocol": "gopher:",
     "username": "",
     "password": "",
-    "host": "example.com",
-    "hostname": "example.com",
+    "host": "",
+    "hostname": "",
     "port": "",
-    "pathname": "/",
+    "pathname": "/example.com/",
     "search": "",
     "hash": ""
   },
@@ -2915,15 +2915,15 @@
   {
     "input": "gopher:example.com/",
     "base": "about:blank",
-    "href": "gopher://example.com/",
-    "origin": "gopher://example.com",
+    "href": "gopher:example.com/",
+    "origin": "null",
     "protocol": "gopher:",
     "username": "",
     "password": "",
-    "host": "example.com",
-    "hostname": "example.com",
+    "host": "",
+    "hostname": "",
     "port": "",
-    "pathname": "/",
+    "pathname": "example.com/",
     "search": "",
     "hash": ""
   },
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/background/no-repaint-for-solid-color-background-attachment-fixed-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/background/no-repaint-for-solid-color-background-attachment-fixed-expected.txt
new file mode 100644
index 0000000..5fea40a1
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/background/no-repaint-for-solid-color-background-attachment-fixed-expected.txt
@@ -0,0 +1,23 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling background of LayoutView #document",
+      "bounds": [800, 5016],
+      "contentsOpaque": true,
+      "backgroundColor": "#0000FF",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1000, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/paint/invalidation/background/no-repaint-for-solid-color-background-attachment-fixed-expected.html b/third_party/blink/web_tests/paint/invalidation/background/no-repaint-for-solid-color-background-attachment-fixed-expected.html
new file mode 100644
index 0000000..406c784c
--- /dev/null
+++ b/third_party/blink/web_tests/paint/invalidation/background/no-repaint-for-solid-color-background-attachment-fixed-expected.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<body style="background: blue"></body>
diff --git a/third_party/blink/web_tests/paint/invalidation/background/no-repaint-for-solid-color-background-attachment-fixed-expected.txt b/third_party/blink/web_tests/paint/invalidation/background/no-repaint-for-solid-color-background-attachment-fixed-expected.txt
new file mode 100644
index 0000000..feb2051
--- /dev/null
+++ b/third_party/blink/web_tests/paint/invalidation/background/no-repaint-for-solid-color-background-attachment-fixed-expected.txt
@@ -0,0 +1,28 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 5016],
+      "contentsOpaque": true,
+      "backgroundColor": "#0000FF",
+      "transform": 1
+    },
+    {
+      "name": "Vertical Scrollbar Layer",
+      "position": [800, 0],
+      "bounds": [0, 600]
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1000, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/paint/invalidation/background/no-repaint-for-solid-color-background-attachment-fixed.html b/third_party/blink/web_tests/paint/invalidation/background/no-repaint-for-solid-color-background-attachment-fixed.html
new file mode 100644
index 0000000..33de4b0
--- /dev/null
+++ b/third_party/blink/web_tests/paint/invalidation/background/no-repaint-for-solid-color-background-attachment-fixed.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<style>
+::-webkit-scrollbar { display: none; }
+body {
+    background: blue;
+    background-attachment: fixed;
+}
+</style>
+<script src="../resources/text-based-repaint.js" type="text/javascript"></script>
+<script>
+if (window.testRunner)
+    internals.settings.setPreferCompositingToLCDTextEnabled(false);
+
+function repaintTest() {
+    window.scrollTo(0, 1000);
+}
+
+window.onload = function() {
+    runRepaintAndPixelTest();
+};
+</script>
+<div style="height: 5000px">
+Tests that scrolling a frame with background-attachment: fixed and solid color background should not invalidate.
+</div>
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/url/a-element-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/url/a-element-expected.txt
index a9c7a84..5bacb56 100644
--- a/third_party/blink/web_tests/platform/linux/external/wpt/url/a-element-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/external/wpt/url/a-element-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 517 tests; 334 PASS, 183 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 517 tests; 329 PASS, 188 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -85,7 +85,7 @@
 FAIL Parsing: <file://example%/> against <about:blank> assert_equals: failure should set href to input expected "file://example%/" but got "file://example%25/"
 PASS Parsing: <file://[example]/> against <about:blank>
 PASS Parsing: <ftps:/example.com/> against <http://example.org/foo/bar>
-PASS Parsing: <gopher:/example.com/> against <http://example.org/foo/bar>
+FAIL Parsing: <gopher:/example.com/> against <http://example.org/foo/bar> assert_equals: href expected "gopher:/example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <wss:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <data:/example.com/> against <http://example.org/foo/bar>
@@ -96,7 +96,7 @@
 PASS Parsing: <https:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <madeupscheme:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <ftps:example.com/> against <http://example.org/foo/bar>
-PASS Parsing: <gopher:example.com/> against <http://example.org/foo/bar>
+FAIL Parsing: <gopher:example.com/> against <http://example.org/foo/bar> assert_equals: href expected "gopher:example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <wss:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <data:example.com/> against <http://example.org/foo/bar>
@@ -183,7 +183,7 @@
 PASS Parsing: <https://foo:80/> against <about:blank>
 PASS Parsing: <ftp://foo:21/> against <about:blank>
 PASS Parsing: <ftp://foo:80/> against <about:blank>
-PASS Parsing: <gopher://foo:70/> against <about:blank>
+FAIL Parsing: <gopher://foo:70/> against <about:blank> assert_equals: href expected "gopher://foo:70/" but got "gopher://foo/"
 PASS Parsing: <gopher://foo:443/> against <about:blank>
 PASS Parsing: <ws://foo:80/> against <about:blank>
 PASS Parsing: <ws://foo:81/> against <about:blank>
@@ -199,7 +199,7 @@
 PASS Parsing: <madeupscheme:/example.com/> against <about:blank>
 PASS Parsing: <file:/example.com/> against <about:blank>
 PASS Parsing: <ftps:/example.com/> against <about:blank>
-PASS Parsing: <gopher:/example.com/> against <about:blank>
+FAIL Parsing: <gopher:/example.com/> against <about:blank> assert_equals: href expected "gopher:/example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:/example.com/> against <about:blank>
 PASS Parsing: <wss:/example.com/> against <about:blank>
 PASS Parsing: <data:/example.com/> against <about:blank>
@@ -210,7 +210,7 @@
 PASS Parsing: <https:example.com/> against <about:blank>
 PASS Parsing: <madeupscheme:example.com/> against <about:blank>
 PASS Parsing: <ftps:example.com/> against <about:blank>
-PASS Parsing: <gopher:example.com/> against <about:blank>
+FAIL Parsing: <gopher:example.com/> against <about:blank> assert_equals: href expected "gopher:example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:example.com/> against <about:blank>
 PASS Parsing: <wss:example.com/> against <about:blank>
 PASS Parsing: <data:example.com/> against <about:blank>
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/url/a-element-origin-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/url/a-element-origin-expected.txt
index 2eff1d990..f9acfa5a 100644
--- a/third_party/blink/web_tests/platform/linux/external/wpt/url/a-element-origin-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/external/wpt/url/a-element-origin-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 304 tests; 300 PASS, 4 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 304 tests; 294 PASS, 10 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing origin: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -69,7 +69,7 @@
 PASS Parsing origin: <https:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <madeupscheme:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <ftps:/example.com/> against <http://example.org/foo/bar>
-PASS Parsing origin: <gopher:/example.com/> against <http://example.org/foo/bar>
+FAIL Parsing origin: <gopher:/example.com/> against <http://example.org/foo/bar> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Parsing origin: <ws:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <wss:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <data:/example.com/> against <http://example.org/foo/bar>
@@ -80,7 +80,7 @@
 PASS Parsing origin: <https:example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <madeupscheme:example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <ftps:example.com/> against <http://example.org/foo/bar>
-PASS Parsing origin: <gopher:example.com/> against <http://example.org/foo/bar>
+FAIL Parsing origin: <gopher:example.com/> against <http://example.org/foo/bar> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Parsing origin: <ws:example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <wss:example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <data:example.com/> against <http://example.org/foo/bar>
@@ -146,8 +146,8 @@
 PASS Parsing origin: <https://foo:80/> against <about:blank>
 PASS Parsing origin: <ftp://foo:21/> against <about:blank>
 PASS Parsing origin: <ftp://foo:80/> against <about:blank>
-PASS Parsing origin: <gopher://foo:70/> against <about:blank>
-PASS Parsing origin: <gopher://foo:443/> against <about:blank>
+FAIL Parsing origin: <gopher://foo:70/> against <about:blank> assert_equals: origin expected "null" but got "gopher://foo"
+FAIL Parsing origin: <gopher://foo:443/> against <about:blank> assert_equals: origin expected "null" but got "gopher://foo:443"
 PASS Parsing origin: <ws://foo:80/> against <about:blank>
 PASS Parsing origin: <ws://foo:81/> against <about:blank>
 PASS Parsing origin: <ws://foo:443/> against <about:blank>
@@ -161,7 +161,7 @@
 PASS Parsing origin: <https:/example.com/> against <about:blank>
 PASS Parsing origin: <madeupscheme:/example.com/> against <about:blank>
 PASS Parsing origin: <ftps:/example.com/> against <about:blank>
-PASS Parsing origin: <gopher:/example.com/> against <about:blank>
+FAIL Parsing origin: <gopher:/example.com/> against <about:blank> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Parsing origin: <ws:/example.com/> against <about:blank>
 PASS Parsing origin: <wss:/example.com/> against <about:blank>
 PASS Parsing origin: <data:/example.com/> against <about:blank>
@@ -172,7 +172,7 @@
 PASS Parsing origin: <https:example.com/> against <about:blank>
 PASS Parsing origin: <madeupscheme:example.com/> against <about:blank>
 PASS Parsing origin: <ftps:example.com/> against <about:blank>
-PASS Parsing origin: <gopher:example.com/> against <about:blank>
+FAIL Parsing origin: <gopher:example.com/> against <about:blank> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Parsing origin: <ws:example.com/> against <about:blank>
 PASS Parsing origin: <wss:example.com/> against <about:blank>
 PASS Parsing origin: <data:example.com/> against <about:blank>
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/url/a-element-origin-xhtml-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/url/a-element-origin-xhtml-expected.txt
index 2eff1d990..f9acfa5a 100644
--- a/third_party/blink/web_tests/platform/linux/external/wpt/url/a-element-origin-xhtml-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/external/wpt/url/a-element-origin-xhtml-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 304 tests; 300 PASS, 4 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 304 tests; 294 PASS, 10 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing origin: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -69,7 +69,7 @@
 PASS Parsing origin: <https:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <madeupscheme:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <ftps:/example.com/> against <http://example.org/foo/bar>
-PASS Parsing origin: <gopher:/example.com/> against <http://example.org/foo/bar>
+FAIL Parsing origin: <gopher:/example.com/> against <http://example.org/foo/bar> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Parsing origin: <ws:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <wss:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <data:/example.com/> against <http://example.org/foo/bar>
@@ -80,7 +80,7 @@
 PASS Parsing origin: <https:example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <madeupscheme:example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <ftps:example.com/> against <http://example.org/foo/bar>
-PASS Parsing origin: <gopher:example.com/> against <http://example.org/foo/bar>
+FAIL Parsing origin: <gopher:example.com/> against <http://example.org/foo/bar> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Parsing origin: <ws:example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <wss:example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <data:example.com/> against <http://example.org/foo/bar>
@@ -146,8 +146,8 @@
 PASS Parsing origin: <https://foo:80/> against <about:blank>
 PASS Parsing origin: <ftp://foo:21/> against <about:blank>
 PASS Parsing origin: <ftp://foo:80/> against <about:blank>
-PASS Parsing origin: <gopher://foo:70/> against <about:blank>
-PASS Parsing origin: <gopher://foo:443/> against <about:blank>
+FAIL Parsing origin: <gopher://foo:70/> against <about:blank> assert_equals: origin expected "null" but got "gopher://foo"
+FAIL Parsing origin: <gopher://foo:443/> against <about:blank> assert_equals: origin expected "null" but got "gopher://foo:443"
 PASS Parsing origin: <ws://foo:80/> against <about:blank>
 PASS Parsing origin: <ws://foo:81/> against <about:blank>
 PASS Parsing origin: <ws://foo:443/> against <about:blank>
@@ -161,7 +161,7 @@
 PASS Parsing origin: <https:/example.com/> against <about:blank>
 PASS Parsing origin: <madeupscheme:/example.com/> against <about:blank>
 PASS Parsing origin: <ftps:/example.com/> against <about:blank>
-PASS Parsing origin: <gopher:/example.com/> against <about:blank>
+FAIL Parsing origin: <gopher:/example.com/> against <about:blank> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Parsing origin: <ws:/example.com/> against <about:blank>
 PASS Parsing origin: <wss:/example.com/> against <about:blank>
 PASS Parsing origin: <data:/example.com/> against <about:blank>
@@ -172,7 +172,7 @@
 PASS Parsing origin: <https:example.com/> against <about:blank>
 PASS Parsing origin: <madeupscheme:example.com/> against <about:blank>
 PASS Parsing origin: <ftps:example.com/> against <about:blank>
-PASS Parsing origin: <gopher:example.com/> against <about:blank>
+FAIL Parsing origin: <gopher:example.com/> against <about:blank> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Parsing origin: <ws:example.com/> against <about:blank>
 PASS Parsing origin: <wss:example.com/> against <about:blank>
 PASS Parsing origin: <data:example.com/> against <about:blank>
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/url/a-element-xhtml-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/url/a-element-xhtml-expected.txt
index a9c7a84..5bacb56 100644
--- a/third_party/blink/web_tests/platform/linux/external/wpt/url/a-element-xhtml-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/external/wpt/url/a-element-xhtml-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 517 tests; 334 PASS, 183 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 517 tests; 329 PASS, 188 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -85,7 +85,7 @@
 FAIL Parsing: <file://example%/> against <about:blank> assert_equals: failure should set href to input expected "file://example%/" but got "file://example%25/"
 PASS Parsing: <file://[example]/> against <about:blank>
 PASS Parsing: <ftps:/example.com/> against <http://example.org/foo/bar>
-PASS Parsing: <gopher:/example.com/> against <http://example.org/foo/bar>
+FAIL Parsing: <gopher:/example.com/> against <http://example.org/foo/bar> assert_equals: href expected "gopher:/example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <wss:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <data:/example.com/> against <http://example.org/foo/bar>
@@ -96,7 +96,7 @@
 PASS Parsing: <https:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <madeupscheme:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <ftps:example.com/> against <http://example.org/foo/bar>
-PASS Parsing: <gopher:example.com/> against <http://example.org/foo/bar>
+FAIL Parsing: <gopher:example.com/> against <http://example.org/foo/bar> assert_equals: href expected "gopher:example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <wss:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <data:example.com/> against <http://example.org/foo/bar>
@@ -183,7 +183,7 @@
 PASS Parsing: <https://foo:80/> against <about:blank>
 PASS Parsing: <ftp://foo:21/> against <about:blank>
 PASS Parsing: <ftp://foo:80/> against <about:blank>
-PASS Parsing: <gopher://foo:70/> against <about:blank>
+FAIL Parsing: <gopher://foo:70/> against <about:blank> assert_equals: href expected "gopher://foo:70/" but got "gopher://foo/"
 PASS Parsing: <gopher://foo:443/> against <about:blank>
 PASS Parsing: <ws://foo:80/> against <about:blank>
 PASS Parsing: <ws://foo:81/> against <about:blank>
@@ -199,7 +199,7 @@
 PASS Parsing: <madeupscheme:/example.com/> against <about:blank>
 PASS Parsing: <file:/example.com/> against <about:blank>
 PASS Parsing: <ftps:/example.com/> against <about:blank>
-PASS Parsing: <gopher:/example.com/> against <about:blank>
+FAIL Parsing: <gopher:/example.com/> against <about:blank> assert_equals: href expected "gopher:/example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:/example.com/> against <about:blank>
 PASS Parsing: <wss:/example.com/> against <about:blank>
 PASS Parsing: <data:/example.com/> against <about:blank>
@@ -210,7 +210,7 @@
 PASS Parsing: <https:example.com/> against <about:blank>
 PASS Parsing: <madeupscheme:example.com/> against <about:blank>
 PASS Parsing: <ftps:example.com/> against <about:blank>
-PASS Parsing: <gopher:example.com/> against <about:blank>
+FAIL Parsing: <gopher:example.com/> against <about:blank> assert_equals: href expected "gopher:example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:example.com/> against <about:blank>
 PASS Parsing: <wss:example.com/> against <about:blank>
 PASS Parsing: <data:example.com/> against <about:blank>
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/url/url-constructor-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/url/url-constructor-expected.txt
index 1938487b..041bb43 100644
--- a/third_party/blink/web_tests/platform/linux/external/wpt/url/url-constructor-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/external/wpt/url/url-constructor-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 517 tests; 400 PASS, 117 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 517 tests; 395 PASS, 122 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -87,7 +87,7 @@
 PASS Parsing: <file://example%/> against <about:blank>
 PASS Parsing: <file://[example]/> against <about:blank>
 PASS Parsing: <ftps:/example.com/> against <http://example.org/foo/bar>
-PASS Parsing: <gopher:/example.com/> against <http://example.org/foo/bar>
+FAIL Parsing: <gopher:/example.com/> against <http://example.org/foo/bar> assert_equals: href expected "gopher:/example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <wss:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <data:/example.com/> against <http://example.org/foo/bar>
@@ -98,7 +98,7 @@
 PASS Parsing: <https:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <madeupscheme:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <ftps:example.com/> against <http://example.org/foo/bar>
-PASS Parsing: <gopher:example.com/> against <http://example.org/foo/bar>
+FAIL Parsing: <gopher:example.com/> against <http://example.org/foo/bar> assert_equals: href expected "gopher:example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <wss:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <data:example.com/> against <http://example.org/foo/bar>
@@ -185,7 +185,7 @@
 PASS Parsing: <https://foo:80/> against <about:blank>
 PASS Parsing: <ftp://foo:21/> against <about:blank>
 PASS Parsing: <ftp://foo:80/> against <about:blank>
-PASS Parsing: <gopher://foo:70/> against <about:blank>
+FAIL Parsing: <gopher://foo:70/> against <about:blank> assert_equals: href expected "gopher://foo:70/" but got "gopher://foo/"
 PASS Parsing: <gopher://foo:443/> against <about:blank>
 PASS Parsing: <ws://foo:80/> against <about:blank>
 PASS Parsing: <ws://foo:81/> against <about:blank>
@@ -201,7 +201,7 @@
 PASS Parsing: <madeupscheme:/example.com/> against <about:blank>
 PASS Parsing: <file:/example.com/> against <about:blank>
 PASS Parsing: <ftps:/example.com/> against <about:blank>
-PASS Parsing: <gopher:/example.com/> against <about:blank>
+FAIL Parsing: <gopher:/example.com/> against <about:blank> assert_equals: href expected "gopher:/example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:/example.com/> against <about:blank>
 PASS Parsing: <wss:/example.com/> against <about:blank>
 PASS Parsing: <data:/example.com/> against <about:blank>
@@ -212,7 +212,7 @@
 PASS Parsing: <https:example.com/> against <about:blank>
 PASS Parsing: <madeupscheme:example.com/> against <about:blank>
 PASS Parsing: <ftps:example.com/> against <about:blank>
-PASS Parsing: <gopher:example.com/> against <about:blank>
+FAIL Parsing: <gopher:example.com/> against <about:blank> assert_equals: href expected "gopher:example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:example.com/> against <about:blank>
 PASS Parsing: <wss:example.com/> against <about:blank>
 PASS Parsing: <data:example.com/> against <about:blank>
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/url/url-origin-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/url/url-origin-expected.txt
index 72594ff..42a736f 100644
--- a/third_party/blink/web_tests/platform/linux/external/wpt/url/url-origin-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/external/wpt/url/url-origin-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 304 tests; 297 PASS, 7 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 304 tests; 291 PASS, 13 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Origin parsing: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -69,7 +69,7 @@
 PASS Origin parsing: <https:/example.com/> against <http://example.org/foo/bar>
 PASS Origin parsing: <madeupscheme:/example.com/> against <http://example.org/foo/bar>
 PASS Origin parsing: <ftps:/example.com/> against <http://example.org/foo/bar>
-PASS Origin parsing: <gopher:/example.com/> against <http://example.org/foo/bar>
+FAIL Origin parsing: <gopher:/example.com/> against <http://example.org/foo/bar> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Origin parsing: <ws:/example.com/> against <http://example.org/foo/bar>
 PASS Origin parsing: <wss:/example.com/> against <http://example.org/foo/bar>
 PASS Origin parsing: <data:/example.com/> against <http://example.org/foo/bar>
@@ -80,7 +80,7 @@
 PASS Origin parsing: <https:example.com/> against <http://example.org/foo/bar>
 PASS Origin parsing: <madeupscheme:example.com/> against <http://example.org/foo/bar>
 PASS Origin parsing: <ftps:example.com/> against <http://example.org/foo/bar>
-PASS Origin parsing: <gopher:example.com/> against <http://example.org/foo/bar>
+FAIL Origin parsing: <gopher:example.com/> against <http://example.org/foo/bar> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Origin parsing: <ws:example.com/> against <http://example.org/foo/bar>
 PASS Origin parsing: <wss:example.com/> against <http://example.org/foo/bar>
 PASS Origin parsing: <data:example.com/> against <http://example.org/foo/bar>
@@ -146,8 +146,8 @@
 PASS Origin parsing: <https://foo:80/> against <about:blank>
 PASS Origin parsing: <ftp://foo:21/> against <about:blank>
 PASS Origin parsing: <ftp://foo:80/> against <about:blank>
-PASS Origin parsing: <gopher://foo:70/> against <about:blank>
-PASS Origin parsing: <gopher://foo:443/> against <about:blank>
+FAIL Origin parsing: <gopher://foo:70/> against <about:blank> assert_equals: origin expected "null" but got "gopher://foo"
+FAIL Origin parsing: <gopher://foo:443/> against <about:blank> assert_equals: origin expected "null" but got "gopher://foo:443"
 PASS Origin parsing: <ws://foo:80/> against <about:blank>
 PASS Origin parsing: <ws://foo:81/> against <about:blank>
 PASS Origin parsing: <ws://foo:443/> against <about:blank>
@@ -161,7 +161,7 @@
 PASS Origin parsing: <https:/example.com/> against <about:blank>
 PASS Origin parsing: <madeupscheme:/example.com/> against <about:blank>
 PASS Origin parsing: <ftps:/example.com/> against <about:blank>
-PASS Origin parsing: <gopher:/example.com/> against <about:blank>
+FAIL Origin parsing: <gopher:/example.com/> against <about:blank> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Origin parsing: <ws:/example.com/> against <about:blank>
 PASS Origin parsing: <wss:/example.com/> against <about:blank>
 PASS Origin parsing: <data:/example.com/> against <about:blank>
@@ -172,7 +172,7 @@
 PASS Origin parsing: <https:example.com/> against <about:blank>
 PASS Origin parsing: <madeupscheme:example.com/> against <about:blank>
 PASS Origin parsing: <ftps:example.com/> against <about:blank>
-PASS Origin parsing: <gopher:example.com/> against <about:blank>
+FAIL Origin parsing: <gopher:example.com/> against <about:blank> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Origin parsing: <ws:example.com/> against <about:blank>
 PASS Origin parsing: <wss:example.com/> against <about:blank>
 PASS Origin parsing: <data:example.com/> against <about:blank>
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/url/a-element-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/url/a-element-expected.txt
index a9c7a84..5bacb56 100644
--- a/third_party/blink/web_tests/platform/mac/external/wpt/url/a-element-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/external/wpt/url/a-element-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 517 tests; 334 PASS, 183 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 517 tests; 329 PASS, 188 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -85,7 +85,7 @@
 FAIL Parsing: <file://example%/> against <about:blank> assert_equals: failure should set href to input expected "file://example%/" but got "file://example%25/"
 PASS Parsing: <file://[example]/> against <about:blank>
 PASS Parsing: <ftps:/example.com/> against <http://example.org/foo/bar>
-PASS Parsing: <gopher:/example.com/> against <http://example.org/foo/bar>
+FAIL Parsing: <gopher:/example.com/> against <http://example.org/foo/bar> assert_equals: href expected "gopher:/example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <wss:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <data:/example.com/> against <http://example.org/foo/bar>
@@ -96,7 +96,7 @@
 PASS Parsing: <https:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <madeupscheme:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <ftps:example.com/> against <http://example.org/foo/bar>
-PASS Parsing: <gopher:example.com/> against <http://example.org/foo/bar>
+FAIL Parsing: <gopher:example.com/> against <http://example.org/foo/bar> assert_equals: href expected "gopher:example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <wss:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <data:example.com/> against <http://example.org/foo/bar>
@@ -183,7 +183,7 @@
 PASS Parsing: <https://foo:80/> against <about:blank>
 PASS Parsing: <ftp://foo:21/> against <about:blank>
 PASS Parsing: <ftp://foo:80/> against <about:blank>
-PASS Parsing: <gopher://foo:70/> against <about:blank>
+FAIL Parsing: <gopher://foo:70/> against <about:blank> assert_equals: href expected "gopher://foo:70/" but got "gopher://foo/"
 PASS Parsing: <gopher://foo:443/> against <about:blank>
 PASS Parsing: <ws://foo:80/> against <about:blank>
 PASS Parsing: <ws://foo:81/> against <about:blank>
@@ -199,7 +199,7 @@
 PASS Parsing: <madeupscheme:/example.com/> against <about:blank>
 PASS Parsing: <file:/example.com/> against <about:blank>
 PASS Parsing: <ftps:/example.com/> against <about:blank>
-PASS Parsing: <gopher:/example.com/> against <about:blank>
+FAIL Parsing: <gopher:/example.com/> against <about:blank> assert_equals: href expected "gopher:/example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:/example.com/> against <about:blank>
 PASS Parsing: <wss:/example.com/> against <about:blank>
 PASS Parsing: <data:/example.com/> against <about:blank>
@@ -210,7 +210,7 @@
 PASS Parsing: <https:example.com/> against <about:blank>
 PASS Parsing: <madeupscheme:example.com/> against <about:blank>
 PASS Parsing: <ftps:example.com/> against <about:blank>
-PASS Parsing: <gopher:example.com/> against <about:blank>
+FAIL Parsing: <gopher:example.com/> against <about:blank> assert_equals: href expected "gopher:example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:example.com/> against <about:blank>
 PASS Parsing: <wss:example.com/> against <about:blank>
 PASS Parsing: <data:example.com/> against <about:blank>
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/url/a-element-origin-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/url/a-element-origin-expected.txt
index 2eff1d990..f9acfa5a 100644
--- a/third_party/blink/web_tests/platform/mac/external/wpt/url/a-element-origin-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/external/wpt/url/a-element-origin-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 304 tests; 300 PASS, 4 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 304 tests; 294 PASS, 10 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing origin: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -69,7 +69,7 @@
 PASS Parsing origin: <https:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <madeupscheme:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <ftps:/example.com/> against <http://example.org/foo/bar>
-PASS Parsing origin: <gopher:/example.com/> against <http://example.org/foo/bar>
+FAIL Parsing origin: <gopher:/example.com/> against <http://example.org/foo/bar> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Parsing origin: <ws:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <wss:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <data:/example.com/> against <http://example.org/foo/bar>
@@ -80,7 +80,7 @@
 PASS Parsing origin: <https:example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <madeupscheme:example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <ftps:example.com/> against <http://example.org/foo/bar>
-PASS Parsing origin: <gopher:example.com/> against <http://example.org/foo/bar>
+FAIL Parsing origin: <gopher:example.com/> against <http://example.org/foo/bar> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Parsing origin: <ws:example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <wss:example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <data:example.com/> against <http://example.org/foo/bar>
@@ -146,8 +146,8 @@
 PASS Parsing origin: <https://foo:80/> against <about:blank>
 PASS Parsing origin: <ftp://foo:21/> against <about:blank>
 PASS Parsing origin: <ftp://foo:80/> against <about:blank>
-PASS Parsing origin: <gopher://foo:70/> against <about:blank>
-PASS Parsing origin: <gopher://foo:443/> against <about:blank>
+FAIL Parsing origin: <gopher://foo:70/> against <about:blank> assert_equals: origin expected "null" but got "gopher://foo"
+FAIL Parsing origin: <gopher://foo:443/> against <about:blank> assert_equals: origin expected "null" but got "gopher://foo:443"
 PASS Parsing origin: <ws://foo:80/> against <about:blank>
 PASS Parsing origin: <ws://foo:81/> against <about:blank>
 PASS Parsing origin: <ws://foo:443/> against <about:blank>
@@ -161,7 +161,7 @@
 PASS Parsing origin: <https:/example.com/> against <about:blank>
 PASS Parsing origin: <madeupscheme:/example.com/> against <about:blank>
 PASS Parsing origin: <ftps:/example.com/> against <about:blank>
-PASS Parsing origin: <gopher:/example.com/> against <about:blank>
+FAIL Parsing origin: <gopher:/example.com/> against <about:blank> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Parsing origin: <ws:/example.com/> against <about:blank>
 PASS Parsing origin: <wss:/example.com/> against <about:blank>
 PASS Parsing origin: <data:/example.com/> against <about:blank>
@@ -172,7 +172,7 @@
 PASS Parsing origin: <https:example.com/> against <about:blank>
 PASS Parsing origin: <madeupscheme:example.com/> against <about:blank>
 PASS Parsing origin: <ftps:example.com/> against <about:blank>
-PASS Parsing origin: <gopher:example.com/> against <about:blank>
+FAIL Parsing origin: <gopher:example.com/> against <about:blank> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Parsing origin: <ws:example.com/> against <about:blank>
 PASS Parsing origin: <wss:example.com/> against <about:blank>
 PASS Parsing origin: <data:example.com/> against <about:blank>
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/url/a-element-origin-xhtml-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/url/a-element-origin-xhtml-expected.txt
index 2eff1d990..f9acfa5a 100644
--- a/third_party/blink/web_tests/platform/mac/external/wpt/url/a-element-origin-xhtml-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/external/wpt/url/a-element-origin-xhtml-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 304 tests; 300 PASS, 4 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 304 tests; 294 PASS, 10 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing origin: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -69,7 +69,7 @@
 PASS Parsing origin: <https:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <madeupscheme:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <ftps:/example.com/> against <http://example.org/foo/bar>
-PASS Parsing origin: <gopher:/example.com/> against <http://example.org/foo/bar>
+FAIL Parsing origin: <gopher:/example.com/> against <http://example.org/foo/bar> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Parsing origin: <ws:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <wss:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <data:/example.com/> against <http://example.org/foo/bar>
@@ -80,7 +80,7 @@
 PASS Parsing origin: <https:example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <madeupscheme:example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <ftps:example.com/> against <http://example.org/foo/bar>
-PASS Parsing origin: <gopher:example.com/> against <http://example.org/foo/bar>
+FAIL Parsing origin: <gopher:example.com/> against <http://example.org/foo/bar> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Parsing origin: <ws:example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <wss:example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <data:example.com/> against <http://example.org/foo/bar>
@@ -146,8 +146,8 @@
 PASS Parsing origin: <https://foo:80/> against <about:blank>
 PASS Parsing origin: <ftp://foo:21/> against <about:blank>
 PASS Parsing origin: <ftp://foo:80/> against <about:blank>
-PASS Parsing origin: <gopher://foo:70/> against <about:blank>
-PASS Parsing origin: <gopher://foo:443/> against <about:blank>
+FAIL Parsing origin: <gopher://foo:70/> against <about:blank> assert_equals: origin expected "null" but got "gopher://foo"
+FAIL Parsing origin: <gopher://foo:443/> against <about:blank> assert_equals: origin expected "null" but got "gopher://foo:443"
 PASS Parsing origin: <ws://foo:80/> against <about:blank>
 PASS Parsing origin: <ws://foo:81/> against <about:blank>
 PASS Parsing origin: <ws://foo:443/> against <about:blank>
@@ -161,7 +161,7 @@
 PASS Parsing origin: <https:/example.com/> against <about:blank>
 PASS Parsing origin: <madeupscheme:/example.com/> against <about:blank>
 PASS Parsing origin: <ftps:/example.com/> against <about:blank>
-PASS Parsing origin: <gopher:/example.com/> against <about:blank>
+FAIL Parsing origin: <gopher:/example.com/> against <about:blank> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Parsing origin: <ws:/example.com/> against <about:blank>
 PASS Parsing origin: <wss:/example.com/> against <about:blank>
 PASS Parsing origin: <data:/example.com/> against <about:blank>
@@ -172,7 +172,7 @@
 PASS Parsing origin: <https:example.com/> against <about:blank>
 PASS Parsing origin: <madeupscheme:example.com/> against <about:blank>
 PASS Parsing origin: <ftps:example.com/> against <about:blank>
-PASS Parsing origin: <gopher:example.com/> against <about:blank>
+FAIL Parsing origin: <gopher:example.com/> against <about:blank> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Parsing origin: <ws:example.com/> against <about:blank>
 PASS Parsing origin: <wss:example.com/> against <about:blank>
 PASS Parsing origin: <data:example.com/> against <about:blank>
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/url/a-element-xhtml-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/url/a-element-xhtml-expected.txt
index a9c7a84..5bacb56 100644
--- a/third_party/blink/web_tests/platform/mac/external/wpt/url/a-element-xhtml-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/external/wpt/url/a-element-xhtml-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 517 tests; 334 PASS, 183 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 517 tests; 329 PASS, 188 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -85,7 +85,7 @@
 FAIL Parsing: <file://example%/> against <about:blank> assert_equals: failure should set href to input expected "file://example%/" but got "file://example%25/"
 PASS Parsing: <file://[example]/> against <about:blank>
 PASS Parsing: <ftps:/example.com/> against <http://example.org/foo/bar>
-PASS Parsing: <gopher:/example.com/> against <http://example.org/foo/bar>
+FAIL Parsing: <gopher:/example.com/> against <http://example.org/foo/bar> assert_equals: href expected "gopher:/example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <wss:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <data:/example.com/> against <http://example.org/foo/bar>
@@ -96,7 +96,7 @@
 PASS Parsing: <https:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <madeupscheme:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <ftps:example.com/> against <http://example.org/foo/bar>
-PASS Parsing: <gopher:example.com/> against <http://example.org/foo/bar>
+FAIL Parsing: <gopher:example.com/> against <http://example.org/foo/bar> assert_equals: href expected "gopher:example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <wss:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <data:example.com/> against <http://example.org/foo/bar>
@@ -183,7 +183,7 @@
 PASS Parsing: <https://foo:80/> against <about:blank>
 PASS Parsing: <ftp://foo:21/> against <about:blank>
 PASS Parsing: <ftp://foo:80/> against <about:blank>
-PASS Parsing: <gopher://foo:70/> against <about:blank>
+FAIL Parsing: <gopher://foo:70/> against <about:blank> assert_equals: href expected "gopher://foo:70/" but got "gopher://foo/"
 PASS Parsing: <gopher://foo:443/> against <about:blank>
 PASS Parsing: <ws://foo:80/> against <about:blank>
 PASS Parsing: <ws://foo:81/> against <about:blank>
@@ -199,7 +199,7 @@
 PASS Parsing: <madeupscheme:/example.com/> against <about:blank>
 PASS Parsing: <file:/example.com/> against <about:blank>
 PASS Parsing: <ftps:/example.com/> against <about:blank>
-PASS Parsing: <gopher:/example.com/> against <about:blank>
+FAIL Parsing: <gopher:/example.com/> against <about:blank> assert_equals: href expected "gopher:/example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:/example.com/> against <about:blank>
 PASS Parsing: <wss:/example.com/> against <about:blank>
 PASS Parsing: <data:/example.com/> against <about:blank>
@@ -210,7 +210,7 @@
 PASS Parsing: <https:example.com/> against <about:blank>
 PASS Parsing: <madeupscheme:example.com/> against <about:blank>
 PASS Parsing: <ftps:example.com/> against <about:blank>
-PASS Parsing: <gopher:example.com/> against <about:blank>
+FAIL Parsing: <gopher:example.com/> against <about:blank> assert_equals: href expected "gopher:example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:example.com/> against <about:blank>
 PASS Parsing: <wss:example.com/> against <about:blank>
 PASS Parsing: <data:example.com/> against <about:blank>
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/url/url-constructor-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/url/url-constructor-expected.txt
index 1938487b..041bb43 100644
--- a/third_party/blink/web_tests/platform/mac/external/wpt/url/url-constructor-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/external/wpt/url/url-constructor-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 517 tests; 400 PASS, 117 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 517 tests; 395 PASS, 122 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -87,7 +87,7 @@
 PASS Parsing: <file://example%/> against <about:blank>
 PASS Parsing: <file://[example]/> against <about:blank>
 PASS Parsing: <ftps:/example.com/> against <http://example.org/foo/bar>
-PASS Parsing: <gopher:/example.com/> against <http://example.org/foo/bar>
+FAIL Parsing: <gopher:/example.com/> against <http://example.org/foo/bar> assert_equals: href expected "gopher:/example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <wss:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <data:/example.com/> against <http://example.org/foo/bar>
@@ -98,7 +98,7 @@
 PASS Parsing: <https:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <madeupscheme:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <ftps:example.com/> against <http://example.org/foo/bar>
-PASS Parsing: <gopher:example.com/> against <http://example.org/foo/bar>
+FAIL Parsing: <gopher:example.com/> against <http://example.org/foo/bar> assert_equals: href expected "gopher:example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <wss:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <data:example.com/> against <http://example.org/foo/bar>
@@ -185,7 +185,7 @@
 PASS Parsing: <https://foo:80/> against <about:blank>
 PASS Parsing: <ftp://foo:21/> against <about:blank>
 PASS Parsing: <ftp://foo:80/> against <about:blank>
-PASS Parsing: <gopher://foo:70/> against <about:blank>
+FAIL Parsing: <gopher://foo:70/> against <about:blank> assert_equals: href expected "gopher://foo:70/" but got "gopher://foo/"
 PASS Parsing: <gopher://foo:443/> against <about:blank>
 PASS Parsing: <ws://foo:80/> against <about:blank>
 PASS Parsing: <ws://foo:81/> against <about:blank>
@@ -201,7 +201,7 @@
 PASS Parsing: <madeupscheme:/example.com/> against <about:blank>
 PASS Parsing: <file:/example.com/> against <about:blank>
 PASS Parsing: <ftps:/example.com/> against <about:blank>
-PASS Parsing: <gopher:/example.com/> against <about:blank>
+FAIL Parsing: <gopher:/example.com/> against <about:blank> assert_equals: href expected "gopher:/example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:/example.com/> against <about:blank>
 PASS Parsing: <wss:/example.com/> against <about:blank>
 PASS Parsing: <data:/example.com/> against <about:blank>
@@ -212,7 +212,7 @@
 PASS Parsing: <https:example.com/> against <about:blank>
 PASS Parsing: <madeupscheme:example.com/> against <about:blank>
 PASS Parsing: <ftps:example.com/> against <about:blank>
-PASS Parsing: <gopher:example.com/> against <about:blank>
+FAIL Parsing: <gopher:example.com/> against <about:blank> assert_equals: href expected "gopher:example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:example.com/> against <about:blank>
 PASS Parsing: <wss:example.com/> against <about:blank>
 PASS Parsing: <data:example.com/> against <about:blank>
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/url/url-origin-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/url/url-origin-expected.txt
index 72594ff..42a736f 100644
--- a/third_party/blink/web_tests/platform/mac/external/wpt/url/url-origin-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/external/wpt/url/url-origin-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 304 tests; 297 PASS, 7 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 304 tests; 291 PASS, 13 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Origin parsing: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -69,7 +69,7 @@
 PASS Origin parsing: <https:/example.com/> against <http://example.org/foo/bar>
 PASS Origin parsing: <madeupscheme:/example.com/> against <http://example.org/foo/bar>
 PASS Origin parsing: <ftps:/example.com/> against <http://example.org/foo/bar>
-PASS Origin parsing: <gopher:/example.com/> against <http://example.org/foo/bar>
+FAIL Origin parsing: <gopher:/example.com/> against <http://example.org/foo/bar> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Origin parsing: <ws:/example.com/> against <http://example.org/foo/bar>
 PASS Origin parsing: <wss:/example.com/> against <http://example.org/foo/bar>
 PASS Origin parsing: <data:/example.com/> against <http://example.org/foo/bar>
@@ -80,7 +80,7 @@
 PASS Origin parsing: <https:example.com/> against <http://example.org/foo/bar>
 PASS Origin parsing: <madeupscheme:example.com/> against <http://example.org/foo/bar>
 PASS Origin parsing: <ftps:example.com/> against <http://example.org/foo/bar>
-PASS Origin parsing: <gopher:example.com/> against <http://example.org/foo/bar>
+FAIL Origin parsing: <gopher:example.com/> against <http://example.org/foo/bar> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Origin parsing: <ws:example.com/> against <http://example.org/foo/bar>
 PASS Origin parsing: <wss:example.com/> against <http://example.org/foo/bar>
 PASS Origin parsing: <data:example.com/> against <http://example.org/foo/bar>
@@ -146,8 +146,8 @@
 PASS Origin parsing: <https://foo:80/> against <about:blank>
 PASS Origin parsing: <ftp://foo:21/> against <about:blank>
 PASS Origin parsing: <ftp://foo:80/> against <about:blank>
-PASS Origin parsing: <gopher://foo:70/> against <about:blank>
-PASS Origin parsing: <gopher://foo:443/> against <about:blank>
+FAIL Origin parsing: <gopher://foo:70/> against <about:blank> assert_equals: origin expected "null" but got "gopher://foo"
+FAIL Origin parsing: <gopher://foo:443/> against <about:blank> assert_equals: origin expected "null" but got "gopher://foo:443"
 PASS Origin parsing: <ws://foo:80/> against <about:blank>
 PASS Origin parsing: <ws://foo:81/> against <about:blank>
 PASS Origin parsing: <ws://foo:443/> against <about:blank>
@@ -161,7 +161,7 @@
 PASS Origin parsing: <https:/example.com/> against <about:blank>
 PASS Origin parsing: <madeupscheme:/example.com/> against <about:blank>
 PASS Origin parsing: <ftps:/example.com/> against <about:blank>
-PASS Origin parsing: <gopher:/example.com/> against <about:blank>
+FAIL Origin parsing: <gopher:/example.com/> against <about:blank> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Origin parsing: <ws:/example.com/> against <about:blank>
 PASS Origin parsing: <wss:/example.com/> against <about:blank>
 PASS Origin parsing: <data:/example.com/> against <about:blank>
@@ -172,7 +172,7 @@
 PASS Origin parsing: <https:example.com/> against <about:blank>
 PASS Origin parsing: <madeupscheme:example.com/> against <about:blank>
 PASS Origin parsing: <ftps:example.com/> against <about:blank>
-PASS Origin parsing: <gopher:example.com/> against <about:blank>
+FAIL Origin parsing: <gopher:example.com/> against <about:blank> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Origin parsing: <ws:example.com/> against <about:blank>
 PASS Origin parsing: <wss:example.com/> against <about:blank>
 PASS Origin parsing: <data:example.com/> against <about:blank>
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/url/a-element-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/url/a-element-expected.txt
index ac76307..72133cf4 100644
--- a/third_party/blink/web_tests/platform/win/external/wpt/url/a-element-expected.txt
+++ b/third_party/blink/web_tests/platform/win/external/wpt/url/a-element-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 517 tests; 330 PASS, 187 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 517 tests; 325 PASS, 192 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -85,7 +85,7 @@
 FAIL Parsing: <file://example%/> against <about:blank> assert_equals: failure should set href to input expected "file://example%/" but got "file://example%25/"
 PASS Parsing: <file://[example]/> against <about:blank>
 PASS Parsing: <ftps:/example.com/> against <http://example.org/foo/bar>
-PASS Parsing: <gopher:/example.com/> against <http://example.org/foo/bar>
+FAIL Parsing: <gopher:/example.com/> against <http://example.org/foo/bar> assert_equals: href expected "gopher:/example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <wss:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <data:/example.com/> against <http://example.org/foo/bar>
@@ -96,7 +96,7 @@
 PASS Parsing: <https:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <madeupscheme:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <ftps:example.com/> against <http://example.org/foo/bar>
-PASS Parsing: <gopher:example.com/> against <http://example.org/foo/bar>
+FAIL Parsing: <gopher:example.com/> against <http://example.org/foo/bar> assert_equals: href expected "gopher:example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <wss:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <data:example.com/> against <http://example.org/foo/bar>
@@ -183,7 +183,7 @@
 PASS Parsing: <https://foo:80/> against <about:blank>
 PASS Parsing: <ftp://foo:21/> against <about:blank>
 PASS Parsing: <ftp://foo:80/> against <about:blank>
-PASS Parsing: <gopher://foo:70/> against <about:blank>
+FAIL Parsing: <gopher://foo:70/> against <about:blank> assert_equals: href expected "gopher://foo:70/" but got "gopher://foo/"
 PASS Parsing: <gopher://foo:443/> against <about:blank>
 PASS Parsing: <ws://foo:80/> against <about:blank>
 PASS Parsing: <ws://foo:81/> against <about:blank>
@@ -199,7 +199,7 @@
 PASS Parsing: <madeupscheme:/example.com/> against <about:blank>
 FAIL Parsing: <file:/example.com/> against <about:blank> assert_equals: href expected "file:///example.com/" but got "file://example.com/"
 PASS Parsing: <ftps:/example.com/> against <about:blank>
-PASS Parsing: <gopher:/example.com/> against <about:blank>
+FAIL Parsing: <gopher:/example.com/> against <about:blank> assert_equals: href expected "gopher:/example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:/example.com/> against <about:blank>
 PASS Parsing: <wss:/example.com/> against <about:blank>
 PASS Parsing: <data:/example.com/> against <about:blank>
@@ -210,7 +210,7 @@
 PASS Parsing: <https:example.com/> against <about:blank>
 PASS Parsing: <madeupscheme:example.com/> against <about:blank>
 PASS Parsing: <ftps:example.com/> against <about:blank>
-PASS Parsing: <gopher:example.com/> against <about:blank>
+FAIL Parsing: <gopher:example.com/> against <about:blank> assert_equals: href expected "gopher:example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:example.com/> against <about:blank>
 PASS Parsing: <wss:example.com/> against <about:blank>
 PASS Parsing: <data:example.com/> against <about:blank>
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/url/a-element-origin-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/url/a-element-origin-expected.txt
index 1955d9f..6bd21b2 100644
--- a/third_party/blink/web_tests/platform/win/external/wpt/url/a-element-origin-expected.txt
+++ b/third_party/blink/web_tests/platform/win/external/wpt/url/a-element-origin-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 304 tests; 298 PASS, 6 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 304 tests; 292 PASS, 12 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing origin: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -69,7 +69,7 @@
 PASS Parsing origin: <https:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <madeupscheme:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <ftps:/example.com/> against <http://example.org/foo/bar>
-PASS Parsing origin: <gopher:/example.com/> against <http://example.org/foo/bar>
+FAIL Parsing origin: <gopher:/example.com/> against <http://example.org/foo/bar> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Parsing origin: <ws:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <wss:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <data:/example.com/> against <http://example.org/foo/bar>
@@ -80,7 +80,7 @@
 PASS Parsing origin: <https:example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <madeupscheme:example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <ftps:example.com/> against <http://example.org/foo/bar>
-PASS Parsing origin: <gopher:example.com/> against <http://example.org/foo/bar>
+FAIL Parsing origin: <gopher:example.com/> against <http://example.org/foo/bar> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Parsing origin: <ws:example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <wss:example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <data:example.com/> against <http://example.org/foo/bar>
@@ -146,8 +146,8 @@
 PASS Parsing origin: <https://foo:80/> against <about:blank>
 PASS Parsing origin: <ftp://foo:21/> against <about:blank>
 PASS Parsing origin: <ftp://foo:80/> against <about:blank>
-PASS Parsing origin: <gopher://foo:70/> against <about:blank>
-PASS Parsing origin: <gopher://foo:443/> against <about:blank>
+FAIL Parsing origin: <gopher://foo:70/> against <about:blank> assert_equals: origin expected "null" but got "gopher://foo"
+FAIL Parsing origin: <gopher://foo:443/> against <about:blank> assert_equals: origin expected "null" but got "gopher://foo:443"
 PASS Parsing origin: <ws://foo:80/> against <about:blank>
 PASS Parsing origin: <ws://foo:81/> against <about:blank>
 PASS Parsing origin: <ws://foo:443/> against <about:blank>
@@ -161,7 +161,7 @@
 PASS Parsing origin: <https:/example.com/> against <about:blank>
 PASS Parsing origin: <madeupscheme:/example.com/> against <about:blank>
 PASS Parsing origin: <ftps:/example.com/> against <about:blank>
-PASS Parsing origin: <gopher:/example.com/> against <about:blank>
+FAIL Parsing origin: <gopher:/example.com/> against <about:blank> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Parsing origin: <ws:/example.com/> against <about:blank>
 PASS Parsing origin: <wss:/example.com/> against <about:blank>
 PASS Parsing origin: <data:/example.com/> against <about:blank>
@@ -172,7 +172,7 @@
 PASS Parsing origin: <https:example.com/> against <about:blank>
 PASS Parsing origin: <madeupscheme:example.com/> against <about:blank>
 PASS Parsing origin: <ftps:example.com/> against <about:blank>
-PASS Parsing origin: <gopher:example.com/> against <about:blank>
+FAIL Parsing origin: <gopher:example.com/> against <about:blank> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Parsing origin: <ws:example.com/> against <about:blank>
 PASS Parsing origin: <wss:example.com/> against <about:blank>
 PASS Parsing origin: <data:example.com/> against <about:blank>
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/url/a-element-origin-xhtml-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/url/a-element-origin-xhtml-expected.txt
index 1955d9f..6bd21b2 100644
--- a/third_party/blink/web_tests/platform/win/external/wpt/url/a-element-origin-xhtml-expected.txt
+++ b/third_party/blink/web_tests/platform/win/external/wpt/url/a-element-origin-xhtml-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 304 tests; 298 PASS, 6 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 304 tests; 292 PASS, 12 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing origin: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -69,7 +69,7 @@
 PASS Parsing origin: <https:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <madeupscheme:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <ftps:/example.com/> against <http://example.org/foo/bar>
-PASS Parsing origin: <gopher:/example.com/> against <http://example.org/foo/bar>
+FAIL Parsing origin: <gopher:/example.com/> against <http://example.org/foo/bar> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Parsing origin: <ws:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <wss:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <data:/example.com/> against <http://example.org/foo/bar>
@@ -80,7 +80,7 @@
 PASS Parsing origin: <https:example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <madeupscheme:example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <ftps:example.com/> against <http://example.org/foo/bar>
-PASS Parsing origin: <gopher:example.com/> against <http://example.org/foo/bar>
+FAIL Parsing origin: <gopher:example.com/> against <http://example.org/foo/bar> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Parsing origin: <ws:example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <wss:example.com/> against <http://example.org/foo/bar>
 PASS Parsing origin: <data:example.com/> against <http://example.org/foo/bar>
@@ -146,8 +146,8 @@
 PASS Parsing origin: <https://foo:80/> against <about:blank>
 PASS Parsing origin: <ftp://foo:21/> against <about:blank>
 PASS Parsing origin: <ftp://foo:80/> against <about:blank>
-PASS Parsing origin: <gopher://foo:70/> against <about:blank>
-PASS Parsing origin: <gopher://foo:443/> against <about:blank>
+FAIL Parsing origin: <gopher://foo:70/> against <about:blank> assert_equals: origin expected "null" but got "gopher://foo"
+FAIL Parsing origin: <gopher://foo:443/> against <about:blank> assert_equals: origin expected "null" but got "gopher://foo:443"
 PASS Parsing origin: <ws://foo:80/> against <about:blank>
 PASS Parsing origin: <ws://foo:81/> against <about:blank>
 PASS Parsing origin: <ws://foo:443/> against <about:blank>
@@ -161,7 +161,7 @@
 PASS Parsing origin: <https:/example.com/> against <about:blank>
 PASS Parsing origin: <madeupscheme:/example.com/> against <about:blank>
 PASS Parsing origin: <ftps:/example.com/> against <about:blank>
-PASS Parsing origin: <gopher:/example.com/> against <about:blank>
+FAIL Parsing origin: <gopher:/example.com/> against <about:blank> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Parsing origin: <ws:/example.com/> against <about:blank>
 PASS Parsing origin: <wss:/example.com/> against <about:blank>
 PASS Parsing origin: <data:/example.com/> against <about:blank>
@@ -172,7 +172,7 @@
 PASS Parsing origin: <https:example.com/> against <about:blank>
 PASS Parsing origin: <madeupscheme:example.com/> against <about:blank>
 PASS Parsing origin: <ftps:example.com/> against <about:blank>
-PASS Parsing origin: <gopher:example.com/> against <about:blank>
+FAIL Parsing origin: <gopher:example.com/> against <about:blank> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Parsing origin: <ws:example.com/> against <about:blank>
 PASS Parsing origin: <wss:example.com/> against <about:blank>
 PASS Parsing origin: <data:example.com/> against <about:blank>
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/url/a-element-xhtml-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/url/a-element-xhtml-expected.txt
index ac76307..72133cf4 100644
--- a/third_party/blink/web_tests/platform/win/external/wpt/url/a-element-xhtml-expected.txt
+++ b/third_party/blink/web_tests/platform/win/external/wpt/url/a-element-xhtml-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 517 tests; 330 PASS, 187 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 517 tests; 325 PASS, 192 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -85,7 +85,7 @@
 FAIL Parsing: <file://example%/> against <about:blank> assert_equals: failure should set href to input expected "file://example%/" but got "file://example%25/"
 PASS Parsing: <file://[example]/> against <about:blank>
 PASS Parsing: <ftps:/example.com/> against <http://example.org/foo/bar>
-PASS Parsing: <gopher:/example.com/> against <http://example.org/foo/bar>
+FAIL Parsing: <gopher:/example.com/> against <http://example.org/foo/bar> assert_equals: href expected "gopher:/example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <wss:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <data:/example.com/> against <http://example.org/foo/bar>
@@ -96,7 +96,7 @@
 PASS Parsing: <https:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <madeupscheme:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <ftps:example.com/> against <http://example.org/foo/bar>
-PASS Parsing: <gopher:example.com/> against <http://example.org/foo/bar>
+FAIL Parsing: <gopher:example.com/> against <http://example.org/foo/bar> assert_equals: href expected "gopher:example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <wss:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <data:example.com/> against <http://example.org/foo/bar>
@@ -183,7 +183,7 @@
 PASS Parsing: <https://foo:80/> against <about:blank>
 PASS Parsing: <ftp://foo:21/> against <about:blank>
 PASS Parsing: <ftp://foo:80/> against <about:blank>
-PASS Parsing: <gopher://foo:70/> against <about:blank>
+FAIL Parsing: <gopher://foo:70/> against <about:blank> assert_equals: href expected "gopher://foo:70/" but got "gopher://foo/"
 PASS Parsing: <gopher://foo:443/> against <about:blank>
 PASS Parsing: <ws://foo:80/> against <about:blank>
 PASS Parsing: <ws://foo:81/> against <about:blank>
@@ -199,7 +199,7 @@
 PASS Parsing: <madeupscheme:/example.com/> against <about:blank>
 FAIL Parsing: <file:/example.com/> against <about:blank> assert_equals: href expected "file:///example.com/" but got "file://example.com/"
 PASS Parsing: <ftps:/example.com/> against <about:blank>
-PASS Parsing: <gopher:/example.com/> against <about:blank>
+FAIL Parsing: <gopher:/example.com/> against <about:blank> assert_equals: href expected "gopher:/example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:/example.com/> against <about:blank>
 PASS Parsing: <wss:/example.com/> against <about:blank>
 PASS Parsing: <data:/example.com/> against <about:blank>
@@ -210,7 +210,7 @@
 PASS Parsing: <https:example.com/> against <about:blank>
 PASS Parsing: <madeupscheme:example.com/> against <about:blank>
 PASS Parsing: <ftps:example.com/> against <about:blank>
-PASS Parsing: <gopher:example.com/> against <about:blank>
+FAIL Parsing: <gopher:example.com/> against <about:blank> assert_equals: href expected "gopher:example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:example.com/> against <about:blank>
 PASS Parsing: <wss:example.com/> against <about:blank>
 PASS Parsing: <data:example.com/> against <about:blank>
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/url/url-constructor-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/url/url-constructor-expected.txt
index 2aa72cb..9e581df 100644
--- a/third_party/blink/web_tests/platform/win/external/wpt/url/url-constructor-expected.txt
+++ b/third_party/blink/web_tests/platform/win/external/wpt/url/url-constructor-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 517 tests; 394 PASS, 123 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 517 tests; 389 PASS, 128 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -87,7 +87,7 @@
 PASS Parsing: <file://example%/> against <about:blank>
 PASS Parsing: <file://[example]/> against <about:blank>
 PASS Parsing: <ftps:/example.com/> against <http://example.org/foo/bar>
-PASS Parsing: <gopher:/example.com/> against <http://example.org/foo/bar>
+FAIL Parsing: <gopher:/example.com/> against <http://example.org/foo/bar> assert_equals: href expected "gopher:/example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <wss:/example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <data:/example.com/> against <http://example.org/foo/bar>
@@ -98,7 +98,7 @@
 PASS Parsing: <https:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <madeupscheme:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <ftps:example.com/> against <http://example.org/foo/bar>
-PASS Parsing: <gopher:example.com/> against <http://example.org/foo/bar>
+FAIL Parsing: <gopher:example.com/> against <http://example.org/foo/bar> assert_equals: href expected "gopher:example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <wss:example.com/> against <http://example.org/foo/bar>
 PASS Parsing: <data:example.com/> against <http://example.org/foo/bar>
@@ -185,7 +185,7 @@
 PASS Parsing: <https://foo:80/> against <about:blank>
 PASS Parsing: <ftp://foo:21/> against <about:blank>
 PASS Parsing: <ftp://foo:80/> against <about:blank>
-PASS Parsing: <gopher://foo:70/> against <about:blank>
+FAIL Parsing: <gopher://foo:70/> against <about:blank> assert_equals: href expected "gopher://foo:70/" but got "gopher://foo/"
 PASS Parsing: <gopher://foo:443/> against <about:blank>
 PASS Parsing: <ws://foo:80/> against <about:blank>
 PASS Parsing: <ws://foo:81/> against <about:blank>
@@ -201,7 +201,7 @@
 PASS Parsing: <madeupscheme:/example.com/> against <about:blank>
 FAIL Parsing: <file:/example.com/> against <about:blank> assert_equals: href expected "file:///example.com/" but got "file://example.com/"
 PASS Parsing: <ftps:/example.com/> against <about:blank>
-PASS Parsing: <gopher:/example.com/> against <about:blank>
+FAIL Parsing: <gopher:/example.com/> against <about:blank> assert_equals: href expected "gopher:/example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:/example.com/> against <about:blank>
 PASS Parsing: <wss:/example.com/> against <about:blank>
 PASS Parsing: <data:/example.com/> against <about:blank>
@@ -212,7 +212,7 @@
 PASS Parsing: <https:example.com/> against <about:blank>
 PASS Parsing: <madeupscheme:example.com/> against <about:blank>
 PASS Parsing: <ftps:example.com/> against <about:blank>
-PASS Parsing: <gopher:example.com/> against <about:blank>
+FAIL Parsing: <gopher:example.com/> against <about:blank> assert_equals: href expected "gopher:example.com/" but got "gopher://example.com/"
 PASS Parsing: <ws:example.com/> against <about:blank>
 PASS Parsing: <wss:example.com/> against <about:blank>
 PASS Parsing: <data:example.com/> against <about:blank>
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/url/url-origin-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/url/url-origin-expected.txt
index 616310c9..4d8f835 100644
--- a/third_party/blink/web_tests/platform/win/external/wpt/url/url-origin-expected.txt
+++ b/third_party/blink/web_tests/platform/win/external/wpt/url/url-origin-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 304 tests; 295 PASS, 9 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 304 tests; 289 PASS, 15 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Origin parsing: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -69,7 +69,7 @@
 PASS Origin parsing: <https:/example.com/> against <http://example.org/foo/bar>
 PASS Origin parsing: <madeupscheme:/example.com/> against <http://example.org/foo/bar>
 PASS Origin parsing: <ftps:/example.com/> against <http://example.org/foo/bar>
-PASS Origin parsing: <gopher:/example.com/> against <http://example.org/foo/bar>
+FAIL Origin parsing: <gopher:/example.com/> against <http://example.org/foo/bar> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Origin parsing: <ws:/example.com/> against <http://example.org/foo/bar>
 PASS Origin parsing: <wss:/example.com/> against <http://example.org/foo/bar>
 PASS Origin parsing: <data:/example.com/> against <http://example.org/foo/bar>
@@ -80,7 +80,7 @@
 PASS Origin parsing: <https:example.com/> against <http://example.org/foo/bar>
 PASS Origin parsing: <madeupscheme:example.com/> against <http://example.org/foo/bar>
 PASS Origin parsing: <ftps:example.com/> against <http://example.org/foo/bar>
-PASS Origin parsing: <gopher:example.com/> against <http://example.org/foo/bar>
+FAIL Origin parsing: <gopher:example.com/> against <http://example.org/foo/bar> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Origin parsing: <ws:example.com/> against <http://example.org/foo/bar>
 PASS Origin parsing: <wss:example.com/> against <http://example.org/foo/bar>
 PASS Origin parsing: <data:example.com/> against <http://example.org/foo/bar>
@@ -146,8 +146,8 @@
 PASS Origin parsing: <https://foo:80/> against <about:blank>
 PASS Origin parsing: <ftp://foo:21/> against <about:blank>
 PASS Origin parsing: <ftp://foo:80/> against <about:blank>
-PASS Origin parsing: <gopher://foo:70/> against <about:blank>
-PASS Origin parsing: <gopher://foo:443/> against <about:blank>
+FAIL Origin parsing: <gopher://foo:70/> against <about:blank> assert_equals: origin expected "null" but got "gopher://foo"
+FAIL Origin parsing: <gopher://foo:443/> against <about:blank> assert_equals: origin expected "null" but got "gopher://foo:443"
 PASS Origin parsing: <ws://foo:80/> against <about:blank>
 PASS Origin parsing: <ws://foo:81/> against <about:blank>
 PASS Origin parsing: <ws://foo:443/> against <about:blank>
@@ -161,7 +161,7 @@
 PASS Origin parsing: <https:/example.com/> against <about:blank>
 PASS Origin parsing: <madeupscheme:/example.com/> against <about:blank>
 PASS Origin parsing: <ftps:/example.com/> against <about:blank>
-PASS Origin parsing: <gopher:/example.com/> against <about:blank>
+FAIL Origin parsing: <gopher:/example.com/> against <about:blank> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Origin parsing: <ws:/example.com/> against <about:blank>
 PASS Origin parsing: <wss:/example.com/> against <about:blank>
 PASS Origin parsing: <data:/example.com/> against <about:blank>
@@ -172,7 +172,7 @@
 PASS Origin parsing: <https:example.com/> against <about:blank>
 PASS Origin parsing: <madeupscheme:example.com/> against <about:blank>
 PASS Origin parsing: <ftps:example.com/> against <about:blank>
-PASS Origin parsing: <gopher:example.com/> against <about:blank>
+FAIL Origin parsing: <gopher:example.com/> against <about:blank> assert_equals: origin expected "null" but got "gopher://example.com"
 PASS Origin parsing: <ws:example.com/> against <about:blank>
 PASS Origin parsing: <wss:example.com/> against <about:blank>
 PASS Origin parsing: <data:example.com/> against <about:blank>
diff --git a/tools/code_coverage/OWNERS b/tools/code_coverage/OWNERS
index 9d226754..c67e1ea 100644
--- a/tools/code_coverage/OWNERS
+++ b/tools/code_coverage/OWNERS
@@ -1,5 +1,7 @@
 liaoyuke@chromium.org
+robertocn@chromium.org
+nodir@chromium.org
 mmoroz@chromium.org
 inferno@chromium.org
-# COMPONENT: Tools>CodeCoverage
+# COMPONENT: Infra>Test>CodeCoverage
 # TEAM: code-coverage@chromium.org
diff --git a/tools/code_coverage/update_clang_coverage_tools.py b/tools/code_coverage/update_clang_coverage_tools.py
index 34257b87..d98988cd 100755
--- a/tools/code_coverage/update_clang_coverage_tools.py
+++ b/tools/code_coverage/update_clang_coverage_tools.py
@@ -48,15 +48,15 @@
 
       return package_version
 
-  cov_path = os.path.join(clang_update.LLVM_BUILD_DIR, 'llvm-cov')
-  profdata_path = os.path.join(clang_update.LLVM_BUILD_DIR, 'llvm-profdata')
+  cov_path = os.path.join(clang_update.LLVM_BUILD_DIR, 'bin', 'llvm-cov')
+  profdata_path = os.path.join(
+      clang_update.LLVM_BUILD_DIR, 'bin', 'llvm-profdata')
 
   host_platform = coverage_utils.GetHostPlatform()
   clang_revision = _GetRevisionFromStampFile(clang_update.STAMP_FILE)
   coverage_revision_stamp_file = os.path.join(
       os.path.dirname(clang_update.STAMP_FILE), 'cr_coverage_revision')
   coverage_revision = _GetRevisionFromStampFile(coverage_revision_stamp_file)
-
   has_coverage_tools = (
       os.path.exists(cov_path) and os.path.exists(profdata_path))
 
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index fb662fe2..a5a74bf 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -833,6 +833,7 @@
 
       'linux_layout_tests_composite_after_paint': 'release_trybot',
       'linux_layout_tests_layout_ng_disabled': 'release_trybot',
+      'linux-layout-tests-fragment-item': 'release_trybot',
       'linux_mojo': 'release_trybot',
       'linux_mojo_chromeos': 'chromeos_with_codecs_release_trybot',
       'linux_optional_gpu_tests_rel': 'gpu_fyi_tests_release_trybot',
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index e43376e7..7444ef6 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -22077,6 +22077,28 @@
   <description>Please enter the description of this user action.</description>
 </action>
 
+<action name="TasksSurface.FakeBox.LongPressed">
+  <owner>gogerald@chromium.org</owner>
+  <description>
+    Recorded when the user long pressed the fake box on the tasks surface.
+  </description>
+</action>
+
+<action name="TasksSurface.FakeBox.Tapped">
+  <owner>gogerald@chromium.org</owner>
+  <description>
+    Recorded when the user taps the fake box on the tasks surface.
+  </description>
+</action>
+
+<action name="TasksSurface.FakeBox.VoiceSearch">
+  <owner>gogerald@chromium.org</owner>
+  <description>
+    Recorded when the user taps the voice search button in the fake box on the
+    tasks surface.
+  </description>
+</action>
+
 <action name="TerminalSystemAppMenuButtonButton_Clicked">
   <owner>alancutter@chromium.org</owner>
   <owner>calamity@chromium.org</owner>
@@ -23353,6 +23375,7 @@
   <suffix name="GlobalMediaControls" label="For GlobalMediaControls feature."/>
   <suffix name="HomePageButton" label="For HomePageButton feature."/>
   <suffix name="HomepageTile" label="For HomepageTile feature."/>
+  <suffix name="IdentityDisc" label="For IdentityDisc feature."/>
   <suffix name="IncognitoWindow" label="For IncognitoWindow feature."/>
   <suffix name="LongPressToolbarTip" label="For LongPressToolbar feature."/>
   <suffix name="MediaDownload" label="For MediaDownload feature."/>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index d706874..daa8acd4 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -3771,6 +3771,12 @@
   <int value="4" label="NotShown, invalid legal message"/>
 </enum>
 
+<enum name="AutofillCreditCardPreflightCallEvent">
+  <int value="0" label="Preflight returned first"/>
+  <int value="1" label="Card chosen first"/>
+  <int value="2" label="Preflight call ignored"/>
+</enum>
+
 <enum name="AutofillDeveloperEngagement">
   <int value="0" label="Fillable form parsed without type hints"/>
   <int value="1" label="Fillable form parsed with type hints"/>
@@ -18408,12 +18414,15 @@
   <int value="624" label="LegacySameSiteCookieBehaviorEnabledForDomainList"/>
   <int value="625" label="PrintJobHistoryExpirationPeriod"/>
   <int value="626" label="TLS13HardeningForLocalAnchorsEnabled"/>
-  <int value="627" label="AudioSandboxEnabled"/>
+  <int value="627" label="ForceDisableAudioSandbox"/>
   <int value="628" label="DeviceLoginScreenScreenMagnifierType"/>
   <int value="629" label="CorsMitigationList"/>
   <int value="630" label="CorsLegacyModeEnabled"/>
   <int value="631" label="ExternalPrintServersWhitelist"/>
   <int value="632" label="ExternalProtocolDialogShowAlwaysOpenCheckbox"/>
+  <int value="633" label="DefaultInsecureContentSetting"/>
+  <int value="634" label="InsecureContentAllowedForUrls"/>
+  <int value="635" label="InsecureContentBlockedForUrls"/>
 </enum>
 
 <enum name="EnterprisePolicyInvalidations">
@@ -54999,6 +55008,12 @@
   <int value="9" label="Rollback: SBER2 absent so SBER1 must be cleared"/>
 </enum>
 
+<enum name="ScreenRotationAcceleratorAction">
+  <int value="0" label="CancelledDialog"/>
+  <int value="1" label="AcceptedDialog"/>
+  <int value="2" label="AlreadyAcceptedDialog"/>
+</enum>
+
 <enum name="ScriptSchedulingType">
   <int value="0" label="NotSet"/>
   <int value="1" label="Defer"/>
@@ -61015,6 +61030,12 @@
       label="Bubbling Root-scroller, scrollable document, handled application"/>
 </enum>
 
+<enum name="TouchToFill.UserAction">
+  <int value="0" label="Selected Credential"/>
+  <int value="1" label="Dismissed"/>
+  <int value="2" label="Selected Manage Passwords"/>
+</enum>
+
 <enum name="TPMFirmwareUpdateResult">
   <int value="0" label="Success"/>
   <int value="1" label="Success after retry"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 1acf5241..840db8b 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -7271,6 +7271,16 @@
   </summary>
 </histogram>
 
+<histogram name="Ash.Accelerators.Rotation.Usage"
+    enum="ScreenRotationAcceleratorAction" expires_after="M81">
+  <owner>baileyberro@chromium.org</owner>
+  <summary>
+    Captures the result of a user using the rotation accelerator -
+    Ctrl+Shift+Refresh. This histogram shows how frequently users accidentally
+    hit the key combination.
+  </summary>
+</histogram>
+
 <histogram name="Ash.ActiveTouchPoints" units="units"
     expires_after="2017-03-03">
   <obsolete>
@@ -10751,6 +10761,22 @@
   </summary>
 </histogram>
 
+<histogram name="Autofill.BetterAuth.UserPerceivedLatencyOnCardSelection"
+    enum="AutofillCreditCardPreflightCallEvent" expires_after="2020-12-15">
+  <owner>jsaul@google.com</owner>
+  <owner>manasverma@google.com</owner>
+  <owner>autofill-auth-team@google.com</owner>
+<!-- Name completed by histogram_suffixes name="AutofillFidoAuthenticationEnabledState" -->
+
+  <summary>
+    The GetDetailsForGetRealPan call is made when card suggestions are shown.
+    This metric tracks whether the response is received before or after a card
+    is chosen by the user. For an opted-in user, a late response would imply
+    perceived latency. For an opted-out user, a late response would imply that
+    opt-in may not have been offered.
+  </summary>
+</histogram>
+
 <histogram name="Autofill.CanLogUKM" enum="BooleanEnabled" expires_after="M78">
   <owner>dlkumar@google.com</owner>
   <owner>chrome-autofill@google.com</owner>
@@ -98810,6 +98836,15 @@
   </summary>
 </histogram>
 
+<histogram name="PageLoad.Clients.SubresourceLoading.MainFrameHadCookies"
+    enum="Boolean" expires_after="M90">
+  <owner>robertogden@chromium.org</owner>
+  <owner>tbansal@chromium.org</owner>
+  <summary>
+    Whether or not any main frame request in the redirect chain had cookies.
+  </summary>
+</histogram>
+
 <histogram name="PageLoad.Clients.ThirdParty.Origins.CookieRead" units="Count"
     expires_after="2021-07-01">
   <owner>jkarlin@chromium.org</owner>
@@ -104264,6 +104299,15 @@
   </summary>
 </histogram>
 
+<histogram name="PasswordManager.TouchToFill.UserAction"
+    enum="TouchToFill.UserAction" expires_after="2020-09-30">
+  <owner>jdoerrie@chromium.org</owner>
+  <owner>fhorschig@chromium.org</owner>
+  <summary>
+    The action a user took when interacting with the Touch To Fill sheet.
+  </summary>
+</histogram>
+
 <histogram name="PasswordManager.UIDismissalReason"
     enum="PasswordManagerUIDismissalReason" expires_after="2020-03-22">
   <owner>vasilii@chromium.org</owner>
@@ -165738,6 +165782,13 @@
   <affected-histogram name="Autofill.FormEvents.CreditCard"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="AutofillFidoAuthenticationEnabledState" separator=".">
+  <suffix name="OptedIn" label="FIDO authentication enabled"/>
+  <suffix name="OptedOut" label="FIDO authentication disabled"/>
+  <affected-histogram
+      name="Autofill.BetterAuth.UserPerceivedLatencyOnCardSelection"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="AutofillFieldPredictionSource" separator=".">
   <suffix name="Heuristic"
       label="Field type predictions using local heuristics."/>
@@ -170852,6 +170903,7 @@
       This feature was deprecated in M79
     </obsolete>
   </suffix>
+  <suffix name="IPH_IdentityDisc" label="In product help for Identity Disc"/>
   <suffix name="IPH_IncognitoWindow" label="In product help incognito window."/>
   <suffix name="IPH_KeyboardAccessoryAddressFilling"
       label="In-product help for address autofill suggestions."/>
diff --git a/tools/perf/core/minidump_unittest.py b/tools/perf/core/minidump_unittest.py
index 045245c..6db77341 100644
--- a/tools/perf/core/minidump_unittest.py
+++ b/tools/perf/core/minidump_unittest.py
@@ -19,7 +19,9 @@
   @decorators.Isolated
   # Android is currently hard coded to return None for minidump paths.
   # Flakes on chromeos: crbug.com/1014754
-  @decorators.Disabled('android', 'chromeos')
+  # Minidump symbolization doesn't work in ChromeOS local mode if the rootfs is
+  # still read-only, so skip the test in that case.
+  @decorators.Disabled('android', 'chromeos', 'chromeos-local')
   def testSymbolizeMinidump(self):
     # Wait for the browser to restart fully before crashing
     self._LoadPageThenWait('var sam = "car";', 'sam')
@@ -93,7 +95,9 @@
 
   @decorators.Isolated
   # Flakes on chromeos: crbug.com/1014754
-  @decorators.Disabled('android', 'chromeos')
+  # Minidump symbolization doesn't work in ChromeOS local mode if the rootfs is
+  # still read-only, so skip the test in that case.
+  @decorators.Disabled('android', 'chromeos', 'chromeos-local')
   def testMultipleCrashMinidumps(self):
     # Wait for the browser to restart fully before crashing
     self._LoadPageThenWait('var cat = "dog";', 'cat')
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index 9abc10c..cf9b138 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -1,7 +1,7 @@
 # Test Expectation file for telemetry tests.
 # Instructions of how to use this file:
 # https://chromium.googlesource.com/chromium/src/+/master/docs/speed/bot_health_sheriffing/how_to_disable_a_story.md
-# tags: [ android chromeos linux mac mac-10.11 mac-10.12 win win10 win7 sierra highsierra
+# tags: [ android chromeos chromeos-local chromeos-remote linux mac mac-10.11 mac-10.12 win win10 win7 sierra highsierra
 #         android-marshmallow android-lollipop android-nougat android-oreo android-pie android-10
 #         android-kitkat ubuntu ]
 # tags: [ android-go android-low-end android-nexus-5 android-nexus-5x android-nexus-6
diff --git a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc
index bcff2a5d..af42c6a8 100644
--- a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc
@@ -1015,12 +1015,16 @@
   // Only normalize non-degenerate ranges.
   if (*start_ != *end_) {
     AXPositionInstance normalized_start = start_->AsPositionBeforeCharacter();
-    AXPositionInstance normalized_end = end_->AsPositionAfterCharacter();
-    DCHECK_EQ(*start_, *normalized_start);
-    DCHECK_EQ(*end_, *normalized_end);
+    if (!normalized_start->IsNullPosition()) {
+      DCHECK_EQ(*start_, *normalized_start);
+      start_ = std::move(normalized_start);
+    }
 
-    start_ = std::move(normalized_start);
-    end_ = std::move(normalized_end);
+    AXPositionInstance normalized_end = end_->AsPositionAfterCharacter();
+    if (!normalized_end->IsNullPosition()) {
+      DCHECK_EQ(*end_, *normalized_end);
+      end_ = std::move(normalized_end);
+    }
   }
 }
 
diff --git a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
index e3eca56c..80d591f 100644
--- a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
@@ -196,6 +196,10 @@
     return text_range->owner_;
   }
 
+  void NormalizeTextRange(AXPlatformNodeTextRangeProviderWin* text_range) {
+    text_range->NormalizeTextRange();
+  }
+
   void GetTextRangeProviderFromTextNode(
       ComPtr<ITextRangeProvider>& text_range_provider,
       ui::AXNode* text_node) {
@@ -4501,4 +4505,118 @@
       /*expected_count*/ 12);
 }
 
+TEST_F(AXPlatformNodeTextRangeProviderTest,
+       TestNormalizeTextRangePastEndOfDocument) {
+  ui::AXTreeUpdate initial_state;
+  ui::AXTreeID tree_id = ui::AXTreeID::CreateNewAXTreeID();
+  initial_state.tree_data.tree_id = tree_id;
+  initial_state.has_tree_data = true;
+  initial_state.root_id = 1;
+  initial_state.nodes.resize(3);
+  initial_state.nodes[0].id = 1;
+  initial_state.nodes[0].child_ids = {2};
+  initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea;
+  initial_state.nodes[1].id = 2;
+  initial_state.nodes[1].child_ids = {3};
+  initial_state.nodes[1].role = ax::mojom::Role::kStaticText;
+  initial_state.nodes[1].SetName("aaa");
+  initial_state.nodes[2].id = 3;
+  initial_state.nodes[2].role = ax::mojom::Role::kInlineTextBox;
+  initial_state.nodes[2].SetName("aaa");
+
+  Init(initial_state);
+  AXNodePosition::SetTree(tree_.get());
+
+  ComPtr<ITextRangeProvider> text_range_provider;
+  GetTextRangeProviderFromTextNode(text_range_provider,
+                                   GetNodeFromTree(tree_id, 3));
+
+  EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"aaa");
+  EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
+      text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Character,
+      /*count*/ 2,
+      /*expected_text*/ L"a",
+      /*expected_count*/ 2);
+
+  ComPtr<AXPlatformNodeTextRangeProviderWin> text_range_provider_win;
+  text_range_provider->QueryInterface(IID_PPV_ARGS(&text_range_provider_win));
+
+  const AXNodePosition::AXPositionInstance start_after_move =
+      GetStart(text_range_provider_win.Get())->Clone();
+  const AXNodePosition::AXPositionInstance end_after_move =
+      GetEnd(text_range_provider_win.Get())->Clone();
+  EXPECT_LT(*start_after_move, *end_after_move);
+
+  AXTreeUpdate update;
+  update.nodes.resize(2);
+  update.nodes[0] = initial_state.nodes[1];
+  update.nodes[0].SetName("aa");
+  update.nodes[1] = initial_state.nodes[2];
+  update.nodes[1].SetName("aa");
+  ASSERT_TRUE(tree_->Unserialize(update));
+
+  NormalizeTextRange(text_range_provider_win.Get());
+  EXPECT_EQ(*start_after_move, *GetStart(text_range_provider_win.Get()));
+  EXPECT_EQ(*end_after_move, *GetEnd(text_range_provider_win.Get()));
+}
+
+TEST_F(AXPlatformNodeTextRangeProviderTest,
+       TestNormalizeTextRangePastEndOfDocumentWithIgnoredNodes) {
+  ui::AXTreeUpdate initial_state;
+  ui::AXTreeID tree_id = ui::AXTreeID::CreateNewAXTreeID();
+  initial_state.tree_data.tree_id = tree_id;
+  initial_state.has_tree_data = true;
+  initial_state.root_id = 1;
+  initial_state.nodes.resize(4);
+  initial_state.nodes[0].id = 1;
+  initial_state.nodes[0].child_ids = {2};
+  initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea;
+  initial_state.nodes[1].id = 2;
+  initial_state.nodes[1].child_ids = {3, 4};
+  initial_state.nodes[1].role = ax::mojom::Role::kStaticText;
+  initial_state.nodes[1].SetName("aaa");
+  initial_state.nodes[2].id = 3;
+  initial_state.nodes[2].role = ax::mojom::Role::kInlineTextBox;
+  initial_state.nodes[2].SetName("aaa");
+  initial_state.nodes[3].id = 4;
+  initial_state.nodes[3].role = ax::mojom::Role::kInlineTextBox;
+  initial_state.nodes[3].AddState(ax::mojom::State::kIgnored);
+  initial_state.nodes[3].SetName("ignored");
+
+  Init(initial_state);
+  AXNodePosition::SetTree(tree_.get());
+
+  ComPtr<ITextRangeProvider> text_range_provider;
+  GetTextRangeProviderFromTextNode(text_range_provider,
+                                   GetNodeFromTree(tree_id, 3));
+
+  EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"aaa");
+  EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
+      text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Character,
+      /*count*/ 2,
+      /*expected_text*/ L"a",
+      /*expected_count*/ 2);
+
+  ComPtr<AXPlatformNodeTextRangeProviderWin> text_range_provider_win;
+  text_range_provider->QueryInterface(IID_PPV_ARGS(&text_range_provider_win));
+
+  const AXNodePosition::AXPositionInstance start_after_move =
+      GetStart(text_range_provider_win.Get())->Clone();
+  const AXNodePosition::AXPositionInstance end_after_move =
+      GetEnd(text_range_provider_win.Get())->Clone();
+  EXPECT_LT(*start_after_move, *end_after_move);
+
+  AXTreeUpdate update;
+  update.nodes.resize(2);
+  update.nodes[0] = initial_state.nodes[1];
+  update.nodes[0].SetName("aa");
+  update.nodes[1] = initial_state.nodes[2];
+  update.nodes[1].SetName("aa");
+  ASSERT_TRUE(tree_->Unserialize(update));
+
+  NormalizeTextRange(text_range_provider_win.Get());
+  EXPECT_EQ(*start_after_move, *GetStart(text_range_provider_win.Get()));
+  EXPECT_EQ(*end_after_move, *GetEnd(text_range_provider_win.Get()));
+}
+
 }  // namespace ui
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn
index 5cb540dc..bf5f650 100644
--- a/ui/base/BUILD.gn
+++ b/ui/base/BUILD.gn
@@ -4,6 +4,7 @@
 
 import("//build/buildflag_header.gni")
 import("//build/config/compiler/compiler.gni")
+import("//build/config/dcheck_always_on.gni")
 import("//build/config/jumbo.gni")
 import("//build/config/linux/pangocairo/pangocairo.gni")
 import("//build/config/sanitizers/sanitizers.gni")
@@ -424,6 +425,10 @@
     "//url",
   ]
 
+  if (is_debug || dcheck_always_on) {
+    deps += [ "//third_party/re2" ]
+  }
+
   if (!is_ios) {
     # iOS does not use Chromium-specific code for event handling.
     public_deps += [
diff --git a/ui/base/DEPS b/ui/base/DEPS
index 4639d9d5..4492764 100644
--- a/ui/base/DEPS
+++ b/ui/base/DEPS
@@ -2,6 +2,7 @@
   "+net",
   "+skia/ext",
   "+third_party/brotli",
+  "+third_party/re2",
   "+third_party/skia",
   "+third_party/zlib",
   "+ui/base/ui_base_jni_headers",
diff --git a/ui/base/template_expressions.cc b/ui/base/template_expressions.cc
index 8adaa61d..3e02c4c0 100644
--- a/ui/base/template_expressions.cc
+++ b/ui/base/template_expressions.cc
@@ -12,6 +12,10 @@
 #include "base/values.h"
 #include "net/base/escape.h"
 
+#if DCHECK_IS_ON()
+#include "third_party/re2/src/re2/re2.h"  // nogncheck
+#endif
+
 namespace {
 const char kLeader[] = "$i18n";
 const size_t kLeaderSize = base::size(kLeader) - 1;
@@ -141,6 +145,19 @@
   return true;
 }
 
+#if DCHECK_IS_ON()
+// Checks whether the replacement has an unsubstituted placeholder, e.g. "$1".
+bool HasUnexpectedPlaceholder(const std::string& key,
+                              const std::string& replacement) {
+  // TODO(crbug.com/988031): Fix display aria labels.
+#if defined(OS_CHROMEOS)
+  if (key == "displayResolutionText")
+    return false;
+#endif
+  return re2::RE2::PartialMatch(replacement, re2::RE2(R"(\$\d)"));
+}
+#endif  // DCHECK_IS_ON()
+
 bool ReplaceTemplateExpressionsInternal(
     base::StringPiece source,
     const ui::TemplateReplacements& replacements,
@@ -205,6 +222,15 @@
       CHECK(false) << "Unknown context " << context;
     }
 
+#if DCHECK_IS_ON()
+    // Replacements in Polymer WebUI may invoke JavaScript to replace string
+    // placeholders. In other contexts, placeholders should already be replaced.
+    if (context != "Polymer") {
+      DCHECK(!HasUnexpectedPlaceholder(key, replacement))
+          << "Dangling placeholder found in " << key;
+    }
+#endif
+
     formatted->append(replacement);
 
     current_pos = key_end + sizeof(kKeyClose);
diff --git a/ui/login/account_picker/chromeos_user_pod_template.html b/ui/login/account_picker/chromeos_user_pod_template.html
index 79c73e8..2ca9526a 100644
--- a/ui/login/account_picker/chromeos_user_pod_template.html
+++ b/ui/login/account_picker/chromeos_user_pod_template.html
@@ -153,9 +153,7 @@
             <div class="action-box-remove-legacy-supervised-user-warning-text">
               $i18n{removeLegacySupervisedUserWarningText}
             </div>
-            <div class="action-box-remove-non-owner-user-warning-text">
-              $i18n{removeNonOwnerUserWarningText}
-            </div>
+            <div class="action-box-remove-non-owner-user-warning-text"></div>
             <!-- cr-button is imported inside user_manager.html -->
             <cr-button class="remove-warning-button action-button" noink>
               $i18n{removeUserWarningButtonTitle}
diff --git a/ui/login/account_picker/user_pod_template.html b/ui/login/account_picker/user_pod_template.html
index fa8c85a..b116941 100644
--- a/ui/login/account_picker/user_pod_template.html
+++ b/ui/login/account_picker/user_pod_template.html
@@ -143,9 +143,7 @@
       <div class="action-box-remove-legacy-supervised-user-warning-text">
         $i18n{removeLegacySupervisedUserWarningText}
       </div>
-      <div class="action-box-remove-non-owner-user-warning-text">
-        $i18n{removeNonOwnerUserWarningText}
-      </div>
+      <div class="action-box-remove-non-owner-user-warning-text"></div>
       <!-- cr-button is imported inside user_manager.html -->
       <cr-button class="remove-warning-button action-button">
         $i18n{removeUserWarningButtonTitle}
diff --git a/ui/login/display_manager.js b/ui/login/display_manager.js
index 4a59ff6..c58de8f 100644
--- a/ui/login/display_manager.js
+++ b/ui/login/display_manager.js
@@ -319,6 +319,14 @@
     },
 
     /**
+     * Sets the hint for calculating OOBE dialog inner padding.
+     * @param {OobeTypes.DialogPaddingMode} mode.
+     */
+    setDialogPaddingMode: function(mode) {
+      document.documentElement.setAttribute('dialog-padding', mode);
+    },
+
+    /**
      * Toggles background of main body between transparency and solid.
      * @param {boolean} solid Whether to show a solid background.
      */
diff --git a/ui/login/oobe.css b/ui/login/oobe.css
index de526a2..ca88408 100644
--- a/ui/login/oobe.css
+++ b/ui/login/oobe.css
@@ -56,6 +56,7 @@
   --oobe-dialog-side-margin: 0px;
 }
 
+
 @media screen and (max-width: 864px), (max-height: 736px) {
   html[screen=oobe] {
     --oobe-dialog-footer-height: 80px;
@@ -64,6 +65,12 @@
   }
 }
 
+html[screen=gaia-signin][dialog-padding=narrow] {
+  --oobe-dialog-footer-height: 80px;
+  --oobe-dialog-footer-padding: 24px;
+  --oobe-dialog-content-padding: 32px;
+}
+
 body.solid {
   background-color: white;
 }
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_config.html b/ui/webui/resources/cr_components/chromeos/network/network_config.html
index f0adbb8..d3fd89d 100644
--- a/ui/webui/resources/cr_components/chromeos/network/network_config.html
+++ b/ui/webui/resources/cr_components/chromeos/network/network_config.html
@@ -45,7 +45,7 @@
       <template is="dom-if" if="[[securityIsVisible_(mojoType_)]]" restamp>
         <network-config-select id="security"
             label="[[i18n('OncWiFi-Security')]]"
-            value="{{securityType}}" key="security"
+            value="{{securityType_}}" key="security"
             disabled="[[!securityIsEnabled_(guid, mojoType_)]]"
             items="[[getSecurityItems_(mojoType_)]]"
             onc-prefix="WiFi.Security"
@@ -55,7 +55,7 @@
 
       <!-- Passphrase (WiFi) -->
       <template is="dom-if" restamp
-          if="[[configRequiresPassphrase_(mojoType_, securityType)]]">
+          if="[[configRequiresPassphrase_(mojoType_, securityType_)]]">
         <network-password-input id="wifi-passphrase"
             label="[[i18n('OncWiFi-Passphrase')]]"
             value="{{configProperties_.typeConfig.wifi.passphrase}}"
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_config.js b/ui/webui/resources/cr_components/chromeos/network/network_config.js
index 31b1e58..ba1b47b 100644
--- a/ui/webui/resources/cr_components/chromeos/network/network_config.js
+++ b/ui/webui/resources/cr_components/chromeos/network/network_config.js
@@ -109,8 +109,7 @@
     propertiesSent_: Boolean,
 
     /**
-     * The configuration properties for the network. |configProperties_.type|
-     * will always be defined as the network type being configured.
+     * The configuration properties for the network.
      * @private {!chromeos.networkConfig.mojom.ConfigProperties|undefined}
      */
     configProperties_: Object,
@@ -191,7 +190,7 @@
      * changes.
      * @private {!chromeos.networkConfig.mojom.SecurityType|undefined}
      */
-    securityType: Number,
+    securityType_: Number,
 
     /**
      * 'SaveCredentials' value used for VPN (OpenVPN, IPsec, and L2TP).
@@ -306,19 +305,19 @@
   observers: [
     'setEnableConnect_(isConfigured_, propertiesSent_)',
     'setEnableSave_(isConfigured_, managedProperties_)',
-    'setShareNetwork_(mojoType_, managedProperties_, securityType,' +
+    'setShareNetwork_(mojoType_, managedProperties_, securityType_,' +
         'shareDefault, shareAllowEnable)',
     'updateHiddenNetworkWarning_(autoConnect_)',
     'updateConfigProperties_(mojoType_, managedProperties_)',
-    'updateSecurity_(configProperties_, securityType)',
+    'updateSecurity_(configProperties_, securityType_)',
     'updateEapOuter_(eapProperties_.outer)',
     'updateEapCerts_(eapProperties_.*, serverCaCerts_, userCerts_)',
-    'updateShowEap_(configProperties_.*, eapProperties_.*, securityType)',
+    'updateShowEap_(configProperties_.*, eapProperties_.*, securityType_)',
     'updateVpnType_(configProperties_, vpnType_)',
     'updateVpnIPsecCerts_(vpnType_, configProperties_.typeConfig.vpn.ipSec.*)',
     'updateOpenVPNCerts_(vpnType_, configProperties_.typeConfig.vpn.openVpn.*)',
     // Multiple updateIsConfigured observers for different configurations.
-    'updateIsConfigured_(configProperties_.*, securityType)',
+    'updateIsConfigured_(configProperties_.*, securityType_)',
     'updateIsConfigured_(configProperties_, eapProperties_.*)',
     'updateIsConfigured_(configProperties_.typeConfig.wifi.*)',
     'updateIsConfigured_(configProperties_.typeConfig.vpn.*, vpnType_)',
@@ -361,10 +360,10 @@
       const mojoType = OncMojo.getNetworkTypeFromString(this.type);
       const managedProperties =
           OncMojo.getDefaultManagedProperties(mojoType, this.guid, this.name);
-      // Allow wifi securityType to be set externally (e.g. in tests).
+      // Allow securityType_ to be set externally (e.g. in tests).
       if (mojoType == mojom.NetworkType.kWiFi &&
-          this.securityType !== undefined) {
-        managedProperties.typeProperties.wifi.security = this.securityType;
+          this.securityType_ !== undefined) {
+        managedProperties.typeProperties.wifi.security = this.securityType_;
       }
       this.managedProperties_ = managedProperties;
       this.mojoType_ = mojoType;
@@ -464,7 +463,7 @@
   close_: function() {
     this.guid = '';
     this.type = '';
-    this.securityType = undefined;
+    this.securityType_ = undefined;
     this.fire('close');
   },
 
@@ -479,7 +478,7 @@
   /** CrNetworkListenerBehavior override */
   onNetworkCertificatesChanged: function() {
     this.networkConfig_.getNetworkCertificates().then(response => {
-      const isOpenVpn = this.configProperties_.type == mojom.NetworkType.kVPN &&
+      const isOpenVpn = !!this.configProperties_.typeConfig.vpn &&
           this.configProperties_.typeConfig.vpn.type == mojom.VpnType.kOpenVPN;
 
       const caCerts = response.serverCas.slice();
@@ -620,7 +619,7 @@
   /** @private */
   setShareNetwork_: function() {
     if (this.mojoType_ === undefined || !this.managedProperties_ ||
-        !this.securityType === undefined) {
+        !this.securityType_ === undefined) {
       return;
     }
     const source = this.managedProperties_.source;
@@ -797,7 +796,7 @@
       configProperties.autoConnect = {value: autoConnect};
     }
     this.configProperties_ = configProperties;
-    this.securityType = security;
+    this.securityType_ = security;
     this.set('eapProperties_', this.getEap_(this.configProperties_));
     if (!this.eapProperties_) {
       this.showEap_ = null;
@@ -809,15 +808,15 @@
 
   /**
    * Ensures that the appropriate properties are set or deleted when
-   * |securityType| changes.
+   * |securityType_| changes.
    * @private
    */
   updateSecurity_: function() {
-    if (this.securityType === undefined || !this.configProperties_) {
+    if (this.securityType_ === undefined || !this.configProperties_) {
       return;
     }
     const type = this.mojoType_;
-    const security = this.securityType;
+    const security = this.securityType_;
     if (type == mojom.NetworkType.kWiFi) {
       this.configProperties_.typeConfig.wifi.security = security;
     } else if (type == mojom.NetworkType.kEthernet) {
@@ -867,7 +866,8 @@
 
   /** @private */
   updateShowEap_: function() {
-    if (!this.eapProperties_ || this.securityType == mojom.SecurityType.kNone) {
+    if (!this.eapProperties_ ||
+        this.securityType_ == mojom.SecurityType.kNone) {
       this.showEap_ = null;
       this.updateCertError_();
       return;
@@ -1189,27 +1189,27 @@
    * @private
    */
   getIsConfigured_: function() {
-    if (this.securityType === undefined || !this.configProperties_) {
+    if (this.securityType_ === undefined || !this.configProperties_) {
       return false;
     }
 
-    const type = this.configProperties_.type;
-    if (type == mojom.NetworkType.kVPN) {
+    const typeConfig = this.configProperties_.typeConfig;
+    if (typeConfig.vpn) {
       return this.vpnIsConfigured_();
     }
 
-    if (type == mojom.NetworkType.kWiFi) {
-      if (!this.configProperties_.typeConfig.wifi.ssid) {
+    if (typeConfig.wifi) {
+      if (!typeConfig.wifi.ssid) {
         return false;
       }
-      if (this.configRequiresPassphrase_(type, this.securityType)) {
-        const passphrase = this.configProperties_.typeConfig.wifi.passphrase;
+      if (this.configRequiresPassphrase_()) {
+        const passphrase = typeConfig.wifi.passphrase;
         if (!passphrase || passphrase.length < this.MIN_PASSPHRASE_LENGTH) {
           return false;
         }
       }
     }
-    if (this.securityType == mojom.SecurityType.kWpaEap) {
+    if (this.securityType_ == mojom.SecurityType.kWpaEap) {
       return this.eapIsConfigured_();
     }
     return true;
@@ -1285,7 +1285,7 @@
 
     // Insecure WiFi networks are always shared.
     if (this.mojoType_ == mojom.NetworkType.kWiFi &&
-        this.securityType == mojom.SecurityType.kNone) {
+        this.securityType_ == mojom.SecurityType.kNone) {
       return false;
     }
     return true;
@@ -1602,16 +1602,14 @@
   },
 
   /**
-   * @param {mojom.NetworkType} type
-   * @param {mojom.SecurityType} security
    * @return {boolean}
    * @private
    */
-  configRequiresPassphrase_: function(type, security) {
+  configRequiresPassphrase_: function() {
     // Note: 'Passphrase' is only used by WiFi; Ethernet uses EAP.Password.
-    return type == mojom.NetworkType.kWiFi &&
-        (security == mojom.SecurityType.kWepPsk ||
-         security == mojom.SecurityType.kWpaPsk);
+    return this.mojoType_ == mojom.NetworkType.kWiFi &&
+        (this.securityType_ == mojom.SecurityType.kWepPsk ||
+         this.securityType_ == mojom.SecurityType.kWpaPsk);
   },
 
   /**
diff --git a/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.html b/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.html
index efc97d5..dd8f225a 100644
--- a/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.html
+++ b/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.html
@@ -73,7 +73,7 @@
             hidden$="[[!isStateTextVisible_(networkState)]]"
             active$="[[isStateTextActive_(networkState,
                          activationUnavailable)]]">
-          [[getNetworkStateText_(networkState, cellActivationAvailable)]]
+          [[getNetworkStateText_(networkState, activationUnavailable)]]
         </div>
       </div>
       <template is="dom-if" if="[[isPolicySource(networkState.source)]]">
diff --git a/weblayer/BUILD.gn b/weblayer/BUILD.gn
index 88675f5..68e8f369 100644
--- a/weblayer/BUILD.gn
+++ b/weblayer/BUILD.gn
@@ -44,7 +44,6 @@
     "browser/browser_main_parts_impl.h",
     "browser/content_browser_client_impl.cc",
     "browser/content_browser_client_impl.h",
-    "browser/isolated_world_ids.h",
     "browser/navigation_controller_impl.cc",
     "browser/navigation_controller_impl.h",
     "browser/navigation_impl.cc",
diff --git a/weblayer/browser/browser_controller_impl.cc b/weblayer/browser/browser_controller_impl.cc
index c373975..880f2c10 100644
--- a/weblayer/browser/browser_controller_impl.cc
+++ b/weblayer/browser/browser_controller_impl.cc
@@ -21,10 +21,7 @@
 #endif
 
 #if defined(OS_ANDROID)
-#include "base/android/callback_android.h"
 #include "base/android/jni_string.h"
-#include "base/json/json_writer.h"
-#include "weblayer/browser/isolated_world_ids.h"
 #include "weblayer/browser/java/jni/BrowserControllerImpl_jni.h"
 #include "weblayer/browser/top_controls_container_view.h"
 #endif
@@ -43,14 +40,6 @@
 
 #if defined(OS_ANDROID)
 BrowserController* g_last_browser_controller;
-
-void JavaScriptResultCallback(
-    const base::android::ScopedJavaGlobalRef<jobject>& callback,
-    base::Value result) {
-  std::string json;
-  base::JSONWriter::Write(result, &json);
-  base::android::RunStringCallbackAndroid(callback, json);
-}
 #endif
 
 }  // namespace
@@ -160,17 +149,6 @@
       native_top_controls_container_view);
 }
 
-void BrowserControllerImpl::ExecuteScript(
-    JNIEnv* env,
-    const base::android::JavaParamRef<jstring>& script,
-    const base::android::JavaParamRef<jobject>& callback) {
-  base::android::ScopedJavaGlobalRef<jobject> jcallback(env, callback);
-  web_contents_->GetMainFrame()->ExecuteJavaScriptInIsolatedWorld(
-      base::android::ConvertJavaStringToUTF16(script),
-      base::BindOnce(&JavaScriptResultCallback, jcallback),
-      ISOLATED_WORLD_ID_WEBLAYER);
-}
-
 #endif
 
 void BrowserControllerImpl::LoadingStateChanged(content::WebContents* source,
diff --git a/weblayer/browser/browser_controller_impl.h b/weblayer/browser/browser_controller_impl.h
index ec14c599..59d9676d 100644
--- a/weblayer/browser/browser_controller_impl.h
+++ b/weblayer/browser/browser_controller_impl.h
@@ -54,9 +54,6 @@
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& caller,
       jlong native_top_controls_container_view);
-  void ExecuteScript(JNIEnv* env,
-                     const base::android::JavaParamRef<jstring>& script,
-                     const base::android::JavaParamRef<jobject>& callback);
 #endif
 
   DownloadDelegate* download_delegate() { return download_delegate_; }
diff --git a/weblayer/browser/isolated_world_ids.h b/weblayer/browser/isolated_world_ids.h
deleted file mode 100644
index ecef6ad..0000000
--- a/weblayer/browser/isolated_world_ids.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef WEBLAYER_BROWSER_ISOLATED_WORLD_IDS_H_
-#define WEBLAYER_BROWSER_ISOLATED_WORLD_IDS_H_
-
-#include "content/public/common/isolated_world_ids.h"
-
-namespace weblayer {
-
-enum IsolatedWorldIDs {
-  ISOLATED_WORLD_ID_WEBLAYER = content::ISOLATED_WORLD_ID_CONTENT_END + 1,
-};
-
-}  // namespace weblayer
-
-#endif  // WEBLAYER_BROWSER_ISOLATED_WORLD_IDS_H_
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/BrowserControllerImpl.java b/weblayer/browser/java/org/chromium/weblayer_private/BrowserControllerImpl.java
index 0fec708..51348b2 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/BrowserControllerImpl.java
+++ b/weblayer/browser/java/org/chromium/weblayer_private/BrowserControllerImpl.java
@@ -13,7 +13,6 @@
 import android.webkit.ValueCallback;
 import android.widget.FrameLayout;
 
-import org.chromium.base.Callback;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.NativeMethods;
 import org.chromium.content_public.browser.ViewEventSink;
@@ -162,22 +161,6 @@
         }
     }
 
-    @Override
-    public void executeScript(String script, IObjectWrapper callback) {
-        Callback<String> nativeCallback = new Callback<String>() {
-            @Override
-            public void onResult(String result) {
-                ValueCallback<String> unwrappedCallback =
-                        (ValueCallback<String>) ObjectWrapper.unwrap(callback, ValueCallback.class);
-                if (unwrappedCallback != null) {
-                    unwrappedCallback.onReceiveValue(result);
-                }
-            }
-        };
-        BrowserControllerImplJni.get().executeScript(
-                mNativeBrowserController, script, nativeCallback);
-    }
-
     public void destroy() {
         BrowserControllerImplJni.get().setTopControlsContainerView(
                 mNativeBrowserController, BrowserControllerImpl.this, 0);
@@ -223,7 +206,5 @@
                 BrowserControllerImpl caller, long nativeTopControlsContainerView);
         void deleteBrowserController(long browserController);
         WebContents getWebContents(long nativeBrowserControllerImpl, BrowserControllerImpl caller);
-        void executeScript(
-                long nativeBrowserControllerImpl, String script, Callback<String> callback);
     }
 }
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/aidl/IBrowserController.aidl b/weblayer/browser/java/org/chromium/weblayer_private/aidl/IBrowserController.aidl
index 0d42322..63de6348 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/aidl/IBrowserController.aidl
+++ b/weblayer/browser/java/org/chromium/weblayer_private/aidl/IBrowserController.aidl
@@ -17,6 +17,4 @@
   void setDownloadDelegateClient(IDownloadDelegateClient client) = 2;
 
   void setFullscreenDelegateClient(in IFullscreenDelegateClient client) = 3;
-
-  void executeScript(in String script, in IObjectWrapper callback) = 4;
 }
diff --git a/weblayer/public/java/org/chromium/weblayer/BrowserController.java b/weblayer/public/java/org/chromium/weblayer/BrowserController.java
index 33fe878..f1c4e352 100644
--- a/weblayer/public/java/org/chromium/weblayer/BrowserController.java
+++ b/weblayer/public/java/org/chromium/weblayer/BrowserController.java
@@ -8,9 +8,6 @@
 import android.os.RemoteException;
 import android.webkit.ValueCallback;
 
-import org.json.JSONException;
-import org.json.JSONObject;
-
 import org.chromium.weblayer_private.aidl.APICallException;
 import org.chromium.weblayer_private.aidl.IBrowserController;
 import org.chromium.weblayer_private.aidl.IBrowserControllerClient;
@@ -20,9 +17,6 @@
 import org.chromium.weblayer_private.aidl.ObjectWrapper;
 
 public final class BrowserController {
-    /** The top level key of the JSON object returned by executeScript(). */
-    public static final String SCRIPT_RESULT_KEY = "result";
-
     private final IBrowserController mImpl;
     private FullscreenDelegateClientImpl mFullscreenDelegateClient;
     private final NavigationController mNavigationController;
@@ -72,32 +66,6 @@
         return mDownloadDelegateClient != null ? mDownloadDelegateClient.getDelegate() : null;
     }
 
-    /**
-     * Executes the script in an isolated world, and returns the result as a JSON object to the
-     * callback if provided. The object passed to the callback will have a single key
-     * SCRIPT_RESULT_KEY which will hold the result of running the script.
-     */
-    public void executeScript(String script, ValueCallback<JSONObject> callback) {
-        try {
-            ValueCallback<String> stringCallback = (String result) -> {
-                if (callback == null) {
-                    return;
-                }
-
-                try {
-                    callback.onReceiveValue(
-                            new JSONObject("{\"" + SCRIPT_RESULT_KEY + "\":" + result + "}"));
-                } catch (JSONException e) {
-                    // This should never happen since the result should be well formed.
-                    throw new RuntimeException(e);
-                }
-            };
-            mImpl.executeScript(script, ObjectWrapper.wrap(stringCallback));
-        } catch (RemoteException e) {
-            throw new APICallException(e);
-        }
-    }
-
     public FullscreenDelegate getFullscreenDelegate() {
         return mFullscreenDelegateClient != null ? mFullscreenDelegateClient.getDelegate() : null;
     }
diff --git a/weblayer/shell/android/BUILD.gn b/weblayer/shell/android/BUILD.gn
index f04b45d2..76f75d3 100644
--- a/weblayer/shell/android/BUILD.gn
+++ b/weblayer/shell/android/BUILD.gn
@@ -258,7 +258,6 @@
     "javatests/src/org/chromium/weblayer/test/BrowserObserverTest.java",
     "javatests/src/org/chromium/weblayer/test/NavigationTest.java",
     "javatests/src/org/chromium/weblayer/test/SmokeTest.java",
-    "javatests/src/org/chromium/weblayer/test/ExecuteScriptTest.java",
     "javatests/src/org/chromium/weblayer/test/RenderingTest.java",
     "javatests/src/org/chromium/weblayer/test/WebLayerShellActivityTestRule.java",
     "javatests/src/org/chromium/weblayer/test/FragmentRestoreTest.java",
diff --git a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/ExecuteScriptTest.java b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/ExecuteScriptTest.java
deleted file mode 100644
index f39768c..0000000
--- a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/ExecuteScriptTest.java
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.weblayer.test;
-
-import android.support.test.filters.SmallTest;
-
-import org.json.JSONObject;
-import org.junit.Assert;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import org.chromium.base.test.BaseJUnit4ClassRunner;
-import org.chromium.base.test.util.UrlUtils;
-import org.chromium.content_public.browser.test.util.TestThreadUtils;
-import org.chromium.weblayer.BrowserController;
-import org.chromium.weblayer.shell.WebLayerShellActivity;
-
-/**
- * Tests that script execution works as expected.
- */
-@RunWith(BaseJUnit4ClassRunner.class)
-public class ExecuteScriptTest {
-    @Rule
-    public WebLayerShellActivityTestRule mActivityTestRule = new WebLayerShellActivityTestRule();
-
-    private static final String DATA_URL = UrlUtils.encodeHtmlDataUri(
-            "<html><head><script>var bar = 10;</script></head><body>foo</body></html>");
-
-    @Test
-    @SmallTest
-    public void testBasicScript() throws Exception {
-        WebLayerShellActivity activity = mActivityTestRule.launchShellWithUrl(DATA_URL);
-        mActivityTestRule.waitForNavigation(DATA_URL);
-        JSONObject result = mActivityTestRule.executeScriptSync("document.body.innerHTML");
-        Assert.assertEquals(result.getString(BrowserController.SCRIPT_RESULT_KEY), "foo");
-    }
-
-    @Test
-    @SmallTest
-    public void testScriptIsolatedFromPage() throws Exception {
-        WebLayerShellActivity activity = mActivityTestRule.launchShellWithUrl(DATA_URL);
-        mActivityTestRule.waitForNavigation(DATA_URL);
-        JSONObject result = mActivityTestRule.executeScriptSync("bar");
-        Assert.assertTrue(result.isNull(BrowserController.SCRIPT_RESULT_KEY));
-    }
-
-    @Test
-    @SmallTest
-    public void testScriptNotIsolatedFromOtherScript() throws Exception {
-        WebLayerShellActivity activity = mActivityTestRule.launchShellWithUrl(DATA_URL);
-        mActivityTestRule.waitForNavigation(DATA_URL);
-        mActivityTestRule.executeScriptSync("var foo = 20;");
-        JSONObject result = mActivityTestRule.executeScriptSync("foo");
-        Assert.assertEquals(result.getInt(BrowserController.SCRIPT_RESULT_KEY), 20);
-    }
-
-    @Test
-    @SmallTest
-    public void testClearedOnNavigate() throws Exception {
-        WebLayerShellActivity activity = mActivityTestRule.launchShellWithUrl(DATA_URL);
-        mActivityTestRule.waitForNavigation(DATA_URL);
-        mActivityTestRule.executeScriptSync("var foo = 20;");
-
-        String newUrl = UrlUtils.encodeHtmlDataUri("<html></html>");
-        mActivityTestRule.loadUrl(newUrl);
-        mActivityTestRule.waitForNavigation(newUrl);
-        JSONObject result = mActivityTestRule.executeScriptSync("foo");
-        Assert.assertTrue(result.isNull(BrowserController.SCRIPT_RESULT_KEY));
-    }
-
-    @Test
-    @SmallTest
-    public void testNullCallback() throws Exception {
-        WebLayerShellActivity activity = mActivityTestRule.launchShellWithUrl(DATA_URL);
-        mActivityTestRule.waitForNavigation(DATA_URL);
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            // Null callback should not crash.
-            activity.getBrowserController().executeScript("null", null);
-        });
-        // Execute a sync script to make sure the other script finishes.
-        mActivityTestRule.executeScriptSync("null");
-    }
-}
diff --git a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/WebLayerShellActivityTestRule.java b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/WebLayerShellActivityTestRule.java
index aa9d91c7..78df02da 100644
--- a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/WebLayerShellActivityTestRule.java
+++ b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/WebLayerShellActivityTestRule.java
@@ -14,9 +14,6 @@
 import android.support.test.InstrumentationRegistry;
 import android.support.test.rule.ActivityTestRule;
 
-import org.json.JSONObject;
-
-import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
@@ -24,7 +21,6 @@
 import org.chromium.weblayer.shell.WebLayerShellActivity;
 
 import java.lang.reflect.Field;
-import java.util.concurrent.TimeoutException;
 
 /**
  * ActivityTestRule for WebLayerShellActivity.
@@ -34,19 +30,6 @@
 public class WebLayerShellActivityTestRule extends ActivityTestRule<WebLayerShellActivity> {
     private static final long WAIT_FOR_NAVIGATION_TIMEOUT = 10000L;
 
-    private static final class JSONCallbackHelper extends CallbackHelper {
-        private JSONObject mResult;
-
-        public JSONObject getResult() {
-            return mResult;
-        }
-
-        public void notifyCalled(JSONObject result) {
-            mResult = result;
-            notifyCalled();
-        }
-    }
-
     public WebLayerShellActivityTestRule() {
         super(WebLayerShellActivity.class, false, false);
     }
@@ -119,22 +102,4 @@
             throw new RuntimeException(e);
         }
     }
-
-    /**
-     * Executes the script passed in and waits for the result.
-     */
-    public JSONObject executeScriptSync(String script) {
-        JSONCallbackHelper callbackHelper = new JSONCallbackHelper();
-        int count = callbackHelper.getCallCount();
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            getActivity().getBrowserController().executeScript(
-                    script, (JSONObject result) -> { callbackHelper.notifyCalled(result); });
-        });
-        try {
-            callbackHelper.waitForCallback(count);
-        } catch (TimeoutException e) {
-            throw new RuntimeException(e);
-        }
-        return callbackHelper.getResult();
-    }
 }