diff --git a/.gitignore b/.gitignore
index 595430f..f2975ca 100644
--- a/.gitignore
+++ b/.gitignore
@@ -71,6 +71,7 @@
 /android_emulator_sdk
 /ash/ash_unittests_run.xml
 /base/base_unittests_run.xml
+/.cache/
 # See build/.gitignore for entries covering src/build.
 
 # The Chrome OS build creates a /c symlink due to http://crbug.com/54866.
diff --git a/.gn b/.gn
index 13648bd..17bf869 100644
--- a/.gn
+++ b/.gn
@@ -74,9 +74,7 @@
   "//chrome/browser/updates:*",  # 21 errors
   "//chrome/browser:*",  # 780 errors
   "//chrome/child:*",  # 3 errors
-  "//chrome/credential_provider/gaiacp:*",  # 34 errors
-  "//chrome/credential_provider/setup:*",  # 1 error
-  "//chrome/credential_provider/test:*",  # 22 errors
+  "//chrome/credential_provider/gaiacp:*",  # 1 error
   "//chrome/gpu:*",  # 2 errors
   "//chrome/install_static:*",  # 4 errors
   "//chrome/notification_helper:*",  # 4 errors
diff --git a/DEPS b/DEPS
index 5acc465..e79d795c 100644
--- a/DEPS
+++ b/DEPS
@@ -159,12 +159,8 @@
   'cros_boards': Str(''),
   'cros_boards_with_qemu_images': Str(''),
   # Building for CrOS is only supported on linux currently.
-  'checkout_simplechrome': '(checkout_chromeos and host_os == "linux") and ("{cros_boards}" != "")',
-  # Surround the board var in quotes so gclient doesn't try parsing the string
-  # as an expression.
-  # TODO(crbug.com/937821): Replace uses of this var with
-  # 'cros_boards_with_qemu_images' above.
-  'cros_download_vm': '(("{cros_boards}" == "amd64-generic") or ("{cros_boards}" == "betty")) or ("{cros_boards}" == "betty-pi-arc")',
+  'checkout_simplechrome': '"{cros_boards}" != ""',
+  'checkout_simplechrome_with_vms': '"{cros_boards_with_qemu_images}" != ""',
   # Should we build and test for public (ie: full) CrOS images, or private
   # (ie: release) images.
   'use_public_cros_config': 'not checkout_src_internal',
@@ -199,11 +195,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '2d7afd4824c656b8c05810cff1751b430148fd8b',
+  'skia_revision': '9662fd6cbdfb1103613e197c3ea6b5bfc0c343d5',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '9109ad2275ba3f77a6e611d593e5215c742ae589',
+  'v8_revision': 'c80db6e1335a652a7d6491d7fd82c1461594ce9c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -215,7 +211,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': 'e8dd233c7a85f3c689caf06c226a7f8405a480d3',
+  'swiftshader_revision': 'a8b8ef775c7539254541c5a1070ce2948ae7be5c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -270,7 +266,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': '2bcf0b808628b338044bd296974437c96b96edb5',
+  'devtools_frontend_revision': '52711d8fe65b1736499d5d668d0f9f4441c254c3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -322,7 +318,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '7f4980e7d265d3f2e984dd316dccdb28a9dd86bf',
+  'dawn_revision': '1233b66c90d45c3c2b16a6d0635183201893dffc',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -549,7 +545,7 @@
   },
 
   'src/ios/third_party/material_components_ios/src': {
-      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'f2dd90e06cca99d66d4e33c99fad0d13180b1e04',
+      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '4216eb6ed560b65e7e5903d12da072a1f322b30d',
       'condition': 'checkout_ios',
   },
 
@@ -899,7 +895,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '320ceb93a21c7b5cee9d8cd95a282d06e1a3f6bd',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '4bbdfa583e743daeb477d848c2be9d18bf0a03a4',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -999,7 +995,7 @@
   },
 
   'src/third_party/arcore-android-sdk/src': {
-      'url': Var('chromium_git') + '/external/github.com/google-ar/arcore-android-sdk.git' + '@' + '765ca36d1d03e8d97bcb4d48d407277c3b503f21',
+      'url': Var('chromium_git') + '/external/github.com/google-ar/arcore-android-sdk.git' + '@' + '54861e38cceb406021fc8ece495f82387376af62',
       'condition': 'checkout_android',
   },
 
@@ -1007,7 +1003,7 @@
       'packages': [
         {
           'package': 'chromium/third_party/arcore-android-sdk-client',
-          'version': 'Ki3Nxeov-cyGeHGIxrhG1teX7zYstsUtg1k-SAQ8CpAC',
+          'version': 'KFu2mHSzZr0ZNOlM_LG5AA5ZIi2_rICieWgkME9IUFYC',
         },
       ],
 
@@ -1330,7 +1326,7 @@
       'packages': [
           {
               'package': 'fuchsia/third_party/aemu/linux-amd64',
-              'version': '6w0qlJN7Xw7ZqAjvr5YYRHsrQ-LH90XaBZQZ8KvSHJAC'
+              'version': 'bMBorsHPd-GA42g-lfkvaE5HhiZVCcqkoLNKDzb8ElUC'
           },
       ],
       'condition': 'host_os == "linux" and checkout_fuchsia',
@@ -1480,7 +1476,7 @@
   },
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'fc4668dae26e1c9ad40eb75919e7e733251fda4b',
+    Var('webrtc_git') + '/src.git' + '@' + 'de90862cce9530602c8f245bab40a931809dd987',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1552,7 +1548,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@0d8628ddce9aa292a44a7207b3f782320f235ced',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@7043cea402ac986bcafc584640c09b22419ac378',
     'condition': 'checkout_src_internal',
   },
 
@@ -4874,7 +4870,7 @@
   {
     'name': 'cros_simplechrome_artifacts_with_vm',
     'pattern': '.',
-    'condition': '(checkout_simplechrome and cros_download_vm) and use_public_cros_config',
+    'condition': 'checkout_simplechrome_with_vms and use_public_cros_config',
     'action': [
       'src/third_party/chromite/bin/cros',
       'chrome-sdk',
@@ -4883,7 +4879,7 @@
       '--fallback-versions=10',
       '--nogn-gen',
       '--download-vm',
-      '--boards={cros_boards}',
+      '--boards={cros_boards_with_qemu_images}',
       '--cache-dir=src/build/cros_cache/',
       '--log-level=error',
       '--no-shell',
@@ -4892,7 +4888,7 @@
   {
     'name': 'cros_simplechrome_artifacts_with_no_vm',
     'pattern': '.',
-    'condition': '(checkout_simplechrome and not cros_download_vm) and use_public_cros_config',
+    'condition': 'checkout_simplechrome and use_public_cros_config',
     'action': [
       'src/third_party/chromite/bin/cros',
       'chrome-sdk',
diff --git a/ash/clipboard/OWNERS b/ash/clipboard/OWNERS
index 0cf2588..57a56246 100644
--- a/ash/clipboard/OWNERS
+++ b/ash/clipboard/OWNERS
@@ -1,3 +1,4 @@
+dmblack@google.com
 newcomer@chromium.org
 
 # COMPONENT: UI>EnhancedClipboard
\ No newline at end of file
diff --git a/ash/hud_display/hud_settings_view.cc b/ash/hud_display/hud_settings_view.cc
index 5794f135..4bc4473 100644
--- a/ash/hud_display/hud_settings_view.cc
+++ b/ash/hud_display/hud_settings_view.cc
@@ -5,8 +5,12 @@
 #include "ash/hud_display/hud_settings_view.h"
 
 #include "ash/hud_display/hud_properties.h"
+#include "base/bind.h"
 #include "base/compiler_specific.h"
 #include "base/strings/string16.h"
+#include "components/viz/common/display/renderer_settings.h"
+#include "components/viz/host/host_frame_sink_manager.h"
+#include "ui/aura/env.h"
 #include "ui/views/controls/button/checkbox.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/layout/box_layout.h"
@@ -14,6 +18,63 @@
 namespace ash {
 namespace hud_display {
 
+class HUDCheckboxHandler {
+ public:
+  HUDCheckboxHandler(
+      views::Checkbox* checkbox,
+      base::RepeatingCallback<void(views::Checkbox*)> update_state,
+      base::RepeatingCallback<void(views::Checkbox*)> handle_click)
+      : checkbox_(checkbox),
+        update_state_(update_state),
+        handle_click_(handle_click) {}
+
+  HUDCheckboxHandler(const HUDCheckboxHandler&) = delete;
+  HUDCheckboxHandler& operator=(const HUDCheckboxHandler&) = delete;
+
+  void UpdateState() const { update_state_.Run(checkbox_); }
+  void HandleClick() const { handle_click_.Run(checkbox_); }
+
+  const views::Checkbox* checkbox() const { return checkbox_; }
+
+ private:
+  views::Checkbox* const checkbox_;  // not owned.
+  base::RepeatingCallback<void(views::Checkbox*)> update_state_;
+  base::RepeatingCallback<void(views::Checkbox*)> handle_click_;
+};
+
+namespace {
+
+base::RepeatingCallback<void(views::Checkbox*)> GetUpdateStateCallback(
+    const bool viz::DebugRendererSettings::*field) {
+  return base::BindRepeating(
+      [](const bool viz::DebugRendererSettings::*field,
+         views::Checkbox* checkbox) {
+        checkbox->SetChecked(aura::Env::GetInstance()
+                                 ->context_factory()
+                                 ->GetHostFrameSinkManager()
+                                 ->debug_renderer_settings().*
+                             field);
+      },
+      field);
+}
+
+base::RepeatingCallback<void(views::Checkbox*)> GetHandleClickCallback(
+    bool viz::DebugRendererSettings::*field) {
+  return base::BindRepeating(
+      [](bool viz::DebugRendererSettings::*field, views::Checkbox* checkbox) {
+        viz::HostFrameSinkManager* manager = aura::Env::GetInstance()
+                                                 ->context_factory()
+                                                 ->GetHostFrameSinkManager();
+        viz::DebugRendererSettings debug_settings =
+            manager->debug_renderer_settings();
+        debug_settings.*field = checkbox->GetChecked();
+        manager->UpdateDebugRendererSettings(debug_settings);
+      },
+      field);
+}
+
+}  // anonymous namespace
+
 BEGIN_METADATA(HUDSettingsView)
 METADATA_PARENT_CLASS(View)
 END_METADATA()
@@ -30,33 +91,57 @@
   SetLayoutManager(std::move(layout_manager));
   SetBorder(views::CreateSolidBorder(1, kDefaultColor));
 
-  // Use this to add checkboxes like:
-  // add_checkbox(this, base::ASCIIToUTF16("test1"));
   auto add_checkbox = [](HUDSettingsView* self,
-                         const base::string16& text) -> const views::Checkbox* {
+                         const base::string16& text) -> views::Checkbox* {
     auto checkbox = std::make_unique<views::Checkbox>(text, self);
-    const views::Checkbox* result = checkbox.get();
+    views::Checkbox* result = checkbox.get();
     checkbox->SetEnabledTextColors(kDefaultColor);
     checkbox->SetProperty(kHUDClickHandler, HTCLIENT);
     self->AddChildView(std::move(checkbox));
     return result;
   };
 
-  // No checkboxes for now.
-  ALLOW_UNUSED_LOCAL(add_checkbox);
+  checkbox_handlers_.push_back(std::make_unique<HUDCheckboxHandler>(
+      add_checkbox(this, base::ASCIIToUTF16("Tint composited content")),
+      GetUpdateStateCallback(
+          &viz::DebugRendererSettings::tint_composited_content),
+      GetHandleClickCallback(
+          &viz::DebugRendererSettings::tint_composited_content)));
+  checkbox_handlers_.push_back(std::make_unique<HUDCheckboxHandler>(
+      add_checkbox(this, base::ASCIIToUTF16("Show overdraw feedback")),
+      GetUpdateStateCallback(
+          &viz::DebugRendererSettings::show_overdraw_feedback),
+      GetHandleClickCallback(
+          &viz::DebugRendererSettings::show_overdraw_feedback)));
+  checkbox_handlers_.push_back(std::make_unique<HUDCheckboxHandler>(
+      add_checkbox(this, base::ASCIIToUTF16("Show DC layer debug borders")),
+      GetUpdateStateCallback(
+          &viz::DebugRendererSettings::show_dc_layer_debug_borders),
+      GetHandleClickCallback(
+          &viz::DebugRendererSettings::show_dc_layer_debug_borders)));
 }
 
 HUDSettingsView::~HUDSettingsView() = default;
 
 void HUDSettingsView::ButtonPressed(views::Button* sender,
                                     const ui::Event& /*event*/) {
-  const views::Checkbox* checkbox = static_cast<views::Checkbox*>(sender);
-  DVLOG(1) << "HUDSettingsView::ButtonPressed(): "
-           << (checkbox->GetChecked() ? "Checked" : "Uncheked");
+  for (const auto& handler : checkbox_handlers_) {
+    if (sender != handler->checkbox())
+      continue;
+
+    handler->HandleClick();
+    break;
+  }
 }
 
 void HUDSettingsView::ToggleVisibility() {
-  SetVisible(!GetVisible());
+  const bool is_shown = !GetVisible();
+  if (is_shown) {
+    for (const auto& handler : checkbox_handlers_) {
+      handler->UpdateState();
+    }
+  }
+  SetVisible(is_shown);
 }
 
 }  // namespace hud_display
diff --git a/ash/hud_display/hud_settings_view.h b/ash/hud_display/hud_settings_view.h
index 30007a7..5b742f10 100644
--- a/ash/hud_display/hud_settings_view.h
+++ b/ash/hud_display/hud_settings_view.h
@@ -5,6 +5,9 @@
 #ifndef ASH_HUD_DISPLAY_HUD_SETTINGS_VIEW_H_
 #define ASH_HUD_DISPLAY_HUD_SETTINGS_VIEW_H_
 
+#include <memory>
+#include <vector>
+
 #include "ash/hud_display/hud_constants.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/views/controls/button/button.h"
@@ -13,6 +16,8 @@
 namespace ash {
 namespace hud_display {
 
+class HUDCheckboxHandler;
+
 class HUDSettingsView : public views::ButtonListener, public views::View {
  public:
   METADATA_HEADER(HUDSettingsView);
@@ -32,6 +37,9 @@
 
   // Shows/hides the view.
   void ToggleVisibility();
+
+ private:
+  std::vector<std::unique_ptr<HUDCheckboxHandler>> checkbox_handlers_;
 };
 
 }  // namespace hud_display
diff --git a/ash/system/tray/tray_constants.h b/ash/system/tray/tray_constants.h
index 4d5c5e52..d33e21a 100644
--- a/ash/system/tray/tray_constants.h
+++ b/ash/system/tray/tray_constants.h
@@ -102,7 +102,7 @@
 
 constexpr gfx::Insets kUnifiedMenuItemPadding(0, 16, 16, 16);
 constexpr gfx::Insets kUnifiedSystemInfoViewPadding(0, 16, 16, 16);
-constexpr gfx::Insets kUnifiedManagedDeviceViewPadding(4, 19, 4, 16);
+constexpr gfx::Insets kUnifiedManagedDeviceViewPadding(0, 16, 11, 16);
 constexpr gfx::Insets kUnifiedSliderRowPadding(0, 16, 8, 16);
 constexpr gfx::Insets kUnifiedSliderBubblePadding(12, 0, 4, 0);
 constexpr gfx::Insets kUnifiedSliderPadding(0, 16);
@@ -137,7 +137,7 @@
 // A dark disc with |kTrayItemSize| diameter is drawn in the background.
 constexpr int kTrayTopShortcutButtonIconSize = 20;
 
-constexpr int kUnifiedManagedDeviceSpacing = 4;
+constexpr int kUnifiedManagedDeviceSpacing = 8;
 constexpr int kUnifiedSystemInfoHeight = 16;
 constexpr int kUnifiedSystemInfoSpacing = 8;
 constexpr gfx::Insets kUnifiedSystemInfoDateViewPadding(3);
diff --git a/ash/system/unified/unified_managed_device_view.cc b/ash/system/unified/unified_managed_device_view.cc
index c479e29f..66b36a3 100644
--- a/ash/system/unified/unified_managed_device_view.cc
+++ b/ash/system/unified/unified_managed_device_view.cc
@@ -4,6 +4,7 @@
 
 #include "ash/system/unified/unified_managed_device_view.h"
 
+#include "ash/public/cpp/ash_view_ids.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
@@ -25,8 +26,12 @@
 
 namespace ash {
 
-UnifiedManagedDeviceView::UnifiedManagedDeviceView()
-    : icon_(new views::ImageView), label_(new views::Label) {
+UnifiedManagedDeviceView::UnifiedManagedDeviceView(
+    UnifiedSystemTrayController* controller)
+    : Button(this),
+      icon_(new views::ImageView),
+      label_(new views::Label),
+      controller_(controller) {
   auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
       views::BoxLayout::Orientation::kHorizontal,
       kUnifiedManagedDeviceViewPadding, kUnifiedManagedDeviceSpacing));
@@ -44,6 +49,8 @@
       AshColorProvider::AshColorMode::kDark));
   AddChildView(label_);
 
+  SetID(VIEW_ID_TRAY_ENTERPRISE);
+
   Shell::Get()->session_controller()->AddObserver(this);
   Shell::Get()->system_tray_model()->enterprise_domain()->AddObserver(this);
   Update();
@@ -54,6 +61,11 @@
   Shell::Get()->session_controller()->RemoveObserver(this);
 }
 
+void UnifiedManagedDeviceView::ButtonPressed(views::Button* sender,
+                                             const ui::Event& event) {
+  controller_->HandleEnterpriseInfoAction();
+}
+
 void UnifiedManagedDeviceView::OnLoginStatusChanged(LoginStatus status) {
   Update();
 }
@@ -80,20 +92,20 @@
     // Show enterpised managed UI.
     icon_->SetImage(gfx::CreateVectorIcon(kSystemTrayManagedIcon, icon_color));
 
-    if (!enterprise_domain_name.empty()) {
-      label_->SetText(l10n_util::GetStringFUTF16(
-          IDS_ASH_ENTERPRISE_DEVICE_MANAGED_BY,
-          base::UTF8ToUTF16(enterprise_domain_name)));
-    } else {
-      label_->SetText(
-          l10n_util::GetStringUTF16(IDS_ASH_ENTERPRISE_DEVICE_MANAGED));
-    }
-
+    base::string16 managed_string =
+        enterprise_domain_name.empty()
+            ? l10n_util::GetStringUTF16(IDS_ASH_ENTERPRISE_DEVICE_MANAGED)
+            : l10n_util::GetStringFUTF16(
+                  IDS_ASH_ENTERPRISE_DEVICE_MANAGED_BY,
+                  base::UTF8ToUTF16(enterprise_domain_name));
+    label_->SetText(managed_string);
+    SetAccessibleName(managed_string);
     SetVisible(true);
   } else if (session->IsUserSupervised()) {
     // Show supervised user UI (locally supervised or Family Link).
     icon_->SetImage(gfx::CreateVectorIcon(GetSupervisedUserIcon(), icon_color));
     label_->SetText(GetSupervisedUserMessage());
+    SetAccessibleName(GetSupervisedUserMessage());
     SetVisible(true);
   } else {
     SetVisible(false);
diff --git a/ash/system/unified/unified_managed_device_view.h b/ash/system/unified/unified_managed_device_view.h
index f92c7fb..7901c1cb 100644
--- a/ash/system/unified/unified_managed_device_view.h
+++ b/ash/system/unified/unified_managed_device_view.h
@@ -8,7 +8,9 @@
 #include "ash/ash_export.h"
 #include "ash/public/cpp/session/session_observer.h"
 #include "ash/system/enterprise/enterprise_domain_observer.h"
+#include "ash/system/unified/unified_system_tray_controller.h"
 #include "base/macros.h"
+#include "ui/views/controls/button/button.h"
 #include "ui/views/view.h"
 
 namespace views {
@@ -20,13 +22,17 @@
 
 // Row in the unified system tray bubble shown when the device is currently
 // managed by an administrator (by a domain admin or FamilyLink).
-class ASH_EXPORT UnifiedManagedDeviceView : public views::View,
+class ASH_EXPORT UnifiedManagedDeviceView : public views::Button,
+                                            public views::ButtonListener,
                                             public SessionObserver,
                                             public EnterpriseDomainObserver {
  public:
-  UnifiedManagedDeviceView();
+  explicit UnifiedManagedDeviceView(UnifiedSystemTrayController* controller);
   ~UnifiedManagedDeviceView() override;
 
+  // views::ButtonListener:
+  void ButtonPressed(views::Button* sender, const ui::Event& event) override;
+
   // SessionObserver:
   void OnLoginStatusChanged(LoginStatus status) override;
 
@@ -43,6 +49,8 @@
   views::ImageView* const icon_;
   views::Label* const label_;
 
+  UnifiedSystemTrayController* const controller_;
+
   DISALLOW_COPY_AND_ASSIGN(UnifiedManagedDeviceView);
 };
 
diff --git a/ash/system/unified/unified_managed_device_view_unittest.cc b/ash/system/unified/unified_managed_device_view_unittest.cc
index 47097eb..16e3d2e6 100644
--- a/ash/system/unified/unified_managed_device_view_unittest.cc
+++ b/ash/system/unified/unified_managed_device_view_unittest.cc
@@ -9,6 +9,8 @@
 #include "ash/shell.h"
 #include "ash/system/model/enterprise_domain_model.h"
 #include "ash/system/model/system_tray_model.h"
+#include "ash/system/unified/unified_system_tray_controller.h"
+#include "ash/system/unified/unified_system_tray_model.h"
 #include "ash/test/ash_test_base.h"
 
 #include "ash/system/unified/unified_system_tray_view.h"
@@ -22,11 +24,16 @@
 
   void SetUp() override {
     AshTestBase::SetUp();
-    managed_device_view_ = std::make_unique<UnifiedManagedDeviceView>();
+    model_ = std::make_unique<UnifiedSystemTrayModel>(nullptr);
+    controller_ = std::make_unique<UnifiedSystemTrayController>(model_.get());
+    managed_device_view_ =
+        std::make_unique<UnifiedManagedDeviceView>(controller_.get());
   }
 
   void TearDown() override {
     managed_device_view_.reset();
+    controller_.reset();
+    model_.reset();
     AshTestBase::TearDown();
   }
 
@@ -34,6 +41,8 @@
   std::unique_ptr<UnifiedManagedDeviceView> managed_device_view_;
 
  private:
+  std::unique_ptr<UnifiedSystemTrayModel> model_;
+  std::unique_ptr<UnifiedSystemTrayController> controller_;
   DISALLOW_COPY_AND_ASSIGN(UnifiedManagedDeviceViewTest);
 };
 
@@ -70,8 +79,12 @@
   ASSERT_FALSE(session->IsActiveUserSessionStarted());
 
   // Before login the UnifiedManagedDeviceView is invisible.
+  std::unique_ptr<UnifiedSystemTrayModel> model =
+      std::make_unique<UnifiedSystemTrayModel>(nullptr);
+  std::unique_ptr<UnifiedSystemTrayController> controller =
+      std::make_unique<UnifiedSystemTrayController>(model.get());
   std::unique_ptr<UnifiedManagedDeviceView> managed_device_view =
-      std::make_unique<UnifiedManagedDeviceView>();
+      std::make_unique<UnifiedManagedDeviceView>(controller.get());
   EXPECT_FALSE(managed_device_view->GetVisible());
   managed_device_view.reset();
 
@@ -85,7 +98,8 @@
   session->UpdateUserSession(std::move(user_session));
 
   // Now the UnifiedManagedDeviceView is visible.
-  managed_device_view = std::make_unique<UnifiedManagedDeviceView>();
+  managed_device_view =
+      std::make_unique<UnifiedManagedDeviceView>(controller.get());
   ASSERT_TRUE(managed_device_view->GetVisible());
 }
 
diff --git a/ash/system/unified/unified_system_tray_view.cc b/ash/system/unified/unified_system_tray_view.cc
index 2628b79..ab6be16 100644
--- a/ash/system/unified/unified_system_tray_view.cc
+++ b/ash/system/unified/unified_system_tray_view.cc
@@ -241,15 +241,16 @@
   system_tray_container_->AddChildView(feature_pods_container_);
   system_tray_container_->AddChildView(page_indicator_view_);
   system_tray_container_->AddChildView(sliders_container_);
+
+  if (features::IsManagedDeviceUIRedesignEnabled()) {
+    managed_device_view_ = new UnifiedManagedDeviceView(controller_);
+    add_layered_child(system_tray_container_, managed_device_view_);
+  }
+
   add_layered_child(system_tray_container_, system_info_view_);
 
   system_tray_container_->SetFlexForView(page_indicator_view_);
 
-  if (features::IsManagedDeviceUIRedesignEnabled()) {
-    managed_device_view_ = new UnifiedManagedDeviceView();
-    system_tray_container_->AddChildView(managed_device_view_);
-  }
-
   detailed_view_container_->SetVisible(false);
   add_layered_child(this, detailed_view_container_);
 
@@ -264,6 +265,10 @@
 void UnifiedSystemTrayView::SetMaxHeight(int max_height) {
   max_height_ = max_height;
 
+  int managed_device_view_height =
+      managed_device_view_ ? managed_device_view_->GetPreferredSize().height()
+                           : 0;
+
   // FeaturePodsContainer can adjust it's height by reducing the number of rows
   // it uses. It will calculate how many rows to use based on the max height
   // passed here.
@@ -271,7 +276,8 @@
       max_height - top_shortcuts_view_->GetPreferredSize().height() -
       page_indicator_view_->GetPreferredSize().height() -
       sliders_container_->GetExpandedHeight() -
-      system_info_view_->GetPreferredSize().height());
+      system_info_view_->GetPreferredSize().height() -
+      managed_device_view_height);
 }
 
 void UnifiedSystemTrayView::AddFeaturePodButton(FeaturePodButton* button) {
@@ -343,6 +349,9 @@
 }
 
 int UnifiedSystemTrayView::GetExpandedSystemTrayHeight() const {
+  int managed_device_view_height =
+      managed_device_view_ ? managed_device_view_->GetPreferredSize().height()
+                           : 0;
   return (notification_hidden_view_->GetVisible()
               ? notification_hidden_view_->GetPreferredSize().height()
               : 0) +
@@ -350,16 +359,21 @@
          feature_pods_container_->GetExpandedHeight() +
          page_indicator_view_->GetExpandedHeight() +
          sliders_container_->GetExpandedHeight() +
-         system_info_view_->GetPreferredSize().height();
+         system_info_view_->GetPreferredSize().height() +
+         managed_device_view_height;
 }
 
 int UnifiedSystemTrayView::GetCollapsedSystemTrayHeight() const {
+  int managed_device_view_height =
+      managed_device_view_ ? managed_device_view_->GetPreferredSize().height()
+                           : 0;
   return (notification_hidden_view_->GetVisible()
               ? notification_hidden_view_->GetPreferredSize().height()
               : 0) +
          top_shortcuts_view_->GetPreferredSize().height() +
          feature_pods_container_->GetCollapsedHeight() +
-         system_info_view_->GetPreferredSize().height();
+         system_info_view_->GetPreferredSize().height() +
+         managed_device_view_height;
 }
 
 int UnifiedSystemTrayView::GetCurrentHeight() const {
diff --git a/base/command_line.cc b/base/command_line.cc
index 57bd113..5f8bcdd 100644
--- a/base/command_line.cc
+++ b/base/command_line.cc
@@ -24,7 +24,7 @@
 #include <shellapi.h>
 
 #include "base/strings/string_util_win.h"
-#endif
+#endif  // defined(OS_WIN)
 
 namespace base {
 
@@ -49,6 +49,17 @@
 #endif
 size_t switch_prefix_count = base::size(kSwitchPrefixes);
 
+#if defined(OS_WIN)
+// Switch string that specifies the single argument to the command line.
+// If present, everything after this switch is interpreted as a single
+// argument regardless of whitespace, quotes, etc. Used for launches from the
+// Windows shell, which may have arguments with unencoded quotes that could
+// otherwise unexpectedly be split into multiple arguments
+// (https://crbug.com/937179).
+constexpr CommandLine::CharType kSingleArgument[] =
+    FILE_PATH_LITERAL("single-argument");
+#endif  // defined(OS_WIN)
+
 size_t GetSwitchPrefixLength(CommandLine::StringPieceType string) {
   for (size_t i = 0; i < switch_prefix_count; ++i) {
     CommandLine::StringType prefix(kSwitchPrefixes[i]);
@@ -89,46 +100,19 @@
          switch_key_without_prefix;
 }
 
-// Append switches and arguments, keeping switches before arguments.
-void AppendSwitchesAndArguments(CommandLine* command_line,
-                                const CommandLine::StringVector& argv) {
-  bool parse_switches = true;
-  for (size_t i = 1; i < argv.size(); ++i) {
-    CommandLine::StringType arg = argv[i];
 #if defined(OS_WIN)
-    arg = CommandLine::StringType(TrimWhitespace(arg, TRIM_ALL));
-#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
-    TrimWhitespaceASCII(arg, TRIM_ALL, &arg);
-#endif
+// Quote a string as necessary for CommandLineToArgvW compatibility *on
+// Windows*.
+std::wstring QuoteForCommandLineToArgvW(const std::wstring& arg) {
+  // Ensure that GetCommandLineString isn't used to generate command-line
+  // strings for the Windows shell by checking for Windows placeholders like
+  // "%1". GetCommandLineStringForShell should be used instead to get a string
+  // with the correct placeholder format for the shell.
+  DCHECK(arg.size() != 2 || arg[0] != L'%');
 
-    CommandLine::StringType switch_string;
-    CommandLine::StringType switch_value;
-    parse_switches &= (arg != kSwitchTerminator);
-    if (parse_switches && IsSwitch(arg, &switch_string, &switch_value)) {
-#if defined(OS_WIN)
-      command_line->AppendSwitchNative(WideToUTF8(switch_string), switch_value);
-#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
-      command_line->AppendSwitchNative(switch_string, switch_value);
-#else
-#error Unsupported platform
-#endif
-    } else {
-      command_line->AppendArgNative(arg);
-    }
-  }
-}
-
-#if defined(OS_WIN)
-// Quote a string as necessary for CommandLineToArgvW compatiblity *on Windows*.
-std::wstring QuoteForCommandLineToArgvW(const std::wstring& arg,
-                                        bool quote_placeholders) {
   // We follow the quoting rules of CommandLineToArgvW.
   // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
   std::wstring quotable_chars(L" \\\"");
-  // We may also be required to quote '%', which is commonly used in a command
-  // line as a placeholder. (It may be substituted for a string with spaces.)
-  if (quote_placeholders)
-    quotable_chars.push_back('%');
   if (arg.find_first_of(quotable_chars) == std::wstring::npos) {
     // No quoting necessary.
     return arg;
@@ -166,7 +150,7 @@
 
   return out;
 }
-#endif
+#endif  // defined(OS_WIN)
 
 }  // namespace
 
@@ -218,7 +202,7 @@
     argv_vector.push_back(UTF8ToWide(argv[i]));
   current_process_commandline_->InitFromArgv(argv_vector);
 }
-#endif
+#endif  // defined(OS_WIN)
 
 // static
 bool CommandLine::Init(int argc, const char* const* argv) {
@@ -266,7 +250,7 @@
   cmd.ParseFromString(command_line);
   return cmd;
 }
-#endif
+#endif  // defined(OS_WIN)
 
 void CommandLine::InitFromArgv(int argc,
                                const CommandLine::CharType* const* argv) {
@@ -281,7 +265,7 @@
   switches_.clear();
   begin_args_ = 1;
   SetProgram(argv.empty() ? FilePath() : FilePath(argv[0]));
-  AppendSwitchesAndArguments(this, argv);
+  AppendSwitchesAndArguments(argv);
 }
 
 FilePath CommandLine::GetProgram() const {
@@ -457,7 +441,7 @@
                                   bool include_program) {
   if (include_program)
     SetProgram(other.GetProgram());
-  AppendSwitchesAndArguments(this, other.argv());
+  AppendSwitchesAndArguments(other.argv());
 }
 
 void CommandLine::PrependWrapper(const CommandLine::StringType& wrapper) {
@@ -482,6 +466,7 @@
   command_line = TrimWhitespace(command_line, TRIM_ALL);
   if (command_line.empty())
     return;
+  raw_command_line_string_ = command_line;
 
   int num_args = 0;
   wchar_t** args = NULL;
@@ -506,20 +491,56 @@
                          << command_line;
   StringVector argv(args, args + num_args);
   InitFromArgv(argv);
+  raw_command_line_string_ = StringPieceType();
   LocalFree(args);
 
   if (downlevel_shell32_dll)
     ::FreeLibrary(downlevel_shell32_dll);
 }
+#endif  // defined(OS_WIN)
+
+void CommandLine::AppendSwitchesAndArguments(
+    const CommandLine::StringVector& argv) {
+  bool parse_switches = true;
+#if defined(OS_WIN)
+  const bool is_parsed_from_string = !raw_command_line_string_.empty();
+#endif
+  for (size_t i = 1; i < argv.size(); ++i) {
+    CommandLine::StringType arg = argv[i];
+#if defined(OS_WIN)
+    arg = CommandLine::StringType(TrimWhitespace(arg, TRIM_ALL));
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+    TrimWhitespaceASCII(arg, TRIM_ALL, &arg);
 #endif
 
-CommandLine::StringType CommandLine::GetCommandLineStringInternal(
-    bool quote_placeholders) const {
+    CommandLine::StringType switch_string;
+    CommandLine::StringType switch_value;
+    parse_switches &= (arg != kSwitchTerminator);
+    if (parse_switches && IsSwitch(arg, &switch_string, &switch_value)) {
+#if defined(OS_WIN)
+      if (is_parsed_from_string &&
+          IsSwitchWithKey(switch_string, kSingleArgument)) {
+        ParseAsSingleArgument(switch_string);
+        return;
+      }
+      AppendSwitchNative(WideToUTF8(switch_string), switch_value);
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+      AppendSwitchNative(switch_string, switch_value);
+#else
+#error Unsupported platform
+#endif
+    } else {
+      AppendArgNative(arg);
+    }
+  }
+}
+
+CommandLine::StringType CommandLine::GetCommandLineString() const {
   StringType string(argv_[0]);
 #if defined(OS_WIN)
-  string = QuoteForCommandLineToArgvW(string, quote_placeholders);
+  string = QuoteForCommandLineToArgvW(string);
 #endif
-  StringType params(GetArgumentsStringInternal(quote_placeholders));
+  StringType params(GetArgumentsString());
   if (!params.empty()) {
     string.append(FILE_PATH_LITERAL(" "));
     string.append(params);
@@ -527,8 +548,24 @@
   return string;
 }
 
-CommandLine::StringType CommandLine::GetArgumentsStringInternal(
-    bool quote_placeholders) const {
+#if defined(OS_WIN)
+// NOTE: this function is used to set Chrome's open command in the registry
+// during update. Any change to the syntax must be compatible with the prior
+// version (i.e., any new syntax must be understood by older browsers expecting
+// the old syntax, and the new browser must still handle the old syntax), as
+// old versions are likely to persist, e.g., immediately after background
+// update, when parsing command lines for other channels, when uninstalling web
+// applications installed using the old syntax, etc.
+CommandLine::StringType CommandLine::GetCommandLineStringForShell() const {
+  DCHECK(GetArgs().empty());
+  StringType command_line_string = GetCommandLineString();
+  return command_line_string + FILE_PATH_LITERAL(" ") +
+         kSwitchPrefixes[0].as_string() + kSingleArgument +
+         FILE_PATH_LITERAL(" %1");
+}
+#endif  // defined(OS_WIN)
+
+CommandLine::StringType CommandLine::GetArgumentsString() const {
   StringType params;
   // Append switches and arguments.
   bool parse_switches = true;
@@ -543,14 +580,13 @@
       params.append(switch_string);
       if (!switch_value.empty()) {
 #if defined(OS_WIN)
-        switch_value =
-            QuoteForCommandLineToArgvW(switch_value, quote_placeholders);
+        switch_value = QuoteForCommandLineToArgvW(switch_value);
 #endif
         params.append(kSwitchValueSeparator + switch_value);
       }
     } else {
 #if defined(OS_WIN)
-      arg = QuoteForCommandLineToArgvW(arg, quote_placeholders);
+      arg = QuoteForCommandLineToArgvW(arg);
 #endif
       params.append(arg);
     }
@@ -558,4 +594,33 @@
   return params;
 }
 
+#if defined(OS_WIN)
+void CommandLine::ParseAsSingleArgument(
+    const CommandLine::StringType& single_arg_switch) {
+  DCHECK(!raw_command_line_string_.empty());
+
+  // Remove any previously parsed arguments.
+  argv_.resize(begin_args_);
+
+  // Locate "--single-argument" in the process's raw command line. Results are
+  // unpredictable if "--single-argument" appears as part of a previous
+  // argument or switch.
+  const size_t single_arg_switch_position =
+      raw_command_line_string_.find(single_arg_switch);
+  DCHECK_NE(single_arg_switch_position, StringType::npos);
+
+  // Append the portion of the raw command line that starts one character past
+  // "--single-argument" as the one and only argument, or return if no
+  // argument is present.
+  const size_t arg_position =
+      single_arg_switch_position + single_arg_switch.length() + 1;
+  if (arg_position >= raw_command_line_string_.length())
+    return;
+  const StringPieceType arg = raw_command_line_string_.substr(arg_position);
+  if (!arg.empty()) {
+    AppendArgNative(arg.as_string());
+  }
+}
+#endif  // defined(OS_WIN)
+
 }  // namespace base
diff --git a/base/command_line.h b/base/command_line.h
index 00388e7..2267baa 100644
--- a/base/command_line.h
+++ b/base/command_line.h
@@ -112,41 +112,27 @@
   // Constructs and returns the represented command line string.
   // CAUTION! This should be avoided on POSIX because quoting behavior is
   // unclear.
-  StringType GetCommandLineString() const {
-    return GetCommandLineStringInternal(false);
-  }
+  // CAUTION! If writing a command line to the Windows registry, use
+  // GetCommandLineStringForShell() instead.
+  StringType GetCommandLineString() const;
 
 #if defined(OS_WIN)
-  // Constructs and returns the represented command line string. Assumes the
-  // command line contains placeholders (eg, %1) and quotes any program or
-  // argument with a '%' in it. This should be avoided unless the placeholder is
-  // required by an external interface (eg, the Windows registry), because it is
-  // not generally safe to replace it with an arbitrary string. If possible,
-  // placeholders should be replaced *before* converting the command line to a
-  // string.
-  StringType GetCommandLineStringWithPlaceholders() const {
-    return GetCommandLineStringInternal(true);
-  }
+  // Returns the command-line string in the proper format for the Windows shell,
+  // ending with the argument placeholder "--single-argument %1". The single-
+  // argument switch prevents unexpected parsing of arguments from other
+  // software that cannot be trusted to escape double quotes when substituting
+  // into a placeholder (e.g., "%1" placeholders populated by the Windows
+  // shell).
+  // NOTE: this must be used to generate the command-line string for the shell
+  // even if this command line was parsed from a string with the proper syntax,
+  // because the --single-argument switch is not preserved during parsing.
+  StringType GetCommandLineStringForShell() const;
 #endif
 
   // Constructs and returns the represented arguments string.
   // CAUTION! This should be avoided on POSIX because quoting behavior is
   // unclear.
-  StringType GetArgumentsString() const {
-    return GetArgumentsStringInternal(false);
-  }
-
-#if defined(OS_WIN)
-  // Constructs and returns the represented arguments string. Assumes the
-  // command line contains placeholders (eg, %1) and quotes any argument with a
-  // '%' in it. This should be avoided unless the placeholder is required by an
-  // external interface (eg, the Windows registry), because it is not generally
-  // safe to replace it with an arbitrary string. If possible, placeholders
-  // should be replaced *before* converting the arguments to a string.
-  StringType GetArgumentsStringWithPlaceholders() const {
-    return GetArgumentsStringInternal(true);
-  }
-#endif
+  StringType GetArgumentsString() const;
 
   // Returns the original command line string as a vector of strings.
   const StringVector& argv() const { return argv_; }
@@ -226,13 +212,26 @@
   //   CommandLine cl(*CommandLine::ForCurrentProcess());
   //   cl.AppendSwitch(...);
 
-  // Internal version of GetCommandLineString. If |quote_placeholders| is true,
-  // also quotes parts with '%' in them.
-  StringType GetCommandLineStringInternal(bool quote_placeholders) const;
+  // Append switches and arguments, keeping switches before arguments.
+  void AppendSwitchesAndArguments(const StringVector& argv);
 
-  // Internal version of GetArgumentsString. If |quote_placeholders| is true,
-  // also quotes parts with '%' in them.
-  StringType GetArgumentsStringInternal(bool quote_placeholders) const;
+#if defined(OS_WIN)
+  // Initializes by parsing |raw_command_line_string_|, treating everything
+  // after |single_arg_switch_string| + <a single character> as the command
+  // line's single argument, and dropping any arguments previously parsed. The
+  // command line must contain |single_arg_switch_string|, and the argument, if
+  // present, must be separated from |single_arg_switch_string| by one
+  // character.
+  // NOTE: the single-argument switch is not preserved after parsing;
+  // GetCommandLineStringForShell() must be used to reproduce the original
+  // command-line string with single-argument switch.
+  void ParseAsSingleArgument(const StringType& single_arg_switch_string);
+
+  // The string returned by GetCommandLineW(), to be parsed via
+  // ParseFromString(). Empty if this command line was not parsed from a string,
+  // or if ParseFromString() has finished executing.
+  StringPieceType raw_command_line_string_;
+#endif
 
   // The singleton CommandLine representing the current process's command line.
   static CommandLine* current_process_commandline_;
diff --git a/base/command_line_unittest.cc b/base/command_line_unittest.cc
index 7285451..3077edd 100644
--- a/base/command_line_unittest.cc
+++ b/base/command_line_unittest.cc
@@ -195,27 +195,23 @@
   static const char kSecondArgName[] = "arg2";
   static const char kThirdArgName[] = "arg with space";
   static const char kFourthArgName[] = "nospace";
-  static const char kFifthArgName[] = "%1";
 
   CommandLine cl(CommandLine::NO_PROGRAM);
   cl.AppendSwitchPath(kFirstArgName, FilePath(kPath1));
   cl.AppendSwitchPath(kSecondArgName, FilePath(kPath2));
   cl.AppendArg(kThirdArgName);
   cl.AppendArg(kFourthArgName);
-  cl.AppendArg(kFifthArgName);
 
 #if defined(OS_WIN)
   CommandLine::StringType expected_first_arg(UTF8ToWide(kFirstArgName));
   CommandLine::StringType expected_second_arg(UTF8ToWide(kSecondArgName));
   CommandLine::StringType expected_third_arg(UTF8ToWide(kThirdArgName));
   CommandLine::StringType expected_fourth_arg(UTF8ToWide(kFourthArgName));
-  CommandLine::StringType expected_fifth_arg(UTF8ToWide(kFifthArgName));
 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
   CommandLine::StringType expected_first_arg(kFirstArgName);
   CommandLine::StringType expected_second_arg(kSecondArgName);
   CommandLine::StringType expected_third_arg(kThirdArgName);
   CommandLine::StringType expected_fourth_arg(kFourthArgName);
-  CommandLine::StringType expected_fifth_arg(kFifthArgName);
 #endif
 
 #if defined(OS_WIN)
@@ -243,21 +239,8 @@
       .append(expected_third_arg)
       .append(QUOTE_ON_WIN)
       .append(FILE_PATH_LITERAL(" "))
-      .append(expected_fourth_arg)
-      .append(FILE_PATH_LITERAL(" "));
-
-  CommandLine::StringType expected_str_no_quote_placeholders(expected_str);
-  expected_str_no_quote_placeholders.append(expected_fifth_arg);
-  EXPECT_EQ(expected_str_no_quote_placeholders, cl.GetArgumentsString());
-
-#if defined(OS_WIN)
-  CommandLine::StringType expected_str_quote_placeholders(expected_str);
-  expected_str_quote_placeholders.append(QUOTE_ON_WIN)
-      .append(expected_fifth_arg)
-      .append(QUOTE_ON_WIN);
-  EXPECT_EQ(expected_str_quote_placeholders,
-            cl.GetArgumentsStringWithPlaceholders());
-#endif
+      .append(expected_fourth_arg);
+  EXPECT_EQ(expected_str, cl.GetArgumentsString());
 }
 
 // Test methods for appending switches to a command line.
@@ -329,6 +312,16 @@
  EXPECT_EQ(FILE_PATH_LITERAL("--arg2"), cl_argv[5]);
 }
 
+#if defined(OS_WIN)
+TEST(CommandLineTest, GetCommandLineStringForShell) {
+  CommandLine cl = CommandLine::FromString(
+      FILE_PATH_LITERAL("program --switch /switch2 --"));
+  EXPECT_EQ(
+      cl.GetCommandLineStringForShell(),
+      FILE_PATH_LITERAL("program --switch /switch2 -- --single-argument %1"));
+}
+#endif  // defined(OS_WIN)
+
 // Tests that when AppendArguments is called that the program is set correctly
 // on the target CommandLine object and the switches from the source
 // CommandLine are added to the target.
@@ -373,12 +366,6 @@
   // Check that quotes are added to command line string paths containing spaces.
   CommandLine::StringType cmd_string(cl_program_path.GetCommandLineString());
   EXPECT_EQ(L"\"Program Path\"", cmd_string);
-
-  // Check the optional quoting of placeholders in programs.
-  CommandLine cl_quote_placeholder(FilePath(L"%1"));
-  EXPECT_EQ(L"%1", cl_quote_placeholder.GetCommandLineString());
-  EXPECT_EQ(L"\"%1\"",
-            cl_quote_placeholder.GetCommandLineStringWithPlaceholders());
 }
 #endif
 
@@ -577,4 +564,26 @@
   EXPECT_EQ("two", cl.GetSwitchValueASCII("foo"));
 }
 
+#if defined(OS_WIN)
+TEST(CommandLineTest, ParseAsSingleArgument) {
+  CommandLine cl = CommandLine::FromString(
+      FILE_PATH_LITERAL("program --switch_before arg_before "
+                        "--single-argument arg with spaces \"and quotes\" \""));
+
+  EXPECT_FALSE(cl.GetCommandLineString().empty());
+  EXPECT_EQ(FilePath(FILE_PATH_LITERAL("program")), cl.GetProgram());
+  EXPECT_TRUE(cl.HasSwitch("switch_before"));
+  EXPECT_EQ(cl.GetArgs(), CommandLine::StringVector({FILE_PATH_LITERAL(
+                              "arg with spaces \"and quotes\" \"")}));
+
+  CommandLine cl_without_arg =
+      CommandLine::FromString(FILE_PATH_LITERAL("program --single-argument "));
+
+  EXPECT_FALSE(cl_without_arg.GetCommandLineString().empty());
+  EXPECT_EQ(FilePath(FILE_PATH_LITERAL("program")),
+            cl_without_arg.GetProgram());
+  EXPECT_TRUE(cl_without_arg.GetArgs().empty());
+}
+#endif  // defined(OS_WIN)
+
 } // namespace base
diff --git a/base/feature_list.cc b/base/feature_list.cc
index 770c7bd..7821f3e0 100644
--- a/base/feature_list.cc
+++ b/base/feature_list.cc
@@ -199,20 +199,6 @@
     const std::string& disable_features) {
   DCHECK(!initialized_);
 
-  // Process disabled features first, so that disabled ones take precedence over
-  // enabled ones (since RegisterOverride() uses insert()).
-  RegisterOverridesFromCommandLine(disable_features, OVERRIDE_DISABLE_FEATURE);
-  RegisterOverridesFromCommandLine(enable_features, OVERRIDE_ENABLE_FEATURE);
-
-  initialized_from_command_line_ = true;
-}
-
-void FeatureList::InitializeFromCommandLineWithFeatureParams(
-    const std::string& enable_features,
-    const std::string& disable_features,
-    FieldTrialParamsDecodeStringFunc decode_data_func) {
-  DCHECK(!initialized_);
-
   std::string parsed_enable_features;
   std::string force_fieldtrials;
   std::string force_fieldtrial_params;
@@ -222,20 +208,32 @@
   DCHECK(parse_enable_features_result) << StringPrintf(
       "The --%s list is unparsable or invalid, please check the format.",
       ::switches::kEnableFeatures);
-  bool associate_params_result = AssociateFieldTrialParamsFromString(
-      force_fieldtrial_params, decode_data_func);
-  DCHECK(associate_params_result) << StringPrintf(
-      "The field trial parameters part of the --%s list is invalid. Make sure "
-      "you %%-encode the following characters in param values: %%:/.,",
-      ::switches::kEnableFeatures);
 
-  bool create_trials_result =
-      FieldTrialList::CreateTrialsFromString(force_fieldtrials);
-  DCHECK(create_trials_result)
-      << StringPrintf("Invalid field trials are specified in --%s.",
-                      ::switches::kEnableFeatures);
+  // Only create field trials when field_trial_list is available. Some tests
+  // don't have field trial list available.
+  if (FieldTrialList::GetInstance()) {
+    bool associate_params_result = AssociateFieldTrialParamsFromString(
+        force_fieldtrial_params, &UnescapeValue);
+    DCHECK(associate_params_result) << StringPrintf(
+        "The field trial parameters part of the --%s list is invalid. Make "
+        "sure "
+        "you %%-encode the following characters in param values: %%:/.,",
+        ::switches::kEnableFeatures);
 
-  InitializeFromCommandLine(parsed_enable_features, disable_features);
+    bool create_trials_result =
+        FieldTrialList::CreateTrialsFromString(force_fieldtrials);
+    DCHECK(create_trials_result)
+        << StringPrintf("Invalid field trials are specified in --%s.",
+                        ::switches::kEnableFeatures);
+  }
+
+  // Process disabled features first, so that disabled ones take precedence over
+  // enabled ones (since RegisterOverride() uses insert()).
+  RegisterOverridesFromCommandLine(disable_features, OVERRIDE_DISABLE_FEATURE);
+  RegisterOverridesFromCommandLine(parsed_enable_features,
+                                   OVERRIDE_ENABLE_FEATURE);
+
+  initialized_from_command_line_ = true;
 }
 
 void FeatureList::InitializeFromSharedMemory(
@@ -461,11 +459,6 @@
   g_feature_list_instance = instance.release();
 }
 
-// static
-std::string FeatureList::NoOpDecodeFunc(const std::string& str) {
-  return str;
-}
-
 void FeatureList::FinalizeInitialization() {
   DCHECK(!initialized_);
   // Store the field trial list pointer for DCHECKing.
diff --git a/base/feature_list.h b/base/feature_list.h
index 40ebacd..57cd529 100644
--- a/base/feature_list.h
+++ b/base/feature_list.h
@@ -130,23 +130,10 @@
 
   // Initializes feature overrides via command-line flags |enable_features| and
   // |disable_features|, each of which is a comma-separated list of features to
-  // enable or disable, respectively. If a feature appears on both lists, then
-  // it will be disabled. If a list entry has the format "FeatureName<TrialName"
-  // then this initialization will also associate the feature state override
-  // with the named field trial, if it exists. If a feature name is prefixed
-  // with the '*' character, it will be created with OVERRIDE_USE_DEFAULT -
-  // which is useful for associating with a trial while using the default state.
-  // Must only be invoked during the initialization phase (before
-  // FinalizeInitialization() has been called).
-  void InitializeFromCommandLine(const std::string& enable_features,
-                                 const std::string& disable_features);
-
-  // Initializes feature overrides via command-line flags |enable_features| and
-  // |disable_features|, each of which is a comma-separated list of features to
   // enable or disable, respectively. This function also allows users to set
-  // feature's field trial params via |enable_features|. |decode_data_func|
-  // allows specifying a custom decoding function. Must only be invoked during
-  // the initialization phase (before FinalizeInitialization() has been called).
+  // feature's field trial params via |enable_features|. Must only be invoked
+  // during the initialization phase (before FinalizeInitialization() has been
+  // called).
   //
   // If a feature appears on both lists, then it will be disabled. If
   // a list entry has the format "FeatureName<TrialName" then this
@@ -162,10 +149,8 @@
   // If a feature name is prefixed with the '*' character, it will be created
   // with OVERRIDE_USE_DEFAULT - which is useful for associating with a trial
   // while using the default state.
-  void InitializeFromCommandLineWithFeatureParams(
-      const std::string& enable_features,
-      const std::string& disable_features,
-      FieldTrialParamsDecodeStringFunc decode_data_func);
+  void InitializeFromCommandLine(const std::string& enable_features,
+                                 const std::string& disable_features);
 
   // Initializes feature overrides through the field trial allocator, which
   // we're using to store the feature names, their override state, and the name
@@ -279,10 +264,6 @@
   // to support base::test::ScopedFeatureList helper class.
   static void RestoreInstanceForTesting(std::unique_ptr<FeatureList> instance);
 
-  // TODO(crbug.com/1068052): Port the UnescapeValue function and cleanup this.
-  // A no-op function that takes a string and returns it.
-  static std::string NoOpDecodeFunc(const std::string& str);
-
  private:
   FRIEND_TEST_ALL_PREFIXES(FeatureListTest, CheckFeatureIdentity);
   FRIEND_TEST_ALL_PREFIXES(FeatureListTest,
diff --git a/base/feature_list_unittest.cc b/base/feature_list_unittest.cc
index c2eb464..75e6faa 100644
--- a/base/feature_list_unittest.cc
+++ b/base/feature_list_unittest.cc
@@ -119,8 +119,7 @@
     SCOPED_TRACE(test_case.enable_features);
 
     auto feature_list = std::make_unique<FeatureList>();
-    feature_list->InitializeFromCommandLineWithFeatureParams(
-        test_case.enable_features, "", &FeatureList::NoOpDecodeFunc);
+    feature_list->InitializeFromCommandLine(test_case.enable_features, "");
     test::ScopedFeatureList scoped_feature_list;
     scoped_feature_list.InitWithFeatureList(std::move(feature_list));
 
diff --git a/base/metrics/field_trial_params.cc b/base/metrics/field_trial_params.cc
index b300aee..2f985c94 100644
--- a/base/metrics/field_trial_params.cc
+++ b/base/metrics/field_trial_params.cc
@@ -11,12 +11,19 @@
 #include "base/feature_list.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/field_trial_param_associator.h"
+#include "base/strings/escape.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/stringprintf.h"
 
 namespace base {
 
+std::string UnescapeValue(const std::string& value) {
+  return UnescapeURLComponent(
+      value, UnescapeRule::PATH_SEPARATORS |
+                 UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS);
+}
+
 bool AssociateFieldTrialParams(const std::string& trial_name,
                                const std::string& group_name,
                                const FieldTrialParams& params) {
diff --git a/base/metrics/field_trial_params.h b/base/metrics/field_trial_params.h
index 6ccbe308f..c44e719 100644
--- a/base/metrics/field_trial_params.h
+++ b/base/metrics/field_trial_params.h
@@ -23,6 +23,11 @@
 // Param string decoding function for AssociateFieldTrialParamsFromString().
 typedef std::string (*FieldTrialParamsDecodeStringFunc)(const std::string& str);
 
+// Unescapes special characters from the given string. Used in
+// AssociateFieldTrialParamsFromString() as one of the feature params decoding
+// functions.
+BASE_EXPORT std::string UnescapeValue(const std::string& value);
+
 // Associates the specified set of key-value |params| with the field trial
 // specified by |trial_name| and |group_name|. Fails and returns false if the
 // specified field trial already has params associated with it or the trial
diff --git a/base/path_service.cc b/base/path_service.cc
index 4c0f5858..59558a1 100644
--- a/base/path_service.cc
+++ b/base/path_service.cc
@@ -15,6 +15,7 @@
 #include "base/check_op.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
+#include "base/logging.h"
 #include "base/synchronization/lock.h"
 #include "build/build_config.h"
 
@@ -231,7 +232,7 @@
 
 FilePath PathService::CheckedGet(int key) {
   FilePath path;
-  CHECK(Get(key, &path));
+  LOG_IF(FATAL, !Get(key, &path)) << "Failed to get the path for " << key;
   return path;
 }
 
diff --git a/base/path_service_unittest.cc b/base/path_service_unittest.cc
index c1a4604..cebd7b0 100644
--- a/base/path_service_unittest.cc
+++ b/base/path_service_unittest.cc
@@ -157,7 +157,7 @@
   constexpr int kBadKey = PATH_END;
   FilePath path;
   EXPECT_FALSE(PathService::Get(kBadKey, &path));
-  EXPECT_CHECK_DEATH(PathService::CheckedGet(kBadKey));
+  EXPECT_DEATH(PathService::CheckedGet(kBadKey), "Failed to get the path");
 }
 
 #endif  // GTEST_HAS_DEATH_TEST
diff --git a/base/task/post_job.cc b/base/task/post_job.cc
index 210ed57b..bc74e242 100644
--- a/base/task/post_job.cc
+++ b/base/task/post_job.cc
@@ -99,10 +99,13 @@
   // Case 2b:
   const bool updated = task_source_->WaitForConcurrencyIncreaseUpdate(
       recorded_increase_version_);
-  DCHECK(updated ||
-         task_source_->GetMaxConcurrency() <= expected_max_concurrency)
-      << "Value returned by |max_concurrency_callback| is expected to "
-         "decrease, unless NotifyConcurrencyIncrease() is called.";
+  const size_t max_concurrency = task_source_->GetMaxConcurrency();
+  DCHECK(updated || max_concurrency <= expected_max_concurrency)
+      << "Value returned by |max_concurrency_callback| (" << max_concurrency
+      << ") is expected to decrease below or equal to "
+      << expected_max_concurrency
+      << ", unless NotifyConcurrencyIncrease() is called."
+      << "Last ShouldYield() returned " << last_should_yield_;
 
   recorded_increase_version_ = task_source_->GetConcurrencyIncreaseVersion();
   recorded_max_concurrency_ = task_source_->GetMaxConcurrency();
diff --git a/base/test/scoped_feature_list.cc b/base/test/scoped_feature_list.cc
index 5d03522..dd3dd0e 100644
--- a/base/test/scoped_feature_list.cc
+++ b/base/test/scoped_feature_list.cc
@@ -179,8 +179,7 @@
     const std::string& enable_features,
     const std::string& disable_features) {
   std::unique_ptr<FeatureList> feature_list(new FeatureList);
-  feature_list->InitializeFromCommandLineWithFeatureParams(
-      enable_features, disable_features, &FeatureList::NoOpDecodeFunc);
+  feature_list->InitializeFromCommandLine(enable_features, disable_features);
   InitWithFeatureList(std::move(feature_list));
 }
 
diff --git a/base/util/type_safety/BUILD.gn b/base/util/type_safety/BUILD.gn
index 88c98b4..fad9896 100644
--- a/base/util/type_safety/BUILD.gn
+++ b/base/util/type_safety/BUILD.gn
@@ -13,7 +13,10 @@
     "id_type.h",
     "pass_key.h",
     "strong_alias.h",
+    "token_type.h",
   ]
+
+  deps = [ "//base" ]
 }
 
 source_set("tests") {
@@ -22,6 +25,7 @@
     "id_type_unittest.cc",
     "pass_key_unittest.cc",
     "strong_alias_unittest.cc",
+    "token_type_unittest.cc",
   ]
 
   deps = [
diff --git a/base/util/type_safety/DEPS b/base/util/type_safety/DEPS
index 22f5998..e49329d 100644
--- a/base/util/type_safety/DEPS
+++ b/base/util/type_safety/DEPS
@@ -1,5 +1,6 @@
 include_rules = [
   "-base",
+  "+base/unguessable_token.h",
   "+base/util/type_safety",
   "-third_party",
 ]
diff --git a/base/util/type_safety/strong_alias.h b/base/util/type_safety/strong_alias.h
index 9c49b777..ea939282 100644
--- a/base/util/type_safety/strong_alias.h
+++ b/base/util/type_safety/strong_alias.h
@@ -63,6 +63,8 @@
 //   using StrongAlias<Tag, bool> instead of a bare bool.
 // - util::IdType<...> which provides helpers for specializing
 //   StrongAlias to be used as an id.
+// - util::TokenType<...> which provides helpers for specializing StrongAlias
+//   to be used as a wrapper of base::UnguessableToken.
 template <typename TagType, typename UnderlyingType>
 class StrongAlias {
  public:
diff --git a/base/util/type_safety/token_type.h b/base/util/type_safety/token_type.h
new file mode 100644
index 0000000..9ba8bfb3
--- /dev/null
+++ b/base/util/type_safety/token_type.h
@@ -0,0 +1,47 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_UTIL_TYPE_SAFETY_TOKEN_TYPE_H_
+#define BASE_UTIL_TYPE_SAFETY_TOKEN_TYPE_H_
+
+#include "base/unguessable_token.h"
+#include "base/util/type_safety/strong_alias.h"
+
+namespace util {
+
+// A specialization of StrongAlias for base::UnguessableToken.
+template <typename TypeMarker>
+class TokenType : public StrongAlias<TypeMarker, base::UnguessableToken> {
+ public:
+  // Inherit constructors.
+  using StrongAlias<TypeMarker, base::UnguessableToken>::StrongAlias;
+
+  // This object allows default assignment operators for compatibility with
+  // STL containers.
+
+  // Hash functor for use in unordered containers.
+  struct Hasher {
+    using argument_type = TokenType;
+    using result_type = size_t;
+    result_type operator()(const argument_type& token) const {
+      return base::UnguessableTokenHash()(token.value());
+    }
+  };
+
+  // Mimic the base::UnguessableToken API for ease and familiarity of use.
+  static TokenType Create() {
+    return TokenType(base::UnguessableToken::Create());
+  }
+  static const TokenType& Null() {
+    static const TokenType kNull;
+    return kNull;
+  }
+  bool is_empty() const { return this->value().is_empty(); }
+  std::string ToString() const { return this->value().ToString(); }
+  explicit constexpr operator bool() const { return !is_empty(); }
+};
+
+}  // namespace util
+
+#endif  // BASE_UTIL_TYPE_SAFETY_TOKEN_TYPE_H_
diff --git a/base/util/type_safety/token_type_unittest.cc b/base/util/type_safety/token_type_unittest.cc
new file mode 100644
index 0000000..ccd04bfa
--- /dev/null
+++ b/base/util/type_safety/token_type_unittest.cc
@@ -0,0 +1,55 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/util/type_safety/token_type.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace util {
+
+using FooToken = TokenType<class Foo>;
+
+TEST(TokenType, TokenApi) {
+  // Test static builders.
+  EXPECT_TRUE(FooToken::Null().is_empty());
+  EXPECT_FALSE(FooToken::Create().is_empty());
+
+  // Test default initialization.
+  FooToken token1;
+  EXPECT_TRUE(token1.is_empty());
+
+  // Test copy construction.
+  FooToken token2(FooToken::Create());
+  EXPECT_FALSE(token2.is_empty());
+
+  // Test assignment.
+  FooToken token3;
+  EXPECT_TRUE(token3.is_empty());
+  token3 = token2;
+  EXPECT_FALSE(token3.is_empty());
+
+  // Test bool conversion.
+  EXPECT_FALSE(token1);
+  EXPECT_TRUE(token2);
+  EXPECT_TRUE(token3);
+
+  // Test comparison operators.
+  EXPECT_TRUE(token1 == FooToken::Null());
+  EXPECT_FALSE(token1 == token2);
+  EXPECT_TRUE(token2 == token3);
+  EXPECT_FALSE(token1 != FooToken::Null());
+  EXPECT_TRUE(token1 != token2);
+  EXPECT_FALSE(token2 != token3);
+  EXPECT_TRUE(token1 < token2);
+  EXPECT_FALSE(token2 < token3);
+
+  // Test hasher.
+  EXPECT_EQ(FooToken::Hasher()(token2),
+            base::UnguessableTokenHash()(token2.value()));
+
+  // Test string representation.
+  EXPECT_EQ(token2.ToString(), token2.value().ToString());
+}
+
+}  // namespace util
diff --git a/build/android/lint/suppressions.xml b/build/android/lint/suppressions.xml
index 8df4a852..68767ac8 100644
--- a/build/android/lint/suppressions.xml
+++ b/build/android/lint/suppressions.xml
@@ -376,19 +376,10 @@
     <ignore regexp="android_webview/test/shell/res/raw/resource_file.html"/>
     <ignore regexp="android_webview/test/shell/res/raw/resource_icon.png"/>
     <ignore regexp="android_webview/tools/automated_ui_tests/java/res/layout/"/>
-    <!-- TODO(crbug.com/1017190): Remove the following 11 suppressions once we lint entire app rather
-         than each individual target -->
-    <ignore regexp="components/browser_ui/strings/android/browser_ui_strings_grd"/>
-    <ignore regexp="chrome/browser/download/android/java/res"/>
-    <ignore regexp="The resource `R.drawable.ic_file_download_36dp` appears to be unused"/>
-    <ignore regexp="The resource `R.drawable.ic_play_arrow_white_24dp` appears to be unused"/>
-    <ignore regexp="chrome/browser/ui/android/strings/ui_strings_grd"/>
-    <ignore regexp="The resource `R.drawable.*_expand_.*` appears to be unused"/>
-    <ignore regexp="The resource `R.drawable.btn_close` appears to be unused"/>
-    <ignore regexp="The resource `R.drawable.ic_more_vert_24dp_on_dark_bg` appears to be unused"/>
-    <ignore regexp="The resource `R.layout.permission_dialog` appears to be unused"/>
-    <ignore regexp="components/browser_ui/styles/android/java/res"/>
-    <ignore regexp="components/permissions/android/res/drawable"/>
+    <!-- 3: WebView uses some //components/browser_ui resources, but not all (crbug.com/1099842). -->
+    <ignore regexp="components/browser_ui/styles/"/>
+    <ignore regexp="components/browser_ui/widget/"/>
+    <ignore regexp="webview_.*__lint.*components/browser_ui/strings/android/browser_ui_strings_grd"/>
     <!-- 1 resource used by android tv to generate resources.zip file -->
     <ignore regexp="chromecast/internal/shell/browser/android/java/res/drawable-hdpi/ic_settings_cast.png"/>
     <!-- 1 string used by Android's policies system, pulled from app directly -->
@@ -407,7 +398,7 @@
     <ignore regexp="components/page_info/android/java/res/drawable-hdpi/pageinfo_*"/>
     <!--TODO(crbug.com/1052375): Remove this suppression once PermissionParamsListBuilder moves to components.-->
     <ignore regexp="The resource `R.string.page_info_permission_ads_subtitle` appears to be unused"/>
-    <!--TODO(crbug.com/1069186): The following 12 are found when we switched to linting the entire app. -->
+    <!--TODO(crbug.com/1069186): The following 14 are found when we switched to linting the entire app. -->
     <ignore regexp="The resource `R.string.download_manager_ui_documents` appears to be unused"/>
     <ignore regexp="The resource `R.string.download_manager_offline_home` appears to be unused"/>
     <ignore regexp="The resource `R.string.ntp_learn_more_about_suggested_content` appears to be unused"/>
@@ -425,6 +416,8 @@
     <ignore regexp="The resource `R.plurals.public_notification_text` appears to be unused"/>
     <ignore regexp="The resource `R.mipmap.app_shortcut_icon` appears to be unused"/>
     <ignore regexp="The resource `R.mipmap.app_single_page_icon` appears to be unused"/>
+    <ignore regexp="The resource `R.string.app_banner_install` appears to be unused"/>
+    <ignore regexp="The resource `R.string.iph_download_indicator_text` appears to be unused"/>
     <!-- 1: Some strings in components_strings_grd are not used in other targets. -->
     <ignore regexp="webview_.*__lint.*components_strings_grd"/>
     <!-- Endnote: Please specify number of suppressions when adding more -->
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index 3340f33..d8de047 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -863,7 +863,6 @@
         executable_args += [
           "--coverage-dir",
           "@WrappedPath(${_rebased_coverage_dir})",
-          "--coverage-on-the-fly",
         ]
       }
     } else if (_test_type == "linker") {
@@ -1840,7 +1839,14 @@
 
     # Create the .jar in lib.java for use by java_binary.
     if (defined(invoker.host_jar_path)) {
-      filter_jar("${target_name}_host") {
+      if (defined(invoker.jacoco_instrument) && invoker.jacoco_instrument) {
+        _filter_jar_target_name = "${target_name}_host__filter_jar"
+        _filter_jar_output_jar = "$target_out_dir/$target_name.host_filter.jar"
+      } else {
+        _filter_jar_target_name = "${target_name}_host"
+        _filter_jar_output_jar = invoker.host_jar_path
+      }
+      filter_jar(_filter_jar_target_name) {
         forward_variables_from(invoker,
                                [
                                  "jar_excluded_patterns",
@@ -1849,7 +1855,7 @@
                                ])
         deps = _deps
         input_jar = _previous_output_jar
-        output_jar = invoker.host_jar_path
+        output_jar = _filter_jar_output_jar
         inputs = []
         if (defined(strip_resource_classes) && strip_resource_classes) {
           inputs += [ invoker.build_config ]
@@ -1861,6 +1867,26 @@
           deps += invoker.input_deps
         }
       }
+
+      if (defined(invoker.jacoco_instrument) && invoker.jacoco_instrument) {
+        # Jacoco must run after desugar (or else desugar sometimes fails).
+        # It must run after filtering to avoid the same (filtered) class mapping
+        # to multiple .jar files.
+        # We run offline code coverage processing here rather than with a
+        # javaagent as the desired coverage data was not being generated.
+        # See crbug.com/1097815.
+        jacoco_instr("${target_name}_host") {
+          deps = [ ":$_filter_jar_target_name" ] + invoker.jar_deps
+          forward_variables_from(invoker,
+                                 [
+                                   "java_files",
+                                   "java_sources_file",
+                                 ])
+
+          input_jar_path = _filter_jar_output_jar
+          output_jar_path = invoker.host_jar_path
+        }
+      }
     }
 
     if (defined(invoker.device_jar_path)) {
@@ -1904,7 +1930,8 @@
 
       if (invoker.jacoco_instrument) {
         _filter_jar_target_name = "${target_name}_device__filter_jar"
-        _filter_jar_output_jar = "$target_out_dir/$target_name.filter.jar"
+        _filter_jar_output_jar =
+            "$target_out_dir/$target_name.device_filter.jar"
       } else {
         _filter_jar_target_name = "${target_name}_device"
         _filter_jar_output_jar = invoker.device_jar_path
diff --git a/build/config/chromeos/rules.gni b/build/config/chromeos/rules.gni
index 3b029a5..f0c7620d 100644
--- a/build/config/chromeos/rules.gni
+++ b/build/config/chromeos/rules.gni
@@ -4,6 +4,7 @@
 
 import("//build/config/chrome_build.gni")
 import("//build/config/chromeos/args.gni")
+import("//build/config/gclient_args.gni")
 
 assert(is_chromeos)
 
@@ -15,15 +16,11 @@
   _cache_path_prefix =
       "//build/cros_cache/chrome-sdk/symlinks/${cros_board}+${cros_sdk_version}"
 
-  # It's difficult to determine if any given board supports QEMU images. So
-  # check if there's one present in the expected location.
-  _qemu_image_path = "${_cache_path_prefix}+chromiumos_qemu_image.tar.xz"
-
-  # TODO(crbug.com/937821): Check for the board in a gclient list var to
-  # determine if we expect a VM image.
-  cros_is_vm = exec_script("//build/dir_exists.py",
-                           [ rebase_path(_qemu_image_path) ],
-                           "string") == "True"
+  foreach(b, string_split(cros_boards_with_qemu_images, ":")) {
+    if (cros_board == b) {
+      cros_is_vm = true
+    }
+  }
 
   _symlinks = [
     # Tast harness & test data.
@@ -39,7 +36,7 @@
     # VM-related tools.
     _symlinks += [
       rebase_path("${_cache_path_prefix}+sys-firmware/seabios"),
-      rebase_path(_qemu_image_path),
+      rebase_path("${_cache_path_prefix}+chromiumos_qemu_image.tar.xz"),
       rebase_path("${_cache_path_prefix}+app-emulation/qemu"),
     ]
   }
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 34c4525..2d54157 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-0.20200717.1.1
+0.20200717.2.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 34c4525..2d54157 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-0.20200717.1.1
+0.20200717.2.1
diff --git a/cc/input/scrollbar_controller.cc b/cc/input/scrollbar_controller.cc
index d6752570..2f2e0e6 100644
--- a/cc/input/scrollbar_controller.cc
+++ b/cc/input/scrollbar_controller.cc
@@ -11,6 +11,7 @@
 #include "cc/input/scroll_utils.h"
 #include "cc/input/scrollbar.h"
 #include "cc/input/scrollbar_controller.h"
+#include "cc/layers/viewport.h"
 #include "cc/trees/layer_tree_impl.h"
 #include "cc/trees/scroll_node.h"
 
@@ -100,7 +101,11 @@
       Granularity(scrollbar_part, perform_jump_click_on_track);
   if (scrollbar_part == ScrollbarPart::THUMB) {
     drag_state_ = DragState();
-    drag_state_->drag_origin = position_in_widget;
+    bool clipped = false;
+    drag_state_->drag_origin =
+        GetScrollbarRelativePosition(position_in_widget, &clipped);
+    // If the point were clipped we shouldn't have hit tested to a valid part.
+    DCHECK(!clipped);
 
     // 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
@@ -236,20 +241,32 @@
 
   const float delta =
       round(std::abs(desired_thumb_origin - current_thumb_origin));
-  return delta * GetScrollerToScrollbarRatio();
+  return delta * GetScrollerToScrollbarRatio() * GetPageScaleFactorForScroll();
 }
 
 int ScrollbarController::GetScrollDeltaForDragPosition(
     const gfx::PointF pointer_position_in_widget) const {
   const ScrollbarLayerImplBase* scrollbar = ScrollbarLayer();
-  const float pointer_delta =
+  // Convert the move position to scrollbar layer relative for comparison with
+  // |drag_state_| drag_origin. Ignore clipping as if we're within the region
+  // that doesn't cause snapping back, we do want the delta in the appropriate
+  // dimension to cause a scroll.
+  bool clipped = false;
+  const gfx::PointF scrollbar_relative_position(
+      GetScrollbarRelativePosition(pointer_position_in_widget, &clipped));
+  float pointer_delta =
       scrollbar->orientation() == ScrollbarOrientation::VERTICAL
-          ? pointer_position_in_widget.y() - drag_state_->drag_origin.y()
-          : pointer_position_in_widget.x() - drag_state_->drag_origin.x();
+          ? scrollbar_relative_position.y() - drag_state_->drag_origin.y()
+          : scrollbar_relative_position.x() - drag_state_->drag_origin.x();
 
   const float new_offset = pointer_delta * GetScrollerToScrollbarRatio();
-  const float scroll_delta = drag_state_->scroll_position_at_start_ +
-                             new_offset - scrollbar->current_pos();
+  float scroll_delta = drag_state_->scroll_position_at_start_ + new_offset -
+                       scrollbar->current_pos();
+
+  // The scroll delta computed is layer relative. In order to scroll the
+  // correct amount, we have to convert the delta to be unscaled (i.e. multiply
+  // by the page scale factor), as GSU deltas are always unscaled.
+  scroll_delta *= GetPageScaleFactorForScroll();
 
   // Scroll delta floored to match main thread per pixel behavior
   return floorf(scroll_delta);
@@ -326,9 +343,8 @@
                                                 ScrollbarOrientation::VERTICAL
                                             ? gfx::ScrollOffset(0, delta)
                                             : gfx::ScrollOffset(delta, 0));
-  const gfx::Vector2dF clamped_scroll_offset(
-      layer_tree_host_impl_->ComputeScrollDelta(
-          *target_node, ScrollOffsetToVector2dF(scroll_offset)));
+  const gfx::Vector2dF clamped_scroll_offset =
+      ComputeClampedDelta(*target_node, ScrollOffsetToVector2dF(scroll_offset));
 
   if (clamped_scroll_offset.IsZero())
     return scroll_result;
@@ -342,6 +358,23 @@
   return scroll_result;
 }
 
+gfx::Vector2dF ScrollbarController::ComputeClampedDelta(
+    const ScrollNode& target_node,
+    const gfx::Vector2dF& scroll_delta) const {
+  DCHECK(!target_node.scrolls_inner_viewport);
+  if (target_node.scrolls_outer_viewport)
+    return layer_tree_host_impl_->viewport().ComputeClampedDelta(scroll_delta);
+
+  // ComputeScrollDelta returns a delta accounting for the current page zoom
+  // level. Since we're producing a delta for an injected GSU, we need to get
+  // back to and unscaled delta (i.e. multiply by the page scale factor).
+  gfx::Vector2dF clamped_delta =
+      layer_tree_host_impl_->ComputeScrollDelta(target_node, scroll_delta);
+  const float scale_factor = GetPageScaleFactorForScroll();
+  clamped_delta.Scale(scale_factor);
+  return clamped_delta;
+}
+
 float ScrollbarController::GetScrollerToScrollbarRatio() const {
   // Calculating the delta by which the scroller layer should move when
   // dragging the thumb depends on the following factors:
@@ -585,9 +618,19 @@
           ->property_trees()
           ->scroll_tree.FindNodeFromElementId(scrollbar->scroll_element_id());
   DCHECK(scroll_node);
-  return scrollbar->orientation() == ScrollbarOrientation::VERTICAL
-             ? scroll_node->container_bounds.height()
-             : scroll_node->container_bounds.width();
+  if (!scroll_node->scrolls_outer_viewport) {
+    float length = scrollbar->orientation() == ScrollbarOrientation::VERTICAL
+                       ? scroll_node->container_bounds.height()
+                       : scroll_node->container_bounds.width();
+    return length;
+  }
+
+  gfx::SizeF viewport_size = layer_tree_host_impl_->viewport()
+                                 .GetInnerViewportSizeExcludingScrollbars();
+  float length = scrollbar->orientation() == ScrollbarOrientation::VERTICAL
+                     ? viewport_size.height()
+                     : viewport_size.width();
+  return length / GetPageScaleFactorForScroll();
 }
 
 int ScrollbarController::GetScrollDeltaForPercentBasedScroll() const {
@@ -614,6 +657,10 @@
              : pixel_delta.x();
 }
 
+float ScrollbarController::GetPageScaleFactorForScroll() const {
+  return layer_tree_host_impl_->active_tree()->page_scale_factor_for_scroll();
+}
+
 int ScrollbarController::GetScrollDeltaForScrollbarPart(
     const ScrollbarPart scrollbar_part,
     const bool jump_key_modifier) const {
diff --git a/cc/input/scrollbar_controller.h b/cc/input/scrollbar_controller.h
index f9b59b3..9551131 100644
--- a/cc/input/scrollbar_controller.h
+++ b/cc/input/scrollbar_controller.h
@@ -172,7 +172,8 @@
   };
 
   struct CC_EXPORT DragState {
-    // This marks the point at which the drag initiated (relative to the widget)
+    // This marks the point at which the drag initiated (relative to the
+    // scrollbar layer).
     gfx::PointF drag_origin;
 
     // This is needed for thumb snapping when the pointer moves too far away
@@ -217,6 +218,12 @@
       const ScrollbarPart scrollbar_part,
       const bool jump_key_modifier) const;
 
+  // Clamps |scroll_delta| based on the available scrollable amount of
+  // |target_node|. The returned delta includes the page scale factor and is
+  // appropriate for use directly as a delta for GSU.
+  gfx::Vector2dF ComputeClampedDelta(const ScrollNode& target_node,
+                                     const gfx::Vector2dF& scroll_delta) const;
+
   // Returns the rect for the ScrollbarPart.
   gfx::Rect GetRectForScrollbarPart(const ScrollbarPart scrollbar_part) const;
 
@@ -258,6 +265,10 @@
   // Returns the pixel delta for a percent-based scroll of the scrollbar
   int GetScrollDeltaForPercentBasedScroll() const;
 
+  // Returns the page scale factor (i.e. pinch zoom factor). This is relevant
+  // for root viewport scrollbar scrolling.
+  float GetPageScaleFactorForScroll() const;
+
   LayerTreeHostImpl* layer_tree_host_impl_;
 
   // Used to safeguard against firing GSE without firing GSB and GSU. For
diff --git a/cc/layers/viewport.cc b/cc/layers/viewport.cc
index dc8074f..d3b83f9 100644
--- a/cc/layers/viewport.cc
+++ b/cc/layers/viewport.cc
@@ -88,6 +88,53 @@
   return result;
 }
 
+gfx::Vector2dF Viewport::ComputeClampedDelta(
+    const gfx::Vector2dF& scroll_delta) const {
+  // When clamping for the outer viewport, we need to distribute the scroll
+  // between inner and outer to get the clamped value. The returned values
+  // from ComputeScrollDelta are unscaled, so we have to do scaling
+  // conversions each step of the way.
+  ScrollNode* inner_node = InnerScrollNode();
+  gfx::Vector2dF inner_delta =
+      host_impl_->ComputeScrollDelta(*inner_node, scroll_delta);
+
+  float page_scale = host_impl_->active_tree()->page_scale_factor_for_scroll();
+  gfx::Vector2dF unscaled_delta = scroll_delta;
+  unscaled_delta.Scale(1.f / page_scale);
+
+  gfx::Vector2dF remaining_delta = unscaled_delta - inner_delta;
+  remaining_delta.Scale(page_scale);
+
+  const ScrollNode* outer_node = OuterScrollNode();
+  gfx::Vector2dF outer_delta =
+      host_impl_->ComputeScrollDelta(*outer_node, remaining_delta);
+
+  gfx::Vector2dF combined_delta = inner_delta + outer_delta;
+  combined_delta.Scale(page_scale);
+
+  return combined_delta;
+}
+
+gfx::SizeF Viewport::GetInnerViewportSizeExcludingScrollbars() const {
+  DCHECK(InnerScrollNode());
+  ScrollNode* inner_node = InnerScrollNode();
+  gfx::SizeF inner_bounds(inner_node->container_bounds);
+  ScrollNode* outer_node = OuterScrollNode();
+  ScrollbarSet scrollbars = host_impl_->ScrollbarsFor(outer_node->element_id);
+  gfx::SizeF scrollbars_size;
+  for (const auto* scrollbar : scrollbars) {
+    if (scrollbar->orientation() == ScrollbarOrientation::VERTICAL) {
+      scrollbars_size.set_width(scrollbar->bounds().width());
+    } else {
+      DCHECK(scrollbar->orientation() == ScrollbarOrientation::HORIZONTAL);
+      scrollbars_size.set_height(scrollbar->bounds().height());
+    }
+  }
+
+  inner_bounds.Enlarge(-scrollbars_size.width(), -scrollbars_size.height());
+  return inner_bounds;
+}
+
 void Viewport::ScrollByInnerFirst(const gfx::Vector2dF& delta) {
   DCHECK(InnerScrollNode());
   gfx::Vector2dF unused_delta = scroll_tree().ScrollBy(
diff --git a/cc/layers/viewport.h b/cc/layers/viewport.h
index d5796337..ed6b861 100644
--- a/cc/layers/viewport.h
+++ b/cc/layers/viewport.h
@@ -92,6 +92,18 @@
   // method.
   bool CanScroll(const ScrollNode& node, const ScrollState& scroll_state) const;
 
+  // Takes |scroll_delta| and returns a clamped delta based on distributing
+  // |scroll_delta| first to the inner viewport, then the outer viewport.
+  // The passed delta must be scaled by the page scale factor and the returned
+  // delta will also be scaled.
+  gfx::Vector2dF ComputeClampedDelta(const gfx::Vector2dF& scroll_delta) const;
+
+  // Returns the innert viewport size, excluding scrollbars. This is not the
+  // same as the inner viewport container_bounds size, which does not account
+  // for scrollbars. This method can be useful for calculating the area of the
+  // inner viewport where content is visible.
+  gfx::SizeF GetInnerViewportSizeExcludingScrollbars() const;
+
  private:
   explicit Viewport(LayerTreeHostImpl* host_impl);
 
diff --git a/cc/paint/oop_pixeltest.cc b/cc/paint/oop_pixeltest.cc
index 415b1b9..2c72fea 100644
--- a/cc/paint/oop_pixeltest.cc
+++ b/cc/paint/oop_pixeltest.cc
@@ -894,6 +894,7 @@
   const SkImageInfo& GetSkImageInfo() override { return info_; }
   gpu::Mailbox GetMailbox() const override { return mailbox_; }
   sk_sp<SkImage> GetAcceleratedSkImage() override { return nullptr; }
+  sk_sp<SkImage> GetSkImageViaReadback() override { return nullptr; }
 
  private:
   gpu::Mailbox mailbox_;
@@ -1870,6 +1871,47 @@
   sii->DestroySharedImage(sync_token, v_mailbox);
 }
 
+TEST_F(OopPixelTest, ReadbackImagePixels) {
+  RasterOptions options(gfx::Size(16, 16));
+  SkImageInfo dest_info = SkImageInfo::MakeN32Premul(
+      options.resource_size.width(), options.resource_size.height(),
+      gfx::ColorSpace::CreateSRGB().ToSkColorSpace());
+
+  SkBitmap expected_bitmap;
+  expected_bitmap.allocPixels(dest_info);
+
+  SkCanvas canvas(expected_bitmap);
+  canvas.drawColor(SK_ColorMAGENTA);
+  SkPaint green;
+  green.setColor(SK_ColorGREEN);
+  canvas.drawRect(SkRect::MakeXYWH(1, 2, 3, 4), green);
+
+  auto* ri = raster_context_provider_->RasterInterface();
+  auto* sii = raster_context_provider_->SharedImageInterface();
+  gpu::Mailbox mailbox = CreateMailboxSharedImage(
+      ri, sii, options, viz::ResourceFormat::RGBA_8888);
+  ri->OrderingBarrierCHROMIUM();
+
+  gpu::gles2::GLES2Interface* gl = gles2_context_provider_->ContextGL();
+  UploadPixels(gl, mailbox, options.resource_size, GL_RGBA, GL_UNSIGNED_BYTE,
+               expected_bitmap.getPixels());
+  gl->OrderingBarrierCHROMIUM();
+
+  SkBitmap actual_bitmap;
+  actual_bitmap.allocPixels(dest_info);
+
+  ri->ReadbackImagePixels(mailbox, dest_info, dest_info.minRowBytes(), 0, 0,
+                          actual_bitmap.getPixels());
+  EXPECT_EQ(ri->GetError(), static_cast<unsigned>(GL_NO_ERROR));
+  ri->OrderingBarrierCHROMIUM();
+
+  ExpectEquals(actual_bitmap, expected_bitmap);
+
+  gpu::SyncToken sync_token;
+  gl->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
+  sii->DestroySharedImage(sync_token, mailbox);
+}
+
 // A workaround on Android that forces the use of GLES 2.0 instead of 3.0
 // prevents the use of the GL_RG textures required for NV12 format. This
 // test will be reactiviated on Android once the workaround is removed.
diff --git a/cc/paint/paint_image.cc b/cc/paint/paint_image.cc
index 3ec28bb..18627f0 100644
--- a/cc/paint/paint_image.cc
+++ b/cc/paint/paint_image.cc
@@ -114,8 +114,12 @@
   return cached_sk_image_;
 }
 
-const sk_sp<SkImage>& PaintImage::GetRasterSkImage() const {
-  return cached_sk_image_;
+sk_sp<SkImage> PaintImage::GetRasterSkImage() const {
+  if (cached_sk_image_)
+    return cached_sk_image_;
+  else if (texture_backing_)
+    return texture_backing_->GetSkImageViaReadback();
+  return nullptr;
 }
 
 SkImageInfo PaintImage::GetSkImageInfo() const {
diff --git a/cc/paint/paint_image.h b/cc/paint/paint_image.h
index 2de5f7a..8f1846f 100644
--- a/cc/paint/paint_image.h
+++ b/cc/paint/paint_image.h
@@ -234,7 +234,7 @@
   // Avoid using this API unless actual pixels are needed.
   // For other cases, prefer using PaintImage APIs directly or use
   // GetSkImageInfo() for metadata about the SkImage.
-  const sk_sp<SkImage>& GetRasterSkImage() const;
+  sk_sp<SkImage> GetRasterSkImage() const;
 
   SkImageInfo GetSkImageInfo() const;
 
diff --git a/cc/paint/texture_backing.h b/cc/paint/texture_backing.h
index 51055d2..d7eaf95 100644
--- a/cc/paint/texture_backing.h
+++ b/cc/paint/texture_backing.h
@@ -31,9 +31,13 @@
   // Returns the shared image mailbox backing for this texture.
   virtual gpu::Mailbox GetMailbox() const = 0;
 
-  // Returns a texture backed SkImage wrapping the mailbox. Only supported if
-  // the context used to create this image has a valid GrContext.
+  // Returns a texture backed SkImage. Only supported if the context used to
+  // create this image has a valid GrContext.
   virtual sk_sp<SkImage> GetAcceleratedSkImage() = 0;
+
+  // Gets SkImage via a readback from GPU memory. Use this when actual SkImage
+  // pixel data is required in software.
+  virtual sk_sp<SkImage> GetSkImageViaReadback() = 0;
 };
 
 }  // namespace cc
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 068d86a..5956c776 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -871,6 +871,8 @@
 
   bool can_use_msaa() const { return can_use_msaa_; }
 
+  Viewport& viewport() const { return *viewport_.get(); }
+
  protected:
   LayerTreeHostImpl(
       const LayerTreeSettings& settings,
@@ -970,8 +972,6 @@
   bool UpdateGpuRasterizationStatus();
   void UpdateTreeResourcesForGpuRasterizationIfNeeded();
 
-  Viewport& viewport() const { return *viewport_.get(); }
-
   bool IsTouchDraggingScrollbar(
       LayerImpl* first_scrolling_layer_or_drawn_scrollbar,
       ui::ScrollInputType type);
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 5aafa00f..edfd961f 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -272,7 +272,6 @@
     ":chrome_public_android_manifest",
     ":chrome_public_apk_template_resources",
     ":chrome_version_constants",
-    ":critical_persisted_tab_data_proto_java",
     ":partner_location_descriptor_proto_java",
     ":update_proto_java",
     ":usage_stats_proto_java",
@@ -717,11 +716,6 @@
   sources = [ "$proto_path/partner_location_descriptor.proto" ]
 }
 
-proto_java_library("critical_persisted_tab_data_proto_java") {
-  proto_path = "java/src/org/chromium/chrome/browser/tab/state/proto"
-  sources = [ "$proto_path/critical_persisted_tab_data.proto" ]
-}
-
 proto_java_library("update_proto_java") {
   proto_path = "java/src/org/chromium/chrome/browser/omaha/metrics"
   sources = [ "$proto_path/update_success_tracking.proto" ]
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index 8178b5f..a9a4b1e 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -1526,14 +1526,6 @@
   "java/src/org/chromium/chrome/browser/tab/TabWebContentsObserver.java",
   "java/src/org/chromium/chrome/browser/tab/TabWebContentsUserData.java",
   "java/src/org/chromium/chrome/browser/tab/TrustedCdn.java",
-  "java/src/org/chromium/chrome/browser/tab/state/CriticalPersistedTabData.java",
-  "java/src/org/chromium/chrome/browser/tab/state/EncryptedFilePersistedTabDataStorage.java",
-  "java/src/org/chromium/chrome/browser/tab/state/FilePersistedTabDataStorage.java",
-  "java/src/org/chromium/chrome/browser/tab/state/MockPersistedTabData.java",
-  "java/src/org/chromium/chrome/browser/tab/state/PersistedTabData.java",
-  "java/src/org/chromium/chrome/browser/tab/state/PersistedTabDataConfiguration.java",
-  "java/src/org/chromium/chrome/browser/tab/state/PersistedTabDataFactory.java",
-  "java/src/org/chromium/chrome/browser/tab/state/PersistedTabDataStorage.java",
   "java/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegate.java",
   "java/src/org/chromium/chrome/browser/tabbed_mode/TabbedNavigationBarColorController.java",
   "java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java",
diff --git a/chrome/android/expectations/monochrome_public_bundle.AndroidManifest.expected b/chrome/android/expectations/monochrome_public_bundle.AndroidManifest.expected
index 3d5ca6f..1dac1c1 100644
--- a/chrome/android/expectations/monochrome_public_bundle.AndroidManifest.expected
+++ b/chrome/android/expectations/monochrome_public_bundle.AndroidManifest.expected
@@ -758,7 +758,7 @@
         android:name="com.google.android.gms.version"
         android:value="@integer/google_play_services_version"/>
     <meta-data android:name="com.google.ar.core" android:value="optional"/>
-    <meta-data android:name="com.google.ar.core.min_apk_version" android:value="190531000"/>
+    <meta-data android:name="com.google.ar.core.min_apk_version" android:value="200501000"/>
     <meta-data android:name="com.samsung.android.sdk.multiwindow.enable" android:value="true"/>
     <meta-data
         android:name="com.samsung.android.sdk.multiwindow.penwindow.enable"
diff --git a/chrome/android/expectations/trichrome_chrome_bundle.AndroidManifest.expected b/chrome/android/expectations/trichrome_chrome_bundle.AndroidManifest.expected
index 3b330293..8f791d4 100644
--- a/chrome/android/expectations/trichrome_chrome_bundle.AndroidManifest.expected
+++ b/chrome/android/expectations/trichrome_chrome_bundle.AndroidManifest.expected
@@ -712,7 +712,7 @@
         android:name="com.google.android.gms.version"
         android:value="@integer/google_play_services_version"/>
     <meta-data android:name="com.google.ar.core" android:value="optional"/>
-    <meta-data android:name="com.google.ar.core.min_apk_version" android:value="190531000"/>
+    <meta-data android:name="com.google.ar.core.min_apk_version" android:value="200501000"/>
     <meta-data android:name="com.samsung.android.sdk.multiwindow.enable" android:value="true"/>
     <meta-data
         android:name="com.samsung.android.sdk.multiwindow.penwindow.enable"
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java
index 131fee4..8ba073d 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java
@@ -33,6 +33,7 @@
 import static org.chromium.chrome.browser.flags.ChromeFeatureList.TAB_GROUPS_ANDROID;
 import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.clickFirstCardFromTabSwitcher;
 import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.clickFirstTabInDialog;
+import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.clickNthTabInDialog;
 import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.closeFirstTabInDialog;
 import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.closeNthTabInDialog;
 import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.createTabs;
@@ -41,6 +42,7 @@
 import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.mergeAllNormalTabsToAGroup;
 import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.prepareTabsWithThumbnail;
 import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.rotateDeviceToOrientation;
+import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.verifyAllTabsHaveThumbnail;
 import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.verifyTabStripFaviconCount;
 import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.verifyTabSwitcherCardCount;
 
@@ -64,33 +66,41 @@
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TestRule;
 import org.junit.runner.RunWith;
 
+import org.chromium.base.test.params.ParameterAnnotations;
+import org.chromium.base.test.params.ParameterizedRunner;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.compositor.layouts.Layout;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.browser.night_mode.ChromeNightModeTestUtils;
 import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilter;
 import org.chromium.chrome.features.start_surface.StartSurfaceLayout;
 import org.chromium.chrome.tab_ui.R;
-import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.chrome.test.util.ChromeRenderTestRule;
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
+import org.chromium.ui.test.util.NightModeTestUtils;
 import org.chromium.ui.test.util.UiRestriction;
 
 import java.util.concurrent.ExecutionException;
 
 /** End-to-end tests for TabGridDialog component. */
-@RunWith(ChromeJUnit4ClassRunner.class)
 // clang-format off
+@RunWith(ParameterizedRunner.class)
+@ParameterAnnotations.UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
 @Features.EnableFeatures({TAB_GRID_LAYOUT_ANDROID, TAB_GROUPS_ANDROID})
@@ -107,12 +117,27 @@
     public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
 
     @Rule
+    public ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus().build();
+
+    @Rule
     public TestRule mProcessor = new Features.InstrumentationProcessor();
 
     @Rule
     public IntentsTestRule<ChromeActivity> mShareActivityTestRule =
             new IntentsTestRule<>(ChromeActivity.class, false, false);
 
+    @BeforeClass
+    public static void setUpBeforeActivityLaunched() {
+        ChromeNightModeTestUtils.setUpNightModeBeforeChromeActivityLaunched();
+    }
+
+    @ParameterAnnotations.UseMethodParameterBefore(NightModeTestUtils.NightModeParams.class)
+    public void setupNightMode(boolean nightModeEnabled) {
+        ChromeNightModeTestUtils.setUpNightModeForChromeActivity(nightModeEnabled);
+        mRenderTestRule.setNightModeEnabled(nightModeEnabled);
+    }
+
     @Before
     public void setUp() {
         TabUiFeatureUtilities.setTabManagementModuleSupportedForTesting(true);
@@ -613,6 +638,73 @@
         verifyShowingDialog(cta, 1, null);
     }
 
+    @Test
+    @MediumTest
+    @Feature({"RenderTest"})
+    @ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class)
+    public void testRenderDialog_3Tabs_Portrait(boolean nightModeEnabled) throws Exception {
+        final ChromeTabbedActivity cta = mActivityTestRule.getActivity();
+        prepareTabsWithThumbnail(mActivityTestRule, 3, 0, "about:blank");
+        enterTabSwitcher(cta);
+        verifyTabSwitcherCardCount(cta, 3);
+        verifyAllTabsHaveThumbnail(cta.getCurrentTabModel());
+
+        // Create a tab group.
+        mergeAllNormalTabsToAGroup(cta);
+        verifyTabSwitcherCardCount(cta, 1);
+        openDialogFromTabSwitcherAndVerify(cta, 3, null);
+
+        View dialogView = cta.findViewById(R.id.dialog_parent_view);
+        mRenderTestRule.render(dialogView, "3_tabs_portrait");
+    }
+
+    @Test
+    @MediumTest
+    @Feature({"RenderTest"})
+    @ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class)
+    public void testRenderDialog_3Tabs_Landscape(boolean nightModeEnabled) throws Exception {
+        final ChromeTabbedActivity cta = mActivityTestRule.getActivity();
+        prepareTabsWithThumbnail(mActivityTestRule, 3, 0, "about:blank");
+        enterTabSwitcher(cta);
+        verifyTabSwitcherCardCount(cta, 3);
+        verifyAllTabsHaveThumbnail(cta.getCurrentTabModel());
+
+        // Rotate to landscape mode and create a tab group.
+        rotateDeviceToOrientation(cta, Configuration.ORIENTATION_LANDSCAPE);
+        mergeAllNormalTabsToAGroup(cta);
+        verifyTabSwitcherCardCount(cta, 1);
+        openDialogFromTabSwitcherAndVerify(cta, 3, null);
+
+        View dialogView = cta.findViewById(R.id.dialog_parent_view);
+        mRenderTestRule.render(dialogView, "3_tabs_landscape");
+    }
+
+    @Test
+    @MediumTest
+    @Feature({"RenderTest"})
+    @ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class)
+    public void testRenderDialog_5Tabs_InitialScroll(boolean nightModeEnabled) throws Exception {
+        final ChromeTabbedActivity cta = mActivityTestRule.getActivity();
+        prepareTabsWithThumbnail(mActivityTestRule, 5, 0, "about:blank");
+        enterTabSwitcher(cta);
+        verifyTabSwitcherCardCount(cta, 5);
+        verifyAllTabsHaveThumbnail(cta.getCurrentTabModel());
+
+        // Create a tab group.
+        mergeAllNormalTabsToAGroup(cta);
+        verifyTabSwitcherCardCount(cta, 1);
+        openDialogFromTabSwitcherAndVerify(cta, 5, null);
+
+        // Select the last tab and reopen the dialog. Verify that the dialog has scrolled to the
+        // correct position.
+        clickNthTabInDialog(cta, 4);
+        enterTabSwitcher(cta);
+        openDialogFromTabSwitcherAndVerify(cta, 5, null);
+
+        View dialogView = cta.findViewById(R.id.dialog_parent_view);
+        mRenderTestRule.render(dialogView, "5_tabs_select_last");
+    }
+
     private void openDialogFromTabSwitcherAndVerify(
             ChromeTabbedActivity cta, int tabCount, String customizedTitle) {
         clickFirstCardFromTabSwitcher(cta);
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/NativeViewListRenderer.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/NativeViewListRenderer.java
index 4c37c97..c06c6e7 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/NativeViewListRenderer.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/NativeViewListRenderer.java
@@ -7,6 +7,8 @@
 import android.content.Context;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.FrameLayout;
 import android.widget.TextView;
 
 import androidx.recyclerview.widget.LinearLayoutManager;
@@ -55,17 +57,22 @@
 
     @Override
     public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        FrameLayout frameLayout = new FrameLayout(parent.getContext());
+        frameLayout.setLayoutParams(
+                new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
         // viewType is same as position.
         int position = viewType;
+        View v;
         if (mManager.isNativeView(position)) {
-            View v = mManager.getNativeView(position, parent);
-            return new ViewHolder(v);
+            v = mManager.getNativeView(position, parent);
         } else {
-            TextView v = new TextView(ContextUtils.getApplicationContext());
+            TextView textView = new TextView(ContextUtils.getApplicationContext());
             String message = "Unable to render external view";
-            v.setText(message);
-            return new ViewHolder(v);
+            textView.setText(message);
+            v = textView;
         }
+        frameLayout.addView(v);
+        return new ViewHolder(frameLayout);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java
index c7a580f..e86c873 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java
@@ -20,6 +20,7 @@
 import androidx.annotation.StringRes;
 import androidx.annotation.VisibleForTesting;
 
+import org.chromium.base.ActivityState;
 import org.chromium.base.Callback;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.IntentUtils;
@@ -576,9 +577,10 @@
         }
 
         // When invoked directly from a browser, we want to trigger switch to tab animation.
-        // If invoded from other activitiies, ex. searchActivity, we do not need to trigger the
+        // If invoked from other activities, ex. searchActivity, we do not need to trigger the
         // animation since Android will show the animation for switching apps.
-        if (mWindowAndroid.equals(tab.getWindowAndroid())) {
+        if (tab.getWindowAndroid().getActivityState() != ActivityState.STOPPED
+                && tab.getWindowAndroid().getActivityState() != ActivityState.DESTROYED) {
             // TODO(1097292):  Do not use Activity to get TabModelSelector.
             assert tab.getWindowAndroid().getActivity().get() instanceof ChromeActivity;
 
@@ -589,13 +591,13 @@
             chromeActivity.getTabModelSelector().getCurrentModel().setIndex(
                     tabIndex, TabSelectionType.FROM_OMNIBOX);
         } else {
+            // Browser is in background, bring to to foreground and switch to the tab.
             Intent newIntent = ChromeIntentUtil.createBringTabToFrontIntent(tab.getId());
             if (newIntent != null) {
                 newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                 IntentUtils.safeStartActivity(ContextUtils.getApplicationContext(), newIntent);
             }
         }
-
         recordMetrics(position, WindowOpenDisposition.SWITCH_TO_TAB, suggestion);
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/SwitchToTabTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/SwitchToTabTest.java
index c87a762..0349086 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/SwitchToTabTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/SwitchToTabTest.java
@@ -8,11 +8,11 @@
 import android.app.Instrumentation;
 import android.app.Instrumentation.ActivityMonitor;
 import android.content.Intent;
-import android.os.Build;
 import android.support.test.InstrumentationRegistry;
-import android.util.Pair;
+import android.text.TextUtils;
 import android.view.ViewGroup;
 import android.widget.ImageView;
+import android.widget.TextView;
 
 import androidx.test.filters.MediumTest;
 
@@ -24,8 +24,9 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import org.chromium.base.ActivityState;
+import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.DisableIf;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
@@ -42,6 +43,7 @@
 import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
+import org.chromium.content_public.browser.test.util.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.content_public.browser.test.util.TestTouchUtils;
 import org.chromium.net.test.EmbeddedTestServer;
@@ -90,46 +92,105 @@
     }
 
     /**
-     * Type the |text| into |activity|'s url_bar, and wait for switch to tab suggestion shows up.
+     * Type the |text| into |activity|'s URL bar, and wait for switch to tab suggestion shows up.
      *
-     * @param activity The Activity which url_bar is in.
+     * @param activity The Activity which URL bar is in.
      * @param locationBarLayout The layout which omnibox suggestions will show in.
-     * @param text The text will be typed into url_bar.
+     * @param tab The tab will be switched to.
      */
-    private void typeAndWaitForTabMatchSuggestions(Activity activity,
-            LocationBarLayout locationBarLayout, String input) throws InterruptedException {
-        typeInOmnibox(activity, input);
+    private void typeAndClickMatchingTabMatchSuggestion(Activity activity,
+            LocationBarLayout locationBarLayout, Tab tab) throws InterruptedException {
+        typeInOmnibox(activity, tab.getTitle());
 
         OmniboxTestUtils.waitForOmniboxSuggestions(locationBarLayout);
         // waitForOmniboxSuggestions only wait until one suggestion shows up, we need to wait util
         // autocomplete return more suggestions.
         CriteriaHelper.pollUiThread(() -> {
-            Criteria.checkThat(findFirstTabMatchOmniboxSuggestion(locationBarLayout).first,
-                    Matchers.not(INVALID_INDEX));
+            OmniboxSuggestion matchSuggestion =
+                    findTabMatchOmniboxSuggestion(locationBarLayout, tab);
+            Criteria.checkThat(matchSuggestion, Matchers.notNullValue());
+
+            OmniboxSuggestionsDropdown suggestionsDropdown =
+                    AutocompleteCoordinatorTestUtils.getSuggestionsDropdown(
+                            locationBarLayout.getAutocompleteCoordinator());
+
+            // Make sure data populated to UI
+            int index = findIndexOfTabMatchSuggestionView(suggestionsDropdown, matchSuggestion);
+            Criteria.checkThat(index, Matchers.not(INVALID_INDEX));
+
+            try {
+                clickSuggestionActionAt(suggestionsDropdown, index);
+            } catch (InterruptedException e) {
+                throw new CriteriaNotSatisfiedException(e);
+            }
         });
     }
 
     /**
-     * Find the first switch to tab suggestion in the omnibox suggestion list, and return the
-     * suggestion and its index.
+     * Find the switch to tab suggestion which suggests the |tab|, and return the
+     * suggestion. This method needs to run on the UI thread.
      *
      * @param locationBarLayout The layout which omnibox suggestions will show in.
-     * @return The the first switch to tab suggestion's index, and the suggesstion.
+     * @param tab The tab which the OmniboxSuggestion should suggest.
+     * @return The suggesstion which suggests the |tab|.
      */
-    private Pair<Integer, OmniboxSuggestion> findFirstTabMatchOmniboxSuggestion(
-            LocationBarLayout locationBarLayout) {
-        OmniboxSuggestionsDropdown suggestionsDropdown =
-                AutocompleteCoordinatorTestUtils.getSuggestionsDropdown(
-                        locationBarLayout.getAutocompleteCoordinator());
-        // Find the index of the first matching suggestion.
-        for (int i = 0; i < suggestionsDropdown.getItemCount(); ++i) {
-            OmniboxSuggestion suggestion = AutocompleteCoordinatorTestUtils.getOmniboxSuggestionAt(
-                    locationBarLayout.getAutocompleteCoordinator(), i);
-            if (suggestion != null && suggestion.hasTabMatch()) {
-                return new Pair<Integer, OmniboxSuggestion>(i, suggestion);
+    private OmniboxSuggestion findTabMatchOmniboxSuggestion(
+            LocationBarLayout locationBarLayout, Tab tab) {
+        ThreadUtils.assertOnUiThread();
+
+        AutocompleteCoordinator coordinator = locationBarLayout.getAutocompleteCoordinator();
+        // Find the first matching suggestion.
+        for (int i = 0; i < coordinator.getSuggestionCount(); ++i) {
+            OmniboxSuggestion suggestion = coordinator.getSuggestionAt(i);
+            if (suggestion != null && suggestion.hasTabMatch()
+                    && TextUtils.equals(suggestion.getDescription(), tab.getTitle())
+                    && TextUtils.equals(suggestion.getUrl().getSpec(), tab.getUrl().getSpec())) {
+                return suggestion;
             }
         }
-        return new Pair<Integer, OmniboxSuggestion>(INVALID_INDEX, null);
+        return null;
+    }
+
+    /**
+     * Find the index of the tab match suggestion in OmniboxSuggestionsDropdown. This method needs
+     * to run on the UI thread.
+     *
+     * @param suggestionsDropdown The OmniboxSuggestionsDropdown contains all the suggestions.
+     * @param suggestion The OmniboxSuggestion we are looking for in the view.
+     * @return The matching suggestion's index.
+     */
+    private int findIndexOfTabMatchSuggestionView(
+            OmniboxSuggestionsDropdown suggestionsDropdown, OmniboxSuggestion suggestion) {
+        ThreadUtils.assertOnUiThread();
+
+        ViewGroup viewGroup = suggestionsDropdown.getViewGroup();
+        if (viewGroup == null) {
+            return INVALID_INDEX;
+        }
+
+        for (int i = 0; i < viewGroup.getChildCount(); i++) {
+            BaseSuggestionView baseSuggestionView = (BaseSuggestionView) viewGroup.getChildAt(i);
+            if (baseSuggestionView == null) {
+                continue;
+            }
+
+            TextView line1 = baseSuggestionView.findViewById(R.id.line_1);
+            TextView line2 = baseSuggestionView.findViewById(R.id.line_2);
+            if (!TextUtils.equals(suggestion.getDescription(), line1.getText())
+                    || !TextUtils.equals(suggestion.getDisplayText(), line2.getText())) {
+                continue;
+            }
+
+            List<ImageView> buttonsList = baseSuggestionView.getActionButtons();
+            if (buttonsList != null && buttonsList.size() == 1
+                    && TextUtils.equals(baseSuggestionView.getResources().getString(
+                                                R.string.accessibility_omnibox_switch_to_tab),
+                            buttonsList.get(0).getContentDescription())) {
+                return i;
+            }
+        }
+
+        return INVALID_INDEX;
     }
 
     /**
@@ -140,10 +201,12 @@
      */
     private void clickSuggestionActionAt(OmniboxSuggestionsDropdown suggestionsDropdown, int index)
             throws InterruptedException {
-        // Wait a bit since the button may not able to click.
         ViewGroup viewGroup = suggestionsDropdown.getViewGroup();
         BaseSuggestionView baseSuggestionView = (BaseSuggestionView) viewGroup.getChildAt(index);
+        Assert.assertNotNull("Null suggestion for index: " + index, baseSuggestionView);
+
         List<ImageView> buttonsList = baseSuggestionView.getActionButtons();
+        Assert.assertNotNull(buttonsList);
         Assert.assertEquals(buttonsList.size(), 1);
         TestTouchUtils.performClickOnMainSync(
                 InstrumentationRegistry.getInstrumentation(), buttonsList.get(0));
@@ -171,9 +234,6 @@
 
     @Test
     @MediumTest
-    @DisableIf.Build(message = "https://crbug.com/1101433",
-            sdk_is_greater_than = Build.VERSION_CODES.LOLLIPOP_MR1,
-            sdk_is_less_than = Build.VERSION_CODES.N)
     @EnableFeatures("OmniboxTabSwitchSuggestions")
     public void
     testSwitchToTabSuggestion() throws InterruptedException {
@@ -183,34 +243,23 @@
         final String testHttpsUrl1 = mTestServer.getURL("/chrome/test/data/android/about.html");
         final String testHttpsUrl2 = mTestServer.getURL("/chrome/test/data/android/ok.txt");
         final String testHttpsUrl3 = mTestServer.getURL("/chrome/test/data/android/test.html");
-        mActivityTestRule.loadUrlInNewTab(testHttpsUrl1);
+        final Tab aboutTab = mActivityTestRule.loadUrlInNewTab(testHttpsUrl1);
         mActivityTestRule.loadUrlInNewTab(testHttpsUrl2);
         mActivityTestRule.loadUrlInNewTab(testHttpsUrl3);
 
         LocationBarLayout locationBarLayout =
                 (LocationBarLayout) mActivityTestRule.getActivity().findViewById(R.id.location_bar);
-        typeAndWaitForTabMatchSuggestions(
-                mActivityTestRule.getActivity(), locationBarLayout, "about");
-
-        Pair<Integer, OmniboxSuggestion> matchSuggestion =
-                findFirstTabMatchOmniboxSuggestion(locationBarLayout);
-
-        Assert.assertNotEquals(INVALID_INDEX, (int) matchSuggestion.first);
-        Assert.assertNotNull("No Switch to Tab suggestion returned.", matchSuggestion.second);
-        Assert.assertEquals(matchSuggestion.second.getUrl().getSpec(), testHttpsUrl1);
-
-        OmniboxSuggestionsDropdown suggestionsDropdown =
-                AutocompleteCoordinatorTestUtils.getSuggestionsDropdown(
-                        locationBarLayout.getAutocompleteCoordinator());
-        clickSuggestionActionAt(suggestionsDropdown, (int) matchSuggestion.first);
+        typeAndClickMatchingTabMatchSuggestion(
+                mActivityTestRule.getActivity(), locationBarLayout, aboutTab);
 
         CriteriaHelper.pollUiThread(() -> {
             Tab tab = mActivityTestRule.getActivity().getActivityTab();
-            if (tab == null) return false;
+            Criteria.checkThat(tab, Matchers.notNullValue());
+            Criteria.checkThat(tab, Matchers.is(aboutTab));
             // Make sure tab is in either upload page or result page. cannot only verify one of
             // them since on fast device tab jump to result page really quick but on slow device
             // may stay on upload page for a really long time.
-            return tab.getUrlString().equals(testHttpsUrl1);
+            Criteria.checkThat(tab.getUrlString(), Matchers.is(testHttpsUrl1));
         });
     }
 
@@ -225,7 +274,7 @@
         final String testHttpsUrl2 = mTestServer.getURL("/chrome/test/data/android/ok.txt");
         final String testHttpsUrl3 = mTestServer.getURL("/chrome/test/data/android/test.html");
         // Open the url trying to match in incognito mode.
-        mActivityTestRule.loadUrlInNewTab(testHttpsUrl1, true);
+        final Tab aboutTab = mActivityTestRule.loadUrlInNewTab(testHttpsUrl1, true);
         mActivityTestRule.loadUrlInNewTab(testHttpsUrl2);
         mActivityTestRule.loadUrlInNewTab(testHttpsUrl3);
 
@@ -235,52 +284,51 @@
         mActivityTestRule.typeInOmnibox("about", false);
         OmniboxTestUtils.waitForOmniboxSuggestions(locationBarLayout);
 
-        Pair<Integer, OmniboxSuggestion> matchSuggestion =
-                findFirstTabMatchOmniboxSuggestion(locationBarLayout);
-
-        Assert.assertNull(
-                "Should no Switch to Incognito Tab from normal tab.", matchSuggestion.second);
+        CriteriaHelper.pollUiThread(() -> {
+            OmniboxSuggestion matchSuggestion =
+                    findTabMatchOmniboxSuggestion(locationBarLayout, aboutTab);
+            Criteria.checkThat(matchSuggestion, Matchers.nullValue());
+        });
     }
 
     @Test
     @MediumTest
     @EnableFeatures("OmniboxTabSwitchSuggestions")
-    public void testSwitchToTabInSearchActiviy() throws InterruptedException {
+    public void testSwitchToTabInSearchActivity() throws InterruptedException {
         mTestServer = EmbeddedTestServer.createAndStartHTTPSServer(
                 InstrumentationRegistry.getInstrumentation().getContext(),
                 ServerCertificate.CERT_OK);
         final String testHttpsUrl1 = mTestServer.getURL("/chrome/test/data/android/about.html");
         final String testHttpsUrl2 = mTestServer.getURL("/chrome/test/data/android/ok.txt");
         final String testHttpsUrl3 = mTestServer.getURL("/chrome/test/data/android/test.html");
-        mActivityTestRule.loadUrlInNewTab(testHttpsUrl1);
+        final Tab aboutTab = mActivityTestRule.loadUrlInNewTab(testHttpsUrl1);
         mActivityTestRule.loadUrlInNewTab(testHttpsUrl2);
         mActivityTestRule.loadUrlInNewTab(testHttpsUrl3);
+        Assert.assertNotEquals(mActivityTestRule.getActivity().getActivityTab(), aboutTab);
 
         final SearchActivity searchActivity = startSearchActivity();
+        CriteriaHelper.pollUiThread(() -> {
+            Tab tab = mActivityTestRule.getActivity().getActivityTab();
+            Criteria.checkThat(tab, Matchers.notNullValue());
+
+            // Make sure chrome fully in background.
+            Criteria.checkThat(tab.getWindowAndroid().getActivityState(),
+                    Matchers.isOneOf(ActivityState.STOPPED, ActivityState.DESTROYED));
+        });
 
         final LocationBarLayout locationBarLayout =
                 (LocationBarLayout) searchActivity.findViewById(R.id.search_location_bar);
-        typeAndWaitForTabMatchSuggestions(searchActivity, locationBarLayout, "about");
-
-        Pair<Integer, OmniboxSuggestion> matchSuggestion =
-                findFirstTabMatchOmniboxSuggestion(locationBarLayout);
-
-        Assert.assertNotEquals(INVALID_INDEX, (int) matchSuggestion.first);
-        Assert.assertNotNull("No Switch to Tab suggestion returned.", matchSuggestion.second);
-        Assert.assertEquals(matchSuggestion.second.getUrl().getSpec(), testHttpsUrl1);
-
-        OmniboxSuggestionsDropdown suggestionsDropdown =
-                AutocompleteCoordinatorTestUtils.getSuggestionsDropdown(
-                        locationBarLayout.getAutocompleteCoordinator());
-        clickSuggestionActionAt(suggestionsDropdown, (int) matchSuggestion.first);
+        typeAndClickMatchingTabMatchSuggestion(searchActivity, locationBarLayout, aboutTab);
 
         CriteriaHelper.pollUiThread(() -> {
             Tab tab = mActivityTestRule.getActivity().getActivityTab();
-            if (tab == null) return false;
-            // Make sure tab is in either upload page or result page. cannot only verify one of
-            // them since on fast device tab jump to result page really quick but on slow device
-            // may stay on upload page for a really long time.
-            return tab.getUrlString().equals(testHttpsUrl1);
+            Criteria.checkThat(tab, Matchers.notNullValue());
+            Criteria.checkThat(tab, Matchers.is(aboutTab));
+            Criteria.checkThat(tab.getUrlString(), Matchers.is(testHttpsUrl1));
+            // Make sure tab is loaded and in foreground.
+            Criteria.checkThat(
+                    tab.getWindowAndroid().getActivityState(), Matchers.is(ActivityState.RESUMED));
+            Assert.assertEquals(tab, aboutTab);
         });
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrArHitTestTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrArHitTestTest.java
index ba135da..9a60dcdb 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrArHitTestTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrArHitTestTest.java
@@ -66,7 +66,7 @@
     @Test
     @MediumTest
     @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL})
-    @ArPlaybackFile("chrome/test/data/xr/ar_playback_datasets/floor_short_start_with_plane.mp4")
+    @ArPlaybackFile("chrome/test/data/xr/ar_playback_datasets/floor_session_12s_30fps.mp4")
     public void testHitTestSucceedsWithPlane() {
         mWebXrArTestFramework.loadFileAndAwaitInitialization(
                 "webxr_test_basic_hittest", PAGE_LOAD_TIMEOUT_S);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/adding_new_tests.md b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/adding_new_tests.md
index 5c454620..0a11207 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/adding_new_tests.md
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/adding_new_tests.md
@@ -153,8 +153,8 @@
 
 If you are adding an AR test and none of the existing datasets work for it, you
 can create and upload a new dataset that fits your needs. Dataset creation
-requires some internal tools, so contact either bsheedy@ or bialpio@ for
-instructions.
+requires some internal tools, see go/arcore-chrome-collect-recordings (internal
+link) or contact either bsheedy@ or bialpio@ for instructions.
 
 Once you have your playback dataset (.mp4 file), simply place it in
 `//chrome/test/data/xr/ar_playback_datasets/` and upload it using
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/ArTestRuleUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/ArTestRuleUtils.java
index ec5ce17..1929396 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/ArTestRuleUtils.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/ArTestRuleUtils.java
@@ -32,7 +32,7 @@
  */
 public class ArTestRuleUtils extends XrTestRuleUtils {
     private static final String DEFAULT_PLAYBACK_FILEPATH =
-            "chrome/test/data/xr/ar_playback_datasets/empty_floor.mp4";
+            "chrome/test/data/xr/ar_playback_datasets/floor_session_12s_30fps.mp4";
     // This must be kept in sync with the ArCore session_settings entry in
     // //chrome/android/javatests/AndroidManifest_monochrome.xml.
     private static final String PLAYBACK_FILE_LOCATION =
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/feed/v2/NativeViewListRendererTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/feed/v2/NativeViewListRendererTest.java
index f22a4ad..68d349c3 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/feed/v2/NativeViewListRendererTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/feed/v2/NativeViewListRendererTest.java
@@ -14,6 +14,7 @@
 import android.content.Context;
 import android.support.test.filters.SmallTest;
 import android.view.ViewGroup;
+import android.widget.FrameLayout;
 import android.widget.TextView;
 
 import androidx.recyclerview.widget.RecyclerView;
@@ -78,8 +79,10 @@
         mRenderer.bind(mManager);
         NativeViewListRenderer.ViewHolder viewHolder = mRenderer.onCreateViewHolder(
                 new DummyViewGroup(mContext), mRenderer.getItemViewType(1));
-        assertThat(viewHolder.itemView).isInstanceOf(TextView.class);
-        assertEquals("2", ((TextView) viewHolder.itemView).getText());
+        assertThat(viewHolder.itemView).isInstanceOf(FrameLayout.class);
+        FrameLayout frameLayout = (FrameLayout) viewHolder.itemView;
+        assertThat(frameLayout.getChildAt(0)).isInstanceOf(TextView.class);
+        assertEquals("2", ((TextView) frameLayout.getChildAt(0)).getText());
     }
 
     @Test
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 0437a9786..cb247b5 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1911,6 +1911,7 @@
     "//components/error_page/common",
     "//components/favicon/content",
     "//components/favicon/core",
+    "//components/favicon/core:history_implementation",
     "//components/favicon_base",
     "//components/feature_engagement",
     "//components/federated_learning",
@@ -3734,6 +3735,7 @@
       "//chrome/browser/nearby_sharing/certificates",
       "//chrome/browser/nearby_sharing/client",
       "//chrome/browser/nearby_sharing/instantmessaging/proto",
+      "//chrome/browser/nearby_sharing/local_device_data",
       "//chrome/browser/nearby_sharing/logging",
       "//chrome/browser/nearby_sharing/logging:util",
       "//chrome/browser/nearby_sharing/proto",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index dfdf31a..4aab6a27 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1192,6 +1192,14 @@
 
 const FeatureEntry::FeatureVariation kDynamicMaxAutocompleteVariations[] = {
     {
+        "9 suggestions if 0 or less URLs",
+        (FeatureEntry::FeatureParam[]){
+            {"OmniboxDynamicMaxAutocompleteUrlCutoff", "0"},
+            {"OmniboxDynamicMaxAutocompleteIncreasedLimit", "9"}},
+        2,
+        nullptr,
+    },
+    {
         "9 suggestions if 1 or less URLs",
         (FeatureEntry::FeatureParam[]){
             {"OmniboxDynamicMaxAutocompleteUrlCutoff", "1"},
@@ -1208,6 +1216,14 @@
         nullptr,
     },
     {
+        "10 suggestions if 0 or less URLs",
+        (FeatureEntry::FeatureParam[]){
+            {"OmniboxDynamicMaxAutocompleteUrlCutoff", "0"},
+            {"OmniboxDynamicMaxAutocompleteIncreasedLimit", "10"}},
+        2,
+        nullptr,
+    },
+    {
         "10 suggestions if 1 or less URLs",
         (FeatureEntry::FeatureParam[]){
             {"OmniboxDynamicMaxAutocompleteUrlCutoff", "1"},
diff --git a/chrome/browser/android/vr/arcore_device/arcore_impl.cc b/chrome/browser/android/vr/arcore_device/arcore_impl.cc
index 08004e1..fd891a6 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_impl.cc
+++ b/chrome/browser/android/vr/arcore_device/arcore_impl.cc
@@ -353,6 +353,11 @@
     return false;
   }
 
+  if (!ConfigureCamera(session.get())) {
+    DLOG(ERROR) << "Failed to configure camera";
+    return false;
+  }
+
   internal::ScopedArCoreObject<ArFrame*> frame;
   ArFrame_create(session.get(),
                  internal::ScopedArCoreObject<ArFrame*>::Receiver(frame).get());
@@ -382,6 +387,206 @@
   return true;
 }
 
+bool ArCoreImpl::ConfigureCamera(ArSession* ar_session) const {
+  internal::ScopedArCoreObject<ArCameraConfigFilter*> camera_config_filter;
+  ArCameraConfigFilter_create(
+      ar_session, internal::ScopedArCoreObject<ArCameraConfigFilter*>::Receiver(
+                      camera_config_filter)
+                      .get());
+  if (!camera_config_filter.is_valid()) {
+    DLOG(ERROR) << "ArCameraConfigFilter_create failed";
+    return false;
+  }
+
+  // We only want to work at 30fps for now.
+  ArCameraConfigFilter_setTargetFps(ar_session, camera_config_filter.get(),
+                                    AR_CAMERA_CONFIG_TARGET_FPS_30);
+  // We do not care if depth sensor is available or not for now.
+  // The default depth sensor usage of the newly created filter is not
+  // documented, so let's set the filter explicitly to accept both cameras with
+  // and without depth sensors.
+  ArCameraConfigFilter_setDepthSensorUsage(
+      ar_session, camera_config_filter.get(),
+      AR_CAMERA_CONFIG_DEPTH_SENSOR_USAGE_REQUIRE_AND_USE |
+          AR_CAMERA_CONFIG_DEPTH_SENSOR_USAGE_DO_NOT_USE);
+
+  internal::ScopedArCoreObject<ArCameraConfigList*> camera_config_list;
+  ArCameraConfigList_create(
+      ar_session, internal::ScopedArCoreObject<ArCameraConfigList*>::Receiver(
+                      camera_config_list)
+                      .get());
+
+  if (!camera_config_list.is_valid()) {
+    DLOG(ERROR) << "ArCameraConfigList_create failed";
+    return false;
+  }
+
+  ArSession_getSupportedCameraConfigsWithFilter(
+      ar_session, camera_config_filter.get(), camera_config_list.get());
+  if (!camera_config_list.is_valid()) {
+    DLOG(ERROR) << "ArSession_getSupportedCameraConfigsWithFilter failed";
+    return false;
+  }
+
+  int32_t available_configs_count;
+  ArCameraConfigList_getSize(ar_session, camera_config_list.get(),
+                             &available_configs_count);
+
+  DVLOG(2) << __func__ << ": ARCore reported " << available_configs_count
+           << " available configurations";
+
+  std::vector<internal::ScopedArCoreObject<ArCameraConfig*>> available_configs;
+  available_configs.reserve(available_configs_count);
+  for (int32_t i = 0; i < available_configs_count; ++i) {
+    internal::ScopedArCoreObject<ArCameraConfig*> camera_config;
+    ArCameraConfig_create(
+        ar_session,
+        internal::ScopedArCoreObject<ArCameraConfig*>::Receiver(camera_config)
+            .get());
+
+    if (!camera_config.is_valid()) {
+      DVLOG(1) << __func__
+               << ": ArCameraConfig_create failed for camera config at index "
+               << i;
+      continue;
+    }
+
+    ArCameraConfigList_getItem(ar_session, camera_config_list.get(), i,
+                               camera_config.get());
+
+    ArCameraConfigFacingDirection facing_direction;
+    ArCameraConfig_getFacingDirection(ar_session, camera_config.get(),
+                                      &facing_direction);
+
+    if (facing_direction != AR_CAMERA_CONFIG_FACING_DIRECTION_BACK) {
+      DVLOG(2)
+          << __func__
+          << ": camera config does not refer to back-facing camera, ignoring";
+      continue;
+    }
+
+#if DCHECK_IS_ON()
+    {
+      int32_t tex_width, tex_height;
+      ArCameraConfig_getTextureDimensions(ar_session, camera_config.get(),
+                                          &tex_width, &tex_height);
+
+      int32_t img_width, img_height;
+      ArCameraConfig_getImageDimensions(ar_session, camera_config.get(),
+                                        &img_width, &img_height);
+
+      uint32_t depth_sensor_usage;
+      ArCameraConfig_getDepthSensorUsage(ar_session, camera_config.get(),
+                                         &depth_sensor_usage);
+
+      DVLOG(3) << __func__
+               << ": matching camera config found, texture dimensions="
+               << tex_width << "x" << tex_height
+               << ", image dimensions= " << img_width << "x" << img_height
+               << ", depth sensor usage=" << depth_sensor_usage;
+    }
+#endif
+
+    available_configs.push_back(std::move(camera_config));
+  }
+
+  if (available_configs.empty()) {
+    DLOG(ERROR) << "No matching configs found";
+    return false;
+  }
+
+  auto best_config = std::max_element(
+      available_configs.begin(), available_configs.end(),
+      [ar_session](const internal::ScopedArCoreObject<ArCameraConfig*>& lhs,
+                   const internal::ScopedArCoreObject<ArCameraConfig*>& rhs) {
+        // true means that lhs is less than rhs
+
+        // We'll prefer the configs with higher total resolution (GPU first,
+        // then CPU), everything else does not matter for us now, but we will
+        // weakly prefer the cameras that support depth sensor (it will be used
+        // as a tie-breaker).
+
+        {
+          int32_t lhs_tex_width, lhs_tex_height;
+          int32_t rhs_tex_width, rhs_tex_height;
+
+          ArCameraConfig_getTextureDimensions(ar_session, lhs.get(),
+                                              &lhs_tex_width, &lhs_tex_height);
+          ArCameraConfig_getTextureDimensions(ar_session, rhs.get(),
+                                              &rhs_tex_width, &rhs_tex_height);
+
+          if (lhs_tex_width * lhs_tex_height !=
+              rhs_tex_width * rhs_tex_height) {
+            return lhs_tex_width * lhs_tex_height <
+                   rhs_tex_width * rhs_tex_height;
+          }
+        }
+
+        {
+          int32_t lhs_img_width, lhs_img_height;
+          int32_t rhs_img_width, rhs_img_height;
+
+          ArCameraConfig_getImageDimensions(ar_session, lhs.get(),
+                                            &lhs_img_width, &lhs_img_height);
+          ArCameraConfig_getImageDimensions(ar_session, rhs.get(),
+                                            &rhs_img_width, &rhs_img_height);
+
+          if (lhs_img_width * lhs_img_height !=
+              rhs_img_width * rhs_img_height) {
+            return lhs_img_width * lhs_img_height <
+                   rhs_img_width * rhs_img_height;
+          }
+        }
+
+        {
+          uint32_t lhs_depth_sensor_usage;
+          uint32_t rhs_depth_sensor_usage;
+
+          ArCameraConfig_getDepthSensorUsage(ar_session, lhs.get(),
+                                             &lhs_depth_sensor_usage);
+          ArCameraConfig_getDepthSensorUsage(ar_session, rhs.get(),
+                                             &rhs_depth_sensor_usage);
+
+          bool lhs_has_depth =
+              lhs_depth_sensor_usage &
+              AR_CAMERA_CONFIG_DEPTH_SENSOR_USAGE_REQUIRE_AND_USE;
+          bool rhs_has_depth =
+              rhs_depth_sensor_usage &
+              AR_CAMERA_CONFIG_DEPTH_SENSOR_USAGE_REQUIRE_AND_USE;
+
+          return lhs_has_depth < rhs_has_depth;
+        }
+      });
+
+#if DCHECK_IS_ON()
+  {
+    int32_t tex_width, tex_height;
+    ArCameraConfig_getTextureDimensions(ar_session, best_config->get(),
+                                        &tex_width, &tex_height);
+
+    int32_t img_width, img_height;
+    ArCameraConfig_getImageDimensions(ar_session, best_config->get(),
+                                      &img_width, &img_height);
+
+    uint32_t depth_sensor_usage;
+    ArCameraConfig_getDepthSensorUsage(ar_session, best_config->get(),
+                                       &depth_sensor_usage);
+    DVLOG(3) << __func__
+             << ": selected camera config with texture dimensions=" << tex_width
+             << "x" << tex_height << ", image dimensions=" << img_width << "x"
+             << img_height << ", depth sensor usage=" << depth_sensor_usage;
+  }
+#endif
+
+  ArStatus status = ArSession_setCameraConfig(ar_session, best_config->get());
+  if (status != AR_SUCCESS) {
+    DLOG(ERROR) << "ArSession_setCameraConfig failed: " << status;
+    return false;
+  }
+
+  return true;
+}
+
 void ArCoreImpl::SetCameraTexture(GLuint camera_texture_id) {
   DCHECK(IsOnGlThread());
   DCHECK(arcore_session_.is_valid());
diff --git a/chrome/browser/android/vr/arcore_device/arcore_impl.h b/chrome/browser/android/vr/arcore_device/arcore_impl.h
index f9e7edad..ca470e2 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_impl.h
+++ b/chrome/browser/android/vr/arcore_device/arcore_impl.h
@@ -276,6 +276,11 @@
       const base::TimeTicks& frame_time,
       FunctionType&& create_anchor_function);
 
+  // Helper, attempts to configure ArSession's camera for use. Note that this is
+  // happening during initialization, before arcore_session_ is set.
+  // Returns true if configuration succeeded, false otherwise.
+  bool ConfigureCamera(ArSession* ar_session) const;
+
   // Must be last.
   base::WeakPtrFactory<ArCoreImpl> weak_ptr_factory_{this};
   DISALLOW_COPY_AND_ASSIGN(ArCoreImpl);
diff --git a/chrome/browser/android/vr/arcore_device/arcore_shim.cc b/chrome/browser/android/vr/arcore_device/arcore_shim.cc
index 3a29a78..6399c0c 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_shim.cc
+++ b/chrome/browser/android/vr/arcore_device/arcore_shim.cc
@@ -26,6 +26,20 @@
   DO(ArCamera_getProjectionMatrix)                                 \
   DO(ArCamera_getTrackingState)                                    \
   DO(ArCamera_getViewMatrix)                                       \
+  DO(ArCameraConfig_create)                                        \
+  DO(ArCameraConfig_destroy)                                       \
+  DO(ArCameraConfig_getDepthSensorUsage)                           \
+  DO(ArCameraConfig_getFacingDirection)                            \
+  DO(ArCameraConfig_getImageDimensions)                            \
+  DO(ArCameraConfig_getTextureDimensions)                          \
+  DO(ArCameraConfigFilter_create)                                  \
+  DO(ArCameraConfigFilter_destroy)                                 \
+  DO(ArCameraConfigFilter_setDepthSensorUsage)                     \
+  DO(ArCameraConfigFilter_setTargetFps)                            \
+  DO(ArCameraConfigList_create)                                    \
+  DO(ArCameraConfigList_destroy)                                   \
+  DO(ArCameraConfigList_getItem)                                   \
+  DO(ArCameraConfigList_getSize)                                   \
   DO(ArConfig_create)                                              \
   DO(ArConfig_destroy)                                             \
   DO(ArConfig_getLightEstimationMode)                              \
@@ -72,8 +86,10 @@
   DO(ArSession_enableIncognitoMode_private)                        \
   DO(ArSession_getAllAnchors)                                      \
   DO(ArSession_getAllTrackables)                                   \
+  DO(ArSession_getSupportedCameraConfigsWithFilter)                \
   DO(ArSession_pause)                                              \
   DO(ArSession_resume)                                             \
+  DO(ArSession_setCameraConfig)                                    \
   DO(ArSession_setCameraTextureName)                               \
   DO(ArSession_setDisplayGeometry)                                 \
   DO(ArSession_update)                                             \
@@ -156,7 +172,6 @@
 
 }  // namespace vr
 
-
 void ArAnchorList_acquireItem(const ArSession* session,
                               const ArAnchorList* anchor_list,
                               int32_t index,
@@ -231,6 +246,93 @@
   return g_arcore_api->impl_ArCamera_getViewMatrix(session, camera, out_matrix);
 }
 
+void ArCameraConfig_create(const ArSession* session,
+                           ArCameraConfig** out_camera_config) {
+  return g_arcore_api->impl_ArCameraConfig_create(session, out_camera_config);
+}
+
+void ArCameraConfig_destroy(ArCameraConfig* camera_config) {
+  return g_arcore_api->impl_ArCameraConfig_destroy(camera_config);
+}
+
+void ArCameraConfig_getDepthSensorUsage(const ArSession* session,
+                                        const ArCameraConfig* camera_config,
+                                        uint32_t* out_depth_sensor_usage) {
+  return g_arcore_api->impl_ArCameraConfig_getDepthSensorUsage(
+      session, camera_config, out_depth_sensor_usage);
+}
+
+void ArCameraConfig_getFacingDirection(
+    const ArSession* session,
+    const ArCameraConfig* camera_config,
+    ArCameraConfigFacingDirection* out_facing) {
+  return g_arcore_api->impl_ArCameraConfig_getFacingDirection(
+      session, camera_config, out_facing);
+}
+
+void ArCameraConfig_getImageDimensions(const ArSession* session,
+                                       const ArCameraConfig* camera_config,
+                                       int32_t* out_width,
+                                       int32_t* out_height) {
+  return g_arcore_api->impl_ArCameraConfig_getImageDimensions(
+      session, camera_config, out_width, out_height);
+}
+
+void ArCameraConfig_getTextureDimensions(const ArSession* session,
+                                         const ArCameraConfig* camera_config,
+                                         int32_t* out_width,
+                                         int32_t* out_height) {
+  return g_arcore_api->impl_ArCameraConfig_getTextureDimensions(
+      session, camera_config, out_width, out_height);
+}
+
+void ArCameraConfigFilter_create(const ArSession* session,
+                                 ArCameraConfigFilter** out_filter) {
+  return g_arcore_api->impl_ArCameraConfigFilter_create(session, out_filter);
+}
+
+void ArCameraConfigFilter_destroy(ArCameraConfigFilter* filter) {
+  return g_arcore_api->impl_ArCameraConfigFilter_destroy(filter);
+}
+
+void ArCameraConfigFilter_setDepthSensorUsage(
+    const ArSession* session,
+    ArCameraConfigFilter* filter,
+    uint32_t depth_sensor_usage_filters) {
+  return g_arcore_api->impl_ArCameraConfigFilter_setDepthSensorUsage(
+      session, filter, depth_sensor_usage_filters);
+}
+
+void ArCameraConfigFilter_setTargetFps(const ArSession* session,
+                                       ArCameraConfigFilter* filter,
+                                       const uint32_t fps_filters) {
+  return g_arcore_api->impl_ArCameraConfigFilter_setTargetFps(session, filter,
+                                                              fps_filters);
+}
+
+void ArCameraConfigList_create(const ArSession* session,
+                               ArCameraConfigList** out_list) {
+  return g_arcore_api->impl_ArCameraConfigList_create(session, out_list);
+}
+
+void ArCameraConfigList_destroy(ArCameraConfigList* list) {
+  return g_arcore_api->impl_ArCameraConfigList_destroy(list);
+}
+
+void ArCameraConfigList_getItem(const ArSession* session,
+                                const ArCameraConfigList* list,
+                                int32_t index,
+                                ArCameraConfig* out_camera_config) {
+  return g_arcore_api->impl_ArCameraConfigList_getItem(session, list, index,
+                                                       out_camera_config);
+}
+
+void ArCameraConfigList_getSize(const ArSession* session,
+                                const ArCameraConfigList* list,
+                                int32_t* out_size) {
+  return g_arcore_api->impl_ArCameraConfigList_getSize(session, list, out_size);
+}
+
 void ArConfig_create(const ArSession* session, ArConfig** out_config) {
   return g_arcore_api->impl_ArConfig_create(session, out_config);
 }
@@ -575,6 +677,14 @@
                                                        out_trackable_list);
 }
 
+void ArSession_getSupportedCameraConfigsWithFilter(
+    const ArSession* session,
+    const ArCameraConfigFilter* filter,
+    ArCameraConfigList* list) {
+  return g_arcore_api->impl_ArSession_getSupportedCameraConfigsWithFilter(
+      session, filter, list);
+}
+
 ArStatus ArSession_pause(ArSession* session) {
   return g_arcore_api->impl_ArSession_pause(session);
 }
@@ -583,6 +693,11 @@
   return g_arcore_api->impl_ArSession_resume(session);
 }
 
+ArStatus ArSession_setCameraConfig(const ArSession* session,
+                                   const ArCameraConfig* camera_config) {
+  return g_arcore_api->impl_ArSession_setCameraConfig(session, camera_config);
+}
+
 void ArSession_setCameraTextureName(ArSession* session, uint32_t texture_id) {
   return g_arcore_api->impl_ArSession_setCameraTextureName(session, texture_id);
 }
diff --git a/chrome/browser/android/vr/arcore_device/scoped_arcore_objects.h b/chrome/browser/android/vr/arcore_device/scoped_arcore_objects.h
index ba1f968..c0eb5ef 100644
--- a/chrome/browser/android/vr/arcore_device/scoped_arcore_objects.h
+++ b/chrome/browser/android/vr/arcore_device/scoped_arcore_objects.h
@@ -33,6 +33,24 @@
 }
 
 template <>
+void inline ScopedGenericArObject<ArCameraConfig*>::Free(
+    ArCameraConfig* ar_camera_config) {
+  ArCameraConfig_destroy(ar_camera_config);
+}
+
+template <>
+void inline ScopedGenericArObject<ArCameraConfigFilter*>::Free(
+    ArCameraConfigFilter* ar_camera_config_filter) {
+  ArCameraConfigFilter_destroy(ar_camera_config_filter);
+}
+
+template <>
+void inline ScopedGenericArObject<ArCameraConfigList*>::Free(
+    ArCameraConfigList* ar_camera_config_list) {
+  ArCameraConfigList_destroy(ar_camera_config_list);
+}
+
+template <>
 void inline ScopedGenericArObject<ArPose*>::Free(ArPose* ar_pose) {
   ArPose_destroy(ar_pose);
 }
diff --git a/chrome/browser/browser_switcher/browser_switcher_policy_migrator.cc b/chrome/browser/browser_switcher/browser_switcher_policy_migrator.cc
index d56d7d5c..fc4d2af 100644
--- a/chrome/browser/browser_switcher/browser_switcher_policy_migrator.cc
+++ b/chrome/browser/browser_switcher/browser_switcher_policy_migrator.cc
@@ -62,7 +62,7 @@
   }
   extension_map.Set("browser_switcher_enabled", entry->DeepCopy());
 
-  using Migration = policy::ExtensionPolicyMigrator::Migration;
+  using Migration = policy::PolicyMigrator::Migration;
   const Migration migrations[] = {
       Migration("alternative_browser_path",
                 policy::key::kAlternativeBrowserPath),
diff --git a/chrome/browser/chrome_content_browser_client_unittest.cc b/chrome/browser/chrome_content_browser_client_unittest.cc
index 1755531..42c4094 100644
--- a/chrome/browser/chrome_content_browser_client_unittest.cc
+++ b/chrome/browser/chrome_content_browser_client_unittest.cc
@@ -9,6 +9,7 @@
 #include <memory>
 
 #include "base/bind.h"
+#include "base/bind_helpers.h"
 #include "base/command_line.h"
 #include "base/macros.h"
 #include "base/metrics/field_trial.h"
@@ -882,7 +883,7 @@
                                    true /* expected_disable_secure_dns */);
   captive_portal::CaptivePortalTabHelper::CreateForWebContents(
       web_contents(), CaptivePortalServiceFactory::GetForProfile(profile()),
-      base::Callback<void(void)>());
+      base::NullCallback());
   captive_portal::CaptivePortalTabHelper::FromWebContents(web_contents())
       ->set_is_captive_portal_window();
   NavigateAndCommit(GURL("https://www.google.com"), ui::PAGE_TRANSITION_LINK);
diff --git a/chrome/browser/chromeos/crosapi/DEPS b/chrome/browser/chromeos/crosapi/DEPS
index c995110..abdbca61 100644
--- a/chrome/browser/chromeos/crosapi/DEPS
+++ b/chrome/browser/chromeos/crosapi/DEPS
@@ -6,6 +6,7 @@
   "select_file_crosapi\.cc": [
     # For window parenting.
     "+ash/shell.h",
+    "+ash/wm/desks/desks_util.h",
     # For Chrome OS-specific file manager parameters.
     "+chrome/browser/ui/views/select_file_dialog_extension.h",
   ],
diff --git a/chrome/browser/chromeos/crosapi/select_file_crosapi.cc b/chrome/browser/chromeos/crosapi/select_file_crosapi.cc
index 984db74..935febd6 100644
--- a/chrome/browser/chromeos/crosapi/select_file_crosapi.cc
+++ b/chrome/browser/chromeos/crosapi/select_file_crosapi.cc
@@ -9,14 +9,17 @@
 
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/shell.h"
+#include "ash/wm/desks/desks_util.h"
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "base/numerics/ranges.h"
 #include "chrome/browser/ui/views/select_file_dialog_extension.h"
 #include "chromeos/crosapi/mojom/select_file.mojom.h"
+#include "components/exo/shell_surface_util.h"
 #include "ui/shell_dialogs/select_file_dialog.h"
 #include "ui/shell_dialogs/select_file_policy.h"
 #include "ui/shell_dialogs/selected_file_info.h"
+#include "ui/wm/public/activation_client.h"
 #include "url/gurl.h"
 
 namespace {
@@ -54,6 +57,20 @@
   }
 }
 
+// TODO(https://crbug.com/1090587): Parent to the ShellSurface that spawned
+// the dialog. For now, parent to the active window, which in practice should be
+// the spawning window.
+aura::Window* GetOwnerWindow() {
+  aura::Window* root = ash::Shell::GetRootWindowForNewWindows();
+  aura::Window* active = ::wm::GetActivationClient(root)->GetActiveWindow();
+  // Check that the active window is still a ShellSurface window.
+  if (active && exo::GetShellSurfaceBaseForWindow(active))
+    return active;
+  // Fallback to the active virtual desk.
+  return ash::Shell::GetContainer(root,
+                                  ash::desks_util::GetActiveDeskContainerId());
+}
+
 // Manages a single open/save dialog. There may be multiple dialogs showing at
 // the same time. Deletes itself when the dialog is closed.
 class SelectFileDialogHolder : public ui::SelectFileDialog::Listener {
@@ -67,11 +84,7 @@
         SelectFileDialogExtension::Create(this, /*policy=*/nullptr);
 
     SelectFileDialogExtension::Owner owner;
-    // TODO(https://crbug.com/1090587): Parent to the ShellSurface that spawned
-    // the dialog. For now, just put it on the default desktop.
-    owner.window = ash::Shell::GetContainer(
-        ash::Shell::GetRootWindowForNewWindows(),
-        ash::kShellWindowId_DefaultContainerDeprecated);
+    owner.window = GetOwnerWindow();
     // TODO(https://crbug.com/1090587): Replace with ID from Wayland client.
     owner.lacros_window_id = g_next_window_id++;
 
diff --git a/chrome/browser/chromeos/web_applications/print_management_app_integration_browsertest.cc b/chrome/browser/chromeos/web_applications/print_management_app_integration_browsertest.cc
index 2934fee..ac670bc 100644
--- a/chrome/browser/chromeos/web_applications/print_management_app_integration_browsertest.cc
+++ b/chrome/browser/chromeos/web_applications/print_management_app_integration_browsertest.cc
@@ -27,7 +27,7 @@
                        PrintManagementAppInLauncher) {
   const GURL url(chromeos::kChromeUIPrintManagementAppUrl);
   EXPECT_NO_FATAL_FAILURE(ExpectSystemWebAppValid(
-      web_app::SystemAppType::PRINT_MANAGEMENT, url, "Print Management App"));
+      web_app::SystemAppType::PRINT_MANAGEMENT, url, "Print Jobs"));
 }
 
 INSTANTIATE_TEST_SUITE_P(All,
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index 5941c4b..95ba4e6f 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -13,6 +13,9 @@
 
 assert(enable_extensions)
 
+# See docs/no_sources_assignment_filter.md and https://crbug.com/1018739.
+set_sources_assignment_filter([])
+
 static_library("extensions") {
   sources = [
     "active_install_data.cc",
@@ -154,8 +157,6 @@
     "api/extension_action/extension_page_actions_api_constants.h",
     "api/feedback_private/chrome_feedback_private_delegate.cc",
     "api/feedback_private/chrome_feedback_private_delegate.h",
-    "api/file_handlers/non_native_file_system_delegate_chromeos.cc",
-    "api/file_handlers/non_native_file_system_delegate_chromeos.h",
     "api/file_system/chrome_file_system_delegate.cc",
     "api/file_system/chrome_file_system_delegate.h",
     "api/file_system/file_entry_picker.cc",
@@ -208,14 +209,10 @@
     "api/image_writer_private/image_writer_utility_client.h",
     "api/image_writer_private/operation.cc",
     "api/image_writer_private/operation.h",
-    "api/image_writer_private/operation_chromeos.cc",
     "api/image_writer_private/operation_manager.cc",
     "api/image_writer_private/operation_manager.h",
     "api/image_writer_private/removable_storage_provider.cc",
     "api/image_writer_private/removable_storage_provider.h",
-    "api/image_writer_private/removable_storage_provider_chromeos.cc",
-    "api/image_writer_private/removable_storage_provider_mac.cc",
-    "api/image_writer_private/removable_storage_provider_win.cc",
     "api/image_writer_private/unzip_helper.cc",
     "api/image_writer_private/unzip_helper.h",
     "api/image_writer_private/write_from_file_operation.cc",
@@ -248,8 +245,6 @@
     "api/metrics_private/chrome_metrics_private_delegate.h",
     "api/module/module.cc",
     "api/module/module.h",
-    "api/networking_private/networking_private_ui_delegate_chromeos.cc",
-    "api/networking_private/networking_private_ui_delegate_chromeos.h",
     "api/networking_private/networking_private_ui_delegate_factory_impl.cc",
     "api/networking_private/networking_private_ui_delegate_factory_impl.h",
     "api/notifications/extension_notification_display_helper.cc",
@@ -291,6 +286,8 @@
     "api/preference/preference_api_constants.h",
     "api/preference/preference_helpers.cc",
     "api/preference/preference_helpers.h",
+    "api/processes/processes_api.cc",
+    "api/processes/processes_api.h",
     "api/proxy/proxy_api.cc",
     "api/proxy/proxy_api.h",
     "api/proxy/proxy_api_constants.cc",
@@ -384,7 +381,6 @@
     "api/tabs/tabs_event_router.cc",
     "api/tabs/tabs_event_router.h",
     "api/tabs/tabs_util.h",
-    "api/tabs/tabs_util_chromeos.cc",
     "api/tabs/tabs_windows_api.cc",
     "api/tabs/tabs_windows_api.h",
     "api/tabs/windows_event_router.cc",
@@ -468,8 +464,6 @@
     "chrome_url_request_util.h",
     "chrome_zipfile_installer.cc",
     "chrome_zipfile_installer.h",
-    "clipboard_extension_helper_chromeos.cc",
-    "clipboard_extension_helper_chromeos.h",
     "component_extensions_whitelist/whitelist.cc",
     "component_extensions_whitelist/whitelist.h",
     "component_loader.cc",
@@ -506,8 +500,6 @@
     "extension_action_storage_manager.h",
     "extension_assets_manager.cc",
     "extension_assets_manager.h",
-    "extension_assets_manager_chromeos.cc",
-    "extension_assets_manager_chromeos.h",
     "extension_browser_window_helper.cc",
     "extension_browser_window_helper.h",
     "extension_checkup.cc",
@@ -525,8 +517,6 @@
     "extension_error_ui_default.h",
     "extension_garbage_collector.cc",
     "extension_garbage_collector.h",
-    "extension_garbage_collector_chromeos.cc",
-    "extension_garbage_collector_chromeos.h",
     "extension_garbage_collector_factory.cc",
     "extension_garbage_collector_factory.h",
     "extension_gcm_app_handler.cc",
@@ -600,8 +590,6 @@
     "external_pref_loader.h",
     "external_provider_impl.cc",
     "external_provider_impl.h",
-    "external_registry_loader_win.cc",
-    "external_registry_loader_win.h",
     "forced_extensions/force_installed_metrics.cc",
     "forced_extensions/force_installed_metrics.h",
     "forced_extensions/force_installed_tracker.cc",
@@ -612,10 +600,6 @@
     "forced_extensions/install_stage_tracker_factory.h",
     "global_shortcut_listener.cc",
     "global_shortcut_listener.h",
-    "global_shortcut_listener_mac.h",
-    "global_shortcut_listener_mac.mm",
-    "global_shortcut_listener_win.cc",
-    "global_shortcut_listener_win.h",
     "install_gate.h",
     "install_observer.cc",
     "install_observer.h",
@@ -684,12 +668,6 @@
     "sync_bundle.cc",
     "sync_bundle.h",
     "system_display/display_info_provider.h",
-    "system_display/display_info_provider_chromeos.cc",
-    "system_display/display_info_provider_chromeos.h",
-    "system_display/display_info_provider_mac.cc",
-    "system_display/display_info_provider_mac.h",
-    "system_display/display_info_provider_win.cc",
-    "system_display/display_info_provider_win.h",
     "tab_helper.cc",
     "tab_helper.h",
     "theme_installed_infobar_delegate.cc",
@@ -951,10 +929,14 @@
       "api/enterprise_platform_keys/enterprise_platform_keys_api.h",
       "api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc",
       "api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.h",
+      "api/file_handlers/non_native_file_system_delegate_chromeos.cc",
+      "api/file_handlers/non_native_file_system_delegate_chromeos.h",
       "api/file_system/consent_provider.cc",
       "api/file_system/consent_provider.h",
       "api/file_system/request_file_system_notification.cc",
       "api/file_system/request_file_system_notification.h",
+      "api/image_writer_private/operation_chromeos.cc",
+      "api/image_writer_private/removable_storage_provider_chromeos.cc",
       "api/input_ime/input_ime_api.cc",
       "api/input_ime/input_ime_api.h",
       "api/input_ime/input_ime_api_chromeos.cc",
@@ -968,6 +950,8 @@
       "api/networking_cast_private/chrome_networking_cast_private_delegate.h",
       "api/networking_cast_private/networking_cast_private_api.cc",
       "api/networking_cast_private/networking_cast_private_api.h",
+      "api/networking_private/networking_private_ui_delegate_chromeos.cc",
+      "api/networking_private/networking_private_ui_delegate_chromeos.h",
       "api/platform_keys/platform_keys_api.cc",
       "api/platform_keys/platform_keys_api.h",
       "api/platform_keys/verify_trust_api.cc",
@@ -978,6 +962,7 @@
       "api/settings_private/chromeos_resolve_time_zone_by_geolocation_on_off.h",
       "api/settings_private/generated_time_zone_pref_base.cc",
       "api/settings_private/generated_time_zone_pref_base.h",
+      "api/tabs/tabs_util_chromeos.cc",
       "api/terminal/crostini_startup_status.cc",
       "api/terminal/crostini_startup_status.h",
       "api/terminal/terminal_extension_helper.cc",
@@ -988,6 +973,14 @@
       "api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.h",
       "api/vpn_provider/vpn_service_factory.cc",
       "chrome_kiosk_delegate_chromeos.cc",
+      "clipboard_extension_helper_chromeos.cc",
+      "clipboard_extension_helper_chromeos.h",
+      "extension_assets_manager_chromeos.cc",
+      "extension_assets_manager_chromeos.h",
+      "extension_garbage_collector_chromeos.cc",
+      "extension_garbage_collector_chromeos.h",
+      "system_display/display_info_provider_chromeos.cc",
+      "system_display/display_info_provider_chromeos.h",
       "updater/chromeos_extension_cache_delegate.cc",
       "updater/chromeos_extension_cache_delegate.h",
       "updater/extension_cache_impl.cc",
@@ -1050,30 +1043,23 @@
       deps += [ "//chrome/browser/resources/chromeos/zip_archiver" ]
     }
   } else {
+    assert(!is_chromeos)
     sources += [
       "api/enterprise_reporting_private/chrome_desktop_report_request_helper.cc",
       "api/enterprise_reporting_private/chrome_desktop_report_request_helper.h",
       "api/enterprise_reporting_private/device_info_fetcher.cc",
       "api/enterprise_reporting_private/device_info_fetcher.h",
-      "api/enterprise_reporting_private/device_info_fetcher_linux.cc",
-      "api/enterprise_reporting_private/device_info_fetcher_linux.h",
-      "api/enterprise_reporting_private/device_info_fetcher_mac.h",
-      "api/enterprise_reporting_private/device_info_fetcher_mac.mm",
-      "api/enterprise_reporting_private/device_info_fetcher_win.cc",
-      "api/enterprise_reporting_private/device_info_fetcher_win.h",
       "api/enterprise_reporting_private/enterprise_reporting_private_api.cc",
       "api/enterprise_reporting_private/enterprise_reporting_private_api.h",
       "api/enterprise_reporting_private/prefs.cc",
       "api/enterprise_reporting_private/prefs.h",
       "api/image_writer_private/operation_nonchromeos.cc",
-      "api/image_writer_private/removable_storage_provider_linux.cc",
       "api/messaging/native_message_process_host.cc",
       "api/messaging/native_message_process_host.h",
       "api/messaging/native_messaging_launch_from_native.cc",
       "api/messaging/native_messaging_launch_from_native.h",
       "api/messaging/native_process_launcher.cc",
       "api/messaging/native_process_launcher.h",
-      "api/messaging/native_process_launcher_win.cc",
       "api/tabs/tabs_util.cc",
       "chrome_kiosk_delegate.cc",
       "default_apps.cc",
@@ -1083,6 +1069,13 @@
       "//components/enterprise",
       "//components/keep_alive_registry",
     ]
+    if (is_linux) {
+      sources += [
+        "api/enterprise_reporting_private/device_info_fetcher_linux.cc",
+        "api/enterprise_reporting_private/device_info_fetcher_linux.h",
+        "api/image_writer_private/removable_storage_provider_linux.cc",
+      ]
+    }
     if (is_posix) {
       sources += [ "api/messaging/native_process_launcher_posix.cc" ]
     }
@@ -1103,6 +1096,18 @@
     ]
   }
 
+  if (is_mac) {
+    sources += [
+      "api/enterprise_reporting_private/device_info_fetcher_mac.h",
+      "api/enterprise_reporting_private/device_info_fetcher_mac.mm",
+      "api/image_writer_private/removable_storage_provider_mac.cc",
+      "global_shortcut_listener_mac.h",
+      "global_shortcut_listener_mac.mm",
+      "system_display/display_info_provider_mac.cc",
+      "system_display/display_info_provider_mac.h",
+    ]
+  }
+
   if (is_linux) {
     deps += [ "//third_party/fontconfig" ]
 
@@ -1122,13 +1127,6 @@
     }
   }
 
-  if (!is_android) {
-    sources += [
-      "api/processes/processes_api.cc",
-      "api/processes/processes_api.h",
-    ]
-  }
-
   if (is_win || is_mac) {
     sources += [
       "api/networking_cast_private/chrome_networking_cast_private_delegate.cc",
@@ -1150,6 +1148,18 @@
   }
 
   if (is_win) {
+    sources += [
+      "api/enterprise_reporting_private/device_info_fetcher_win.cc",
+      "api/enterprise_reporting_private/device_info_fetcher_win.h",
+      "api/image_writer_private/removable_storage_provider_win.cc",
+      "api/messaging/native_process_launcher_win.cc",
+      "external_registry_loader_win.cc",
+      "external_registry_loader_win.h",
+      "global_shortcut_listener_win.cc",
+      "global_shortcut_listener_win.h",
+      "system_display/display_info_provider_win.cc",
+      "system_display/display_info_provider_win.h",
+    ]
     deps += [
       "//third_party/iaccessible2",
       "//third_party/isimpledom",
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index d723c48..8a8b0f4 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1696,7 +1696,7 @@
   {
     "name": "enable-md-rounded-corners-on-dialogs",
     "owners": [ "tluk" ],
-    "expiry_milestone": 85
+    "expiry_milestone": 87
   },
   {
     "name": "enable-media-feeds",
diff --git a/chrome/browser/nearby_sharing/local_device_data/BUILD.gn b/chrome/browser/nearby_sharing/local_device_data/BUILD.gn
new file mode 100644
index 0000000..49453330
--- /dev/null
+++ b/chrome/browser/nearby_sharing/local_device_data/BUILD.gn
@@ -0,0 +1,49 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("local_device_data") {
+  sources = [
+    "nearby_share_device_data_updater.cc",
+    "nearby_share_device_data_updater.h",
+    "nearby_share_device_data_updater_impl.cc",
+    "nearby_share_device_data_updater_impl.h",
+  ]
+
+  deps = [
+    "//base",
+    "//chrome/browser/nearby_sharing/client",
+    "//chrome/browser/nearby_sharing/proto",
+  ]
+}
+
+source_set("test_support") {
+  testonly = true
+
+  sources = [
+    "fake_nearby_share_device_data_updater.cc",
+    "fake_nearby_share_device_data_updater.h",
+  ]
+
+  deps = [
+    ":local_device_data",
+    "//base",
+    "//chrome/browser/nearby_sharing/proto",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+
+  sources = [ "nearby_share_device_data_updater_impl_unittest.cc" ]
+
+  deps = [
+    ":local_device_data",
+    "//base",
+    "//base/test:test_support",
+    "//chrome/browser/nearby_sharing/client",
+    "//chrome/browser/nearby_sharing/client:test_support",
+    "//chrome/browser/nearby_sharing/proto",
+    "//testing/gtest",
+  ]
+}
diff --git a/chrome/browser/nearby_sharing/local_device_data/fake_nearby_share_device_data_updater.cc b/chrome/browser/nearby_sharing/local_device_data/fake_nearby_share_device_data_updater.cc
new file mode 100644
index 0000000..6d68ee1
--- /dev/null
+++ b/chrome/browser/nearby_sharing/local_device_data/fake_nearby_share_device_data_updater.cc
@@ -0,0 +1,33 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/nearby_sharing/local_device_data/fake_nearby_share_device_data_updater.h"
+
+FakeNearbyShareDeviceDataUpdater::FakeNearbyShareDeviceDataUpdater(
+    const std::string& device_id)
+    : NearbyShareDeviceDataUpdater(device_id) {}
+
+FakeNearbyShareDeviceDataUpdater::~FakeNearbyShareDeviceDataUpdater() = default;
+
+void FakeNearbyShareDeviceDataUpdater::RunNextRequest(
+    bool success,
+    const base::Optional<nearbyshare::proto::UpdateDeviceResponse>& response) {
+  FinishAttempt(success, response);
+}
+
+void FakeNearbyShareDeviceDataUpdater::HandleNextRequest() {}
+
+std::unique_ptr<NearbyShareDeviceDataUpdater>
+FakeNearbyShareDeviceDataUpdaterFactory::CreateInstance(
+    const std::string& device_id,
+    base::TimeDelta timeout,
+    NearbyShareClientFactory* client_factory) {
+  latest_timeout_ = timeout;
+  latest_client_factory_ = client_factory;
+
+  auto instance = std::make_unique<FakeNearbyShareDeviceDataUpdater>(device_id);
+  instances_.push_back(instance.get());
+
+  return instance;
+}
diff --git a/chrome/browser/nearby_sharing/local_device_data/fake_nearby_share_device_data_updater.h b/chrome/browser/nearby_sharing/local_device_data/fake_nearby_share_device_data_updater.h
new file mode 100644
index 0000000..b01d1b0
--- /dev/null
+++ b/chrome/browser/nearby_sharing/local_device_data/fake_nearby_share_device_data_updater.h
@@ -0,0 +1,73 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_NEARBY_SHARING_LOCAL_DEVICE_DATA_FAKE_NEARBY_SHARE_DEVICE_DATA_UPDATER_H_
+#define CHROME_BROWSER_NEARBY_SHARING_LOCAL_DEVICE_DATA_FAKE_NEARBY_SHARE_DEVICE_DATA_UPDATER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/containers/queue.h"
+#include "base/optional.h"
+#include "base/time/time.h"
+#include "chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater.h"
+#include "chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater_impl.h"
+#include "chrome/browser/nearby_sharing/proto/device_rpc.pb.h"
+
+// An fake implementation of NearbyShareDeviceDataUpdater for use in unit tests.
+class FakeNearbyShareDeviceDataUpdater : public NearbyShareDeviceDataUpdater {
+ public:
+  explicit FakeNearbyShareDeviceDataUpdater(const std::string& device_id);
+  ~FakeNearbyShareDeviceDataUpdater() override;
+
+  // Advances the request queue and invokes request callback with the input
+  // parameters |success| and |response|.
+  void RunNextRequest(
+      bool success,
+      const base::Optional<nearbyshare::proto::UpdateDeviceResponse>& response);
+
+  const std::string& device_id() const { return device_id_; }
+
+  const base::queue<Request>& pending_requests() const {
+    return pending_requests_;
+  }
+
+ private:
+  // NearbyShareDeviceDataUpdater:
+  void HandleNextRequest() override;
+};
+
+// A fake NearbyShareDeviceDataUpdaterImpl factory for use in unit tests.
+class FakeNearbyShareDeviceDataUpdaterFactory
+    : public NearbyShareDeviceDataUpdaterImpl::Factory {
+ public:
+  FakeNearbyShareDeviceDataUpdaterFactory();
+  ~FakeNearbyShareDeviceDataUpdaterFactory() override;
+
+  // Returns all FakeNearbyShareDeviceDataUpdater instances created by
+  // CreateInstance().
+  std::vector<FakeNearbyShareDeviceDataUpdater*>& instances() {
+    return instances_;
+  }
+
+  base::TimeDelta latest_timeout() const { return latest_timeout_; }
+
+  NearbyShareClientFactory* latest_client_factory() const {
+    return latest_client_factory_;
+  }
+
+ private:
+  // NearbyShareDeviceDataUpdaterImpl::Factory:
+  std::unique_ptr<NearbyShareDeviceDataUpdater> CreateInstance(
+      const std::string& device_id,
+      base::TimeDelta timeout,
+      NearbyShareClientFactory* client_factory) override;
+
+  std::vector<FakeNearbyShareDeviceDataUpdater*> instances_;
+  base::TimeDelta latest_timeout_;
+  NearbyShareClientFactory* latest_client_factory_ = nullptr;
+};
+
+#endif  // CHROME_BROWSER_NEARBY_SHARING_LOCAL_DEVICE_DATA_FAKE_NEARBY_SHARE_DEVICE_DATA_UPDATER_H_
diff --git a/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater.cc b/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater.cc
new file mode 100644
index 0000000..10e7f14
--- /dev/null
+++ b/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater.cc
@@ -0,0 +1,68 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <utility>
+
+#include "base/check.h"
+#include "chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater.h"
+
+NearbyShareDeviceDataUpdater::Request::Request(
+    base::Optional<std::string> device_name,
+    base::Optional<std::vector<nearbyshare::proto::Contact>> contacts,
+    base::Optional<std::vector<nearbyshare::proto::PublicCertificate>>
+        certificates,
+    ResultCallback callback)
+    : device_name(std::move(device_name)),
+      contacts(std::move(contacts)),
+      certificates(std::move(certificates)),
+      callback(std::move(callback)) {}
+
+NearbyShareDeviceDataUpdater::Request::Request(
+    NearbyShareDeviceDataUpdater::Request&& request) = default;
+
+NearbyShareDeviceDataUpdater::Request&
+NearbyShareDeviceDataUpdater::Request::operator=(
+    NearbyShareDeviceDataUpdater::Request&& request) = default;
+
+NearbyShareDeviceDataUpdater::Request::~Request() = default;
+
+NearbyShareDeviceDataUpdater::NearbyShareDeviceDataUpdater(
+    const std::string& device_id)
+    : device_id_(device_id) {}
+
+NearbyShareDeviceDataUpdater::~NearbyShareDeviceDataUpdater() = default;
+
+void NearbyShareDeviceDataUpdater::UpdateDeviceData(
+    base::Optional<std::string> device_name,
+    base::Optional<std::vector<nearbyshare::proto::Contact>> contacts,
+    base::Optional<std::vector<nearbyshare::proto::PublicCertificate>>
+        certificates,
+    ResultCallback callback) {
+  pending_requests_.emplace(std::move(device_name), std::move(contacts),
+                            std::move(certificates), std::move(callback));
+  ProcessRequestQueue();
+}
+
+void NearbyShareDeviceDataUpdater::ProcessRequestQueue() {
+  if (is_request_in_progress_ || pending_requests_.empty())
+    return;
+
+  is_request_in_progress_ = true;
+  HandleNextRequest();
+}
+
+void NearbyShareDeviceDataUpdater::FinishAttempt(
+    bool success,
+    const base::Optional<nearbyshare::proto::UpdateDeviceResponse>& response) {
+  DCHECK(is_request_in_progress_);
+  DCHECK(!pending_requests_.empty());
+
+  Request current_request = std::move(pending_requests_.front());
+  pending_requests_.pop();
+
+  std::move(current_request.callback).Run(success, response);
+
+  is_request_in_progress_ = false;
+  ProcessRequestQueue();
+}
diff --git a/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater.h b/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater.h
new file mode 100644
index 0000000..0bde64c
--- /dev/null
+++ b/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater.h
@@ -0,0 +1,91 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_NEARBY_SHARING_LOCAL_DEVICE_DATA_NEARBY_SHARE_DEVICE_DATA_UPDATER_H_
+#define CHROME_BROWSER_NEARBY_SHARING_LOCAL_DEVICE_DATA_NEARBY_SHARE_DEVICE_DATA_UPDATER_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/containers/queue.h"
+#include "base/optional.h"
+#include "chrome/browser/nearby_sharing/proto/device_rpc.pb.h"
+#include "chrome/browser/nearby_sharing/proto/rpc_resources.pb.h"
+
+// Manages a queue of data needed to make UpdateDevice RPC requests to the
+// Nearby Server. Implementations should make the actual HTTP calls by
+// overriding HandleNextRequest(), which is invoked when the next request is
+// ready to be run. Implementations should call FinishAttempt() with the result
+// of the attempt and possibly the response.
+// TODO(crbug.com/1105547): Instead of queuing requests, hold a single pending
+// request and update the fields as other UpdateDeviceData() call are made.
+// Then, queue up all of callbacks from the merged requests in the Request
+// struct; invoke the callback in the order they were added. This will reduce
+// the number of UpdateDevice RPC calls.
+class NearbyShareDeviceDataUpdater {
+ public:
+  using ResultCallback = base::OnceCallback<void(
+      bool,
+      const base::Optional<nearbyshare::proto::UpdateDeviceResponse>&)>;
+
+  struct Request {
+    Request(base::Optional<std::string> device_name,
+            base::Optional<std::vector<nearbyshare::proto::Contact>> contacts,
+            base::Optional<std::vector<nearbyshare::proto::PublicCertificate>>
+                certificates,
+            ResultCallback callback);
+    Request(Request&& request);
+    Request& operator=(Request&& request);
+    Request(const Request&) = delete;
+    Request& operator=(const Request&) = delete;
+    ~Request();
+
+    base::Optional<std::string> device_name;
+    base::Optional<std::vector<nearbyshare::proto::Contact>> contacts;
+    base::Optional<std::vector<nearbyshare::proto::PublicCertificate>>
+        certificates;
+    ResultCallback callback;
+  };
+
+  // |device_id|: The ID used by the Nearby server to differentiate multiple
+  //              devices from the same account.
+  explicit NearbyShareDeviceDataUpdater(const std::string& device_id);
+
+  virtual ~NearbyShareDeviceDataUpdater();
+
+  // Queue up an UpdateDevice RPC request to update the following fields on the
+  // Nearby server if the parameter is not base::nullopt:
+  //
+  // |device_name|: The device display name, for example, "Joe's Pixel".
+  //
+  // |contacts|: The list of contacts that the Nearby server will send
+  //             all-contacts-visibility certificates to. Contacts marked
+  //             is_selected will be sent selected-contacts-visibility
+  //             certificates.
+  //
+  // |certificates|: The local device's certificates that the Nearby server will
+  //                 distribute to the appropriate |contacts|.
+  //
+  // If only the UpdateDevice RPC response data is desired, set all
+  // aforementioned parameters to base::nullopt.
+  void UpdateDeviceData(
+      base::Optional<std::string> device_name,
+      base::Optional<std::vector<nearbyshare::proto::Contact>> contacts,
+      base::Optional<std::vector<nearbyshare::proto::PublicCertificate>>
+          certificates,
+      ResultCallback callback);
+
+ protected:
+  void ProcessRequestQueue();
+  virtual void HandleNextRequest() = 0;
+  void FinishAttempt(
+      bool success,
+      const base::Optional<nearbyshare::proto::UpdateDeviceResponse>& response);
+
+  std::string device_id_;
+  bool is_request_in_progress_ = false;
+  base::queue<Request> pending_requests_;
+};
+
+#endif  // CHROME_BROWSER_NEARBY_SHARING_LOCAL_DEVICE_DATA_NEARBY_SHARE_DEVICE_DATA_UPDATER_H_
diff --git a/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater_impl.cc b/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater_impl.cc
new file mode 100644
index 0000000..e06759582
--- /dev/null
+++ b/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater_impl.cc
@@ -0,0 +1,149 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater_impl.h"
+
+#include "base/memory/ptr_util.h"
+#include "chrome/browser/nearby_sharing/client/nearby_share_client.h"
+#include "chrome/browser/nearby_sharing/proto/rpc_resources.pb.h"
+
+namespace {
+
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class UpdaterResultCode {
+  kSuccess = 0,
+  kTimeout = 1,
+  kHttpErrorOffline = 2,
+  kHttpErrorEndpointNotFound = 3,
+  kHttpErrorAuthenticationError = 4,
+  kHttpErrorBadRequest = 5,
+  kHttpErrorResponseMalformed = 6,
+  kHttpErrorInternalServerError = 7,
+  kHttpErrorUnknown = 8,
+  kMaxValue = kHttpErrorUnknown
+};
+
+const char kDeviceIdPrefix[] = "users/me/devices/";
+const char kDeviceNameFieldMaskPath[] = "device.display_name";
+const char kContactsFieldMaskPath[] = "device.contacts";
+const char kCertificatesFieldMaskPath[] = "device.public_certificates";
+
+UpdaterResultCode RequestErrorToUpdaterResultCode(
+    NearbyShareRequestError error) {
+  switch (error) {
+    case NearbyShareRequestError::kOffline:
+      return UpdaterResultCode::kHttpErrorOffline;
+    case NearbyShareRequestError::kEndpointNotFound:
+      return UpdaterResultCode::kHttpErrorEndpointNotFound;
+    case NearbyShareRequestError::kAuthenticationError:
+      return UpdaterResultCode::kHttpErrorAuthenticationError;
+    case NearbyShareRequestError::kBadRequest:
+      return UpdaterResultCode::kHttpErrorBadRequest;
+    case NearbyShareRequestError::kResponseMalformed:
+      return UpdaterResultCode::kHttpErrorResponseMalformed;
+    case NearbyShareRequestError::kInternalServerError:
+      return UpdaterResultCode::kHttpErrorInternalServerError;
+    case NearbyShareRequestError::kUnknown:
+      return UpdaterResultCode::kHttpErrorUnknown;
+  }
+}
+
+void RecordResultMetrics(UpdaterResultCode code) {
+  // TODO(crbug.com/1105579): Record a histogram value for each result.
+}
+
+}  // namespace
+
+// static
+NearbyShareDeviceDataUpdaterImpl::Factory*
+    NearbyShareDeviceDataUpdaterImpl::Factory::test_factory_ = nullptr;
+
+// static
+std::unique_ptr<NearbyShareDeviceDataUpdater>
+NearbyShareDeviceDataUpdaterImpl::Factory::Create(
+    const std::string& device_id,
+    base::TimeDelta timeout,
+    NearbyShareClientFactory* client_factory) {
+  if (test_factory_)
+    return test_factory_->CreateInstance(device_id, timeout, client_factory);
+
+  return base::WrapUnique(
+      new NearbyShareDeviceDataUpdaterImpl(device_id, timeout, client_factory));
+}
+
+// static
+void NearbyShareDeviceDataUpdaterImpl::Factory::SetFactoryForTesting(
+    Factory* test_factory) {
+  test_factory_ = test_factory;
+}
+
+NearbyShareDeviceDataUpdaterImpl::Factory::~Factory() = default;
+
+NearbyShareDeviceDataUpdaterImpl::NearbyShareDeviceDataUpdaterImpl(
+    const std::string& device_id,
+    base::TimeDelta timeout,
+    NearbyShareClientFactory* client_factory)
+    : NearbyShareDeviceDataUpdater(device_id),
+      timeout_(timeout),
+      client_factory_(client_factory) {}
+
+NearbyShareDeviceDataUpdaterImpl::~NearbyShareDeviceDataUpdaterImpl() = default;
+
+void NearbyShareDeviceDataUpdaterImpl::HandleNextRequest() {
+  timer_.Start(FROM_HERE, timeout_,
+               base::BindOnce(&NearbyShareDeviceDataUpdaterImpl::OnTimeout,
+                              base::Unretained(this)));
+
+  nearbyshare::proto::UpdateDeviceRequest request;
+  request.mutable_device()->set_name(kDeviceIdPrefix + device_id_);
+  if (pending_requests_.front().device_name) {
+    request.mutable_device()->set_display_name(
+        *pending_requests_.front().device_name);
+    request.mutable_update_mask()->add_paths(kDeviceNameFieldMaskPath);
+  }
+  if (pending_requests_.front().contacts) {
+    *request.mutable_device()->mutable_contacts() = {
+        pending_requests_.front().contacts->begin(),
+        pending_requests_.front().contacts->end()};
+    request.mutable_update_mask()->add_paths(kContactsFieldMaskPath);
+  }
+  if (pending_requests_.front().certificates) {
+    *request.mutable_device()->mutable_public_certificates() = {
+        pending_requests_.front().certificates->begin(),
+        pending_requests_.front().certificates->end()};
+    request.mutable_update_mask()->add_paths(kCertificatesFieldMaskPath);
+  }
+
+  client_ = client_factory_->CreateInstance();
+  client_->UpdateDevice(
+      request,
+      base::BindOnce(&NearbyShareDeviceDataUpdaterImpl::OnRpcSuccess,
+                     base::Unretained(this)),
+      base::BindOnce(&NearbyShareDeviceDataUpdaterImpl::OnRpcFailure,
+                     base::Unretained(this)));
+}
+
+void NearbyShareDeviceDataUpdaterImpl::OnRpcSuccess(
+    const nearbyshare::proto::UpdateDeviceResponse& response) {
+  timer_.Stop();
+  nearbyshare::proto::UpdateDeviceResponse response_copy(response);
+  client_.reset();
+  RecordResultMetrics(UpdaterResultCode::kSuccess);
+  FinishAttempt(/*success=*/true, response_copy);
+}
+
+void NearbyShareDeviceDataUpdaterImpl::OnRpcFailure(
+    NearbyShareRequestError error) {
+  timer_.Stop();
+  client_.reset();
+  RecordResultMetrics(RequestErrorToUpdaterResultCode(error));
+  FinishAttempt(/*success=*/false, /*response=*/base::nullopt);
+}
+
+void NearbyShareDeviceDataUpdaterImpl::OnTimeout() {
+  client_.reset();
+  RecordResultMetrics(UpdaterResultCode::kTimeout);
+  FinishAttempt(/*success=*/false, /*response=*/base::nullopt);
+}
diff --git a/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater_impl.h b/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater_impl.h
new file mode 100644
index 0000000..dfebbe1
--- /dev/null
+++ b/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater_impl.h
@@ -0,0 +1,62 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_NEARBY_SHARING_LOCAL_DEVICE_DATA_NEARBY_SHARE_DEVICE_DATA_UPDATER_IMPL_H_
+#define CHROME_BROWSER_NEARBY_SHARING_LOCAL_DEVICE_DATA_NEARBY_SHARE_DEVICE_DATA_UPDATER_IMPL_H_
+
+#include <memory>
+
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "chrome/browser/nearby_sharing/client/nearby_share_request_error.h"
+#include "chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater.h"
+#include "chrome/browser/nearby_sharing/proto/device_rpc.pb.h"
+
+class NearbyShareClient;
+class NearbyShareClientFactory;
+
+// An implementation of NearbyShareDeviceDataUpdater that uses the
+// NearbyShareClient to make UpdateDevice RPC calls to the Nearby server. An
+// UpdateDeviceData() attempt will fail if a response is not received within the
+// specified timeout value.
+class NearbyShareDeviceDataUpdaterImpl : public NearbyShareDeviceDataUpdater {
+ public:
+  class Factory {
+   public:
+    static std::unique_ptr<NearbyShareDeviceDataUpdater> Create(
+        const std::string& device_id,
+        base::TimeDelta timeout,
+        NearbyShareClientFactory* client_factory);
+    static void SetFactoryForTesting(Factory* test_factory);
+
+   protected:
+    virtual ~Factory();
+    virtual std::unique_ptr<NearbyShareDeviceDataUpdater> CreateInstance(
+        const std::string& device_id,
+        base::TimeDelta timeout,
+        NearbyShareClientFactory* client_factory) = 0;
+
+   private:
+    static Factory* test_factory_;
+  };
+
+  ~NearbyShareDeviceDataUpdaterImpl() override;
+
+ private:
+  NearbyShareDeviceDataUpdaterImpl(const std::string& device_id,
+                                   base::TimeDelta timeout,
+                                   NearbyShareClientFactory* client_factory);
+
+  void HandleNextRequest() override;
+  void OnTimeout();
+  void OnRpcSuccess(const nearbyshare::proto::UpdateDeviceResponse& response);
+  void OnRpcFailure(NearbyShareRequestError error);
+
+  base::TimeDelta timeout_;
+  NearbyShareClientFactory* client_factory_ = nullptr;
+  std::unique_ptr<NearbyShareClient> client_;
+  base::OneShotTimer timer_;
+};
+
+#endif  // CHROME_BROWSER_NEARBY_SHARING_LOCAL_DEVICE_DATA_NEARBY_SHARE_DEVICE_DATA_UPDATER_IMPL_H_
diff --git a/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater_impl_unittest.cc b/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater_impl_unittest.cc
new file mode 100644
index 0000000..f6b0b9e
--- /dev/null
+++ b/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater_impl_unittest.cc
@@ -0,0 +1,291 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/no_destructor.h"
+#include "base/optional.h"
+#include "base/stl_util.h"
+#include "base/test/task_environment.h"
+#include "base/time/clock.h"
+#include "base/time/time.h"
+#include "chrome/browser/nearby_sharing/client/fake_nearby_share_client.h"
+#include "chrome/browser/nearby_sharing/client/nearby_share_request_error.h"
+#include "chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater_impl.h"
+#include "chrome/browser/nearby_sharing/proto/device_rpc.pb.h"
+#include "chrome/browser/nearby_sharing/proto/rpc_resources.pb.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kDeviceIdPrefix[] = "users/me/devices/";
+const char kTestDeviceId[] = "test_device_id";
+const char kTestDeviceName[] = "test_device_name";
+const char kTestContactEmail1[] = "test1@gmail.com";
+const char kTestContactEmail2[] = "test2@gmail.com";
+const char kTestCertificateId1[] = "cert_id_1";
+const char kTestCertificateId2[] = "cert_id_2";
+const char kTestPersonName[] = "person_name";
+constexpr base::TimeDelta kTestTimeout = base::TimeDelta::FromMinutes(123);
+
+const std::vector<nearbyshare::proto::Contact>& TestContactList() {
+  static const base::NoDestructor<std::vector<nearbyshare::proto::Contact>>
+      list([] {
+        nearbyshare::proto::Contact contact1;
+        contact1.mutable_identifier()->set_account_name(kTestContactEmail1);
+        nearbyshare::proto::Contact contact2;
+        contact2.mutable_identifier()->set_account_name(kTestContactEmail2);
+        return std::vector<nearbyshare::proto::Contact>{contact1, contact2};
+      }());
+  return *list;
+}
+
+const std::vector<nearbyshare::proto::PublicCertificate>&
+TestCertificateList() {
+  static const base::NoDestructor<
+      std::vector<nearbyshare::proto::PublicCertificate>>
+      list([] {
+        nearbyshare::proto::PublicCertificate cert1;
+        cert1.set_secret_id(kTestCertificateId1);
+        nearbyshare::proto::PublicCertificate cert2;
+        cert2.set_secret_id(kTestCertificateId2);
+        return std::vector<nearbyshare::proto::PublicCertificate>{cert1, cert2};
+      }());
+  return *list;
+}
+
+const nearbyshare::proto::UpdateDeviceResponse& TestResponse() {
+  static const base::NoDestructor<nearbyshare::proto::UpdateDeviceResponse>
+      response([] {
+        nearbyshare::proto::UpdateDeviceResponse response;
+        response.set_person_name(kTestPersonName);
+        return response;
+      }());
+  return *response;
+}
+
+void VerifyRequest(
+    const base::Optional<std::string>& expected_device_name,
+    const base::Optional<std::vector<nearbyshare::proto::Contact>>&
+        expected_contacts,
+    const base::Optional<std::vector<nearbyshare::proto::PublicCertificate>>&
+        expected_certificates,
+    const nearbyshare::proto::UpdateDeviceRequest& request) {
+  std::vector<std::string> field_mask{request.update_mask().paths().begin(),
+                                      request.update_mask().paths().end()};
+
+  EXPECT_EQ(static_cast<size_t>(expected_device_name.has_value()) +
+                static_cast<size_t>(expected_contacts.has_value()) +
+                static_cast<size_t>(expected_certificates.has_value()),
+            field_mask.size());
+  EXPECT_EQ(expected_device_name.has_value(),
+            base::Contains(field_mask, "device.display_name"));
+  EXPECT_EQ(expected_contacts.has_value(),
+            base::Contains(field_mask, "device.contacts"));
+  EXPECT_EQ(expected_certificates.has_value(),
+            base::Contains(field_mask, "device.public_certificates"));
+
+  EXPECT_EQ(std::string(kDeviceIdPrefix) + kTestDeviceId,
+            request.device().name());
+
+  EXPECT_EQ(expected_device_name.value_or(std::string()),
+            request.device().display_name());
+
+  if (expected_contacts) {
+    ASSERT_EQ(static_cast<int>(expected_contacts->size()),
+              request.device().contacts().size());
+    for (size_t i = 0; i < expected_contacts->size(); ++i) {
+      EXPECT_EQ((*expected_contacts)[i].SerializeAsString(),
+                request.device().contacts()[i].SerializeAsString());
+    }
+  } else {
+    EXPECT_TRUE(request.device().contacts().empty());
+  }
+
+  if (expected_certificates) {
+    ASSERT_EQ(static_cast<int>(expected_certificates->size()),
+              request.device().public_certificates().size());
+    for (size_t i = 0; i < expected_certificates->size(); ++i) {
+      EXPECT_EQ((*expected_certificates)[i].SerializeAsString(),
+                request.device().public_certificates()[i].SerializeAsString());
+    }
+  } else {
+    EXPECT_TRUE(request.device().public_certificates().empty());
+  }
+}
+
+void VerifyResponse(
+    const base::Optional<nearbyshare::proto::UpdateDeviceResponse>&
+        expected_response,
+    const base::Optional<nearbyshare::proto::UpdateDeviceResponse>& response) {
+  if (expected_response) {
+    ASSERT_TRUE(response);
+    EXPECT_EQ(expected_response->SerializeAsString(),
+              response->SerializeAsString());
+  } else {
+    EXPECT_FALSE(response);
+  }
+}
+
+}  // namespace
+
+class NearbyShareDeviceDataUpdaterImplTest : public ::testing::Test {
+ protected:
+  enum class UpdateDeviceRequestResult { kSuccess, kHttpFailure, kTimeout };
+
+  NearbyShareDeviceDataUpdaterImplTest() = default;
+  ~NearbyShareDeviceDataUpdaterImplTest() override = default;
+
+  void SetUp() override {
+    updater_ = NearbyShareDeviceDataUpdaterImpl::Factory::Create(
+        kTestDeviceId, kTestTimeout, &fake_client_factory_);
+  }
+
+  void CallUpdateDeviceData(
+      const base::Optional<std::string>& device_name,
+      const base::Optional<std::vector<nearbyshare::proto::Contact>>& contacts,
+      const base::Optional<std::vector<nearbyshare::proto::PublicCertificate>>&
+          certificates) {
+    updater_->UpdateDeviceData(
+        device_name, contacts, certificates,
+        base::BindOnce(&NearbyShareDeviceDataUpdaterImplTest::OnResult,
+                       base::Unretained(this)));
+  }
+
+  void ProcessNextUpdateDeviceDataRequest(
+      const base::Optional<std::string>& expected_device_name,
+      const base::Optional<std::vector<nearbyshare::proto::Contact>>&
+          expected_contacts,
+      const base::Optional<std::vector<nearbyshare::proto::PublicCertificate>>&
+          expected_certificates,
+      UpdateDeviceRequestResult result) {
+    // Verify the next request.
+    ASSERT_FALSE(fake_client_factory_.instances().empty());
+    FakeNearbyShareClient* client = fake_client_factory_.instances().back();
+    ASSERT_EQ(1u, client->update_device_requests().size());
+    VerifyRequest(expected_device_name, expected_contacts,
+                  expected_certificates,
+                  client->update_device_requests()[0].request);
+
+    // Send and verify the response.
+    size_t num_results = results_.size();
+    size_t num_responses = responses_.size();
+    switch (result) {
+      case UpdateDeviceRequestResult::kSuccess:
+        std::move(client->update_device_requests()[0].callback)
+            .Run(TestResponse());
+        return;
+      case UpdateDeviceRequestResult::kHttpFailure:
+        std::move(client->update_device_requests()[0].error_callback)
+            .Run(NearbyShareRequestError::kBadRequest);
+        return;
+      case UpdateDeviceRequestResult::kTimeout:
+        FastForward(kTestTimeout);
+        return;
+    }
+    EXPECT_EQ(num_results + 1, results_.size());
+    EXPECT_EQ(num_responses + 1, responses_.size());
+
+    bool success = result == UpdateDeviceRequestResult::kSuccess;
+    EXPECT_EQ(success, results_.back());
+    VerifyResponse(
+        success ? base::make_optional(TestResponse()) : base::nullopt,
+        responses_.back());
+  }
+
+ private:
+  // Fast-forwards mock time by |delta| and fires relevant timers.
+  void FastForward(base::TimeDelta delta) {
+    task_environment_.FastForwardBy(delta);
+  }
+
+  // The callback passed into UpdateDeviceData().
+  void OnResult(bool success,
+                const base::Optional<nearbyshare::proto::UpdateDeviceResponse>&
+                    response) {
+    results_.push_back(success);
+    responses_.push_back(response);
+  }
+
+  base::test::SingleThreadTaskEnvironment task_environment_{
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+  std::vector<bool> results_;
+  std::vector<base::Optional<nearbyshare::proto::UpdateDeviceResponse>>
+      responses_;
+  FakeNearbyShareClientFactory fake_client_factory_;
+  std::unique_ptr<NearbyShareDeviceDataUpdater> updater_;
+};
+
+TEST_F(NearbyShareDeviceDataUpdaterImplTest, Success_NoParameters) {
+  CallUpdateDeviceData(/*device_name=*/base::nullopt,
+                       /*contacts=*/base::nullopt,
+                       /*certificates=*/base::nullopt);
+  ProcessNextUpdateDeviceDataRequest(
+      /*expected_device_name=*/base::nullopt,
+      /*expected_contacts=*/base::nullopt,
+      /*expected_certificates=*/base::nullopt,
+      UpdateDeviceRequestResult::kSuccess);
+}
+
+TEST_F(NearbyShareDeviceDataUpdaterImplTest, Success_AllParameters) {
+  CallUpdateDeviceData(kTestDeviceName, TestContactList(),
+                       TestCertificateList());
+  ProcessNextUpdateDeviceDataRequest(kTestDeviceName, TestContactList(),
+                                     TestCertificateList(),
+                                     UpdateDeviceRequestResult::kSuccess);
+}
+
+TEST_F(NearbyShareDeviceDataUpdaterImplTest, Success_OneParameter) {
+  CallUpdateDeviceData(kTestDeviceName,
+                       /*contacts=*/base::nullopt,
+                       /*certificates=*/base::nullopt);
+  ProcessNextUpdateDeviceDataRequest(kTestDeviceName,
+                                     /*expected_contacts=*/base::nullopt,
+                                     /*expected_certificates=*/base::nullopt,
+                                     UpdateDeviceRequestResult::kSuccess);
+}
+
+TEST_F(NearbyShareDeviceDataUpdaterImplTest, Failure_Timeout) {
+  CallUpdateDeviceData(kTestDeviceName, TestContactList(),
+                       TestCertificateList());
+  ProcessNextUpdateDeviceDataRequest(kTestDeviceName, TestContactList(),
+                                     TestCertificateList(),
+                                     UpdateDeviceRequestResult::kTimeout);
+}
+
+TEST_F(NearbyShareDeviceDataUpdaterImplTest, Failure_HttpError) {
+  CallUpdateDeviceData(kTestDeviceName, TestContactList(),
+                       TestCertificateList());
+  ProcessNextUpdateDeviceDataRequest(kTestDeviceName, TestContactList(),
+                                     TestCertificateList(),
+                                     UpdateDeviceRequestResult::kHttpFailure);
+}
+
+TEST_F(NearbyShareDeviceDataUpdaterImplTest, QueuedRequests) {
+  // Queue requests while waiting to process.
+  CallUpdateDeviceData(/*device_name=*/base::nullopt,
+                       /*contacts=*/base::nullopt,
+                       /*certificates=*/base::nullopt);
+  CallUpdateDeviceData(kTestDeviceName, TestContactList(),
+                       TestCertificateList());
+  CallUpdateDeviceData(kTestDeviceName,
+                       /*contacts=*/base::nullopt,
+                       /*certificates=*/base::nullopt);
+
+  // Requests are processed in the order they are received.
+  ProcessNextUpdateDeviceDataRequest(
+      /*expected_device_name=*/base::nullopt,
+      /*expected_contacts=*/base::nullopt,
+      /*expected_certificates=*/base::nullopt,
+      UpdateDeviceRequestResult::kSuccess);
+  ProcessNextUpdateDeviceDataRequest(kTestDeviceName, TestContactList(),
+                                     TestCertificateList(),
+                                     UpdateDeviceRequestResult::kTimeout);
+  ProcessNextUpdateDeviceDataRequest(kTestDeviceName,
+                                     /*expected_contacts=*/base::nullopt,
+                                     /*expected_certificates=*/base::nullopt,
+                                     UpdateDeviceRequestResult::kHttpFailure);
+}
diff --git a/chrome/browser/policy/chrome_extension_policy_migrator.cc b/chrome/browser/policy/chrome_extension_policy_migrator.cc
index 5237783..1b0510c 100644
--- a/chrome/browser/policy/chrome_extension_policy_migrator.cc
+++ b/chrome/browser/policy/chrome_extension_policy_migrator.cc
@@ -5,10 +5,8 @@
 #include "chrome/browser/policy/chrome_extension_policy_migrator.h"
 
 #include "base/logging.h"
-#include "base/strings/utf_string_conversions.h"
 #include "components/strings/grit/components_strings.h"
 #include "extensions/common/hashed_extension_id.h"
-#include "ui/base/l10n/l10n_util.h"
 
 namespace policy {
 
@@ -46,29 +44,7 @@
       PolicyDomain::POLICY_DOMAIN_CHROME, /* component_id */ std::string()));
 
   for (const auto& migration : migrations) {
-    PolicyMap::Entry* entry = extension_map->GetMutable(migration.old_name);
-    if (entry) {
-      if (!chrome_map.Get(migration.new_name)) {
-        VLOG(3) << "Extension policy is configured: '" << migration.old_name
-                << "'. Copied to '" << migration.new_name << "'.";
-        auto new_entry = entry->DeepCopy();
-        migration.transform.Run(new_entry.value());
-        new_entry.AddError(
-            l10n_util::GetStringFUTF8(IDS_POLICY_MIGRATED_NEW_POLICY,
-                                      base::UTF8ToUTF16(migration.old_name)));
-        chrome_map.Set(migration.new_name, std::move(new_entry));
-      } else {
-        VLOG(3) << "Extension policy is configured, but conflicts: '"
-                << migration.old_name << "' (Chrome policy '"
-                << migration.new_name << "' is also set). Skipped.";
-      }
-      entry->AddError(
-          l10n_util::GetStringFUTF8(IDS_POLICY_MIGRATED_OLD_POLICY,
-                                    base::UTF8ToUTF16(migration.new_name)));
-    } else {
-      VLOG(3) << "Extension policy is not configured: '" << migration.old_name
-              << "'. Skipped.";
-    }
+    CopyPolicyIfUnset(*extension_map, &chrome_map, migration);
   }
 }
 
diff --git a/chrome/browser/policy/chrome_extension_policy_migrator.h b/chrome/browser/policy/chrome_extension_policy_migrator.h
index 75d5ffda..5b92268 100644
--- a/chrome/browser/policy/chrome_extension_policy_migrator.h
+++ b/chrome/browser/policy/chrome_extension_policy_migrator.h
@@ -5,12 +5,16 @@
 #ifndef CHROME_BROWSER_POLICY_CHROME_EXTENSION_POLICY_MIGRATOR_H_
 #define CHROME_BROWSER_POLICY_CHROME_EXTENSION_POLICY_MIGRATOR_H_
 
-#include "components/policy/core/common/extension_policy_migrator.h"
+#include "components/policy/core/common/policy_migrator.h"
 
 namespace policy {
 
-// ExtensionPolicyMigrator with chrome-specific helper functions.
-class ChromeExtensionPolicyMigrator : public ExtensionPolicyMigrator {
+// A helper class that migrates a deprecated policy to a new policy across
+// domain boundaries, by setting up the new policy based on the old one. It can
+// migrate a deprecated extension policy to a new Chrome policy.
+//
+// PolicyMigrator with chrome-specific helper functions.
+class ChromeExtensionPolicyMigrator : public PolicyMigrator {
  public:
   ~ChromeExtensionPolicyMigrator() override {}
 
diff --git a/chrome/browser/policy/chrome_extension_policy_migrator_unittest.cc b/chrome/browser/policy/chrome_extension_policy_migrator_unittest.cc
index f475203..c204649 100644
--- a/chrome/browser/policy/chrome_extension_policy_migrator_unittest.cc
+++ b/chrome/browser/policy/chrome_extension_policy_migrator_unittest.cc
@@ -51,7 +51,7 @@
 class TestingPolicyMigrator : public ChromeExtensionPolicyMigrator {
  public:
   void Migrate(PolicyBundle* bundle) override {
-    using Migration = ExtensionPolicyMigrator::Migration;
+    using Migration = PolicyMigrator::Migration;
     const Migration migrations[] = {
         Migration(kOldPolicy1, kNewPolicy1),
         Migration(kOldPolicy2, kNewPolicy2),
diff --git a/chrome/browser/policy/profile_policy_connector.cc b/chrome/browser/policy/profile_policy_connector.cc
index 151b3a36..db816163 100644
--- a/chrome/browser/policy/profile_policy_connector.cc
+++ b/chrome/browser/policy/profile_policy_connector.cc
@@ -213,7 +213,7 @@
   }
 #endif
 
-  std::vector<std::unique_ptr<ExtensionPolicyMigrator>> migrators;
+  std::vector<std::unique_ptr<PolicyMigrator>> migrators;
 #if defined(OS_WIN)
   migrators.push_back(
       std::make_unique<browser_switcher::BrowserSwitcherPolicyMigrator>());
@@ -344,7 +344,7 @@
 std::unique_ptr<PolicyService>
 ProfilePolicyConnector::CreatePolicyServiceWithInitializationThrottled(
     const std::vector<ConfigurationPolicyProvider*>& policy_providers,
-    std::vector<std::unique_ptr<ExtensionPolicyMigrator>> migrators,
+    std::vector<std::unique_ptr<PolicyMigrator>> migrators,
     ConfigurationPolicyProvider* user_policy_delegate) {
   DCHECK(user_policy_delegate);
 
diff --git a/chrome/browser/policy/profile_policy_connector.h b/chrome/browser/policy/profile_policy_connector.h
index fdbecca..53a6084 100644
--- a/chrome/browser/policy/profile_policy_connector.h
+++ b/chrome/browser/policy/profile_policy_connector.h
@@ -26,7 +26,7 @@
 
 class CloudPolicyStore;
 class ConfigurationPolicyProvider;
-class ExtensionPolicyMigrator;
+class PolicyMigrator;
 class PolicyService;
 class PolicyServiceImpl;
 class SchemaRegistry;
@@ -114,7 +114,7 @@
   // [2] i.e. g_browser_process->local_state()
   std::unique_ptr<PolicyService> CreatePolicyServiceWithInitializationThrottled(
       const std::vector<ConfigurationPolicyProvider*>& policy_providers,
-      std::vector<std::unique_ptr<ExtensionPolicyMigrator>> migrators,
+      std::vector<std::unique_ptr<PolicyMigrator>> migrators,
       ConfigurationPolicyProvider* user_policy_delegate);
 
   // Called when primary user policies that are proxied to the device-wide
diff --git a/chrome/browser/resources/chromeos/accessibility/common/repeated_tree_change_handler.js b/chrome/browser/resources/chromeos/accessibility/common/repeated_tree_change_handler.js
index 6042143..7123305 100644
--- a/chrome/browser/resources/chromeos/accessibility/common/repeated_tree_change_handler.js
+++ b/chrome/browser/resources/chromeos/accessibility/common/repeated_tree_change_handler.js
@@ -10,9 +10,9 @@
   /**
    * @param {!chrome.automation.TreeChangeObserverFilter} filter
    * @param {!function(!chrome.automation.TreeChange)} callback
-   * @param {{predicate: (function(!chrome.automation.TreeChange): boolean)}}
-   *     options
-   *         predicate A generic predicate that filters for changes of interest.
+   * @param {{predicate: ((function(!chrome.automation.TreeChange): boolean) |
+   *     undefined)}} options predicate A generic predicate that filters for
+   *     changes of interest.
    */
   constructor(filter, callback, options = {}) {
     /** @private {!Array<!chrome.automation.TreeChange>} */
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/switch_access/BUILD.gn
index 8f75b17..acdacb8 100644
--- a/chrome/browser/resources/chromeos/accessibility/switch_access/BUILD.gn
+++ b/chrome/browser/resources/chromeos/accessibility/switch_access/BUILD.gn
@@ -161,6 +161,7 @@
     "../common:closure_shim",
     "../common:constants",
     "../common:repeated_event_handler",
+    "../common:repeated_tree_change_handler",
     "../common:tree_walker",
   ]
 }
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/history.js b/chrome/browser/resources/chromeos/accessibility/switch_access/history.js
index 34d8f11..8051c86 100644
--- a/chrome/browser/resources/chromeos/accessibility/switch_access/history.js
+++ b/chrome/browser/resources/chromeos/accessibility/switch_access/history.js
@@ -17,6 +17,11 @@
 
   /** @return {boolean} */
   isValid() {
+    if (this.group.isValidGroup()) {
+      // Ensure it is still valid. Some nodes may have been added
+      // or removed since this was last used.
+      this.group.refreshChildren();
+    }
     return this.group.isValidGroup();
   }
 }
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/navigation_manager.js b/chrome/browser/resources/chromeos/accessibility/switch_access/navigation_manager.js
index 9e5c7b07..6e90ea9e 100644
--- a/chrome/browser/resources/chromeos/accessibility/switch_access/navigation_manager.js
+++ b/chrome/browser/resources/chromeos/accessibility/switch_access/navigation_manager.js
@@ -143,7 +143,11 @@
    */
   static moveBackward() {
     const navigator = NavigationManager.instance;
-    navigator.setNode_(navigator.node_.previous);
+    if (navigator.node_.isValidAndVisible()) {
+      navigator.setNode_(navigator.node_.previous);
+    } else {
+      NavigationManager.moveToValidNode();
+    }
   }
 
   /**
@@ -151,7 +155,11 @@
    */
   static moveForward() {
     const navigator = NavigationManager.instance;
-    navigator.setNode_(navigator.node_.next);
+    if (navigator.node_.isValidAndVisible()) {
+      navigator.setNode_(navigator.node_.next);
+    } else {
+      NavigationManager.moveToValidNode();
+    }
   }
 
   /**
@@ -251,14 +259,20 @@
   }
 
   /**
-   * When the automation tree changes, check if it affects any nodes we are
-   *     currently listening to.
+   * When the automation tree changes, ensure the group and node we are
+   * currently listening to are fresh. This is only called when the tree change
+   * occurred on the node or group which are currently active.
    * @param {!chrome.automation.TreeChange} treeChange
    * @private
    */
   onTreeChange_(treeChange) {
     if (treeChange.type === chrome.automation.TreeChangeType.NODE_REMOVED) {
+      this.group_.refresh();
       NavigationManager.moveToValidNode();
+    } else if (
+        treeChange.type ===
+        chrome.automation.TreeChangeType.SUBTREE_UPDATE_END) {
+      this.group_.refresh();
     }
   }
 
@@ -283,6 +297,14 @@
         this.desktop_, chrome.automation.EventType.SCROLL_POSITION_CHANGED,
         this.onScrollChange_.bind(this));
 
+    new RepeatedTreeChangeHandler(
+        chrome.automation.TreeChangeObserverFilter.ALL_TREE_CHANGES,
+        this.onTreeChange_.bind(this), {
+          predicate: (treeChange) =>
+              this.group_.findChild(treeChange.target) != null ||
+              this.group_.isEquivalentTo(treeChange.target)
+        });
+
     // The status tray fires a SHOW event when it opens.
     this.desktop_.addEventListener(
         chrome.automation.EventType.SHOW, this.onModalDialog_.bind(this),
@@ -290,9 +312,6 @@
     this.desktop_.addEventListener(
         chrome.automation.EventType.MENU_START, this.onModalDialog_.bind(this),
         false);
-    chrome.automation.addTreeChangeObserver(
-        chrome.automation.TreeChangeObserverFilter.ALL_TREE_CHANGES,
-        this.onTreeChange_.bind(this));
   }
 
   /**
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/back_button_node.js b/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/back_button_node.js
index 0e6a1b0..028b005 100644
--- a/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/back_button_node.js
+++ b/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/back_button_node.js
@@ -77,7 +77,7 @@
 
   /** @override */
   isValidAndVisible() {
-    return true;
+    return this.group_.isValidGroup();
   }
 
   /** @override */
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/node_wrapper.js b/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/node_wrapper.js
index b7b0482..fb3e060 100644
--- a/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/node_wrapper.js
+++ b/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/node_wrapper.js
@@ -305,6 +305,16 @@
   }
 
   /** @override */
+  refreshChildren() {
+    const childConstructor = (node) => NodeWrapper.create(node, this);
+    try {
+      RootNodeWrapper.findAndSetChildren(this, childConstructor);
+    } catch (e) {
+      this.invalidated_ = true;
+    }
+  }
+
+  /** @override */
   refresh() {
     // Find the currently focused child.
     let focusedChild = null;
@@ -316,12 +326,9 @@
     }
 
     // Update this RootNodeWrapper's children.
-    const childConstructor = (node) => NodeWrapper.create(node, this);
-    try {
-      RootNodeWrapper.findAndSetChildren(this, childConstructor);
-    } catch (e) {
+    this.refreshChildren();
+    if (this.invalidated_) {
       this.onUnfocus();
-      this.invalidated_ = true;
       NavigationManager.moveToValidNode();
       return;
     }
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/switch_access_node.js b/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/switch_access_node.js
index 63fc5ec5..c5cf2f5f 100644
--- a/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/switch_access_node.js
+++ b/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/switch_access_node.js
@@ -363,8 +363,8 @@
     // Must have one interesting child that is not the back button.
     return this.children_
                .filter(
-                   (child) => child.isValidAndVisible() &&
-                       !(child instanceof BackButtonNode))
+                   (child) => !(child instanceof BackButtonNode) &&
+                       child.isValidAndVisible())
                .length >= 1;
   }
 
@@ -384,6 +384,11 @@
   /** Called when a group is explicitly exited. */
   onExit() {}
 
+  /** Called when a group should recalculate its children. */
+  refreshChildren() {
+    this.children = this.children.filter((child) => child.isValidAndVisible());
+  }
+
   /** Called when the group's children may have changed. */
   refresh() {}
 
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access_manifest.json.jinja2 b/chrome/browser/resources/chromeos/accessibility/switch_access_manifest.json.jinja2
index 33072b5e..3dc53b3 100644
--- a/chrome/browser/resources/chromeos/accessibility/switch_access_manifest.json.jinja2
+++ b/chrome/browser/resources/chromeos/accessibility/switch_access_manifest.json.jinja2
@@ -16,6 +16,7 @@
       "common/array_util.js",
       "common/automation_predicate.js",
       "common/repeated_event_handler.js",
+      "common/repeated_tree_change_handler.js",
       "common/tree_walker.js",
       "switch_access/auto_scan_manager.js",
       "switch_access/commands.js",
diff --git a/chrome/browser/resources/downloads/item.html b/chrome/browser/resources/downloads/item.html
index 9e23df60..3801221 100644
--- a/chrome/browser/resources/downloads/item.html
+++ b/chrome/browser/resources/downloads/item.html
@@ -362,7 +362,7 @@
           </cr-button>
         </div>
       </template>
-      <template is="dom-if" if="[[showOpenNow_]]">
+      <template is="dom-if" if="[[showOpenNow_]]" restamp>
         <div role="gridcell">
           <cr-button on-click="onOpenNowTap_" id="openNow" class="action-button"
                      focus-row-control focus-type="open">
diff --git a/chrome/browser/resources/downloads/item.js b/chrome/browser/resources/downloads/item.js
index e5d8ca9..20e815f 100644
--- a/chrome/browser/resources/downloads/item.js
+++ b/chrome/browser/resources/downloads/item.js
@@ -498,7 +498,8 @@
      * @private
      */
     computeShowOpenNow_() {
-      return this.data.state === States.ASYNC_SCANNING;
+      const allowOpenNow = loadTimeData.getBoolean('allowOpenNow');
+      return this.data.state === States.ASYNC_SCANNING && allowOpenNow;
     },
 
     /**
diff --git a/chrome/browser/resources/extensions/BUILD.gn b/chrome/browser/resources/extensions/BUILD.gn
index 53ed19c..7f06e62 100644
--- a/chrome/browser/resources/extensions/BUILD.gn
+++ b/chrome/browser/resources/extensions/BUILD.gn
@@ -100,10 +100,6 @@
 }
 
 js_type_check("extensions_module_resources") {
-  closure_flags = default_closure_args + [
-                    "js_module_root=../../chrome/browser/resources/extensions/",
-                    "js_module_root=./gen/chrome/browser/resources/extensions/",
-                  ]
   is_polymer3 = true
   deps = [
     ":checkup",
diff --git a/chrome/browser/resources/extensions/activity_log/BUILD.gn b/chrome/browser/resources/extensions/activity_log/BUILD.gn
index c0eff544..8ceba341 100644
--- a/chrome/browser/resources/extensions/activity_log/BUILD.gn
+++ b/chrome/browser/resources/extensions/activity_log/BUILD.gn
@@ -16,10 +16,6 @@
 }
 
 js_type_check("closure_compile_module") {
-  closure_flags = default_closure_args + [
-                    "js_module_root=../../chrome/browser/resources/extensions/",
-                    "js_module_root=./gen/chrome/browser/resources/extensions/",
-                  ]
   is_polymer3 = true
   deps = [
     ":activity_log",
diff --git a/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar-new.js b/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar-new.js
index bbff260..907b87a7 100644
--- a/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar-new.js
+++ b/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar-new.js
@@ -66,6 +66,10 @@
       pdfAnnotationsEnabled: Boolean,
       pdfFormSaveEnabled: Boolean,
       printingEnabled: Boolean,
+      viewportZoom: {
+        type: Number,
+        observer: 'viewportZoomChanged_',
+      },
 
       fittingType_: Number,
 
@@ -121,6 +125,12 @@
     this.loading_ = this.loadProgress < 100;
   }
 
+  /** @private */
+  viewportZoomChanged_() {
+    const zoom = Math.round(this.viewportZoom * 100);
+    this.shadowRoot.querySelector('#zoom-controls input').value = `${zoom}%`;
+  }
+
   // <if expr="chromeos">
   /**
    * @return {boolean}
diff --git a/chrome/browser/resources/pdf/pdf_viewer.html b/chrome/browser/resources/pdf/pdf_viewer.html
index daac835..1bfc8a9 100644
--- a/chrome/browser/resources/pdf/pdf_viewer.html
+++ b/chrome/browser/resources/pdf/pdf_viewer.html
@@ -34,6 +34,10 @@
       ink-controller="[[inkController_]]"
       pdf-annotations-enabled="[[pdfAnnotationsEnabled_]]"
 </if>
+      on-change-page-and-xy="onChangePageAndXy_"
+      on-change-page="onChangePage_"
+      on-dropdown-opened="onDropdownOpened_"
+      on-navigate="onNavigate_"
       on-save="onToolbarSave_" on-print="onPrint_"
 <if expr="chromeos">
       on-annotation-mode-toggled="onAnnotationModeToggled_"
@@ -49,11 +53,14 @@
     pdf-form-save-enabled="[[pdfFormSaveEnabled_]]"
     printing-enabled="[[printingEnabled_]]"
     is-form-field-focused="[[isFormFieldFocused_]]"
+    viewport-zoom="[[viewportZoom_]]"
 <if expr="chromeos">
     annotation-available="[[annotationAvailable_]]"
     ink-controller="[[inkController_]]"
     pdf-annotations-enabled="[[pdfAnnotationsEnabled_]]"
 </if>
+    on-change-page="onChangePage_"
+    on-dropdown-opened="onDropdownOpened_"
     on-fit-to-changed="onFitToChanged" on-zoom-in="onZoomIn"
     on-zoom-out="onZoomOut" on-rotate-left="rotateCounterclockwise"
 <if expr="chromeos">
diff --git a/chrome/browser/resources/pdf/pdf_viewer.js b/chrome/browser/resources/pdf/pdf_viewer.js
index cd024f5..ce0606f 100644
--- a/chrome/browser/resources/pdf/pdf_viewer.js
+++ b/chrome/browser/resources/pdf/pdf_viewer.js
@@ -146,6 +146,7 @@
       pdfFormSaveEnabled_: Boolean,
       pdfAnnotationsEnabled_: Boolean,
       printingEnabled_: Boolean,
+      viewportZoom_: Number,
     };
   }
 
@@ -197,6 +198,9 @@
     /** @private {boolean} */
     this.printingEnabled_ = false;
 
+    /** @private {number} */
+    this.viewportZoom_ = 1;
+
     // Non-Polymer properties
 
     /** @private {number} */
@@ -248,6 +252,11 @@
   }
 
   /** @override */
+  hasFixedToolbar() {
+    return this.pdfViewerUpdateEnabled_;
+  }
+
+  /** @override */
   getContent() {
     return /** @type {!HTMLDivElement} */ (this.$$('#content'));
   }
@@ -309,33 +318,6 @@
       this.getToolbar_().hidden = false;
     }
 
-    document.body.addEventListener('change-page', e => {
-      this.viewport.goToPage(e.detail.page);
-      if (e.detail.origin === 'bookmark') {
-        PDFMetrics.record(PDFMetrics.UserAction.FOLLOW_BOOKMARK);
-      } else if (e.detail.origin === 'pageselector') {
-        PDFMetrics.record(PDFMetrics.UserAction.PAGE_SELECTOR_NAVIGATE);
-      }
-    });
-
-    document.body.addEventListener('change-page-and-xy', e => {
-      const point = this.viewport.convertPageToScreen(e.detail.page, e.detail);
-      this.goToPageAndXY_(e.detail.origin, e.detail.page, point);
-    });
-
-    document.body.addEventListener('navigate', e => {
-      const disposition = e.detail.newtab ?
-          PdfNavigator.WindowOpenDisposition.NEW_BACKGROUND_TAB :
-          PdfNavigator.WindowOpenDisposition.CURRENT_TAB;
-      this.navigator_.navigate(e.detail.uri, disposition);
-    });
-
-    document.body.addEventListener('dropdown-opened', e => {
-      if (e.detail === 'bookmarks') {
-        PDFMetrics.record(PDFMetrics.UserAction.OPEN_BOOKMARKS_PANEL);
-      }
-    });
-
     if (!this.pdfViewerUpdateEnabled_) {
       this.toolbarManager_ = new ToolbarManager(
           window, this.getToolbar_(), this.getZoomToolbar_());
@@ -725,6 +707,11 @@
   }
 
   /** @override */
+  afterZoom(viewportZoom) {
+    this.viewportZoom_ = viewportZoom;
+  }
+
+  /** @override */
   setDocumentDimensions(documentDimensions) {
     super.setDocumentDimensions(documentDimensions);
     // If we received the document dimensions, the password was good so we
@@ -822,6 +809,50 @@
   }
 
   /**
+   * @param {!CustomEvent<!{page: number, origin: string}>} e
+   * @private
+   */
+  onChangePage_(e) {
+    this.viewport.goToPage(e.detail.page);
+    if (e.detail.origin === 'bookmark') {
+      PDFMetrics.record(PDFMetrics.UserAction.FOLLOW_BOOKMARK);
+    } else if (e.detail.origin === 'pageselector') {
+      PDFMetrics.record(PDFMetrics.UserAction.PAGE_SELECTOR_NAVIGATE);
+    }
+  }
+
+  /**
+   * @param {!CustomEvent<!{
+   *   page: number, origin: string, x: number, y: number}>} e
+   * @private
+   */
+  onChangePageAndXy_(e) {
+    const point = this.viewport.convertPageToScreen(e.detail.page, e.detail);
+    this.goToPageAndXY_(e.detail.origin, e.detail.page, point);
+  }
+
+  /**
+   * @param {!CustomEvent<string>} e
+   * @private
+   */
+  onDropdownOpened_(e) {
+    if (e.detail === 'bookmarks') {
+      PDFMetrics.record(PDFMetrics.UserAction.OPEN_BOOKMARKS_PANEL);
+    }
+  }
+
+  /**
+   * @param {!CustomEvent<!{newtab: boolean, uri: string}>} e
+   * @private
+   */
+  onNavigate_(e) {
+    const disposition = e.detail.newtab ?
+        PdfNavigator.WindowOpenDisposition.NEW_BACKGROUND_TAB :
+        PdfNavigator.WindowOpenDisposition.CURRENT_TAB;
+    this.navigator_.navigate(e.detail.uri, disposition);
+  }
+
+  /**
    * Saves the current PDF document to disk.
    * @param {SaveRequestType} requestType The type of save request.
    * @private
diff --git a/chrome/browser/resources/pdf/pdf_viewer_base.js b/chrome/browser/resources/pdf/pdf_viewer_base.js
index 3f2e538..3b3e24f 100644
--- a/chrome/browser/resources/pdf/pdf_viewer_base.js
+++ b/chrome/browser/resources/pdf/pdf_viewer_base.js
@@ -120,6 +120,11 @@
     return 0;
   }
 
+  /** @return {boolean} Whether the top toolbar is fixed (does not auto-hide) */
+  hasFixedToolbar() {
+    return false;
+  }
+
   /**
    * @return {!HTMLDivElement}
    * @protected
@@ -145,6 +150,12 @@
   forceFit(view) {}
 
   /**
+   * @param {number} viewportZoom
+   * @protected
+   */
+  afterZoom(viewportZoom) {}
+
+  /**
    * @param {string} query
    * @return {?Element}
    * @protected
@@ -232,12 +243,14 @@
         1.0;
     this.viewport_ = new Viewport(
         window, this.getSizer(), this.getContent(), getScrollbarWidth(),
-        defaultZoom, this.getToolbarHeight());
+        defaultZoom, this.getToolbarHeight(), this.hasFixedToolbar());
     this.viewport_.setViewportChangedCallback(() => this.viewportChanged_());
     this.viewport_.setBeforeZoomCallback(
         () => this.currentController.beforeZoom());
-    this.viewport_.setAfterZoomCallback(
-        () => this.currentController.afterZoom());
+    this.viewport_.setAfterZoomCallback(() => {
+      this.currentController.afterZoom();
+      this.afterZoom(this.viewport_.getZoom());
+    });
     this.viewport_.setUserInitiatedCallback(
         userInitiated => this.setUserInitiated_(userInitiated));
     window.addEventListener('beforeunload', () => this.resetTrackers_());
diff --git a/chrome/browser/resources/pdf/viewport.js b/chrome/browser/resources/pdf/viewport.js
index 3e68d39..cf75928 100644
--- a/chrome/browser/resources/pdf/viewport.js
+++ b/chrome/browser/resources/pdf/viewport.js
@@ -78,9 +78,12 @@
    * @param {number} defaultZoom The default zoom level.
    * @param {number} topToolbarHeight The number of pixels that should initially
    *     be left blank above the document for the toolbar.
+   * @param {boolean} topToolbarFixed True if the top toolbar is fixed and does
+   *     not automatically disappear in fit to page mode.
    */
   constructor(
-      window, sizer, content, scrollbarWidth, defaultZoom, topToolbarHeight) {
+      window, sizer, content, scrollbarWidth, defaultZoom, topToolbarHeight,
+      topToolbarFixed) {
     /** @private {!Window} */
     this.window_ = window;
 
@@ -99,6 +102,9 @@
     /** @private {number} */
     this.topToolbarHeight_ = topToolbarHeight;
 
+    /** @private {boolean} */
+    this.topToolbarFixed_ = topToolbarFixed;
+
     /** @private {function():void} */
     this.viewportChangedCallback_ = function() {};
 
@@ -798,8 +804,12 @@
             'true.');
 
     // First compute the zoom without scrollbars.
+    let height = this.window_.innerHeight;
+    if (this.topToolbarFixed_) {
+      height -= this.topToolbarHeight_;
+    }
     let zoom = this.computeFittingZoomGivenDimensions_(
-        fitWidth, fitHeight, this.window_.innerWidth, this.window_.innerHeight,
+        fitWidth, fitHeight, this.window_.innerWidth, height,
         pageDimensions.width, pageDimensions.height);
 
     // Check if there needs to be any scrollbars.
@@ -826,7 +836,7 @@
     // Compute available window space.
     const windowWithScrollbars = {
       width: this.window_.innerWidth,
-      height: this.window_.innerHeight
+      height: height,
     };
     if (needsScrollbars.horizontal) {
       windowWithScrollbars.height -= scrollbarWidth;
@@ -922,9 +932,10 @@
       };
       this.setZoomInternal_(this.computeFittingZoom_(dimensions, false, true));
       if (scrollToTopOfPage) {
+        const offset = this.topToolbarFixed_ ? this.topToolbarHeight_ : 0;
         this.position = {
           x: 0,
-          y: this.pageDimensions_[page].y * this.getZoom()
+          y: this.pageDimensions_[page].y * this.getZoom() - offset,
         };
       }
       this.updateViewport_();
@@ -957,9 +968,10 @@
       };
       this.setZoomInternal_(this.computeFittingZoom_(dimensions, true, true));
       if (scrollToTopOfPage) {
+        const offset = this.topToolbarFixed_ ? this.topToolbarHeight_ : 0;
         this.position = {
           x: 0,
-          y: this.pageDimensions_[page].y * this.getZoom()
+          y: this.pageDimensions_[page].y * this.getZoom() - offset,
         };
       }
       this.updateViewport_();
@@ -1219,7 +1231,7 @@
       // Unless we're in fit to page or fit to height mode, scroll above the
       // page by |this.topToolbarHeight_| so that the toolbar isn't covering it
       // initially.
-      if (!this.isPagedMode_()) {
+      if (!this.isPagedMode_() || this.topToolbarFixed_) {
         toolbarOffset = this.topToolbarHeight_;
       }
       this.position = {
diff --git a/chrome/browser/resources/settings/chromeos/BUILD.gn b/chrome/browser/resources/settings/chromeos/BUILD.gn
index 86779cd..0601c30 100644
--- a/chrome/browser/resources/settings/chromeos/BUILD.gn
+++ b/chrome/browser/resources/settings/chromeos/BUILD.gn
@@ -146,6 +146,7 @@
 
 group("closure_compile") {
   deps = [
+    ":deep_linking_behavior",
     ":metrics_recorder",
     ":os_page_visibility",
     ":os_route",
@@ -185,6 +186,15 @@
   ]
 }
 
+js_library("deep_linking_behavior") {
+  deps = [
+    "..:router",
+    "//chrome/browser/ui/webui/settings/chromeos/constants:mojom_js_library_for_compile",
+    "//ui/webui/resources/js:assert",
+    "//ui/webui/resources/js:load_time_data",
+  ]
+}
+
 js_library("os_page_visibility") {
   deps = [
     "//ui/webui/resources/js:cr",
@@ -288,6 +298,17 @@
   ]
 }
 
+js_library("deep_linking_behavior.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/deep_linking_behavior.m.js" ]
+  deps = [
+    "..:router.m",
+    "//chrome/browser/ui/webui/settings/chromeos/constants:mojom_js_library_for_compile",
+    "//ui/webui/resources/js:assert.m",
+    "//ui/webui/resources/js:load_time_data.m",
+  ]
+  extra_deps = [ ":modulize" ]
+}
+
 js_library("metrics_recorder.m") {
   sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/metrics_recorder.m.js" ]
   deps = [ "//chrome/browser/ui/webui/settings/chromeos/search:mojo_bindings_js_library_for_compile" ]
@@ -434,6 +455,7 @@
     "route_origin_behavior.js",
     "search_handler.js",
     "os_route.js",
+    "deep_linking_behavior.js",
   ]
   namespace_rewrites = os_settings_namespace_rewrites
 }
diff --git a/chrome/browser/resources/settings/chromeos/deep_linking_behavior.html b/chrome/browser/resources/settings/chromeos/deep_linking_behavior.html
new file mode 100644
index 0000000..154fbb6
--- /dev/null
+++ b/chrome/browser/resources/settings/chromeos/deep_linking_behavior.html
@@ -0,0 +1,5 @@
+<link rel="import" href="../router.html">
+<link rel="import" href="chrome://resources/html/load_time_data.html">
+
+<script src="chrome://os-settings/constants/setting.mojom-lite.js"></script>
+<script src="deep_linking_behavior.js"></script>
\ No newline at end of file
diff --git a/chrome/browser/resources/settings/chromeos/deep_linking_behavior.js b/chrome/browser/resources/settings/chromeos/deep_linking_behavior.js
new file mode 100644
index 0000000..29f9b05
--- /dev/null
+++ b/chrome/browser/resources/settings/chromeos/deep_linking_behavior.js
@@ -0,0 +1,67 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+/**
+ * @fileoverview Polymer behavior for scrolling/focusing/indicating
+ * setting elements with deep links.
+ */
+
+// clang-format off
+// #import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js'
+// #import '../constants/setting.mojom-lite.js';
+
+// #import {afterNextRender, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+// #import {assert} from 'chrome://resources/js/assert.m.js';
+// #import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
+// #import {Router} from '../router.m.js';
+// clang-format on
+
+const kDeepLinkSettingId = 'settingId';
+const kDeepLinkFocusId = 'deep-link-focus-id';
+
+/** @polymerBehavior */
+/* #export */ const DeepLinkingBehavior = {
+  properties: {
+    /**
+     * An object whose values are the kSetting mojom values which can be used to
+     * define deep link IDs on HTML elems.
+     * @type {!Object}
+     */
+    Setting: {
+      type: Object,
+      value: chromeos.settings.mojom.Setting,
+    },
+  },
+
+  /**
+   * Retrieves the settingId saved in the url's query parameter. Returns null if
+   * deep linking is disabled or if no settingId is found.
+   * @return {?chromeos.settings.mojom.Setting}
+   */
+  getDeepLinkSettingId() {
+    if (!loadTimeData.getBoolean('isDeepLinkingEnabled')) {
+      return null;
+    }
+    const settingIdStr = settings.Router.getInstance().getQueryParameters().get(
+        kDeepLinkSettingId);
+    const settingIdNum = Number(settingIdStr);
+    if (isNaN(settingIdNum)) {
+      return null;
+    }
+    return /** @type {!chromeos.settings.mojom.Setting} */ (settingIdNum);
+  },
+
+  /**
+   * Focuses the deep linked element referred to by |settindId|.
+   * @param {chromeos.settings.mojom.Setting} settingId
+   */
+  showDeepLink(settingId) {
+    assert(loadTimeData.getBoolean('isDeepLinkingEnabled'));
+    const elToFocus = this.$$(`[${kDeepLinkFocusId}~="${settingId}"]`);
+    Polymer.RenderStatus.afterNextRender(this, () => {
+      elToFocus.focus();
+    });
+  }
+};
diff --git a/chrome/browser/resources/settings/chromeos/os_reset_page/BUILD.gn b/chrome/browser/resources/settings/chromeos/os_reset_page/BUILD.gn
index e05a989..a363496a 100644
--- a/chrome/browser/resources/settings/chromeos/os_reset_page/BUILD.gn
+++ b/chrome/browser/resources/settings/chromeos/os_reset_page/BUILD.gn
@@ -26,9 +26,11 @@
 
 js_library("os_reset_page") {
   deps = [
+    "..:deep_linking_behavior",
+    "..:os_route",
+    "../..:router",
     "//ui/webui/resources/js:assert",
     "//ui/webui/resources/js:cr",
-    "//ui/webui/resources/js:load_time_data",
     "//ui/webui/resources/js/cr/ui:focus_without_ink",
   ]
 }
@@ -71,9 +73,11 @@
 js_library("os_reset_page.m") {
   sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_reset_page/os_reset_page.m.js" ]
   deps = [
+    "..:deep_linking_behavior.m",
+    "..:os_route.m",
+    "../..:router.m",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
     "//ui/webui/resources/js:assert.m",
-    "//ui/webui/resources/js:load_time_data.m",
     "//ui/webui/resources/js/cr/ui:focus_without_ink.m",
   ]
   extra_deps = [ ":os_reset_page_module" ]
diff --git a/chrome/browser/resources/settings/chromeos/os_reset_page/os_reset_page.html b/chrome/browser/resources/settings/chromeos/os_reset_page/os_reset_page.html
index 0b075bc..6b08be2 100644
--- a/chrome/browser/resources/settings/chromeos/os_reset_page/os_reset_page.html
+++ b/chrome/browser/resources/settings/chromeos/os_reset_page/os_reset_page.html
@@ -3,7 +3,10 @@
 <link rel="import" href="chrome://resources/html/assert.html">
 <link rel="import" href="chrome://resources/html/cr/ui/focus_without_ink.html">
 <link rel="import" href="os_powerwash_dialog.html">
+<link rel="import" href="../deep_linking_behavior.html">
+<link rel="import" href="../os_route.html">
 <link rel="import" href="../../i18n_setup.html">
+<link rel="import" href="../../router.html">
 
 <dom-module id="os-settings-reset-page">
   <template>
@@ -22,7 +25,8 @@
             on-click="onShowPowerwashDialog_"
             aria-labelledby="title"
             aria-describedby="secondaryText"
-            aria-roledescription="$i18n{powerwashButtonRoleDescription}">
+            aria-roledescription="$i18n{powerwashButtonRoleDescription}"
+            deep-link-focus-id$="[[Setting.kPowerwash]]">
           $i18n{powerwashButton}
         </cr-button>
       </div>
diff --git a/chrome/browser/resources/settings/chromeos/os_reset_page/os_reset_page.js b/chrome/browser/resources/settings/chromeos/os_reset_page/os_reset_page.js
index effd68ce..e6da298 100644
--- a/chrome/browser/resources/settings/chromeos/os_reset_page/os_reset_page.js
+++ b/chrome/browser/resources/settings/chromeos/os_reset_page/os_reset_page.js
@@ -10,6 +10,7 @@
 Polymer({
   is: 'os-settings-reset-page',
 
+  behaviors: [DeepLinkingBehavior, settings.RouteObserverBehavior],
 
   properties: {
     /** @private */
@@ -31,4 +32,22 @@
     this.showPowerwashDialog_ = false;
     cr.ui.focusWithoutInk(assert(this.$.powerwash));
   },
+
+  /**
+   * settings.RouteObserverBehavior
+   * @param {!settings.Route} newRoute
+   * @param {!settings.Route} oldRoute
+   * @protected
+   */
+  currentRouteChanged(newRoute, oldRoute) {
+    // Does not apply to this page.
+    if (newRoute != settings.routes.OS_RESET) {
+      return;
+    }
+
+    const settingId = this.getDeepLinkSettingId();
+    if (settingId === chromeos.settings.mojom.Setting.kPowerwash) {
+      this.showDeepLink(settingId);
+    }
+  },
 });
diff --git a/chrome/browser/resources/settings/chromeos/os_settings.gni b/chrome/browser/resources/settings/chromeos/os_settings.gni
index 6c3a5b6..4b130af 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings.gni
+++ b/chrome/browser/resources/settings/chromeos/os_settings.gni
@@ -32,29 +32,30 @@
       "settings.WallpaperBrowserProxy|WallpaperBrowserProxy",
     ]
 
-os_settings_auto_imports =
-    settings_auto_imports + cr_components_chromeos_auto_imports +
-    cr_elements_chromeos_auto_imports + [
-      "chrome/browser/resources/settings/chromeos/ambient_mode_page/constants.html|AmbientModeTopicSource,AmbientModeSettings",
-      "chrome/browser/resources/settings/chromeos/ambient_mode_page/ambient_mode_browser_proxy.html|AmbientModeBrowserProxy,AmbientModeBrowserProxyImpl",
-      "chrome/browser/resources/settings/chromeos/metrics_recorder.html|recordSettingChange",
-      "chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_constants.html|MultiDeviceSettingsMode,MultiDeviceFeature,MultiDeviceFeatureState,MultiDevicePageContentData,SmartLockSignInEnabledState",
-      "chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_feature_behavior.html|MultiDeviceFeatureBehavior",
-      "chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_browser_proxy.html|MultiDeviceBrowserProxy,MultiDeviceBrowserProxyImpl",
-      "chrome/browser/resources/settings/chromeos/os_people_page/kerberos_accounts_browser_proxy.html|KerberosAccount,KerberosAccountsBrowserProxyImpl,KerberosAccountsBrowserProxy,KerberosErrorType,KerberosConfigErrorCode,ValidateKerberosConfigResult",
-      "chrome/browser/resources/settings/chromeos/os_people_page/os_sync_browser_proxy.html|OsSyncBrowserProxy,OsSyncBrowserProxyImpl,OsSyncPrefs",
-      "chrome/browser/resources/settings/chromeos/os_reset_page/os_reset_browser_proxy.html|OsResetBrowserProxy,OsResetBrowserProxyImpl",
-      "chrome/browser/resources/settings/chromeos/os_route.html|routes",
-      "chrome/browser/resources/settings/chromeos/os_settings_routes.html|OsSettingsRoutes",
-      "chrome/browser/resources/settings/chromeos/personalization_page/change_picture_browser_proxy.html|ChangePictureBrowserProxy,ChangePictureBrowserProxyImpl,DefaultImage",
-      "chrome/browser/resources/settings/chromeos/personalization_page/wallpaper_browser_proxy.html|WallpaperBrowserProxy,WallpaperBrowserProxyImpl",
-      "chrome/browser/resources/settings/chromeos/route_origin_behavior.html|RouteOriginBehaviorImpl,RouteOriginBehavior",
-      "chrome/browser/resources/settings/lifetime_browser_proxy.html|LifetimeBrowserProxy,LifetimeBrowserProxyImpl",
-      "chrome/browser/resources/settings/people_page/account_manager_browser_proxy.html|AccountManagerBrowserProxy,AccountManagerBrowserProxyImpl",
-      "chrome/browser/resources/settings/route.html|routes",
-      "chrome/browser/resources/settings/router.html|Router,Route,RouteObserverBehavior",
-      "ui/webui/resources/html/polymer.html|Polymer,html,flush",
-      "ui/webui/resources/html/icon.html|getImage",
-    ]
+os_settings_auto_imports = settings_auto_imports +
+                           cr_components_chromeos_auto_imports +
+                           cr_elements_chromeos_auto_imports + [
+                             "chrome/browser/resources/settings/chromeos/ambient_mode_page/constants.html|AmbientModeTopicSource,AmbientModeSettings",
+                             "chrome/browser/resources/settings/chromeos/ambient_mode_page/ambient_mode_browser_proxy.html|AmbientModeBrowserProxy,AmbientModeBrowserProxyImpl",
+                             "chrome/browser/resources/settings/chromeos/deep_linking_behavior.html|DeepLinkingBehavior",
+                             "chrome/browser/resources/settings/chromeos/metrics_recorder.html|recordSettingChange",
+                             "chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_constants.html|MultiDeviceSettingsMode,MultiDeviceFeature,MultiDeviceFeatureState,MultiDevicePageContentData,SmartLockSignInEnabledState",
+                             "chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_feature_behavior.html|MultiDeviceFeatureBehavior",
+                             "chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_browser_proxy.html|MultiDeviceBrowserProxy,MultiDeviceBrowserProxyImpl",
+                             "chrome/browser/resources/settings/chromeos/os_people_page/kerberos_accounts_browser_proxy.html|KerberosAccount,KerberosAccountsBrowserProxyImpl,KerberosAccountsBrowserProxy,KerberosErrorType,KerberosConfigErrorCode,ValidateKerberosConfigResult",
+                             "chrome/browser/resources/settings/chromeos/os_people_page/os_sync_browser_proxy.html|OsSyncBrowserProxy,OsSyncBrowserProxyImpl,OsSyncPrefs",
+                             "chrome/browser/resources/settings/chromeos/os_reset_page/os_reset_browser_proxy.html|OsResetBrowserProxy,OsResetBrowserProxyImpl",
+                             "chrome/browser/resources/settings/chromeos/os_route.html|routes",
+                             "chrome/browser/resources/settings/chromeos/os_settings_routes.html|OsSettingsRoutes",
+                             "chrome/browser/resources/settings/chromeos/personalization_page/change_picture_browser_proxy.html|ChangePictureBrowserProxy,ChangePictureBrowserProxyImpl,DefaultImage",
+                             "chrome/browser/resources/settings/chromeos/personalization_page/wallpaper_browser_proxy.html|WallpaperBrowserProxy,WallpaperBrowserProxyImpl",
+                             "chrome/browser/resources/settings/chromeos/route_origin_behavior.html|RouteOriginBehaviorImpl,RouteOriginBehavior",
+                             "chrome/browser/resources/settings/lifetime_browser_proxy.html|LifetimeBrowserProxy,LifetimeBrowserProxyImpl",
+                             "chrome/browser/resources/settings/people_page/account_manager_browser_proxy.html|AccountManagerBrowserProxy,AccountManagerBrowserProxyImpl",
+                             "chrome/browser/resources/settings/route.html|routes",
+                             "chrome/browser/resources/settings/router.html|Router,Route,RouteObserverBehavior",
+                             "ui/webui/resources/html/polymer.html|Polymer,html,flush",
+                             "ui/webui/resources/html/icon.html|getImage",
+                           ]
 
 os_settings_migrated_imports = settings_migrated_imports
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_resources_v3.grdp b/chrome/browser/resources/settings/chromeos/os_settings_resources_v3.grdp
index 7f744ed..2e8abe7 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings_resources_v3.grdp
+++ b/chrome/browser/resources/settings/chromeos/os_settings_resources_v3.grdp
@@ -117,6 +117,11 @@
            use_base_dir="false"
            compress="false"
            type="BINDATA" />
+  <include name="IDR_OS_SETTINGS_DEEP_LINKING_BEHAVIOR_M_JS"
+           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/deep_linking_behavior.m.js"
+           use_base_dir="false"
+           compress="false"
+           type="BINDATA" />
   <include name="IDR_OS_SETTINGS_LOCALIZED_LINK_M_JS"
            file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/localized_link/localized_link.m.js"
            use_base_dir="false"
diff --git a/chrome/browser/resources/settings/os_settings_resources.grd b/chrome/browser/resources/settings/os_settings_resources.grd
index 9cc11d9..2180101a 100644
--- a/chrome/browser/resources/settings/os_settings_resources.grd
+++ b/chrome/browser/resources/settings/os_settings_resources.grd
@@ -510,6 +510,12 @@
       <structure name="IDR_OS_SETTINGS_CONTROLS_TOGGLE_BUTTON_JS"
                  file="controls/settings_toggle_button.js"
                  compress="false" type="chrome_html" />
+      <structure name="IDR_OS_SETTINGS_DEEP_LINKING_BEHAVIOR_HTML"
+                 file="chromeos/deep_linking_behavior.html"
+                 compress="false" type="chrome_html" />
+      <structure name="IDR_OS_SETTINGS_DEEP_LINKING_BEHAVIOR_JS"
+                 file="chromeos/deep_linking_behavior.js"
+                 compress="false" type="chrome_html" />
       <structure name="IDR_OS_SETTINGS_DEVICE_BROWSER_PROXY_HTML"
                  file="chromeos/device_page/device_page_browser_proxy.html"
                  compress="false" type="chrome_html" />
diff --git a/chrome/browser/resources/welcome/BUILD.gn b/chrome/browser/resources/welcome/BUILD.gn
index 6ceb907..d67421f2 100644
--- a/chrome/browser/resources/welcome/BUILD.gn
+++ b/chrome/browser/resources/welcome/BUILD.gn
@@ -16,10 +16,6 @@
 
 js_type_check("welcome_files") {
   is_polymer3 = true
-  closure_flags = default_closure_args + [
-                    "js_module_root=../../chrome/browser/resources/welcome/",
-                    "js_module_root=./gen/chrome/browser/resources/welcome/",
-                  ]
   deps = [
     ":landing_view",
     ":signin_view",
diff --git a/chrome/browser/resources/welcome/google_apps/BUILD.gn b/chrome/browser/resources/welcome/google_apps/BUILD.gn
index c6b73f1..722f6a7 100644
--- a/chrome/browser/resources/welcome/google_apps/BUILD.gn
+++ b/chrome/browser/resources/welcome/google_apps/BUILD.gn
@@ -6,10 +6,6 @@
 import("//tools/polymer/html_to_js.gni")
 
 js_type_check("closure_compile") {
-  closure_flags = default_closure_args + [
-                    "js_module_root=../../chrome/browser/resources/welcome/",
-                    "js_module_root=gen/chrome/browser/resources/welcome/",
-                  ]
   is_polymer3 = true
   deps = [
     ":google_app_proxy",
diff --git a/chrome/browser/resources/welcome/ntp_background/BUILD.gn b/chrome/browser/resources/welcome/ntp_background/BUILD.gn
index 310c3d6..ca4e0c5 100644
--- a/chrome/browser/resources/welcome/ntp_background/BUILD.gn
+++ b/chrome/browser/resources/welcome/ntp_background/BUILD.gn
@@ -6,10 +6,6 @@
 import("//tools/polymer/html_to_js.gni")
 js_type_check("closure_compile") {
   is_polymer3 = true
-  closure_flags = default_closure_args + [
-                    "js_module_root=../../chrome/browser/resources/welcome/",
-                    "js_module_root=gen/chrome/browser/resources/welcome/",
-                  ]
   deps = [
     ":ntp_background_metrics_proxy",
     ":ntp_background_proxy",
diff --git a/chrome/browser/resources/welcome/set_as_default/BUILD.gn b/chrome/browser/resources/welcome/set_as_default/BUILD.gn
index eacb2b0..93154344 100644
--- a/chrome/browser/resources/welcome/set_as_default/BUILD.gn
+++ b/chrome/browser/resources/welcome/set_as_default/BUILD.gn
@@ -7,10 +7,6 @@
 
 js_type_check("closure_compile") {
   is_polymer3 = true
-  closure_flags = default_closure_args + [
-                    "js_module_root=../../chrome/browser/resources/welcome/",
-                    "js_module_root=gen/chrome/browser/resources/welcome/",
-                  ]
   deps = [ ":nux_set_as_default" ]
 }
 
diff --git a/chrome/browser/resources/welcome/shared/BUILD.gn b/chrome/browser/resources/welcome/shared/BUILD.gn
index 4c9544a..43d7de3 100644
--- a/chrome/browser/resources/welcome/shared/BUILD.gn
+++ b/chrome/browser/resources/welcome/shared/BUILD.gn
@@ -7,10 +7,6 @@
 
 js_type_check("closure_compile") {
   is_polymer3 = true
-  closure_flags = default_closure_args + [
-                    "js_module_root=../../chrome/browser/resources/welcome/",
-                    "js_module_root=gen/chrome/browser/resources/welcome/",
-                  ]
   deps = [
     ":bookmark_proxy",
     ":module_metrics_proxy",
diff --git a/chrome/browser/safe_browsing/mock_report_sender.cc b/chrome/browser/safe_browsing/mock_report_sender.cc
index 159aa12..2aace2f2 100644
--- a/chrome/browser/safe_browsing/mock_report_sender.cc
+++ b/chrome/browser/safe_browsing/mock_report_sender.cc
@@ -24,8 +24,8 @@
     const GURL& report_uri,
     base::StringPiece content_type,
     base::StringPiece report,
-    const base::Callback<void()>& success_callback,
-    const base::Callback<void(const GURL&, int, int)>& error_callback) {
+    base::OnceCallback<void()> success_callback,
+    base::OnceCallback<void(const GURL&, int, int)> error_callback) {
   latest_report_uri_ = report_uri;
   latest_report_.assign(report.data(), report.size());
   latest_content_type_.assign(content_type.data(), content_type.size());
diff --git a/chrome/browser/safe_browsing/mock_report_sender.h b/chrome/browser/safe_browsing/mock_report_sender.h
index 3eb8bdb..f604958 100644
--- a/chrome/browser/safe_browsing/mock_report_sender.h
+++ b/chrome/browser/safe_browsing/mock_report_sender.h
@@ -17,12 +17,12 @@
 
   ~MockReportSender() override;
 
-  void Send(const GURL& report_uri,
-            base::StringPiece content_type,
-            base::StringPiece report,
-            const base::Callback<void()>& success_callback,
-            const base::Callback<void(const GURL&, int, int)>& error_callback)
-      override;
+  void Send(
+      const GURL& report_uri,
+      base::StringPiece content_type,
+      base::StringPiece report,
+      base::OnceCallback<void()> success_callback,
+      base::OnceCallback<void(const GURL&, int, int)> error_callback) override;
 
   const GURL& latest_report_uri();
 
diff --git a/chrome/browser/tab/BUILD.gn b/chrome/browser/tab/BUILD.gn
index bd72d1d..47192f9 100644
--- a/chrome/browser/tab/BUILD.gn
+++ b/chrome/browser/tab/BUILD.gn
@@ -23,15 +23,26 @@
     "java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java",
     "java/src/org/chromium/chrome/browser/tab/WebContentsState.java",
     "java/src/org/chromium/chrome/browser/tab/WebContentsStateBridge.java",
+    "java/src/org/chromium/chrome/browser/tab/state/CriticalPersistedTabData.java",
+    "java/src/org/chromium/chrome/browser/tab/state/EncryptedFilePersistedTabDataStorage.java",
+    "java/src/org/chromium/chrome/browser/tab/state/FilePersistedTabDataStorage.java",
+    "java/src/org/chromium/chrome/browser/tab/state/MockPersistedTabData.java",
+    "java/src/org/chromium/chrome/browser/tab/state/PersistedTabData.java",
+    "java/src/org/chromium/chrome/browser/tab/state/PersistedTabDataConfiguration.java",
+    "java/src/org/chromium/chrome/browser/tab/state/PersistedTabDataFactory.java",
+    "java/src/org/chromium/chrome/browser/tab/state/PersistedTabDataStorage.java",
   ]
 
   # TabSelectionType, TabLaunchType
   srcjar_deps = [ "//chrome/browser/ui:tab_model_enums_java" ]
 
   deps = [
+    ":critical_persisted_tab_data_proto_java",
     ":jni_headers",
     "//base:base_java",
+    "//base:base_java",
     "//base:jni_java",
+    "//chrome/browser/android/crypto:java",
     "//chrome/browser/contextmenu:java",
     "//chrome/browser/profiles/android:java",
     "//chrome/browser/ui/android/native_page:java",
@@ -43,6 +54,8 @@
     "//components/find_in_page/android:java",
     "//components/navigation_interception/android:navigation_interception_java",
     "//content/public/android:content_java",
+    "//third_party/android_deps:androidx_core_core_java",
+    "//third_party/android_deps:com_google_protobuf_protobuf_javalite_java",
     "//ui/android:ui_full_java",
   ]
 
@@ -68,3 +81,8 @@
     "//content/public/browser",
   ]
 }
+
+proto_java_library("critical_persisted_tab_data_proto_java") {
+  proto_path = "java/src/org/chromium/chrome/browser/tab/state/proto"
+  sources = [ "$proto_path/critical_persisted_tab_data.proto" ]
+}
diff --git a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/DEPS b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/DEPS
index a80c897..ed381b4 100644
--- a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/DEPS
+++ b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/DEPS
@@ -3,7 +3,9 @@
 include_rules = [
   "-chrome",
   "+base/android/java/src/org/chromium/base",
+  "+chrome/browser/android/crypto/java",
   "+chrome/browser/contextmenu/java",
+  "+chrome/browser/tab/java",
   "+chrome/browser/profiles/android/java",
   "+chrome/browser/ui/android/native_page",
   "+components/browser_ui/util/android/java",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/state/CriticalPersistedTabData.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/CriticalPersistedTabData.java
similarity index 86%
rename from chrome/android/java/src/org/chromium/chrome/browser/tab/state/CriticalPersistedTabData.java
rename to chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/CriticalPersistedTabData.java
index 7ca553d..545875f8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/state/CriticalPersistedTabData.java
+++ b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/CriticalPersistedTabData.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.tab.state;
 
+import android.graphics.Color;
+
 import androidx.annotation.VisibleForTesting;
 
 import com.google.protobuf.ByteString;
@@ -12,14 +14,7 @@
 import org.chromium.base.Callback;
 import org.chromium.base.Log;
 import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.browser.tab.TabAssociatedApp;
-import org.chromium.chrome.browser.tab.TabImpl;
 import org.chromium.chrome.browser.tab.TabLaunchType;
-import org.chromium.chrome.browser.tab.TabState;
-import org.chromium.chrome.browser.tab.TabStateExtractor;
-import org.chromium.chrome.browser.tab.TabStateFileManager;
-import org.chromium.chrome.browser.tab.TabThemeColorHelper;
-import org.chromium.chrome.browser.tab.WebContentsState;
 import org.chromium.chrome.browser.tab.proto.CriticalPersistedTabData.CriticalPersistedTabDataProto;
 
 import java.util.Locale;
@@ -32,6 +27,8 @@
     private static final Class<CriticalPersistedTabData> USER_DATA_KEY =
             CriticalPersistedTabData.class;
 
+    private static final int UNSPECIFIED_THEME_COLOR = Color.TRANSPARENT;
+
     private int mParentId;
     private int mRootId;
     private long mTimestampMillis;
@@ -126,31 +123,16 @@
 
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
     public static CriticalPersistedTabData build(Tab tab) {
-        TabImpl tabImpl = (TabImpl) tab;
-        // TODO(crbug.com/1059634) this can be removed once we access all fields
-        // from CriticalPersistedTabData
-        // The following is only needed as an interim measure until all
-        // fields are migrated to {@link CriticalPersistedTabData}. At that point
-        // This function will only be used to acquire the {@link CriticalPersistedTabData}
-        // from the {@link Tab}.
-        if (tabImpl.isInitialized()) {
-            WebContentsState webContentsState = TabStateExtractor.getWebContentsState(tabImpl);
-            PersistedTabDataConfiguration config = PersistedTabDataConfiguration.get(
-                    CriticalPersistedTabData.class, tab.isIncognito());
-            CriticalPersistedTabData criticalPersistedTabData = new CriticalPersistedTabData(tab,
-                    tab.getParentId(), tab.getId(), tab.getTimestampMillis(),
-                    webContentsState != null ? TabStateFileManager.getContentStateByteArray(
-                            webContentsState.buffer())
-                                             : null,
-                    WebContentsState.CONTENTS_STATE_CURRENT_VERSION, TabAssociatedApp.getAppId(tab),
-                    TabThemeColorHelper.isUsingColorFromTabContents(tab)
-                            ? TabThemeColorHelper.getColor(tab)
-                            : TabState.UNSPECIFIED_THEME_COLOR,
-                    tab.getLaunchTypeAtInitialTabCreation(), config.storage, config.id);
-            return criticalPersistedTabData;
-        }
-        CriticalPersistedTabData criticalPersistedTabData = new CriticalPersistedTabData(tab);
-        criticalPersistedTabData.setRootId(tab.getId());
+        PersistedTabDataConfiguration config = PersistedTabDataConfiguration.get(
+                CriticalPersistedTabData.class, tab.isIncognito());
+        // CriticalPersistedTabData is initialized with default values
+        CriticalPersistedTabData criticalPersistedTabData =
+                new CriticalPersistedTabData(tab, tab.getParentId(), tab.getId(),
+                        tab.getTimestampMillis(), null, -1, "", UNSPECIFIED_THEME_COLOR,
+                        tab.getLaunchTypeAtInitialTabCreation() == null
+                                ? TabLaunchType.FROM_LINK
+                                : tab.getLaunchTypeAtInitialTabCreation(),
+                        config.storage, config.id);
         return criticalPersistedTabData;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/state/DEPS b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/DEPS
similarity index 100%
rename from chrome/android/java/src/org/chromium/chrome/browser/tab/state/DEPS
rename to chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/DEPS
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/state/EncryptedFilePersistedTabDataStorage.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/EncryptedFilePersistedTabDataStorage.java
similarity index 100%
rename from chrome/android/java/src/org/chromium/chrome/browser/tab/state/EncryptedFilePersistedTabDataStorage.java
rename to chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/EncryptedFilePersistedTabDataStorage.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/state/FilePersistedTabDataStorage.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/FilePersistedTabDataStorage.java
similarity index 95%
rename from chrome/android/java/src/org/chromium/chrome/browser/tab/state/FilePersistedTabDataStorage.java
rename to chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/FilePersistedTabDataStorage.java
index e0fad3fc..4d778578 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/state/FilePersistedTabDataStorage.java
+++ b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/FilePersistedTabDataStorage.java
@@ -4,18 +4,20 @@
 
 package org.chromium.chrome.browser.tab.state;
 
+import android.content.Context;
+
 import androidx.annotation.MainThread;
 import androidx.annotation.VisibleForTesting;
 import androidx.core.util.AtomicFile;
 
 import org.chromium.base.Callback;
+import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.StreamUtil;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.task.AsyncTask;
 import org.chromium.base.task.PostTask;
-import org.chromium.chrome.browser.tabpersistence.TabStateDirectory;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
 
 import java.io.File;
@@ -36,6 +38,16 @@
     };
     private static final int DECREMENT_SEMAPHORE_VAL = 1;
 
+    private static final String sBaseDirName = "persisted_tab_data_storage";
+    private static class BaseStorageDirectoryHolder {
+        private static File sDirectory;
+
+        static {
+            sDirectory =
+                    ContextUtils.getApplicationContext().getDir(sBaseDirName, Context.MODE_PRIVATE);
+        }
+    }
+
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
     protected LinkedList<StorageRequest> mQueue = new LinkedList<>();
 
@@ -86,10 +98,14 @@
 
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
     protected File getFile(int tabId, String dataId) {
-        return new File(TabStateDirectory.getOrCreateTabbedModeStateDirectory(),
+        return new File(getOrCreateBaseStorageDirectory(),
                 String.format(Locale.ENGLISH, "%d%s", tabId, dataId));
     }
 
+    public static File getOrCreateBaseStorageDirectory() {
+        return BaseStorageDirectoryHolder.sDirectory;
+    }
+
     /**
      * Request for saving, restoring and deleting {@link PersistedTabData}
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/state/MockPersistedTabData.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/MockPersistedTabData.java
similarity index 100%
rename from chrome/android/java/src/org/chromium/chrome/browser/tab/state/MockPersistedTabData.java
rename to chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/MockPersistedTabData.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/state/PersistedTabData.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/PersistedTabData.java
similarity index 100%
rename from chrome/android/java/src/org/chromium/chrome/browser/tab/state/PersistedTabData.java
rename to chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/PersistedTabData.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/state/PersistedTabDataConfiguration.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/PersistedTabDataConfiguration.java
similarity index 100%
rename from chrome/android/java/src/org/chromium/chrome/browser/tab/state/PersistedTabDataConfiguration.java
rename to chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/PersistedTabDataConfiguration.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/state/PersistedTabDataFactory.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/PersistedTabDataFactory.java
similarity index 100%
rename from chrome/android/java/src/org/chromium/chrome/browser/tab/state/PersistedTabDataFactory.java
rename to chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/PersistedTabDataFactory.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/state/PersistedTabDataStorage.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/PersistedTabDataStorage.java
similarity index 100%
rename from chrome/android/java/src/org/chromium/chrome/browser/tab/state/PersistedTabDataStorage.java
rename to chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/PersistedTabDataStorage.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/state/proto/critical_persisted_tab_data.proto b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/proto/critical_persisted_tab_data.proto
similarity index 100%
rename from chrome/android/java/src/org/chromium/chrome/browser/tab/state/proto/critical_persisted_tab_data.proto
rename to chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/proto/critical_persisted_tab_data.proto
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc
index e811008..cb6f254 100644
--- a/chrome/browser/ui/tab_helpers.cc
+++ b/chrome/browser/ui/tab_helpers.cc
@@ -396,8 +396,9 @@
 #if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION)
   captive_portal::CaptivePortalTabHelper::CreateForWebContents(
       web_contents, CaptivePortalServiceFactory::GetForProfile(profile),
-      base::Bind(&ChromeSecurityBlockingPageFactory::OpenLoginTabForWebContents,
-                 web_contents, false));
+      base::BindRepeating(
+          &ChromeSecurityBlockingPageFactory::OpenLoginTabForWebContents,
+          web_contents, false));
 #endif
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
diff --git a/chrome/browser/ui/views/find_bar_view.cc b/chrome/browser/ui/views/find_bar_view.cc
index 8d7ad0f..9c0851b 100644
--- a/chrome/browser/ui/views/find_bar_view.cc
+++ b/chrome/browser/ui/views/find_bar_view.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 #include <utility>
 
+#include "base/feature_list.h"
 #include "base/i18n/number_formatting.h"
 #include "base/macros.h"
 #include "base/strings/string_util.h"
@@ -44,8 +45,10 @@
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/separator.h"
 #include "ui/views/layout/box_layout.h"
+#include "ui/views/layout/layout_provider.h"
 #include "ui/views/painter.h"
 #include "ui/views/view_class_properties.h"
+#include "ui/views/views_features.h"
 #include "ui/views/widget/widget.h"
 
 namespace {
@@ -460,10 +463,13 @@
                   0xFF);
   auto border = std::make_unique<views::BubbleBorder>(
       views::BubbleBorder::NONE, views::BubbleBorder::SMALL_SHADOW, bg_color);
-  // TODO(tluk): Remove when fixing https://crbug.com/822075 and use
-  // EMPHASIS_HIGH metric values from the LayoutProvider to get the
-  // corner radius.
-  border->SetCornerRadius(2);
+
+  border->SetCornerRadius(
+      base::FeatureList::IsEnabled(
+          views::features::kEnableMDRoundedCornersOnDialogs)
+          ? views::LayoutProvider::Get()->GetCornerRadiusMetric(
+                views::EMPHASIS_MEDIUM)
+          : 2);
 
   SetBackground(std::make_unique<views::BubbleBackground>(border.get()));
   SetBorder(std::move(border));
diff --git a/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc b/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc
index bdd2f9b..b1ed7f1b 100644
--- a/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc
+++ b/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc
@@ -495,6 +495,21 @@
     return true;
   }
 
+  views::ImageButton* GetButtonForAction(MediaSessionAction action) {
+    return GetButtonForAction(
+        MediaDialogView::GetDialogViewForTesting()->children().front(),
+        static_cast<int>(action));
+  }
+
+  // Returns true if |target| exists in |base|'s forward focus chain
+  bool ViewFollowsInFocusChain(views::View* base, views::View* target) {
+    for (views::View* cur = base; cur; cur = cur->GetNextFocusableView()) {
+      if (cur == target)
+        return true;
+    }
+    return false;
+  }
+
  protected:
   std::unique_ptr<TestWebContentsPresentationManager> presentation_manager_;
   TestMediaRouter* media_router_ = nullptr;
@@ -508,12 +523,6 @@
     closure_loop.Run();
   }
 
-  views::ImageButton* GetButtonForAction(MediaSessionAction action) {
-    return GetButtonForAction(
-        MediaDialogView::GetDialogViewForTesting()->children().front(),
-        static_cast<int>(action));
-  }
-
   // Recursively tries to find a views::ImageButton for the given
   // MediaSessionAction. This operates under the assumption that
   // media_message_center::MediaNotificationViewImpl sets the tags of its action
@@ -605,6 +614,80 @@
   EXPECT_FALSE(IsDialogVisible());
 }
 
+IN_PROC_BROWSER_TEST_F(MediaDialogViewBrowserTest,
+                       ShowsMetadataAndControlsMediaInRTL) {
+  base::i18n::SetICUDefaultLocale("ar");
+  ASSERT_TRUE(base::i18n::IsRTL());
+
+  // The toolbar icon should not start visible.
+  EXPECT_FALSE(IsToolbarIconVisible());
+
+  // Opening a page with media that hasn't played yet should not make the
+  // toolbar icon visible.
+  OpenTestURL();
+  LayoutBrowser();
+  EXPECT_FALSE(IsToolbarIconVisible());
+
+  // Once playback starts, the icon should be visible, but the dialog should not
+  // appear if it hasn't been clicked.
+  StartPlayback();
+  WaitForStart();
+  WaitForVisibleToolbarIcon();
+  EXPECT_TRUE(IsToolbarIconVisible());
+  EXPECT_FALSE(IsDialogVisible());
+
+  // At this point, the toolbar icon has been set visible. Layout the
+  // browser to ensure it can be clicked.
+  LayoutBrowser();
+
+  // Clicking on the toolbar icon should open the dialog.
+  ClickToolbarIcon();
+  WaitForDialogOpened();
+  EXPECT_TRUE(IsDialogVisible());
+
+  // The view containing playback controls should not be mirrored.
+  EXPECT_FALSE(MediaDialogView::GetDialogViewForTesting()
+                   ->GetNotificationsForTesting()
+                   .begin()
+                   ->second->view_for_testing()
+                   ->playback_button_container_for_testing()
+                   ->GetMirrored());
+
+  // The dialog should contain the title and artist. These are taken from
+  // video-with-metadata.html.
+  WaitForDialogToContainText(base::ASCIIToUTF16("Big Buck Bunny"));
+  WaitForDialogToContainText(base::ASCIIToUTF16("Blender Foundation"));
+
+  // Clicking on the pause button in the dialog should pause the media on the
+  // page.
+  ClickPauseButtonOnDialog();
+  WaitForStop();
+
+  // Clicking on the play button in the dialog should play the media on the
+  // page.
+  ClickPlayButtonOnDialog();
+  WaitForStart();
+
+  // In the RTL UI the picture in picture button should be to the left of the
+  // playback control buttons.
+  EXPECT_LT(
+      GetButtonForAction(MediaSessionAction::kEnterPictureInPicture)
+          ->GetMirroredX(),
+      GetButtonForAction(MediaSessionAction::kPlay)->parent()->GetMirroredX());
+
+  // In the RTL UI the focus order should be the same as it is in the LTR UI.
+  // That is the play/pause button logically proceeds the picture in picture
+  // button.
+  EXPECT_TRUE(ViewFollowsInFocusChain(
+      GetButtonForAction(MediaSessionAction::kPlay)->parent(),
+      GetButtonForAction(MediaSessionAction::kEnterPictureInPicture)));
+
+  // Clicking on the toolbar icon again should hide the dialog.
+  EXPECT_TRUE(IsDialogVisible());
+  ClickToolbarIcon();
+  EXPECT_FALSE(IsDialogVisible());
+}
+
 IN_PROC_BROWSER_TEST_F(MediaDialogViewBrowserTest, ShowsMultipleMediaSessions) {
   // Open a tab and play media.
   OpenTestURL();
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc
index 0d31cd4..c5b478e 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -375,16 +375,16 @@
 void LocationBarView::FocusLocation(bool is_user_initiated) {
   const bool omnibox_already_focused = omnibox_view_->HasFocus();
 
+  if (is_user_initiated)
+    omnibox_view()->model()->Unelide();
+
   omnibox_view_->SetFocus(is_user_initiated);
 
   if (omnibox_already_focused)
     omnibox_view()->model()->ClearKeyword();
 
-  if (!is_user_initiated)
-    return;
-
-  omnibox_view_->SelectAll(true);
-  omnibox_view()->model()->Unelide();
+  if (is_user_initiated)
+    omnibox_view_->SelectAll(true);
 }
 
 void LocationBarView::Revert() {
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
index a21c1c9..f4697da 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -2431,6 +2431,15 @@
     elide_after_interaction_animation_->Stop();
   ApplyCaretVisibility();
   FitToLocalBounds();
+
+  // Previous animations or elisions might have faded the path and/or subdomains
+  // to transparent, so reset their color now that they should be visible.
+  ApplyColor(GetOmniboxColor(GetThemeProvider(),
+                             OmniboxPart::LOCATION_BAR_TEXT_DIMMED),
+             gfx::Range(0, GetText().size()));
+  UpdateTextStyle(GetText(), model()->CurrentTextIsURL(),
+                  model()->client()->GetSchemeClassifier());
+
   GetRenderText()->SetElideBehavior(gfx::ELIDE_TAIL);
 }
 
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
index a83a421..d0a7da4c 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
@@ -2505,10 +2505,32 @@
       kSimplifiedDomainDisplayUrlHostnameAndScheme,
       kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
 
-  // Now focus and blur the omnibox. After blur, the path should fade out again
-  // after another user interaction.
+  // After focus, the URL should be fully unelided.
   omnibox_view()->OnFocus();
+  ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
+      render_text, gfx::Range(0, kSimplifiedDomainDisplayUrl.size())));
+  EXPECT_NE(SK_ColorTRANSPARENT,
+            omnibox_view()->GetLatestColorForRange(
+                gfx::Range(0, omnibox_view()->GetText().size())));
+  EXPECT_EQ(gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
+                       kSimplifiedDomainDisplayUrlHostnameAndScheme.size()),
+            omnibox_view()->emphasis_range());
+
+  // After blur, the URL should return to the same state as page load: only
+  // scheme and trivial subdomains elided.
   omnibox_view()->OnBlur();
+  ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
+      render_text, gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
+                              kSimplifiedDomainDisplayUrl.size())));
+  EXPECT_NE(SK_ColorTRANSPARENT,
+            omnibox_view()->GetLatestColorForRange(
+                gfx::Range(0, omnibox_view()->GetText().size())));
+  EXPECT_EQ(gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
+                       kSimplifiedDomainDisplayUrlHostnameAndScheme.size()),
+            omnibox_view()->emphasis_range());
+
+  // After a post-blur user interaction, the URL should animate to the
+  // simplified domain.
   omnibox_view()->DidGetUserInteraction(
       blink::WebInputEvent::Type::kGestureScrollBegin);
   elide_animation =
diff --git a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
index 362ac523..9c87ddcf 100644
--- a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
+++ b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
@@ -106,8 +106,12 @@
 class BrowserTabStripController::TabContextMenuContents
     : public ui::SimpleMenuModel::Delegate {
  public:
-  TabContextMenuContents(Tab* tab, BrowserTabStripController* controller)
-      : tab_(tab), controller_(controller) {
+  TabContextMenuContents(Tab* tab,
+                         BrowserTabStripController* controller,
+                         TabGroupsIPHController* tab_groups_iph_controller)
+      : tab_(tab),
+        controller_(controller),
+        tab_groups_iph_controller_(tab_groups_iph_controller) {
     model_ = controller_->menu_model_factory_->Create(
         this, controller->model_, controller->tabstrip_->GetModelIndexOf(tab));
     menu_runner_ = std::make_unique<views::MenuRunner>(
@@ -118,6 +122,7 @@
   void Cancel() { controller_ = nullptr; }
 
   void RunMenuAt(const gfx::Point& point, ui::MenuSourceType source_type) {
+    tab_groups_iph_controller_->TabContextMenuOpened();
     menu_runner_->RunMenuAt(tab_->GetWidget(), nullptr,
                             gfx::Rect(point, gfx::Size()),
                             views::MenuAnchorPosition::kTopLeft, source_type);
@@ -130,6 +135,17 @@
         static_cast<TabStripModel::ContextMenuCommand>(command_id),
         tab_);
   }
+
+  bool IsCommandIdAlerted(int command_id) const override {
+    return command_id == TabStripModel::CommandAddToNewGroup &&
+           tab_groups_iph_controller_ &&
+           tab_groups_iph_controller_->ShouldHighlightContextMenuItem();
+  }
+
+  void MenuClosed(ui::SimpleMenuModel*) override {
+    tab_groups_iph_controller_->TabContextMenuClosed();
+  }
+
   bool GetAcceleratorForCommandId(int command_id,
                                   ui::Accelerator* accelerator) const override {
     auto* app_controller =
@@ -162,6 +178,8 @@
   // A pointer back to our hosting controller, for command state information.
   BrowserTabStripController* controller_;
 
+  TabGroupsIPHController* const tab_groups_iph_controller_;
+
   DISALLOW_COPY_AND_ASSIGN(TabContextMenuContents);
 };
 
@@ -398,13 +416,9 @@
     Tab* tab,
     const gfx::Point& p,
     ui::MenuSourceType source_type) {
-  context_menu_contents_ = std::make_unique<TabContextMenuContents>(tab, this);
+  context_menu_contents_ = std::make_unique<TabContextMenuContents>(
+      tab, this, browser_view_->tab_groups_iph_controller());
   context_menu_contents_->RunMenuAt(p, source_type);
-
-  TabGroupsIPHController* const iph_controller =
-      browser_view_->tab_groups_iph_controller();
-  if (iph_controller)
-    iph_controller->TabContextMenuOpened();
 }
 
 int BrowserTabStripController::HasAvailableDragActions() const {
diff --git a/chrome/browser/ui/views/tabs/tab_groups_iph_controller.cc b/chrome/browser/ui/views/tabs/tab_groups_iph_controller.cc
index 551dcfb..c91cdc1 100644
--- a/chrome/browser/ui/views/tabs/tab_groups_iph_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_groups_iph_controller.cc
@@ -38,13 +38,32 @@
   HandlePromoClose();
 }
 
+bool TabGroupsIPHController::ShouldHighlightContextMenuItem() {
+  // If the bubble is currently showing, the promo hasn't timed out yet.
+  // The promo should continue into the context menu as a highlighted
+  // item.
+  return promo_widget_ != nullptr;
+}
+
 void TabGroupsIPHController::TabContextMenuOpened() {
   if (!promo_widget_)
     return;
 
+  // Assume that the context menu code checked
+  // ShouldHighlightContextMenuItem() and is correctly showing the promo
+  // there.
+  showing_in_menu_ = true;
   promo_widget_->Close();
 }
 
+void TabGroupsIPHController::TabContextMenuClosed() {
+  if (!showing_in_menu_)
+    return;
+
+  showing_in_menu_ = false;
+  Dismissed();
+}
+
 void TabGroupsIPHController::OnTabStripModelChanged(
     TabStripModel* tab_strip_model,
     const TabStripModelChange& change,
@@ -93,5 +112,16 @@
 void TabGroupsIPHController::HandlePromoClose() {
   widget_observer_.Remove(promo_widget_);
   promo_widget_ = nullptr;
+
+  // If the promo continued into the context menu, it hasn't been
+  // dismissed yet. We wait on notifying the backend until the menu
+  // closes at which point the promo is complete.
+  if (!showing_in_menu_)
+    Dismissed();
+}
+
+void TabGroupsIPHController::Dismissed() {
+  DCHECK_EQ(promo_widget_, nullptr);
+  DCHECK(!showing_in_menu_);
   tracker_->Dismissed(feature_engagement::kIPHDesktopTabGroupsNewGroupFeature);
 }
diff --git a/chrome/browser/ui/views/tabs/tab_groups_iph_controller.h b/chrome/browser/ui/views/tabs/tab_groups_iph_controller.h
index 0f07086..dd321af3 100644
--- a/chrome/browser/ui/views/tabs/tab_groups_iph_controller.h
+++ b/chrome/browser/ui/views/tabs/tab_groups_iph_controller.h
@@ -25,9 +25,6 @@
 // Manages in-product help for tab groups. Watches for relevant events
 // in a browser window, communicates them to the IPH backend, and
 // displays IPH when appropriate.
-//
-// This doesn't actually show the IPH yet. TODO(crbug.com/1022943): show
-// a promo.
 class TabGroupsIPHController : public TabStripModelObserver,
                                public views::WidgetObserver {
  public:
@@ -40,8 +37,17 @@
   TabGroupsIPHController(Browser* browser, GetTabViewCallback get_tab_view);
   ~TabGroupsIPHController() override;
 
+  // Whether the add-to-new-group item in the tab context menu should be
+  // highlighted. Must be checked before TabContextMenuOpened() is
+  // called.
+  bool ShouldHighlightContextMenuItem();
+
+  // Should be called when a tab context menu is opened.
   void TabContextMenuOpened();
 
+  // Likewise, should be called when a tab context menu is closed.
+  void TabContextMenuClosed();
+
   // TabStripModelObserver:
   void OnTabStripModelChanged(
       TabStripModel* tab_strip_model,
@@ -53,17 +59,27 @@
   void OnWidgetClosing(views::Widget* widget) override;
   void OnWidgetDestroying(views::Widget* widget) override;
 
+  views::Widget* promo_widget_for_testing() { return promo_widget_; }
+
  private:
   void HandlePromoClose();
 
+  // Notify the backend that the promo finished.
+  void Dismissed();
+
   // The IPH backend for the profile.
   feature_engagement::Tracker* const tracker_;
 
   GetTabViewCallback get_tab_view_;
 
-  // The promo widget. Only non-null while it is showing.
+  // The promo bubble's widget. Only non-null while it is showing.
   views::Widget* promo_widget_ = nullptr;
 
+  // True if the user opened a tab context menu while the bubble was
+  // showing. A promo is now showing in the menu. When true, we wait
+  // until the menu is closed to notify the backend of dismissal.
+  bool showing_in_menu_ = false;
+
   ScopedObserver<views::Widget, views::WidgetObserver> widget_observer_{this};
 };
 
diff --git a/chrome/browser/ui/views/tabs/tab_groups_iph_controller_unittest.cc b/chrome/browser/ui/views/tabs/tab_groups_iph_controller_unittest.cc
index 9efd4fb6..c2ff4daa 100644
--- a/chrome/browser/ui/views/tabs/tab_groups_iph_controller_unittest.cc
+++ b/chrome/browser/ui/views/tabs/tab_groups_iph_controller_unittest.cc
@@ -122,7 +122,7 @@
   browser()->tab_strip_model()->AddToNewGroup({0});
 }
 
-TEST_F(TabGroupsIPHControllerTest, DismissedOnContextMenuOpened) {
+TEST_F(TabGroupsIPHControllerTest, DismissedOnBubbleClosedBeforeMenuOpened) {
   EXPECT_CALL(*mock_tracker_,
               ShouldTriggerHelpUI(
                   Ref(feature_engagement::kIPHDesktopTabGroupsNewGroupFeature)))
@@ -132,10 +132,88 @@
   for (int i = 0; i < 6; ++i)
     chrome::NewTab(browser());
 
+  ASSERT_TRUE(iph_controller_->promo_widget_for_testing());
+
   EXPECT_CALL(
       *mock_tracker_,
       Dismissed(Ref(feature_engagement::kIPHDesktopTabGroupsNewGroupFeature)))
       .Times(1);
 
+  iph_controller_->promo_widget_for_testing()->Close();
+}
+
+TEST_F(TabGroupsIPHControllerTest, DismissedOnMenuClosed) {
+  EXPECT_CALL(*mock_tracker_,
+              ShouldTriggerHelpUI(
+                  Ref(feature_engagement::kIPHDesktopTabGroupsNewGroupFeature)))
+      .Times(1)
+      .WillOnce(Return(true));
+
+  for (int i = 0; i < 6; ++i)
+    chrome::NewTab(browser());
+
+  EXPECT_TRUE(iph_controller_->promo_widget_for_testing());
   iph_controller_->TabContextMenuOpened();
+  EXPECT_FALSE(iph_controller_->promo_widget_for_testing());
+
+  EXPECT_CALL(
+      *mock_tracker_,
+      Dismissed(Ref(feature_engagement::kIPHDesktopTabGroupsNewGroupFeature)))
+      .Times(1);
+
+  iph_controller_->TabContextMenuClosed();
+  EXPECT_FALSE(iph_controller_->promo_widget_for_testing());
+}
+
+TEST_F(TabGroupsIPHControllerTest, ShowsContextMenuHighlightIfAppropriate) {
+  EXPECT_CALL(*mock_tracker_,
+              ShouldTriggerHelpUI(
+                  Ref(feature_engagement::kIPHDesktopTabGroupsNewGroupFeature)))
+      .Times(1)
+      .WillOnce(Return(true));
+  EXPECT_CALL(
+      *mock_tracker_,
+      Dismissed(Ref(feature_engagement::kIPHDesktopTabGroupsNewGroupFeature)))
+      .Times(1);
+
+  EXPECT_FALSE(iph_controller_->ShouldHighlightContextMenuItem());
+
+  for (int i = 0; i < 6; ++i)
+    chrome::NewTab(browser());
+
+  EXPECT_TRUE(iph_controller_->ShouldHighlightContextMenuItem());
+  iph_controller_->TabContextMenuOpened();
+  iph_controller_->TabContextMenuClosed();
+  EXPECT_FALSE(iph_controller_->ShouldHighlightContextMenuItem());
+}
+
+TEST_F(TabGroupsIPHControllerTest, DoesNothingIfDisallowed) {
+  EXPECT_CALL(*mock_tracker_,
+              ShouldTriggerHelpUI(
+                  Ref(feature_engagement::kIPHDesktopTabGroupsNewGroupFeature)))
+      .Times(1)
+      .WillOnce(Return(false));
+  EXPECT_CALL(
+      *mock_tracker_,
+      Dismissed(Ref(feature_engagement::kIPHDesktopTabGroupsNewGroupFeature)))
+      .Times(0);
+
+  EXPECT_FALSE(iph_controller_->ShouldHighlightContextMenuItem());
+  EXPECT_FALSE(iph_controller_->promo_widget_for_testing());
+
+  for (int i = 0; i < 6; ++i)
+    chrome::NewTab(browser());
+
+  EXPECT_FALSE(iph_controller_->ShouldHighlightContextMenuItem());
+  EXPECT_FALSE(iph_controller_->promo_widget_for_testing());
+
+  iph_controller_->TabContextMenuOpened();
+
+  EXPECT_FALSE(iph_controller_->ShouldHighlightContextMenuItem());
+  EXPECT_FALSE(iph_controller_->promo_widget_for_testing());
+
+  iph_controller_->TabContextMenuClosed();
+
+  EXPECT_FALSE(iph_controller_->ShouldHighlightContextMenuItem());
+  EXPECT_FALSE(iph_controller_->promo_widget_for_testing());
 }
diff --git a/chrome/browser/ui/webui/downloads/downloads_ui.cc b/chrome/browser/ui/webui/downloads/downloads_ui.cc
index 0f976c1..91712e49 100644
--- a/chrome/browser/ui/webui/downloads/downloads_ui.cc
+++ b/chrome/browser/ui/webui/downloads/downloads_ui.cc
@@ -14,6 +14,7 @@
 #include "base/threading/thread.h"
 #include "base/values.h"
 #include "chrome/browser/defaults.h"
+#include "chrome/browser/enterprise/connectors/connectors_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/safe_browsing/advanced_protection_status_manager.h"
 #include "chrome/browser/safe_browsing/advanced_protection_status_manager_factory.h"
@@ -169,6 +170,12 @@
   source->AddResourcePath("downloads.mojom-lite.js",
                           IDR_DOWNLOADS_MOJO_LITE_JS);
 
+  source->AddBoolean(
+      "allowOpenNow",
+      !enterprise_connectors::ConnectorsManager::GetInstance()
+           ->DelayUntilVerdict(
+               enterprise_connectors::AnalysisConnector::FILE_DOWNLOADED));
+
   return source;
 }
 
diff --git a/chrome/browser/web_applications/components/web_app_file_handler_registration_win.cc b/chrome/browser/web_applications/components/web_app_file_handler_registration_win.cc
index 3724f31..baf0454 100644
--- a/chrome/browser/web_applications/components/web_app_file_handler_registration_win.cc
+++ b/chrome/browser/web_applications/components/web_app_file_handler_registration_win.cc
@@ -204,7 +204,6 @@
     return;
   }
   base::CommandLine app_specific_launcher_command(app_specific_launcher_path);
-  app_specific_launcher_command.AppendArg("%1");
   app_specific_launcher_command.AppendSwitchPath(switches::kProfileDirectory,
                                                  profile_path.BaseName());
   app_specific_launcher_command.AppendSwitchASCII(switches::kAppId, app_id);
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index cbaf5439..8fb3932 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-master-1594987060-434c51fdab164717c1b94e12633f94a30a81dd52.profdata
+chrome-mac-master-1595028747-81e43afb2ec18845c639db32e07c52ff5831a7c4.profdata
diff --git a/chrome/common/extensions/manifest_tests/extension_manifests_options_unittest.cc b/chrome/common/extensions/manifest_tests/extension_manifests_options_unittest.cc
index e6d0e81..768d9af 100644
--- a/chrome/common/extensions/manifest_tests/extension_manifests_options_unittest.cc
+++ b/chrome/common/extensions/manifest_tests/extension_manifests_options_unittest.cc
@@ -138,4 +138,15 @@
   }
 }
 
+// Tests that the chrome_style flag is not supported in manifest v3 and will
+// trigger an error when specified.
+TEST_F(OptionsPageManifestTest, OptionsPageChromeStyleManifestV3) {
+  LoadAndExpectError(
+      "options_ui_chrome_style_manifest_v3_false.json",
+      extensions::manifest_errors::kChromeStyleInvalidForManifestV3);
+  LoadAndExpectError(
+      "options_ui_chrome_style_manifest_v3_true.json",
+      extensions::manifest_errors::kChromeStyleInvalidForManifestV3);
+}
+
 }  // namespace
diff --git a/chrome/credential_provider/gaiacp/BUILD.gn b/chrome/credential_provider/gaiacp/BUILD.gn
index 978b3ca..b62746b 100644
--- a/chrome/credential_provider/gaiacp/BUILD.gn
+++ b/chrome/credential_provider/gaiacp/BUILD.gn
@@ -41,10 +41,12 @@
     "//build:branding_buildflags",
     "//chrome/common:version_header",
     "//chrome/installer/launcher_support",
+    "//components/crash/core/app",
     "//components/crash/core/common",
     "//components/version_info",
     "//google_apis:google_apis",
     "//third_party/re2",
+    "//url",
   ]
 }
 
@@ -117,6 +119,7 @@
   deps = [
     ":gaia_credential_provider_idl",
     ":static_resources",
+    ":string_resources",
     "../eventlog:gcp_eventlog_messages",
     "//build:branding_buildflags",
     "//chrome/common:non_code_constants",
@@ -126,14 +129,14 @@
     "//components/crash/core/app:app",
     "//components/crash/core/app:crash_export_thunks",
     "//components/crash/core/app:run_as_crashpad_handler",
+    "//content/public/browser",
+    "//crypto",
+    "//google_apis",
+    "//net",
     "//third_party/boringssl",
     "//third_party/re2",
+    "//url",
   ]
-  if (is_component_build) {
-    deps += [ "//content/public/common" ]
-  } else {
-    deps += [ "//content/public/common:static_switches" ]
-  }
   libs = [
     "hid.lib",
     "setupapi.lib",
@@ -228,8 +231,12 @@
     ":common",
     ":gaiacp_lib",
     ":version",
+    "//base",
     "//build:branding_buildflags",
     "//chrome/common:version_header",
+    "//components/crash/core/app",
+    "//components/crash/core/app:run_as_crashpad_handler",
+    "//content/public/browser",
   ]
   configs += [ "//build/config/win:windowed" ]
 }
diff --git a/chrome/credential_provider/gaiacp/gaia_credential.cc b/chrome/credential_provider/gaiacp/gaia_credential.cc
index 2b8ef84..d24bdb3 100644
--- a/chrome/credential_provider/gaiacp/gaia_credential.cc
+++ b/chrome/credential_provider/gaiacp/gaia_credential.cc
@@ -13,7 +13,6 @@
 #include "chrome/credential_provider/gaiacp/logging.h"
 #include "chrome/credential_provider/gaiacp/mdm_utils.h"
 #include "content/public/common/content_switches.h"
-#include "google_apis/gaia/gaia_switches.h"
 
 namespace credential_provider {
 CGaiaCredential::CGaiaCredential() = default;
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_provider_module.cc b/chrome/credential_provider/gaiacp/gaia_credential_provider_module.cc
index 97f3627..2486f9a 100644
--- a/chrome/credential_provider/gaiacp/gaia_credential_provider_module.cc
+++ b/chrome/credential_provider/gaiacp/gaia_credential_provider_module.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/credential_provider/gaiacp/dllmain.h"
+#include "chrome/credential_provider/gaiacp/gaia_credential_provider_module.h"
 
 #include "base/command_line.h"
 #include "base/files/file_path.h"
diff --git a/chrome/credential_provider/gaiacp/gcp_utils.h b/chrome/credential_provider/gaiacp/gcp_utils.h
index b6e2882..001f5b2 100644
--- a/chrome/credential_provider/gaiacp/gcp_utils.h
+++ b/chrome/credential_provider/gaiacp/gcp_utils.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_CREDENTIAL_PROVIDER_GAIACP_GCP_UTILS_H_
 #define CHROME_CREDENTIAL_PROVIDER_GAIACP_GCP_UTILS_H_
 
+#include <windows.h>
 #include <memory>
 #include <string>
 
@@ -15,7 +16,6 @@
 #include "base/version.h"
 #include "base/win/scoped_handle.h"
 #include "base/win/windows_types.h"
-#include "chrome/credential_provider/gaiacp/scoped_handle.h"
 #include "chrome/credential_provider/gaiacp/scoped_lsa_policy.h"
 #include "url/gurl.h"
 
diff --git a/chrome/credential_provider/gaiacp/gem_device_details_manager.cc b/chrome/credential_provider/gaiacp/gem_device_details_manager.cc
index 2275cf7..40134bb5 100644
--- a/chrome/credential_provider/gaiacp/gem_device_details_manager.cc
+++ b/chrome/credential_provider/gaiacp/gem_device_details_manager.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include "chrome/credential_provider/gaiacp/gem_device_details_manager.h"
-#include "chrome/credential_provider/gaiacp/mdm_utils.h"
 
 #include <windows.h>
 #include <winternl.h>
@@ -23,6 +22,7 @@
 #include "chrome/credential_provider/gaiacp/gcpw_strings.h"
 #include "chrome/credential_provider/gaiacp/logging.h"
 #include "chrome/credential_provider/gaiacp/mdm_utils.h"
+#include "chrome/credential_provider/gaiacp/os_user_manager.h"
 #include "chrome/credential_provider/gaiacp/reg_utils.h"
 #include "chrome/credential_provider/gaiacp/win_http_url_fetcher.h"
 
diff --git a/chrome/credential_provider/gaiacp/mdm_utils.h b/chrome/credential_provider/gaiacp/mdm_utils.h
index c73f2b01..73d882e 100644
--- a/chrome/credential_provider/gaiacp/mdm_utils.h
+++ b/chrome/credential_provider/gaiacp/mdm_utils.h
@@ -10,7 +10,6 @@
 #include "base/strings/string16.h"
 #include "base/values.h"
 #include "base/win/windows_types.h"
-#include "chrome/credential_provider/gaiacp/os_user_manager.h"
 #include "url/gurl.h"
 
 namespace credential_provider {
diff --git a/chrome/credential_provider/gaiacp/os_process_manager.cc b/chrome/credential_provider/gaiacp/os_process_manager.cc
index 88ad4e3..9f66ec1 100644
--- a/chrome/credential_provider/gaiacp/os_process_manager.cc
+++ b/chrome/credential_provider/gaiacp/os_process_manager.cc
@@ -40,6 +40,7 @@
 #include "chrome/credential_provider/common/gcp_strings.h"
 #include "chrome/credential_provider/gaiacp/gcp_utils.h"
 #include "chrome/credential_provider/gaiacp/logging.h"
+#include "chrome/credential_provider/gaiacp/scoped_handle.h"
 
 typedef NTSTATUS(FAR WINAPI* NtOpenDirectoryObjectPfn)(
     OUT PHANDLE DirectoryHandle,
diff --git a/chrome/credential_provider/setup/gcp_installer_crash_reporting.cc b/chrome/credential_provider/setup/gcp_installer_crash_reporting.cc
index ccc0de4..273abb2c 100644
--- a/chrome/credential_provider/setup/gcp_installer_crash_reporting.cc
+++ b/chrome/credential_provider/setup/gcp_installer_crash_reporting.cc
@@ -13,7 +13,6 @@
 #include "base/version.h"
 #include "base/win/registry.h"
 #include "build/branding_buildflags.h"
-#include "chrome/common/chrome_paths.h"
 #include "chrome/credential_provider/common/gcp_strings.h"
 #include "chrome/credential_provider/gaiacp/gcp_crash_reporter_client.h"
 #include "chrome/credential_provider/gaiacp/gcp_crash_reporting_utils.h"
diff --git a/chrome/credential_provider/test/BUILD.gn b/chrome/credential_provider/test/BUILD.gn
index 09eb1ea..5851ccb2 100644
--- a/chrome/credential_provider/test/BUILD.gn
+++ b/chrome/credential_provider/test/BUILD.gn
@@ -30,11 +30,16 @@
 
   deps = [
     "../gaiacp:common",
+    "../gaiacp:gaia_credential_provider_idl",
     "../gaiacp:gaiacp_lib",
+    "../gaiacp:string_resources",
     "../gaiacp:version",
     "../setup:common",
     "//base",
+    "//chrome/common:non_code_constants",
     "//chrome/test:credential_provider_test_utils",
+    "//content/public/browser",
+    "//google_apis",
     "//net:test_support",
     "//testing/gmock",
     "//testing/gtest",
diff --git a/chrome/installer/mini_installer/decompress.cc b/chrome/installer/mini_installer/decompress.cc
index e314cb5..276343d 100644
--- a/chrome/installer/mini_installer/decompress.cc
+++ b/chrome/installer/mini_installer/decompress.cc
@@ -96,8 +96,9 @@
   }
 
   scoped_ptr<wchar_t> path(Utf8ToWide(pszFile));
-  HANDLE file = CreateFileW(path, access, FILE_SHARE_READ, nullptr, disposition,
-                            FILE_ATTRIBUTE_NORMAL, nullptr);
+  HANDLE file =
+      CreateFileW(path, access, FILE_SHARE_DELETE | FILE_SHARE_READ, nullptr,
+                  disposition, FILE_ATTRIBUTE_NORMAL, nullptr);
   return reinterpret_cast<INT_PTR>(file);
 }
 
diff --git a/chrome/installer/util/install_util.cc b/chrome/installer/util/install_util.cc
index 95b36eb..665644810 100644
--- a/chrome/installer/util/install_util.cc
+++ b/chrome/installer/util/install_util.cc
@@ -508,7 +508,7 @@
 bool InstallUtil::ProgramCompare::OpenForInfo(const base::FilePath& path,
                                               base::File* file) {
   DCHECK(file);
-  file->Initialize(path, base::File::FLAG_OPEN);
+  file->Initialize(path, base::File::FLAG_OPEN | base::File::FLAG_SHARE_DELETE);
   return file->IsValid();
 }
 
diff --git a/chrome/installer/util/lzma_util.cc b/chrome/installer/util/lzma_util.cc
index ac15c2a..4992112 100644
--- a/chrome/installer/util/lzma_util.cc
+++ b/chrome/installer/util/lzma_util.cc
@@ -147,7 +147,8 @@
 
   archive_file_.Initialize(archivePath, base::File::FLAG_OPEN |
                                             base::File::FLAG_READ |
-                                            base::File::FLAG_EXCLUSIVE_WRITE);
+                                            base::File::FLAG_EXCLUSIVE_WRITE |
+                                            base::File::FLAG_SHARE_DELETE);
   if (archive_file_.IsValid())
     return UNPACK_NO_ERROR;
   error_code_ = ::GetLastError();
diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc
index 0f5dd30b..0d6f0d3 100644
--- a/chrome/installer/util/shell_util.cc
+++ b/chrome/installer/util/shell_util.cc
@@ -1770,7 +1770,7 @@
 
 base::string16 ShellUtil::GetChromeShellOpenCmd(
     const base::FilePath& chrome_exe) {
-  return L"\"" + chrome_exe.value() + L"\" -- \"%1\"";
+  return base::CommandLine(chrome_exe).GetCommandLineStringForShell();
 }
 
 base::string16 ShellUtil::GetChromeDelegateCommand(
@@ -2402,7 +2402,8 @@
   app_info.file_type_name = file_type_name;
   app_info.file_type_icon_path = icon_path;
   app_info.file_type_icon_index = 0;
-  app_info.command_line = command_line.GetCommandLineStringWithPlaceholders();
+  app_info.command_line = command_line.GetCommandLineStringForShell();
+
   GetProgIdEntries(app_info, &entries);
 
   std::vector<base::string16> handled_file_extensions;
diff --git a/chrome/installer/util/shell_util.h b/chrome/installer/util/shell_util.h
index 1c149bf..27e6950 100644
--- a/chrome/installer/util/shell_util.h
+++ b/chrome/installer/util/shell_util.h
@@ -625,8 +625,8 @@
   // |prog_id| is the ProgId used by Windows for file associations with this
   // application. Must not be empty or start with a '.'.
   // |command_line| is the command to execute when opening a file via this
-  // association. It should contain "%1" (to tell Windows to pass the filename
-  // as an argument).
+  // association. It must not contain the Windows filename placeholder "%1";
+  // this function will register |command_line| plus the filename placeholder.
   // |application_name| is the friendly name displayed for this application in
   // the Open With menu.
   // |file_type_name| is the friendly name for files of these types when
diff --git a/chrome/installer/util/shell_util_unittest.cc b/chrome/installer/util/shell_util_unittest.cc
index 65851be..fe081c6 100644
--- a/chrome/installer/util/shell_util_unittest.cc
+++ b/chrome/installer/util/shell_util_unittest.cc
@@ -820,8 +820,6 @@
   static base::CommandLine OpenCommand() {
     base::FilePath open_command_path(kTestOpenCommand);
     base::CommandLine open_command(open_command_path);
-    // The "%1" should automatically be quoted.
-    open_command.AppendArg("%1");
     return open_command;
   }
 
@@ -863,7 +861,7 @@
       key.Open(HKEY_CURRENT_USER,
                L"Software\\Classes\\TestApp\\shell\\open\\command", KEY_READ));
   EXPECT_EQ(ERROR_SUCCESS, key.ReadValue(L"", &value));
-  EXPECT_EQ(L"\"C:\\test.exe\" \"%1\"", value);
+  EXPECT_EQ(L"\"C:\\test.exe\" --single-argument %1", value);
 
   // The Application subkey and values are only required by Windows 8 and later.
   if (base::win::GetVersion() >= base::win::Version::WIN8) {
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 0517448..88f9f719 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -4341,6 +4341,7 @@
     deps += [
       "//chrome/browser/nearby_sharing/certificates:unit_tests",
       "//chrome/browser/nearby_sharing/client:unit_tests",
+      "//chrome/browser/nearby_sharing/local_device_data:unit_tests",
       "//chrome/browser/nearby_sharing/logging:unit_tests",
       "//chrome/browser/nearby_sharing/proto",
       "//chrome/browser/nearby_sharing/scheduling:unit_tests",
diff --git a/chrome/test/data/extensions/manifest_tests/options_ui_chrome_style_manifest_v3_false.json b/chrome/test/data/extensions/manifest_tests/options_ui_chrome_style_manifest_v3_false.json
new file mode 100644
index 0000000..a631b3d
--- /dev/null
+++ b/chrome/test/data/extensions/manifest_tests/options_ui_chrome_style_manifest_v3_false.json
@@ -0,0 +1,10 @@
+{
+  "name": "options_ui with chrome_style in manifest v3",
+  "description": "Tests that specifying chrome_style=false is invalid for manifest v3",
+  "version": "1",
+  "manifest_version": 3,
+  "options_ui": {
+    "page": "options.html",
+    "chrome_style": false
+  }
+}
diff --git a/chrome/test/data/extensions/manifest_tests/options_ui_chrome_style_manifest_v3_true.json b/chrome/test/data/extensions/manifest_tests/options_ui_chrome_style_manifest_v3_true.json
new file mode 100644
index 0000000..318baa9
--- /dev/null
+++ b/chrome/test/data/extensions/manifest_tests/options_ui_chrome_style_manifest_v3_true.json
@@ -0,0 +1,10 @@
+{
+  "name": "options_ui with chrome_style in manifest v3",
+  "description": "Tests that specifying chrome_style=true is invalid for manifest v3",
+  "version": "1",
+  "manifest_version": 3,
+  "options_ui": {
+    "page": "options.html",
+    "chrome_style": true
+  }
+}
diff --git a/chrome/test/data/pdf/test_util.js b/chrome/test/data/pdf/test_util.js
index 31caeb2..5679f8a 100644
--- a/chrome/test/data/pdf/test_util.js
+++ b/chrome/test/data/pdf/test_util.js
@@ -242,7 +242,7 @@
   document.body.appendChild(dummyContent);
   const viewport = new Viewport(
       window, /** @type {!HTMLDivElement} */ (sizer), dummyContent,
-      scrollbarWidth, defaultZoom, topToolbarHeight);
+      scrollbarWidth, defaultZoom, topToolbarHeight, false);
   viewport.setZoomFactorRange([0.25, 0.4, 0.5, 1, 2]);
   return viewport;
 }
diff --git a/chrome/test/data/pdf/viewport_test.js b/chrome/test/data/pdf/viewport_test.js
index be44317..19f3917 100644
--- a/chrome/test/data/pdf/viewport_test.js
+++ b/chrome/test/data/pdf/viewport_test.js
@@ -451,6 +451,75 @@
     chrome.test.succeed();
   },
 
+  // Verifies that fitting computations work correctly for a fixed toolbar. In
+  // this case, the viewport should fit the document to the area below the
+  // toolbar, rather than the full window.
+  function testFitToPageFixedToolbar() {
+    const mockWindow = new MockWindow(100, 100);
+    const mockSizer = new MockSizer();
+    const mockCallback = new MockViewportChangedCallback();
+    const dummyContent =
+        /** @type {!HTMLDivElement} */ (document.createElement('div'));
+    document.body.appendChild(dummyContent);
+    const toolbarHeight = 10;
+    const viewport = new Viewport(
+        mockWindow, /** @type {!HTMLDivElement} */ (mockSizer), dummyContent, 0,
+        1, toolbarHeight, true);
+    viewport.setZoomFactorRange([0.25, 0.4, 0.5, 1, 2]);
+    viewport.setViewportChangedCallback(mockCallback.callback);
+    const documentDimensions = new MockDocumentDimensions();
+
+    function assertZoomed(expectedMockWidth, expectedMockHeight, expectedZoom) {
+      chrome.test.assertEq(FittingType.FIT_TO_PAGE, viewport.fittingType);
+      chrome.test.assertTrue(mockCallback.wasCalled);
+      chrome.test.assertEq(`${expectedMockWidth}px`, mockSizer.style.width);
+      chrome.test.assertEq(`${expectedMockHeight}px`, mockSizer.style.height);
+      chrome.test.assertEq(expectedZoom, viewport.getZoom());
+      // Should also make sure the viewport is correctly scrolled so that the
+      // entire page is visible, rather than covered by the toolbar.
+      chrome.test.assertEq(-1 * toolbarHeight, viewport.position.y);
+      chrome.test.assertEq(0, viewport.position.x);
+    }
+
+    function testForSize(
+        pageWidth, pageHeight, expectedMockWidth, expectedMockHeight,
+        expectedZoom) {
+      documentDimensions.reset();
+      documentDimensions.addPage(pageWidth, pageHeight);
+      viewport.setDocumentDimensions(documentDimensions);
+      viewport.setZoom(0.1);
+      mockCallback.reset();
+      viewport.fitToPage();
+      assertZoomed(expectedMockWidth, expectedMockHeight, expectedZoom);
+    }
+
+    // Note: Toolbar height is added to all expected heights below, as the sizer
+    // height includes the height of the toolbar.
+
+    // Page size which matches the window size.
+    testForSize(100, 100, 90, 90 + toolbarHeight, .9);
+
+    // Page size whose width is larger than its height.
+    testForSize(200, 100, 100, 50 + toolbarHeight, 0.5);
+
+    // Page size whose height is larger than its width.
+    testForSize(100, 200, 45, 90 + toolbarHeight, 0.45);
+
+    // Page size smaller than the window size in width but not height.
+    testForSize(50, 100, 45, 90 + toolbarHeight, .9);
+
+    // Page size smaller than the window size in height but not width.
+    testForSize(100, 50, 100, 50 + toolbarHeight, 1);
+
+    // Page size smaller than the window size in both width and height.
+    testForSize(25, 50, 45, 90 + toolbarHeight, 1.8);
+
+    // Page size smaller in one dimension and bigger in another.
+    testForSize(60, 200, 27, 90 + toolbarHeight, 0.45);
+
+    chrome.test.succeed();
+  },
+
   function testFitToHeight() {
     const mockWindow = new MockWindow(100, 100);
     const mockSizer = new MockSizer();
diff --git a/chrome/test/data/webui/downloads/item_tests.js b/chrome/test/data/webui/downloads/item_tests.js
index 5905958b..ecad62ea 100644
--- a/chrome/test/data/webui/downloads/item_tests.js
+++ b/chrome/test/data/webui/downloads/item_tests.js
@@ -85,4 +85,24 @@
     assertEquals(item.computeIcon_(), 'cr:warning');
     assertFalse(item.useFileIcon_);
   });
+
+  test('open now button controlled by load time data', async () => {
+    loadTimeData.overrideValues({'allowOpenNow': true});
+    item.set('data', createDownload({
+               filePath: 'unique1',
+               hideDate: false,
+               state: States.ASYNC_SCANNING,
+             }));
+    flush();
+    assertNotEquals(item.$$('#openNow'), null);
+
+    loadTimeData.overrideValues({'allowOpenNow': false});
+    item.set('data', createDownload({
+               filePath: 'unique1',
+               hideDate: false,
+               state: States.ASYNC_SCANNING,
+             }));
+    flush();
+    assertEquals(item.$$('#openNow'), null);
+  });
 });
diff --git a/chrome/test/data/webui/settings/chromeos/os_reset_page_test.js b/chrome/test/data/webui/settings/chromeos/os_reset_page_test.js
index 2d15c1a..47db94f 100644
--- a/chrome/test/data/webui/settings/chromeos/os_reset_page_test.js
+++ b/chrome/test/data/webui/settings/chromeos/os_reset_page_test.js
@@ -2,17 +2,23 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// clang-format off
 // #import {TestLifetimeBrowserProxy} from './test_os_lifetime_browser_proxy.m.js';
 // #import {LifetimeBrowserProxy, LifetimeBrowserProxyImpl, OsResetBrowserProxyImpl} from 'chrome://os-settings/chromeos/os_settings.js';
 // #import {TestOsResetBrowserProxy} from './test_os_reset_browser_proxy.m.js';
 // #import {assertEquals, assertFalse, assertNotEquals, assertTrue} from '../../chai_assert.js';
 // #import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+// #import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
+// clang-format on
 
 cr.define('settings_reset_page', function() {
   /** @enum {string} */
   const TestNames = {
     PowerwashDialogAction: 'PowerwashDialogAction',
     PowerwashDialogOpenClose: 'PowerwashDialogOpenClose',
+    PowerwashFocusDeepLink: 'PowerwashFocusDeepLink',
+    PowerwashFocusDeepLinkNoFlag: 'PowerwashFocusDeepLinkNoFlag',
+    PowerwashFocusDeepLinkWrongId: 'PowerwashFocusDeepLinkWrongId',
   };
 
   suite('DialogTests', function() {
@@ -38,6 +44,7 @@
     });
 
     teardown(function() {
+      settings.Router.getInstance().resetRouteForTesting();
       resetPage.remove();
     });
 
@@ -69,6 +76,23 @@
       ]);
     }
 
+    /**
+     * Navigates to the deep link provided by |settingId| and returns true if
+     * the focused element is |deepLinkElement|.
+     * @param {!Element} deepLinkElement
+     * @param {!string} settingId
+     * @returns {!boolean}
+     */
+    async function isDeepLinkFocusedForSettingId(deepLinkElement, settingId) {
+      const params = new URLSearchParams;
+      params.append('settingId', settingId);
+      settings.Router.getInstance().navigateTo(
+          settings.routes.OS_RESET, params);
+
+      await test_util.waitAfterNextRender(deepLinkElement);
+      return deepLinkElement === getDeepActiveElement();
+    }
+
     // Tests that the powerwash dialog opens and closes correctly, and
     // that chrome.send calls are propagated as expected.
     test(TestNames.PowerwashDialogOpenClose, function() {
@@ -91,6 +115,36 @@
           await lifetimeBrowserProxy.whenCalled('factoryReset');
       assertFalse(requestTpmFirmwareUpdate);
     });
+
+    // Tests that when the route changes to one containing a deep link to
+    // powerwash, powerwash is focused.
+    test(TestNames.PowerwashFocusDeepLink, async () => {
+      loadTimeData.overrideValues({isDeepLinkingEnabled: true});
+      assertTrue(loadTimeData.getBoolean('isDeepLinkingEnabled'));
+      assertTrue(
+          await isDeepLinkFocusedForSettingId(resetPage.$.powerwash, '1600'),
+          'Powerwash should be focused for settingId=1600.');
+    });
+
+    // Tests that when the deep linking flag is disabled, no focusing of deep
+    // links occurs.
+    test(TestNames.PowerwashFocusDeepLinkNoFlag, async () => {
+      loadTimeData.overrideValues({isDeepLinkingEnabled: false});
+      assertFalse(loadTimeData.getBoolean('isDeepLinkingEnabled'));
+      assertFalse(
+          await isDeepLinkFocusedForSettingId(resetPage.$.powerwash, '1600'),
+          'Powerwash should not be focused with flag disabled.');
+    });
+
+    // Tests that when the route changes to one containing a deep link not equal
+    // to powerwash, no focusing of powerwash occurs.
+    test(TestNames.PowerwashFocusDeepLinkWrongId, async () => {
+      loadTimeData.overrideValues({isDeepLinkingEnabled: true});
+      assertTrue(loadTimeData.getBoolean('isDeepLinkingEnabled'));
+      assertFalse(
+          await isDeepLinkFocusedForSettingId(resetPage.$.powerwash, '1234'),
+          'Powerwash should not be focused for settingId=1234.');
+    });
   });
 
   // #cr_define_end
diff --git a/chrome/test/data/xr/ar_playback_datasets/floor_session_12s_30fps.mp4.sha1 b/chrome/test/data/xr/ar_playback_datasets/floor_session_12s_30fps.mp4.sha1
new file mode 100644
index 0000000..e533580a
--- /dev/null
+++ b/chrome/test/data/xr/ar_playback_datasets/floor_session_12s_30fps.mp4.sha1
@@ -0,0 +1 @@
+ab81c1c2be25a6022f99de47affee40ae0c51ff1
\ No newline at end of file
diff --git a/chrome/updater/mac/net/network_fetcher.mm b/chrome/updater/mac/net/network_fetcher.mm
index eed7b9f2..c1a0f64 100644
--- a/chrome/updater/mac/net/network_fetcher.mm
+++ b/chrome/updater/mac/net/network_fetcher.mm
@@ -95,6 +95,7 @@
           initWithResponseStartedCallback:std::move(responseStartedCallback)
                          progressCallback:progressCallback]) {
     _postRequestCompleteCallback = std::move(postRequestCompleteCallback);
+    _downloadedData.reset([[NSMutableData alloc] init]);
   }
   return self;
 }
@@ -104,9 +105,6 @@
 - (void)URLSession:(NSURLSession*)session
           dataTask:(NSURLSessionDataTask*)dataTask
     didReceiveData:(NSData*)data {
-  if (_downloadedData == nil) {
-    _downloadedData.reset([[NSMutableData alloc] init]);
-  }
   [_downloadedData appendData:data];
 
   int64_t current = 0;
@@ -169,18 +167,15 @@
     retryAfterResult = [xRetryAfter intValue];
   }
 
-  NSString* dataToUse =
-      _downloadedData ? [[NSString alloc] initWithData:_downloadedData
-                                              encoding:NSUTF8StringEncoding]
-                      : response.description;
-
   _callbackRunner->PostTask(
       FROM_HERE,
-      base::BindOnce(
-          std::move(_postRequestCompleteCallback),
-          std::make_unique<std::string>(base::SysNSStringToUTF8(dataToUse)),
-          error.code, base::SysNSStringToUTF8(etag),
-          base::SysNSStringToUTF8(cupServerProof), retryAfterResult));
+      base::BindOnce(std::move(_postRequestCompleteCallback),
+                     std::make_unique<std::string>(
+                         reinterpret_cast<const char*>([_downloadedData bytes]),
+                         [_downloadedData length]),
+                     error.code, base::SysNSStringToUTF8(etag),
+                     base::SysNSStringToUTF8(cupServerProof),
+                     retryAfterResult));
 }
 
 @end
@@ -303,10 +298,18 @@
   base::scoped_nsobject<NSMutableURLRequest> urlRequest(
       [[NSMutableURLRequest alloc] initWithURL:net::NSURLWithGURL(url)]);
   [urlRequest setHTTPMethod:@"POST"];
-  [urlRequest setHTTPBody:[base::SysUTF8ToNSString(post_data)
-                              dataUsingEncoding:NSUTF8StringEncoding]];
+  base::scoped_nsobject<NSData> body(
+      [[NSData alloc] initWithBytes:post_data.c_str() length:post_data.size()]);
+  [urlRequest setHTTPBody:body];
   [urlRequest addValue:base::SysUTF8ToNSString(content_type)
       forHTTPHeaderField:@"Content-Type"];
+
+  // Post additional headers could overwrite existing headers with the same key,
+  // such as "Content-Type" above.
+  for (const auto& header : post_additional_headers) {
+    [urlRequest setValue:base::SysUTF8ToNSString(header.second)
+        forHTTPHeaderField:base::SysUTF8ToNSString(header.first)];
+  }
   VLOG(1) << "Posting data: " << post_data.c_str();
 
   NSURLSessionDataTask* dataTask = [session dataTaskWithRequest:urlRequest];
diff --git a/chrome/updater/mac/net/network_unittest.mm b/chrome/updater/mac/net/network_unittest.mm
index dac0d05..c125cee 100644
--- a/chrome/updater/mac/net/network_unittest.mm
+++ b/chrome/updater/mac/net/network_unittest.mm
@@ -48,11 +48,13 @@
     EXPECT_LE(current, 100);
   }
 
-  void PostRequestCompleteCallback(std::unique_ptr<std::string> response_body,
+  void PostRequestCompleteCallback(const std::string& expected_body,
+                                   std::unique_ptr<std::string> response_body,
                                    int net_error,
                                    const std::string& header_etag,
                                    const std::string& header_x_cup_server_proof,
                                    int64_t xheader_retry_after_sec) {
+    EXPECT_STREQ(response_body->c_str(), expected_body.c_str());
     EXPECT_EQ(net_error, 0);
     EXPECT_STREQ(header_etag.c_str(), "Wfhw789h");
     EXPECT_STREQ(header_x_cup_server_proof.c_str(), "server-proof");
@@ -73,8 +75,15 @@
     auto http_response =
         std::make_unique<net::test_server::BasicHttpResponse>();
     http_response->set_code(net::HTTP_OK);
-    http_response->set_content("hello");
-    http_response->set_content_type("text/plain");
+
+    if (request.content.size() > 0) {
+      // Echo the posted data back if there's any.
+      http_response->set_content(request.content);
+    } else {
+      http_response->set_content("hello");
+    }
+    http_response->set_content_type("application/octet-stream");
+
     http_response->AddCustomHeader("X-Retry-After", "67");
     http_response->AddCustomHeader("ETag", "Wfhw789h");
     http_response->AddCustomHeader("X-Cup-Server-Proof", "server-proof");
@@ -110,14 +119,16 @@
   ASSERT_TRUE(test_server.Start());
   const GURL url = test_server.GetURL("/echo");
 
+  constexpr char kPostData[] = {0x01, 0x00, 0x55, 0x33, 0xda, 0x10, 0x44};
+  const std::string post_data(kPostData, sizeof(kPostData));
   fetcher->PostRequest(
-      url, {}, {}, {},
+      url, post_data, {}, {},
       base::BindOnce(&ChromeUpdaterNetworkMacTest::StartedCallback,
                      base::Unretained(this)),
       base::BindRepeating(&ChromeUpdaterNetworkMacTest::ProgressCallback,
                           base::Unretained(this)),
       base::BindOnce(&ChromeUpdaterNetworkMacTest::PostRequestCompleteCallback,
-                     base::Unretained(this)));
+                     base::Unretained(this), post_data));
 
   run_loop.Run();
 }
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn
index a0e138e4..5393065 100644
--- a/chromeos/BUILD.gn
+++ b/chromeos/BUILD.gn
@@ -341,14 +341,15 @@
   deps = [ ":chromeos" ]
 }
 
-fuzzer_test("printer_configuration_fuzzer") {
-  sources = [ "printing/printer_configuration_fuzzer.cc" ]
-  seed_corpus = "printing/uri_fuzzer_seed_corpus"
-  deps = [
-    ":chromeos",
-    "//base",
-  ]
-}
+# Commented out due to crbug.com/1106355
+# fuzzer_test("printer_configuration_fuzzer") {
+#   sources = [ "printing/printer_configuration_fuzzer.cc" ]
+#   seed_corpus = "printing/uri_fuzzer_seed_corpus"
+#   deps = [
+#     ":chromeos",
+#     "//base",
+#   ]
+# }
 
 fuzzer_test("uri_fuzzer") {
   sources = [ "printing/uri_fuzzer.cc" ]
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd
index 025800a..03f6c19a 100644
--- a/chromeos/chromeos_strings.grd
+++ b/chromeos/chromeos_strings.grd
@@ -339,6 +339,9 @@
       <message name="IDS_PRINT_MANAGEMENT_TITLE" desc="The title of the print management app.">
         Print jobs
       </message>
+      <message name="IDS_PRINT_MANAGEMENT_APP_NAME" desc="The app name of the print management app.">
+        Print Jobs
+      </message>
       <message name="IDS_PRINT_MANAGEMENT_CLEAR_ALL_HISTORY_BUTTON_TEXT" desc="The label for the button that clears the print job history.">
         Clear all history
       </message>
diff --git a/chromeos/chromeos_strings_grd/IDS_PRINT_MANAGEMENT_APP_NAME.png.sha1 b/chromeos/chromeos_strings_grd/IDS_PRINT_MANAGEMENT_APP_NAME.png.sha1
new file mode 100644
index 0000000..edc51a1
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_PRINT_MANAGEMENT_APP_NAME.png.sha1
@@ -0,0 +1 @@
+f62f08e78643f5865a9093e03383088d9715fa91
\ No newline at end of file
diff --git a/chromeos/components/print_management/BUILD.gn b/chromeos/components/print_management/BUILD.gn
index bd7f136..5097203 100644
--- a/chromeos/components/print_management/BUILD.gn
+++ b/chromeos/components/print_management/BUILD.gn
@@ -14,6 +14,7 @@
 
   deps = [
     "//chromeos/components/print_management/mojom",
+    "//chromeos/components/web_applications",
     "//chromeos/constants",
     "//chromeos/resources:print_management_resources",
     "//chromeos/strings/",
diff --git a/chromeos/components/print_management/print_management_ui.cc b/chromeos/components/print_management/print_management_ui.cc
index 9278836..31f5bcb 100644
--- a/chromeos/components/print_management/print_management_ui.cc
+++ b/chromeos/components/print_management/print_management_ui.cc
@@ -8,6 +8,7 @@
 #include "base/memory/ptr_util.h"
 #include "chromeos/components/print_management/mojom/printing_manager.mojom.h"
 #include "chromeos/components/print_management/url_constants.h"
+#include "chromeos/components/web_applications/manifest_request_filter.h"
 #include "chromeos/constants/chromeos_features.h"
 #include "chromeos/grit/chromeos_print_management_resources.h"
 #include "chromeos/grit/chromeos_print_management_resources_map.h"
@@ -115,6 +116,9 @@
                                IDR_PRINTING_MANAGER_MOJO_LITE_JS);
 
   AddPrintManagementStrings(html_source.get());
+  web_app::SetManifestRequestFilter(html_source.get(),
+                                    IDR_PRINT_MANAGEMENT_MANIFEST,
+                                    IDS_PRINT_MANAGEMENT_APP_NAME);
 
   if (base::FeatureList::IsEnabled(chromeos::features::kScanningUI)) {
     html_source->AddResourcePath("scanning_page.js", IDR_SCANNING_PAGE_JS);
diff --git a/chromeos/components/print_management/resources/index.html b/chromeos/components/print_management/resources/index.html
index c30bdef..0ed2a9b 100644
--- a/chromeos/components/print_management/resources/index.html
+++ b/chromeos/components/print_management/resources/index.html
@@ -5,7 +5,7 @@
 <html>
   <head>
     <meta charset="utf-8">
-    <title>Print Jobs</title>
+    <title>$i18n{printJobTitle}</title>
     <style>
       html {
         background-color: var(--cros-bg-color);
diff --git a/chromeos/components/print_management/resources/manifest.json b/chromeos/components/print_management/resources/manifest.json
index 2ac48cd..9f377f8 100644
--- a/chromeos/components/print_management/resources/manifest.json
+++ b/chromeos/components/print_management/resources/manifest.json
@@ -1,6 +1,6 @@
 {
-    "name": "Print Management App",
-    "short_name": "Print Management",
+    "name": "$i18nRaw{name}",
+    "short_name": "$i18nRaw{name}",
     "start_url": "/",
     "display": "standalone",
     "theme_color": "#ffffff",
diff --git a/chromeos/components/print_management/resources/print_job_entry.html b/chromeos/components/print_management/resources/print_job_entry.html
index 03c7214..a8c5e9b6 100644
--- a/chromeos/components/print_management/resources/print_job_entry.html
+++ b/chromeos/components/print_management/resources/print_job_entry.html
@@ -34,7 +34,6 @@
 
   #fileIcon {
     margin-inline-end: 16px;
-    margin-inline-start: 12px;
     min-width: 22px;
   }
 
diff --git a/chromeos/components/print_management/resources/print_management_shared_css.html b/chromeos/components/print_management/resources/print_management_shared_css.html
index e8ba704..dfd09391a 100644
--- a/chromeos/components/print_management/resources/print_management_shared_css.html
+++ b/chromeos/components/print_management/resources/print_management_shared_css.html
@@ -25,7 +25,7 @@
       }
 
       .file-name-column {
-        width: 176px;
+        width: 184px;
       }
 
       .file-name-header-column {
@@ -55,7 +55,7 @@
       }
 
       .file-name-column {
-        width: 216px;
+        width: 224px;
       }
 
       .file-name-header-column {
@@ -85,7 +85,7 @@
       }
 
       .file-name-column {
-        width: 272px;
+        width: 280px;
       }
 
       .file-name-header-column {
@@ -115,7 +115,7 @@
       }
 
       .file-name-column {
-        width: 308px;
+        width: 316px;
       }
 
       .file-name-header-column {
diff --git a/chromeos/profiles/airmont.afdo.newest.txt b/chromeos/profiles/airmont.afdo.newest.txt
index 766512b4..cfbb9f48 100644
--- a/chromeos/profiles/airmont.afdo.newest.txt
+++ b/chromeos/profiles/airmont.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-airmont-86-4181.3-1594633354-benchmark-86.0.4203.0-r1-redacted.afdo.xz
+chromeos-chrome-amd64-airmont-86-4181.3-1594633354-benchmark-86.0.4204.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/broadwell.afdo.newest.txt b/chromeos/profiles/broadwell.afdo.newest.txt
index 7a9d7ef3..65ffb42c 100644
--- a/chromeos/profiles/broadwell.afdo.newest.txt
+++ b/chromeos/profiles/broadwell.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-broadwell-86-4181.3-1594633791-benchmark-86.0.4203.0-r1-redacted.afdo.xz
+chromeos-chrome-amd64-broadwell-86-4181.3-1594633791-benchmark-86.0.4204.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/silvermont.afdo.newest.txt b/chromeos/profiles/silvermont.afdo.newest.txt
index 0746fc5..6c32889 100644
--- a/chromeos/profiles/silvermont.afdo.newest.txt
+++ b/chromeos/profiles/silvermont.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-silvermont-86-4181.3-1594638142-benchmark-86.0.4203.0-r1-redacted.afdo.xz
+chromeos-chrome-amd64-silvermont-86-4181.3-1594638142-benchmark-86.0.4204.0-r1-redacted.afdo.xz
diff --git a/components/browser_ui/styles/android/java/res/color/default_icon_color_light_tint_list.xml b/components/browser_ui/styles/android/java/res/color/default_icon_color_light_tint_list.xml
index 545e91c..8539624b 100644
--- a/components/browser_ui/styles/android/java/res/color/default_icon_color_light_tint_list.xml
+++ b/components/browser_ui/styles/android/java/res/color/default_icon_color_light_tint_list.xml
@@ -4,10 +4,7 @@
      found in the LICENSE file.
 -->
 
-<!-- TODO(crbug.com/1017190): Remove the UnusedResources workaround. -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-          xmlns:tools="http://schemas.android.com/tools"
-          tools:ignore="UnusedResources">
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:alpha="@dimen/default_disabled_alpha"
           android:state_enabled="false" android:color="@color/default_icon_color_light" />
     <item android:state_selected="true" android:color="@color/default_icon_color_light" />
diff --git a/components/browser_ui/styles/android/java/res/color/default_icon_color_tint_list.xml b/components/browser_ui/styles/android/java/res/color/default_icon_color_tint_list.xml
index 6a40143..802dd21 100644
--- a/components/browser_ui/styles/android/java/res/color/default_icon_color_tint_list.xml
+++ b/components/browser_ui/styles/android/java/res/color/default_icon_color_tint_list.xml
@@ -4,10 +4,7 @@
      found in the LICENSE file.
 -->
 
-<!-- TODO(crbug.com/1017190): Remove the UnusedResources workaround. -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-          xmlns:tools="http://schemas.android.com/tools"
-          tools:ignore="UnusedResources">
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:alpha="@dimen/default_disabled_alpha"
           android:state_enabled="false" android:color="@color/default_icon_color" />
     <item android:state_selected="true" android:color="@color/default_icon_color" />
diff --git a/components/browser_ui/styles/android/java/res/values/colors.xml b/components/browser_ui/styles/android/java/res/values/colors.xml
index f6a7a5ea..edb99bb 100644
--- a/components/browser_ui/styles/android/java/res/values/colors.xml
+++ b/components/browser_ui/styles/android/java/res/values/colors.xml
@@ -3,8 +3,7 @@
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file. -->
 
-<!-- TODO(crbug.com/1017190): Remove the UnusedResources workaround. -->
-<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="UnusedResources">
+<resources xmlns:tools="http://schemas.android.com/tools">
     <!-- Text colors -->
     <color name="default_primary_color">#F2F2F2</color>
     <color name="input_underline_error_color">#D32F2F</color>
diff --git a/components/browser_ui/styles/android/java/res/values/dimens.xml b/components/browser_ui/styles/android/java/res/values/dimens.xml
index 856bf31..95462044b 100644
--- a/components/browser_ui/styles/android/java/res/values/dimens.xml
+++ b/components/browser_ui/styles/android/java/res/values/dimens.xml
@@ -3,8 +3,7 @@
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file. -->
 
-<!-- TODO(crbug.com/1017190): Remove the UnusedResources workaround. -->
-<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="UnusedResources">
+<resources>
     <!-- Standard width for overflow menu in Chrome. -->
     <dimen name="menu_width">258dp</dimen>
 
diff --git a/components/browser_ui/styles/android/java/res/values/styles.xml b/components/browser_ui/styles/android/java/res/values/styles.xml
index bceb1e0..cd0136ae 100644
--- a/components/browser_ui/styles/android/java/res/values/styles.xml
+++ b/components/browser_ui/styles/android/java/res/values/styles.xml
@@ -3,8 +3,7 @@
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file. -->
 
-<!-- TODO(crbug.com/1017190): Remove the UnusedResources workaround. -->
-<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="UnusedResources">
+<resources xmlns:tools="http://schemas.android.com/tools">
     <!-- Theme shared between Chrome and embedders. -->
     <style name="Theme.BrowserUI" parent="Theme.AppCompat.DayNight.NoActionBar">
         <!-- Text colors -->
diff --git a/components/browser_ui/widget/android/java/res/layout/more_progress_button.xml b/components/browser_ui/widget/android/java/res/layout/more_progress_button.xml
index 39831f5b..18582bfa8 100644
--- a/components/browser_ui/widget/android/java/res/layout/more_progress_button.xml
+++ b/components/browser_ui/widget/android/java/res/layout/more_progress_button.xml
@@ -3,15 +3,12 @@
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file. -->
 
-
 <org.chromium.components.browser_ui.widget.MoreProgressButton
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:focusable="false"
-    tools:ignore="UnusedResources">
-    <!-- TODO(wenyufu): to remove once linting strategy is updated (https://crbug.com/1017190) -->
+    android:focusable="false">
     <org.chromium.ui.widget.ButtonCompat
         style="@style/ListActionButton"
         android:id="@+id/action_button"
diff --git a/components/browser_ui/widget/android/java/res/values/styles.xml b/components/browser_ui/widget/android/java/res/values/styles.xml
index d6895d0..2ce775d 100644
--- a/components/browser_ui/widget/android/java/res/values/styles.xml
+++ b/components/browser_ui/widget/android/java/res/values/styles.xml
@@ -3,13 +3,12 @@
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file. -->
 
-<resources xmlns:tools="http://schemas.android.com/tools">
+<resources>
     <!-- Card styles -->
     <style name="Card">
         <item name="android:background">@drawable/hairline_border_card_background</item>
     </style>
-    <!-- TODO(crbug.com/1017190): Remove the UnusedResources workaround. -->
-    <style name="CardTransparentForDark" tools:ignore="UnusedResources">
+    <style name="CardTransparentForDark">
         <item name="android:background">@drawable/hairline_border_card_dark_transparent_bg</item>
     </style>
 
diff --git a/components/captive_portal/content/captive_portal_service.cc b/components/captive_portal/content/captive_portal_service.cc
index 93f988fa..1acd9d8 100644
--- a/components/captive_portal/content/captive_portal_service.cc
+++ b/components/captive_portal/content/captive_portal_service.cc
@@ -142,8 +142,8 @@
   // created before the call to UpdateEnabledState.
   resolve_errors_with_web_service_.Init(
       embedder_support::kAlternateErrorPagesEnabled, pref_service,
-      base::Bind(&CaptivePortalService::UpdateEnabledState,
-                 base::Unretained(this)));
+      base::BindRepeating(&CaptivePortalService::UpdateEnabledState,
+                          base::Unretained(this)));
   ResetBackoffEntry(last_detection_result_);
 
   UpdateEnabledState();
diff --git a/components/captive_portal/content/captive_portal_service_unittest.cc b/components/captive_portal/content/captive_portal_service_unittest.cc
index 64e307b..30bf310 100644
--- a/components/captive_portal/content/captive_portal_service_unittest.cc
+++ b/components/captive_portal/content/captive_portal_service_unittest.cc
@@ -33,8 +33,8 @@
         num_results_received_(0),
         captive_portal_service_(captive_portal_service),
         subscription_(captive_portal_service->RegisterCallback(
-            base::Bind(&CaptivePortalObserver::Observe,
-                       base::Unretained(this)))) {}
+            base::BindRepeating(&CaptivePortalObserver::Observe,
+                                base::Unretained(this)))) {}
 
   CaptivePortalResult captive_portal_result() const {
     return captive_portal_result_;
diff --git a/components/captive_portal/content/captive_portal_tab_helper.cc b/components/captive_portal/content/captive_portal_tab_helper.cc
index 9d21cf3..8a0a0fa 100644
--- a/components/captive_portal/content/captive_portal_tab_helper.cc
+++ b/components/captive_portal/content/captive_portal_tab_helper.cc
@@ -47,8 +47,8 @@
       login_detector_(new CaptivePortalLoginDetector(captive_portal_service)),
       is_captive_portal_window_(false),
       subscription_(captive_portal_service->RegisterCallback(
-          base::Bind(&CaptivePortalTabHelper::Observe,
-                     base::Unretained(this)))) {
+          base::BindRepeating(&CaptivePortalTabHelper::Observe,
+                              base::Unretained(this)))) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 }
 
diff --git a/components/captive_portal/content/captive_portal_tab_helper_unittest.cc b/components/captive_portal/content/captive_portal_tab_helper_unittest.cc
index 1cf7d8d..4bca09a 100644
--- a/components/captive_portal/content/captive_portal_tab_helper_unittest.cc
+++ b/components/captive_portal/content/captive_portal_tab_helper_unittest.cc
@@ -44,7 +44,7 @@
 class MockCaptivePortalTabReloader : public CaptivePortalTabReloader {
  public:
   MockCaptivePortalTabReloader()
-      : CaptivePortalTabReloader(nullptr, nullptr, base::Callback<void()>()) {}
+      : CaptivePortalTabReloader(nullptr, nullptr, base::NullCallback()) {}
 
   MOCK_METHOD1(OnLoadStart, void(bool));
   MOCK_METHOD2(OnLoadCommitted, void(int, net::ResolveErrorInfo));
diff --git a/components/captive_portal/content/captive_portal_tab_reloader.h b/components/captive_portal/content/captive_portal_tab_reloader.h
index 76991cf..103b5487 100644
--- a/components/captive_portal/content/captive_portal_tab_reloader.h
+++ b/components/captive_portal/content/captive_portal_tab_reloader.h
@@ -71,7 +71,7 @@
   };
 
   // Function to open a login tab, if there isn't one already.
-  typedef base::Callback<void()> OpenLoginTabCallback;
+  using OpenLoginTabCallback = base::RepeatingCallback<void()>;
 
   // |captive_portal_service| and |web_contents| will only be dereferenced in
   // ReloadTab, MaybeOpenCaptivePortalLoginTab, and CheckForCaptivePortal, so
diff --git a/components/captive_portal/content/captive_portal_tab_reloader_unittest.cc b/components/captive_portal/content/captive_portal_tab_reloader_unittest.cc
index e36fc53..563e89b 100644
--- a/components/captive_portal/content/captive_portal_tab_reloader_unittest.cc
+++ b/components/captive_portal/content/captive_portal_tab_reloader_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "components/captive_portal/content/captive_portal_tab_reloader.h"
 
+#include "base/bind_helpers.h"
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
@@ -24,9 +25,7 @@
 class TestCaptivePortalTabReloader : public CaptivePortalTabReloader {
  public:
   explicit TestCaptivePortalTabReloader(content::WebContents* web_contents)
-      : CaptivePortalTabReloader(NULL,
-                                 web_contents,
-                                 base::Callback<void(void)>()) {}
+      : CaptivePortalTabReloader(nullptr, web_contents, base::NullCallback()) {}
 
   ~TestCaptivePortalTabReloader() override {}
 
diff --git a/components/cronet/tools/hide_symbols.py b/components/cronet/tools/hide_symbols.py
index 7140383e..5873cec 100755
--- a/components/cronet/tools/hide_symbols.py
+++ b/components/cronet/tools/hide_symbols.py
@@ -114,12 +114,25 @@
     options.output_lib,
     options.output_obj,
   ]
+
+  # When compiling for 64bit targets, the symbols in call_with_eh_frame.o are
+  # referenced in assembly and eventually stripped by the call to ld -r above,
+  # perhaps because the linker incorrectly assumes that those symbols are not
+  # used. Using -keep_private_externs fixes the compile issue, but breaks
+  # other parts of cronet. Instead, simply add a second .o file with the
+  # personality routine. Note that this issue was not caught by Chrome tests,
+  # it was only detected when apps tried to link the resulting .a file.
+  if options.current_cpu == 'x64' or options.current_cpu == 'arm64':
+    command += [ 'obj/base/base/call_with_eh_frame.o' ]
+
   subprocess.check_call(command)
 
   if options.use_custom_libcxx:
-    ret = os.system('xcrun nm -u "' + options.output_obj + '" | grep ___cxa_pure_virtual')
+    ret = os.system('xcrun nm -u "' + options.output_obj +
+                    '" | grep ___cxa_pure_virtual')
     if ret == 0:
-      print "ERROR: Found undefined libc++ symbols, is libc++ indcluded in dependencies?"
+      print "ERROR: Found undefined libc++ symbols, " + \
+          "is libc++ indcluded in dependencies?"
       exit(2)
 
 
diff --git a/components/favicon/core/BUILD.gn b/components/favicon/core/BUILD.gn
index 3b9c192e..63c64b9 100644
--- a/components/favicon/core/BUILD.gn
+++ b/components/favicon/core/BUILD.gn
@@ -15,8 +15,6 @@
     "favicon_handler.cc",
     "favicon_handler.h",
     "favicon_service.h",
-    "favicon_service_impl.cc",
-    "favicon_service_impl.h",
     "favicon_url.cc",
     "favicon_url.h",
     "favicon_util.cc",
@@ -35,7 +33,6 @@
     "//base",
     "//base:i18n",
     "//components/favicon_base",
-    "//components/history/core/browser",
     "//components/image_fetcher/core",
     "//components/keyed_service/core",
     "//net:net",
@@ -46,6 +43,25 @@
   ]
 }
 
+# This target contains the implementation of FaviconService backed by
+# the HistoryService.
+static_library("history_implementation") {
+  sources = [
+    "favicon_service_impl.cc",
+    "favicon_service_impl.h",
+  ]
+
+  deps = [
+    ":core",
+    "//base",
+    "//components/favicon_base",
+    "//components/history/core/browser",
+    "//skia",
+    "//ui/gfx",
+    "//url",
+  ]
+}
+
 source_set("unit_tests") {
   testonly = true
   sources = [
@@ -58,6 +74,7 @@
 
   deps = [
     ":core",
+    ":history_implementation",
     "//base",
     "//base/test:test_support",
     "//components/favicon/core/test:test_support",
diff --git a/components/favicon/core/large_icon_service.h b/components/favicon/core/large_icon_service.h
index f6a82b2..b5e6cf3 100644
--- a/components/favicon/core/large_icon_service.h
+++ b/components/favicon/core/large_icon_service.h
@@ -20,7 +20,8 @@
 
 namespace favicon {
 
-// The large icon service provides methods to access large icons.
+// The large icon service provides methods to access large icons. The actual
+// implementation of this uses Google's favicon service.
 class LargeIconService : public KeyedService {
  public:
   // Requests the best large icon for the page at |page_url|.
diff --git a/components/media_message_center/media_notification_view_impl.cc b/components/media_message_center/media_notification_view_impl.cc
index 7bae475..f571def 100644
--- a/components/media_message_center/media_notification_view_impl.cc
+++ b/components/media_message_center/media_notification_view_impl.cc
@@ -185,6 +185,20 @@
   button_row->SetPreferredSize(kMediaNotificationButtonRowSize);
   button_row_ = main_row_->AddChildView(std::move(button_row));
 
+  auto playback_button_container = std::make_unique<views::View>();
+  auto* playback_button_container_layout =
+      playback_button_container->SetLayoutManager(
+          std::make_unique<views::BoxLayout>(
+              views::BoxLayout::Orientation::kHorizontal, gfx::Insets(),
+              kMediaButtonRowSeparator));
+  playback_button_container_layout->set_cross_axis_alignment(
+      views::BoxLayout::CrossAxisAlignment::kCenter);
+  // Media playback controls should always be presented left-to-right,
+  // regardless of the local UI direction.
+  playback_button_container->SetMirrored(false);
+  playback_button_container_ =
+      button_row_->AddChildView(std::move(playback_button_container));
+
   CreateMediaButton(
       MediaSessionAction::kPreviousTrack,
       l10n_util::GetStringUTF16(
@@ -203,7 +217,9 @@
       IDS_MEDIA_MESSAGE_CENTER_MEDIA_NOTIFICATION_ACTION_PLAY));
   play_pause_button->SetToggledTooltipText(l10n_util::GetStringUTF16(
       IDS_MEDIA_MESSAGE_CENTER_MEDIA_NOTIFICATION_ACTION_PAUSE));
-  play_pause_button_ = button_row_->AddChildView(std::move(play_pause_button));
+  play_pause_button->EnableCanvasFlippingForRTLUI(false);
+  play_pause_button_ =
+      playback_button_container_->AddChildView(std::move(play_pause_button));
 
   CreateMediaButton(
       MediaSessionAction::kSeekForward,
@@ -244,6 +260,7 @@
       IDS_MEDIA_MESSAGE_CENTER_MEDIA_NOTIFICATION_ACTION_ENTER_PIP));
   picture_in_picture_button->SetToggledTooltipText(l10n_util::GetStringUTF16(
       IDS_MEDIA_MESSAGE_CENTER_MEDIA_NOTIFICATION_ACTION_EXIT_PIP));
+  picture_in_picture_button->EnableCanvasFlippingForRTLUI(false);
   picture_in_picture_button_ =
       button_row_->AddChildView(std::move(picture_in_picture_button));
 
@@ -321,7 +338,8 @@
     return;
   }
 
-  if (sender->parent() == button_row_) {
+  if (sender->parent() == button_row_ ||
+      sender->parent() == playback_button_container_) {
     if (item_) {
       item_->OnMediaSessionActionButtonPressed(GetActionFromButtonTag(*sender));
     }
@@ -474,10 +492,7 @@
       GetTopVisibleActions(enabled_actions_, ignored_actions,
                            GetMaxNumActions(IsActuallyExpanded()));
 
-  for (auto* view : button_row_->children()) {
-    if (view == pip_button_separator_view_)
-      continue;
-
+  for (auto* view : GetButtons()) {
     views::Button* action_button = views::Button::AsButton(view);
     bool should_show =
         base::Contains(visible_actions, GetActionFromButtonTag(*action_button));
@@ -560,7 +575,8 @@
   button->SetAccessibleName(accessible_name);
   button->SetTooltipText(accessible_name);
   button->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
-  button_row_->AddChildView(std::move(button));
+  button->EnableCanvasFlippingForRTLUI(false);
+  playback_button_container_->AddChildView(std::move(button));
 }
 
 MediaNotificationBackground*
@@ -634,18 +650,11 @@
       kMediaButtonIconSize, foreground, disabled_icon_color);
 
   // Update action buttons.
-  for (views::View* child : button_row_->children()) {
+  for (views::View* child : playback_button_container_->children()) {
     // Skip the play pause button since it is a special case.
     if (child == play_pause_button_)
       continue;
 
-    if (child == picture_in_picture_button_)
-      continue;
-
-    // Skip if the view is not an image button.
-    if (child->GetClassName() != views::ImageButton::kViewClassName)
-      continue;
-
     views::ImageButton* button = static_cast<views::ImageButton*>(child);
 
     views::SetImageFromVectorIconWithColor(
@@ -658,4 +667,20 @@
   container_->OnColorsChanged(foreground, background);
 }
 
+std::vector<views::View*> MediaNotificationViewImpl::GetButtons() {
+  auto buttons = button_row_->children();
+  buttons.insert(buttons.cbegin(),
+                 playback_button_container_->children().cbegin(),
+                 playback_button_container_->children().cend());
+  buttons.erase(
+      std::remove_if(buttons.begin(), buttons.end(),
+                     [](views::View* view) {
+                       return !(view->GetClassName() ==
+                                    views::ImageButton::kViewClassName ||
+                                view->GetClassName() ==
+                                    views::ToggleImageButton::kViewClassName);
+                     }),
+      buttons.end());
+  return buttons;
+}
 }  // namespace media_message_center
diff --git a/components/media_message_center/media_notification_view_impl.h b/components/media_message_center/media_notification_view_impl.h
index 6e34f77..0ebcf0f2 100644
--- a/components/media_message_center/media_notification_view_impl.h
+++ b/components/media_message_center/media_notification_view_impl.h
@@ -91,6 +91,12 @@
     return picture_in_picture_button_;
   }
 
+  const views::View* playback_button_container_for_testing() const {
+    return playback_button_container_;
+  }
+
+  std::vector<views::View*> get_buttons_for_testing() { return GetButtons(); }
+
   views::Button* GetHeaderRowForTesting() const;
   base::string16 GetSourceTitleForTesting() const;
 
@@ -114,6 +120,10 @@
 
   void UpdateForegroundColor();
 
+  // Returns the buttons contained in the button row and playback button
+  // container.
+  std::vector<views::View*> GetButtons();
+
   // Container that receives OnExpanded events.
   MediaNotificationContainer* const container_;
 
@@ -149,6 +159,7 @@
   // Container views directly attached to this view.
   message_center::NotificationHeaderView* header_row_ = nullptr;
   views::View* button_row_ = nullptr;
+  views::View* playback_button_container_ = nullptr;
   views::View* pip_button_separator_view_ = nullptr;
   views::ToggleImageButton* play_pause_button_ = nullptr;
   views::ToggleImageButton* picture_in_picture_button_ = nullptr;
diff --git a/components/media_message_center/media_notification_view_impl_unittest.cc b/components/media_message_center/media_notification_view_impl_unittest.cc
index dccf7db..6ffd7b0 100644
--- a/components/media_message_center/media_notification_view_impl_unittest.cc
+++ b/components/media_message_center/media_notification_view_impl_unittest.cc
@@ -62,12 +62,6 @@
 constexpr int kViewArtworkWidth = kViewWidth * 0.4;
 const gfx::Size kViewSize(kViewWidth, 400);
 
-// Checks if the view class name is used by a media button.
-bool IsMediaButtonType(const char* class_name) {
-  return class_name == views::ImageButton::kViewClassName ||
-         class_name == views::ToggleImageButton::kViewClassName;
-}
-
 class MockMediaNotificationController : public MediaNotificationController {
  public:
   MockMediaNotificationController() = default;
@@ -227,6 +221,10 @@
 
   views::View* button_row() const { return view()->button_row_; }
 
+  const views::View* playback_button_container() const {
+    return view()->playback_button_container_;
+  }
+
   views::View* title_artist_row() const { return view()->title_artist_row_; }
 
   views::Label* title_label() const { return view()->title_label_; }
@@ -234,14 +232,12 @@
   views::Label* artist_label() const { return view()->artist_label_; }
 
   views::Button* GetButtonForAction(MediaSessionAction action) const {
-    const auto& children = button_row()->children();
+    auto buttons = view()->get_buttons_for_testing();
     const auto i = std::find_if(
-        children.begin(), children.end(), [action](const views::View* v) {
-          return (IsMediaButtonType(v->GetClassName()) &&
-                  views::Button::AsButton(v)->tag() ==
-                      static_cast<int>(action));
+        buttons.begin(), buttons.end(), [action](const views::View* v) {
+          return views::Button::AsButton(v)->tag() == static_cast<int>(action);
         });
-    return (i == children.end()) ? nullptr : views::Button::AsButton(*i);
+    return (i == buttons.end()) ? nullptr : views::Button::AsButton(*i);
   }
 
   bool IsActionButtonVisible(MediaSessionAction action) const {
@@ -364,16 +360,14 @@
   EXPECT_GT(button_row()->width(), 0);
   EXPECT_GT(button_row()->height(), 0);
 
-  EXPECT_EQ(7u, button_row()->children().size());
+  auto buttons = view()->get_buttons_for_testing();
+  EXPECT_EQ(6u, buttons.size());
 
-  for (auto* child : button_row()->children()) {
-    if (!IsMediaButtonType(child->GetClassName()))
-      continue;
-
-    EXPECT_TRUE(child->GetVisible());
-    EXPECT_LT(kMediaButtonIconSize, child->width());
-    EXPECT_LT(kMediaButtonIconSize, child->height());
-    EXPECT_FALSE(views::Button::AsButton(child)->GetAccessibleName().empty());
+  for (auto* button : buttons) {
+    EXPECT_TRUE(button->GetVisible());
+    EXPECT_LT(kMediaButtonIconSize, button->width());
+    EXPECT_LT(kMediaButtonIconSize, button->height());
+    EXPECT_FALSE(views::Button::AsButton(button)->GetAccessibleName().empty());
   }
 
   EXPECT_TRUE(GetButtonForAction(MediaSessionAction::kPlay));
diff --git a/components/ntp_tiles/BUILD.gn b/components/ntp_tiles/BUILD.gn
index cd47631..6c9a0838a 100644
--- a/components/ntp_tiles/BUILD.gn
+++ b/components/ntp_tiles/BUILD.gn
@@ -89,6 +89,7 @@
     "//base/test:test_support",
     "//build:branding_buildflags",
     "//components/favicon/core",
+    "//components/favicon/core:history_implementation",
     "//components/favicon_base",
     "//components/history/core/test",
     "//components/image_fetcher/core",
diff --git a/components/omnibox/browser/omnibox_popup_model.cc b/components/omnibox/browser/omnibox_popup_model.cc
index b36a019..30045df 100644
--- a/components/omnibox/browser/omnibox_popup_model.cc
+++ b/components/omnibox/browser/omnibox_popup_model.cc
@@ -178,9 +178,9 @@
                                     base::string16(), keyword, is_keyword_hint,
                                     base::string16());
   } else if (old_selection.line != selection_.line ||
-             old_selection.state == FOCUSED_BUTTON_HEADER) {
+             old_selection.IsButtonFocused()) {
     // Otherwise, only update the edit model for line number changes, or
-    // when the old selection was a Header. Updating the edit model for every
+    // when the old selection was a button. Updating the edit model for every
     // state change breaks keyword mode.
     if (reset_to_default) {
       edit_model_->OnPopupDataChanged(
diff --git a/components/policy/core/common/BUILD.gn b/components/policy/core/common/BUILD.gn
index 458ce081e..17669ef 100644
--- a/components/policy/core/common/BUILD.gn
+++ b/components/policy/core/common/BUILD.gn
@@ -97,8 +97,6 @@
     "config_dir_policy_loader.h",
     "configuration_policy_provider.cc",
     "configuration_policy_provider.h",
-    "extension_policy_migrator.cc",
-    "extension_policy_migrator.h",
     "external_data_fetcher.cc",
     "external_data_fetcher.h",
     "external_data_manager.h",
@@ -106,6 +104,8 @@
     "features.h",
     "json_schema_constants.cc",
     "json_schema_constants.h",
+    "legacy_chrome_policy_migrator.cc",
+    "legacy_chrome_policy_migrator.h",
     "management/management_service.cc",
     "management/management_service.h",
     "management/platform_management_service.cc",
@@ -123,6 +123,8 @@
     "policy_map.h",
     "policy_merger.cc",
     "policy_merger.h",
+    "policy_migrator.cc",
+    "policy_migrator.h",
     "policy_namespace.cc",
     "policy_namespace.h",
     "policy_proto_decoders.cc",
@@ -178,6 +180,7 @@
     "//services/network/public/cpp",
     "//third_party/libxml:xml_writer",
     "//third_party/re2",
+    "//ui/base",
     "//url",
   ]
 
@@ -389,6 +392,7 @@
     "cloud/device_management_service_unittest.cc",
     "cloud/user_info_fetcher_unittest.cc",
     "generate_policy_source_unittest.cc",
+    "legacy_chrome_policy_migrator_unittest.cc",
     "management/management_service_unittest.cc",
     "plist_writer_unittest.cc",
     "policy_bundle_unittest.cc",
@@ -483,6 +487,7 @@
     "//testing/gmock",
     "//testing/gtest",
     "//third_party/libxml:xml_reader",
+    "//ui/base",
   ]
   if (is_chromeos) {
     deps += [ "//chromeos/system" ]
diff --git a/components/policy/core/common/DEPS b/components/policy/core/common/DEPS
index 0dd266da..0c358062 100644
--- a/components/policy/core/common/DEPS
+++ b/components/policy/core/common/DEPS
@@ -8,4 +8,5 @@
   "+net/traffic_annotation",
   "+services/network/test",
   "+third_party/libxml/chromium",
+  "+ui/base/l10n",
 ]
diff --git a/components/policy/core/common/configuration_policy_provider_test.cc b/components/policy/core/common/configuration_policy_provider_test.cc
index 961dcfc..0ac29db 100644
--- a/components/policy/core/common/configuration_policy_provider_test.cc
+++ b/components/policy/core/common/configuration_policy_provider_test.cc
@@ -13,11 +13,11 @@
 #include "base/task/thread_pool.h"
 #include "base/values.h"
 #include "components/policy/core/common/configuration_policy_provider.h"
-#include "components/policy/core/common/extension_policy_migrator.h"
 #include "components/policy/core/common/external_data_fetcher.h"
 #include "components/policy/core/common/mock_configuration_policy_provider.h"
 #include "components/policy/core/common/policy_bundle.h"
 #include "components/policy/core/common/policy_map.h"
+#include "components/policy/core/common/policy_migrator.h"
 #include "components/policy/core/common/policy_namespace.h"
 #include "components/policy/core/common/policy_types.h"
 #include "testing/gmock/include/gmock/gmock.h"
diff --git a/components/policy/core/common/extension_policy_migrator.cc b/components/policy/core/common/extension_policy_migrator.cc
deleted file mode 100644
index f847c86..0000000
--- a/components/policy/core/common/extension_policy_migrator.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/policy/core/common/extension_policy_migrator.h"
-
-#include <algorithm>
-#include <utility>
-
-#include "base/bind.h"
-
-namespace policy {
-
-namespace {
-
-void DoNothing(base::Value* val) {}
-
-}  // namespace
-
-ExtensionPolicyMigrator::Migration::Migration(Migration&&) = default;
-
-ExtensionPolicyMigrator::Migration::Migration(const char* old_name_,
-                                              const char* new_name_)
-    : Migration(old_name_, new_name_, base::BindRepeating(&DoNothing)) {}
-
-ExtensionPolicyMigrator::Migration::Migration(const char* old_name_,
-                                              const char* new_name_,
-                                              ValueTransform transform_)
-    : old_name(old_name_),
-      new_name(new_name_),
-      transform(std::move(transform_)) {}
-
-ExtensionPolicyMigrator::Migration::~Migration() = default;
-
-}  // namespace policy
diff --git a/components/policy/core/common/extension_policy_migrator.h b/components/policy/core/common/extension_policy_migrator.h
deleted file mode 100644
index e091cff..0000000
--- a/components/policy/core/common/extension_policy_migrator.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_POLICY_CORE_COMMON_EXTENSION_POLICY_MIGRATOR_H_
-#define COMPONENTS_POLICY_CORE_COMMON_EXTENSION_POLICY_MIGRATOR_H_
-
-#include <memory>
-
-#include "base/callback.h"
-#include "base/containers/span.h"
-#include "base/values.h"
-#include "components/policy/core/common/policy_bundle.h"
-#include "components/policy/policy_export.h"
-
-namespace policy {
-
-// A helper class that migrates a deprecated policy to a new policy across
-// domain boundaries, by setting up the new policy based on the old one. It can
-// migrate a deprecated extension policy to a new Chrome policy.
-//
-// For migrations that are only in the Chrome domain: you should use
-// |LegacyPoliciesDeprecatingPolicyHandler| instead.
-class POLICY_EXPORT ExtensionPolicyMigrator {
- public:
-  virtual ~ExtensionPolicyMigrator() {}
-
-  // If there are deprecated policies in |bundle|, set the value of the new
-  // policies accordingly.
-  virtual void Migrate(PolicyBundle* bundle) = 0;
-
-  // Indicates how to rename a policy when migrating from the extension domain
-  // to the Chrome domain.
-  struct POLICY_EXPORT Migration {
-    using ValueTransform = base::RepeatingCallback<void(base::Value*)>;
-
-    Migration(Migration&&);
-    Migration(const char* old_name_, const char* new_name_);
-    Migration(const char* old_name_,
-              const char* new_name_,
-              ValueTransform transform_);
-    ~Migration();
-
-    // Old name for the policy, in the extension domain.
-    const char* old_name;
-    // New name for the policy, in the Chrome domain.
-    const char* new_name;
-    // Function to use to convert values from the old namespace to the new
-    // namespace (e.g. convert value types). It should mutate the Value in
-    // place. By default, it does no transform.
-    ValueTransform transform;
-  };
-};
-
-}  // namespace policy
-
-#endif  // COMPONENTS_POLICY_CORE_COMMON_EXTENSION_POLICY_MIGRATOR_H_
diff --git a/components/policy/core/common/legacy_chrome_policy_migrator.cc b/components/policy/core/common/legacy_chrome_policy_migrator.cc
new file mode 100644
index 0000000..bf3a1f0
--- /dev/null
+++ b/components/policy/core/common/legacy_chrome_policy_migrator.cc
@@ -0,0 +1,34 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/policy/core/common/legacy_chrome_policy_migrator.h"
+
+#include <string>
+
+#include "components/policy/core/common/policy_bundle.h"
+#include "components/policy/core/common/policy_map.h"
+#include "components/policy/core/common/policy_namespace.h"
+
+namespace policy {
+
+LegacyChromePolicyMigrator::LegacyChromePolicyMigrator(const char* old_name,
+                                                       const char* new_name)
+    : migration_(old_name, new_name) {}
+
+LegacyChromePolicyMigrator::LegacyChromePolicyMigrator(
+    const char* old_name,
+    const char* new_name,
+    Migration::ValueTransform transform)
+    : migration_(old_name, new_name, transform) {}
+
+LegacyChromePolicyMigrator::~LegacyChromePolicyMigrator() = default;
+
+void LegacyChromePolicyMigrator::Migrate(policy::PolicyBundle* bundle) {
+  policy::PolicyMap& chrome_map =
+      bundle->Get(policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, ""));
+
+  CopyPolicyIfUnset(chrome_map, &chrome_map, migration_);
+}
+
+}  // namespace policy
diff --git a/components/policy/core/common/legacy_chrome_policy_migrator.h b/components/policy/core/common/legacy_chrome_policy_migrator.h
new file mode 100644
index 0000000..0012b646
--- /dev/null
+++ b/components/policy/core/common/legacy_chrome_policy_migrator.h
@@ -0,0 +1,40 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_POLICY_CORE_COMMON_LEGACY_CHROME_POLICY_MIGRATOR_H_
+#define COMPONENTS_POLICY_CORE_COMMON_LEGACY_CHROME_POLICY_MIGRATOR_H_
+
+#include "components/policy/core/common/policy_migrator.h"
+
+namespace policy {
+
+// LegacyChromePolicyMigrator migrates a deprecated Chrome domain policy to a
+// new name, setting up the new policy based on the old one.
+//
+// This is intended to be used for policies that do not have a corresponding
+// pref. If the policy has a pref, please use
+// |LegacyPoliciesDeprecatingPolicyHandler| instead.
+class POLICY_EXPORT LegacyChromePolicyMigrator : public PolicyMigrator {
+ public:
+  using Migration = PolicyMigrator::Migration;
+
+  LegacyChromePolicyMigrator(const char* old_name, const char* new_name);
+  LegacyChromePolicyMigrator(const char* old_name,
+                             const char* new_name,
+                             Migration::ValueTransform transform);
+  ~LegacyChromePolicyMigrator() override;
+
+  LegacyChromePolicyMigrator(const LegacyChromePolicyMigrator&) = delete;
+  LegacyChromePolicyMigrator& operator=(const LegacyChromePolicyMigrator&) =
+      delete;
+
+  void Migrate(policy::PolicyBundle* bundle) override;
+
+ private:
+  Migration migration_;
+};
+
+}  // namespace policy
+
+#endif  // COMPONENTS_POLICY_CORE_COMMON_LEGACY_CHROME_POLICY_MIGRATOR_H_
diff --git a/components/policy/core/common/legacy_chrome_policy_migrator_unittest.cc b/components/policy/core/common/legacy_chrome_policy_migrator_unittest.cc
new file mode 100644
index 0000000..2577ad0
--- /dev/null
+++ b/components/policy/core/common/legacy_chrome_policy_migrator_unittest.cc
@@ -0,0 +1,110 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/policy/core/common/legacy_chrome_policy_migrator.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace policy {
+
+namespace {
+const char kOldPolicy[] = "OldPolicy";
+const char kNewPolicy[] = "NewPolicy";
+const char kOtherPolicy[] = "OtherPolicy";
+
+const int kOldValue = 111;
+const int kNewValue = 222;
+const int kTransformedValue = 333;
+const int kOtherValue = 999;
+
+void MultiplyByThree(base::Value* val) {
+  *val = base::Value(val->GetInt() * 3);
+}
+
+void SetPolicy(PolicyMap* policy,
+               const char* policy_name,
+               std::unique_ptr<base::Value> value) {
+  policy->Set(policy_name, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+              POLICY_SOURCE_CLOUD, std::move(value), nullptr);
+}
+
+}  // namespace
+
+TEST(LegacyChromePolicyMigratorTest, CopyPolicyIfUnset) {
+  PolicyBundle bundle;
+
+  PolicyMap& chrome_map = bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, ""));
+
+  SetPolicy(&chrome_map, kOldPolicy, std::make_unique<base::Value>(kOldValue));
+  SetPolicy(&chrome_map, kOtherPolicy,
+            std::make_unique<base::Value>(kOtherValue));
+
+  LegacyChromePolicyMigrator migrator(kOldPolicy, kNewPolicy);
+
+  migrator.Migrate(&bundle);
+
+  // kOldPolicy should have been copied to kNewPolicy, kOtherPolicy remains
+  EXPECT_EQ(3u, chrome_map.size());
+  ASSERT_TRUE(chrome_map.GetValue(kNewPolicy));
+  // Old Value should be copied over.
+  EXPECT_EQ(base::Value(kOldValue), *chrome_map.GetValue(kNewPolicy));
+  // Other Value should be unchanged.
+  EXPECT_EQ(base::Value(kOtherValue), *chrome_map.GetValue(kOtherPolicy));
+  base::RepeatingCallback<base::string16(int)> l10nlookup =
+      base::BindRepeating(&l10n_util::GetStringUTF16);
+  // Old policy should always be marked deprecated
+  EXPECT_FALSE(
+      chrome_map.Get(kOldPolicy)->GetLocalizedErrors(l10nlookup).empty());
+  EXPECT_FALSE(
+      chrome_map.Get(kNewPolicy)->GetLocalizedErrors(l10nlookup).empty());
+}
+
+TEST(LegacyChromePolicyMigratorTest, TransformPolicy) {
+  PolicyBundle bundle;
+
+  PolicyMap& chrome_map = bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, ""));
+
+  SetPolicy(&chrome_map, kOldPolicy, std::make_unique<base::Value>(kOldValue));
+
+  LegacyChromePolicyMigrator migrator(kOldPolicy, kNewPolicy,
+                                      base::BindRepeating(&MultiplyByThree));
+
+  migrator.Migrate(&bundle);
+
+  ASSERT_TRUE(chrome_map.GetValue(kNewPolicy));
+  // Old Value should be transformed
+  EXPECT_EQ(base::Value(kTransformedValue), *chrome_map.GetValue(kNewPolicy));
+}
+
+TEST(LegacyChromePolicyMigratorTest, IgnoreOldIfNewIsSet) {
+  PolicyBundle bundle;
+
+  PolicyMap& chrome_map = bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, ""));
+
+  SetPolicy(&chrome_map, kOldPolicy, std::make_unique<base::Value>(kOldValue));
+  SetPolicy(&chrome_map, kNewPolicy, std::make_unique<base::Value>(kNewValue));
+
+  LegacyChromePolicyMigrator migrator(kOldPolicy, kNewPolicy);
+
+  migrator.Migrate(&bundle);
+  // New Value is unchanged
+  EXPECT_EQ(base::Value(kNewValue), *chrome_map.GetValue(kNewPolicy));
+  // Should be no warning on new policy
+  base::RepeatingCallback<base::string16(int)> l10nlookup =
+      base::BindRepeating(&l10n_util::GetStringUTF16);
+  // Old policy should always be marked deprecated
+  EXPECT_FALSE(
+      chrome_map.Get(kOldPolicy)->GetLocalizedErrors(l10nlookup).empty());
+  // No warnings on new policy because it was unchanged.
+  EXPECT_TRUE(
+      chrome_map.Get(kNewPolicy)->GetLocalizedErrors(l10nlookup).empty());
+}
+
+}  // namespace policy
diff --git a/components/policy/core/common/policy_migrator.cc b/components/policy/core/common/policy_migrator.cc
new file mode 100644
index 0000000..d4724fa
--- /dev/null
+++ b/components/policy/core/common/policy_migrator.cc
@@ -0,0 +1,64 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/policy/core/common/policy_migrator.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/strings/grit/components_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace policy {
+
+namespace {
+
+void DoNothing(base::Value* val) {}
+
+}  // namespace
+
+PolicyMigrator::~PolicyMigrator() = default;
+
+void PolicyMigrator::CopyPolicyIfUnset(PolicyMap& source,
+                                       PolicyMap* dest,
+                                       const Migration& migration) {
+  PolicyMap::Entry* entry = source.GetMutable(migration.old_name);
+  if (entry) {
+    if (!dest->Get(migration.new_name)) {
+      VLOG(3) << "Legacy policy '" << migration.old_name
+              << "' has been copied to '" << migration.new_name << "'.";
+      auto new_entry = entry->DeepCopy();
+      migration.transform.Run(new_entry.value());
+      new_entry.AddError(
+          l10n_util::GetStringFUTF8(IDS_POLICY_MIGRATED_NEW_POLICY,
+                                    base::UTF8ToUTF16(migration.old_name)));
+      dest->Set(migration.new_name, std::move(new_entry));
+    } else {
+      VLOG(3) << "Legacy policy '" << migration.old_name
+              << "' is ignored because '" << migration.new_name
+              << "' is also set. ";
+    }
+    entry->AddError(l10n_util::GetStringFUTF8(
+        IDS_POLICY_MIGRATED_OLD_POLICY, base::UTF8ToUTF16(migration.new_name)));
+  } else {
+    VLOG(3) << "Legacy policy '" << migration.old_name << "' is not set.";
+  }
+}
+
+PolicyMigrator::Migration::Migration(Migration&&) = default;
+
+PolicyMigrator::Migration::Migration(const char* old_name, const char* new_name)
+    : Migration(old_name, new_name, base::BindRepeating(&DoNothing)) {}
+
+PolicyMigrator::Migration::Migration(const char* old_name,
+                                     const char* new_name,
+                                     ValueTransform transform)
+    : old_name(old_name), new_name(new_name), transform(std::move(transform)) {}
+
+PolicyMigrator::Migration::~Migration() = default;
+
+}  // namespace policy
diff --git a/components/policy/core/common/policy_migrator.h b/components/policy/core/common/policy_migrator.h
new file mode 100644
index 0000000..3d34284
--- /dev/null
+++ b/components/policy/core/common/policy_migrator.h
@@ -0,0 +1,63 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_POLICY_CORE_COMMON_POLICY_MIGRATOR_H_
+#define COMPONENTS_POLICY_CORE_COMMON_POLICY_MIGRATOR_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/containers/span.h"
+#include "base/values.h"
+#include "components/policy/core/common/policy_bundle.h"
+#include "components/policy/core/common/policy_map.h"
+#include "components/policy/policy_export.h"
+
+namespace policy {
+
+// A helper class that migrates a deprecated policy to a new policy -
+// potentially across domain boundaries, by setting up the new policy based on
+// the old one. It can migrate a deprecated policy to a new policy.
+//
+// For migrations that are only in the Chrome domain and which are accessed via
+// prefs: you should use |LegacyPoliciesDeprecatingPolicyHandler| instead.
+class POLICY_EXPORT PolicyMigrator {
+ public:
+  virtual ~PolicyMigrator();
+
+  // If there are deprecated policies in |bundle|, set the value of the new
+  // policies accordingly.
+  virtual void Migrate(PolicyBundle* bundle) = 0;
+
+  // Indicates how to rename a policy when migrating the old policy to the new
+  // policy.
+  struct POLICY_EXPORT Migration {
+    using ValueTransform = base::RepeatingCallback<void(base::Value*)>;
+
+    Migration(Migration&&);
+    Migration(const char* old_name, const char* new_name);
+    Migration(const char* old_name,
+              const char* new_name,
+              ValueTransform transform);
+    ~Migration();
+
+    // Old name for the policy
+    const char* old_name;
+    // New name for the policy, in the Chrome domain.
+    const char* new_name;
+    // Function to use to convert values from the old policy to the new
+    // policy (e.g. convert value types). It should mutate the Value in
+    // place. By default, it does no transform.
+    ValueTransform transform;
+  };
+
+ protected:
+  static void CopyPolicyIfUnset(PolicyMap& source,
+                                PolicyMap* dest,
+                                const Migration& migration);
+};
+
+}  // namespace policy
+
+#endif  // COMPONENTS_POLICY_CORE_COMMON_POLICY_MIGRATOR_H_
diff --git a/components/policy/core/common/policy_service_impl.h b/components/policy/core/common/policy_service_impl.h
index b007cc6..6b3c017 100644
--- a/components/policy/core/common/policy_service_impl.h
+++ b/components/policy/core/common/policy_service_impl.h
@@ -17,8 +17,8 @@
 #include "base/observer_list.h"
 #include "base/threading/thread_checker.h"
 #include "components/policy/core/common/configuration_policy_provider.h"
-#include "components/policy/core/common/extension_policy_migrator.h"
 #include "components/policy/core/common/policy_bundle.h"
+#include "components/policy/core/common/policy_migrator.h"
 #include "components/policy/core/common/policy_service.h"
 #include "components/policy/policy_export.h"
 
@@ -31,14 +31,13 @@
       public ConfigurationPolicyProvider::Observer {
  public:
   using Providers = std::vector<ConfigurationPolicyProvider*>;
-  using Migrators = std::vector<std::unique_ptr<ExtensionPolicyMigrator>>;
+  using Migrators = std::vector<std::unique_ptr<PolicyMigrator>>;
 
   // Creates a new PolicyServiceImpl with the list of
   // ConfigurationPolicyProviders, in order of decreasing priority.
   explicit PolicyServiceImpl(
       Providers providers,
-      Migrators migrators =
-          std::vector<std::unique_ptr<ExtensionPolicyMigrator>>());
+      Migrators migrators = std::vector<std::unique_ptr<PolicyMigrator>>());
 
   // Creates a new PolicyServiceImpl with the list of
   // ConfigurationPolicyProviders, in order of decreasing priority.
@@ -47,8 +46,7 @@
   // |UnthrottleInitialization| has been called.
   static std::unique_ptr<PolicyServiceImpl> CreateWithThrottledInitialization(
       Providers providers,
-      Migrators migrators =
-          std::vector<std::unique_ptr<ExtensionPolicyMigrator>>());
+      Migrators migrators = std::vector<std::unique_ptr<PolicyMigrator>>());
 
   ~PolicyServiceImpl() override;
 
diff --git a/components/policy/core/common/policy_service_impl_unittest.cc b/components/policy/core/common/policy_service_impl_unittest.cc
index c386689..ebeb3e4 100644
--- a/components/policy/core/common/policy_service_impl_unittest.cc
+++ b/components/policy/core/common/policy_service_impl_unittest.cc
@@ -14,10 +14,10 @@
 #include "base/run_loop.h"
 #include "base/test/task_environment.h"
 #include "base/values.h"
-#include "components/policy/core/common/extension_policy_migrator.h"
 #include "components/policy/core/common/external_data_fetcher.h"
 #include "components/policy/core/common/mock_configuration_policy_provider.h"
 #include "components/policy/core/common/mock_policy_service.h"
+#include "components/policy/core/common/policy_migrator.h"
 #include "components/policy/core/common/policy_types.h"
 #include "components/policy/policy_constants.h"
 #include "components/strings/grit/components_strings.h"
@@ -96,7 +96,7 @@
   bool observer_invoked_;
 };
 
-class MockPolicyMigrator : public ExtensionPolicyMigrator {
+class MockPolicyMigrator : public PolicyMigrator {
  public:
   MOCK_METHOD1(Migrate, void(PolicyBundle* bundle));
 };
diff --git a/components/variations/field_trial_config/field_trial_util.cc b/components/variations/field_trial_config/field_trial_util.cc
index 71897b4..4dc7852 100644
--- a/components/variations/field_trial_config/field_trial_util.cc
+++ b/components/variations/field_trial_config/field_trial_util.cc
@@ -167,19 +167,14 @@
 
 }  // namespace
 
-std::string UnescapeValue(const std::string& value) {
-  return net::UnescapeURLComponent(
-      value, net::UnescapeRule::PATH_SEPARATORS |
-                 net::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS);
-}
-
 std::string EscapeValue(const std::string& value) {
-  // This needs to be the inverse of UnescapeValue in the anonymous namespace
-  // above.
+  // This needs to be the inverse of UnescapeValue in
+  // base/metrics/field_trial_params.
   std::string net_escaped_str =
       net::EscapeQueryParamValue(value, true /* use_plus */);
 
-  // net doesn't escape '.' and '*' but UnescapeValue() covers those cases.
+  // net doesn't escape '.' and '*' but base::UnescapeValue() covers those
+  // cases.
   std::string escaped_str;
   escaped_str.reserve(net_escaped_str.length());
   for (const char ch : net_escaped_str) {
@@ -195,7 +190,7 @@
 
 bool AssociateParamsFromString(const std::string& varations_string) {
   return base::AssociateFieldTrialParamsFromString(varations_string,
-                                                   &UnescapeValue);
+                                                   &base::UnescapeValue);
 }
 
 void AssociateParamsFromFieldTrialConfig(
diff --git a/components/variations/field_trial_config/field_trial_util_unittest.cc b/components/variations/field_trial_config/field_trial_util_unittest.cc
index 946e1dfc..4b788f9 100644
--- a/components/variations/field_trial_config/field_trial_util_unittest.cc
+++ b/components/variations/field_trial_config/field_trial_util_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/command_line.h"
 #include "base/macros.h"
 #include "base/metrics/field_trial.h"
+#include "base/metrics/field_trial_params.h"
 #include "base/optional.h"
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -903,6 +904,7 @@
   EXPECT_EQ(escaped_str.find(','), std::string::npos);
   EXPECT_EQ(escaped_str.find('*'), std::string::npos);
 
-  EXPECT_EQ(str, UnescapeValue(escaped_str));
+  // Make sure the EscapeValue function is the inverse of base::UnescapeValue.
+  EXPECT_EQ(str, base::UnescapeValue(escaped_str));
 }
 }  // namespace variations
diff --git a/components/variations/service/variations_field_trial_creator.cc b/components/variations/service/variations_field_trial_creator.cc
index f7768da..386b858 100644
--- a/components/variations/service/variations_field_trial_creator.cc
+++ b/components/variations/service/variations_field_trial_creator.cc
@@ -509,9 +509,9 @@
                                        switches::kForceDisableVariationIds));
   }
 
-  feature_list->InitializeFromCommandLineWithFeatureParams(
+  feature_list->InitializeFromCommandLine(
       command_line->GetSwitchValueASCII(kEnableFeatures),
-      command_line->GetSwitchValueASCII(kDisableFeatures), &UnescapeValue);
+      command_line->GetSwitchValueASCII(kDisableFeatures));
 
   // This needs to happen here: After the InitializeFromCommandLine() call,
   // because the explicit cmdline --disable-features and --enable-features
diff --git a/components/viz/common/BUILD.gn b/components/viz/common/BUILD.gn
index 72a679eb..53bc661 100644
--- a/components/viz/common/BUILD.gn
+++ b/components/viz/common/BUILD.gn
@@ -200,6 +200,8 @@
     "quads/largest_draw_quad.h",
     "quads/picture_draw_quad.cc",
     "quads/picture_draw_quad.h",
+    "quads/quad_list.cc",
+    "quads/quad_list.h",
     "quads/render_pass.cc",
     "quads/render_pass.h",
     "quads/render_pass_draw_quad.cc",
diff --git a/components/viz/common/quads/quad_list.cc b/components/viz/common/quads/quad_list.cc
new file mode 100644
index 0000000..d4c72dc
--- /dev/null
+++ b/components/viz/common/quads/quad_list.cc
@@ -0,0 +1,107 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/viz/common/quads/quad_list.h"
+
+#include "components/viz/common/quads/debug_border_draw_quad.h"
+#include "components/viz/common/quads/draw_quad.h"
+#include "components/viz/common/quads/largest_draw_quad.h"
+#include "components/viz/common/quads/picture_draw_quad.h"
+#include "components/viz/common/quads/render_pass_draw_quad.h"
+#include "components/viz/common/quads/shared_quad_state.h"
+#include "components/viz/common/quads/solid_color_draw_quad.h"
+#include "components/viz/common/quads/stream_video_draw_quad.h"
+#include "components/viz/common/quads/surface_draw_quad.h"
+#include "components/viz/common/quads/texture_draw_quad.h"
+#include "components/viz/common/quads/tile_draw_quad.h"
+#include "components/viz/common/quads/video_hole_draw_quad.h"
+#include "components/viz/common/quads/yuv_video_draw_quad.h"
+
+namespace {
+const size_t kDefaultNumQuadsToReserve = 128;
+}  // namespace
+
+namespace viz {
+
+QuadList::QuadList()
+    : ListContainer<DrawQuad>(LargestDrawQuadAlignment(),
+                              LargestDrawQuadSize(),
+                              kDefaultNumQuadsToReserve) {}
+
+QuadList::QuadList(size_t default_size_to_reserve)
+    : ListContainer<DrawQuad>(LargestDrawQuadAlignment(),
+                              LargestDrawQuadSize(),
+                              default_size_to_reserve) {}
+
+void QuadList::ReplaceExistingQuadWithOpaqueTransparentSolidColor(Iterator at) {
+  // In order to fill the backbuffer with transparent black, the replacement
+  // solid color quad needs to set |needs_blending| to false, and
+  // ShouldDrawWithBlending() returns false so it is drawn without blending.
+  const gfx::Rect rect = at->rect;
+  bool needs_blending = false;
+  const SharedQuadState* shared_quad_state = at->shared_quad_state;
+
+  auto* replacement = QuadList::ReplaceExistingElement<SolidColorDrawQuad>(at);
+  replacement->SetAll(shared_quad_state, rect, rect /* visible_rect */,
+                      needs_blending, SK_ColorTRANSPARENT, true);
+}
+
+QuadList::Iterator QuadList::InsertCopyBeforeDrawQuad(Iterator at,
+                                                      size_t count) {
+  DCHECK(at->shared_quad_state);
+  switch (at->material) {
+    case DrawQuad::Material::kDebugBorder: {
+      const auto copy = *DebugBorderDrawQuad::MaterialCast(*at);
+      return InsertBeforeAndInvalidateAllPointers<DebugBorderDrawQuad>(
+          at, count, copy);
+    }
+    case DrawQuad::Material::kPictureContent: {
+      const auto copy = *PictureDrawQuad::MaterialCast(*at);
+      return InsertBeforeAndInvalidateAllPointers<PictureDrawQuad>(at, count,
+                                                                   copy);
+    }
+    case DrawQuad::Material::kTextureContent: {
+      const auto copy = *TextureDrawQuad::MaterialCast(*at);
+      return InsertBeforeAndInvalidateAllPointers<TextureDrawQuad>(at, count,
+                                                                   copy);
+    }
+    case DrawQuad::Material::kSolidColor: {
+      const auto copy = *SolidColorDrawQuad::MaterialCast(*at);
+      return InsertBeforeAndInvalidateAllPointers<SolidColorDrawQuad>(at, count,
+                                                                      copy);
+    }
+    case DrawQuad::Material::kTiledContent: {
+      const auto copy = *TileDrawQuad::MaterialCast(*at);
+      return InsertBeforeAndInvalidateAllPointers<TileDrawQuad>(at, count,
+                                                                copy);
+    }
+    case DrawQuad::Material::kStreamVideoContent: {
+      const auto copy = *StreamVideoDrawQuad::MaterialCast(*at);
+      return InsertBeforeAndInvalidateAllPointers<StreamVideoDrawQuad>(
+          at, count, copy);
+    }
+    case DrawQuad::Material::kSurfaceContent: {
+      const auto copy = *SurfaceDrawQuad::MaterialCast(*at);
+      return InsertBeforeAndInvalidateAllPointers<SurfaceDrawQuad>(at, count,
+                                                                   copy);
+    }
+    case DrawQuad::Material::kVideoHole: {
+      const auto copy = *VideoHoleDrawQuad::MaterialCast(*at);
+      return InsertBeforeAndInvalidateAllPointers<VideoHoleDrawQuad>(at, count,
+                                                                     copy);
+    }
+    case DrawQuad::Material::kYuvVideoContent: {
+      const auto copy = *YUVVideoDrawQuad::MaterialCast(*at);
+      return InsertBeforeAndInvalidateAllPointers<YUVVideoDrawQuad>(at, count,
+                                                                    copy);
+    }
+    // RenderPass quads should not be copied.
+    case DrawQuad::Material::kRenderPass:
+    case DrawQuad::Material::kInvalid:
+      NOTREACHED();  // Invalid DrawQuad material.
+      return at;
+  }
+}
+
+}  // namespace viz
diff --git a/components/viz/common/quads/quad_list.h b/components/viz/common/quads/quad_list.h
new file mode 100644
index 0000000..f551252
--- /dev/null
+++ b/components/viz/common/quads/quad_list.h
@@ -0,0 +1,39 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_VIZ_COMMON_QUADS_QUAD_LIST_H_
+#define COMPONENTS_VIZ_COMMON_QUADS_QUAD_LIST_H_
+
+#include <stddef.h>
+
+#include "cc/base/list_container.h"
+#include "components/viz/common/quads/draw_quad.h"
+
+namespace viz {
+
+// A list of DrawQuad objects, sorted internally in front-to-back order. To
+// add a new quad drawn behind another quad, it must be placed after the other
+// quad.
+class VIZ_COMMON_EXPORT QuadList : public cc::ListContainer<DrawQuad> {
+ public:
+  QuadList();
+  explicit QuadList(size_t default_size_to_reserve);
+
+  using BackToFrontIterator = QuadList::ReverseIterator;
+  using ConstBackToFrontIterator = QuadList::ConstReverseIterator;
+
+  inline BackToFrontIterator BackToFrontBegin() { return rbegin(); }
+  inline BackToFrontIterator BackToFrontEnd() { return rend(); }
+  inline ConstBackToFrontIterator BackToFrontBegin() const { return rbegin(); }
+  inline ConstBackToFrontIterator BackToFrontEnd() const { return rend(); }
+
+  // This function is used by overlay algorithm to fill the backbuffer with
+  // transparent black.
+  void ReplaceExistingQuadWithOpaqueTransparentSolidColor(Iterator at);
+  Iterator InsertCopyBeforeDrawQuad(Iterator at, size_t count);
+};
+
+}  // namespace viz
+
+#endif  // COMPONENTS_VIZ_COMMON_QUADS_QUAD_LIST_H_
diff --git a/components/viz/common/quads/render_pass.cc b/components/viz/common/quads/render_pass.cc
index 2e08e45..854931e 100644
--- a/components/viz/common/quads/render_pass.cc
+++ b/components/viz/common/quads/render_pass.cc
@@ -7,6 +7,7 @@
 #include <stddef.h>
 
 #include <algorithm>
+#include <memory>
 
 #include "base/memory/ptr_util.h"
 #include "base/numerics/safe_conversions.h"
@@ -37,86 +38,6 @@
 
 namespace viz {
 
-QuadList::QuadList()
-    : ListContainer<DrawQuad>(LargestDrawQuadAlignment(),
-                              LargestDrawQuadSize(),
-                              kDefaultNumSharedQuadStatesToReserve) {}
-
-QuadList::QuadList(size_t default_size_to_reserve)
-    : ListContainer<DrawQuad>(LargestDrawQuadAlignment(),
-                              LargestDrawQuadSize(),
-                              default_size_to_reserve) {}
-
-void QuadList::ReplaceExistingQuadWithOpaqueTransparentSolidColor(Iterator at) {
-  // In order to fill the backbuffer with transparent black, the replacement
-  // solid color quad needs to set |needs_blending| to false, and
-  // ShouldDrawWithBlending() returns false so it is drawn without blending.
-  const gfx::Rect rect = at->rect;
-  bool needs_blending = false;
-  const SharedQuadState* shared_quad_state = at->shared_quad_state;
-
-  auto* replacement = QuadList::ReplaceExistingElement<SolidColorDrawQuad>(at);
-  replacement->SetAll(shared_quad_state, rect, rect /* visible_rect */,
-                      needs_blending, SK_ColorTRANSPARENT, true);
-}
-
-QuadList::Iterator QuadList::InsertCopyBeforeDrawQuad(Iterator at,
-                                                      size_t count) {
-  DCHECK(at->shared_quad_state);
-  switch (at->material) {
-    case DrawQuad::Material::kDebugBorder: {
-      const auto copy = *DebugBorderDrawQuad::MaterialCast(*at);
-      return InsertBeforeAndInvalidateAllPointers<DebugBorderDrawQuad>(
-          at, count, copy);
-    }
-    case DrawQuad::Material::kPictureContent: {
-      const auto copy = *PictureDrawQuad::MaterialCast(*at);
-      return InsertBeforeAndInvalidateAllPointers<PictureDrawQuad>(at, count,
-                                                                   copy);
-    }
-    case DrawQuad::Material::kTextureContent: {
-      const auto copy = *TextureDrawQuad::MaterialCast(*at);
-      return InsertBeforeAndInvalidateAllPointers<TextureDrawQuad>(at, count,
-                                                                   copy);
-    }
-    case DrawQuad::Material::kSolidColor: {
-      const auto copy = *SolidColorDrawQuad::MaterialCast(*at);
-      return InsertBeforeAndInvalidateAllPointers<SolidColorDrawQuad>(at, count,
-                                                                      copy);
-    }
-    case DrawQuad::Material::kTiledContent: {
-      const auto copy = *TileDrawQuad::MaterialCast(*at);
-      return InsertBeforeAndInvalidateAllPointers<TileDrawQuad>(at, count,
-                                                                copy);
-    }
-    case DrawQuad::Material::kStreamVideoContent: {
-      const auto copy = *StreamVideoDrawQuad::MaterialCast(*at);
-      return InsertBeforeAndInvalidateAllPointers<StreamVideoDrawQuad>(
-          at, count, copy);
-    }
-    case DrawQuad::Material::kSurfaceContent: {
-      const auto copy = *SurfaceDrawQuad::MaterialCast(*at);
-      return InsertBeforeAndInvalidateAllPointers<SurfaceDrawQuad>(at, count,
-                                                                   copy);
-    }
-    case DrawQuad::Material::kVideoHole: {
-      const auto copy = *VideoHoleDrawQuad::MaterialCast(*at);
-      return InsertBeforeAndInvalidateAllPointers<VideoHoleDrawQuad>(at, count,
-                                                                     copy);
-    }
-    case DrawQuad::Material::kYuvVideoContent: {
-      const auto copy = *YUVVideoDrawQuad::MaterialCast(*at);
-      return InsertBeforeAndInvalidateAllPointers<YUVVideoDrawQuad>(at, count,
-                                                                    copy);
-    }
-    // RenderPass quads should not be copied.
-    case DrawQuad::Material::kRenderPass:
-    case DrawQuad::Material::kInvalid:
-      NOTREACHED();  // Invalid DrawQuad material.
-      return at;
-  }
-}
-
 std::unique_ptr<RenderPass> RenderPass::Create() {
   return base::WrapUnique(new RenderPass());
 }
diff --git a/components/viz/common/quads/render_pass.h b/components/viz/common/quads/render_pass.h
index c020979..ad71fa4 100644
--- a/components/viz/common/quads/render_pass.h
+++ b/components/viz/common/quads/render_pass.h
@@ -7,6 +7,7 @@
 
 #include <stddef.h>
 
+#include <memory>
 #include <utility>
 #include <vector>
 
@@ -17,6 +18,7 @@
 #include "cc/paint/filter_operations.h"
 #include "components/viz/common/quads/draw_quad.h"
 #include "components/viz/common/quads/largest_draw_quad.h"
+#include "components/viz/common/quads/quad_list.h"
 #include "components/viz/common/viz_common_export.h"
 #include "ui/gfx/display_color_spaces.h"
 #include "ui/gfx/geometry/rect.h"
@@ -35,30 +37,7 @@
 class RenderPassDrawQuad;
 class SharedQuadState;
 
-// A list of DrawQuad objects, sorted internally in front-to-back order. To
-// add a new quad drawn behind another quad, it must be placed after the other
-// quad.
-class VIZ_COMMON_EXPORT QuadList : public cc::ListContainer<DrawQuad> {
- public:
-  QuadList();
-  explicit QuadList(size_t default_size_to_reserve);
-
-  typedef QuadList::ReverseIterator BackToFrontIterator;
-  typedef QuadList::ConstReverseIterator ConstBackToFrontIterator;
-
-  inline BackToFrontIterator BackToFrontBegin() { return rbegin(); }
-  inline BackToFrontIterator BackToFrontEnd() { return rend(); }
-  inline ConstBackToFrontIterator BackToFrontBegin() const { return rbegin(); }
-  inline ConstBackToFrontIterator BackToFrontEnd() const { return rend(); }
-
-  // This function is used by overlay algorithm to fill the backbuffer with
-  // transparent black.
-  void ReplaceExistingQuadWithOpaqueTransparentSolidColor(Iterator at);
-  Iterator InsertCopyBeforeDrawQuad(Iterator at, size_t count);
-};
-
 using SharedQuadStateList = cc::ListContainer<SharedQuadState>;
-
 using RenderPassId = uint64_t;
 
 class VIZ_COMMON_EXPORT RenderPass {
diff --git a/components/viz/service/display_embedder/output_presenter_fuchsia.cc b/components/viz/service/display_embedder/output_presenter_fuchsia.cc
index 50a65e9..799084259 100644
--- a/components/viz/service/display_embedder/output_presenter_fuchsia.cc
+++ b/components/viz/service/display_embedder/output_presenter_fuchsia.cc
@@ -338,7 +338,8 @@
     if (!shared_image_factory_.CreateSharedImage(
             mailbox, gpu::kInProcessCommandBufferClientId,
             std::move(gmb_handle), buffer_format_, gpu::kNullSurfaceHandle,
-            frame_size_, color_space, image_usage)) {
+            frame_size_, color_space, kTopLeft_GrSurfaceOrigin,
+            kPremul_SkAlphaType, image_usage)) {
       return {};
     }
 
diff --git a/components/viz/service/display_embedder/output_presenter_gl.cc b/components/viz/service/display_embedder/output_presenter_gl.cc
index 289ab589..521fc10 100644
--- a/components/viz/service/display_embedder/output_presenter_gl.cc
+++ b/components/viz/service/display_embedder/output_presenter_gl.cc
@@ -73,9 +73,9 @@
     uint32_t shared_image_usage) {
   auto mailbox = gpu::Mailbox::GenerateForSharedImage();
 
-  if (!factory->CreateSharedImage(mailbox, format, size, color_space,
-                                  deps->GetSurfaceHandle(),
-                                  shared_image_usage)) {
+  if (!factory->CreateSharedImage(
+          mailbox, format, size, color_space, kTopLeft_GrSurfaceOrigin,
+          kPremul_SkAlphaType, deps->GetSurfaceHandle(), shared_image_usage)) {
     DLOG(ERROR) << "CreateSharedImage failed.";
     return false;
   }
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
index 3ce75948..634cbe9e 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -546,7 +546,8 @@
                                  gpu::SurfaceHandle surface_handle) override {
     auto mailbox = gpu::Mailbox::GenerateForSharedImage();
     if (shared_image_factory_.CreateSharedImage(
-            mailbox, format, size, color_space, surface_handle, usage))
+            mailbox, format, size, color_space, surface_origin, alpha_type,
+            surface_handle, usage))
       return mailbox;
     return gpu::Mailbox();
   }
@@ -561,7 +562,9 @@
       base::span<const uint8_t> pixel_data) override {
     auto mailbox = gpu::Mailbox::GenerateForSharedImage();
     if (shared_image_factory_.CreateSharedImage(mailbox, format, size,
-                                                color_space, usage, pixel_data))
+
+                                                color_space, surface_origin,
+                                                alpha_type, usage, pixel_data))
       return mailbox;
     return gpu::Mailbox();
   }
diff --git a/components/zucchini/zucchini_commands.cc b/components/zucchini/zucchini_commands.cc
index 1abe08f..106b256 100644
--- a/components/zucchini/zucchini_commands.cc
+++ b/components/zucchini/zucchini_commands.cc
@@ -55,7 +55,8 @@
 zucchini::status::Code MainRead(MainParams params) {
   CHECK_EQ(1U, params.file_paths.size());
   base::File input_file(params.file_paths[0],
-                        base::File::FLAG_OPEN | base::File::FLAG_READ);
+                        base::File::FLAG_OPEN | base::File::FLAG_READ |
+                            base::File::FLAG_SHARE_DELETE);
   zucchini::MappedFileReader input(std::move(input_file));
   if (input.HasError()) {
     LOG(ERROR) << "Error with file " << params.file_paths[0].value() << ": "
@@ -74,7 +75,8 @@
 zucchini::status::Code MainDetect(MainParams params) {
   CHECK_EQ(1U, params.file_paths.size());
   base::File input_file(params.file_paths[0],
-                        base::File::FLAG_OPEN | base::File::FLAG_READ);
+                        base::File::FLAG_OPEN | base::File::FLAG_READ |
+                            base::File::FLAG_SHARE_DELETE);
   zucchini::MappedFileReader input(std::move(input_file));
   if (input.HasError()) {
     LOG(ERROR) << "Error with file " << params.file_paths[0].value() << ": "
@@ -93,14 +95,16 @@
 zucchini::status::Code MainMatch(MainParams params) {
   CHECK_EQ(2U, params.file_paths.size());
   using base::File;
-  File old_file(params.file_paths[0], File::FLAG_OPEN | File::FLAG_READ);
+  File old_file(params.file_paths[0], File::FLAG_OPEN | File::FLAG_READ |
+                                          base::File::FLAG_SHARE_DELETE);
   zucchini::MappedFileReader old_image(std::move(old_file));
   if (old_image.HasError()) {
     LOG(ERROR) << "Error with file " << params.file_paths[0].value() << ": "
                << old_image.error();
     return zucchini::status::kStatusFileReadError;
   }
-  File new_file(params.file_paths[1], File::FLAG_OPEN | File::FLAG_READ);
+  File new_file(params.file_paths[1], File::FLAG_OPEN | File::FLAG_READ |
+                                          base::File::FLAG_SHARE_DELETE);
   zucchini::MappedFileReader new_image(std::move(new_file));
   if (new_image.HasError()) {
     LOG(ERROR) << "Error with file " << params.file_paths[1].value() << ": "
@@ -122,7 +126,8 @@
 zucchini::status::Code MainCrc32(MainParams params) {
   CHECK_EQ(1U, params.file_paths.size());
   base::File image_file(params.file_paths[0],
-                        base::File::FLAG_OPEN | base::File::FLAG_READ);
+                        base::File::FLAG_OPEN | base::File::FLAG_READ |
+                            base::File::FLAG_SHARE_DELETE);
   zucchini::MappedFileReader image(std::move(image_file));
   if (image.HasError()) {
     LOG(ERROR) << "Error with file " << params.file_paths[0].value() << ": "
diff --git a/components/zucchini/zucchini_integration.cc b/components/zucchini/zucchini_integration.cc
index 97790a34..ff7e792 100644
--- a/components/zucchini/zucchini_integration.cc
+++ b/components/zucchini/zucchini_integration.cc
@@ -167,8 +167,10 @@
                       bool is_raw,
                       std::string imposed_matches) {
   using base::File;
-  File old_file(old_path, File::FLAG_OPEN | File::FLAG_READ);
-  File new_file(new_path, File::FLAG_OPEN | File::FLAG_READ);
+  File old_file(old_path, File::FLAG_OPEN | File::FLAG_READ |
+                              base::File::FLAG_SHARE_DELETE);
+  File new_file(new_path, File::FLAG_OPEN | File::FLAG_READ |
+                              base::File::FLAG_SHARE_DELETE);
   File patch_file(patch_path, File::FLAG_CREATE_ALWAYS | File::FLAG_READ |
                                   File::FLAG_WRITE | File::FLAG_SHARE_DELETE |
                                   File::FLAG_CAN_DELETE_ON_CLOSE);
@@ -192,8 +194,10 @@
                    const base::FilePath& new_path,
                    bool force_keep) {
   using base::File;
-  File old_file(old_path, File::FLAG_OPEN | File::FLAG_READ);
-  File patch_file(patch_path, File::FLAG_OPEN | File::FLAG_READ);
+  File old_file(old_path, File::FLAG_OPEN | File::FLAG_READ |
+                              base::File::FLAG_SHARE_DELETE);
+  File patch_file(patch_path, File::FLAG_OPEN | File::FLAG_READ |
+                                  base::File::FLAG_SHARE_DELETE);
   File new_file(new_path, File::FLAG_CREATE_ALWAYS | File::FLAG_READ |
                               File::FLAG_WRITE | File::FLAG_SHARE_DELETE |
                               File::FLAG_CAN_DELETE_ON_CLOSE);
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 79643f8..c69fee7 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -2082,6 +2082,10 @@
     ]
   }
 
+  if (is_chromecast) {
+    deps += [ "//chromecast:chromecast_buildflags" ]
+  }
+
   if (is_chromecast && is_linux) {
     sources += [
       "tracing/cast_tracing_agent.cc",
diff --git a/content/browser/appcache/appcache_quota_client.cc b/content/browser/appcache/appcache_quota_client.cc
index a0ed9741..c299e8fd 100644
--- a/content/browser/appcache/appcache_quota_client.cc
+++ b/content/browser/appcache/appcache_quota_client.cc
@@ -69,7 +69,7 @@
 
 void AppCacheQuotaClient::GetOriginUsage(const url::Origin& origin,
                                          StorageType type,
-                                         GetUsageCallback callback) {
+                                         GetOriginUsageCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK_EQ(type, blink::mojom::StorageType::kTemporary);
   DCHECK(!callback.is_null());
@@ -106,8 +106,9 @@
       std::move(callback));
 }
 
-void AppCacheQuotaClient::GetOriginsForType(StorageType type,
-                                            GetOriginsCallback callback) {
+void AppCacheQuotaClient::GetOriginsForType(
+    StorageType type,
+    GetOriginsForTypeCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK_EQ(type, blink::mojom::StorageType::kTemporary);
   DCHECK(!callback.is_null());
@@ -115,9 +116,10 @@
   GetOriginsHelper(std::string(), std::move(callback));
 }
 
-void AppCacheQuotaClient::GetOriginsForHost(StorageType type,
-                                            const std::string& host,
-                                            GetOriginsCallback callback) {
+void AppCacheQuotaClient::GetOriginsForHost(
+    StorageType type,
+    const std::string& host,
+    GetOriginsForHostCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK_EQ(type, blink::mojom::StorageType::kTemporary);
   DCHECK(!callback.is_null());
@@ -131,7 +133,7 @@
 
 void AppCacheQuotaClient::DeleteOriginData(const url::Origin& origin,
                                            StorageType type,
-                                           DeletionCallback callback) {
+                                           DeleteOriginDataCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK_EQ(type, blink::mojom::StorageType::kTemporary);
   DCHECK(!callback.is_null());
@@ -183,7 +185,7 @@
 }
 
 void AppCacheQuotaClient::GetOriginsHelper(const std::string& opt_host,
-                                           GetOriginsCallback callback) {
+                                           GetOriginsForTypeCallback callback) {
   DCHECK(!callback.is_null());
 
   if (service_is_destroyed_) {
diff --git a/content/browser/appcache/appcache_quota_client.h b/content/browser/appcache/appcache_quota_client.h
index 9a12063..1f1a4c9 100644
--- a/content/browser/appcache/appcache_quota_client.h
+++ b/content/browser/appcache/appcache_quota_client.h
@@ -43,17 +43,17 @@
   void OnQuotaManagerDestroyed() override;
   void GetOriginUsage(const url::Origin& origin,
                       blink::mojom::StorageType type,
-                      GetUsageCallback callback) override;
+                      GetOriginUsageCallback callback) override;
   void GetOriginsForType(blink::mojom::StorageType type,
-                         GetOriginsCallback callback) override;
+                         GetOriginsForTypeCallback callback) override;
   void GetOriginsForHost(blink::mojom::StorageType type,
                          const std::string& host,
-                         GetOriginsCallback callback) override;
+                         GetOriginsForHostCallback callback) override;
   void DeleteOriginData(const url::Origin& origin,
                         blink::mojom::StorageType type,
-                        DeletionCallback callback) override;
+                        DeleteOriginDataCallback callback) override;
   void PerformStorageCleanup(blink::mojom::StorageType type,
-                             base::OnceClosure callback) override;
+                             PerformStorageCleanupCallback callback) override;
 
  private:
   friend class content::AppCacheQuotaClientTest;
@@ -64,7 +64,7 @@
 
   void DidDeleteAppCachesForOrigin(int rv);
   void GetOriginsHelper(const std::string& opt_host,
-                        GetOriginsCallback callback);
+                        GetOriginsForTypeCallback callback);
   void ProcessPendingRequests();
   void DeletePendingRequests();
   net::CancelableCompletionRepeatingCallback* GetServiceDeleteCallback();
@@ -80,7 +80,7 @@
 
   // And once it's ready, we can only handle one delete request at a time,
   // so we queue up additional requests while one is in already in progress.
-  DeletionCallback current_delete_request_callback_;
+  DeleteOriginDataCallback current_delete_request_callback_;
   std::unique_ptr<net::CancelableCompletionRepeatingCallback>
       service_delete_callback_;
 
diff --git a/content/browser/cache_storage/cache_storage_manager.h b/content/browser/cache_storage/cache_storage_manager.h
index d36a761..80cdfaa 100644
--- a/content/browser/cache_storage/cache_storage_manager.h
+++ b/content/browser/cache_storage/cache_storage_manager.h
@@ -53,18 +53,18 @@
   virtual void GetOriginUsage(
       const url::Origin& origin_url,
       CacheStorageOwner owner,
-      storage::QuotaClient::GetUsageCallback callback) = 0;
+      storage::QuotaClient::GetOriginUsageCallback callback) = 0;
   virtual void GetOrigins(
       CacheStorageOwner owner,
-      storage::QuotaClient::GetOriginsCallback callback) = 0;
+      storage::QuotaClient::GetOriginsForTypeCallback callback) = 0;
   virtual void GetOriginsForHost(
       const std::string& host,
       CacheStorageOwner owner,
-      storage::QuotaClient::GetOriginsCallback callback) = 0;
+      storage::QuotaClient::GetOriginsForHostCallback callback) = 0;
   virtual void DeleteOriginData(
       const url::Origin& origin,
       CacheStorageOwner owner,
-      storage::QuotaClient::DeletionCallback callback) = 0;
+      storage::QuotaClient::DeleteOriginDataCallback callback) = 0;
   virtual void DeleteOriginData(const url::Origin& origin,
                                 CacheStorageOwner owner) = 0;
 
diff --git a/content/browser/cache_storage/cache_storage_quota_client.cc b/content/browser/cache_storage/cache_storage_quota_client.cc
index 18e73a7..7af4c174 100644
--- a/content/browser/cache_storage/cache_storage_quota_client.cc
+++ b/content/browser/cache_storage/cache_storage_quota_client.cc
@@ -23,7 +23,7 @@
 
 void CacheStorageQuotaClient::GetOriginUsage(const url::Origin& origin,
                                              blink::mojom::StorageType type,
-                                             GetUsageCallback callback) {
+                                             GetOriginUsageCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK_EQ(type, blink::mojom::StorageType::kTemporary);
 
@@ -35,26 +35,29 @@
   cache_manager_->GetOriginUsage(origin, owner_, std::move(callback));
 }
 
-void CacheStorageQuotaClient::GetOriginsForType(blink::mojom::StorageType type,
-                                                GetOriginsCallback callback) {
+void CacheStorageQuotaClient::GetOriginsForType(
+    blink::mojom::StorageType type,
+    GetOriginsForTypeCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK_EQ(type, blink::mojom::StorageType::kTemporary);
 
   cache_manager_->GetOrigins(owner_, std::move(callback));
 }
 
-void CacheStorageQuotaClient::GetOriginsForHost(blink::mojom::StorageType type,
-                                                const std::string& host,
-                                                GetOriginsCallback callback) {
+void CacheStorageQuotaClient::GetOriginsForHost(
+    blink::mojom::StorageType type,
+    const std::string& host,
+    GetOriginsForHostCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK_EQ(type, blink::mojom::StorageType::kTemporary);
 
   cache_manager_->GetOriginsForHost(host, owner_, std::move(callback));
 }
 
-void CacheStorageQuotaClient::DeleteOriginData(const url::Origin& origin,
-                                               blink::mojom::StorageType type,
-                                               DeletionCallback callback) {
+void CacheStorageQuotaClient::DeleteOriginData(
+    const url::Origin& origin,
+    blink::mojom::StorageType type,
+    DeleteOriginDataCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK_EQ(type, blink::mojom::StorageType::kTemporary);
 
@@ -68,7 +71,7 @@
 
 void CacheStorageQuotaClient::PerformStorageCleanup(
     blink::mojom::StorageType type,
-    base::OnceClosure callback) {
+    PerformStorageCleanupCallback callback) {
   std::move(callback).Run();
 }
 
diff --git a/content/browser/cache_storage/cache_storage_quota_client.h b/content/browser/cache_storage/cache_storage_quota_client.h
index 5b27bcc..bdccd07 100644
--- a/content/browser/cache_storage/cache_storage_quota_client.h
+++ b/content/browser/cache_storage/cache_storage_quota_client.h
@@ -30,17 +30,17 @@
   void OnQuotaManagerDestroyed() override;
   void GetOriginUsage(const url::Origin& origin,
                       blink::mojom::StorageType type,
-                      GetUsageCallback callback) override;
+                      GetOriginUsageCallback callback) override;
   void GetOriginsForType(blink::mojom::StorageType type,
-                         GetOriginsCallback callback) override;
+                         GetOriginsForTypeCallback callback) override;
   void GetOriginsForHost(blink::mojom::StorageType type,
                          const std::string& host,
-                         GetOriginsCallback callback) override;
+                         GetOriginsForHostCallback callback) override;
   void DeleteOriginData(const url::Origin& origin,
                         blink::mojom::StorageType type,
-                        DeletionCallback callback) override;
+                        DeleteOriginDataCallback callback) override;
   void PerformStorageCleanup(blink::mojom::StorageType type,
-                             base::OnceClosure callback) override;
+                             PerformStorageCleanupCallback callback) override;
 
   static storage::QuotaClientType GetClientTypeFromOwner(
       CacheStorageOwner owner);
diff --git a/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_manager.cc b/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_manager.cc
index d42e7d7..53bedcfd 100644
--- a/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_manager.cc
+++ b/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_manager.cc
@@ -33,27 +33,29 @@
 
   void GetOriginUsage(const url::Origin& origin_url,
                       CacheStorageOwner owner,
-                      storage::QuotaClient::GetUsageCallback callback) {
+                      storage::QuotaClient::GetOriginUsageCallback callback) {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     target_manager_->GetOriginUsage(origin_url, owner, std::move(callback));
   }
 
   void GetOrigins(CacheStorageOwner owner,
-                  storage::QuotaClient::GetOriginsCallback callback) {
+                  storage::QuotaClient::GetOriginsForTypeCallback callback) {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     target_manager_->GetOrigins(owner, std::move(callback));
   }
 
-  void GetOriginsForHost(const std::string& host,
-                         CacheStorageOwner owner,
-                         storage::QuotaClient::GetOriginsCallback callback) {
+  void GetOriginsForHost(
+      const std::string& host,
+      CacheStorageOwner owner,
+      storage::QuotaClient::GetOriginsForHostCallback callback) {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     target_manager_->GetOriginsForHost(host, owner, std::move(callback));
   }
 
-  void DeleteOriginData(const url::Origin& origin,
-                        CacheStorageOwner owner,
-                        storage::QuotaClient::DeletionCallback callback) {
+  void DeleteOriginData(
+      const url::Origin& origin,
+      CacheStorageOwner owner,
+      storage::QuotaClient::DeleteOriginDataCallback callback) {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     target_manager_->DeleteOriginData(origin, owner, std::move(callback));
   }
@@ -94,7 +96,7 @@
 void CrossSequenceCacheStorageManager::GetOriginUsage(
     const url::Origin& origin_url,
     CacheStorageOwner owner,
-    storage::QuotaClient::GetUsageCallback callback) {
+    storage::QuotaClient::GetOriginUsageCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   inner_.Post(FROM_HERE, &Inner::GetOriginUsage, origin_url, owner,
               WrapCallbackForCurrentSequence(std::move(callback)));
@@ -102,7 +104,7 @@
 
 void CrossSequenceCacheStorageManager::GetOrigins(
     CacheStorageOwner owner,
-    storage::QuotaClient::GetOriginsCallback callback) {
+    storage::QuotaClient::GetOriginsForTypeCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   inner_.Post(FROM_HERE, &Inner::GetOrigins, owner,
               WrapCallbackForCurrentSequence(std::move(callback)));
@@ -111,7 +113,7 @@
 void CrossSequenceCacheStorageManager::GetOriginsForHost(
     const std::string& host,
     CacheStorageOwner owner,
-    storage::QuotaClient::GetOriginsCallback callback) {
+    storage::QuotaClient::GetOriginsForHostCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   inner_.Post(FROM_HERE, &Inner::GetOriginsForHost, host, owner,
               WrapCallbackForCurrentSequence(std::move(callback)));
@@ -120,7 +122,7 @@
 void CrossSequenceCacheStorageManager::DeleteOriginData(
     const url::Origin& origin,
     CacheStorageOwner owner,
-    storage::QuotaClient::DeletionCallback callback) {
+    storage::QuotaClient::DeleteOriginDataCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   inner_.Post(FROM_HERE, &Inner::DeleteOriginData, origin, owner,
               WrapCallbackForCurrentSequence(std::move(callback)));
diff --git a/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_manager.h b/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_manager.h
index 5ca0805..489ee5b 100644
--- a/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_manager.h
+++ b/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_manager.h
@@ -33,19 +33,21 @@
   void GetAllOriginsUsage(
       CacheStorageOwner owner,
       CacheStorageContext::GetUsageInfoCallback callback) override;
-  void GetOriginUsage(const url::Origin& origin_url,
-                      CacheStorageOwner owner,
-                      storage::QuotaClient::GetUsageCallback callback) override;
-  void GetOrigins(CacheStorageOwner owner,
-                  storage::QuotaClient::GetOriginsCallback callback) override;
+  void GetOriginUsage(
+      const url::Origin& origin_url,
+      CacheStorageOwner owner,
+      storage::QuotaClient::GetOriginUsageCallback callback) override;
+  void GetOrigins(
+      CacheStorageOwner owner,
+      storage::QuotaClient::GetOriginsForTypeCallback callback) override;
   void GetOriginsForHost(
       const std::string& host,
       CacheStorageOwner owner,
-      storage::QuotaClient::GetOriginsCallback callback) override;
+      storage::QuotaClient::GetOriginsForHostCallback callback) override;
   void DeleteOriginData(
       const url::Origin& origin,
       CacheStorageOwner owner,
-      storage::QuotaClient::DeletionCallback callback) override;
+      storage::QuotaClient::DeleteOriginDataCallback callback) override;
   void DeleteOriginData(const url::Origin& origin,
                         CacheStorageOwner owner) override;
   void SetBlobParametersForCache(
diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage_manager.cc b/content/browser/cache_storage/legacy/legacy_cache_storage_manager.cc
index f63488d2..2d30caa 100644
--- a/content/browser/cache_storage/legacy/legacy_cache_storage_manager.cc
+++ b/content/browser/cache_storage/legacy/legacy_cache_storage_manager.cc
@@ -45,8 +45,9 @@
   return base::DeletePathRecursively(path);
 }
 
-void DeleteOriginDidDeleteDir(storage::QuotaClient::DeletionCallback callback,
-                              bool rv) {
+void DeleteOriginDidDeleteDir(
+    storage::QuotaClient::DeleteOriginDataCallback callback,
+    bool rv) {
   // On scheduler sequence.
   base::SequencedTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
@@ -199,7 +200,7 @@
 
 void GetOriginsForHostDidListOrigins(
     const std::string& host,
-    storage::QuotaClient::GetOriginsCallback callback,
+    storage::QuotaClient::GetOriginsForTypeCallback callback,
     const std::vector<url::Origin>& origins) {
   // On scheduler sequence.
   std::vector<url::Origin> out_origins;
@@ -401,7 +402,7 @@
 void LegacyCacheStorageManager::GetOriginUsage(
     const url::Origin& origin,
     CacheStorageOwner owner,
-    storage::QuotaClient::GetUsageCallback callback) {
+    storage::QuotaClient::GetOriginUsageCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   CacheStorageHandle cache_storage = OpenCacheStorage(origin, owner);
@@ -410,7 +411,7 @@
 
 void LegacyCacheStorageManager::GetOrigins(
     CacheStorageOwner owner,
-    storage::QuotaClient::GetOriginsCallback callback) {
+    storage::QuotaClient::GetOriginsForTypeCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (IsMemoryBacked()) {
@@ -433,7 +434,7 @@
 void LegacyCacheStorageManager::GetOriginsForHost(
     const std::string& host,
     CacheStorageOwner owner,
-    storage::QuotaClient::GetOriginsCallback callback) {
+    storage::QuotaClient::GetOriginsForHostCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (IsMemoryBacked()) {
@@ -459,7 +460,7 @@
 void LegacyCacheStorageManager::DeleteOriginData(
     const url::Origin& origin,
     CacheStorageOwner owner,
-    storage::QuotaClient::DeletionCallback callback) {
+    storage::QuotaClient::DeleteOriginDataCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // Create the CacheStorage for the origin if it hasn't been loaded yet.
@@ -486,7 +487,7 @@
 void LegacyCacheStorageManager::DeleteOriginDidClose(
     const url::Origin& origin,
     CacheStorageOwner owner,
-    storage::QuotaClient::DeletionCallback callback,
+    storage::QuotaClient::DeleteOriginDataCallback callback,
     std::unique_ptr<LegacyCacheStorage> cache_storage,
     int64_t origin_size) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage_manager.h b/content/browser/cache_storage/legacy/legacy_cache_storage_manager.h
index d55a1f8..8266ede 100644
--- a/content/browser/cache_storage/legacy/legacy_cache_storage_manager.h
+++ b/content/browser/cache_storage/legacy/legacy_cache_storage_manager.h
@@ -66,19 +66,21 @@
   void GetAllOriginsUsage(
       CacheStorageOwner owner,
       CacheStorageContext::GetUsageInfoCallback callback) override;
-  void GetOriginUsage(const url::Origin& origin_url,
-                      CacheStorageOwner owner,
-                      storage::QuotaClient::GetUsageCallback callback) override;
-  void GetOrigins(CacheStorageOwner owner,
-                  storage::QuotaClient::GetOriginsCallback callback) override;
+  void GetOriginUsage(
+      const url::Origin& origin_url,
+      CacheStorageOwner owner,
+      storage::QuotaClient::GetOriginUsageCallback callback) override;
+  void GetOrigins(
+      CacheStorageOwner owner,
+      storage::QuotaClient::GetOriginsForTypeCallback callback) override;
   void GetOriginsForHost(
       const std::string& host,
       CacheStorageOwner owner,
-      storage::QuotaClient::GetOriginsCallback callback) override;
+      storage::QuotaClient::GetOriginsForHostCallback callback) override;
   void DeleteOriginData(
       const url::Origin& origin,
       CacheStorageOwner owner,
-      storage::QuotaClient::DeletionCallback callback) override;
+      storage::QuotaClient::DeleteOriginDataCallback callback) override;
   void DeleteOriginData(const url::Origin& origin,
                         CacheStorageOwner owner) override;
 
@@ -118,11 +120,12 @@
       std::unique_ptr<std::vector<StorageUsageInfo>> usage_info,
       CacheStorageContext::GetUsageInfoCallback callback);
 
-  void DeleteOriginDidClose(const url::Origin& origin,
-                            CacheStorageOwner owner,
-                            storage::QuotaClient::DeletionCallback callback,
-                            std::unique_ptr<LegacyCacheStorage> cache_storage,
-                            int64_t origin_size);
+  void DeleteOriginDidClose(
+      const url::Origin& origin,
+      CacheStorageOwner owner,
+      storage::QuotaClient::DeleteOriginDataCallback callback,
+      std::unique_ptr<LegacyCacheStorage> cache_storage,
+      int64_t origin_size);
 
   scoped_refptr<base::SequencedTaskRunner> cache_task_runner() const {
     return cache_task_runner_;
diff --git a/content/browser/gpu/DEPS b/content/browser/gpu/DEPS
index a20e9f7..7b4aa95 100644
--- a/content/browser/gpu/DEPS
+++ b/content/browser/gpu/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+chromecast/chromecast_buildflags.h",
   "+components/metal_util",
   "+components/ui_devtools/buildflags.h",
 ]
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.cc b/content/browser/gpu/gpu_data_manager_impl_private.cc
index c4c5c35..462ac6dc 100644
--- a/content/browser/gpu/gpu_data_manager_impl_private.cc
+++ b/content/browser/gpu/gpu_data_manager_impl_private.cc
@@ -91,6 +91,9 @@
 #include "base/win/windows_version.h"
 #include "ui/display/win/screen_win.h"
 #endif  // OS_WIN
+#if BUILDFLAG(IS_CHROMECAST)
+#include "chromecast/chromecast_buildflags.h"
+#endif
 
 namespace content {
 
@@ -563,8 +566,10 @@
     // Chomecast audio-only builds run with the flag --disable-gpu. The GPU
     // process should not be started in this case.
 #if BUILDFLAG(IS_CHROMECAST)
+#if BUILDFLAG(IS_CAST_AUDIO_ONLY)
     fallback_modes_.clear();
     fallback_modes_.push_back(gpu::GpuMode::DISABLED);
+#endif
 #elif defined(OS_ANDROID) || defined(OS_CHROMEOS)
     CHECK(false) << "GPU acceleration is required on certain platforms!";
 #endif  // IS_CHROMECAST
diff --git a/content/browser/gpu/gpu_data_manager_impl_private_unittest.cc b/content/browser/gpu/gpu_data_manager_impl_private_unittest.cc
index eb0735e..1f687eb 100644
--- a/content/browser/gpu/gpu_data_manager_impl_private_unittest.cc
+++ b/content/browser/gpu/gpu_data_manager_impl_private_unittest.cc
@@ -26,6 +26,13 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
+#if BUILDFLAG(IS_CHROMECAST)
+#include "chromecast/chromecast_buildflags.h"
+#if BUILDFLAG(IS_CAST_AUDIO_ONLY)
+#define CAST_AUDIO_ONLY
+#endif
+#endif
+
 namespace content {
 namespace {
 
@@ -292,7 +299,7 @@
 }
 #endif  // !OS_FUCHSIA
 
-#if !BUILDFLAG(IS_CHROMECAST)
+#if !defined(CAST_AUDIO_ONLY)
 TEST_F(GpuDataManagerImplPrivateTest, GpuStartsWithGpuDisabled) {
   base::CommandLine::ForCurrentProcess()->AppendSwitch(switches::kDisableGpu);
   ScopedGpuDataManagerImplPrivate manager;
@@ -302,7 +309,7 @@
 #endif  // !OS_ANDROID && !OS_CHROMEOS
 
 // Chromecast audio-only builds should not launch the GPU process.
-#if BUILDFLAG(IS_CHROMECAST)
+#if defined(CAST_AUDIO_ONLY)
 TEST_F(GpuDataManagerImplPrivateTest, ChromecastStartsWithGpuDisabled) {
   base::CommandLine::ForCurrentProcess()->AppendSwitch(switches::kDisableGpu);
   ScopedGpuDataManagerImplPrivate manager;
diff --git a/content/browser/indexed_db/indexed_db_quota_client.cc b/content/browser/indexed_db/indexed_db_quota_client.cc
index 05f7439..89cf61d 100644
--- a/content/browser/indexed_db/indexed_db_quota_client.cc
+++ b/content/browser/indexed_db/indexed_db_quota_client.cc
@@ -28,7 +28,7 @@
 namespace {
 
 void DidDeleteIDBData(scoped_refptr<base::SequencedTaskRunner> task_runner,
-                      IndexedDBQuotaClient::DeletionCallback callback,
+                      IndexedDBQuotaClient::DeleteOriginDataCallback callback,
                       bool) {
   task_runner->PostTask(
       FROM_HERE,
@@ -48,7 +48,7 @@
   *origins_to_return = context->GetAllOrigins();
 }
 
-void DidGetOrigins(IndexedDBQuotaClient::GetOriginsCallback callback,
+void DidGetOrigins(IndexedDBQuotaClient::GetOriginsForTypeCallback callback,
                    const std::vector<url::Origin>* origins) {
   // Run on the same sequence that GetOriginsForType was called on,
   // which is likely the IO thread.
@@ -83,7 +83,7 @@
 
 void IndexedDBQuotaClient::GetOriginUsage(const url::Origin& origin,
                                           StorageType type,
-                                          GetUsageCallback callback) {
+                                          GetOriginUsageCallback callback) {
   DCHECK(!callback.is_null());
   DCHECK_EQ(type, StorageType::kTemporary);
 
@@ -94,8 +94,9 @@
       std::move(callback));
 }
 
-void IndexedDBQuotaClient::GetOriginsForType(StorageType type,
-                                             GetOriginsCallback callback) {
+void IndexedDBQuotaClient::GetOriginsForType(
+    StorageType type,
+    GetOriginsForTypeCallback callback) {
   DCHECK(!callback.is_null());
   DCHECK_EQ(type, StorageType::kTemporary);
 
@@ -109,9 +110,10 @@
                      base::Owned(origins_to_return)));
 }
 
-void IndexedDBQuotaClient::GetOriginsForHost(StorageType type,
-                                             const std::string& host,
-                                             GetOriginsCallback callback) {
+void IndexedDBQuotaClient::GetOriginsForHost(
+    StorageType type,
+    const std::string& host,
+    GetOriginsForHostCallback callback) {
   DCHECK(!callback.is_null());
   DCHECK_EQ(type, StorageType::kTemporary);
 
@@ -127,7 +129,7 @@
 
 void IndexedDBQuotaClient::DeleteOriginData(const url::Origin& origin,
                                             StorageType type,
-                                            DeletionCallback callback) {
+                                            DeleteOriginDataCallback callback) {
   DCHECK(!callback.is_null());
   DCHECK_EQ(type, StorageType::kTemporary);
 
@@ -140,8 +142,9 @@
                                     std::move(callback))));
 }
 
-void IndexedDBQuotaClient::PerformStorageCleanup(blink::mojom::StorageType type,
-                                                 base::OnceClosure callback) {
+void IndexedDBQuotaClient::PerformStorageCleanup(
+    blink::mojom::StorageType type,
+    PerformStorageCleanupCallback callback) {
   std::move(callback).Run();
 }
 
diff --git a/content/browser/indexed_db/indexed_db_quota_client.h b/content/browser/indexed_db/indexed_db_quota_client.h
index 28b40b9..8a6b82e 100644
--- a/content/browser/indexed_db/indexed_db_quota_client.h
+++ b/content/browser/indexed_db/indexed_db_quota_client.h
@@ -33,17 +33,17 @@
   void OnQuotaManagerDestroyed() override;
   void GetOriginUsage(const url::Origin& origin,
                       blink::mojom::StorageType type,
-                      GetUsageCallback callback) override;
+                      GetOriginUsageCallback callback) override;
   void GetOriginsForType(blink::mojom::StorageType type,
-                         GetOriginsCallback callback) override;
+                         GetOriginsForTypeCallback callback) override;
   void GetOriginsForHost(blink::mojom::StorageType type,
                          const std::string& host,
-                         GetOriginsCallback callback) override;
+                         GetOriginsForHostCallback callback) override;
   void DeleteOriginData(const url::Origin& origin,
                         blink::mojom::StorageType type,
-                        DeletionCallback callback) override;
+                        DeleteOriginDataCallback callback) override;
   void PerformStorageCleanup(blink::mojom::StorageType type,
-                             base::OnceClosure callback) override;
+                             PerformStorageCleanupCallback callback) override;
 
  private:
   ~IndexedDBQuotaClient() override;
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index fbb357d..94a78100 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -2899,6 +2899,13 @@
   return frame_widget_input_handler_.get();
 }
 
+base::Optional<blink::VisualProperties>
+RenderWidgetHostImpl::GetLastVisualPropertiesSentToRendererForTesting() {
+  if (!old_visual_properties_)
+    return base::nullopt;
+  return *old_visual_properties_;
+}
+
 void RenderWidgetHostImpl::DispatchInputEventWithLatencyInfo(
     const blink::WebInputEvent& event,
     ui::LatencyInfo* latency) {
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index 37e7c602..0d5bc90 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -802,6 +802,10 @@
     return blink_widget_host_receiver_;
   }
 
+  // Returns the visual properties that were last sent to the renderer.
+  base::Optional<blink::VisualProperties>
+  GetLastVisualPropertiesSentToRendererForTesting();
+
  protected:
   // ---------------------------------------------------------------------------
   // The following method is overridden by RenderViewHost to send upwards to
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc b/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc
index 858d0d8a..2385e78 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc
@@ -162,50 +162,6 @@
       base::BindLambdaForTesting(check_screen_width));
 }
 
-class OutgoingVisualPropertiesIPCWatcher {
- public:
-  OutgoingVisualPropertiesIPCWatcher(
-      RenderProcessHostImpl* rph,
-      FrameTreeNode* root,
-      base::RepeatingCallback<void(const blink::VisualProperties&)> callback)
-      : rph_(rph), root_(root), callback_(std::move(callback)) {
-    rph_->SetIpcSendWatcherForTesting(
-        base::BindRepeating(&OutgoingVisualPropertiesIPCWatcher::OnMessage,
-                            base::Unretained(this)));
-  }
-  ~OutgoingVisualPropertiesIPCWatcher() {
-    rph_->SetIpcSendWatcherForTesting(base::NullCallback());
-  }
-
- private:
-  bool IsMessageForFrameTreeWidget(int routing_id, FrameTreeNode* node) {
-    auto* render_widget_host =
-        node->current_frame_host()->GetRenderWidgetHost();
-    if (routing_id == render_widget_host->GetRoutingID())
-      return true;
-    for (size_t i = 0; i < node->child_count(); ++i) {
-      if (IsMessageForFrameTreeWidget(routing_id, node->child_at(i)))
-        return true;
-    }
-    return false;
-  }
-  void OnMessage(const IPC::Message& message) {
-    if (!IsMessageForFrameTreeWidget(message.routing_id(), root_))
-      return;
-    IPC_BEGIN_MESSAGE_MAP(OutgoingVisualPropertiesIPCWatcher, message)
-      IPC_MESSAGE_HANDLER(WidgetMsg_UpdateVisualProperties, ProcessMessage)
-    IPC_END_MESSAGE_MAP()
-  }
-
-  void ProcessMessage(const blink::VisualProperties& props) {
-    callback_.Run(props);
-  }
-
-  RenderProcessHostImpl* const rph_;
-  FrameTreeNode* const root_;
-  base::RepeatingCallback<void(const blink::VisualProperties&)> callback_;
-};
-
 // Auto-resize is only implemented for Ash and GuestViews. So we need to inject
 // an implementation that actually resizes the top level widget.
 class AutoResizeWebContentsDelegate : public WebContentsDelegate {
@@ -247,17 +203,16 @@
 
   // Watch processes for a.com and c.com, as we will throw away b.com when we
   // navigate it below.
-  auto* root_rph = static_cast<RenderProcessHostImpl*>(
-      root->current_frame_host()->GetProcess());
-  auto* child_rph = static_cast<RenderProcessHostImpl*>(
-      root->child_at(1)->current_frame_host()->GetProcess());
-  ASSERT_NE(root_rph, child_rph);
+  auto* root_rwh = root->current_frame_host()->GetRenderWidgetHost();
+  auto* child_rwh =
+      root->child_at(1)->current_frame_host()->GetRenderWidgetHost();
+  ASSERT_NE(root_rwh->GetProcess(), child_rwh->GetProcess());
 
-  auto* nested_root_rph = static_cast<RenderProcessHostImpl*>(
-      nested_root->current_frame_host()->GetProcess());
-  auto* nested_child_rph = static_cast<RenderProcessHostImpl*>(
-      nested_root->child_at(1)->current_frame_host()->GetProcess());
-  ASSERT_NE(nested_root_rph, nested_child_rph);
+  auto* nested_root_rwh =
+      nested_root->current_frame_host()->GetRenderWidgetHost();
+  auto* nested_child_rwh =
+      nested_root->child_at(1)->current_frame_host()->GetRenderWidgetHost();
+  ASSERT_NE(nested_root_rwh->GetProcess(), nested_child_rwh->GetProcess());
 
   const gfx::Size initial_size = root_view->GetVisibleViewportSize();
   const gfx::Size nested_initial_size =
@@ -272,52 +227,35 @@
   // This property is not directly visible in the renderer, so we can only
   // check that the value is sent to the appropriate RenderWidget.
   {
-    base::RunLoop loop;
-
-    gfx::Size child_visible_viewport_size;
-    OutgoingVisualPropertiesIPCWatcher child_watcher(
-        child_rph, root,
-        base::BindLambdaForTesting([&](const blink::VisualProperties& props) {
-          child_visible_viewport_size = props.visible_viewport_size;
-
-          if (child_visible_viewport_size == initial_size)
-            loop.Quit();
-        }));
-
     GURL cross_site_url(
         embedded_test_server()->GetURL("c.com", "/title2.html"));
     NavigateFrameToURL(root->child_at(0), cross_site_url);
 
     // Wait to see the size sent to the child RenderWidget.
-    loop.Run();
-
-    // The child widget was also informed of the same size.
-    EXPECT_EQ(initial_size, child_visible_viewport_size);
+    while (true) {
+      base::Optional<blink::VisualProperties> properties =
+          child_rwh->GetLastVisualPropertiesSentToRendererForTesting();
+      if (properties && properties->visible_viewport_size == initial_size)
+        break;
+      base::RunLoop().RunUntilIdle();
+    }
   }
 
   // Same check as above but for a nested WebContents.
   {
-    base::RunLoop loop;
-
-    gfx::Size child_visible_viewport_size;
-    OutgoingVisualPropertiesIPCWatcher child_watcher(
-        nested_child_rph, nested_root,
-        base::BindLambdaForTesting([&](const blink::VisualProperties& props) {
-          child_visible_viewport_size = props.visible_viewport_size;
-
-          if (child_visible_viewport_size == nested_initial_size)
-            loop.Quit();
-        }));
-
     GURL cross_site_url(
         embedded_test_server()->GetURL("c.com", "/title2.html"));
     NavigateFrameToURL(nested_root->child_at(0), cross_site_url);
 
     // Wait to see the size sent to the child RenderWidget.
-    loop.Run();
-
-    // The child widget was also informed of the same size.
-    EXPECT_EQ(nested_initial_size, child_visible_viewport_size);
+    while (true) {
+      base::Optional<blink::VisualProperties> properties =
+          nested_child_rwh->GetLastVisualPropertiesSentToRendererForTesting();
+      if (properties &&
+          properties->visible_viewport_size == nested_initial_size)
+        break;
+      base::RunLoop().RunUntilIdle();
+    }
   }
 
 // This part of the test does not work well on Android, for a few reasons:
@@ -333,36 +271,26 @@
   // Resize the top level widget to cause its |visible_viewport_size| to be
   // changed. The change should propagate down to the child RenderWidget.
   {
-    base::RunLoop loop;
-
     const gfx::Size resize_to(initial_size.width() - 10,
                               initial_size.height() - 10);
 
-    gfx::Size root_visible_viewport_size;
-    gfx::Size child_visible_viewport_size;
-    OutgoingVisualPropertiesIPCWatcher root_watcher(
-        root_rph, root,
-        base::BindLambdaForTesting([&](const blink::VisualProperties& props) {
-          root_visible_viewport_size = props.visible_viewport_size;
-        }));
-    OutgoingVisualPropertiesIPCWatcher child_watcher(
-        child_rph, root,
-        base::BindLambdaForTesting([&](const blink::VisualProperties& props) {
-          child_visible_viewport_size = props.visible_viewport_size;
-
-          if (child_visible_viewport_size == resize_to)
-            loop.Quit();
-        }));
-
     root_view->SetSize(resize_to);
 
     // Wait to see both RenderWidgets receive the message.
-    loop.Run();
-
-    // The top level widget was resized.
-    EXPECT_EQ(resize_to, root_visible_viewport_size);
-    // The child widget was also informed of the same size.
-    EXPECT_EQ(resize_to, child_visible_viewport_size);
+    while (true) {
+      base::Optional<blink::VisualProperties> properties =
+          root_rwh->GetLastVisualPropertiesSentToRendererForTesting();
+      if (properties && properties->visible_viewport_size == resize_to)
+        break;
+      base::RunLoop().RunUntilIdle();
+    }
+    while (true) {
+      base::Optional<blink::VisualProperties> properties =
+          child_rwh->GetLastVisualPropertiesSentToRendererForTesting();
+      if (properties && properties->visible_viewport_size == resize_to)
+        break;
+      base::RunLoop().RunUntilIdle();
+    }
   }
 
   // Same check as above but resizing the nested WebContents' main frame
@@ -370,27 +298,9 @@
   // Resize the top level widget to cause its |visible_viewport_size| to be
   // changed. The change should propagate down to the child RenderWidget.
   {
-    base::RunLoop loop;
-
     const gfx::Size resize_to(nested_initial_size.width() - 10,
                               nested_initial_size.height() - 10);
 
-    gfx::Size root_visible_viewport_size;
-    gfx::Size child_visible_viewport_size;
-    OutgoingVisualPropertiesIPCWatcher root_watcher(
-        nested_root_rph, nested_root,
-        base::BindLambdaForTesting([&](const blink::VisualProperties& props) {
-          root_visible_viewport_size = props.visible_viewport_size;
-        }));
-    OutgoingVisualPropertiesIPCWatcher child_watcher(
-        nested_child_rph, nested_root,
-        base::BindLambdaForTesting([&](const blink::VisualProperties& props) {
-          child_visible_viewport_size = props.visible_viewport_size;
-
-          if (child_visible_viewport_size == resize_to)
-            loop.Quit();
-        }));
-
     EXPECT_TRUE(ExecJs(
         root->current_frame_host(),
         JsReplace("document.getElementById('portal').style.width = '$1px';"
@@ -398,12 +308,20 @@
                   resize_to.width(), resize_to.height())));
 
     // Wait to see both RenderWidgets receive the message.
-    loop.Run();
-
-    // The top level widget was resized.
-    EXPECT_EQ(resize_to, root_visible_viewport_size);
-    // The child widget was also informed of the same size.
-    EXPECT_EQ(resize_to, child_visible_viewport_size);
+    while (true) {
+      base::Optional<blink::VisualProperties> properties =
+          nested_root_rwh->GetLastVisualPropertiesSentToRendererForTesting();
+      if (properties && properties->visible_viewport_size == resize_to)
+        break;
+      base::RunLoop().RunUntilIdle();
+    }
+    while (true) {
+      base::Optional<blink::VisualProperties> properties =
+          nested_child_rwh->GetLastVisualPropertiesSentToRendererForTesting();
+      if (properties && properties->visible_viewport_size == resize_to)
+        break;
+      base::RunLoop().RunUntilIdle();
+    }
   }
 
   // Informs the top-level frame it can auto-resize. It will shrink down to its
@@ -418,24 +336,7 @@
   // This property is not directly visible in the renderer, so we can only
   // check that the value is sent to both RenderWidgets.
   {
-    base::RunLoop loop;
-
     const gfx::Size auto_resize_to(105, 100);
-    gfx::Size root_visible_viewport_size;
-    gfx::Size child_visible_viewport_size;
-    OutgoingVisualPropertiesIPCWatcher root_watcher(
-        root_rph, root,
-        base::BindLambdaForTesting([&](const blink::VisualProperties& props) {
-          root_visible_viewport_size = props.visible_viewport_size;
-        }));
-    OutgoingVisualPropertiesIPCWatcher child_watcher(
-        child_rph, root,
-        base::BindLambdaForTesting([&](const blink::VisualProperties& props) {
-          child_visible_viewport_size = props.visible_viewport_size;
-
-          if (child_visible_viewport_size == auto_resize_to)
-            loop.Quit();
-        }));
 
     // Replace the WebContentsDelegate so that we can use the auto-resize
     // changes to adjust the size of the top widget.
@@ -447,12 +348,20 @@
 
     // Wait for the renderer side to resize itself and the RenderWidget
     // waterfall to pass the new |visible_viewport_size| down.
-    loop.Run();
-
-    // The top level widget was resized to match the auto-resized renderer.
-    EXPECT_EQ(auto_resize_to, root_visible_viewport_size);
-    // The child widget was also informed of the same size.
-    EXPECT_EQ(auto_resize_to, child_visible_viewport_size);
+    while (true) {
+      base::Optional<blink::VisualProperties> properties =
+          root_rwh->GetLastVisualPropertiesSentToRendererForTesting();
+      if (properties && properties->visible_viewport_size == auto_resize_to)
+        break;
+      base::RunLoop().RunUntilIdle();
+    }
+    while (true) {
+      base::Optional<blink::VisualProperties> properties =
+          child_rwh->GetLastVisualPropertiesSentToRendererForTesting();
+      if (properties && properties->visible_viewport_size == auto_resize_to)
+        break;
+      base::RunLoop().RunUntilIdle();
+    }
 
     shell()->web_contents()->SetDelegate(old_delegate);
   }
@@ -613,12 +522,8 @@
   RenderWidgetHostViewBase* root_view = root_widget->GetView();
   // Out-of-process child frame.
   FrameTreeNode* oopchild = root->child_at(0);
-  auto* oopchild_rph = static_cast<RenderProcessHostImpl*>(
-      oopchild->current_frame_host()->GetProcess());
   // Out-of-process descendant frame (child of the first oop-iframe).
   FrameTreeNode* oopdescendant = oopchild->child_at(0);
-  auto* oopdescendant_rph = static_cast<RenderProcessHostImpl*>(
-      oopdescendant->current_frame_host()->GetProcess());
 
   const gfx::Size root_view_size = root_view->GetVisibleViewportSize();
   const int kDisplayFeatureLength = 10;
@@ -634,58 +539,36 @@
       emulated_display_feature.offset, root_view_size.height());
 
   {
-    base::RunLoop loop;
-
     // Watch for visual properties changes, first to the child oop-iframe, then
     // to the descendant (at which point we're done and can validate the
     // values).
-    std::vector<gfx::Rect> oopchild_root_window_segments;
-    OutgoingVisualPropertiesIPCWatcher oopchild_watcher(
-        oopchild_rph, root,
-        base::BindLambdaForTesting([&](const blink::VisualProperties& props) {
-          oopchild_root_window_segments = props.root_widget_window_segments;
-        }));
-
-    std::vector<gfx::Rect> oopdescendant_root_window_segments;
-    OutgoingVisualPropertiesIPCWatcher oopdescendant_watcher(
-        oopdescendant_rph, root,
-        base::BindLambdaForTesting([&](const blink::VisualProperties& props) {
-          oopdescendant_root_window_segments =
-              props.root_widget_window_segments;
-          if (oopdescendant_root_window_segments == expected_segments)
-            loop.Quit();
-        }));
 
     root_view->SetDisplayFeatureForTesting(emulated_display_feature);
     root_widget->SynchronizeVisualProperties();
 
-    loop.Run();
-
-    // The child widgets must be informed of the changed window segments.
-    EXPECT_THAT(oopchild_root_window_segments,
-                ::testing::ContainerEq(expected_segments));
-    EXPECT_THAT(oopdescendant_root_window_segments,
-                ::testing::ContainerEq(expected_segments));
+    while (true) {
+      base::Optional<blink::VisualProperties> properties =
+          oopchild->current_frame_host()
+              ->GetRenderWidgetHost()
+              ->GetLastVisualPropertiesSentToRendererForTesting();
+      if (properties &&
+          properties->root_widget_window_segments == expected_segments)
+        break;
+      base::RunLoop().RunUntilIdle();
+    }
+    while (true) {
+      base::Optional<blink::VisualProperties> properties =
+          oopdescendant->current_frame_host()
+              ->GetRenderWidgetHost()
+              ->GetLastVisualPropertiesSentToRendererForTesting();
+      if (properties &&
+          properties->root_widget_window_segments == expected_segments)
+        break;
+      base::RunLoop().RunUntilIdle();
+    }
   }
 
   {
-    base::RunLoop loop;
-    std::vector<gfx::Rect> new_frame_root_window_segments;
-    OutgoingVisualPropertiesIPCWatcher oopdescendant_watcher(
-        oopdescendant_rph, root,
-        base::BindLambdaForTesting([&](const blink::VisualProperties& props) {
-          new_frame_root_window_segments = props.root_widget_window_segments;
-          // This check is needed, since we'll get an IPC originating from
-          // RenderWidgetHostImpl immediately after the frame is added with the
-          // incorrect value (the segments are cascaded from the parent renderer
-          // when the frame is added in that process). So we need to wait for
-          // the outgoing VisualProperties triggered from the parent renderer
-          // and comes in via the CrossProcessFrameConnector, which can happen
-          // after NavigateFrameToURL completes.
-          if (new_frame_root_window_segments == expected_segments)
-            loop.Quit();
-        }));
-
     // Creating a new local frame root (navigating a.com to c.com) should also
     // propagate the property to the new local frame root. Note that we're
     // re-using the existing RenderProcessHost from c.com (aka
@@ -693,10 +576,23 @@
     GURL new_frame_url(embedded_test_server()->GetURL("c.com", "/title2.html"));
     NavigateFrameToURL(root->child_at(1), new_frame_url);
 
-    loop.Run();
-
-    EXPECT_THAT(new_frame_root_window_segments,
-                ::testing::ContainerEq(expected_segments));
+    while (true) {
+      base::Optional<blink::VisualProperties> properties =
+          oopdescendant->current_frame_host()
+              ->GetRenderWidgetHost()
+              ->GetLastVisualPropertiesSentToRendererForTesting();
+      // This check is needed, since we'll get an IPC originating from
+      // RenderWidgetHostImpl immediately after the frame is added with the
+      // incorrect value (the segments are cascaded from the parent renderer
+      // when the frame is added in that process). So we need to wait for
+      // the outgoing VisualProperties triggered from the parent renderer
+      // and comes in via the CrossProcessFrameConnector, which can happen
+      // after NavigateFrameToURL completes.
+      if (properties &&
+          properties->root_widget_window_segments == expected_segments)
+        break;
+      base::RunLoop().RunUntilIdle();
+    }
   }
 }
 
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc
index b70b9d7..0bf8f71 100644
--- a/content/browser/security_exploit_browsertest.cc
+++ b/content/browser/security_exploit_browsertest.cc
@@ -1178,7 +1178,9 @@
 
 // Test which verifies that when an exploited renderer process sends a commit
 // message with URL that the process is not allowed to commit.
-IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, DidCommitInvalidURL) {
+// Disabled as per crbug.com/1106893.
+IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest,
+                       DISABLED_DidCommitInvalidURL) {
   // Explicitly isolating foo.com helps ensure that this test is applicable on
   // platforms without site-per-process.
   IsolateOrigin("foo.com");
diff --git a/content/browser/service_worker/service_worker_quota_client.cc b/content/browser/service_worker/service_worker_quota_client.cc
index 2b39dcb..6c042d74 100644
--- a/content/browser/service_worker/service_worker_quota_client.cc
+++ b/content/browser/service_worker/service_worker_quota_client.cc
@@ -20,12 +20,13 @@
 
 namespace content {
 namespace {
-void ReportToQuotaStatus(QuotaClient::DeletionCallback callback, bool status) {
+void ReportToQuotaStatus(QuotaClient::DeleteOriginDataCallback callback,
+                         bool status) {
   std::move(callback).Run(status ? blink::mojom::QuotaStatusCode::kOk
                                  : blink::mojom::QuotaStatusCode::kUnknown);
 }
 
-void FindUsageForOrigin(QuotaClient::GetUsageCallback callback,
+void FindUsageForOrigin(QuotaClient::GetOriginUsageCallback callback,
                         blink::ServiceWorkerStatusCode status,
                         int64_t usage) {
   std::move(callback).Run(usage);
@@ -42,28 +43,31 @@
 
 void ServiceWorkerQuotaClient::GetOriginUsage(const url::Origin& origin,
                                               StorageType type,
-                                              GetUsageCallback callback) {
+                                              GetOriginUsageCallback callback) {
   DCHECK_EQ(type, StorageType::kTemporary);
   context_->GetStorageUsageForOrigin(
       origin, base::BindOnce(&FindUsageForOrigin, std::move(callback)));
 }
 
-void ServiceWorkerQuotaClient::GetOriginsForType(StorageType type,
-                                                 GetOriginsCallback callback) {
+void ServiceWorkerQuotaClient::GetOriginsForType(
+    StorageType type,
+    GetOriginsForTypeCallback callback) {
   DCHECK_EQ(type, StorageType::kTemporary);
   context_->GetInstalledRegistrationOrigins(base::nullopt, std::move(callback));
 }
 
-void ServiceWorkerQuotaClient::GetOriginsForHost(StorageType type,
-                                                 const std::string& host,
-                                                 GetOriginsCallback callback) {
+void ServiceWorkerQuotaClient::GetOriginsForHost(
+    StorageType type,
+    const std::string& host,
+    GetOriginsForHostCallback callback) {
   DCHECK_EQ(type, StorageType::kTemporary);
   context_->GetInstalledRegistrationOrigins(host, std::move(callback));
 }
 
-void ServiceWorkerQuotaClient::DeleteOriginData(const url::Origin& origin,
-                                                StorageType type,
-                                                DeletionCallback callback) {
+void ServiceWorkerQuotaClient::DeleteOriginData(
+    const url::Origin& origin,
+    StorageType type,
+    DeleteOriginDataCallback callback) {
   DCHECK_EQ(type, StorageType::kTemporary);
   context_->DeleteForOrigin(
       origin, base::BindOnce(&ReportToQuotaStatus, std::move(callback)));
@@ -71,7 +75,7 @@
 
 void ServiceWorkerQuotaClient::PerformStorageCleanup(
     blink::mojom::StorageType type,
-    base::OnceClosure callback) {
+    PerformStorageCleanupCallback callback) {
   DCHECK_EQ(type, StorageType::kTemporary);
   context_->PerformStorageCleanup(std::move(callback));
 }
diff --git a/content/browser/service_worker/service_worker_quota_client.h b/content/browser/service_worker/service_worker_quota_client.h
index 885e598..56f1f5cc 100644
--- a/content/browser/service_worker/service_worker_quota_client.h
+++ b/content/browser/service_worker/service_worker_quota_client.h
@@ -29,17 +29,17 @@
   void OnQuotaManagerDestroyed() override {}
   void GetOriginUsage(const url::Origin& origin,
                       blink::mojom::StorageType type,
-                      GetUsageCallback callback) override;
+                      GetOriginUsageCallback callback) override;
   void GetOriginsForType(blink::mojom::StorageType type,
-                         GetOriginsCallback callback) override;
+                         GetOriginsForTypeCallback callback) override;
   void GetOriginsForHost(blink::mojom::StorageType type,
                          const std::string& host,
-                         GetOriginsCallback callback) override;
+                         GetOriginsForHostCallback callback) override;
   void DeleteOriginData(const url::Origin& origin,
                         blink::mojom::StorageType type,
-                        DeletionCallback callback) override;
+                        DeleteOriginDataCallback callback) override;
   void PerformStorageCleanup(blink::mojom::StorageType type,
-                             base::OnceClosure callback) override;
+                             PerformStorageCleanupCallback callback) override;
 
   static constexpr storage::QuotaClientType kType =
       storage::QuotaClientType::kServiceWorker;
diff --git a/content/browser/site_instance_impl.h b/content/browser/site_instance_impl.h
index 26b9f7d..e5d2688 100644
--- a/content/browser/site_instance_impl.h
+++ b/content/browser/site_instance_impl.h
@@ -5,8 +5,6 @@
 #ifndef CONTENT_BROWSER_SITE_INSTANCE_IMPL_H_
 #define CONTENT_BROWSER_SITE_INSTANCE_IMPL_H_
 
-#include <functional>
-
 #include <stddef.h>
 #include <stdint.h>
 
diff --git a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/TestTouchUtils.java b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/TestTouchUtils.java
index 485b818..23fbf56 100644
--- a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/TestTouchUtils.java
+++ b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/TestTouchUtils.java
@@ -203,7 +203,7 @@
      * @param v The view to call performClick on.
      */
     public static void performClickOnMainSync(Instrumentation instrumentation, final View v) {
-        instrumentation.runOnMainSync(() -> v.performClick());
+        TestThreadUtils.runOnUiThreadBlocking(() -> { v.performClick(); });
     }
 
     /**
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 695a1405..c4cba8f 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -4147,6 +4147,18 @@
                "RenderFrameImpl::didStartProvisionalLoad", "id", routing_id_,
                "url", document_loader->GetUrl().GetString().Utf8());
 
+  // Install factories as early as possible - it needs to happen before the
+  // newly committed document starts any subresource fetches.  In particular,
+  // this needs to happen before invoking
+  // RenderFrameObserver::ReadyToCommitNavigation below.
+  //
+  // Note that |pending_loader_factories_| might be missing in some cases - one
+  // example is when committing an empty document synchronously, without a
+  // roundtrip to the browser process - this is what happens as a result of
+  // `window.open('', '_blank').
+  if (pending_loader_factories_)
+    loader_factories_ = std::move(pending_loader_factories_);
+
   // TODO(dgozman): call DidStartNavigation in various places where we call
   // CommitNavigation() on the frame.
   if (!navigation_state->was_initiated_in_this_frame()) {
@@ -4159,9 +4171,6 @@
   for (auto& observer : observers_)
     observer.ReadyToCommitNavigation(document_loader);
 
-  if (pending_loader_factories_)
-    loader_factories_ = std::move(pending_loader_factories_);
-
   for (auto& observer : observers_)
     observer.DidCreateNewDocument();
 
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 4afcc24..60ade4b 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -2417,6 +2417,10 @@
     sources += [ "../browser/xr/service/xr_runtime_manager_unittest.cc" ]
     deps += [ "//device/vr:vr_fakes" ]
   }
+
+  if (is_chromecast) {
+    deps += [ "//chromecast:chromecast_buildflags" ]
+  }
 }
 
 if (enable_nocompile_tests) {
diff --git a/content/test/gpu/gpu_tests/gpu_helper.py b/content/test/gpu/gpu_tests/gpu_helper.py
index cf0a1541..5c40e6d 100644
--- a/content/test/gpu/gpu_tests/gpu_helper.py
+++ b/content/test/gpu/gpu_tests/gpu_helper.py
@@ -202,8 +202,9 @@
 
 
 # No good way to reduce the number of local variables, particularly since each
-# argument is also considered a local.
-# pylint: disable=too-many-locals
+# argument is also considered a local. Also no good way to reduce the number of
+# branches without harming readability.
+# pylint: disable=too-many-locals,too-many-branches
 def EvaluateVersionComparison(version,
                               operation,
                               ref_version,
@@ -273,7 +274,7 @@
     raise Exception('Invalid operation: ' + operation)
 
   return operation == 'eq' or operation == 'ge' or operation == 'le'
-# pylint: enable=too-many-locals
+# pylint: enable=too-many-locals,too-many-branches
 
 
 def ExpectationsDriverTags():
diff --git a/content/test/gpu/gpu_tests/gpu_integration_test.py b/content/test/gpu/gpu_tests/gpu_integration_test.py
index bf5b919..1646910f 100644
--- a/content/test/gpu/gpu_tests/gpu_integration_test.py
+++ b/content/test/gpu/gpu_tests/gpu_integration_test.py
@@ -195,7 +195,7 @@
         super(GpuIntegrationTest, cls).StartBrowser()
         cls.tab = cls.browser.tabs[0]
         return
-      except Exception:
+      except Exception:  # pylint: disable=broad-except
         logging.exception('Browser start failed (attempt %d of %d). Backtrace:',
                           x, _START_BROWSER_RETRIES)
         # If we are on the last try and there is an exception take a screenshot
diff --git a/content/test/gpu/gpu_tests/gpu_process_integration_test.py b/content/test/gpu/gpu_tests/gpu_process_integration_test.py
index 384a737..434a756e0 100644
--- a/content/test/gpu/gpu_tests/gpu_process_integration_test.py
+++ b/content/test/gpu/gpu_tests/gpu_process_integration_test.py
@@ -296,32 +296,24 @@
     feature_status_list = self.tab.EvaluateJavaScript(
         'browserBridge.gpuInfo.featureStatus.featureStatus')
     for name, status in feature_status_list.items():
-      if name == 'webgl':
-        if status != 'unavailable_software':
-          self.fail('WebGL status for SwiftShader failed: %s' % status)
-          return
-      elif name == '2d_canvas':
-        if status != 'unavailable_software':
-          self.fail('2D Canvas status for SwiftShader failed: %s' % status)
-          return
-      else:
-        pass
-    if not sys.platform.startswith('linux'):
-      # On Linux we relaunch GPU process to fallback to SwiftShader, therefore
-      # featureStatusForHardwareGpu isn't available.
-      feature_status_for_hardware_gpu_list = self.tab.EvaluateJavaScript(
-          'browserBridge.gpuInfo.featureStatusForHardwareGpu.featureStatus')
-      for name, status in feature_status_for_hardware_gpu_list.items():
-        if name == 'webgl':
-          if status != 'unavailable_off':
-            self.fail('WebGL status for hardware GPU failed: %s' % status)
-            return
-        elif name == '2d_canvas':
-          if status != 'enabled':
-            self.fail('2D Canvas status for hardware GPU failed: %s' % status)
-            return
-        else:
-          pass
+      if name == 'webgl' and status != 'unavailable_software':
+        self.fail('WebGL status for SwiftShader failed: %s' % status)
+      elif name == '2d_canvas' and status != 'unavailable_software':
+        self.fail('2D Canvas status for SwiftShader failed: %s' % status)
+
+    # On Linux we relaunch GPU process to fallback to SwiftShader, therefore
+    # featureStatusForHardwareGpu isn't available. So finish early if we're on
+    # Linux.
+    if sys.platform.startswith('linux'):
+      return
+
+    feature_status_for_hardware_gpu_list = self.tab.EvaluateJavaScript(
+        'browserBridge.gpuInfo.featureStatusForHardwareGpu.featureStatus')
+    for name, status in feature_status_for_hardware_gpu_list.items():
+      if name == 'webgl' and status != 'unavailable_off':
+        self.fail('WebGL status for hardware GPU failed: %s' % status)
+      elif name == '2d_canvas' and status != 'enabled':
+        self.fail('2D Canvas status for hardware GPU failed: %s' % status)
 
   def _GpuProcess_one_extra_workaround(self, test_path):
     # Start this test by launching the browser with no command line
diff --git a/content/test/gpu/gpu_tests/skia_gold_integration_test_base.py b/content/test/gpu/gpu_tests/skia_gold_integration_test_base.py
index f30d7de..143522b 100644
--- a/content/test/gpu/gpu_tests/skia_gold_integration_test_base.py
+++ b/content/test/gpu/gpu_tests/skia_gold_integration_test_base.py
@@ -510,7 +510,7 @@
       # related to Gold.
       try:
         self._UploadTestResultToSkiaGold(image_name, screenshot, page)
-      except Exception as gold_exception:
+      except Exception as gold_exception:  # pylint: disable=broad-except
         logging.error(str(gold_exception))
       # TODO(https://crbug.com/1043129): Switch this to just "raise" once these
       # tests are run with Python 3. Python 2's behavior with nested try/excepts
diff --git a/content/test/gpu/gpu_tests/test_expectations_unittest.py b/content/test/gpu/gpu_tests/test_expectations_unittest.py
index cfcab7f3..746d49b 100644
--- a/content/test/gpu/gpu_tests/test_expectations_unittest.py
+++ b/content/test/gpu/gpu_tests/test_expectations_unittest.py
@@ -114,7 +114,7 @@
 
 # No good way to reduce the number of return statements to the required level
 # without harming readability.
-# pylint: disable=too-many-return-statements
+# pylint: disable=too-many-return-statements,too-many-branches
 def _IsDriverTagDuplicated(driver_tag1, driver_tag2):
   if driver_tag1 == driver_tag2:
     return True
@@ -160,7 +160,7 @@
     return not gpu_helper.EvaluateVersionComparison(version1, 'le', version2)
   else:
     assert False
-# pylint: enable=too-many-return-statements
+# pylint: enable=too-many-return-statements,too-many-branches
 
 
 def _DoTagsConflict(t1, t2):
diff --git a/content/test/gpu/gpu_tests/trace_integration_test.py b/content/test/gpu/gpu_tests/trace_integration_test.py
index 4b7fef4..b98967a5 100644
--- a/content/test/gpu/gpu_tests/trace_integration_test.py
+++ b/content/test/gpu/gpu_tests/trace_integration_test.py
@@ -239,6 +239,13 @@
     return self.GetOverlayBotConfig(os_version_name, gpu.vendor_id,
                                     gpu.device_id)
 
+  def _GetAndAssertOverlayBotConfig(self):
+    overlay_bot_config = self.GetOverlayBotConfig()
+    if overlay_bot_config is None:
+      self.fail('Overlay bot config can not be determined')
+    assert overlay_bot_config.get('direct_composition', False)
+    return overlay_bot_config
+
   @staticmethod
   def _SwapChainPresentationModeToStr(presentation_mode):
     if presentation_mode == _SWAP_CHAIN_PRESENTATION_MODE_COMPOSED:
@@ -281,6 +288,40 @@
     else:
       self.fail('Trace markers for GPU category %s were not found' % category)
 
+  def _GetVideoPathExpectations(self, other_args):
+    """Helper method to get expectations for CheckVideoPath.
+
+    Args:
+      other_args: The |other_args| arg passed into the test.
+
+    Returns:
+      A _VideoExpectations instance with zero_copy, pixel_format, and no_overlay
+      filled in.
+    """
+    overlay_bot_config = self._GetAndAssertOverlayBotConfig()
+    expect_yuy2 = other_args.get('expect_yuy2', False)
+    expected = _VideoExpectations()
+    expected.zero_copy = other_args.get('zero_copy', False)
+    expected.pixel_format = "NV12"
+    expected.no_overlay = other_args.get('no_overlay', False)
+
+    supports_nv12_overlays = False
+    if overlay_bot_config.get('supports_overlays', False):
+      supports_yuy2_overlays = False
+      if overlay_bot_config['yuy2_overlay_support'] != 'NONE':
+        supports_yuy2_overlays = True
+      if overlay_bot_config['nv12_overlay_support'] != 'NONE':
+        supports_nv12_overlays = True
+      assert supports_yuy2_overlays or supports_nv12_overlays
+      if expect_yuy2 or not supports_nv12_overlays:
+        if overlay_bot_config['yuy2_overlay_support'] != 'SOFTWARE':
+          expected.pixel_format = "YUY2"
+    if not supports_nv12_overlays or overlay_bot_config[
+        'nv12_overlay_support'] == 'SOFTWARE':
+      expected.zero_copy = False
+
+    return expected
+
   def _EvaluateSuccess_CheckVideoPath(self, category, event_iterator,
                                       other_args):
     """Verifies Chrome goes down the code path as expected.
@@ -293,33 +334,8 @@
     os_name = self.browser.platform.GetOSName()
     assert os_name and os_name.lower() == 'win'
 
-    # Calculate expectations.
-    other_args = other_args if other_args is not None else {}
-    expect_yuy2 = other_args.get('expect_yuy2', False)
-    zero_copy = other_args.get('zero_copy', False)
-
-    overlay_bot_config = self.GetOverlayBotConfig()
-    if overlay_bot_config is None:
-      self.fail('Overlay bot config can not be determined')
-    assert overlay_bot_config.get('direct_composition', False)
-
-    expected_pixel_format = "NV12"
-    supports_nv12_overlays = False
-    if overlay_bot_config.get('supports_overlays', False):
-      supports_yuy2_overlays = False
-      if overlay_bot_config['yuy2_overlay_support'] != 'NONE':
-        supports_yuy2_overlays = True
-      if overlay_bot_config['nv12_overlay_support'] != 'NONE':
-        supports_nv12_overlays = True
-      assert supports_yuy2_overlays or supports_nv12_overlays
-      if expect_yuy2 or not supports_nv12_overlays:
-        if overlay_bot_config['yuy2_overlay_support'] != 'SOFTWARE':
-          expected_pixel_format = "YUY2"
-    if not supports_nv12_overlays or overlay_bot_config[
-        'nv12_overlay_support'] == 'SOFTWARE':
-      zero_copy = False
-
-    expect_no_overlay = other_args.get('no_overlay', False)
+    other_args = other_args or {}
+    expected = self._GetVideoPathExpectations(other_args)
 
     # Verify expectations through captured trace events.
     for event in event_iterator:
@@ -327,47 +343,57 @@
         continue
       if event.name != _SWAP_CHAIN_PRESENT_EVENT_NAME:
         continue
-      if expect_no_overlay:
+      if expected.no_overlay:
         self.fail('Expected no overlay got %s' % _SWAP_CHAIN_PRESENT_EVENT_NAME)
       detected_pixel_format = event.args.get('PixelFormat', None)
       if detected_pixel_format is None:
         self.fail('PixelFormat is missing from event %s' %
                   _SWAP_CHAIN_PRESENT_EVENT_NAME)
-      if expected_pixel_format != detected_pixel_format:
+      if expected.pixel_format != detected_pixel_format:
         self.fail('SwapChain pixel format mismatch, expected %s got %s' %
-                  (expected_pixel_format, detected_pixel_format))
+                  (expected.pixel_format, detected_pixel_format))
       detected_zero_copy = event.args.get('ZeroCopy', None)
       if detected_zero_copy is None:
         self.fail('ZeroCopy is missing from event %s' %
                   _SWAP_CHAIN_PRESENT_EVENT_NAME)
-      if zero_copy != detected_zero_copy:
+      if expected.zero_copy != detected_zero_copy:
         self.fail('ZeroCopy mismatch, expected %s got %s' %
-                  (zero_copy, detected_zero_copy))
+                  (expected.zero_copy, detected_zero_copy))
       break
     else:
-      if expect_no_overlay:
+      if expected.no_overlay:
         return
       self.fail(
           'Events with name %s were not found' % _SWAP_CHAIN_PRESENT_EVENT_NAME)
 
+  def _GetOverlayModeExpectations(self, other_args):
+    """Helper method to get expectations for CheckOverlayMode.
+
+    Args:
+      other_args: The |other_args| arg passed into the test.
+
+    Returns:
+      A _VideoExpectations instance with presentation_mode and no_overlay filled
+      in.
+    """
+    overlay_bot_config = self._GetAndAssertOverlayBotConfig()
+    expected = _VideoExpectations()
+    expected.presentation_mode = _SWAP_CHAIN_PRESENTATION_MODE_COMPOSED
+    expected.no_overlay = other_args.get('no_overlay', False)
+
+    if overlay_bot_config.get('supports_overlays', False):
+      if overlay_bot_config['nv12_overlay_support'] != 'SOFTWARE':
+        expected.presentation_mode = _SWAP_CHAIN_PRESENTATION_MODE_OVERLAY
+    return expected
+
   def _EvaluateSuccess_CheckOverlayMode(self, category, event_iterator,
                                         other_args):
     """Verifies video frames are promoted to overlays when supported."""
     os_name = self.browser.platform.GetOSName()
     assert os_name and os_name.lower() == 'win'
 
-    overlay_bot_config = self.GetOverlayBotConfig()
-    if overlay_bot_config is None:
-      self.fail('Overlay bot config can not be determined')
-    assert overlay_bot_config.get('direct_composition', False)
-
-    expected_presentation_mode = _SWAP_CHAIN_PRESENTATION_MODE_COMPOSED
-    if overlay_bot_config.get('supports_overlays', False):
-      if overlay_bot_config['nv12_overlay_support'] != 'SOFTWARE':
-        expected_presentation_mode = _SWAP_CHAIN_PRESENTATION_MODE_OVERLAY
-
-    other_args = other_args if other_args is not None else {}
-    expect_no_overlay = other_args.get('no_overlay', False)
+    other_args = other_args or {}
+    expected = self._GetOverlayModeExpectations(other_args)
 
     presentation_mode_history = []
     for event in event_iterator:
@@ -375,7 +401,7 @@
         continue
       if event.name != _GET_STATISTICS_EVENT_NAME:
         continue
-      if expect_no_overlay:
+      if expected.no_overlay:
         self.fail('Expected no overlay got %s' % _GET_STATISTICS_EVENT_NAME)
       detected_presentation_mode = event.args.get('CompositionMode', None)
       if detected_presentation_mode is None:
@@ -383,7 +409,7 @@
                   _GET_STATISTICS_EVENT_NAME)
       presentation_mode_history.append(detected_presentation_mode)
 
-    if expect_no_overlay:
+    if expected.no_overlay:
       return
 
     valid_entry_found = False
@@ -393,12 +419,12 @@
           or mode == _SWAP_CHAIN_GET_FRAME_STATISTICS_MEDIA_FAILED):
         # Be more tolerant to avoid test flakiness
         continue
-      if mode != expected_presentation_mode:
+      if mode != expected.presentation_mode:
         if index >= len(presentation_mode_history) // 2:
           # Be more tolerant for the first half frames in non-overlay mode.
           self.fail('SwapChain presentation mode mismatch, expected %s got %s' %
                     (TraceIntegrationTest._SwapChainPresentationModeToStr(
-                        expected_presentation_mode),
+                        expected.presentation_mode),
                      TraceIntegrationTest._SwapChainPresentationModeListToStr(
                          presentation_mode_history)))
       valid_entry_found = True
@@ -441,6 +467,16 @@
     ]
 
 
+class _VideoExpectations(object):
+  """Struct-like object for passing around video test expectations."""
+
+  def __init__(self):
+    self.pixel_format = None
+    self.zero_copy = None
+    self.no_overlay = None
+    self.presentation_mode = None
+
+
 def load_tests(loader, tests, pattern):
   del loader, tests, pattern  # Unused.
   return gpu_integration_test.LoadAllTestsInModule(sys.modules[__name__])
diff --git a/content/test/gpu/pylintrc b/content/test/gpu/pylintrc
index 28c61e9..1da35d7 100644
--- a/content/test/gpu/pylintrc
+++ b/content/test/gpu/pylintrc
@@ -2,8 +2,7 @@
 
 # Disable the message, report, category or checker with the given id(s).
 # TODO(crbug.com/1076144): Shrink this list to as small as possible.
-disable=broad-except,
-        fixme,
+disable=fixme,
         invalid-name,
         locally-disabled,
         locally-enabled,
@@ -11,7 +10,6 @@
         star-args,
         too-few-public-methods,
         too-many-arguments,
-        too-many-branches,
         too-many-function-args,
         too-many-instance-attributes,
         too-many-public-methods,
@@ -44,6 +42,11 @@
 # There are valid cases where we want to selectively enable/disable lint errors
 # in a particular file/scope, e.g. allowing protected access in unittests.
 
+# too-few-public-methods
+# This is supposedly to catch "functions disguised as classes", but we have
+# never had issues with that. We do, however, use a handful of struct-like
+# classes, which this complains about.
+
 
 [REPORTS]
 
diff --git a/courgette/ensemble_apply.cc b/courgette/ensemble_apply.cc
index 490e1829..6a60fd3c 100644
--- a/courgette/ensemble_apply.cc
+++ b/courgette/ensemble_apply.cc
@@ -419,17 +419,16 @@
                           const base::FilePath::CharType* patch_file_name,
                           const base::FilePath::CharType* new_file_name) {
   Status result = ApplyEnsemblePatch(
-      base::File(
-          base::FilePath(old_file_name),
-          base::File::FLAG_OPEN | base::File::FLAG_READ),
-      base::File(
-          base::FilePath(patch_file_name),
-          base::File::FLAG_OPEN | base::File::FLAG_READ),
-      base::File(
-          base::FilePath(new_file_name),
-          base::File::FLAG_CREATE_ALWAYS |
-              base::File::FLAG_WRITE |
-              base::File::FLAG_EXCLUSIVE_WRITE));
+      base::File(base::FilePath(old_file_name),
+                 base::File::FLAG_OPEN | base::File::FLAG_READ |
+                     base::File::FLAG_SHARE_DELETE),
+      base::File(base::FilePath(patch_file_name),
+                 base::File::FLAG_OPEN | base::File::FLAG_READ |
+                     base::File::FLAG_SHARE_DELETE),
+      base::File(base::FilePath(new_file_name),
+                 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE |
+                     base::File::FLAG_EXCLUSIVE_WRITE |
+                     base::File::FLAG_SHARE_DELETE));
   if (result != C_OK)
     base::DeleteFile(base::FilePath(new_file_name));
   return result;
diff --git a/courgette/third_party/bsdiff/bsdiff_apply.cc b/courgette/third_party/bsdiff/bsdiff_apply.cc
index 6c78fbfe6..1f4e885 100644
--- a/courgette/third_party/bsdiff/bsdiff_apply.cc
+++ b/courgette/third_party/bsdiff/bsdiff_apply.cc
@@ -230,17 +230,15 @@
                               const base::FilePath& patch_file_path,
                               const base::FilePath& new_file_path) {
   BSDiffStatus result = ApplyBinaryPatch(
-      base::File(
-          old_file_path,
-          base::File::FLAG_OPEN | base::File::FLAG_READ),
-      base::File(
-          patch_file_path,
-          base::File::FLAG_OPEN | base::File::FLAG_READ),
-      base::File(
-          new_file_path,
-          base::File::FLAG_CREATE_ALWAYS |
-              base::File::FLAG_WRITE |
-              base::File::FLAG_EXCLUSIVE_WRITE));
+      base::File(old_file_path, base::File::FLAG_OPEN | base::File::FLAG_READ |
+                                    base::File::FLAG_SHARE_DELETE),
+      base::File(patch_file_path, base::File::FLAG_OPEN |
+                                      base::File::FLAG_READ |
+                                      base::File::FLAG_SHARE_DELETE),
+      base::File(new_file_path, base::File::FLAG_CREATE_ALWAYS |
+                                    base::File::FLAG_WRITE |
+                                    base::File::FLAG_EXCLUSIVE_WRITE |
+                                    base::File::FLAG_SHARE_DELETE));
   if (result != OK)
     base::DeleteFile(new_file_path);
   return result;
diff --git a/device/bluetooth/BUILD.gn b/device/bluetooth/BUILD.gn
index 951b0cb..7648ac3c 100644
--- a/device/bluetooth/BUILD.gn
+++ b/device/bluetooth/BUILD.gn
@@ -324,6 +324,8 @@
         "dbus/bluetooth_agent_manager_client.h",
         "dbus/bluetooth_agent_service_provider.cc",
         "dbus/bluetooth_agent_service_provider.h",
+        "dbus/bluetooth_battery_client.cc",
+        "dbus/bluetooth_battery_client.h",
         "dbus/bluetooth_dbus_client_bundle.cc",
         "dbus/bluetooth_dbus_client_bundle.h",
         "dbus/bluetooth_debug_manager_client.cc",
@@ -400,6 +402,8 @@
           "dbus/fake_bluetooth_agent_manager_client.h",
           "dbus/fake_bluetooth_agent_service_provider.cc",
           "dbus/fake_bluetooth_agent_service_provider.h",
+          "dbus/fake_bluetooth_battery_client.cc",
+          "dbus/fake_bluetooth_battery_client.h",
           "dbus/fake_bluetooth_debug_manager_client.cc",
           "dbus/fake_bluetooth_debug_manager_client.h",
           "dbus/fake_bluetooth_device_client.cc",
diff --git a/device/bluetooth/bluez/bluetooth_adapter_bluez.cc b/device/bluetooth/bluez/bluetooth_adapter_bluez.cc
index d54045e..5858a029 100644
--- a/device/bluetooth/bluez/bluetooth_adapter_bluez.cc
+++ b/device/bluetooth/bluez/bluetooth_adapter_bluez.cc
@@ -40,6 +40,7 @@
 #include "device/bluetooth/dbus/bluetooth_adapter_client.h"
 #include "device/bluetooth/dbus/bluetooth_agent_manager_client.h"
 #include "device/bluetooth/dbus/bluetooth_agent_service_provider.h"
+#include "device/bluetooth/dbus/bluetooth_battery_client.h"
 #include "device/bluetooth/dbus/bluetooth_device_client.h"
 #include "device/bluetooth/dbus/bluetooth_gatt_application_service_provider.h"
 #include "device/bluetooth/dbus/bluetooth_gatt_manager_client.h"
@@ -244,6 +245,8 @@
 
   bluez::BluezDBusManager::Get()->GetBluetoothAdapterClient()->RemoveObserver(
       this);
+  bluez::BluezDBusManager::Get()->GetBluetoothBatteryClient()->RemoveObserver(
+      this);
   bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->RemoveObserver(
       this);
   bluez::BluezDBusManager::Get()->GetBluetoothInputClient()->RemoveObserver(
@@ -282,6 +285,8 @@
 
   bluez::BluezDBusManager::Get()->GetBluetoothAdapterClient()->AddObserver(
       this);
+  bluez::BluezDBusManager::Get()->GetBluetoothBatteryClient()->AddObserver(
+      this);
   bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->AddObserver(this);
   bluez::BluezDBusManager::Get()->GetBluetoothInputClient()->AddObserver(this);
   bluez::BluezDBusManager::Get()->GetBluetoothAgentManagerClient()->AddObserver(
@@ -641,6 +646,21 @@
   }
 }
 
+void BluetoothAdapterBlueZ::BatteryAdded(const dbus::ObjectPath& object_path) {
+  // TODO(b/160905767): Handle it by updating device battery percentage field.
+}
+
+void BluetoothAdapterBlueZ::BatteryRemoved(
+    const dbus::ObjectPath& object_path) {
+  // TODO(b/160905767): Handle it by updating device battery percentage field.
+}
+
+void BluetoothAdapterBlueZ::BatteryPropertyChanged(
+    const dbus::ObjectPath& object_path,
+    const std::string& property_name) {
+  // TODO(b/160905767): Handle it by updating device battery percentage field.
+}
+
 void BluetoothAdapterBlueZ::DeviceAdded(const dbus::ObjectPath& object_path) {
   DCHECK(bluez::BluezDBusManager::Get());
   bluez::BluetoothDeviceClient::Properties* properties =
diff --git a/device/bluetooth/bluez/bluetooth_adapter_bluez.h b/device/bluetooth/bluez/bluetooth_adapter_bluez.h
index 7c0caf1..673bae6 100644
--- a/device/bluetooth/bluez/bluetooth_adapter_bluez.h
+++ b/device/bluetooth/bluez/bluetooth_adapter_bluez.h
@@ -28,6 +28,7 @@
 #include "device/bluetooth/dbus/bluetooth_adapter_client.h"
 #include "device/bluetooth/dbus/bluetooth_agent_manager_client.h"
 #include "device/bluetooth/dbus/bluetooth_agent_service_provider.h"
+#include "device/bluetooth/dbus/bluetooth_battery_client.h"
 #include "device/bluetooth/dbus/bluetooth_device_client.h"
 #include "device/bluetooth/dbus/bluetooth_input_client.h"
 #include "device/bluetooth/dbus/bluetooth_profile_manager_client.h"
@@ -77,6 +78,7 @@
 class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterBlueZ final
     : public device::BluetoothAdapter,
       public bluez::BluetoothAdapterClient::Observer,
+      public bluez::BluetoothBatteryClient::Observer,
       public bluez::BluetoothDeviceClient::Observer,
       public bluez::BluetoothInputClient::Observer,
       public bluez::BluetoothAgentManagerClient::Observer,
@@ -287,6 +289,12 @@
   void AdapterPropertyChanged(const dbus::ObjectPath& object_path,
                               const std::string& property_name) override;
 
+  // bluez::BluetoothBatteryClient::Observer override.
+  void BatteryAdded(const dbus::ObjectPath& object_path) override;
+  void BatteryRemoved(const dbus::ObjectPath& object_path) override;
+  void BatteryPropertyChanged(const dbus::ObjectPath& object_path,
+                              const std::string& property_name) override;
+
   // bluez::BluetoothDeviceClient::Observer override.
   void DeviceAdded(const dbus::ObjectPath& object_path) override;
   void DeviceRemoved(const dbus::ObjectPath& object_path) override;
diff --git a/device/bluetooth/dbus/bluetooth_battery_client.cc b/device/bluetooth/dbus/bluetooth_battery_client.cc
new file mode 100644
index 0000000..96104228
--- /dev/null
+++ b/device/bluetooth/dbus/bluetooth_battery_client.cc
@@ -0,0 +1,144 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/bluetooth/dbus/bluetooth_battery_client.h"
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
+#include "dbus/bus.h"
+#include "dbus/message.h"
+#include "dbus/object_manager.h"
+#include "dbus/object_proxy.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+namespace bluez {
+
+BluetoothBatteryClient::Properties::Properties(
+    dbus::ObjectProxy* object_proxy,
+    const std::string& interface_name,
+    const PropertyChangedCallback& callback)
+    : dbus::PropertySet(object_proxy, interface_name, callback) {
+  RegisterProperty(bluetooth_battery::kPercentageProperty, &percentage);
+}
+
+BluetoothBatteryClient::Properties::~Properties() = default;
+
+// The BluetoothBatteryClient implementation used in production.
+class BluetoothBatteryClientImpl : public BluetoothBatteryClient,
+                                   public dbus::ObjectManager::Interface {
+ public:
+  BluetoothBatteryClientImpl() = default;
+
+  ~BluetoothBatteryClientImpl() override {
+    // There is an instance of this client that is created but not initialized
+    // on Linux. See 'Alternate D-Bus Client' note in bluez_dbus_manager.h.
+    if (object_manager_) {
+      object_manager_->UnregisterInterface(
+          bluetooth_adapter::kBluetoothAdapterInterface);
+    }
+  }
+
+  // BluetoothBatteryClient override.
+  void AddObserver(BluetoothBatteryClient::Observer* observer) override {
+    DCHECK(observer);
+    observers_.AddObserver(observer);
+  }
+
+  // BluetoothBatteryClient override.
+  void RemoveObserver(BluetoothBatteryClient::Observer* observer) override {
+    DCHECK(observer);
+    observers_.RemoveObserver(observer);
+  }
+
+  // dbus::ObjectManager::Interface override.
+  dbus::PropertySet* CreateProperties(
+      dbus::ObjectProxy* object_proxy,
+      const dbus::ObjectPath& object_path,
+      const std::string& interface_name) override {
+    return new Properties(
+        object_proxy, interface_name,
+        base::BindRepeating(&BluetoothBatteryClientImpl::OnPropertyChanged,
+                            weak_ptr_factory_.GetWeakPtr(), object_path));
+  }
+
+  // BluetoothBatteryClient override.
+  std::vector<dbus::ObjectPath> GetBatteriesForAdapter(
+      const dbus::ObjectPath& adapter_path) override {
+    std::vector<dbus::ObjectPath> object_paths, battery_paths;
+    battery_paths = object_manager_->GetObjectsWithInterface(
+        bluetooth_battery::kBluetoothBatteryInterface);
+    for (const auto& path : battery_paths)
+      object_paths.push_back(path);
+
+    return object_paths;
+  }
+
+  // BluetoothBatteryClient override.
+  Properties* GetProperties(const dbus::ObjectPath& object_path) override {
+    return static_cast<Properties*>(object_manager_->GetProperties(
+        object_path, bluetooth_battery::kBluetoothBatteryInterface));
+  }
+
+ protected:
+  void Init(dbus::Bus* bus,
+            const std::string& bluetooth_service_name) override {
+    object_manager_ = bus->GetObjectManager(
+        bluetooth_service_name,
+        dbus::ObjectPath(
+            bluetooth_object_manager::kBluetoothObjectManagerServicePath));
+    object_manager_->RegisterInterface(
+        bluetooth_battery::kBluetoothBatteryInterface, this);
+  }
+
+ private:
+  // Called by dbus::ObjectManager when an object with the battery interface
+  // is created. Informs observers.
+  void ObjectAdded(const dbus::ObjectPath& object_path,
+                   const std::string& interface_name) override {
+    for (auto& observer : observers_)
+      observer.BatteryAdded(object_path);
+  }
+
+  // Called by dbus::ObjectManager when an object with the battery interface
+  // is removed. Informs observers.
+  void ObjectRemoved(const dbus::ObjectPath& object_path,
+                     const std::string& interface_name) override {
+    for (auto& observer : observers_)
+      observer.BatteryRemoved(object_path);
+  }
+
+  // Called by BluetoothPropertySet when a property value is changed,
+  // either by result of a signal or response to a GetAll() or Get()
+  // call. Informs observers.
+  void OnPropertyChanged(const dbus::ObjectPath& object_path,
+                         const std::string& property_name) {
+    for (auto& observer : observers_)
+      observer.BatteryPropertyChanged(object_path, property_name);
+  }
+
+  dbus::ObjectManager* object_manager_ = nullptr;
+
+  // List of observers interested in event notifications from us.
+  base::ObserverList<BluetoothBatteryClient::Observer>::Unchecked observers_;
+
+  // Weak pointer factory for generating 'this' pointers that might live longer
+  // than we do.
+  // Note: This should remain the last member so it'll be destroyed and
+  // invalidate its weak pointers before any other members are destroyed.
+  base::WeakPtrFactory<BluetoothBatteryClientImpl> weak_ptr_factory_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(BluetoothBatteryClientImpl);
+};
+
+BluetoothBatteryClient::BluetoothBatteryClient() = default;
+
+BluetoothBatteryClient::~BluetoothBatteryClient() = default;
+
+BluetoothBatteryClient* BluetoothBatteryClient::Create() {
+  return new BluetoothBatteryClientImpl();
+}
+
+}  // namespace bluez
diff --git a/device/bluetooth/dbus/bluetooth_battery_client.h b/device/bluetooth/dbus/bluetooth_battery_client.h
new file mode 100644
index 0000000..167013f
--- /dev/null
+++ b/device/bluetooth/dbus/bluetooth_battery_client.h
@@ -0,0 +1,87 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_BLUETOOTH_DBUS_BLUETOOTH_BATTERY_CLIENT_H_
+#define DEVICE_BLUETOOTH_DBUS_BLUETOOTH_BATTERY_CLIENT_H_
+
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/observer_list.h"
+#include "base/values.h"
+#include "dbus/object_path.h"
+#include "dbus/property.h"
+#include "device/bluetooth/bluetooth_export.h"
+#include "device/bluetooth/dbus/bluez_dbus_client.h"
+
+namespace bluez {
+
+// BluetoothBatteryClient is used to communicate with objects on BlueZ's
+// org.bluez.Battery1 interface.
+class DEVICE_BLUETOOTH_EXPORT BluetoothBatteryClient : public BluezDBusClient {
+ public:
+  // Structure of properties on org.bluez.Battery1 interface.
+  struct Properties : public dbus::PropertySet {
+    // The percentage (0-100) of the battery. Read-only.
+    dbus::Property<uint8_t> percentage;
+
+    Properties(dbus::ObjectProxy* object_proxy,
+               const std::string& interface_name,
+               const PropertyChangedCallback& callback);
+    ~Properties() override;
+  };
+
+  // Interface for observing changes from a remote bluetooth battery.
+  class Observer {
+   public:
+    virtual ~Observer() = default;
+
+    // Called when the remote battery with object path |object_path| is added
+    // to the set of known batteries.
+    virtual void BatteryAdded(const dbus::ObjectPath& object_path) {}
+
+    // Called when the remote battery with object path |object_path| is removed
+    // from the set of known batteries.
+    virtual void BatteryRemoved(const dbus::ObjectPath& object_path) {}
+
+    // Called when the battery with object path |object_path| has a
+    // change in value of the property named |property_name|.
+    virtual void BatteryPropertyChanged(const dbus::ObjectPath& object_path,
+                                        const std::string& property_name) {}
+  };
+
+  ~BluetoothBatteryClient() override;
+
+  // Adds and removes observers for events on all remote bluetooth
+  // batteries. Check the |object_path| parameter of observer methods to
+  // determine which battery is issuing the event.
+  virtual void AddObserver(Observer* observer) = 0;
+  virtual void RemoveObserver(Observer* observer) = 0;
+
+  // Returns the list of battery object paths associated with the given adapter
+  // identified by the D-Bus object path |adapter_path|.
+  virtual std::vector<dbus::ObjectPath> GetBatteriesForAdapter(
+      const dbus::ObjectPath& adapter_path) = 0;
+
+  // Obtain the properties for the battery with object path |object_path|,
+  // any values should be copied if needed.
+  virtual Properties* GetProperties(const dbus::ObjectPath& object_path) = 0;
+
+  // Creates the instance.
+  static BluetoothBatteryClient* Create();
+
+ protected:
+  BluetoothBatteryClient();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BluetoothBatteryClient);
+};
+
+}  // namespace bluez
+
+#endif  // DEVICE_BLUETOOTH_DBUS_BLUETOOTH_BATTERY_CLIENT_H_
diff --git a/device/bluetooth/dbus/bluetooth_dbus_client_bundle.cc b/device/bluetooth/dbus/bluetooth_dbus_client_bundle.cc
index 7abf123e..5f784d2d 100644
--- a/device/bluetooth/dbus/bluetooth_dbus_client_bundle.cc
+++ b/device/bluetooth/dbus/bluetooth_dbus_client_bundle.cc
@@ -12,6 +12,7 @@
 #include "base/strings/string_util.h"
 #include "device/bluetooth/dbus/bluetooth_adapter_client.h"
 #include "device/bluetooth/dbus/bluetooth_agent_manager_client.h"
+#include "device/bluetooth/dbus/bluetooth_battery_client.h"
 #include "device/bluetooth/dbus/bluetooth_debug_manager_client.h"
 #include "device/bluetooth/dbus/bluetooth_device_client.h"
 #include "device/bluetooth/dbus/bluetooth_gatt_characteristic_client.h"
@@ -23,6 +24,7 @@
 #include "device/bluetooth/dbus/bluetooth_profile_manager_client.h"
 #include "device/bluetooth/dbus/fake_bluetooth_adapter_client.h"
 #include "device/bluetooth/dbus/fake_bluetooth_agent_manager_client.h"
+#include "device/bluetooth/dbus/fake_bluetooth_battery_client.h"
 #include "device/bluetooth/dbus/fake_bluetooth_debug_manager_client.h"
 #include "device/bluetooth/dbus/fake_bluetooth_device_client.h"
 #include "device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_client.h"
@@ -43,6 +45,7 @@
         BluetoothLEAdvertisingManagerClient::Create());
     bluetooth_agent_manager_client_.reset(
         BluetoothAgentManagerClient::Create());
+    bluetooth_battery_client_.reset(BluetoothBatteryClient::Create());
     bluetooth_debug_manager_client_.reset(
         BluetoothDebugManagerClient::Create());
     bluetooth_device_client_.reset(BluetoothDeviceClient::Create());
@@ -66,6 +69,7 @@
     bluetooth_le_advertising_manager_client_.reset(
         new FakeBluetoothLEAdvertisingManagerClient);
     bluetooth_agent_manager_client_.reset(new FakeBluetoothAgentManagerClient);
+    bluetooth_battery_client_.reset(new FakeBluetoothBatteryClient);
     bluetooth_debug_manager_client_.reset(new FakeBluetoothDebugManagerClient);
     bluetooth_device_client_.reset(new FakeBluetoothDeviceClient);
     bluetooth_input_client_.reset(new FakeBluetoothInputClient);
diff --git a/device/bluetooth/dbus/bluetooth_dbus_client_bundle.h b/device/bluetooth/dbus/bluetooth_dbus_client_bundle.h
index 02c63e3e..44843c4 100644
--- a/device/bluetooth/dbus/bluetooth_dbus_client_bundle.h
+++ b/device/bluetooth/dbus/bluetooth_dbus_client_bundle.h
@@ -15,6 +15,7 @@
 
 class BluetoothAdapterClient;
 class BluetoothAgentManagerClient;
+class BluetoothBatteryClient;
 class BluetoothDebugManagerClient;
 class BluetoothDeviceClient;
 class BluetoothGattCharacteristicClient;
@@ -53,6 +54,10 @@
     return bluetooth_debug_manager_client_.get();
   }
 
+  BluetoothBatteryClient* bluetooth_battery_client() {
+    return bluetooth_battery_client_.get();
+  }
+
   BluetoothDeviceClient* bluetooth_device_client() {
     return bluetooth_device_client_.get();
   }
@@ -98,6 +103,7 @@
   std::unique_ptr<BluetoothLEAdvertisingManagerClient>
       bluetooth_le_advertising_manager_client_;
   std::unique_ptr<BluetoothAgentManagerClient> bluetooth_agent_manager_client_;
+  std::unique_ptr<BluetoothBatteryClient> bluetooth_battery_client_;
   std::unique_ptr<BluetoothDebugManagerClient> bluetooth_debug_manager_client_;
   std::unique_ptr<BluetoothDeviceClient> bluetooth_device_client_;
   std::unique_ptr<BluetoothGattCharacteristicClient>
diff --git a/device/bluetooth/dbus/bluez_dbus_manager.cc b/device/bluetooth/dbus/bluez_dbus_manager.cc
index 84963a30..22b420c 100644
--- a/device/bluetooth/dbus/bluez_dbus_manager.cc
+++ b/device/bluetooth/dbus/bluez_dbus_manager.cc
@@ -23,6 +23,7 @@
 #include "device/base/features.h"
 #include "device/bluetooth/dbus/bluetooth_adapter_client.h"
 #include "device/bluetooth/dbus/bluetooth_agent_manager_client.h"
+#include "device/bluetooth/dbus/bluetooth_battery_client.h"
 #include "device/bluetooth/dbus/bluetooth_debug_manager_client.h"
 #include "device/bluetooth/dbus/bluetooth_device_client.h"
 #include "device/bluetooth/dbus/bluetooth_gatt_characteristic_client.h"
@@ -115,6 +116,11 @@
   return client_bundle_->bluetooth_debug_manager_client();
 }
 
+BluetoothBatteryClient* bluez::BluezDBusManager::GetBluetoothBatteryClient() {
+  DCHECK(object_manager_support_known_);
+  return client_bundle_->bluetooth_battery_client();
+}
+
 BluetoothDeviceClient* bluez::BluezDBusManager::GetBluetoothDeviceClient() {
   DCHECK(object_manager_support_known_);
   return client_bundle_->bluetooth_device_client();
diff --git a/device/bluetooth/dbus/bluez_dbus_manager.h b/device/bluetooth/dbus/bluez_dbus_manager.h
index 191b3d1..d38b0cf3 100644
--- a/device/bluetooth/dbus/bluez_dbus_manager.h
+++ b/device/bluetooth/dbus/bluez_dbus_manager.h
@@ -26,6 +26,7 @@
 // Style Note: Clients are sorted by names.
 class BluetoothAdapterClient;
 class BluetoothAgentManagerClient;
+class BluetoothBatteryClient;
 class BluetoothDebugManagerClient;
 class BluetoothDeviceClient;
 class BluetoothGattCharacteristicClient;
@@ -119,6 +120,7 @@
   BluetoothAdapterClient* GetBluetoothAdapterClient();
   BluetoothLEAdvertisingManagerClient* GetBluetoothLEAdvertisingManagerClient();
   BluetoothAgentManagerClient* GetBluetoothAgentManagerClient();
+  BluetoothBatteryClient* GetBluetoothBatteryClient();
   BluetoothDebugManagerClient* GetBluetoothDebugManagerClient();
   BluetoothDeviceClient* GetBluetoothDeviceClient();
   BluetoothGattCharacteristicClient* GetBluetoothGattCharacteristicClient();
diff --git a/device/bluetooth/dbus/fake_bluetooth_battery_client.cc b/device/bluetooth/dbus/fake_bluetooth_battery_client.cc
new file mode 100644
index 0000000..f5170324
--- /dev/null
+++ b/device/bluetooth/dbus/fake_bluetooth_battery_client.cc
@@ -0,0 +1,74 @@
+// Copyright (c) 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/bluetooth/dbus/fake_bluetooth_battery_client.h"
+
+#include "base/logging.h"
+#include "device/bluetooth/dbus/fake_bluetooth_adapter_client.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+namespace bluez {
+
+FakeBluetoothBatteryClient::Properties::Properties(
+    const PropertyChangedCallback& callback)
+    : BluetoothBatteryClient::Properties(
+          nullptr,
+          bluetooth_battery::kBluetoothBatteryInterface,
+          callback) {}
+
+FakeBluetoothBatteryClient::Properties::~Properties() = default;
+
+void FakeBluetoothBatteryClient::Properties::Get(
+    dbus::PropertyBase* property,
+    dbus::PropertySet::GetCallback callback) {
+  DVLOG(1) << "Get " << property->name();
+  std::move(callback).Run(false);
+}
+
+void FakeBluetoothBatteryClient::Properties::GetAll() {
+  DVLOG(1) << "GetAll";
+}
+
+void FakeBluetoothBatteryClient::Properties::Set(
+    dbus::PropertyBase* property,
+    dbus::PropertySet::SetCallback callback) {
+  DVLOG(1) << "Set " << property->name();
+  std::move(callback).Run(false);
+}
+
+FakeBluetoothBatteryClient::FakeBluetoothBatteryClient() = default;
+
+FakeBluetoothBatteryClient::~FakeBluetoothBatteryClient() = default;
+
+void FakeBluetoothBatteryClient::Init(
+    dbus::Bus* bus,
+    const std::string& bluetooth_service_name) {}
+
+void FakeBluetoothBatteryClient::AddObserver(Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void FakeBluetoothBatteryClient::RemoveObserver(Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+std::vector<dbus::ObjectPath>
+FakeBluetoothBatteryClient::GetBatteriesForAdapter(
+    const dbus::ObjectPath& adapter_path) {
+  if (adapter_path ==
+      dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath))
+    return battery_list_;
+  else
+    return std::vector<dbus::ObjectPath>();
+}
+
+FakeBluetoothBatteryClient::Properties*
+FakeBluetoothBatteryClient::GetProperties(const dbus::ObjectPath& object_path) {
+  PropertiesMap::const_iterator iter = properties_map_.find(object_path);
+  if (iter != properties_map_.end())
+    return iter->second.get();
+  return nullptr;
+}
+
+}  // namespace bluez
diff --git a/device/bluetooth/dbus/fake_bluetooth_battery_client.h b/device/bluetooth/dbus/fake_bluetooth_battery_client.h
new file mode 100644
index 0000000..c6543a9
--- /dev/null
+++ b/device/bluetooth/dbus/fake_bluetooth_battery_client.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_BLUETOOTH_DBUS_FAKE_BLUETOOTH_BATTERY_CLIENT_H_
+#define DEVICE_BLUETOOTH_DBUS_FAKE_BLUETOOTH_BATTERY_CLIENT_H_
+
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "base/observer_list.h"
+#include "dbus/object_path.h"
+#include "dbus/property.h"
+#include "device/bluetooth/bluetooth_export.h"
+#include "device/bluetooth/dbus/bluetooth_battery_client.h"
+
+namespace bluez {
+
+// FakeBluetoothBatteryClient simulates the behavior of the Bluetooth Daemon
+// battery objects and is used both in test cases in place of a mock and on
+// the Linux desktop.
+class DEVICE_BLUETOOTH_EXPORT FakeBluetoothBatteryClient
+    : public BluetoothBatteryClient {
+ public:
+  struct Properties : public BluetoothBatteryClient::Properties {
+    explicit Properties(const PropertyChangedCallback& callback);
+    ~Properties() override;
+
+    // dbus::PropertySet override
+    void Get(dbus::PropertyBase* property,
+             dbus::PropertySet::GetCallback callback) override;
+    void GetAll() override;
+    void Set(dbus::PropertyBase* property,
+             dbus::PropertySet::SetCallback callback) override;
+  };
+
+  FakeBluetoothBatteryClient();
+  ~FakeBluetoothBatteryClient() override;
+
+  // BluetoothBatteryClient overrides
+  void Init(dbus::Bus* bus, const std::string& bluetooth_service_name) override;
+  void AddObserver(Observer* observer) override;
+  void RemoveObserver(Observer* observer) override;
+  std::vector<dbus::ObjectPath> GetBatteriesForAdapter(
+      const dbus::ObjectPath& adapter_path) override;
+  Properties* GetProperties(const dbus::ObjectPath& object_path) override;
+
+ private:
+  // List of observers interested in event notifications from us.
+  base::ObserverList<Observer>::Unchecked observers_;
+
+  using PropertiesMap =
+      std::map<const dbus::ObjectPath, std::unique_ptr<Properties>>;
+  PropertiesMap properties_map_;
+  std::vector<dbus::ObjectPath> battery_list_;
+};
+
+}  // namespace bluez
+
+#endif  // DEVICE_BLUETOOTH_DBUS_FAKE_BLUETOOTH_DEVICE_CLIENT_H_
diff --git a/device/fido/cable/fido_cable_discovery.cc b/device/fido/cable/fido_cable_discovery.cc
index 790278c..beb8a0f 100644
--- a/device/fido/cable/fido_cable_discovery.cc
+++ b/device/fido/cable/fido_cable_discovery.cc
@@ -185,7 +185,6 @@
   for (auto advertisement : advertisements_) {
     advertisement.second->Unregister(base::DoNothing(), base::DoNothing());
   }
-  StopBluetoothDiscoverySession();
 
   if (adapter_)
     adapter_->RemoveObserver(this);
@@ -290,6 +289,11 @@
                                 weak_factory_.GetWeakPtr()));
 }
 
+void FidoCableDiscovery::SetDiscoverySession(
+    std::unique_ptr<BluetoothDiscoverySession> discovery_session) {
+  discovery_session_ = std::move(discovery_session);
+}
+
 void FidoCableDiscovery::DeviceAdded(BluetoothAdapter* adapter,
                                      BluetoothDevice* device) {
   if (!IsCableDevice(device))
@@ -384,7 +388,6 @@
 }
 
 void FidoCableDiscovery::StartCableDiscovery() {
-  DCHECK(!discovery_session_);
   adapter()->StartDiscoverySessionWithFilter(
       std::make_unique<BluetoothDiscoveryFilter>(
           BluetoothTransport::BLUETOOTH_TRANSPORT_LE),
@@ -397,14 +400,12 @@
 }
 
 void FidoCableDiscovery::OnStartDiscoverySession(
-    std::unique_ptr<BluetoothDiscoverySession> discovery_session) {
+    std::unique_ptr<BluetoothDiscoverySession> session) {
   FIDO_LOG(DEBUG) << "Discovery session started.";
-  discovery_session_ = std::move(discovery_session);
-
   if (has_v1_discovery_data_) {
     RecordCableV1DiscoveryEventOnce(CableV1DiscoveryEvent::kScanningStarted);
   }
-
+  SetDiscoverySession(std::move(session));
   // Advertising is delayed by 500ms to ensure that any UI has a chance to
   // appear as we don't want to start broadcasting without the user being
   // aware.
@@ -446,15 +447,6 @@
   }
 }
 
-void FidoCableDiscovery::StopBluetoothDiscoverySession() {
-  FIDO_LOG(DEBUG) << "Stopping Bluetooth discovery";
-  // BluetoothDiscoverySession::Stop() is considered deprecated, deleting the
-  // instance suffices. Note that general, other parts of Chrome or other
-  // processes on the system may still perform BLE scans, so this is only a
-  // best-effort attempt.
-  discovery_session_.reset();
-}
-
 void FidoCableDiscovery::StopAdvertisements(base::OnceClosure callback) {
   // Destructing a BluetoothAdvertisement invokes its Unregister() method, but
   // there may be references to the advertisement outside this
@@ -477,7 +469,6 @@
         cb.Run();
       },
       barrier_closure);
-
   for (auto advertisement : advertisements_) {
     advertisement.second->Unregister(barrier_closure, error_closure);
   }
@@ -544,10 +535,6 @@
   active_handshakes_.emplace_back(std::move(cable_device),
                                   std::move(*handshake_handler));
 
-  // Stop discovery and advertisements, then establish a GATT connection and
-  // begin the handshake. On some platforms (Windows), supposedly connecting is
-  // more reliable if there is no discovery running in parallel.
-  StopBluetoothDiscoverySession();
   StopAdvertisements(
       base::BindOnce(&FidoCableDiscovery::ConductEncryptionHandshake,
                      weak_factory_.GetWeakPtr(), handshake_handler_ptr,
@@ -840,7 +827,6 @@
     NOTREACHED();
   }
   StopAdvertisements(base::DoNothing());
-  StopBluetoothDiscoverySession();
   return true;
 }
 
diff --git a/device/fido/cable/fido_cable_discovery.h b/device/fido/cable/fido_cable_discovery.h
index 169a98f..5381ff8 100644
--- a/device/fido/cable/fido_cable_discovery.h
+++ b/device/fido/cable/fido_cable_discovery.h
@@ -114,18 +114,19 @@
   void OnGetAdapter(scoped_refptr<BluetoothAdapter> adapter);
   void OnSetPowered();
 
+  void SetDiscoverySession(
+      std::unique_ptr<BluetoothDiscoverySession> discovery_session);
+
   BluetoothAdapter* adapter() { return adapter_.get(); }
 
+  // Attempt to stop all on-going advertisements in best-effort basis.
+  // Once all the callbacks for Unregister() function is received, invoke
+  // |callback|.
   void StopAdvertisements(base::OnceClosure callback);
   void OnAdvertisementsStopped(base::OnceClosure callback);
-
-  void StopBluetoothDiscoverySession();
-
   void CableDeviceFound(BluetoothAdapter* adapter, BluetoothDevice* device);
-
   void ConductEncryptionHandshake(FidoCableHandshakeHandler* handshake_handler,
                                   CableDiscoveryData::Version cable_version);
-
   void ValidateAuthenticatorHandshakeMessage(
       CableDiscoveryData::Version cable_version,
       FidoCableHandshakeHandler* handshake_handler,
diff --git a/device/fido/cable/fido_cable_discovery_unittest.cc b/device/fido/cable/fido_cable_discovery_unittest.cc
index 14b9764..de13e65 100644
--- a/device/fido/cable/fido_cable_discovery_unittest.cc
+++ b/device/fido/cable/fido_cable_discovery_unittest.cc
@@ -11,7 +11,6 @@
 #include "base/containers/span.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
-#include "base/test/gmock_callback_support.h"
 #include "base/test/task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
@@ -27,7 +26,6 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using base::test::RunOnceCallback;
 using ::testing::_;
 using ::testing::NiceMock;
 using ::testing::Sequence;
@@ -155,10 +153,10 @@
 
   void ExpectUnregisterAndSucceed() {
     EXPECT_CALL(*this, Unregister(_, _))
-        .WillOnce(::testing::WithArg<0>([](auto success_cb) {
+        .WillOnce(::testing::WithArg<0>(::testing::Invoke([](auto success_cb) {
           base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
                                                         std::move(success_cb));
-        }));
+        })));
   }
 
  private:
@@ -249,12 +247,13 @@
       bool simulate_success,
       base::span<const uint8_t> expected_client_eid,
       base::StringPiece expected_uuid_formatted_client_eid,
-      Sequence sequence = Sequence()) {
-    auto advertisement =
-        base::MakeRefCounted<CableMockBluetoothAdvertisement>();
-    if (simulate_success) {
-      // All successful advertisements must be unregistered eventually.
-      advertisement->ExpectUnregisterAndSucceed();
+      Sequence sequence = Sequence(),
+      scoped_refptr<CableMockBluetoothAdvertisement> advertisement = nullptr) {
+    if (!advertisement) {
+      advertisement = base::MakeRefCounted<CableMockBluetoothAdvertisement>();
+      EXPECT_CALL(*advertisement, Unregister(_, _))
+          .WillRepeatedly(::testing::WithArg<0>(
+              [](auto callback) { std::move(callback).Run(); }));
     }
 
     EXPECT_CALL(*this,
@@ -275,14 +274,26 @@
 
   void ExpectDiscoveryWithScanCallback() {
     EXPECT_CALL(*this, StartScanWithFilter_(_, _))
-        .WillOnce(RunOnceCallback<1>(
-            false, device::UMABluetoothDiscoverySessionOutcome::SUCCESS));
+        .WillOnce(::testing::WithArg<1>([](auto& callback) {
+          std::move(callback).Run(
+              false, device::UMABluetoothDiscoverySessionOutcome::SUCCESS);
+        }));
   }
 
-  void ExpectStopDiscovery() {
-    EXPECT_CALL(*this, StopScan(_))
-        .WillOnce(RunOnceCallback<0>(
-            false, device::UMABluetoothDiscoverySessionOutcome::SUCCESS));
+  void ExpectDiscoveryWithScanCallback(
+      base::span<const uint8_t, kCableEphemeralIdSize> eid,
+      bool is_apple_device = false) {
+    EXPECT_CALL(*this, StartScanWithFilter_(_, _))
+        .WillOnce(
+            ::testing::WithArg<1>([this, eid, is_apple_device](auto& callback) {
+              std::move(callback).Run(
+                  false, device::UMABluetoothDiscoverySessionOutcome::SUCCESS);
+              if (is_apple_device) {
+                AddNewTestAppleBluetoothDevice(eid);
+              } else {
+                AddNewTestBluetoothDevice(eid);
+              }
+            }));
   }
 
  protected:
@@ -396,19 +407,12 @@
   cable_discovery->set_observer(&mock_observer);
 
   auto mock_adapter = CableMockAdapter::MakePoweredOn();
-  mock_adapter->ExpectDiscoveryWithScanCallback();
+  mock_adapter->ExpectDiscoveryWithScanCallback(kAuthenticatorEid);
   mock_adapter->ExpectRegisterAdvertisementWithResponse(
       true /* simulate_success */, kClientEid, kUuidFormattedClientEid);
-  mock_adapter->ExpectStopDiscovery();
 
   BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
   cable_discovery->Start();
-
-  // Spin until the advertisement is registered, then simulate a device being
-  // found.
-  task_environment_.FastForwardUntilNoTasksRemain();
-
-  mock_adapter->AddNewTestBluetoothDevice(kAuthenticatorEid);
   task_environment_.FastForwardUntilNoTasksRemain();
 }
 
@@ -423,17 +427,13 @@
   cable_discovery->set_observer(&mock_observer);
 
   auto mock_adapter = CableMockAdapter::MakePoweredOn();
-  mock_adapter->ExpectDiscoveryWithScanCallback();
+  mock_adapter->ExpectDiscoveryWithScanCallback(kAuthenticatorEid, true);
   mock_adapter->ExpectRegisterAdvertisementWithResponse(
       true /* simulate_success */, kClientEid, kUuidFormattedClientEid);
-  mock_adapter->ExpectStopDiscovery();
 
   BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
   cable_discovery->Start();
   task_environment_.FastForwardUntilNoTasksRemain();
-
-  mock_adapter->AddNewTestAppleBluetoothDevice(kAuthenticatorEid);
-  task_environment_.FastForwardUntilNoTasksRemain();
 }
 
 // Tests a scenario where upon broadcasting advertisement and scanning, client
@@ -450,15 +450,11 @@
   auto mock_adapter = CableMockAdapter::MakePoweredOn();
   mock_adapter->ExpectRegisterAdvertisementWithResponse(
       true /* simulate_success */, kClientEid, kUuidFormattedClientEid);
-  mock_adapter->ExpectDiscoveryWithScanCallback();
-  mock_adapter->ExpectStopDiscovery();
+  mock_adapter->ExpectDiscoveryWithScanCallback(kInvalidAuthenticatorEid);
 
   BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
   cable_discovery->Start();
   task_environment_.FastForwardUntilNoTasksRemain();
-
-  mock_adapter->AddNewTestBluetoothDevice(kInvalidAuthenticatorEid);
-  task_environment_.FastForwardUntilNoTasksRemain();
 }
 
 // Windows currently does not support multiple EIDs, so the following tests are
@@ -479,7 +475,7 @@
   auto cable_discovery =
       std::make_unique<FakeFidoCableDiscovery>(std::move(discovery_data));
   auto mock_adapter = CableMockAdapter::MakePoweredOn();
-  mock_adapter->ExpectDiscoveryWithScanCallback();
+  mock_adapter->ExpectDiscoveryWithScanCallback(kAuthenticatorEid);
 
   NiceMock<MockFidoDiscoveryObserver> mock_observer;
   EXPECT_CALL(mock_observer,
@@ -495,14 +491,10 @@
   mock_adapter->ExpectRegisterAdvertisementWithResponse(
       true /* simulate_success */, kSecondaryClientEid,
       kUuidFormattedSecondaryClientEid, sequence);
-  mock_adapter->ExpectStopDiscovery();
 
   BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
   cable_discovery->Start();
   task_environment_.FastForwardUntilNoTasksRemain();
-
-  mock_adapter->AddNewTestBluetoothDevice(kAuthenticatorEid);
-  task_environment_.FastForwardUntilNoTasksRemain();
 }
 
 // Tests a scenario where only one of the two client EID's are advertised
@@ -532,15 +524,11 @@
   mock_adapter->ExpectRegisterAdvertisementWithResponse(
       false /* simulate_success */, kSecondaryClientEid,
       kUuidFormattedSecondaryClientEid, sequence);
-  mock_adapter->ExpectDiscoveryWithScanCallback();
-  mock_adapter->ExpectStopDiscovery();
+  mock_adapter->ExpectDiscoveryWithScanCallback(kAuthenticatorEid);
 
   BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
   cable_discovery->Start();
   task_environment_.FastForwardUntilNoTasksRemain();
-
-  mock_adapter->AddNewTestBluetoothDevice(kAuthenticatorEid);
-  task_environment_.FastForwardUntilNoTasksRemain();
 }
 
 // Test the scenario when all advertisement for client EID's fails.
@@ -555,6 +543,7 @@
       std::make_unique<FakeFidoCableDiscovery>(std::move(discovery_data));
 
   NiceMock<MockFidoDiscoveryObserver> mock_observer;
+  EXPECT_CALL(mock_observer, AuthenticatorAdded(_, _)).Times(0);
   EXPECT_CALL(mock_observer, DiscoveryStarted(cable_discovery.get(), true,
                                               testing::IsEmpty()));
   cable_discovery->set_observer(&mock_observer);
@@ -568,7 +557,6 @@
       false /* simulate_success */, kSecondaryClientEid,
       kUuidFormattedSecondaryClientEid, sequence);
   mock_adapter->ExpectDiscoveryWithScanCallback();
-  mock_adapter->ExpectStopDiscovery();
 
   BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
   cable_discovery->Start();
@@ -579,12 +567,14 @@
 
 TEST_F(FidoCableDiscoveryTest, TestUnregisterAdvertisementUponDestruction) {
   auto cable_discovery = CreateDiscovery();
+  auto advertisement = base::MakeRefCounted<CableMockBluetoothAdvertisement>();
+  advertisement->ExpectUnregisterAndSucceed();
 
   auto mock_adapter = CableMockAdapter::MakePoweredOn();
   mock_adapter->ExpectDiscoveryWithScanCallback();
   mock_adapter->ExpectRegisterAdvertisementWithResponse(
       true /* simulate_success */, kClientEid, kUuidFormattedClientEid,
-      Sequence());
+      Sequence(), std::move(advertisement));
 
   BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
   cable_discovery->Start();
@@ -596,12 +586,14 @@
 
 TEST_F(FidoCableDiscoveryTest, TestUnregisterAdvertisementUponStop) {
   auto cable_discovery = CreateDiscovery();
+  auto advertisement = base::MakeRefCounted<CableMockBluetoothAdvertisement>();
+  advertisement->ExpectUnregisterAndSucceed();
 
   auto mock_adapter = CableMockAdapter::MakePoweredOn();
   mock_adapter->ExpectDiscoveryWithScanCallback();
   mock_adapter->ExpectRegisterAdvertisementWithResponse(
       true /* simulate_success */, kClientEid, kUuidFormattedClientEid,
-      Sequence());
+      Sequence(), std::move(advertisement));
 
   BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
   cable_discovery->Start();
@@ -647,10 +639,9 @@
 
   // After BluetoothAdapter is powered on, we expect that Cable discovery starts
   // again.
-  mock_adapter->ExpectDiscoveryWithScanCallback();
+  mock_adapter->ExpectDiscoveryWithScanCallback(kAuthenticatorEid);
   mock_adapter->ExpectRegisterAdvertisementWithResponse(
       true /* simulate_success */, kClientEid, kUuidFormattedClientEid);
-  mock_adapter->ExpectStopDiscovery();
 
   // Wait until error callback for SetPowered() is invoked. Then, simulate
   // Bluetooth adapter power change by invoking
@@ -669,9 +660,6 @@
 
   mock_adapter->NotifyAdapterPoweredChanged(true);
   task_environment_.FastForwardUntilNoTasksRemain();
-
-  mock_adapter->AddNewTestBluetoothDevice(kAuthenticatorEid);
-  task_environment_.FastForwardUntilNoTasksRemain();
 }
 
 }  // namespace device
diff --git a/extensions/browser/api/serial/serial_api.cc b/extensions/browser/api/serial/serial_api.cc
index a0bfd248..c7b49532 100644
--- a/extensions/browser/api/serial/serial_api.cc
+++ b/extensions/browser/api/serial/serial_api.cc
@@ -278,12 +278,13 @@
   if (!connection)
     return RespondNow(Error(kErrorSerialConnectionNotFound));
 
-  connection->Flush(base::BindOnce(&SerialFlushFunction::OnFlushed, this));
+  connection->Flush(device::mojom::SerialPortFlushMode::kReceiveAndTransmit,
+                    base::BindOnce(&SerialFlushFunction::OnFlushed, this));
   return RespondLater();
 }
 
-void SerialFlushFunction::OnFlushed(bool success) {
-  Respond(OneArgument(std::make_unique<base::Value>(success)));
+void SerialFlushFunction::OnFlushed() {
+  Respond(OneArgument(std::make_unique<base::Value>(true)));
 }
 
 SerialSetPausedFunction::SerialSetPausedFunction() = default;
diff --git a/extensions/browser/api/serial/serial_api.h b/extensions/browser/api/serial/serial_api.h
index 12e4876..a89ac74 100644
--- a/extensions/browser/api/serial/serial_api.h
+++ b/extensions/browser/api/serial/serial_api.h
@@ -186,7 +186,7 @@
   ResponseAction Run() override;
 
  private:
-  void OnFlushed(bool success);
+  void OnFlushed();
 };
 
 class SerialGetControlSignalsFunction : public SerialExtensionFunction {
diff --git a/extensions/browser/api/serial/serial_apitest.cc b/extensions/browser/api/serial/serial_apitest.cc
index 9aa02113..d14c9a9 100644
--- a/extensions/browser/api/serial/serial_apitest.cc
+++ b/extensions/browser/api/serial/serial_apitest.cc
@@ -126,7 +126,18 @@
     out_stream_watcher_.ArmOrNotify();
   }
 
-  void Flush(FlushCallback callback) override { std::move(callback).Run(true); }
+  void Flush(device::mojom::SerialPortFlushMode mode,
+             FlushCallback callback) override {
+    if (mode == device::mojom::SerialPortFlushMode::kReceiveAndTransmit) {
+      std::move(callback).Run();
+      return;
+    }
+
+    NOTREACHED();
+  }
+
+  void Drain(DrainCallback callback) override { NOTREACHED(); }
+
   void GetControlSignals(GetControlSignalsCallback callback) override {
     auto signals = device::mojom::SerialPortControlSignals::New();
     signals->dcd = true;
diff --git a/extensions/browser/api/serial/serial_connection.cc b/extensions/browser/api/serial/serial_connection.cc
index 5df8db3..465f0abc 100644
--- a/extensions/browser/api/serial/serial_connection.cc
+++ b/extensions/browser/api/serial/serial_connection.cc
@@ -474,10 +474,11 @@
       std::move(resp_callback), nullptr));
 }
 
-void SerialConnection::Flush(FlushCompleteCallback callback) const {
+void SerialConnection::Flush(device::mojom::SerialPortFlushMode mode,
+                             FlushCompleteCallback callback) const {
   DCHECK(serial_port_);
   return serial_port_->Flush(
-      mojo::WrapCallbackWithDefaultInvokeIfNotRun(std::move(callback), false));
+      mode, mojo::WrapCallbackWithDefaultInvokeIfNotRun(std::move(callback)));
 }
 
 void SerialConnection::GetControlSignals(
diff --git a/extensions/browser/api/serial/serial_connection.h b/extensions/browser/api/serial/serial_connection.h
index 29cf85cb..421ef66 100644
--- a/extensions/browser/api/serial/serial_connection.h
+++ b/extensions/browser/api/serial/serial_connection.h
@@ -110,7 +110,8 @@
   virtual void StartPolling(const ReceiveEventCallback& callback);
 
   // Flushes input and output buffers.
-  void Flush(FlushCompleteCallback callback) const;
+  void Flush(device::mojom::SerialPortFlushMode mode,
+             FlushCompleteCallback callback) const;
 
   // Configures some subset of port options for this connection.
   // Omitted options are unchanged.
diff --git a/extensions/common/api/_behavior_features.json b/extensions/common/api/_behavior_features.json
index 3ce4bff..950be70 100644
--- a/extensions/common/api/_behavior_features.json
+++ b/extensions/common/api/_behavior_features.json
@@ -13,14 +13,14 @@
   "do_not_sync": {
     "channel": "stable",
     "component_extensions_auto_granted": false,
-    "extension_types": "all",
+    "extension_types": ["extension"],
     "whitelist": [
       "226CF815E39A363090A1E547D53063472B8279FA"   // Media Router Stable
     ]
   },
   "zoom_without_bubble": {
     "channel": "stable",
-    "extension_types": "all",
+    "extension_types": ["extension"],
     "whitelist": [
       "CBCC42ABED43A4B58FE3810E62AFFA010EB0349F"   // https://crbug.com/538252
     ]
diff --git a/extensions/common/api/extensions_manifest_types.json b/extensions/common/api/extensions_manifest_types.json
index 0c2f12dd..7157156 100644
--- a/extensions/common/api/extensions_manifest_types.json
+++ b/extensions/common/api/extensions_manifest_types.json
@@ -91,7 +91,7 @@
             "type": "string"
           },
           "chrome_style": {
-            "description": "If <code>true</code>, a Chrome user agent stylesheet will be applied to your options page. The default value is <code>false</code>, but we recommend you enable it for a consistent UI with Chrome.",
+            "description": "If <code>true</code>, a Chrome user agent stylesheet will be applied to your options page. The default value is <code>false</code>. We do not recommend you enable it as it no longer results in a consistent UI with Chrome. This option will be removed in Manifest V3.",
             "optional": true,
             "type": "boolean"
           },
diff --git a/extensions/common/manifest_constants.cc b/extensions/common/manifest_constants.cc
index 598b1cdcc..ab260bab 100644
--- a/extensions/common/manifest_constants.cc
+++ b/extensions/common/manifest_constants.cc
@@ -312,6 +312,8 @@
 const char kCannotScriptNtp[] = "The New Tab Page cannot be scripted.";
 const char kCannotScriptSigninPage[] =
     "The sign-in page cannot be scripted.";
+const char kChromeStyleInvalidForManifestV3[] =
+    "The chrome_style option cannot be used with manifest version 3.";
 const char kChromeVersionTooLow[] =
     "This extension requires * version * or greater.";
 const char kDeclarativeNetRequestPermissionNeeded[] =
diff --git a/extensions/common/manifest_constants.h b/extensions/common/manifest_constants.h
index ebe69de..5272707 100644
--- a/extensions/common/manifest_constants.h
+++ b/extensions/common/manifest_constants.h
@@ -283,6 +283,7 @@
 extern const char kCannotScriptNtp[];
 extern const char kCannotScriptSigninPage[];
 extern const char kCannotUninstallManagedExtension[];
+extern const char kChromeStyleInvalidForManifestV3[];
 extern const char kChromeVersionTooLow[];
 extern const char kDeclarativeNetRequestPermissionNeeded[];
 extern const char kDefaultStateShouldNotBeSet[];
diff --git a/extensions/common/manifest_handlers/options_page_info.cc b/extensions/common/manifest_handlers/options_page_info.cc
index c8cddb38..51aba51 100644
--- a/extensions/common/manifest_handlers/options_page_info.cc
+++ b/extensions/common/manifest_handlers/options_page_info.cc
@@ -144,8 +144,14 @@
         install_warnings->push_back(
             InstallWarning(base::UTF16ToASCII(options_parse_error)));
       }
-      if (options_ui->chrome_style.get())
-        chrome_style = *options_ui->chrome_style;
+      if (options_ui->chrome_style.get()) {
+        if (extension->manifest_version() < 3)
+          chrome_style = *options_ui->chrome_style;
+        else {
+          *error = base::ASCIIToUTF16(errors::kChromeStyleInvalidForManifestV3);
+          return nullptr;
+        }
+      }
       open_in_tab = false;
       if (options_ui->open_in_tab.get())
         open_in_tab = *options_ui->open_in_tab;
diff --git a/gpu/command_buffer/build_raster_cmd_buffer.py b/gpu/command_buffer/build_raster_cmd_buffer.py
index 281dd77..25fe5cd6 100755
--- a/gpu/command_buffer/build_raster_cmd_buffer.py
+++ b/gpu/command_buffer/build_raster_cmd_buffer.py
@@ -197,6 +197,14 @@
     'unit_test': False,
     'trace_level': 2,
   },
+  'ReadbackImagePixelsINTERNAL': {
+    'decoder_func': 'DoReadbackImagePixelsINTERNAL',
+    'internal': True,
+    'type': 'PUT',
+    'count': 16,  # GL_MAILBOX_SIZE_CHROMIUM
+    'unit_test': False,
+    'trace_level': 2,
+  },
   'ConvertYUVMailboxesToRGBINTERNAL': {
     'decoder_func': 'DoConvertYUVMailboxesToRGBINTERNAL',
     'internal': True,
diff --git a/gpu/command_buffer/client/raster_cmd_helper_autogen.h b/gpu/command_buffer/client/raster_cmd_helper_autogen.h
index ad373f2..1f3a658 100644
--- a/gpu/command_buffer/client/raster_cmd_helper_autogen.h
+++ b/gpu/command_buffer/client/raster_cmd_helper_autogen.h
@@ -227,6 +227,28 @@
   }
 }
 
+void ReadbackImagePixelsINTERNALImmediate(GLint src_x,
+                                          GLint src_y,
+                                          GLuint dst_width,
+                                          GLuint dst_height,
+                                          GLuint row_bytes,
+                                          GLuint dst_sk_color_type,
+                                          GLuint dst_sk_alpha_type,
+                                          GLint shm_id,
+                                          GLuint shm_offset,
+                                          GLuint pixels_offset,
+                                          const GLbyte* mailbox) {
+  const uint32_t size =
+      raster::cmds::ReadbackImagePixelsINTERNALImmediate::ComputeSize();
+  raster::cmds::ReadbackImagePixelsINTERNALImmediate* c =
+      GetImmediateCmdSpaceTotalSize<
+          raster::cmds::ReadbackImagePixelsINTERNALImmediate>(size);
+  if (c) {
+    c->Init(src_x, src_y, dst_width, dst_height, row_bytes, dst_sk_color_type,
+            dst_sk_alpha_type, shm_id, shm_offset, pixels_offset, mailbox);
+  }
+}
+
 void ConvertYUVMailboxesToRGBINTERNALImmediate(GLenum planes_yuv_color_space,
                                                GLboolean is_nv12,
                                                const GLbyte* mailboxes) {
diff --git a/gpu/command_buffer/client/raster_implementation.cc b/gpu/command_buffer/client/raster_implementation.cc
index f1b93c14..cbc75f0 100644
--- a/gpu/command_buffer/client/raster_implementation.cc
+++ b/gpu/command_buffer/client/raster_implementation.cc
@@ -1306,6 +1306,45 @@
   NOTREACHED();
 }
 
+void RasterImplementation::ReadbackImagePixels(
+    const gpu::Mailbox& source_mailbox,
+    const SkImageInfo& dst_info,
+    GLuint dst_row_bytes,
+    int src_x,
+    int src_y,
+    void* dst_pixels) {
+  DCHECK_GE(dst_row_bytes, dst_info.minRowBytes());
+
+  // Get the size of the SkColorSpace while maintaining 8-byte alignment.
+  GLuint pixels_offset = 0;
+  if (dst_info.colorSpace()) {
+    pixels_offset = base::bits::Align(
+        dst_info.colorSpace()->writeToMemory(nullptr), sizeof(uint64_t));
+  }
+
+  GLuint dst_size = dst_info.computeByteSize(dst_row_bytes);
+  GLuint total_size =
+      pixels_offset + base::bits::Align(dst_size, sizeof(uint64_t));
+
+  ScopedSharedMemoryPtr scoped_shared_memory(total_size, transfer_buffer_,
+                                             mapped_memory_.get(), helper());
+  GLint shm_id = scoped_shared_memory.shm_id();
+  GLuint shm_offset = scoped_shared_memory.offset();
+  void* address = scoped_shared_memory.address();
+
+  if (dst_info.colorSpace()) {
+    size_t bytes_written = dst_info.colorSpace()->writeToMemory(address);
+    DCHECK_LE(bytes_written, pixels_offset);
+  }
+
+  helper_->ReadbackImagePixelsINTERNALImmediate(
+      src_x, src_y, dst_info.width(), dst_info.height(), dst_row_bytes,
+      dst_info.colorType(), dst_info.alphaType(), shm_id, shm_offset,
+      pixels_offset, source_mailbox.name);
+  WaitForCmd();
+  memcpy(dst_pixels, static_cast<uint8_t*>(address) + pixels_offset, dst_size);
+}
+
 void RasterImplementation::IssueImageDecodeCacheEntryCreation(
     base::span<const uint8_t> encoded_data,
     const gfx::Size& output_size,
diff --git a/gpu/command_buffer/client/raster_implementation.h b/gpu/command_buffer/client/raster_implementation.h
index c5d04b1..1d53503 100644
--- a/gpu/command_buffer/client/raster_implementation.h
+++ b/gpu/command_buffer/client/raster_implementation.h
@@ -183,6 +183,12 @@
       const gfx::Point& paste_location,
       base::OnceCallback<void()> release_mailbox,
       base::OnceCallback<void(bool)> readback_done) override;
+  void ReadbackImagePixels(const gpu::Mailbox& source_mailbox,
+                           const SkImageInfo& dst_info,
+                           GLuint dst_row_bytes,
+                           int src_x,
+                           int src_y,
+                           void* dst_pixels) override;
   GLuint CreateAndConsumeForGpuRaster(const gpu::Mailbox& mailbox) override;
   void DeleteGpuRasterTexture(GLuint texture) override;
   void BeginGpuRaster() override;
diff --git a/gpu/command_buffer/client/raster_implementation_gles.cc b/gpu/command_buffer/client/raster_implementation_gles.cc
index 299dd4f..997a1422 100644
--- a/gpu/command_buffer/client/raster_implementation_gles.cc
+++ b/gpu/command_buffer/client/raster_implementation_gles.cc
@@ -366,6 +366,16 @@
   std::move(release_mailbox).Run();
 }
 
+void RasterImplementationGLES::ReadbackImagePixels(
+    const gpu::Mailbox& source_mailbox,
+    const SkImageInfo& dst_info,
+    GLuint dst_row_bytes,
+    int src_x,
+    int src_y,
+    void* dst_pixels) {
+  NOTREACHED();
+}
+
 GLuint RasterImplementationGLES::CreateAndConsumeForGpuRaster(
     const gpu::Mailbox& mailbox) {
   return mailbox.IsSharedImage()
diff --git a/gpu/command_buffer/client/raster_implementation_gles.h b/gpu/command_buffer/client/raster_implementation_gles.h
index d52ad7a..10739bb 100644
--- a/gpu/command_buffer/client/raster_implementation_gles.h
+++ b/gpu/command_buffer/client/raster_implementation_gles.h
@@ -137,6 +137,13 @@
       base::OnceCallback<void()> release_mailbox,
       base::OnceCallback<void(bool)> readback_done) override;
 
+  void ReadbackImagePixels(const gpu::Mailbox& source_mailbox,
+                           const SkImageInfo& dst_info,
+                           GLuint dst_row_bytes,
+                           int src_x,
+                           int src_y,
+                           void* dst_pixels) override;
+
   // Raster via GrContext.
   GLuint CreateAndConsumeForGpuRaster(const gpu::Mailbox& mailbox) override;
   void DeleteGpuRasterTexture(GLuint texture) override;
diff --git a/gpu/command_buffer/client/raster_interface.h b/gpu/command_buffer/client/raster_interface.h
index 2452f5ab..046e3e45 100644
--- a/gpu/command_buffer/client/raster_interface.h
+++ b/gpu/command_buffer/client/raster_interface.h
@@ -146,6 +146,15 @@
       base::OnceCallback<void()> release_mailbox,
       base::OnceCallback<void(bool)> readback_done) = 0;
 
+  // Synchronously does a readback of SkImage pixels from |source_mailbox| into
+  // caller-owned memory |dst_pixels|.
+  virtual void ReadbackImagePixels(const gpu::Mailbox& source_mailbox,
+                                   const SkImageInfo& dst_info,
+                                   GLuint dst_row_bytes,
+                                   int src_x,
+                                   int src_y,
+                                   void* dst_pixels) = 0;
+
   // Raster via GrContext.
   virtual GLuint CreateAndConsumeForGpuRaster(const gpu::Mailbox& mailbox) = 0;
   virtual void DeleteGpuRasterTexture(GLuint texture) = 0;
diff --git a/gpu/command_buffer/common/raster_cmd_format_autogen.h b/gpu/command_buffer/common/raster_cmd_format_autogen.h
index 1ac558c..0c94bc9 100644
--- a/gpu/command_buffer/common/raster_cmd_format_autogen.h
+++ b/gpu/command_buffer/common/raster_cmd_format_autogen.h
@@ -985,6 +985,118 @@
     offsetof(WritePixelsINTERNALImmediate, pixels_offset) == 40,
     "offset of WritePixelsINTERNALImmediate pixels_offset should be 40");
 
+struct ReadbackImagePixelsINTERNALImmediate {
+  typedef ReadbackImagePixelsINTERNALImmediate ValueType;
+  static const CommandId kCmdId = kReadbackImagePixelsINTERNALImmediate;
+  static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(2);
+
+  static uint32_t ComputeDataSize() {
+    return static_cast<uint32_t>(sizeof(GLbyte) * 16);
+  }
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType) + ComputeDataSize());
+  }
+
+  void SetHeader() { header.SetCmdByTotalSize<ValueType>(ComputeSize()); }
+
+  void Init(GLint _src_x,
+            GLint _src_y,
+            GLuint _dst_width,
+            GLuint _dst_height,
+            GLuint _row_bytes,
+            GLuint _dst_sk_color_type,
+            GLuint _dst_sk_alpha_type,
+            GLint _shm_id,
+            GLuint _shm_offset,
+            GLuint _pixels_offset,
+            const GLbyte* _mailbox) {
+    SetHeader();
+    src_x = _src_x;
+    src_y = _src_y;
+    dst_width = _dst_width;
+    dst_height = _dst_height;
+    row_bytes = _row_bytes;
+    dst_sk_color_type = _dst_sk_color_type;
+    dst_sk_alpha_type = _dst_sk_alpha_type;
+    shm_id = _shm_id;
+    shm_offset = _shm_offset;
+    pixels_offset = _pixels_offset;
+    memcpy(ImmediateDataAddress(this), _mailbox, ComputeDataSize());
+  }
+
+  void* Set(void* cmd,
+            GLint _src_x,
+            GLint _src_y,
+            GLuint _dst_width,
+            GLuint _dst_height,
+            GLuint _row_bytes,
+            GLuint _dst_sk_color_type,
+            GLuint _dst_sk_alpha_type,
+            GLint _shm_id,
+            GLuint _shm_offset,
+            GLuint _pixels_offset,
+            const GLbyte* _mailbox) {
+    static_cast<ValueType*>(cmd)->Init(
+        _src_x, _src_y, _dst_width, _dst_height, _row_bytes, _dst_sk_color_type,
+        _dst_sk_alpha_type, _shm_id, _shm_offset, _pixels_offset, _mailbox);
+    const uint32_t size = ComputeSize();
+    return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+  }
+
+  gpu::CommandHeader header;
+  int32_t src_x;
+  int32_t src_y;
+  uint32_t dst_width;
+  uint32_t dst_height;
+  uint32_t row_bytes;
+  uint32_t dst_sk_color_type;
+  uint32_t dst_sk_alpha_type;
+  int32_t shm_id;
+  uint32_t shm_offset;
+  uint32_t pixels_offset;
+};
+
+static_assert(sizeof(ReadbackImagePixelsINTERNALImmediate) == 44,
+              "size of ReadbackImagePixelsINTERNALImmediate should be 44");
+static_assert(
+    offsetof(ReadbackImagePixelsINTERNALImmediate, header) == 0,
+    "offset of ReadbackImagePixelsINTERNALImmediate header should be 0");
+static_assert(
+    offsetof(ReadbackImagePixelsINTERNALImmediate, src_x) == 4,
+    "offset of ReadbackImagePixelsINTERNALImmediate src_x should be 4");
+static_assert(
+    offsetof(ReadbackImagePixelsINTERNALImmediate, src_y) == 8,
+    "offset of ReadbackImagePixelsINTERNALImmediate src_y should be 8");
+static_assert(
+    offsetof(ReadbackImagePixelsINTERNALImmediate, dst_width) == 12,
+    "offset of ReadbackImagePixelsINTERNALImmediate dst_width should be 12");
+static_assert(
+    offsetof(ReadbackImagePixelsINTERNALImmediate, dst_height) == 16,
+    "offset of ReadbackImagePixelsINTERNALImmediate dst_height should be 16");
+static_assert(
+    offsetof(ReadbackImagePixelsINTERNALImmediate, row_bytes) == 20,
+    "offset of ReadbackImagePixelsINTERNALImmediate row_bytes should be 20");
+static_assert(offsetof(ReadbackImagePixelsINTERNALImmediate,
+                       dst_sk_color_type) == 24,
+              "offset of ReadbackImagePixelsINTERNALImmediate "
+              "dst_sk_color_type should be 24");
+static_assert(offsetof(ReadbackImagePixelsINTERNALImmediate,
+                       dst_sk_alpha_type) == 28,
+              "offset of ReadbackImagePixelsINTERNALImmediate "
+              "dst_sk_alpha_type should be 28");
+static_assert(
+    offsetof(ReadbackImagePixelsINTERNALImmediate, shm_id) == 32,
+    "offset of ReadbackImagePixelsINTERNALImmediate shm_id should be 32");
+static_assert(
+    offsetof(ReadbackImagePixelsINTERNALImmediate, shm_offset) == 36,
+    "offset of ReadbackImagePixelsINTERNALImmediate shm_offset should be 36");
+static_assert(offsetof(ReadbackImagePixelsINTERNALImmediate, pixels_offset) ==
+                  40,
+              "offset of ReadbackImagePixelsINTERNALImmediate pixels_offset "
+              "should be 40");
+
 struct ConvertYUVMailboxesToRGBINTERNALImmediate {
   typedef ConvertYUVMailboxesToRGBINTERNALImmediate ValueType;
   static const CommandId kCmdId = kConvertYUVMailboxesToRGBINTERNALImmediate;
diff --git a/gpu/command_buffer/common/raster_cmd_format_test_autogen.h b/gpu/command_buffer/common/raster_cmd_format_test_autogen.h
index c74f1ea..a18da15 100644
--- a/gpu/command_buffer/common/raster_cmd_format_test_autogen.h
+++ b/gpu/command_buffer/common/raster_cmd_format_test_autogen.h
@@ -405,6 +405,52 @@
       next_cmd, sizeof(cmd) + RoundSizeToMultipleOfEntries(sizeof(data)));
 }
 
+TEST_F(RasterFormatTest, ReadbackImagePixelsINTERNALImmediate) {
+  const int kSomeBaseValueToTestWith = 51;
+  static GLbyte data[] = {
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 0),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 1),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 2),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 3),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 4),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 5),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 6),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 7),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 8),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 9),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 10),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 11),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 12),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 13),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 14),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 15),
+  };
+  cmds::ReadbackImagePixelsINTERNALImmediate& cmd =
+      *GetBufferAs<cmds::ReadbackImagePixelsINTERNALImmediate>();
+  void* next_cmd = cmd.Set(
+      &cmd, static_cast<GLint>(11), static_cast<GLint>(12),
+      static_cast<GLuint>(13), static_cast<GLuint>(14), static_cast<GLuint>(15),
+      static_cast<GLuint>(16), static_cast<GLuint>(17), static_cast<GLint>(18),
+      static_cast<GLuint>(19), static_cast<GLuint>(20), data);
+  EXPECT_EQ(
+      static_cast<uint32_t>(cmds::ReadbackImagePixelsINTERNALImmediate::kCmdId),
+      cmd.header.command);
+  EXPECT_EQ(sizeof(cmd) + RoundSizeToMultipleOfEntries(sizeof(data)),
+            cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLint>(11), cmd.src_x);
+  EXPECT_EQ(static_cast<GLint>(12), cmd.src_y);
+  EXPECT_EQ(static_cast<GLuint>(13), cmd.dst_width);
+  EXPECT_EQ(static_cast<GLuint>(14), cmd.dst_height);
+  EXPECT_EQ(static_cast<GLuint>(15), cmd.row_bytes);
+  EXPECT_EQ(static_cast<GLuint>(16), cmd.dst_sk_color_type);
+  EXPECT_EQ(static_cast<GLuint>(17), cmd.dst_sk_alpha_type);
+  EXPECT_EQ(static_cast<GLint>(18), cmd.shm_id);
+  EXPECT_EQ(static_cast<GLuint>(19), cmd.shm_offset);
+  EXPECT_EQ(static_cast<GLuint>(20), cmd.pixels_offset);
+  CheckBytesWrittenMatchesExpectedSize(
+      next_cmd, sizeof(cmd) + RoundSizeToMultipleOfEntries(sizeof(data)));
+}
+
 TEST_F(RasterFormatTest, ConvertYUVMailboxesToRGBINTERNALImmediate) {
   const int kSomeBaseValueToTestWith = 51;
   static GLbyte data[] = {
diff --git a/gpu/command_buffer/common/raster_cmd_ids_autogen.h b/gpu/command_buffer/common/raster_cmd_ids_autogen.h
index 0a0da94..00359c37 100644
--- a/gpu/command_buffer/common/raster_cmd_ids_autogen.h
+++ b/gpu/command_buffer/common/raster_cmd_ids_autogen.h
@@ -32,10 +32,11 @@
   OP(ClearPaintCacheINTERNAL)                    /* 273 */ \
   OP(CopySubTextureINTERNALImmediate)            /* 274 */ \
   OP(WritePixelsINTERNALImmediate)               /* 275 */ \
-  OP(ConvertYUVMailboxesToRGBINTERNALImmediate)  /* 276 */ \
-  OP(TraceBeginCHROMIUM)                         /* 277 */ \
-  OP(TraceEndCHROMIUM)                           /* 278 */ \
-  OP(SetActiveURLCHROMIUM)                       /* 279 */
+  OP(ReadbackImagePixelsINTERNALImmediate)       /* 276 */ \
+  OP(ConvertYUVMailboxesToRGBINTERNALImmediate)  /* 277 */ \
+  OP(TraceBeginCHROMIUM)                         /* 278 */ \
+  OP(TraceEndCHROMIUM)                           /* 279 */ \
+  OP(SetActiveURLCHROMIUM)                       /* 280 */
 
 enum CommandId {
   kOneBeforeStartPoint =
diff --git a/gpu/command_buffer/raster_cmd_buffer_functions.txt b/gpu/command_buffer/raster_cmd_buffer_functions.txt
index aece272..7debe3e 100644
--- a/gpu/command_buffer/raster_cmd_buffer_functions.txt
+++ b/gpu/command_buffer/raster_cmd_buffer_functions.txt
@@ -38,6 +38,7 @@
 // |mailboxes| argument is the concatenation of the source mailbox and the destination mailbox (32 bytes total)
 GL_APICALL void         GL_APIENTRY glCopySubTextureINTERNAL (GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, GLboolean unpack_flip_y, GLboolean unpack_premultiply_alpha, const GLbyte* mailboxes);
 GL_APICALL void         GL_APIENTRY glWritePixelsINTERNAL (GLint x_offset, GLint y_offset, GLuint src_width, GLuint src_height, GLuint row_bytes, GLuint src_sk_color_type, GLuint src_sk_alpha_type, GLint shm_id, GLuint shm_offset, GLuint pixels_offset, const GLbyte* mailbox);
+GL_APICALL void         GL_APIENTRY glReadbackImagePixelsINTERNAL (GLint src_x, GLint src_y, GLuint dst_width, GLuint dst_height, GLuint row_bytes, GLuint dst_sk_color_type, GLuint dst_sk_alpha_type, GLint shm_id, GLuint shm_offset, GLuint pixels_offset, const GLbyte* mailbox);
 GL_APICALL void         GL_APIENTRY glConvertYUVMailboxesToRGBINTERNAL (GLenum planes_yuv_color_space, GLboolean is_nv12, const GLbyte* mailboxes);
 GL_APICALL void         GL_APIENTRY glTraceBeginCHROMIUM (const char* category_name, const char* trace_name);
 GL_APICALL void         GL_APIENTRY glTraceEndCHROMIUM (void);
diff --git a/gpu/command_buffer/service/external_vk_image_backing.cc b/gpu/command_buffer/service/external_vk_image_backing.cc
index d58823c0..39200b0 100644
--- a/gpu/command_buffer/service/external_vk_image_backing.cc
+++ b/gpu/command_buffer/service/external_vk_image_backing.cc
@@ -156,6 +156,8 @@
     viz::ResourceFormat format,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage,
     const VulkanImageUsageCache* image_usage_cache,
     base::span<const uint8_t> pixel_data,
@@ -222,8 +224,8 @@
   bool use_separate_gl_texture = UseSeparateGLTexture(context_state, format);
   auto backing = std::make_unique<ExternalVkImageBacking>(
       util::PassKey<ExternalVkImageBacking>(), mailbox, format, size,
-      color_space, usage, context_state, std::move(image), command_pool,
-      use_separate_gl_texture);
+      color_space, surface_origin, alpha_type, usage, context_state,
+      std::move(image), command_pool, use_separate_gl_texture);
 
   if (!pixel_data.empty()) {
     size_t stride = BitsPerPixel(format) / 8 * size.width();
@@ -242,6 +244,8 @@
     gfx::BufferFormat buffer_format,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage,
     const VulkanImageUsageCache* image_usage_cache) {
   if (!gpu::IsImageSizeValidForGpuMemoryBufferFormat(size, buffer_format)) {
@@ -266,8 +270,8 @@
         UseSeparateGLTexture(context_state, resource_format);
     auto backing = std::make_unique<ExternalVkImageBacking>(
         util::PassKey<ExternalVkImageBacking>(), mailbox, resource_format, size,
-        color_space, usage, context_state, std::move(image), command_pool,
-        use_separate_gl_texture);
+        color_space, surface_origin, alpha_type, usage, context_state,
+        std::move(image), command_pool, use_separate_gl_texture);
     backing->SetCleared();
     return backing;
   }
@@ -283,9 +287,10 @@
   if (!shared_memory_wrapper.Initialize(handle, size, resource_format))
     return nullptr;
 
-  auto backing = Create(context_state, command_pool, mailbox, resource_format,
-                        size, color_space, usage, image_usage_cache,
-                        base::span<const uint8_t>(), true /* using_gmb */);
+  auto backing =
+      Create(context_state, command_pool, mailbox, resource_format, size,
+             color_space, surface_origin, alpha_type, usage, image_usage_cache,
+             base::span<const uint8_t>(), true /* using_gmb */);
   if (!backing)
     return nullptr;
 
@@ -299,6 +304,8 @@
     viz::ResourceFormat format,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage,
     SharedContextState* context_state,
     std::unique_ptr<VulkanImage> image,
@@ -308,6 +315,8 @@
                                       format,
                                       size,
                                       color_space,
+                                      surface_origin,
+                                      alpha_type,
                                       usage,
                                       image->device_size(),
                                       false /* is_thread_safe */),
diff --git a/gpu/command_buffer/service/external_vk_image_backing.h b/gpu/command_buffer/service/external_vk_image_backing.h
index 442bdaf..840772a 100644
--- a/gpu/command_buffer/service/external_vk_image_backing.h
+++ b/gpu/command_buffer/service/external_vk_image_backing.h
@@ -41,6 +41,8 @@
       viz::ResourceFormat format,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage,
       const VulkanImageUsageCache* image_usage_cache,
       base::span<const uint8_t> pixel_data,
@@ -54,6 +56,8 @@
       gfx::BufferFormat buffer_format,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage,
       const VulkanImageUsageCache* image_usage_cache);
 
@@ -62,6 +66,8 @@
                          viz::ResourceFormat format,
                          const gfx::Size& size,
                          const gfx::ColorSpace& color_space,
+                         GrSurfaceOrigin surface_origin,
+                         SkAlphaType alpha_type,
                          uint32_t usage,
                          SharedContextState* context_state,
                          std::unique_ptr<VulkanImage> image,
diff --git a/gpu/command_buffer/service/external_vk_image_factory.cc b/gpu/command_buffer/service/external_vk_image_factory.cc
index 86441a1..be1f1ad 100644
--- a/gpu/command_buffer/service/external_vk_image_factory.cc
+++ b/gpu/command_buffer/service/external_vk_image_factory.cc
@@ -86,12 +86,15 @@
     SurfaceHandle surface_handle,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage,
     bool is_thread_safe) {
   DCHECK(!is_thread_safe);
   return ExternalVkImageBacking::Create(
       context_state_, command_pool_.get(), mailbox, format, size, color_space,
-      usage, &image_usage_cache_, base::span<const uint8_t>());
+      surface_origin, alpha_type, usage, &image_usage_cache_,
+      base::span<const uint8_t>());
 }
 
 std::unique_ptr<SharedImageBacking> ExternalVkImageFactory::CreateSharedImage(
@@ -99,11 +102,13 @@
     viz::ResourceFormat format,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage,
     base::span<const uint8_t> pixel_data) {
-  return ExternalVkImageBacking::Create(context_state_, command_pool_.get(),
-                                        mailbox, format, size, color_space,
-                                        usage, &image_usage_cache_, pixel_data);
+  return ExternalVkImageBacking::Create(
+      context_state_, command_pool_.get(), mailbox, format, size, color_space,
+      surface_origin, alpha_type, usage, &image_usage_cache_, pixel_data);
 }
 
 std::unique_ptr<SharedImageBacking> ExternalVkImageFactory::CreateSharedImage(
@@ -114,11 +119,14 @@
     SurfaceHandle surface_handle,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage) {
   DCHECK(CanImportGpuMemoryBuffer(handle.type));
   return ExternalVkImageBacking::CreateFromGMB(
       context_state_, command_pool_.get(), mailbox, std::move(handle),
-      buffer_format, size, color_space, usage, &image_usage_cache_);
+      buffer_format, size, color_space, surface_origin, alpha_type, usage,
+      &image_usage_cache_);
 }
 
 bool ExternalVkImageFactory::CanImportGpuMemoryBuffer(
diff --git a/gpu/command_buffer/service/external_vk_image_factory.h b/gpu/command_buffer/service/external_vk_image_factory.h
index 6f1a57a..63d36f2 100644
--- a/gpu/command_buffer/service/external_vk_image_factory.h
+++ b/gpu/command_buffer/service/external_vk_image_factory.h
@@ -32,6 +32,8 @@
       SurfaceHandle surface_handle,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage,
       bool is_thread_safe) override;
   std::unique_ptr<SharedImageBacking> CreateSharedImage(
@@ -39,6 +41,8 @@
       viz::ResourceFormat format,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage,
       base::span<const uint8_t> pixel_data) override;
   std::unique_ptr<SharedImageBacking> CreateSharedImage(
@@ -49,6 +53,8 @@
       SurfaceHandle surface_handle,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage) override;
   bool CanImportGpuMemoryBuffer(
       gfx::GpuMemoryBufferType memory_buffer_type) override;
diff --git a/gpu/command_buffer/service/external_vk_image_skia_representation.cc b/gpu/command_buffer/service/external_vk_image_skia_representation.cc
index 742d34a..088172e 100644
--- a/gpu/command_buffer/service/external_vk_image_skia_representation.cc
+++ b/gpu/command_buffer/service/external_vk_image_skia_representation.cc
@@ -164,7 +164,7 @@
     begin_semaphores->back().initVulkan(semaphore);
   }
 
-  if (backing_impl()->need_synchronization()) {
+  if (backing_impl()->need_synchronization() && end_semaphores) {
     // Create an |end_access_semaphore_| which will be signalled by the caller.
     end_access_semaphore_ =
         vk_implementation()->CreateExternalSemaphore(backing_impl()->device());
@@ -178,11 +178,12 @@
 
 void ExternalVkImageSkiaRepresentation::EndAccess(bool readonly) {
   DCHECK_NE(access_mode_, kNone);
+  DCHECK(backing_impl()->need_synchronization() ||
+         end_access_semaphore_ == VK_NULL_HANDLE);
 
   SemaphoreHandle handle;
-  if (backing_impl()->need_synchronization()) {
-    DCHECK(end_access_semaphore_ != VK_NULL_HANDLE);
-
+  if (backing_impl()->need_synchronization() &&
+      end_access_semaphore_ != VK_NULL_HANDLE) {
     handle = vk_implementation()->GetSemaphoreHandle(vk_device(),
                                                      end_access_semaphore_);
     DCHECK(handle.is_valid());
@@ -191,8 +192,6 @@
     fence_helper()->EnqueueSemaphoreCleanupForSubmittedWork(
         end_access_semaphore_);
     end_access_semaphore_ = VK_NULL_HANDLE;
-  } else {
-    DCHECK(end_access_semaphore_ == VK_NULL_HANDLE);
   }
 
   backing_impl()->EndAccess(readonly, std::move(handle), false /* is_gl */);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_unittest_textures.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_unittest_textures.cc
index f2fffe2c..c99e8cf 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_unittest_textures.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_unittest_textures.cc
@@ -18,6 +18,8 @@
     viz::ResourceFormat format,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage) {
   GLuint service_id;
   glGenTextures(1, &service_id);
@@ -26,8 +28,8 @@
                size.height(), 0, GLDataFormat(format), GLDataType(format),
                nullptr /* data */);
   return std::make_unique<TestSharedImageBacking>(
-      mailbox, format, size, color_space, usage, 0 /* estimated_size */,
-      service_id);
+      mailbox, format, size, color_space, surface_origin, alpha_type, usage,
+      0 /* estimated_size */, service_id);
 }
 
 }  // namespace
@@ -37,7 +39,7 @@
   Mailbox mailbox = Mailbox::GenerateForSharedImage();
   auto backing = AllocateTextureAndCreateSharedImage(
       mailbox, viz::ResourceFormat::RGBA_8888, gfx::Size(10, 10),
-      gfx::ColorSpace(), 0);
+      gfx::ColorSpace(), kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, 0);
   GLuint service_id = backing->service_id();
   std::unique_ptr<SharedImageRepresentationFactoryRef> shared_image =
       GetSharedImageManager()->Register(std::move(backing), &memory_tracker);
@@ -102,7 +104,8 @@
       GetSharedImageManager()->Register(
           AllocateTextureAndCreateSharedImage(
               mailbox, viz::ResourceFormat::RGBA_8888, gfx::Size(10, 10),
-              gfx::ColorSpace(), 0),
+              gfx::ColorSpace(), kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
+              0),
           &memory_tracker);
 
   {
@@ -137,7 +140,8 @@
         GetSharedImageManager()->Register(
             AllocateTextureAndCreateSharedImage(
                 mailbox, viz::ResourceFormat::RGBA_8888, gfx::Size(10, 10),
-                gfx::ColorSpace(), 0),
+                gfx::ColorSpace(), kTopLeft_GrSurfaceOrigin,
+                kPremul_SkAlphaType, 0),
             &memory_tracker);
     shared_images.emplace_back(std::move(shared_image));
 
@@ -202,7 +206,7 @@
   Mailbox mailbox = Mailbox::GenerateForSharedImage();
   auto shared_image_backing = AllocateTextureAndCreateSharedImage(
       mailbox, viz::ResourceFormat::RGBA_8888, gfx::Size(10, 10),
-      gfx::ColorSpace(), 0);
+      gfx::ColorSpace(), kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, 0);
   // Set the shared image to fail BeginAccess.
   shared_image_backing->set_can_access(false);
   std::unique_ptr<SharedImageRepresentationFactoryRef> shared_image =
@@ -245,7 +249,8 @@
       GetSharedImageManager()->Register(
           AllocateTextureAndCreateSharedImage(
               mailbox, viz::ResourceFormat::RGBA_8888, gfx::Size(10, 10),
-              gfx::ColorSpace(), 0),
+              gfx::ColorSpace(), kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
+              0),
           &memory_tracker);
 
   auto& cmd = *GetImmediateAs<
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
index 4b7cd418..1e3c9b6 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
@@ -3120,7 +3120,8 @@
       GetSharedImageManager()->Register(
           std::make_unique<TestSharedImageBacking>(
               mailbox, viz::ResourceFormat::RGBA_8888, gfx::Size(10, 10),
-              gfx::ColorSpace(), 0, 0, kNewServiceId),
+              gfx::ColorSpace(), kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
+              0, 0, kNewServiceId),
           &memory_tracker);
 
   auto& cmd = *GetImmediateAs<
@@ -3181,7 +3182,8 @@
       GetSharedImageManager()->Register(
           std::make_unique<TestSharedImageBacking>(
               mailbox, viz::ResourceFormat::RGBA_8888, gfx::Size(10, 10),
-              gfx::ColorSpace(), 0, 0, kNewServiceId),
+              gfx::ColorSpace(), kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
+              0, 0, kNewServiceId),
           &memory_tracker);
 
   auto& cmd = *GetImmediateAs<
@@ -3204,7 +3206,8 @@
       GetSharedImageManager()->Register(
           std::make_unique<TestSharedImageBacking>(
               mailbox, viz::ResourceFormat::RGBA_8888, gfx::Size(10, 10),
-              gfx::ColorSpace(), 0, 0, kNewServiceId),
+              gfx::ColorSpace(), kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
+              0, 0, kNewServiceId),
           &memory_tracker);
 
   auto& cmd = *GetImmediateAs<
@@ -3262,7 +3265,8 @@
   Mailbox mailbox = Mailbox::GenerateForSharedImage();
   auto shared_image_backing = std::make_unique<TestSharedImageBacking>(
       mailbox, viz::ResourceFormat::RGBA_8888, gfx::Size(10, 10),
-      gfx::ColorSpace(), 0, 0, kNewServiceId);
+      gfx::ColorSpace(), kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, 0, 0,
+      kNewServiceId);
   // Set the shared image to fail BeginAccess.
   shared_image_backing->set_can_access(false);
   std::unique_ptr<SharedImageRepresentationFactoryRef> shared_image =
diff --git a/gpu/command_buffer/service/raster_decoder.cc b/gpu/command_buffer/service/raster_decoder.cc
index 30320ee..5fcb13f 100644
--- a/gpu/command_buffer/service/raster_decoder.cc
+++ b/gpu/command_buffer/service/raster_decoder.cc
@@ -589,6 +589,17 @@
                              GLuint shm_offset,
                              GLuint shm_size,
                              const volatile GLbyte* mailbox);
+  void DoReadbackImagePixelsINTERNAL(GLint src_x,
+                                     GLint src_y,
+                                     GLuint dst_width,
+                                     GLuint dst_height,
+                                     GLuint row_bytes,
+                                     GLuint dst_sk_color_type,
+                                     GLuint dst_sk_alpha_type,
+                                     GLint shm_id,
+                                     GLuint shm_offset,
+                                     GLuint pixels_offset,
+                                     const volatile GLbyte* mailbox);
   void DoConvertYUVMailboxesToRGBINTERNAL(GLenum yuv_color_space,
                                           GLboolean is_nv12,
                                           const volatile GLbyte* mailboxes);
@@ -2448,6 +2459,118 @@
   }
 }
 
+void RasterDecoderImpl::DoReadbackImagePixelsINTERNAL(
+    GLint src_x,
+    GLint src_y,
+    GLuint dst_width,
+    GLuint dst_height,
+    GLuint row_bytes,
+    GLuint dst_sk_color_type,
+    GLuint dst_sk_alpha_type,
+    GLint shm_id,
+    GLuint shm_offset,
+    GLuint pixels_offset,
+    const volatile GLbyte* mailbox) {
+  if (dst_sk_color_type > kLastEnum_SkColorType) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_ENUM, "ReadbackImagePixels",
+                       "dst_sk_color_type must be a valid SkColorType");
+    return;
+  }
+  if (dst_sk_alpha_type > kLastEnum_SkAlphaType) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_ENUM, "ReadbackImagePixels",
+                       "dst_sk_alpha_type must be a valid SkAlphaType");
+    return;
+  }
+
+  Mailbox source_mailbox = Mailbox::FromVolatile(
+      *reinterpret_cast<const volatile Mailbox*>(mailbox));
+  DLOG_IF(ERROR, !source_mailbox.Verify())
+      << "ReadbackImagePixels was passed an invalid mailbox";
+  auto source_shared_image = shared_image_representation_factory_.ProduceSkia(
+      source_mailbox, shared_context_state_);
+  if (!source_shared_image) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glReadbackImagePixels",
+                       "Unknown mailbox");
+    return;
+  }
+
+  // If present, the color space is serialized into shared memory before the
+  // pixel data.
+  sk_sp<SkColorSpace> dst_color_space;
+  if (pixels_offset > 0) {
+    void* color_space_bytes =
+        GetSharedMemoryAs<void*>(shm_id, shm_offset, pixels_offset);
+    if (!color_space_bytes) {
+      LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glReadbackImagePixels",
+                         "Failed to retrieve serialized SkColorSpace.");
+      return;
+    }
+    dst_color_space =
+        SkColorSpace::Deserialize(color_space_bytes, pixels_offset);
+    if (!dst_color_space) {
+      LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glReadbackImagePixels",
+                         "Failed to deserialize expected SkColorSpace");
+      return;
+    }
+  }
+
+  SkImageInfo dst_info = SkImageInfo::Make(
+      dst_width, dst_height, static_cast<SkColorType>(dst_sk_color_type),
+      static_cast<SkAlphaType>(dst_sk_alpha_type), std::move(dst_color_space));
+
+  if (row_bytes < dst_info.minRowBytes()) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glReadbackImagePixels",
+                       "row_bytes be >= "
+                       "SkImageInfo::minRowBytes() for dest image.");
+    return;
+  }
+
+  std::vector<GrBackendSemaphore> begin_semaphores;
+
+  std::unique_ptr<SharedImageRepresentationSkia::ScopedReadAccess>
+      source_scoped_access = source_shared_image->BeginScopedReadAccess(
+          &begin_semaphores, nullptr);
+
+  if (!begin_semaphores.empty()) {
+    bool result = shared_context_state_->gr_context()->wait(
+        begin_semaphores.size(), begin_semaphores.data());
+    DCHECK(result);
+  }
+
+  if (!source_scoped_access) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glReadbackImagePixels",
+                       "Source shared image is not accessible");
+    return;
+  }
+
+  auto src_color_type = viz::ResourceFormatToClosestSkColorType(
+      true /* gpu_compositing */, source_shared_image->format());
+
+  // TODO(http://crbug.com/1034086): We should initialize alpha_type and
+  // origin using metadata stored with the shared image.
+  SkAlphaType src_alpha_type = kPremul_SkAlphaType;
+  auto src_color_space = source_shared_image->color_space().ToSkColorSpace();
+  auto sk_image = SkImage::MakeFromTexture(
+      shared_context_state_->gr_context(),
+      source_scoped_access->promise_image_texture()->backendTexture(),
+      kTopLeft_GrSurfaceOrigin, src_color_type, src_alpha_type,
+      src_color_space);
+
+  void* shm_address = GetSharedMemoryAs<void*>(
+      shm_id, shm_offset + pixels_offset, dst_info.computeByteSize(row_bytes));
+  if (!shm_address) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glReadbackImagePixels",
+                       "Failed to retrieve memory for readPixels");
+    return;
+  }
+
+  bool success = sk_image->readPixels(dst_info, shm_address, row_bytes, 0, 0);
+  if (!success) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glReadbackImagePixels",
+                       "Failed to read pixels from SkImage");
+  }
+}
+
 namespace {
 // Helper class for mailbox index iteration that handles NV12 images which have
 // no separate V plane mailbox.
diff --git a/gpu/command_buffer/service/raster_decoder_autogen.h b/gpu/command_buffer/service/raster_decoder_autogen.h
index 7281cb18..6c89478 100644
--- a/gpu/command_buffer/service/raster_decoder_autogen.h
+++ b/gpu/command_buffer/service/raster_decoder_autogen.h
@@ -334,6 +334,42 @@
   return error::kNoError;
 }
 
+error::Error RasterDecoderImpl::HandleReadbackImagePixelsINTERNALImmediate(
+    uint32_t immediate_data_size,
+    const volatile void* cmd_data) {
+  const volatile raster::cmds::ReadbackImagePixelsINTERNALImmediate& c =
+      *static_cast<
+          const volatile raster::cmds::ReadbackImagePixelsINTERNALImmediate*>(
+          cmd_data);
+  GLint src_x = static_cast<GLint>(c.src_x);
+  GLint src_y = static_cast<GLint>(c.src_y);
+  GLuint dst_width = static_cast<GLuint>(c.dst_width);
+  GLuint dst_height = static_cast<GLuint>(c.dst_height);
+  GLuint row_bytes = static_cast<GLuint>(c.row_bytes);
+  GLuint dst_sk_color_type = static_cast<GLuint>(c.dst_sk_color_type);
+  GLuint dst_sk_alpha_type = static_cast<GLuint>(c.dst_sk_alpha_type);
+  GLint shm_id = static_cast<GLint>(c.shm_id);
+  GLuint shm_offset = static_cast<GLuint>(c.shm_offset);
+  GLuint pixels_offset = static_cast<GLuint>(c.pixels_offset);
+  uint32_t mailbox_size;
+  if (!gles2::GLES2Util::ComputeDataSize<GLbyte, 16>(1, &mailbox_size)) {
+    return error::kOutOfBounds;
+  }
+  if (mailbox_size > immediate_data_size) {
+    return error::kOutOfBounds;
+  }
+  volatile const GLbyte* mailbox =
+      gles2::GetImmediateDataAs<volatile const GLbyte*>(c, mailbox_size,
+                                                        immediate_data_size);
+  if (mailbox == nullptr) {
+    return error::kOutOfBounds;
+  }
+  DoReadbackImagePixelsINTERNAL(src_x, src_y, dst_width, dst_height, row_bytes,
+                                dst_sk_color_type, dst_sk_alpha_type, shm_id,
+                                shm_offset, pixels_offset, mailbox);
+  return error::kNoError;
+}
+
 error::Error RasterDecoderImpl::HandleConvertYUVMailboxesToRGBINTERNALImmediate(
     uint32_t immediate_data_size,
     const volatile void* cmd_data) {
diff --git a/gpu/command_buffer/service/shared_context_state.cc b/gpu/command_buffer/service/shared_context_state.cc
index 30126252..479619f 100644
--- a/gpu/command_buffer/service/shared_context_state.cc
+++ b/gpu/command_buffer/service/shared_context_state.cc
@@ -122,40 +122,44 @@
       real_context_(std::move(context)),
       surface_(std::move(surface)),
       sk_surface_cache_(MaxNumSkSurface()) {
-  if (GrContextIsVulkan()) {
-#if BUILDFLAG(ENABLE_VULKAN)
-    gr_context_ = vk_context_provider_->GetGrContext();
-#endif
-    use_virtualized_gl_contexts_ = false;
-    DCHECK(gr_context_);
-  }
-  if (GrContextIsMetal()) {
-#if defined(OS_MACOSX)
-    gr_context_ = metal_context_provider_->GetGrContext();
-#endif
-    use_virtualized_gl_contexts_ = false;
-    DCHECK(gr_context_);
-  }
-  if (GrContextIsDawn()) {
-#if BUILDFLAG(SKIA_USE_DAWN)
-    gr_context_ = dawn_context_provider_->GetGrContext();
-#endif
-    use_virtualized_gl_contexts_ = false;
-    DCHECK(gr_context_);
-  }
+  static crash_reporter::CrashKeyString<16> crash_key("gr-context-type");
+  crash_key.Set(
+      base::StringPrintf("%u", static_cast<uint32_t>(gr_context_type_)));
 
-  // Ensure that the context type is consistent with the provided factories.
+  // If |gr_context_type_| is not GL, then initialize |gr_context_| here. In
+  // the case of GL, |gr_context_| will be initialized in InitializeGrContext.
+  // Note that if |gr_context_| is not GL and also not initialized here (e.g,
+  // due to vk/metal/dawn_context_provider_ being nullptr), then
+  // InitializeGrContext will fail.
   switch (gr_context_type_) {
     case GrContextType::kGL:
       break;
     case GrContextType::kVulkan:
-      DCHECK(vk_context_provider_);
+      if (vk_context_provider_) {
+#if BUILDFLAG(ENABLE_VULKAN)
+        gr_context_ = vk_context_provider_->GetGrContext();
+#endif
+        use_virtualized_gl_contexts_ = false;
+        DCHECK(gr_context_);
+      }
       break;
     case GrContextType::kMetal:
-      DCHECK(metal_context_provider_);
+      if (metal_context_provider_) {
+#if defined(OS_MACOSX)
+        gr_context_ = metal_context_provider_->GetGrContext();
+#endif
+        use_virtualized_gl_contexts_ = false;
+        DCHECK(gr_context_);
+      }
       break;
     case GrContextType::kDawn:
-      DCHECK(dawn_context_provider_);
+      if (dawn_context_provider_) {
+#if BUILDFLAG(SKIA_USE_DAWN)
+        gr_context_ = dawn_context_provider_->GetGrContext();
+#endif
+        use_virtualized_gl_contexts_ = false;
+        DCHECK(gr_context_);
+      }
       break;
   }
 
@@ -167,9 +171,6 @@
   scratch_deserialization_buffer_.resize(
       kInitialScratchDeserializationBufferSize);
 
-  static crash_reporter::CrashKeyString<16> crash_key("gr-context-type");
-  crash_key.Set(
-      base::StringPrintf("%u", static_cast<uint32_t>(gr_context_type_)));
 }
 
 SharedContextState::~SharedContextState() {
@@ -224,7 +225,7 @@
   DetermineGrCacheLimitsFromAvailableMemory(&max_resource_cache_bytes,
                                             &glyph_cache_max_texture_bytes);
 
-  if (GrContextIsGL()) {
+  if (gr_context_type_ == GrContextType::kGL) {
     DCHECK(context_->IsCurrent(nullptr));
     bool use_version_es2 = false;
 #if defined(OS_ANDROID)
diff --git a/gpu/command_buffer/service/shared_image_backing.cc b/gpu/command_buffer/service/shared_image_backing.cc
index 58fc1a4..c7ab7bdc 100644
--- a/gpu/command_buffer/service/shared_image_backing.cc
+++ b/gpu/command_buffer/service/shared_image_backing.cc
@@ -16,6 +16,8 @@
                                        viz::ResourceFormat format,
                                        const gfx::Size& size,
                                        const gfx::ColorSpace& color_space,
+                                       GrSurfaceOrigin surface_origin,
+                                       SkAlphaType alpha_type,
                                        uint32_t usage,
                                        size_t estimated_size,
                                        bool is_thread_safe)
@@ -23,6 +25,8 @@
       format_(format),
       size_(size),
       color_space_(color_space),
+      surface_origin_(surface_origin),
+      alpha_type_(alpha_type),
       usage_(usage),
       estimated_size_(estimated_size) {
   DCHECK_CALLED_ON_VALID_THREAD(factory_thread_checker_);
@@ -181,6 +185,8 @@
     viz::ResourceFormat format,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage,
     size_t estimated_size,
     bool is_thread_safe)
@@ -188,6 +194,8 @@
                          format,
                          size,
                          color_space,
+                         surface_origin,
+                         alpha_type,
                          usage,
                          estimated_size,
                          is_thread_safe) {}
diff --git a/gpu/command_buffer/service/shared_image_backing.h b/gpu/command_buffer/service/shared_image_backing.h
index 5e87980..5121c28 100644
--- a/gpu/command_buffer/service/shared_image_backing.h
+++ b/gpu/command_buffer/service/shared_image_backing.h
@@ -18,6 +18,8 @@
 #include "components/viz/common/resources/resource_format.h"
 #include "gpu/command_buffer/common/mailbox.h"
 #include "gpu/gpu_gles2_export.h"
+#include "third_party/skia/include/core/SkImageInfo.h"
+#include "third_party/skia/include/gpu/GrTypes.h"
 #include "ui/gfx/color_space.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
@@ -58,6 +60,8 @@
                      viz::ResourceFormat format,
                      const gfx::Size& size,
                      const gfx::ColorSpace& color_space,
+                     GrSurfaceOrigin surface_origin,
+                     SkAlphaType alpha_type,
                      uint32_t usage,
                      size_t estimated_size,
                      bool is_thread_safe);
@@ -67,6 +71,8 @@
   viz::ResourceFormat format() const { return format_; }
   const gfx::Size& size() const { return size_; }
   const gfx::ColorSpace& color_space() const { return color_space_; }
+  GrSurfaceOrigin surface_origin() const { return surface_origin_; }
+  SkAlphaType alpha_type() const { return alpha_type_; }
   uint32_t usage() const { return usage_; }
   const Mailbox& mailbox() const { return mailbox_; }
   size_t estimated_size() const { return estimated_size_; }
@@ -209,6 +215,8 @@
   const viz::ResourceFormat format_;
   const gfx::Size size_;
   const gfx::ColorSpace color_space_;
+  const GrSurfaceOrigin surface_origin_;
+  const SkAlphaType alpha_type_;
   const uint32_t usage_;
   const size_t estimated_size_;
 
@@ -239,6 +247,8 @@
                                   viz::ResourceFormat format,
                                   const gfx::Size& size,
                                   const gfx::ColorSpace& color_space,
+                                  GrSurfaceOrigin surface_origin,
+                                  SkAlphaType alpha_type,
                                   uint32_t usage,
                                   size_t estimated_size,
                                   bool is_thread_safe);
diff --git a/gpu/command_buffer/service/shared_image_backing_android.cc b/gpu/command_buffer/service/shared_image_backing_android.cc
index 6c2455e..9644b67a 100644
--- a/gpu/command_buffer/service/shared_image_backing_android.cc
+++ b/gpu/command_buffer/service/shared_image_backing_android.cc
@@ -15,6 +15,8 @@
     viz::ResourceFormat format,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage,
     size_t estimated_size,
     bool is_thread_safe,
@@ -23,6 +25,8 @@
                                       format,
                                       size,
                                       color_space,
+                                      surface_origin,
+                                      alpha_type,
                                       usage,
                                       estimated_size,
                                       is_thread_safe),
diff --git a/gpu/command_buffer/service/shared_image_backing_android.h b/gpu/command_buffer/service/shared_image_backing_android.h
index b2d7e345..c3ecfe18 100644
--- a/gpu/command_buffer/service/shared_image_backing_android.h
+++ b/gpu/command_buffer/service/shared_image_backing_android.h
@@ -17,6 +17,8 @@
                             viz::ResourceFormat format,
                             const gfx::Size& size,
                             const gfx::ColorSpace& color_space,
+                            GrSurfaceOrigin surface_origin,
+                            SkAlphaType alpha_type,
                             uint32_t usage,
                             size_t estimated_size,
                             bool is_thread_safe,
diff --git a/gpu/command_buffer/service/shared_image_backing_d3d.cc b/gpu/command_buffer/service/shared_image_backing_d3d.cc
index cf99b41..194259c 100644
--- a/gpu/command_buffer/service/shared_image_backing_d3d.cc
+++ b/gpu/command_buffer/service/shared_image_backing_d3d.cc
@@ -40,6 +40,8 @@
     viz::ResourceFormat format,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage,
     Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain,
     scoped_refptr<gles2::TexturePassthrough> texture,
@@ -52,6 +54,8 @@
                                       format,
                                       size,
                                       color_space,
+                                      surface_origin,
+                                      alpha_type,
                                       usage,
                                       texture->estimated_size(),
                                       false /* is_thread_safe */),
diff --git a/gpu/command_buffer/service/shared_image_backing_d3d.h b/gpu/command_buffer/service/shared_image_backing_d3d.h
index ecf44221..a808c3c 100644
--- a/gpu/command_buffer/service/shared_image_backing_d3d.h
+++ b/gpu/command_buffer/service/shared_image_backing_d3d.h
@@ -39,6 +39,8 @@
       viz::ResourceFormat format,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage,
       Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain,
       scoped_refptr<gles2::TexturePassthrough> texture,
diff --git a/gpu/command_buffer/service/shared_image_backing_egl_image.cc b/gpu/command_buffer/service/shared_image_backing_egl_image.cc
index 6cb0ebe..f24e3665 100644
--- a/gpu/command_buffer/service/shared_image_backing_egl_image.cc
+++ b/gpu/command_buffer/service/shared_image_backing_egl_image.cc
@@ -86,6 +86,8 @@
     viz::ResourceFormat format,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage,
     size_t estimated_size,
     GLuint gl_format,
@@ -96,6 +98,8 @@
                                       format,
                                       size,
                                       color_space,
+                                      surface_origin,
+                                      alpha_type,
                                       usage,
                                       estimated_size,
                                       true /*is_thread_safe*/),
diff --git a/gpu/command_buffer/service/shared_image_backing_egl_image.h b/gpu/command_buffer/service/shared_image_backing_egl_image.h
index 29f9922..8802139 100644
--- a/gpu/command_buffer/service/shared_image_backing_egl_image.h
+++ b/gpu/command_buffer/service/shared_image_backing_egl_image.h
@@ -40,6 +40,8 @@
       viz::ResourceFormat format,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage,
       size_t estimated_size,
       GLuint gl_format,
diff --git a/gpu/command_buffer/service/shared_image_backing_factory.h b/gpu/command_buffer/service/shared_image_backing_factory.h
index 575c8066..197f7f4 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory.h
+++ b/gpu/command_buffer/service/shared_image_backing_factory.h
@@ -9,6 +9,8 @@
 
 #include "components/viz/common/resources/resource_format.h"
 #include "gpu/ipc/common/surface_handle.h"
+#include "third_party/skia/include/core/SkImageInfo.h"
+#include "third_party/skia/include/gpu/GrTypes.h"
 #include "ui/gfx/buffer_types.h"
 #include "ui/gfx/gpu_memory_buffer.h"
 
@@ -30,6 +32,8 @@
       SurfaceHandle surface_handle,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage,
       bool is_thread_safe) = 0;
   virtual std::unique_ptr<SharedImageBacking> CreateSharedImage(
@@ -37,6 +41,8 @@
       viz::ResourceFormat format,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage,
       base::span<const uint8_t> pixel_data) = 0;
   virtual std::unique_ptr<SharedImageBacking> CreateSharedImage(
@@ -47,6 +53,8 @@
       SurfaceHandle surface_handle,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage) = 0;
 
   // Returns true if the specified GpuMemoryBufferType can be imported using
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.cc b/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.cc
index 1511c11..44800465 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.cc
+++ b/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.cc
@@ -135,6 +135,8 @@
                         viz::ResourceFormat format,
                         const gfx::Size& size,
                         const gfx::ColorSpace& color_space,
+                        GrSurfaceOrigin surface_origin,
+                        SkAlphaType alpha_type,
                         uint32_t usage,
                         base::android::ScopedHardwareBufferHandle handle,
                         size_t estimated_size,
@@ -247,6 +249,8 @@
     viz::ResourceFormat format,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage,
     base::android::ScopedHardwareBufferHandle handle,
     size_t estimated_size,
@@ -256,6 +260,8 @@
                                 format,
                                 size,
                                 color_space,
+                                surface_origin,
+                                alpha_type,
                                 usage,
                                 estimated_size,
                                 is_thread_safe,
@@ -561,6 +567,8 @@
     viz::ResourceFormat format,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage,
     bool is_thread_safe,
     base::span<const uint8_t> pixel_data) {
@@ -649,8 +657,9 @@
   }
 
   auto backing = std::make_unique<SharedImageBackingAHB>(
-      mailbox, format, size, color_space, usage, std::move(handle),
-      estimated_size, is_thread_safe, std::move(initial_upload_fd));
+      mailbox, format, size, color_space, surface_origin, alpha_type, usage,
+      std::move(handle), estimated_size, is_thread_safe,
+      std::move(initial_upload_fd));
 
   // If we uploaded initial data, set the backing as cleared.
   if (!pixel_data.empty())
@@ -666,10 +675,12 @@
     SurfaceHandle surface_handle,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage,
     bool is_thread_safe) {
-  return MakeBacking(mailbox, format, size, color_space, usage, is_thread_safe,
-                     base::span<uint8_t>());
+  return MakeBacking(mailbox, format, size, color_space, surface_origin,
+                     alpha_type, usage, is_thread_safe, base::span<uint8_t>());
 }
 
 std::unique_ptr<SharedImageBacking>
@@ -678,10 +689,12 @@
     viz::ResourceFormat format,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage,
     base::span<const uint8_t> pixel_data) {
-  return MakeBacking(mailbox, format, size, color_space, usage, false,
-                     pixel_data);
+  return MakeBacking(mailbox, format, size, color_space, surface_origin,
+                     alpha_type, usage, false, pixel_data);
 }
 
 bool SharedImageBackingFactoryAHB::CanImportGpuMemoryBuffer(
@@ -709,6 +722,8 @@
     SurfaceHandle surface_handle,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage) {
   // TODO(vasilyt): support SHARED_MEMORY_BUFFER?
   if (handle.type != gfx::ANDROID_HARDWARE_BUFFER) {
@@ -730,8 +745,8 @@
   }
 
   return std::make_unique<SharedImageBackingAHB>(
-      mailbox, resource_format, size, color_space, usage,
-      std::move(handle.android_hardware_buffer), estimated_size, false,
+      mailbox, resource_format, size, color_space, surface_origin, alpha_type,
+      usage, std::move(handle.android_hardware_buffer), estimated_size, false,
       base::ScopedFD());
 }
 
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.h b/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.h
index 294e8dd..e477818 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.h
+++ b/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.h
@@ -38,6 +38,8 @@
       SurfaceHandle surface_handle,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage,
       bool is_thread_safe) override;
   std::unique_ptr<SharedImageBacking> CreateSharedImage(
@@ -45,6 +47,8 @@
       viz::ResourceFormat format,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage,
       base::span<const uint8_t> pixel_data) override;
   std::unique_ptr<SharedImageBacking> CreateSharedImage(
@@ -55,6 +59,8 @@
       SurfaceHandle surface_handle,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage) override;
   bool CanImportGpuMemoryBuffer(
       gfx::GpuMemoryBufferType memory_buffer_type) override;
@@ -70,6 +76,8 @@
       viz::ResourceFormat format,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage,
       bool is_thread_safe,
       base::span<const uint8_t> pixel_data);
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer_unittest.cc b/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer_unittest.cc
index ca4028c..e58b7def 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer_unittest.cc
+++ b/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer_unittest.cc
@@ -168,11 +168,13 @@
   auto format = viz::ResourceFormat::RGBA_8888;
   gfx::Size size(1, 1);
   auto color_space = gfx::ColorSpace::CreateSRGB();
+  GrSurfaceOrigin surface_origin = kTopLeft_GrSurfaceOrigin;
+  SkAlphaType alpha_type = kPremul_SkAlphaType;
   uint32_t usage = SHARED_IMAGE_USAGE_GLES2 | SHARED_IMAGE_USAGE_DISPLAY;
   gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
   auto backing = backing_factory_->CreateSharedImage(
-      mailbox, format, surface_handle, size, color_space, usage,
-      false /* is_thread_safe */);
+      mailbox, format, surface_handle, size, color_space, surface_origin,
+      alpha_type, usage, false /* is_thread_safe */);
   EXPECT_TRUE(backing);
 
   GLenum expected_target = GL_TEXTURE_2D;
@@ -234,9 +236,12 @@
   }
 
   auto color_space = gfx::ColorSpace::CreateSRGB();
+  GrSurfaceOrigin surface_origin = kTopLeft_GrSurfaceOrigin;
+  SkAlphaType alpha_type = kPremul_SkAlphaType;
   uint32_t usage = SHARED_IMAGE_USAGE_GLES2 | SHARED_IMAGE_USAGE_DISPLAY;
   auto backing = backing_factory_->CreateSharedImage(
-      mailbox, format, size, color_space, usage, initial_data);
+      mailbox, format, size, color_space, surface_origin, alpha_type, usage,
+      initial_data);
   EXPECT_TRUE(backing);
 
   std::unique_ptr<SharedImageRepresentationFactoryRef> factory_ref =
@@ -263,11 +268,13 @@
   auto format = viz::ResourceFormat::YUV_420_BIPLANAR;
   gfx::Size size(256, 256);
   auto color_space = gfx::ColorSpace::CreateSRGB();
+  GrSurfaceOrigin surface_origin = kTopLeft_GrSurfaceOrigin;
+  SkAlphaType alpha_type = kPremul_SkAlphaType;
   gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
   uint32_t usage = SHARED_IMAGE_USAGE_GLES2;
   auto backing = backing_factory_->CreateSharedImage(
-      mailbox, format, surface_handle, size, color_space, usage,
-      false /* is_thread_safe */);
+      mailbox, format, surface_handle, size, color_space, surface_origin,
+      alpha_type, usage, false /* is_thread_safe */);
   EXPECT_FALSE(backing);
 }
 
@@ -280,17 +287,19 @@
   auto format = viz::ResourceFormat::RGBA_8888;
   gfx::Size size(0, 0);
   auto color_space = gfx::ColorSpace::CreateSRGB();
+  GrSurfaceOrigin surface_origin = kTopLeft_GrSurfaceOrigin;
+  SkAlphaType alpha_type = kPremul_SkAlphaType;
   gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
   uint32_t usage = SHARED_IMAGE_USAGE_GLES2;
   auto backing = backing_factory_->CreateSharedImage(
-      mailbox, format, surface_handle, size, color_space, usage,
-      false /* is_thread_safe */);
+      mailbox, format, surface_handle, size, color_space, surface_origin,
+      alpha_type, usage, false /* is_thread_safe */);
   EXPECT_FALSE(backing);
 
   size = gfx::Size(INT_MAX, INT_MAX);
-  backing = backing_factory_->CreateSharedImage(mailbox, format, surface_handle,
-                                                size, color_space, usage,
-                                                false /* is_thread_safe */);
+  backing = backing_factory_->CreateSharedImage(
+      mailbox, format, surface_handle, size, color_space, surface_origin,
+      alpha_type, usage, false /* is_thread_safe */);
   EXPECT_FALSE(backing);
 }
 
@@ -302,11 +311,13 @@
   auto format = viz::ResourceFormat::RGBA_8888;
   gfx::Size size(256, 256);
   auto color_space = gfx::ColorSpace::CreateSRGB();
+  GrSurfaceOrigin surface_origin = kTopLeft_GrSurfaceOrigin;
+  SkAlphaType alpha_type = kPremul_SkAlphaType;
   gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
   uint32_t usage = SHARED_IMAGE_USAGE_GLES2;
   auto backing = backing_factory_->CreateSharedImage(
-      mailbox, format, surface_handle, size, color_space, usage,
-      false /* is_thread_safe */);
+      mailbox, format, surface_handle, size, color_space, surface_origin,
+      alpha_type, usage, false /* is_thread_safe */);
   EXPECT_TRUE(backing);
 
   size_t backing_estimated_size = backing->estimated_size();
@@ -554,6 +565,8 @@
   mailbox_ = Mailbox::GenerateForSharedImage();
   auto format = viz::ResourceFormat::RGBA_8888;
   auto color_space = gfx::ColorSpace::CreateSRGB();
+  GrSurfaceOrigin surface_origin = kTopLeft_GrSurfaceOrigin;
+  SkAlphaType alpha_type = kPremul_SkAlphaType;
   gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
 
   // SHARED_IMAGE_USAGE_DISPLAY for skia read and SHARED_IMAGE_USAGE_RASTER for
@@ -562,8 +575,8 @@
   if (!is_thread_safe)
     usage |= SHARED_IMAGE_USAGE_DISPLAY;
   backing_ = backing_factory->CreateSharedImage(
-      mailbox_, format, surface_handle, size_, color_space, usage,
-      is_thread_safe);
+      mailbox_, format, surface_handle, size_, color_space, surface_origin,
+      alpha_type, usage, is_thread_safe);
   EXPECT_TRUE(backing_);
 
   // Check clearing.
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_d3d.cc b/gpu/command_buffer/service/shared_image_backing_factory_d3d.cc
index 6529f07..70585fe 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_d3d.cc
+++ b/gpu/command_buffer/service/shared_image_backing_factory_d3d.cc
@@ -110,6 +110,8 @@
     viz::ResourceFormat format,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage,
     Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain,
     size_t buffer_index,
@@ -175,8 +177,8 @@
   texture->SetEstimatedSize(texture_memory_size);
 
   return std::make_unique<SharedImageBackingD3D>(
-      mailbox, format, size, color_space, usage, std::move(swap_chain),
-      std::move(texture), std::move(image), buffer_index,
+      mailbox, format, size, color_space, surface_origin, alpha_type, usage,
+      std::move(swap_chain), std::move(texture), std::move(image), buffer_index,
       std::move(d3d11_texture), std::move(shared_handle),
       std::move(dxgi_keyed_mutex));
 }
@@ -188,6 +190,8 @@
     viz::ResourceFormat format,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage) {
   if (!SharedImageBackingFactoryD3D::IsSwapChainSupported())
     return {nullptr, nullptr};
@@ -260,17 +264,17 @@
   if (!ClearBackBuffer(swap_chain, d3d11_device_))
     return {nullptr, nullptr};
 
-  auto back_buffer_backing =
-      MakeBacking(back_buffer_mailbox, format, size, color_space, usage,
-                  swap_chain, 0 /* buffer_index */, nullptr /* d3d11_texture */,
-                  base::win::ScopedHandle());
+  auto back_buffer_backing = MakeBacking(
+      back_buffer_mailbox, format, size, color_space, surface_origin,
+      alpha_type, usage, swap_chain, 0 /* buffer_index */,
+      nullptr /* d3d11_texture */, base::win::ScopedHandle());
   if (!back_buffer_backing)
     return {nullptr, nullptr};
 
-  auto front_buffer_backing =
-      MakeBacking(front_buffer_mailbox, format, size, color_space, usage,
-                  swap_chain, 1 /* buffer_index */, nullptr /* d3d11_texture */,
-                  base::win::ScopedHandle());
+  auto front_buffer_backing = MakeBacking(
+      front_buffer_mailbox, format, size, color_space, surface_origin,
+      alpha_type, usage, swap_chain, 1 /* buffer_index */,
+      nullptr /* d3d11_texture */, base::win::ScopedHandle());
   if (!front_buffer_backing)
     return {nullptr, nullptr};
 
@@ -284,6 +288,8 @@
     SurfaceHandle surface_handle,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage,
     bool is_thread_safe) {
   DCHECK(!is_thread_safe);
@@ -343,8 +349,9 @@
   // ensure we do not leak it.
   base::win::ScopedHandle scoped_shared_handle(shared_handle);
 
-  return MakeBacking(mailbox, format, size, color_space, usage, nullptr, 0,
-                     std::move(d3d11_texture), std::move(scoped_shared_handle));
+  return MakeBacking(mailbox, format, size, color_space, surface_origin,
+                     alpha_type, usage, nullptr, 0, std::move(d3d11_texture),
+                     std::move(scoped_shared_handle));
 }
 
 std::unique_ptr<SharedImageBacking>
@@ -353,6 +360,8 @@
     viz::ResourceFormat format,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage,
     base::span<const uint8_t> pixel_data) {
   NOTIMPLEMENTED();
@@ -368,6 +377,8 @@
     SurfaceHandle surface_handle,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage) {
   NOTIMPLEMENTED();
   return nullptr;
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_d3d.h b/gpu/command_buffer/service/shared_image_backing_factory_d3d.h
index d828383..7abb0b0 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_d3d.h
+++ b/gpu/command_buffer/service/shared_image_backing_factory_d3d.h
@@ -56,6 +56,8 @@
                                     viz::ResourceFormat format,
                                     const gfx::Size& size,
                                     const gfx::ColorSpace& color_space,
+                                    GrSurfaceOrigin surface_origin,
+                                    SkAlphaType alpha_type,
                                     uint32_t usage);
 
   std::unique_ptr<SharedImageBacking> CreateSharedImage(
@@ -64,6 +66,8 @@
       SurfaceHandle surface_handle,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage,
       bool is_thread_safe) override;
   std::unique_ptr<SharedImageBacking> CreateSharedImage(
@@ -71,6 +75,8 @@
       viz::ResourceFormat format,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage,
       base::span<const uint8_t> pixel_data) override;
   std::unique_ptr<SharedImageBacking> CreateSharedImage(
@@ -81,6 +87,8 @@
       SurfaceHandle surface_handle,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage) override;
 
   // Returns true if the specified GpuMemoryBufferType can be imported using
@@ -97,6 +105,8 @@
       viz::ResourceFormat format,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage,
       Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain,
       size_t buffer_index,
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_d3d_unittest.cc b/gpu/command_buffer/service/shared_image_backing_factory_d3d_unittest.cc
index e6bcb27..45461e9b 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_d3d_unittest.cc
+++ b/gpu/command_buffer/service/shared_image_backing_factory_d3d_unittest.cc
@@ -121,12 +121,14 @@
   auto back_buffer_mailbox = Mailbox::GenerateForSharedImage();
   gfx::Size size(1, 1);
   auto color_space = gfx::ColorSpace::CreateSRGB();
+  auto surface_origin = kTopLeft_GrSurfaceOrigin;
+  auto alpha_type = kPremul_SkAlphaType;
   uint32_t usage = gpu::SHARED_IMAGE_USAGE_SCANOUT;
   {
     auto valid_format = viz::RGBA_8888;
     auto backings = shared_image_factory_->CreateSwapChain(
         front_buffer_mailbox, back_buffer_mailbox, valid_format, size,
-        color_space, usage);
+        color_space, surface_origin, alpha_type, usage);
     EXPECT_TRUE(backings.front_buffer);
     EXPECT_TRUE(backings.back_buffer);
   }
@@ -134,7 +136,7 @@
     auto valid_format = viz::BGRA_8888;
     auto backings = shared_image_factory_->CreateSwapChain(
         front_buffer_mailbox, back_buffer_mailbox, valid_format, size,
-        color_space, usage);
+        color_space, surface_origin, alpha_type, usage);
     EXPECT_TRUE(backings.front_buffer);
     EXPECT_TRUE(backings.back_buffer);
   }
@@ -142,7 +144,7 @@
     auto valid_format = viz::RGBA_F16;
     auto backings = shared_image_factory_->CreateSwapChain(
         front_buffer_mailbox, back_buffer_mailbox, valid_format, size,
-        color_space, usage);
+        color_space, surface_origin, alpha_type, usage);
     EXPECT_TRUE(backings.front_buffer);
     EXPECT_TRUE(backings.back_buffer);
   }
@@ -150,7 +152,7 @@
     auto invalid_format = viz::RGBA_4444;
     auto backings = shared_image_factory_->CreateSwapChain(
         front_buffer_mailbox, back_buffer_mailbox, invalid_format, size,
-        color_space, usage);
+        color_space, surface_origin, alpha_type, usage);
     EXPECT_FALSE(backings.front_buffer);
     EXPECT_FALSE(backings.back_buffer);
   }
@@ -165,6 +167,8 @@
   auto format = viz::RGBA_8888;
   gfx::Size size(1, 1);
   auto color_space = gfx::ColorSpace::CreateSRGB();
+  auto surface_origin = kTopLeft_GrSurfaceOrigin;
+  auto alpha_type = kPremul_SkAlphaType;
   uint32_t usage = gpu::SHARED_IMAGE_USAGE_GLES2 |
                    gpu::SHARED_IMAGE_USAGE_GLES2_FRAMEBUFFER_HINT |
                    gpu::SHARED_IMAGE_USAGE_DISPLAY |
@@ -172,7 +176,7 @@
 
   auto backings = shared_image_factory_->CreateSwapChain(
       front_buffer_mailbox, back_buffer_mailbox, format, size, color_space,
-      usage);
+      surface_origin, alpha_type, usage);
   EXPECT_TRUE(backings.front_buffer);
   EXPECT_TRUE(backings.back_buffer);
 
@@ -465,7 +469,8 @@
   const uint32_t usage = SHARED_IMAGE_USAGE_GLES2 | SHARED_IMAGE_USAGE_DISPLAY;
   const gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
   auto backing = shared_image_factory_->CreateSharedImage(
-      mailbox, format, surface_handle, size, color_space, usage,
+      mailbox, format, surface_handle, size, color_space,
+      kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, usage,
       false /* is_thread_safe */);
   ASSERT_NE(backing, nullptr);
 
@@ -541,7 +546,8 @@
   const gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
   const uint32_t usage = SHARED_IMAGE_USAGE_WEBGPU | SHARED_IMAGE_USAGE_DISPLAY;
   auto backing = shared_image_factory_->CreateSharedImage(
-      mailbox, format, surface_handle, size, color_space, usage,
+      mailbox, format, surface_handle, size, color_space,
+      kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, usage,
       false /* is_thread_safe */);
   ASSERT_NE(backing, nullptr);
 
@@ -611,7 +617,8 @@
                          SHARED_IMAGE_USAGE_WEBGPU;
   const gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
   auto backing = shared_image_factory_->CreateSharedImage(
-      mailbox, format, surface_handle, size, color_space, usage,
+      mailbox, format, surface_handle, size, color_space,
+      kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, usage,
       false /* is_thread_safe */);
   ASSERT_NE(backing, nullptr);
 
@@ -729,7 +736,8 @@
                          SHARED_IMAGE_USAGE_WEBGPU;
   const gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
   auto backing = shared_image_factory_->CreateSharedImage(
-      mailbox, format, surface_handle, size, color_space, usage,
+      mailbox, format, surface_handle, size, color_space,
+      kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, usage,
       false /* is_thread_safe */);
   ASSERT_NE(backing, nullptr);
 
@@ -817,7 +825,8 @@
   const uint32_t usage = SHARED_IMAGE_USAGE_GLES2 | SHARED_IMAGE_USAGE_DISPLAY;
   const gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
   auto backing = shared_image_factory_->CreateSharedImage(
-      mailbox, format, surface_handle, size, color_space, usage,
+      mailbox, format, surface_handle, size, color_space,
+      kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, usage,
       false /* is_thread_safe */);
   ASSERT_NE(backing, nullptr);
 
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc b/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc
index 876f8d0..2a4203a 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc
+++ b/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc
@@ -213,7 +213,8 @@
 
   bool success = factory->CreateSharedImage(
       dst_mailbox, backing->format(), backing->size(), backing->color_space(),
-      gpu::kNullSurfaceHandle, backing->usage() | SHARED_IMAGE_USAGE_WEBGPU);
+      kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, gpu::kNullSurfaceHandle,
+      backing->usage() | SHARED_IMAGE_USAGE_WEBGPU);
   if (!success) {
     DLOG(ERROR) << "Cannot create a shared image resource for internal blit";
     return nullptr;
@@ -311,6 +312,13 @@
       client_(client),
       texture_(texture) {}
 
+SharedImageRepresentationGLTextureImpl::
+    ~SharedImageRepresentationGLTextureImpl() {
+  texture_ = nullptr;
+  if (client_)
+    client_->SharedImageRepresentationGLTextureRelease(has_context());
+}
+
 gles2::Texture* SharedImageRepresentationGLTextureImpl::GetTexture() {
   return texture_;
 }
@@ -341,7 +349,11 @@
       texture_passthrough_(std::move(texture_passthrough)) {}
 
 SharedImageRepresentationGLTexturePassthroughImpl::
-    ~SharedImageRepresentationGLTexturePassthroughImpl() = default;
+    ~SharedImageRepresentationGLTexturePassthroughImpl() {
+  texture_passthrough_.reset();
+  if (client_)
+    client_->SharedImageRepresentationGLTextureRelease(has_context());
+}
 
 const scoped_refptr<gles2::TexturePassthrough>&
 SharedImageRepresentationGLTexturePassthroughImpl::GetTexturePassthrough() {
@@ -426,6 +438,11 @@
     DLOG(ERROR) << "SharedImageRepresentationSkia was destroyed while still "
                 << "open for write access.";
   }
+  promise_texture_.reset();
+  if (client_) {
+    DCHECK(context_state_->GrContextIsGL());
+    client_->SharedImageRepresentationGLTextureRelease(has_context());
+  }
 }
 
 sk_sp<SkSurface> SharedImageRepresentationSkiaImpl::BeginWriteAccess(
@@ -450,7 +467,7 @@
       /*gpu_compositing=*/true, format());
   auto surface = SkSurface::MakeFromBackendTexture(
       context_state_->gr_context(), promise_texture_->backendTexture(),
-      kTopLeft_GrSurfaceOrigin, final_msaa_count, sk_color_type,
+      backing()->surface_origin(), final_msaa_count, sk_color_type,
       backing()->color_space().ToSkColorSpace(), &surface_props);
   write_surface_ = surface.get();
   return surface;
@@ -528,12 +545,16 @@
     viz::ResourceFormat format,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage,
     bool is_passthrough)
     : SharedImageBacking(mailbox,
                          format,
                          size,
                          color_space,
+                         surface_origin,
+                         alpha_type,
                          usage,
                          EstimatedSize(format, size),
                          false /* is_thread_safe */),
@@ -685,6 +706,8 @@
     viz::ResourceFormat format,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage,
     const SharedImageBackingGLCommon::InitializeGLTextureParams& params,
     const UnpackStateAttribs& attribs,
@@ -693,6 +716,8 @@
                          format,
                          size,
                          color_space,
+                         surface_origin,
+                         alpha_type,
                          usage,
                          EstimatedSize(format, size),
                          false /* is_thread_safe */),
@@ -700,8 +725,21 @@
       gl_params_(params),
       gl_unpack_attribs_(attribs),
       is_passthrough_(is_passthrough),
+      cleared_rect_(params.is_cleared ? gfx::Rect(size) : gfx::Rect()),
       weak_factory_(this) {
   DCHECK(image_);
+}
+
+SharedImageBackingGLImage::~SharedImageBackingGLImage() {
+  if (gl_texture_retained_for_legacy_mailbox_)
+    ReleaseGLTexture(have_context());
+  DCHECK_EQ(gl_texture_retain_count_, 0u);
+}
+
+void SharedImageBackingGLImage::RetainGLTexture() {
+  gl_texture_retain_count_ += 1;
+  if (gl_texture_retain_count_ > 1)
+    return;
 
   // Allocate the GL texture.
   SharedImageBackingGLCommon::MakeTextureAndSetParameters(
@@ -711,35 +749,50 @@
       is_passthrough_ ? nullptr : &texture_);
 
   // Set the GLImage to be initially unbound from the GL texture.
+  image_bind_or_copy_needed_ = true;
   if (is_passthrough_) {
-    passthrough_texture_->SetEstimatedSize(EstimatedSize(format, size));
+    passthrough_texture_->SetEstimatedSize(EstimatedSize(format(), size()));
     passthrough_texture_->SetLevelImage(gl_params_.target, 0, image_.get());
     passthrough_texture_->set_is_bind_pending(true);
   } else {
-    texture_->SetLevelInfo(
-        gl_params_.target, 0, gl_params_.internal_format, size.width(),
-        size.height(), 1, 0, gl_params_.format, gl_params_.type,
-        gl_params_.is_cleared ? gfx::Rect(size) : gfx::Rect());
+    texture_->SetLevelInfo(gl_params_.target, 0, gl_params_.internal_format,
+                           size().width(), size().height(), 1, 0,
+                           gl_params_.format, gl_params_.type, cleared_rect_);
     texture_->SetLevelImage(gl_params_.target, 0, image_.get(),
                             gles2::Texture::UNBOUND);
     texture_->SetImmutable(true, false /* has_immutable_storage */);
   }
 }
 
-SharedImageBackingGLImage::~SharedImageBackingGLImage() {
+void SharedImageBackingGLImage::ReleaseGLTexture(bool have_context) {
+  DCHECK_GT(gl_texture_retain_count_, 0u);
+  gl_texture_retain_count_ -= 1;
+  if (gl_texture_retain_count_ > 0)
+    return;
+
+  // If the cached promise texture is referencing the GL texture, then it needs
+  // to be deleted, too.
+  if (cached_promise_texture_) {
+    if (cached_promise_texture_->backendTexture().backend() ==
+        GrBackendApi::kOpenGL) {
+      cached_promise_texture_.reset();
+    }
+  }
+
   if (rgb_emulation_texture_) {
-    rgb_emulation_texture_->RemoveLightweightRef(have_context());
+    rgb_emulation_texture_->RemoveLightweightRef(have_context);
     rgb_emulation_texture_ = nullptr;
   }
   if (IsPassthrough()) {
     if (passthrough_texture_) {
-      if (!have_context())
+      if (!have_context)
         passthrough_texture_->MarkContextLost();
       passthrough_texture_.reset();
     }
   } else {
     if (texture_) {
-      texture_->RemoveLightweightRef(have_context());
+      cleared_rect_ = texture_->GetLevelClearedRect(texture_->target(), 0);
+      texture_->RemoveLightweightRef(have_context);
       texture_ = nullptr;
     }
   }
@@ -750,7 +803,11 @@
 }
 
 GLuint SharedImageBackingGLImage::GetGLServiceId() const {
-  return texture_ ? texture_->service_id() : passthrough_texture_->service_id();
+  if (texture_)
+    return texture_->service_id();
+  if (passthrough_texture_)
+    return passthrough_texture_->service_id();
+  return 0;
 }
 
 scoped_refptr<gfx::NativePixmap> SharedImageBackingGLImage::GetNativePixmap() {
@@ -768,39 +825,36 @@
   // Add a |service_guid| which expresses shared ownership between the
   // various GPU dumps.
   auto client_guid = GetSharedImageGUIDForTracing(mailbox());
-  auto service_guid = gl::GetGLTextureServiceGUIDForTracing(GetGLServiceId());
-  pmd->CreateSharedGlobalAllocatorDump(service_guid);
-  // TODO(piman): coalesce constant with TextureManager::DumpTextureRef.
-  int importance = 2;  // This client always owns the ref.
-
-  pmd->AddOwnershipEdge(client_guid, service_guid, importance);
-
-  if (IsPassthrough()) {
-    auto* gl_image = passthrough_texture_->GetLevelImage(GetGLTarget(), 0);
-    if (gl_image)
-      gl_image->OnMemoryDump(pmd, client_tracing_id, dump_name);
-  } else {
-    // Dump all sub-levels held by the texture. They will appear below the
-    // main gl/textures/client_X/mailbox_Y dump.
-    texture_->DumpLevelMemory(pmd, client_tracing_id, dump_name);
+  if (auto service_id = GetGLServiceId()) {
+    auto service_guid = gl::GetGLTextureServiceGUIDForTracing(GetGLServiceId());
+    pmd->CreateSharedGlobalAllocatorDump(service_guid);
+    // TODO(piman): coalesce constant with TextureManager::DumpTextureRef.
+    int importance = 2;  // This client always owns the ref.
+    pmd->AddOwnershipEdge(client_guid, service_guid, importance);
   }
+  image_->OnMemoryDump(pmd, client_tracing_id, dump_name);
 }
 
 gfx::Rect SharedImageBackingGLImage::ClearedRect() const {
-  if (IsPassthrough()) {
-    // This backing is used exclusively with ANGLE which handles clear tracking
-    // internally. Act as though the texture is always cleared.
-    return gfx::Rect(size());
-  } else {
+  if (texture_)
     return texture_->GetLevelClearedRect(texture_->target(), 0);
-  }
+  return cleared_rect_;
 }
+
 void SharedImageBackingGLImage::SetClearedRect(const gfx::Rect& cleared_rect) {
-  if (!IsPassthrough())
+  if (texture_)
     texture_->SetLevelClearedRect(texture_->target(), 0, cleared_rect);
+  else
+    cleared_rect_ = cleared_rect;
 }
+
 bool SharedImageBackingGLImage::ProduceLegacyMailbox(
     MailboxManager* mailbox_manager) {
+  if (!gl_texture_retained_for_legacy_mailbox_) {
+    RetainGLTexture();
+    gl_texture_retained_for_legacy_mailbox_ = true;
+  }
+
   if (IsPassthrough())
     mailbox_manager->ProduceTexture(mailbox(), passthrough_texture_.get());
   else
@@ -811,6 +865,9 @@
 std::unique_ptr<SharedImageRepresentationGLTexture>
 SharedImageBackingGLImage::ProduceGLTexture(SharedImageManager* manager,
                                             MemoryTypeTracker* tracker) {
+  // The corresponding release will be done when the returned representation is
+  // destroyed, in SharedImageRepresentationGLTextureRelease.
+  RetainGLTexture();
   DCHECK(texture_);
   return std::make_unique<SharedImageRepresentationGLTextureImpl>(
       manager, this, this, tracker, texture_);
@@ -819,6 +876,9 @@
 SharedImageBackingGLImage::ProduceGLTexturePassthrough(
     SharedImageManager* manager,
     MemoryTypeTracker* tracker) {
+  // The corresponding release will be done when the returned representation is
+  // destroyed, in SharedImageRepresentationGLTextureRelease.
+  RetainGLTexture();
   DCHECK(passthrough_texture_);
   return std::make_unique<SharedImageRepresentationGLTexturePassthroughImpl>(
       manager, this, this, tracker, passthrough_texture_);
@@ -859,6 +919,14 @@
     SharedImageManager* manager,
     MemoryTypeTracker* tracker,
     scoped_refptr<SharedContextState> context_state) {
+  SharedImageRepresentationGLTextureClient* gl_client = nullptr;
+  if (context_state->GrContextIsGL()) {
+    // The corresponding release will be done when the returned representation
+    // is destroyed, in SharedImageRepresentationGLTextureRelease.
+    RetainGLTexture();
+    gl_client = this;
+  }
+
   if (!cached_promise_texture_) {
     if (context_state->GrContextIsMetal()) {
 #if defined(OS_MACOSX)
@@ -875,8 +943,8 @@
     }
   }
   return std::make_unique<SharedImageRepresentationSkiaImpl>(
-      manager, this, context_state->GrContextIsGL() ? this : nullptr,
-      std::move(context_state), cached_promise_texture_, tracker);
+      manager, this, gl_client, std::move(context_state),
+      cached_promise_texture_, tracker);
 }
 
 std::unique_ptr<SharedImageRepresentationGLTexture>
@@ -886,6 +954,7 @@
   if (IsPassthrough())
     return nullptr;
 
+  RetainGLTexture();
   if (!rgb_emulation_texture_) {
     const GLenum target = GetGLTarget();
     gl::GLApi* api = gl::g_current_gl_context;
@@ -908,6 +977,7 @@
       LOG(ERROR) << "Failed to bind image to rgb texture.";
       rgb_emulation_texture_->RemoveLightweightRef(true /* have_context */);
       rgb_emulation_texture_ = nullptr;
+      ReleaseGLTexture(true /* has_context */);
       return nullptr;
     }
     GLenum format =
@@ -958,7 +1028,14 @@
 #endif
 }
 
+void SharedImageBackingGLImage::SharedImageRepresentationGLTextureRelease(
+    bool has_context) {
+  ReleaseGLTexture(has_context);
+}
+
 bool SharedImageBackingGLImage::BindOrCopyImageIfNeeded() {
+  // This is called by code that has retained the GL texture.
+  DCHECK(texture_ || passthrough_texture_);
   if (!image_bind_or_copy_needed_)
     return true;
 
@@ -1025,6 +1102,7 @@
   if (SharedImageBackingFactoryIOSurface::InitializePixels(this, image_, data))
     return;
 #else
+  RetainGLTexture();
   BindOrCopyImageIfNeeded();
 
   const GLenum target = GetGLTarget();
@@ -1035,6 +1113,7 @@
       api, gl_unpack_attribs_, true /* uploading_data */);
   api->glTexSubImage2DFn(target, 0, 0, 0, size().width(), size().height(),
                          format, type, data);
+  ReleaseGLTexture(true /* have_context */);
 #endif
 }
 
@@ -1168,14 +1247,17 @@
     SurfaceHandle surface_handle,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage,
     bool is_thread_safe) {
   if (is_thread_safe) {
-    return MakeEglImageBacking(mailbox, format, size, color_space, usage);
+    return MakeEglImageBacking(mailbox, format, size, color_space,
+                               surface_origin, alpha_type, usage);
   } else {
     return CreateSharedImageInternal(mailbox, format, surface_handle, size,
-                                     color_space, usage,
-                                     base::span<const uint8_t>());
+                                     color_space, surface_origin, alpha_type,
+                                     usage, base::span<const uint8_t>());
   }
 }
 
@@ -1185,10 +1267,13 @@
     viz::ResourceFormat format,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage,
     base::span<const uint8_t> pixel_data) {
   return CreateSharedImageInternal(mailbox, format, kNullSurfaceHandle, size,
-                                   color_space, usage, pixel_data);
+                                   color_space, surface_origin, alpha_type,
+                                   usage, pixel_data);
 }
 
 std::unique_ptr<SharedImageBacking>
@@ -1200,6 +1285,8 @@
     SurfaceHandle surface_handle,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage) {
   if (!gpu_memory_buffer_formats_.Has(buffer_format)) {
     LOG(ERROR) << "CreateSharedImage: unsupported buffer format "
@@ -1262,8 +1349,8 @@
   params.framebuffer_attachment_angle =
       for_framebuffer_attachment && texture_usage_angle_;
   return std::make_unique<SharedImageBackingGLImage>(
-      image, mailbox, format, size, color_space, usage, params, attribs,
-      use_passthrough_);
+      image, mailbox, format, size, color_space, surface_origin, alpha_type,
+      usage, params, attribs, use_passthrough_);
 }
 
 std::unique_ptr<SharedImageBacking>
@@ -1276,8 +1363,8 @@
     const gfx::Size& size,
     uint32_t usage) {
   auto result = std::make_unique<SharedImageBackingGLTexture>(
-      mailbox, format, size, gfx::ColorSpace(), usage,
-      false /* is_passthrough */);
+      mailbox, format, size, gfx::ColorSpace(), kTopLeft_GrSurfaceOrigin,
+      kPremul_SkAlphaType, usage, false /* is_passthrough */);
   SharedImageBackingGLCommon::InitializeGLTextureParams params;
   params.target = target;
   params.internal_format = viz::GLInternalFormat(format);
@@ -1327,6 +1414,8 @@
     viz::ResourceFormat format,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage) {
 #if defined(OS_ANDROID)
   const FormatInfo& format_info = format_info_[format];
@@ -1351,9 +1440,9 @@
   }
 
   return std::make_unique<SharedImageBackingEglImage>(
-      mailbox, format, size, color_space, usage, estimated_size,
-      format_info.gl_format, format_info.gl_type, batch_access_manager_,
-      workarounds_);
+      mailbox, format, size, color_space, surface_origin, alpha_type, usage,
+      estimated_size, format_info.gl_format, format_info.gl_type,
+      batch_access_manager_, workarounds_);
 #else
   return nullptr;
 #endif
@@ -1366,6 +1455,8 @@
     SurfaceHandle surface_handle,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage,
     base::span<const uint8_t> pixel_data) {
   const FormatInfo& format_info = format_info_[format];
@@ -1496,8 +1587,8 @@
   if (image) {
     DCHECK(!format_info.swizzle);
     auto result = std::make_unique<SharedImageBackingGLImage>(
-        image, mailbox, format, size, color_space, usage, params, attribs,
-        use_passthrough_);
+        image, mailbox, format, size, color_space, surface_origin, alpha_type,
+        usage, params, attribs, use_passthrough_);
     if (!pixel_data.empty()) {
       result->InitializePixels(format_info.adjusted_format, format_info.gl_type,
                                pixel_data.data());
@@ -1505,7 +1596,8 @@
     return std::move(result);
   } else {
     auto result = std::make_unique<SharedImageBackingGLTexture>(
-        mailbox, format, size, color_space, usage, use_passthrough_);
+        mailbox, format, size, color_space, surface_origin, alpha_type, usage,
+        use_passthrough_);
     result->InitializeGLTexture(0, params);
 
     gl::GLApi* api = gl::g_current_gl_context;
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.h b/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.h
index b73c656..e08e2b6 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.h
+++ b/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.h
@@ -58,6 +58,8 @@
       SurfaceHandle surface_handle,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage,
       bool is_thread_safe) override;
   std::unique_ptr<SharedImageBacking> CreateSharedImage(
@@ -65,6 +67,8 @@
       viz::ResourceFormat format,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage,
       base::span<const uint8_t> pixel_data) override;
   std::unique_ptr<SharedImageBacking> CreateSharedImage(
@@ -75,6 +79,8 @@
       SurfaceHandle surface_handle,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage) override;
   bool CanImportGpuMemoryBuffer(
       gfx::GpuMemoryBufferType memory_buffer_type) override;
@@ -102,6 +108,8 @@
       viz::ResourceFormat format,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage);
 
   std::unique_ptr<SharedImageBacking> CreateSharedImageInternal(
@@ -110,6 +118,8 @@
       SurfaceHandle surface_handle,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage,
       base::span<const uint8_t> pixel_data);
 
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_gl_texture_internal.h b/gpu/command_buffer/service/shared_image_backing_factory_gl_texture_internal.h
index e501116d..d367ed7 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_gl_texture_internal.h
+++ b/gpu/command_buffer/service/shared_image_backing_factory_gl_texture_internal.h
@@ -17,6 +17,7 @@
  public:
   virtual bool SharedImageRepresentationGLTextureBeginAccess() = 0;
   virtual void SharedImageRepresentationGLTextureEndAccess() = 0;
+  virtual void SharedImageRepresentationGLTextureRelease(bool have_context) = 0;
 };
 
 // Representation of a SharedImageBackingGLTexture or SharedImageBackingGLImage
@@ -30,6 +31,7 @@
       SharedImageRepresentationGLTextureClient* client,
       MemoryTypeTracker* tracker,
       gles2::Texture* texture);
+  ~SharedImageRepresentationGLTextureImpl() override;
 
  private:
   // SharedImageRepresentationGLTexture:
@@ -171,6 +173,8 @@
                               viz::ResourceFormat format,
                               const gfx::Size& size,
                               const gfx::ColorSpace& color_space,
+                              GrSurfaceOrigin surface_origin,
+                              SkAlphaType alpha_type,
                               uint32_t usage,
                               bool is_passthrough);
   SharedImageBackingGLTexture(const SharedImageBackingGLTexture&) = delete;
@@ -234,6 +238,8 @@
       viz::ResourceFormat format,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage,
       const SharedImageBackingGLCommon::InitializeGLTextureParams& params,
       const SharedImageBackingFactoryGLTexture::UnpackStateAttribs& attribs,
@@ -283,6 +289,7 @@
   // SharedImageRepresentationGLTextureClient:
   bool SharedImageRepresentationGLTextureBeginAccess() override;
   void SharedImageRepresentationGLTextureEndAccess() override;
+  void SharedImageRepresentationGLTextureRelease(bool have_context) override;
 
   bool IsPassthrough() const { return is_passthrough_; }
 
@@ -293,11 +300,20 @@
   bool BindOrCopyImageIfNeeded();
   bool image_bind_or_copy_needed_ = true;
 
+  void RetainGLTexture();
+  void ReleaseGLTexture(bool have_context);
+  size_t gl_texture_retain_count_ = 0;
+  bool gl_texture_retained_for_legacy_mailbox_ = false;
+
   const SharedImageBackingGLCommon::InitializeGLTextureParams gl_params_;
   const SharedImageBackingFactoryGLTexture::UnpackStateAttribs
       gl_unpack_attribs_;
   const bool is_passthrough_;
 
+  // This is the cleared rect used by ClearedRect and SetClearedRect when
+  // |texture_| is nullptr.
+  gfx::Rect cleared_rect_;
+
   gles2::Texture* rgb_emulation_texture_ = nullptr;
   gles2::Texture* texture_ = nullptr;
   scoped_refptr<gles2::TexturePassthrough> passthrough_texture_;
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_gl_texture_unittest.cc b/gpu/command_buffer/service/shared_image_backing_factory_gl_texture_unittest.cc
index 647dad2..6694c8ae 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_gl_texture_unittest.cc
+++ b/gpu/command_buffer/service/shared_image_backing_factory_gl_texture_unittest.cc
@@ -216,11 +216,13 @@
   auto format = get_format();
   gfx::Size size(256, 256);
   auto color_space = gfx::ColorSpace::CreateSRGB();
+  GrSurfaceOrigin surface_origin = kTopLeft_GrSurfaceOrigin;
+  SkAlphaType alpha_type = kPremul_SkAlphaType;
   uint32_t usage = SHARED_IMAGE_USAGE_GLES2;
   gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
   auto backing = backing_factory_->CreateSharedImage(
-      mailbox, format, surface_handle, size, color_space, usage,
-      false /* is_thread_safe */);
+      mailbox, format, surface_handle, size, color_space, surface_origin,
+      alpha_type, usage, false /* is_thread_safe */);
 
   // As long as either |chromium_image_ar30| or |chromium_image_ab30| is
   // enabled, we can create a non-scanout SharedImage with format
@@ -348,11 +350,13 @@
   auto format = get_format();
   gfx::Size size(256, 256);
   auto color_space = gfx::ColorSpace::CreateSRGB();
+  GrSurfaceOrigin surface_origin = kTopLeft_GrSurfaceOrigin;
+  SkAlphaType alpha_type = kPremul_SkAlphaType;
   uint32_t usage = SHARED_IMAGE_USAGE_SCANOUT;
   gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
   auto backing = backing_factory_->CreateSharedImage(
-      mailbox, format, surface_handle, size, color_space, usage,
-      false /* is_thread_safe */);
+      mailbox, format, surface_handle, size, color_space, surface_origin,
+      alpha_type, usage, false /* is_thread_safe */);
 
   // We can only create a scanout SharedImage with format
   // viz::ResourceFormat::{BGRA,RGBA}_1010102 if the corresponding
@@ -473,8 +477,8 @@
     auto format = viz::ResourceFormat::RED_8;
     gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
     backing = backing_factory_->CreateSharedImage(
-        mailbox, format, surface_handle, size, color_space, usage,
-        false /* is_thread_safe */);
+        mailbox, format, surface_handle, size, color_space, surface_origin,
+        alpha_type, usage, false /* is_thread_safe */);
     EXPECT_TRUE(backing);
     shared_image = shared_image_manager_->Register(std::move(backing),
                                                    memory_type_tracker_.get());
@@ -501,11 +505,14 @@
     auto mailbox = Mailbox::GenerateForSharedImage();
     gfx::Size size(256, 256);
     auto color_space = gfx::ColorSpace::CreateSRGB();
+    GrSurfaceOrigin surface_origin = kTopLeft_GrSurfaceOrigin;
+    SkAlphaType alpha_type = kPremul_SkAlphaType;
     uint32_t usage = SHARED_IMAGE_USAGE_GLES2;
     std::vector<uint8_t> initial_data(
         viz::ResourceSizes::CheckedSizeInBytes<unsigned int>(size, format));
     auto backing = backing_factory_->CreateSharedImage(
-        mailbox, format, size, color_space, usage, initial_data);
+        mailbox, format, size, color_space, surface_origin, alpha_type, usage,
+        initial_data);
 
     if (format == viz::ResourceFormat::ETC1 && !supports_etc1_) {
       EXPECT_FALSE(backing);
@@ -567,10 +574,13 @@
   auto format = get_format();
   gfx::Size size(256, 256);
   auto color_space = gfx::ColorSpace::CreateSRGB();
+  GrSurfaceOrigin surface_origin = kTopLeft_GrSurfaceOrigin;
+  SkAlphaType alpha_type = kPremul_SkAlphaType;
   uint32_t usage = SHARED_IMAGE_USAGE_GLES2 | SHARED_IMAGE_USAGE_SCANOUT;
   std::vector<uint8_t> initial_data(256 * 256 * 4);
   auto backing = backing_factory_->CreateSharedImage(
-      mailbox, format, size, color_space, usage, initial_data);
+      mailbox, format, size, color_space, surface_origin, alpha_type, usage,
+      initial_data);
 
   // We can only create a scanout SharedImage with format
   // viz::ResourceFormat::{BGRA,RGBA}_1010102 if the corresponding
@@ -616,14 +626,18 @@
   auto format = get_format();
   gfx::Size size(256, 256);
   auto color_space = gfx::ColorSpace::CreateSRGB();
+  GrSurfaceOrigin surface_origin = kTopLeft_GrSurfaceOrigin;
+  SkAlphaType alpha_type = kPremul_SkAlphaType;
   uint32_t usage = SHARED_IMAGE_USAGE_GLES2;
   std::vector<uint8_t> initial_data_small(256 * 128 * 4);
   std::vector<uint8_t> initial_data_large(256 * 512 * 4);
   auto backing = backing_factory_->CreateSharedImage(
-      mailbox, format, size, color_space, usage, initial_data_small);
+      mailbox, format, size, color_space, surface_origin, alpha_type, usage,
+      initial_data_small);
   EXPECT_FALSE(backing);
   backing = backing_factory_->CreateSharedImage(
-      mailbox, format, size, color_space, usage, initial_data_large);
+      mailbox, format, size, color_space, surface_origin, alpha_type, usage,
+      initial_data_large);
   EXPECT_FALSE(backing);
 }
 
@@ -632,11 +646,13 @@
   auto format = viz::ResourceFormat::YUV_420_BIPLANAR;
   gfx::Size size(256, 256);
   auto color_space = gfx::ColorSpace::CreateSRGB();
+  GrSurfaceOrigin surface_origin = kTopLeft_GrSurfaceOrigin;
+  SkAlphaType alpha_type = kPremul_SkAlphaType;
   gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
   uint32_t usage = SHARED_IMAGE_USAGE_GLES2;
   auto backing = backing_factory_->CreateSharedImage(
-      mailbox, format, surface_handle, size, color_space, usage,
-      false /* is_thread_safe */);
+      mailbox, format, surface_handle, size, color_space, surface_origin,
+      alpha_type, usage, false /* is_thread_safe */);
   EXPECT_FALSE(backing);
 }
 
@@ -645,17 +661,19 @@
   auto format = get_format();
   gfx::Size size(0, 0);
   auto color_space = gfx::ColorSpace::CreateSRGB();
+  GrSurfaceOrigin surface_origin = kTopLeft_GrSurfaceOrigin;
+  SkAlphaType alpha_type = kPremul_SkAlphaType;
   gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
   uint32_t usage = SHARED_IMAGE_USAGE_GLES2;
   auto backing = backing_factory_->CreateSharedImage(
-      mailbox, format, surface_handle, size, color_space, usage,
-      false /* is_thread_safe */);
+      mailbox, format, surface_handle, size, color_space, surface_origin,
+      alpha_type, usage, false /* is_thread_safe */);
   EXPECT_FALSE(backing);
 
   size = gfx::Size(INT_MAX, INT_MAX);
-  backing = backing_factory_->CreateSharedImage(mailbox, format, surface_handle,
-                                                size, color_space, usage,
-                                                false /* is_thread_safe */);
+  backing = backing_factory_->CreateSharedImage(
+      mailbox, format, surface_handle, size, color_space, surface_origin,
+      alpha_type, usage, false /* is_thread_safe */);
   EXPECT_FALSE(backing);
 }
 
@@ -664,11 +682,13 @@
   auto format = get_format();
   gfx::Size size(256, 256);
   auto color_space = gfx::ColorSpace::CreateSRGB();
+  GrSurfaceOrigin surface_origin = kTopLeft_GrSurfaceOrigin;
+  SkAlphaType alpha_type = kPremul_SkAlphaType;
   gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
   uint32_t usage = SHARED_IMAGE_USAGE_GLES2;
   auto backing = backing_factory_->CreateSharedImage(
-      mailbox, format, surface_handle, size, color_space, usage,
-      false /* is_thread_safe */);
+      mailbox, format, surface_handle, size, color_space, surface_origin,
+      alpha_type, usage, false /* is_thread_safe */);
 
   // As long as either |chromium_image_ar30| or |chromium_image_ab30| is
   // enabled, we can create a non-scanout SharedImage with format
@@ -837,12 +857,14 @@
   gfx::Size size(256, 256);
   gfx::BufferFormat format = viz::BufferFormat(get_format());
   auto color_space = gfx::ColorSpace::CreateSRGB();
+  GrSurfaceOrigin surface_origin = kTopLeft_GrSurfaceOrigin;
+  SkAlphaType alpha_type = kPremul_SkAlphaType;
   uint32_t usage = SHARED_IMAGE_USAGE_GLES2;
 
   gfx::GpuMemoryBufferHandle handle;
   auto backing = backing_factory_->CreateSharedImage(
       mailbox, kClientId, std::move(handle), format, kNullSurfaceHandle, size,
-      color_space, usage);
+      color_space, surface_origin, alpha_type, usage);
   EXPECT_FALSE(backing);
 }
 
@@ -859,13 +881,15 @@
   gfx::Size size(256, 256);
   gfx::BufferFormat format = viz::BufferFormat(get_format());
   auto color_space = gfx::ColorSpace::CreateSRGB();
+  GrSurfaceOrigin surface_origin = kTopLeft_GrSurfaceOrigin;
+  SkAlphaType alpha_type = kPremul_SkAlphaType;
   uint32_t usage = SHARED_IMAGE_USAGE_GLES2;
 
   gfx::GpuMemoryBufferHandle handle;
   handle.type = gfx::NATIVE_PIXMAP;
   auto backing = backing_factory_->CreateSharedImage(
       mailbox, kClientId, std::move(handle), format, kNullSurfaceHandle, size,
-      color_space, usage);
+      color_space, surface_origin, alpha_type, usage);
 
   // We can only create a GMB SharedImage with format
   // viz::ResourceFormat::{BGRA,RGBA}_1010102 if the corresponding
@@ -910,6 +934,8 @@
   gfx::Size size(256, 256);
   gfx::BufferFormat format = viz::BufferFormat(get_format());
   auto color_space = gfx::ColorSpace::CreateSRGB();
+  GrSurfaceOrigin surface_origin = kTopLeft_GrSurfaceOrigin;
+  SkAlphaType alpha_type = kPremul_SkAlphaType;
   uint32_t usage = SHARED_IMAGE_USAGE_GLES2;
 
   size_t shm_size = 0u;
@@ -924,7 +950,7 @@
 
   auto backing = backing_factory_->CreateSharedImage(
       mailbox, kClientId, std::move(handle), format, kNullSurfaceHandle, size,
-      color_space, usage);
+      color_space, surface_origin, alpha_type, usage);
 
   // We can only create a GMB SharedImage with format
   // viz::ResourceFormat::{BGRA,RGBA}_1010102 if the corresponding
@@ -954,13 +980,15 @@
   gfx::Size size(256, 256);
   gfx::BufferFormat format = viz::BufferFormat(get_format());
   auto color_space = gfx::ColorSpace::CreateSRGB();
+  GrSurfaceOrigin surface_origin = kTopLeft_GrSurfaceOrigin;
+  SkAlphaType alpha_type = kPremul_SkAlphaType;
   uint32_t usage = SHARED_IMAGE_USAGE_GLES2;
 
   gfx::GpuMemoryBufferHandle handle;
   handle.type = gfx::NATIVE_PIXMAP;
   auto backing = backing_factory_->CreateSharedImage(
       mailbox, kClientId, std::move(handle), format, kNullSurfaceHandle, size,
-      color_space, usage);
+      color_space, surface_origin, alpha_type, usage);
 
   // We can only create a GMB SharedImage with format
   // viz::ResourceFormat::{BGRA,RGBA}_1010102 if the corresponding
@@ -1105,6 +1133,8 @@
       context_state->MakeCurrent(context_state->surface(), true /* needs_gl*/));
   mailbox_ = Mailbox::GenerateForSharedImage();
   auto color_space = gfx::ColorSpace::CreateSRGB();
+  GrSurfaceOrigin surface_origin = kTopLeft_GrSurfaceOrigin;
+  SkAlphaType alpha_type = kPremul_SkAlphaType;
   gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
 
   // SHARED_IMAGE_USAGE_DISPLAY for skia read and SHARED_IMAGE_USAGE_RASTER for
@@ -1113,8 +1143,8 @@
   if (!is_thread_safe)
     usage |= SHARED_IMAGE_USAGE_DISPLAY;
   backing_ = backing_factory->CreateSharedImage(
-      mailbox_, format, surface_handle, size_, color_space, usage,
-      is_thread_safe);
+      mailbox_, format, surface_handle, size_, color_space, surface_origin,
+      alpha_type, usage, is_thread_safe);
 
   // As long as either |chromium_image_ar30| or |chromium_image_ab30| is
   // enabled, we can create a non-scanout SharedImage with format
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_iosurface.h b/gpu/command_buffer/service/shared_image_backing_factory_iosurface.h
index cb463178..6f34aa3 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_iosurface.h
+++ b/gpu/command_buffer/service/shared_image_backing_factory_iosurface.h
@@ -8,45 +8,21 @@
 #include <memory>
 
 #include "base/macros.h"
-#include "components/viz/common/resources/resource_format.h"
 #include "gpu/command_buffer/service/shared_image_backing.h"
-#include "gpu/command_buffer/service/shared_image_backing_factory.h"
 #include "gpu/command_buffer/service/shared_image_representation.h"
 #include "gpu/gpu_gles2_export.h"
-#include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_image.h"
 
-namespace gfx {
-class Size;
-class ColorSpace;
-}  // namespace gfx
-
 namespace gpu {
-class GpuDriverBugWorkarounds;
-struct GpuFeatureInfo;
-struct Mailbox;
 
-// Implementation of SharedImageBackingFactory that produce IOSurface backed
-// SharedImages. This is meant to be used on macOS only.
-class GPU_GLES2_EXPORT SharedImageBackingFactoryIOSurface
-    : public SharedImageBackingFactory {
+// Helper functions used used by SharedImageRepresentationGLImage to do
+// IOSurface-specific sharing.
+class GPU_GLES2_EXPORT SharedImageBackingFactoryIOSurface {
  public:
-  SharedImageBackingFactoryIOSurface(const GpuDriverBugWorkarounds& workarounds,
-                                     const GpuFeatureInfo& gpu_feature_info,
-                                     bool use_gl);
-  ~SharedImageBackingFactoryIOSurface() override;
-
-  // Helper functions used used by SharedImageRepresentationGLImage to do
-  // IOSurface-specific sharing.
   static sk_sp<SkPromiseImageTexture> ProduceSkiaPromiseTextureMetal(
       SharedImageBacking* backing,
       scoped_refptr<SharedContextState> context_state,
       scoped_refptr<gl::GLImage> image);
-  static std::unique_ptr<SharedImageRepresentationOverlay> ProduceOverlay(
-      SharedImageManager* manager,
-      SharedImageBacking* backing,
-      MemoryTypeTracker* tracker,
-      scoped_refptr<gl::GLImage> image);
   static std::unique_ptr<SharedImageRepresentationDawn> ProduceDawn(
       SharedImageManager* manager,
       SharedImageBacking* backing,
@@ -56,42 +32,6 @@
   static bool InitializePixels(SharedImageBacking* backing,
                                scoped_refptr<gl::GLImage> image,
                                const uint8_t* pixel_data);
-
-  // SharedImageBackingFactory implementation.
-  std::unique_ptr<SharedImageBacking> CreateSharedImage(
-      const Mailbox& mailbox,
-      viz::ResourceFormat requested_format,
-      SurfaceHandle surface_handle,
-      const gfx::Size& size,
-      const gfx::ColorSpace& color_space,
-      uint32_t usage,
-      bool is_thread_safe) override;
-  std::unique_ptr<SharedImageBacking> CreateSharedImage(
-      const Mailbox& mailbox,
-      viz::ResourceFormat format,
-      const gfx::Size& size,
-      const gfx::ColorSpace& color_space,
-      uint32_t usage,
-      base::span<const uint8_t> pixel_data) override;
-  std::unique_ptr<SharedImageBacking> CreateSharedImage(
-      const Mailbox& mailbox,
-      int client_id,
-      gfx::GpuMemoryBufferHandle handle,
-      gfx::BufferFormat format,
-      SurfaceHandle surface_handle,
-      const gfx::Size& size,
-      const gfx::ColorSpace& color_space,
-      uint32_t usage) override;
-  bool CanImportGpuMemoryBuffer(
-      gfx::GpuMemoryBufferType memory_buffer_type) override;
-
- private:
-  void CollectGLFormatInfo(const GpuDriverBugWorkarounds& workarounds,
-                           const GpuFeatureInfo& gpu_feature_info);
-  bool format_supported_by_gl_[viz::RESOURCE_FORMAT_MAX + 1];
-  bool use_gl_ = false;
-
-  DISALLOW_COPY_AND_ASSIGN(SharedImageBackingFactoryIOSurface);
 };
 
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_iosurface.mm b/gpu/command_buffer/service/shared_image_backing_factory_iosurface.mm
index e6e1b40c..8b1f3d6 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_iosurface.mm
+++ b/gpu/command_buffer/service/shared_image_backing_factory_iosurface.mm
@@ -35,74 +35,6 @@
 
 namespace {
 
-struct GLFormatInfo {
-  bool supported = false;
-
-  // GL internal_format/format/type triplet.
-  GLuint internal_format = 0;
-  GLenum format = 0;
-  GLenum type = 0;
-};
-
-// Get GL format triplets and modify them to match the logic in
-// gl_image_iosurface.mm
-GLFormatInfo GetGLFormatInfo(viz::ResourceFormat format) {
-  GLFormatInfo info = {
-      true,
-      viz::GLInternalFormat(format),
-      viz::GLDataFormat(format),
-      viz::GLDataType(format),
-  };
-
-  if (info.internal_format == GL_ZERO || info.format == GL_ZERO ||
-      info.type == GL_ZERO) {
-    return {false, GL_ZERO, GL_ZERO, GL_ZERO};
-  }
-
-  switch (format) {
-    case viz::BGRA_8888:
-      info.format = GL_RGBA;
-      info.internal_format = GL_RGBA;
-      break;
-
-      // Technically we should use GL_RGB but CGLTexImageIOSurface2D() (and
-      // OpenGL ES 3.0, for the case) support only GL_RGBA (the hardware ignores
-      // the alpha channel anyway), see https://crbug.com/797347.
-    case viz::BGRA_1010102:
-      info.format = GL_RGBA;
-      info.internal_format = GL_RGBA;
-      break;
-
-    default:
-      break;
-  }
-
-  return info;
-}
-
-void FlushIOSurfaceGLOperations() {
-  // The CGLTexImageIOSurface2D documentation says that we need to call
-  // glFlush, otherwise there is the risk of a race between different
-  // graphics contexts.
-  gl::GLApi* api = gl::g_current_gl_context;
-  api->glFlushFn();
-}
-
-base::Optional<WGPUTextureFormat> GetWGPUFormat(gfx::BufferFormat format) {
-  switch (format) {
-    case gfx::BufferFormat::R_8:
-      return WGPUTextureFormat_R8Unorm;
-    case gfx::BufferFormat::RG_88:
-      return WGPUTextureFormat_RG8Unorm;
-    case gfx::BufferFormat::RGBX_8888:
-    case gfx::BufferFormat::RGBA_8888:
-    case gfx::BufferFormat::BGRX_8888:
-      return WGPUTextureFormat_BGRA8Unorm;
-    default:
-      return {};
-  }
-}
-
 base::scoped_nsprotocol<id<MTLTexture>> API_AVAILABLE(macos(10.11))
     CreateMetalTexture(id<MTLDevice> mtl_device,
                        IOSurfaceRef io_surface,
@@ -148,125 +80,6 @@
 
 }  // anonymous namespace
 
-// Representation of a SharedImageBackingIOSurface as a GL Texture.
-class SharedImageRepresentationGLTextureIOSurface
-    : public SharedImageRepresentationGLTexture {
- public:
-  SharedImageRepresentationGLTextureIOSurface(SharedImageManager* manager,
-                                              SharedImageBacking* backing,
-                                              MemoryTypeTracker* tracker,
-                                              gles2::Texture* texture)
-      : SharedImageRepresentationGLTexture(manager, backing, tracker),
-        texture_(texture) {
-    DCHECK(texture_);
-  }
-
-  ~SharedImageRepresentationGLTextureIOSurface() override {
-    texture_->RemoveLightweightRef(has_context());
-  }
-
-  gles2::Texture* GetTexture() override { return texture_; }
-
-  bool BeginAccess(GLenum mode) override { return true; }
-
-  void EndAccess() override { FlushIOSurfaceGLOperations(); }
-
- private:
-  gles2::Texture* texture_;
-
-  DISALLOW_COPY_AND_ASSIGN(SharedImageRepresentationGLTextureIOSurface);
-};
-
-class SharedImageRepresentationGLTexturePassthroughIOSurface
-    : public SharedImageRepresentationGLTexturePassthrough {
- public:
-  SharedImageRepresentationGLTexturePassthroughIOSurface(
-      SharedImageManager* manager,
-      SharedImageBacking* backing,
-      MemoryTypeTracker* tracker,
-      scoped_refptr<gles2::TexturePassthrough> texture_passthrough)
-      : SharedImageRepresentationGLTexturePassthrough(manager,
-                                                      backing,
-                                                      tracker),
-        texture_passthrough_(texture_passthrough) {}
-
-  const scoped_refptr<gles2::TexturePassthrough>& GetTexturePassthrough()
-      override {
-    return texture_passthrough_;
-  }
-  bool BeginAccess(GLenum mode) override { return true; }
-  void EndAccess() override { FlushIOSurfaceGLOperations(); }
-
- private:
-  scoped_refptr<gles2::TexturePassthrough> texture_passthrough_;
-  DISALLOW_COPY_AND_ASSIGN(
-      SharedImageRepresentationGLTexturePassthroughIOSurface);
-};
-
-// Representation of a SharedImageBackingIOSurface as a Skia Texture.
-class SharedImageRepresentationSkiaIOSurface
-    : public SharedImageRepresentationSkia {
- public:
-  SharedImageRepresentationSkiaIOSurface(
-      SharedImageManager* manager,
-      SharedImageBacking* backing,
-      scoped_refptr<SharedContextState> context_state,
-      sk_sp<SkPromiseImageTexture> promise_texture,
-      MemoryTypeTracker* tracker,
-      gles2::Texture* gles2_texture)
-      : SharedImageRepresentationSkia(manager, backing, tracker),
-        context_state_(std::move(context_state)),
-        promise_texture_(std::move(promise_texture)),
-        gles2_texture_(gles2_texture) {
-    DCHECK(promise_texture_);
-  }
-
-  ~SharedImageRepresentationSkiaIOSurface() override {
-    if (gles2_texture_)
-      gles2_texture_->RemoveLightweightRef(has_context());
-  }
-
-  sk_sp<SkSurface> BeginWriteAccess(
-      int final_msaa_count,
-      const SkSurfaceProps& surface_props,
-      std::vector<GrBackendSemaphore>* begin_semaphores,
-      std::vector<GrBackendSemaphore>* end_semaphores) override {
-    SkColorType sk_color_type = viz::ResourceFormatToClosestSkColorType(
-        /*gpu_compositing=*/true, format());
-
-    return SkSurface::MakeFromBackendTexture(
-        context_state_->gr_context(), promise_texture_->backendTexture(),
-        kTopLeft_GrSurfaceOrigin, final_msaa_count, sk_color_type,
-        backing()->color_space().ToSkColorSpace(), &surface_props);
-  }
-
-  void EndWriteAccess(sk_sp<SkSurface> surface) override {
-    if (context_state_->GrContextIsGL())
-      FlushIOSurfaceGLOperations();
-
-    if (gles2_texture_ &&
-        gles2_texture_->IsLevelCleared(gles2_texture_->target(), 0)) {
-      backing()->SetCleared();
-    }
-  }
-
-  sk_sp<SkPromiseImageTexture> BeginReadAccess(
-      std::vector<GrBackendSemaphore>* begin_semaphores,
-      std::vector<GrBackendSemaphore>* end_semaphores) override {
-    return promise_texture_;
-  }
-
-  void EndReadAccess() override {
-    if (context_state_->GrContextIsGL())
-      FlushIOSurfaceGLOperations();
-  }
-
- private:
-  scoped_refptr<SharedContextState> context_state_;
-  sk_sp<SkPromiseImageTexture> promise_texture_;
-  gles2::Texture* const gles2_texture_;
-};
-
 // Representation of a SharedImageBackingIOSurface as a Dawn Texture.
 #if BUILDFLAG(USE_DAWN)
 class SharedImageRepresentationDawnIOSurface
@@ -364,414 +177,6 @@
 };
 #endif  // BUILDFLAG(USE_DAWN)
 
-// Implementation of SharedImageBacking by wrapping IOSurfaces. Disable
-// unguarded availability warnings because they are incompatible with using a
-// scoped_nsprotocol for the id<MTLTexture> and because all access to Metal is
-// guarded on the context provider already successfully using Metal.
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunguarded-availability"
-class SharedImageBackingIOSurface : public ClearTrackingSharedImageBacking {
- public:
-  SharedImageBackingIOSurface(const Mailbox& mailbox,
-                              viz::ResourceFormat format,
-                              const gfx::Size& size,
-                              const gfx::ColorSpace& color_space,
-                              uint32_t usage,
-                              base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
-                              base::Optional<WGPUTextureFormat> dawn_format,
-                              size_t estimated_size)
-      : ClearTrackingSharedImageBacking(mailbox,
-                                        format,
-                                        size,
-                                        color_space,
-                                        usage,
-                                        estimated_size,
-                                        false /* is_thread_safe */),
-        io_surface_(std::move(io_surface)),
-        dawn_format_(dawn_format) {
-    DCHECK(io_surface_);
-  }
-  ~SharedImageBackingIOSurface() final {
-    TRACE_EVENT0("gpu", "SharedImageBackingFactoryIOSurface::Destroy");
-    DCHECK(io_surface_);
-
-    if (legacy_texture_) {
-      legacy_texture_->RemoveLightweightRef(have_context());
-      legacy_texture_ = nullptr;
-    }
-    mtl_texture_.reset();
-    io_surface_.reset();
-  }
-
-  gfx::Rect ClearedRect() const final {
-    // If a |legacy_texture_| exists, defer to that. Once created,
-    // |legacy_texture_| is never destroyed, so no need to synchronize with
-    // ClearedRect.
-    if (legacy_texture_) {
-      return legacy_texture_->GetLevelClearedRect(legacy_texture_->target(), 0);
-    } else {
-      return ClearTrackingSharedImageBacking::ClearedRect();
-    }
-  }
-
-  void SetClearedRect(const gfx::Rect& cleared_rect) final {
-    // If a |legacy_texture_| exists, defer to that. Once created,
-    // |legacy_texture_| is never destroyed, so no need to synchronize with
-    // SetClearedRect.
-    if (legacy_texture_) {
-      legacy_texture_->SetLevelClearedRect(legacy_texture_->target(), 0,
-                                           cleared_rect);
-    } else {
-      ClearTrackingSharedImageBacking::SetClearedRect(cleared_rect);
-    }
-  }
-
-  void Update(std::unique_ptr<gfx::GpuFence> in_fence) final {}
-
-  bool ProduceLegacyMailbox(MailboxManager* mailbox_manager) final {
-    DCHECK(io_surface_);
-
-    GenGLTexture(&legacy_texture_, nullptr);
-    if (!legacy_texture_) {
-      return false;
-    }
-
-    // Make sure our |legacy_texture_| has the right initial cleared rect.
-    legacy_texture_->SetLevelClearedRect(
-        legacy_texture_->target(), 0,
-        ClearTrackingSharedImageBacking::ClearedRect());
-
-    mailbox_manager->ProduceTexture(mailbox(), legacy_texture_);
-    return true;
-  }
-
- protected:
-  std::unique_ptr<SharedImageRepresentationGLTexture> ProduceGLTexture(
-      SharedImageManager* manager,
-      MemoryTypeTracker* tracker) final {
-    gles2::Texture* texture = nullptr;
-    GenGLTexture(&texture, nullptr);
-    if (!texture)
-      return nullptr;
-    return std::make_unique<SharedImageRepresentationGLTextureIOSurface>(
-        manager, this, tracker, texture);
-  }
-
-  std::unique_ptr<SharedImageRepresentationGLTexturePassthrough>
-  ProduceGLTexturePassthrough(SharedImageManager* manager,
-                              MemoryTypeTracker* tracker) override {
-    TRACE_EVENT0("gpu",
-                 "SharedImageBackingFactoryIOSurface::GenGLTexturePassthrough");
-    scoped_refptr<gles2::TexturePassthrough> texture_passthrough;
-    GenGLTexture(nullptr, &texture_passthrough);
-    if (!texture_passthrough)
-      return nullptr;
-    return std::make_unique<
-        SharedImageRepresentationGLTexturePassthroughIOSurface>(
-        manager, this, tracker, texture_passthrough);
-  }
-
-  std::unique_ptr<SharedImageRepresentationSkia> ProduceSkia(
-      SharedImageManager* manager,
-      MemoryTypeTracker* tracker,
-      scoped_refptr<SharedContextState> context_state) override {
-    gles2::Texture* gles2_texture = nullptr;
-    GrBackendTexture gr_backend_texture;
-    if (context_state->GrContextIsGL()) {
-      GenGLTexture(&gles2_texture, nullptr);
-      if (!gles2_texture)
-        return nullptr;
-      GetGrBackendTexture(
-          context_state->feature_info(), gles2_texture->target(), size(),
-          gles2_texture->service_id(), format(), &gr_backend_texture);
-    }
-    if (context_state->GrContextIsMetal()) {
-      if (!mtl_texture_) {
-        id<MTLDevice> mtl_device =
-            context_state->metal_context_provider()->GetMTLDevice();
-        mtl_texture_ =
-            CreateMetalTexture(mtl_device, io_surface_, size(), format());
-        DCHECK(mtl_texture_);
-      }
-      GrMtlTextureInfo info;
-      info.fTexture.retain(mtl_texture_.get());
-      gr_backend_texture = GrBackendTexture(size().width(), size().height(),
-                                            GrMipMapped::kNo, info);
-    }
-    sk_sp<SkPromiseImageTexture> promise_texture =
-        SkPromiseImageTexture::Make(gr_backend_texture);
-    return std::make_unique<SharedImageRepresentationSkiaIOSurface>(
-        manager, this, std::move(context_state), promise_texture, tracker,
-        gles2_texture);
-  }
-
-  std::unique_ptr<SharedImageRepresentationDawn> ProduceDawn(
-      SharedImageManager* manager,
-      MemoryTypeTracker* tracker,
-      WGPUDevice device) override {
-#if BUILDFLAG(USE_DAWN)
-    if (!dawn_format_) {
-      LOG(ERROR) << "Format not supported for Dawn";
-      return nullptr;
-    }
-
-    return std::make_unique<SharedImageRepresentationDawnIOSurface>(
-        manager, this, tracker, device, io_surface_, dawn_format_.value());
-#else   // BUILDFLAG(USE_DAWN)
-    return nullptr;
-#endif  // BUILDFLAG(USE_DAWN)
-  }
-
- private:
-  bool EnsureGLImage() {
-    if (!gl_image_) {
-      GLFormatInfo gl_info = GetGLFormatInfo(format());
-      scoped_refptr<gl::GLImageIOSurface> gl_image(
-          gl::GLImageIOSurface::Create(size(), gl_info.internal_format));
-      if (!gl_image->Initialize(io_surface_, gfx::GenericSharedMemoryId(),
-                                viz::BufferFormat(format()))) {
-        LOG(ERROR) << "Failed to create GLImageIOSurface";
-      } else {
-        gl_image_ = gl_image;
-      }
-    }
-    return !!gl_image_;
-  }
-
-  void GenGLTexture(
-      gles2::Texture** texture,
-      scoped_refptr<gles2::TexturePassthrough>* texture_passthrough) {
-    TRACE_EVENT0("gpu", "SharedImageBackingFactoryIOSurface::GenGLTexture");
-    GLFormatInfo gl_info = GetGLFormatInfo(format());
-    DCHECK(gl_info.supported);
-    if (texture)
-      *texture = nullptr;
-    if (texture_passthrough)
-      *texture_passthrough = nullptr;
-
-    // Wrap the IOSurface in a GLImageIOSurface
-    if (!EnsureGLImage())
-      return;
-
-    gl::GLApi* api = gl::g_current_gl_context;
-
-    // Save the currently bound rectangle texture to reset it once we are done.
-    GLint old_texture_binding = 0;
-    api->glGetIntegervFn(GL_TEXTURE_BINDING_RECTANGLE, &old_texture_binding);
-
-    // Create a gles2 rectangle texture to bind to the IOSurface.
-    GLuint service_id = 0;
-    api->glGenTexturesFn(1, &service_id);
-    api->glBindTextureFn(GL_TEXTURE_RECTANGLE, service_id);
-    api->glTexParameteriFn(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER,
-                           GL_LINEAR);
-    api->glTexParameteriFn(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER,
-                           GL_LINEAR);
-    api->glTexParameteriFn(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S,
-                           GL_CLAMP_TO_EDGE);
-    api->glTexParameteriFn(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T,
-                           GL_CLAMP_TO_EDGE);
-
-    // Bind the GLImageIOSurface to our texture
-    if (!gl_image_->BindTexImage(GL_TEXTURE_RECTANGLE)) {
-      LOG(ERROR) << "Failed to bind GLImageIOSurface";
-      api->glBindTextureFn(GL_TEXTURE_RECTANGLE, old_texture_binding);
-      api->glDeleteTexturesFn(1, &service_id);
-      return;
-    }
-
-    // If the backing is already cleared, no need to clear it again.
-    gfx::Rect cleared_rect = ClearedRect();
-
-    // Manually create a gles2::Texture wrapping our driver texture.
-    if (texture) {
-      *texture = new gles2::Texture(service_id);
-      (*texture)->SetLightweightRef();
-      (*texture)->SetTarget(GL_TEXTURE_RECTANGLE, 1);
-      (*texture)->set_min_filter(GL_LINEAR);
-      (*texture)->set_mag_filter(GL_LINEAR);
-      (*texture)->set_wrap_t(GL_CLAMP_TO_EDGE);
-      (*texture)->set_wrap_s(GL_CLAMP_TO_EDGE);
-      (*texture)->SetLevelInfo(GL_TEXTURE_RECTANGLE, 0, gl_info.internal_format,
-                               size().width(), size().height(), 1, 0,
-                               gl_info.format, gl_info.type, cleared_rect);
-      (*texture)->SetLevelImage(GL_TEXTURE_RECTANGLE, 0, gl_image_.get(),
-                                gles2::Texture::BOUND);
-      (*texture)->SetImmutable(true, false);
-    }
-    if (texture_passthrough) {
-      *texture_passthrough = scoped_refptr<gles2::TexturePassthrough>(
-          new gles2::TexturePassthrough(service_id, GL_TEXTURE_RECTANGLE,
-                                        gl_info.internal_format, size().width(),
-                                        size().height(), 1, 0, gl_info.format,
-                                        gl_info.type));
-      (*texture_passthrough)
-          ->SetLevelImage(GL_TEXTURE_RECTANGLE, 0, gl_image_.get());
-    }
-
-    DCHECK_EQ(gl_image_->GetInternalFormat(), gl_info.internal_format);
-
-    api->glBindTextureFn(GL_TEXTURE_RECTANGLE, old_texture_binding);
-  }
-
-  scoped_refptr<gl::GLImageIOSurface> gl_image_;
-  base::ScopedCFTypeRef<IOSurfaceRef> io_surface_;
-  base::Optional<WGPUTextureFormat> dawn_format_;
-  base::scoped_nsprotocol<id<MTLTexture>> mtl_texture_;
-
-  // A texture for the associated legacy mailbox.
-  gles2::Texture* legacy_texture_ = nullptr;
-
-  DISALLOW_COPY_AND_ASSIGN(SharedImageBackingIOSurface);
-};
-#pragma clang diagnostic pop
-
-// Implementation of SharedImageBackingFactoryIOSurface that creates
-// SharedImageBackings wrapping IOSurfaces.
-SharedImageBackingFactoryIOSurface::SharedImageBackingFactoryIOSurface(
-    const GpuDriverBugWorkarounds& workarounds,
-    const GpuFeatureInfo& gpu_feature_info,
-    bool use_gl)
-    : use_gl_(use_gl) {
-  if (use_gl_) {
-    CollectGLFormatInfo(workarounds, gpu_feature_info);
-  }
-}
-
-void SharedImageBackingFactoryIOSurface::CollectGLFormatInfo(
-    const GpuDriverBugWorkarounds& workarounds,
-    const GpuFeatureInfo& gpu_feature_info) {
-  scoped_refptr<gles2::FeatureInfo> feature_info =
-      new gles2::FeatureInfo(workarounds, gpu_feature_info);
-  feature_info->Initialize(ContextType::CONTEXT_TYPE_OPENGLES2, false,
-                           gles2::DisallowedFeatures());
-  const gles2::Validators* validators = feature_info->validators();
-
-  // Precompute for each format if we can use it with GL.
-  for (int i = 0; i <= viz::RESOURCE_FORMAT_MAX; ++i) {
-    viz::ResourceFormat format = static_cast<viz::ResourceFormat>(i);
-    GLFormatInfo gl_info = GetGLFormatInfo(format);
-
-    format_supported_by_gl_[i] =
-        gl_info.supported &&
-        validators->texture_internal_format.IsValid(gl_info.internal_format) &&
-        validators->texture_format.IsValid(gl_info.format) &&
-        validators->pixel_type.IsValid(gl_info.type);
-  }
-}
-
-SharedImageBackingFactoryIOSurface::~SharedImageBackingFactoryIOSurface() =
-    default;
-
-std::unique_ptr<SharedImageBacking>
-SharedImageBackingFactoryIOSurface::CreateSharedImage(
-    const Mailbox& mailbox,
-    viz::ResourceFormat requested_format,
-    SurfaceHandle surface_handle,
-    const gfx::Size& size,
-    const gfx::ColorSpace& color_space,
-    uint32_t usage,
-    bool is_thread_safe) {
-  TRACE_EVENT0("gpu", "SharedImageBackingFactoryIOSurface::CreateSharedImage");
-  DCHECK(!is_thread_safe);
-  // Check the format is supported and for simplicity always require it to be
-  // supported for GL.
-  if (use_gl_ && !format_supported_by_gl_[requested_format]) {
-    LOG(ERROR) << "viz::ResourceFormat " << requested_format
-               << " not supported by IOSurfaces";
-    return nullptr;
-  }
-
-  // Calculate SharedImage size in bytes.
-  size_t estimated_size;
-  if (!viz::ResourceSizes::MaybeSizeInBytes(size, requested_format,
-                                            &estimated_size)) {
-    LOG(ERROR) << "Failed to calculate SharedImage size";
-    return nullptr;
-  }
-
-  // Note: OpenGL textures bound to IOSurfaces won't work on macOS unless the
-  // internal format is BGRA. So if RGBA8 is passed into CreateIOSurface(), the
-  // resulting IOSurface is actually BGRA8 (see PixelFormat() in
-  // ui/gfx/mac/io_surface.cc).
-  // Explicitly override it here to avoid confusion.
-  viz::ResourceFormat actual_format = requested_format;
-  if (requested_format == viz::RGBA_8888) {
-    actual_format = viz::BGRA_8888;
-  }
-
-  base::ScopedCFTypeRef<IOSurfaceRef> io_surface(
-      gfx::CreateIOSurface(size, viz::BufferFormat(actual_format), false));
-  if (!io_surface) {
-    LOG(ERROR) << "Failed to allocate IOSurface.";
-    return nullptr;
-  }
-
-  gfx::IOSurfaceSetColorSpace(io_surface, color_space);
-
-  base::Optional<WGPUTextureFormat> wgpu_format =
-      viz::ToWGPUFormat(actual_format);
-  if (wgpu_format.value() == WGPUTextureFormat_Undefined) {
-    wgpu_format = base::nullopt;
-  }
-
-  return std::make_unique<SharedImageBackingIOSurface>(
-      mailbox, requested_format, size, color_space, usage,
-      std::move(io_surface), wgpu_format, estimated_size);
-}
-
-std::unique_ptr<SharedImageBacking>
-SharedImageBackingFactoryIOSurface::CreateSharedImage(
-    const Mailbox& mailbox,
-    viz::ResourceFormat format,
-    const gfx::Size& size,
-    const gfx::ColorSpace& color_space,
-    uint32_t usage,
-    base::span<const uint8_t> pixel_data) {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
-std::unique_ptr<SharedImageBacking>
-SharedImageBackingFactoryIOSurface::CreateSharedImage(
-    const Mailbox& mailbox,
-    int client_id,
-    gfx::GpuMemoryBufferHandle handle,
-    gfx::BufferFormat format,
-    SurfaceHandle surface_handle,
-    const gfx::Size& size,
-    const gfx::ColorSpace& color_space,
-    uint32_t usage) {
-  if (handle.type != gfx::GpuMemoryBufferType::IO_SURFACE_BUFFER) {
-    NOTIMPLEMENTED();
-    return nullptr;
-  }
-
-  base::ScopedCFTypeRef<IOSurfaceRef> io_surface(
-      IOSurfaceLookupFromMachPort(handle.mach_port.get()));
-  if (!io_surface) {
-    DLOG(ERROR) << "IOSurfaceLookupFromMachPort failed.";
-    return nullptr;
-  }
-
-  viz::ResourceFormat resource_format = viz::GetResourceFormat(format);
-  size_t estimated_size = 0;
-  if (!viz::ResourceSizes::MaybeSizeInBytes(size, resource_format,
-                                            &estimated_size)) {
-    DLOG(ERROR) << "Failed to calculate SharedImage size";
-    return nullptr;
-  }
-
-  return std::make_unique<SharedImageBackingIOSurface>(
-      mailbox, resource_format, size, color_space, usage, std::move(io_surface),
-      GetWGPUFormat(format), estimated_size);
-}
-
-bool SharedImageBackingFactoryIOSurface::CanImportGpuMemoryBuffer(
-    gfx::GpuMemoryBufferType memory_buffer_type) {
-  return false;
-}
-
 // static
 sk_sp<SkPromiseImageTexture>
 SharedImageBackingFactoryIOSurface::ProduceSkiaPromiseTextureMetal(
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_iosurface_unittest.cc b/gpu/command_buffer/service/shared_image_backing_factory_iosurface_unittest.cc
index f9f3422..3c705e2 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_iosurface_unittest.cc
+++ b/gpu/command_buffer/service/shared_image_backing_factory_iosurface_unittest.cc
@@ -150,12 +150,14 @@
   viz::ResourceFormat format = viz::ResourceFormat::RGBA_8888;
   gfx::Size size(256, 256);
   gfx::ColorSpace color_space = gfx::ColorSpace::CreateSRGB();
+  GrSurfaceOrigin surface_origin = kTopLeft_GrSurfaceOrigin;
+  SkAlphaType alpha_type = kPremul_SkAlphaType;
   gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
   uint32_t usage = SHARED_IMAGE_USAGE_GLES2 | SHARED_IMAGE_USAGE_SCANOUT;
 
   auto backing = backing_factory_->CreateSharedImage(
-      mailbox, format, surface_handle, size, color_space, usage,
-      false /* is_thread_safe */);
+      mailbox, format, surface_handle, size, color_space, surface_origin,
+      alpha_type, usage, false /* is_thread_safe */);
   EXPECT_TRUE(backing);
 
   // Check clearing.
@@ -252,11 +254,13 @@
   auto format = viz::ResourceFormat::RGBA_8888;
   gfx::Size size(1, 1);
   auto color_space = gfx::ColorSpace::CreateSRGB();
+  GrSurfaceOrigin surface_origin = kTopLeft_GrSurfaceOrigin;
+  SkAlphaType alpha_type = kPremul_SkAlphaType;
   gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
   uint32_t usage = SHARED_IMAGE_USAGE_GLES2 | SHARED_IMAGE_USAGE_SCANOUT;
   auto backing = backing_factory_->CreateSharedImage(
-      mailbox, format, surface_handle, size, color_space, usage,
-      false /* is_thread_safe */);
+      mailbox, format, surface_handle, size, color_space, surface_origin,
+      alpha_type, usage, false /* is_thread_safe */);
   EXPECT_TRUE(backing);
 
   GLenum expected_target = GL_TEXTURE_RECTANGLE;
@@ -308,13 +312,15 @@
   viz::ResourceFormat format = viz::ResourceFormat::RGBA_8888;
   gfx::Size size(256, 256);
   gfx::ColorSpace color_space = gfx::ColorSpace::CreateSRGB();
+  GrSurfaceOrigin surface_origin = kTopLeft_GrSurfaceOrigin;
+  SkAlphaType alpha_type = kPremul_SkAlphaType;
   uint32_t usage = SHARED_IMAGE_USAGE_GLES2 | SHARED_IMAGE_USAGE_SCANOUT;
   gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
 
   // Create a backing.
   auto backing = backing_factory_->CreateSharedImage(
-      mailbox, format, surface_handle, size, color_space, usage,
-      false /* is_thread_safe */);
+      mailbox, format, surface_handle, size, color_space, surface_origin,
+      alpha_type, usage, false /* is_thread_safe */);
   EXPECT_TRUE(backing);
   backing->SetCleared();
   EXPECT_TRUE(backing->IsCleared());
@@ -385,11 +391,13 @@
   auto format = viz::ResourceFormat::RGBA_8888;
   gfx::Size size(1, 1);
   auto color_space = gfx::ColorSpace::CreateSRGB();
+  GrSurfaceOrigin surface_origin = kTopLeft_GrSurfaceOrigin;
+  SkAlphaType alpha_type = kPremul_SkAlphaType;
   gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
   uint32_t usage = SHARED_IMAGE_USAGE_WEBGPU | SHARED_IMAGE_USAGE_SCANOUT;
   auto backing = backing_factory_->CreateSharedImage(
-      mailbox, format, surface_handle, size, color_space, usage,
-      false /* is_thread_safe */);
+      mailbox, format, surface_handle, size, color_space, surface_origin,
+      alpha_type, usage, false /* is_thread_safe */);
   EXPECT_TRUE(backing);
 
   std::unique_ptr<SharedImageRepresentationFactoryRef> factory_ref =
@@ -458,12 +466,14 @@
   const auto format = viz::ResourceFormat::RGBA_8888;
   const gfx::Size size(1, 1);
   const auto color_space = gfx::ColorSpace::CreateSRGB();
+  GrSurfaceOrigin surface_origin = kTopLeft_GrSurfaceOrigin;
+  SkAlphaType alpha_type = kPremul_SkAlphaType;
   const gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
   const uint32_t usage = SHARED_IMAGE_USAGE_GLES2 | SHARED_IMAGE_USAGE_SCANOUT |
                          SHARED_IMAGE_USAGE_WEBGPU;
   auto backing = backing_factory_->CreateSharedImage(
-      mailbox, format, surface_handle, size, color_space, usage,
-      false /* is_thread_safe */);
+      mailbox, format, surface_handle, size, color_space, surface_origin,
+      alpha_type, usage, false /* is_thread_safe */);
   EXPECT_TRUE(backing);
 
   GLenum expected_target = GL_TEXTURE_RECTANGLE;
@@ -573,12 +583,14 @@
   const auto format = viz::ResourceFormat::RGBA_8888;
   const gfx::Size size(1, 1);
   const auto color_space = gfx::ColorSpace::CreateSRGB();
+  GrSurfaceOrigin surface_origin = kTopLeft_GrSurfaceOrigin;
+  SkAlphaType alpha_type = kPremul_SkAlphaType;
   const uint32_t usage = SHARED_IMAGE_USAGE_GLES2 | SHARED_IMAGE_USAGE_SCANOUT |
                          SHARED_IMAGE_USAGE_WEBGPU;
   const gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
   auto backing = backing_factory_->CreateSharedImage(
-      mailbox, format, surface_handle, size, color_space, usage,
-      false /* is_thread_safe */);
+      mailbox, format, surface_handle, size, color_space, surface_origin,
+      alpha_type, usage, false /* is_thread_safe */);
   ASSERT_NE(backing, nullptr);
 
   std::unique_ptr<SharedImageRepresentationFactoryRef> factory_ref =
@@ -659,11 +671,13 @@
   const auto format = viz::ResourceFormat::RGBA_8888;
   const gfx::Size size(1, 1);
   const auto color_space = gfx::ColorSpace::CreateSRGB();
+  GrSurfaceOrigin surface_origin = kTopLeft_GrSurfaceOrigin;
+  SkAlphaType alpha_type = kPremul_SkAlphaType;
   const uint32_t usage = SHARED_IMAGE_USAGE_GLES2 | SHARED_IMAGE_USAGE_SCANOUT;
   const gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
   auto backing = backing_factory_->CreateSharedImage(
-      mailbox, format, surface_handle, size, color_space, usage,
-      false /* is_thread_safe */);
+      mailbox, format, surface_handle, size, color_space, surface_origin,
+      alpha_type, usage, false /* is_thread_safe */);
   ASSERT_NE(backing, nullptr);
 
   std::unique_ptr<SharedImageRepresentationFactoryRef> factory_ref =
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_ozone.cc b/gpu/command_buffer/service/shared_image_backing_factory_ozone.cc
index f91847e..27a131b 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_ozone.cc
+++ b/gpu/command_buffer/service/shared_image_backing_factory_ozone.cc
@@ -31,12 +31,14 @@
     SurfaceHandle surface_handle,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage,
     bool is_thread_safe) {
   DCHECK(!is_thread_safe);
-  return SharedImageBackingOzone::Create(dawn_procs_, shared_context_state_,
-                                         mailbox, format, size, color_space,
-                                         usage, surface_handle);
+  return SharedImageBackingOzone::Create(
+      dawn_procs_, shared_context_state_, mailbox, format, size, color_space,
+      surface_origin, alpha_type, usage, surface_handle);
 }
 
 std::unique_ptr<SharedImageBacking>
@@ -45,6 +47,8 @@
     viz::ResourceFormat format,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage,
     base::span<const uint8_t> pixel_data) {
   NOTIMPLEMENTED_LOG_ONCE();
@@ -60,6 +64,8 @@
     SurfaceHandle surface_handle,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage) {
   NOTIMPLEMENTED_LOG_ONCE();
   return nullptr;
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_ozone.h b/gpu/command_buffer/service/shared_image_backing_factory_ozone.h
index f843faa..c81609a 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_ozone.h
+++ b/gpu/command_buffer/service/shared_image_backing_factory_ozone.h
@@ -32,6 +32,8 @@
       SurfaceHandle surface_handle,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage,
       bool is_thread_safe) override;
 
@@ -40,6 +42,8 @@
       viz::ResourceFormat format,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage,
       base::span<const uint8_t> pixel_data) override;
 
@@ -51,6 +55,8 @@
       SurfaceHandle surface_handle,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage) override;
 
   bool CanImportGpuMemoryBuffer(
diff --git a/gpu/command_buffer/service/shared_image_backing_ozone.cc b/gpu/command_buffer/service/shared_image_backing_ozone.cc
index c5686c3..b195fce0 100644
--- a/gpu/command_buffer/service/shared_image_backing_ozone.cc
+++ b/gpu/command_buffer/service/shared_image_backing_ozone.cc
@@ -96,6 +96,8 @@
     viz::ResourceFormat format,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage,
     SurfaceHandle surface_handle) {
   gfx::BufferFormat buffer_format = viz::BufferFormat(format);
@@ -115,8 +117,8 @@
     return nullptr;
   }
   return base::WrapUnique(new SharedImageBackingOzone(
-      mailbox, format, size, color_space, usage, context_state,
-      std::move(pixmap), std::move(dawn_procs)));
+      mailbox, format, size, color_space, surface_origin, alpha_type, usage,
+      context_state, std::move(pixmap), std::move(dawn_procs)));
 }
 
 SharedImageBackingOzone::~SharedImageBackingOzone() = default;
@@ -202,6 +204,8 @@
     viz::ResourceFormat format,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage,
     SharedContextState* context_state,
     scoped_refptr<gfx::NativePixmap> pixmap,
@@ -210,6 +214,8 @@
                                       format,
                                       size,
                                       color_space,
+                                      surface_origin,
+                                      alpha_type,
                                       usage,
                                       GetPixmapSizeInBytes(*pixmap),
                                       false),
diff --git a/gpu/command_buffer/service/shared_image_backing_ozone.h b/gpu/command_buffer/service/shared_image_backing_ozone.h
index e49d259..85393fd 100644
--- a/gpu/command_buffer/service/shared_image_backing_ozone.h
+++ b/gpu/command_buffer/service/shared_image_backing_ozone.h
@@ -41,6 +41,8 @@
       viz::ResourceFormat format,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage,
       SurfaceHandle surface_handle);
   ~SharedImageBackingOzone() override;
@@ -82,6 +84,8 @@
       viz::ResourceFormat format,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage,
       SharedContextState* context_state,
       scoped_refptr<gfx::NativePixmap> pixmap,
diff --git a/gpu/command_buffer/service/shared_image_backing_scoped_hardware_buffer_fence_sync.cc b/gpu/command_buffer/service/shared_image_backing_scoped_hardware_buffer_fence_sync.cc
index 2749d13..0925ca0 100644
--- a/gpu/command_buffer/service/shared_image_backing_scoped_hardware_buffer_fence_sync.cc
+++ b/gpu/command_buffer/service/shared_image_backing_scoped_hardware_buffer_fence_sync.cc
@@ -44,6 +44,8 @@
         viz::ResourceFormat format,
         const gfx::Size& size,
         const gfx::ColorSpace& color_space,
+        GrSurfaceOrigin surface_origin,
+        SkAlphaType alpha_type,
         uint32_t usage,
         size_t estimated_size,
         bool is_thread_safe)
@@ -51,6 +53,8 @@
                                 format,
                                 size,
                                 color_space,
+                                surface_origin,
+                                alpha_type,
                                 usage,
                                 estimated_size,
                                 is_thread_safe,
diff --git a/gpu/command_buffer/service/shared_image_backing_scoped_hardware_buffer_fence_sync.h b/gpu/command_buffer/service/shared_image_backing_scoped_hardware_buffer_fence_sync.h
index 7cc3e7a..46cdc8b2 100644
--- a/gpu/command_buffer/service/shared_image_backing_scoped_hardware_buffer_fence_sync.h
+++ b/gpu/command_buffer/service/shared_image_backing_scoped_hardware_buffer_fence_sync.h
@@ -36,6 +36,8 @@
       viz::ResourceFormat format,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage,
       size_t estimated_size,
       bool is_thread_safe);
diff --git a/gpu/command_buffer/service/shared_image_factory.cc b/gpu/command_buffer/service/shared_image_factory.cc
index 02f9d3dbc8..3eafc0c4 100644
--- a/gpu/command_buffer/service/shared_image_factory.cc
+++ b/gpu/command_buffer/service/shared_image_factory.cc
@@ -177,15 +177,17 @@
                                            viz::ResourceFormat format,
                                            const gfx::Size& size,
                                            const gfx::ColorSpace& color_space,
+                                           GrSurfaceOrigin surface_origin,
+                                           SkAlphaType alpha_type,
                                            gpu::SurfaceHandle surface_handle,
                                            uint32_t usage) {
   bool allow_legacy_mailbox = false;
   auto* factory = GetFactoryByUsage(usage, format, &allow_legacy_mailbox);
   if (!factory)
     return false;
-  auto backing = factory->CreateSharedImage(mailbox, format, surface_handle,
-                                            size, color_space, usage,
-                                            IsSharedBetweenThreads(usage));
+  auto backing = factory->CreateSharedImage(
+      mailbox, format, surface_handle, size, color_space, surface_origin,
+      alpha_type, usage, IsSharedBetweenThreads(usage));
   return RegisterBacking(std::move(backing), allow_legacy_mailbox);
 }
 
@@ -193,6 +195,8 @@
                                            viz::ResourceFormat format,
                                            const gfx::Size& size,
                                            const gfx::ColorSpace& color_space,
+                                           GrSurfaceOrigin surface_origin,
+                                           SkAlphaType alpha_type,
                                            uint32_t usage,
                                            base::span<const uint8_t> data) {
   // For now, restrict this to SHARED_IMAGE_USAGE_DISPLAY with optional
@@ -222,8 +226,9 @@
   }
   if (!factory)
     return false;
-  auto backing = factory->CreateSharedImage(mailbox, format, size, color_space,
-                                            usage, data);
+  auto backing =
+      factory->CreateSharedImage(mailbox, format, size, color_space,
+                                 surface_origin, alpha_type, usage, data);
   if (backing)
     backing->OnWriteSucceeded();
   return RegisterBacking(std::move(backing), allow_legacy_mailbox);
@@ -236,6 +241,8 @@
                                            SurfaceHandle surface_handle,
                                            const gfx::Size& size,
                                            const gfx::ColorSpace& color_space,
+                                           GrSurfaceOrigin surface_origin,
+                                           SkAlphaType alpha_type,
                                            uint32_t usage) {
   // TODO(piman): depending on handle.type, choose platform-specific backing
   // factory, e.g. SharedImageBackingFactoryAHB.
@@ -245,9 +252,9 @@
                                     &allow_legacy_mailbox, handle.type);
   if (!factory)
     return false;
-  auto backing =
-      factory->CreateSharedImage(mailbox, client_id, std::move(handle), format,
-                                 surface_handle, size, color_space, usage);
+  auto backing = factory->CreateSharedImage(
+      mailbox, client_id, std::move(handle), format, surface_handle, size,
+      color_space, surface_origin, alpha_type, usage);
   if (backing)
     backing->OnWriteSucceeded();
   return RegisterBacking(std::move(backing), allow_legacy_mailbox);
@@ -293,6 +300,8 @@
                                          viz::ResourceFormat format,
                                          const gfx::Size& size,
                                          const gfx::ColorSpace& color_space,
+                                         GrSurfaceOrigin surface_origin,
+                                         SkAlphaType alpha_type,
                                          uint32_t usage) {
   if (!SharedImageBackingFactoryD3D::IsSwapChainSupported())
     return false;
@@ -303,7 +312,7 @@
   bool allow_legacy_mailbox = true;
   auto backings = d3d_backing_factory->CreateSwapChain(
       front_buffer_mailbox, back_buffer_mailbox, format, size, color_space,
-      usage);
+      surface_origin, alpha_type, usage);
   return RegisterBacking(std::move(backings.front_buffer),
                          allow_legacy_mailbox) &&
          RegisterBacking(std::move(backings.back_buffer), allow_legacy_mailbox);
diff --git a/gpu/command_buffer/service/shared_image_factory.h b/gpu/command_buffer/service/shared_image_factory.h
index 0aad865..b7586c56 100644
--- a/gpu/command_buffer/service/shared_image_factory.h
+++ b/gpu/command_buffer/service/shared_image_factory.h
@@ -65,12 +65,17 @@
                          viz::ResourceFormat format,
                          const gfx::Size& size,
                          const gfx::ColorSpace& color_space,
+                         GrSurfaceOrigin surface_origin,
+                         SkAlphaType alpha_type,
                          gpu::SurfaceHandle surface_handle,
+
                          uint32_t usage);
   bool CreateSharedImage(const Mailbox& mailbox,
                          viz::ResourceFormat format,
                          const gfx::Size& size,
                          const gfx::ColorSpace& color_space,
+                         GrSurfaceOrigin surface_origin,
+                         SkAlphaType alpha_type,
                          uint32_t usage,
                          base::span<const uint8_t> pixel_data);
   bool CreateSharedImage(const Mailbox& mailbox,
@@ -80,6 +85,8 @@
                          SurfaceHandle surface_handle,
                          const gfx::Size& size,
                          const gfx::ColorSpace& color_space,
+                         GrSurfaceOrigin surface_origin,
+                         SkAlphaType alpha_type,
                          uint32_t usage);
   bool UpdateSharedImage(const Mailbox& mailbox);
   bool UpdateSharedImage(const Mailbox& mailbox,
@@ -94,6 +101,8 @@
                        viz::ResourceFormat format,
                        const gfx::Size& size,
                        const gfx::ColorSpace& color_space,
+                       GrSurfaceOrigin surface_origin,
+                       SkAlphaType alpha_type,
                        uint32_t usage);
   bool PresentSwapChain(const Mailbox& mailbox);
 #endif  // OS_WIN
diff --git a/gpu/command_buffer/service/shared_image_factory_unittest.cc b/gpu/command_buffer/service/shared_image_factory_unittest.cc
index 22a310d..1ff4e117 100644
--- a/gpu/command_buffer/service/shared_image_factory_unittest.cc
+++ b/gpu/command_buffer/service/shared_image_factory_unittest.cc
@@ -65,8 +65,9 @@
   auto color_space = gfx::ColorSpace::CreateSRGB();
   gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
   uint32_t usage = SHARED_IMAGE_USAGE_GLES2;
-  EXPECT_TRUE(factory_->CreateSharedImage(mailbox, format, size, color_space,
-                                          surface_handle, usage));
+  EXPECT_TRUE(factory_->CreateSharedImage(
+      mailbox, format, size, color_space, kTopLeft_GrSurfaceOrigin,
+      kPremul_SkAlphaType, surface_handle, usage));
   TextureBase* texture_base = mailbox_manager_.ConsumeTexture(mailbox);
   // Validation of the produced backing/mailbox is handled in individual backing
   // factory unittests.
@@ -82,10 +83,12 @@
   auto color_space = gfx::ColorSpace::CreateSRGB();
   gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
   uint32_t usage = SHARED_IMAGE_USAGE_GLES2;
-  EXPECT_TRUE(factory_->CreateSharedImage(mailbox, format, size, color_space,
-                                          surface_handle, usage));
-  EXPECT_FALSE(factory_->CreateSharedImage(mailbox, format, size, color_space,
-                                           surface_handle, usage));
+  EXPECT_TRUE(factory_->CreateSharedImage(
+      mailbox, format, size, color_space, kTopLeft_GrSurfaceOrigin,
+      kPremul_SkAlphaType, surface_handle, usage));
+  EXPECT_FALSE(factory_->CreateSharedImage(
+      mailbox, format, size, color_space, kTopLeft_GrSurfaceOrigin,
+      kPremul_SkAlphaType, surface_handle, usage));
 
   GpuPreferences preferences;
   GpuDriverBugWorkarounds workarounds;
@@ -95,7 +98,8 @@
       &shared_image_manager_, &image_factory_, nullptr,
       /*enable_wrapped_sk_image=*/false);
   EXPECT_FALSE(other_factory->CreateSharedImage(
-      mailbox, format, size, color_space, surface_handle, usage));
+      mailbox, format, size, color_space, kTopLeft_GrSurfaceOrigin,
+      kPremul_SkAlphaType, surface_handle, usage));
 }
 
 TEST_F(SharedImageFactoryTest, DestroyInexistentMailbox) {
diff --git a/gpu/command_buffer/service/shared_image_manager_unittest.cc b/gpu/command_buffer/service/shared_image_manager_unittest.cc
index e068fe28..8d20004 100644
--- a/gpu/command_buffer/service/shared_image_manager_unittest.cc
+++ b/gpu/command_buffer/service/shared_image_manager_unittest.cc
@@ -37,10 +37,13 @@
   auto format = viz::ResourceFormat::RGBA_8888;
   gfx::Size size(256, 256);
   auto color_space = gfx::ColorSpace::CreateSRGB();
+  auto surface_origin = kTopLeft_GrSurfaceOrigin;
+  auto alpha_type = kPremul_SkAlphaType;
   uint32_t usage = SHARED_IMAGE_USAGE_GLES2;
 
   auto backing = std::make_unique<TestSharedImageBacking>(
-      mailbox, format, size, color_space, usage, kSizeBytes);
+      mailbox, format, size, color_space, surface_origin, alpha_type, usage,
+      kSizeBytes);
 
   auto factory_ref = manager.Register(std::move(backing), tracker.get());
   EXPECT_EQ(kSizeBytes, tracker->GetMemRepresented());
@@ -74,10 +77,13 @@
   auto format = viz::ResourceFormat::RGBA_8888;
   gfx::Size size(256, 256);
   auto color_space = gfx::ColorSpace::CreateSRGB();
+  auto surface_origin = kTopLeft_GrSurfaceOrigin;
+  auto alpha_type = kPremul_SkAlphaType;
   uint32_t usage = SHARED_IMAGE_USAGE_GLES2;
 
   auto backing = std::make_unique<TestSharedImageBacking>(
-      mailbox, format, size, color_space, usage, kSizeBytes);
+      mailbox, format, size, color_space, surface_origin, alpha_type, usage,
+      kSizeBytes);
 
   auto factory_ref = manager.Register(std::move(backing), tracker.get());
   EXPECT_EQ(kSizeBytes, tracker->GetMemRepresented());
@@ -103,10 +109,13 @@
   auto format = viz::ResourceFormat::RGBA_8888;
   gfx::Size size(256, 256);
   auto color_space = gfx::ColorSpace::CreateSRGB();
+  auto surface_origin = kTopLeft_GrSurfaceOrigin;
+  auto alpha_type = kPremul_SkAlphaType;
   uint32_t usage = SHARED_IMAGE_USAGE_GLES2;
 
   auto backing = std::make_unique<TestSharedImageBacking>(
-      mailbox, format, size, color_space, usage, kSizeBytes);
+      mailbox, format, size, color_space, surface_origin, alpha_type, usage,
+      kSizeBytes);
 
   auto factory_ref = manager.Register(std::move(backing), tracker.get());
   EXPECT_EQ(kSizeBytes, tracker->GetMemRepresented());
diff --git a/gpu/command_buffer/service/shared_image_representation.h b/gpu/command_buffer/service/shared_image_representation.h
index 5c7d414..d5b8d6d 100644
--- a/gpu/command_buffer/service/shared_image_representation.h
+++ b/gpu/command_buffer/service/shared_image_representation.h
@@ -68,6 +68,8 @@
   viz::ResourceFormat format() const { return backing_->format(); }
   const gfx::Size& size() const { return backing_->size(); }
   const gfx::ColorSpace& color_space() const { return backing_->color_space(); }
+  GrSurfaceOrigin surface_origin() const { return backing_->surface_origin(); }
+  SkAlphaType alpha_type() const { return backing_->alpha_type(); }
   uint32_t usage() const { return backing_->usage(); }
   const gpu::Mailbox& mailbox() const { return backing_->mailbox(); }
   MemoryTypeTracker* tracker() { return tracker_; }
@@ -291,10 +293,11 @@
   // Begin the write access. The implementations should insert semaphores into
   // begin_semaphores vector which client will wait on before writing the
   // backing. The ownership of begin_semaphores will be passed to client.
-  // The implementations should also insert semaphores into end_semaphores,
-  // client must submit them with drawing operations which use the backing.
-  // The ownership of end_semaphores are not passed to client. And client must
-  // submit the end_semaphores before calling EndWriteAccess().
+  // The implementations can also optionally insert semaphores into
+  // end_semaphores. If using end_semaphores, the client must submit them with
+  // drawing operations which use the backing. The ownership of end_semaphores
+  // are not passed to client. And client must submit the end_semaphores before
+  // calling EndWriteAccess().
   // The backing can assign end_state, and the caller must reset backing's state
   // to the end_state before calling EndWriteAccess().
   virtual sk_sp<SkSurface> BeginWriteAccess(
@@ -313,10 +316,11 @@
   // Begin the read access. The implementations should insert semaphores into
   // begin_semaphores vector which client will wait on before reading the
   // backing. The ownership of begin_semaphores will be passed to client.
-  // The implementations should also insert semaphores into end_semaphores,
-  // client must submit them with drawing operations which use the backing.
-  // The ownership of end_semaphores are not passed to client. And client must
-  // submit the end_semaphores before calling EndReadAccess().
+  // The implementations can also optionally insert semaphores into
+  // end_semaphores. If using end_semaphores, the client must submit them with
+  // drawing operations which use the backing. The ownership of end_semaphores
+  // are not passed to client. And client must submit the end_semaphores before
+  // calling EndReadAccess().
   // The backing can assign end_state, and the caller must reset backing's state
   // to the end_state before calling EndReadAccess().
   virtual sk_sp<SkPromiseImageTexture> BeginReadAccess(
diff --git a/gpu/command_buffer/service/shared_image_representation_skia_vk_android.cc b/gpu/command_buffer/service/shared_image_representation_skia_vk_android.cc
index 0d834e8..774da09 100644
--- a/gpu/command_buffer/service/shared_image_representation_skia_vk_android.cc
+++ b/gpu/command_buffer/service/shared_image_representation_skia_vk_android.cc
@@ -156,7 +156,6 @@
     std::vector<GrBackendSemaphore>* end_semaphores,
     base::ScopedFD init_read_fence) {
   DCHECK(begin_semaphores);
-  DCHECK(end_semaphores);
   DCHECK(end_access_semaphore_ == VK_NULL_HANDLE);
 
   // Synchronise the read access with the writes.
@@ -182,24 +181,28 @@
     }
   }
 
-  end_access_semaphore_ =
-      vk_implementation()->CreateExternalSemaphore(vk_device());
+  if (end_semaphores) {
+    end_access_semaphore_ =
+        vk_implementation()->CreateExternalSemaphore(vk_device());
 
-  if (end_access_semaphore_ == VK_NULL_HANDLE) {
-    DLOG(ERROR) << "Failed to create the external semaphore.";
-    if (begin_access_semaphore != VK_NULL_HANDLE) {
-      vkDestroySemaphore(vk_device(), begin_access_semaphore,
-                         nullptr /* pAllocator */);
+    if (end_access_semaphore_ == VK_NULL_HANDLE) {
+      DLOG(ERROR) << "Failed to create the external semaphore.";
+      if (begin_access_semaphore != VK_NULL_HANDLE) {
+        vkDestroySemaphore(vk_device(), begin_access_semaphore,
+                           nullptr /* pAllocator */);
+      }
+      return false;
     }
-    return false;
   }
 
   if (begin_access_semaphore != VK_NULL_HANDLE) {
     begin_semaphores->emplace_back();
     begin_semaphores->back().initVulkan(begin_access_semaphore);
   }
-  end_semaphores->emplace_back();
-  end_semaphores->back().initVulkan(end_access_semaphore_);
+  if (end_semaphores) {
+    end_semaphores->emplace_back();
+    end_semaphores->back().initVulkan(end_access_semaphore_);
+  }
 
   mode_ = readonly ? RepresentationAccessMode::kRead
                    : RepresentationAccessMode::kWrite;
@@ -207,23 +210,28 @@
 }
 
 void SharedImageRepresentationSkiaVkAndroid::EndAccess(bool readonly) {
-  // There should be a surface_ from the BeginWriteAccess().
-  DCHECK(end_access_semaphore_ != VK_NULL_HANDLE);
-
-  SemaphoreHandle semaphore_handle = vk_implementation()->GetSemaphoreHandle(
-      vk_device(), end_access_semaphore_);
-  auto sync_fd = semaphore_handle.TakeHandle();
-  DCHECK(sync_fd.is_valid());
+  base::ScopedFD sync_fd;
+  if (end_access_semaphore_ != VK_NULL_HANDLE) {
+    SemaphoreHandle semaphore_handle = vk_implementation()->GetSemaphoreHandle(
+        vk_device(), end_access_semaphore_);
+    sync_fd = semaphore_handle.TakeHandle();
+    DCHECK(sync_fd.is_valid());
+  }
 
   if (readonly) {
     android_backing()->EndRead(this, std::move(sync_fd));
   } else {
     android_backing()->EndWrite(std::move(sync_fd));
   }
-  VulkanFenceHelper* fence_helper =
-      context_state_->vk_context_provider()->GetDeviceQueue()->GetFenceHelper();
-  fence_helper->EnqueueSemaphoreCleanupForSubmittedWork(end_access_semaphore_);
-  end_access_semaphore_ = VK_NULL_HANDLE;
+
+  if (end_access_semaphore_ != VK_NULL_HANDLE) {
+    VulkanFenceHelper* fence_helper = context_state_->vk_context_provider()
+                                          ->GetDeviceQueue()
+                                          ->GetFenceHelper();
+    fence_helper->EnqueueSemaphoreCleanupForSubmittedWork(
+        end_access_semaphore_);
+    end_access_semaphore_ = VK_NULL_HANDLE;
+  }
   mode_ = RepresentationAccessMode::kNone;
 }
 
diff --git a/gpu/command_buffer/service/shared_image_representation_unittest.cc b/gpu/command_buffer/service/shared_image_representation_unittest.cc
index 26b6f78..ce578e18 100644
--- a/gpu/command_buffer/service/shared_image_representation_unittest.cc
+++ b/gpu/command_buffer/service/shared_image_representation_unittest.cc
@@ -27,10 +27,13 @@
     auto format = viz::ResourceFormat::RGBA_8888;
     gfx::Size size(256, 256);
     auto color_space = gfx::ColorSpace::CreateSRGB();
+    auto surface_origin = kTopLeft_GrSurfaceOrigin;
+    auto alpha_type = kPremul_SkAlphaType;
     uint32_t usage = SHARED_IMAGE_USAGE_GLES2;
 
     auto backing = std::make_unique<TestSharedImageBacking>(
-        mailbox_, format, size, color_space, usage, 0 /* estimated_size */);
+        mailbox_, format, size, color_space, surface_origin, alpha_type, usage,
+        0 /* estimated_size */);
     factory_ref_ = manager_.Register(std::move(backing), tracker_.get());
   }
 
diff --git a/gpu/command_buffer/service/shared_image_video.cc b/gpu/command_buffer/service/shared_image_video.cc
index bbc90fd9..cec6d99 100644
--- a/gpu/command_buffer/service/shared_image_video.cc
+++ b/gpu/command_buffer/service/shared_image_video.cc
@@ -39,6 +39,8 @@
     const Mailbox& mailbox,
     const gfx::Size& size,
     const gfx::ColorSpace color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     scoped_refptr<StreamTextureSharedImageInterface> stream_texture_sii,
     std::unique_ptr<gles2::AbstractTexture> abstract_texture,
     scoped_refptr<SharedContextState> context_state,
@@ -48,6 +50,8 @@
           viz::RGBA_8888,
           size,
           color_space,
+          surface_origin,
+          alpha_type,
           (SHARED_IMAGE_USAGE_DISPLAY | SHARED_IMAGE_USAGE_GLES2),
           viz::ResourceSizes::UncheckedSizeInBytes<size_t>(size,
                                                            viz::RGBA_8888),
diff --git a/gpu/command_buffer/service/shared_image_video.h b/gpu/command_buffer/service/shared_image_video.h
index 042681e5..68e330aa 100644
--- a/gpu/command_buffer/service/shared_image_video.h
+++ b/gpu/command_buffer/service/shared_image_video.h
@@ -34,6 +34,8 @@
       const Mailbox& mailbox,
       const gfx::Size& size,
       const gfx::ColorSpace color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       scoped_refptr<StreamTextureSharedImageInterface> stream_texture_sii,
       std::unique_ptr<gles2::AbstractTexture> abstract_texture,
       scoped_refptr<SharedContextState> shared_context_state,
diff --git a/gpu/command_buffer/service/test_shared_image_backing.cc b/gpu/command_buffer/service/test_shared_image_backing.cc
index 290bf97..ab09c2f9 100644
--- a/gpu/command_buffer/service/test_shared_image_backing.cc
+++ b/gpu/command_buffer/service/test_shared_image_backing.cc
@@ -132,6 +132,8 @@
     viz::ResourceFormat format,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage,
     size_t estimated_size,
     GLuint texture_id)
@@ -139,6 +141,8 @@
                          format,
                          size,
                          color_space,
+                         surface_origin,
+                         alpha_type,
                          usage,
                          estimated_size,
                          false /* is_thread_safe */),
@@ -163,12 +167,16 @@
     viz::ResourceFormat format,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage,
     size_t estimated_size)
     : TestSharedImageBacking(mailbox,
                              format,
                              size,
                              color_space,
+                             surface_origin,
+                             alpha_type,
                              usage,
                              estimated_size,
                              203 /* texture_id */) {
diff --git a/gpu/command_buffer/service/test_shared_image_backing.h b/gpu/command_buffer/service/test_shared_image_backing.h
index 14d3654..b97d29d 100644
--- a/gpu/command_buffer/service/test_shared_image_backing.h
+++ b/gpu/command_buffer/service/test_shared_image_backing.h
@@ -18,6 +18,8 @@
                          viz::ResourceFormat format,
                          const gfx::Size& size,
                          const gfx::ColorSpace& color_space,
+                         GrSurfaceOrigin surface_origin,
+                         SkAlphaType alpha_type,
                          uint32_t usage,
                          size_t estimated_size);
   // Constructor which uses a provided GL texture ID for the backing.
@@ -25,6 +27,8 @@
                          viz::ResourceFormat format,
                          const gfx::Size& size,
                          const gfx::ColorSpace& color_space,
+                         GrSurfaceOrigin surface_origin,
+                         SkAlphaType alpha_type,
                          uint32_t usage,
                          size_t estimated_size,
                          GLuint texture_id);
diff --git a/gpu/command_buffer/service/webgpu_decoder_unittest.cc b/gpu/command_buffer/service/webgpu_decoder_unittest.cc
index 8108e4c..1a04452 100644
--- a/gpu/command_buffer/service/webgpu_decoder_unittest.cc
+++ b/gpu/command_buffer/service/webgpu_decoder_unittest.cc
@@ -171,7 +171,8 @@
   gpu::Mailbox mailbox = Mailbox::GenerateForSharedImage();
   EXPECT_TRUE(factory_->CreateSharedImage(
       mailbox, viz::ResourceFormat::RGBA_8888, {1, 1},
-      gfx::ColorSpace::CreateSRGB(), gfx::kNullAcceleratedWidget,
+      gfx::ColorSpace::CreateSRGB(), kTopLeft_GrSurfaceOrigin,
+      kPremul_SkAlphaType, gfx::kNullAcceleratedWidget,
       SHARED_IMAGE_USAGE_WEBGPU));
 
   // Error case: invalid mailbox
@@ -268,8 +269,8 @@
   gpu::Mailbox mailbox = Mailbox::GenerateForSharedImage();
   EXPECT_TRUE(factory_->CreateSharedImage(
       mailbox, viz::ResourceFormat::RGBA_8888, {1, 1},
-      gfx::ColorSpace::CreateSRGB(), kNullSurfaceHandle,
-      SHARED_IMAGE_USAGE_WEBGPU));
+      gfx::ColorSpace::CreateSRGB(), kTopLeft_GrSurfaceOrigin,
+      kPremul_SkAlphaType, kNullSurfaceHandle, SHARED_IMAGE_USAGE_WEBGPU));
 
   // Associate a mailbox so we can later dissociate it.
   {
diff --git a/gpu/command_buffer/service/wrapped_sk_image.cc b/gpu/command_buffer/service/wrapped_sk_image.cc
index 7762881..3e146624 100644
--- a/gpu/command_buffer/service/wrapped_sk_image.cc
+++ b/gpu/command_buffer/service/wrapped_sk_image.cc
@@ -151,6 +151,8 @@
                  viz::ResourceFormat format,
                  const gfx::Size& size,
                  const gfx::ColorSpace& color_space,
+                 GrSurfaceOrigin surface_origin,
+                 SkAlphaType alpha_type,
                  uint32_t usage,
                  size_t estimated_size,
                  SharedContextState* context_state)
@@ -158,6 +160,8 @@
                                         format,
                                         size,
                                         color_space,
+                                        surface_origin,
+                                        alpha_type,
                                         usage,
                                         estimated_size,
                                         false /* is_thread_safe */),
@@ -362,11 +366,13 @@
     SurfaceHandle surface_handle,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage,
     bool is_thread_safe) {
   DCHECK(!is_thread_safe);
-  return CreateSharedImage(mailbox, format, size, color_space, usage,
-                           base::span<uint8_t>());
+  return CreateSharedImage(mailbox, format, size, color_space, surface_origin,
+                           alpha_type, usage, base::span<uint8_t>());
 }
 
 std::unique_ptr<SharedImageBacking> WrappedSkImageFactory::CreateSharedImage(
@@ -374,13 +380,15 @@
     viz::ResourceFormat format,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage,
     base::span<const uint8_t> data) {
   auto info = MakeSkImageInfo(size, format);
   size_t estimated_size = info.computeMinByteSize();
   std::unique_ptr<WrappedSkImage> texture(
-      new WrappedSkImage(mailbox, format, size, color_space, usage,
-                         estimated_size, context_state_));
+      new WrappedSkImage(mailbox, format, size, color_space, surface_origin,
+                         alpha_type, usage, estimated_size, context_state_));
   if (!texture->Initialize(info, data, /*stride=*/0))
     return nullptr;
   return texture;
@@ -394,6 +402,8 @@
     SurfaceHandle surface_handle,
     const gfx::Size& size,
     const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
     uint32_t usage) {
   DCHECK_EQ(handle.type, gfx::SHARED_MEMORY_BUFFER);
 
@@ -418,9 +428,9 @@
     return nullptr;
 
   auto info = MakeSkImageInfo(size, format);
-  std::unique_ptr<WrappedSkImage> texture(
-      new WrappedSkImage(mailbox, format, size, color_space, usage,
-                         info.computeMinByteSize(), context_state_));
+  std::unique_ptr<WrappedSkImage> texture(new WrappedSkImage(
+      mailbox, format, size, color_space, surface_origin, alpha_type, usage,
+      info.computeMinByteSize(), context_state_));
   if (!texture->InitializeGMB(info, std::move(shm_wrapper)))
     return nullptr;
 
diff --git a/gpu/command_buffer/service/wrapped_sk_image.h b/gpu/command_buffer/service/wrapped_sk_image.h
index 9cb0df47..b0b8bc9 100644
--- a/gpu/command_buffer/service/wrapped_sk_image.h
+++ b/gpu/command_buffer/service/wrapped_sk_image.h
@@ -34,6 +34,8 @@
       SurfaceHandle surface_handle,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage,
       bool is_thread_safe) override;
   std::unique_ptr<SharedImageBacking> CreateSharedImage(
@@ -41,6 +43,8 @@
       viz::ResourceFormat format,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage,
       base::span<const uint8_t> pixel_data) override;
   std::unique_ptr<SharedImageBacking> CreateSharedImage(
@@ -51,6 +55,8 @@
       SurfaceHandle surface_handle,
       const gfx::Size& size,
       const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
       uint32_t usage) override;
   bool CanImportGpuMemoryBuffer(
       gfx::GpuMemoryBufferType memory_buffer_type) override;
diff --git a/gpu/command_buffer/tests/fuzzer_main.cc b/gpu/command_buffer/tests/fuzzer_main.cc
index 853ccea..9482241 100644
--- a/gpu/command_buffer/tests/fuzzer_main.cc
+++ b/gpu/command_buffer/tests/fuzzer_main.cc
@@ -419,7 +419,8 @@
       mailbox.SetName(name);
       shared_image_factory_->CreateSharedImage(
           mailbox, viz::RGBA_8888, gfx::Size(256, 256),
-          gfx::ColorSpace::CreateSRGB(), gfx::kNullAcceleratedWidget, usage);
+          gfx::ColorSpace::CreateSRGB(), kTopLeft_GrSurfaceOrigin,
+          kPremul_SkAlphaType, gfx::kNullAcceleratedWidget, usage);
     }
 
 #if defined(GPU_FUZZER_USE_RASTER_DECODER)
diff --git a/gpu/ipc/common/BUILD.gn b/gpu/ipc/common/BUILD.gn
index 01d014d..f81d1413 100644
--- a/gpu/ipc/common/BUILD.gn
+++ b/gpu/ipc/common/BUILD.gn
@@ -509,6 +509,9 @@
       ]
       traits_headers = [ "gpu_preferences_mojom_traits.h" ]
       traits_public_deps = [ "//media:media_buildflags" ]
+      if (use_ozone) {
+        traits_public_deps += [ "//ui/base:features" ]
+      }
       traits_deps = [
         # We depend on gpu_preferences but since it also depends on its own
         # mojo bindings, that is handled with an |allowed_circular_includes|
diff --git a/gpu/ipc/service/gpu_memory_ablation_experiment.cc b/gpu/ipc/service/gpu_memory_ablation_experiment.cc
index 4da13f0..6a278047 100644
--- a/gpu/ipc/service/gpu_memory_ablation_experiment.cc
+++ b/gpu/ipc/service/gpu_memory_ablation_experiment.cc
@@ -112,8 +112,9 @@
   auto mailbox = Mailbox::GenerateForSharedImage();
   auto color_space = gfx::ColorSpace::CreateSRGB();
 
-  if (!factory_->CreateSharedImage(mailbox, kFormat, size_, color_space,
-                                   gpu::kNullSurfaceHandle, kUsage)) {
+  if (!factory_->CreateSharedImage(
+          mailbox, kFormat, size_, color_space, kTopLeft_GrSurfaceOrigin,
+          kPremul_SkAlphaType, gpu::kNullSurfaceHandle, kUsage)) {
     return;
   }
 
diff --git a/gpu/ipc/service/shared_image_stub.cc b/gpu/ipc/service/shared_image_stub.cc
index 4dac0b4..a7655ed54 100644
--- a/gpu/ipc/service/shared_image_stub.cc
+++ b/gpu/ipc/service/shared_image_stub.cc
@@ -99,6 +99,8 @@
                                         SurfaceHandle surface_handle,
                                         const gfx::Size& size,
                                         const gfx::ColorSpace& color_space,
+                                        GrSurfaceOrigin surface_origin,
+                                        SkAlphaType alpha_type,
                                         uint32_t usage) {
   TRACE_EVENT2("gpu", "SharedImageStub::CreateSharedImage", "width",
                size.width(), "height", size.height());
@@ -114,7 +116,7 @@
   }
   if (!factory_->CreateSharedImage(mailbox, client_id, std::move(handle),
                                    format, surface_handle, size, color_space,
-                                   usage)) {
+                                   surface_origin, alpha_type, usage)) {
     LOG(ERROR) << "SharedImageStub: Unable to create shared image";
     OnError();
     return false;
@@ -164,7 +166,9 @@
   }
 
   if (!factory_->CreateSharedImage(params.mailbox, params.format, params.size,
-                                   params.color_space, gpu::kNullSurfaceHandle,
+                                   params.color_space, params.surface_origin,
+                                   params.alpha_type, gpu::kNullSurfaceHandle,
+
                                    params.usage)) {
     LOG(ERROR) << "SharedImageStub: Unable to create shared image";
     OnError();
@@ -217,7 +221,8 @@
       memory.subspan(params.pixel_data_offset, params.pixel_data_size);
 
   if (!factory_->CreateSharedImage(params.mailbox, params.format, params.size,
-                                   params.color_space, params.usage, subspan)) {
+                                   params.color_space, params.surface_origin,
+                                   params.alpha_type, params.usage, subspan)) {
     LOG(ERROR) << "SharedImageStub: Unable to create shared image";
     OnError();
     return;
@@ -243,10 +248,10 @@
                params.size.width(), "height", params.size.height());
   // TODO(piman): add support for SurfaceHandle (for backbuffers for ozone/drm).
   constexpr SurfaceHandle surface_handle = kNullSurfaceHandle;
-  if (!CreateSharedImage(params.mailbox, channel_->client_id(),
-                         std::move(params.handle), params.format,
-                         surface_handle, params.size, params.color_space,
-                         params.usage)) {
+  if (!CreateSharedImage(
+          params.mailbox, channel_->client_id(), std::move(params.handle),
+          params.format, surface_handle, params.size, params.color_space,
+          params.surface_origin, params.alpha_type, params.usage)) {
     return;
   }
 
@@ -316,7 +321,8 @@
 
   if (!factory_->CreateSwapChain(
           params.front_buffer_mailbox, params.back_buffer_mailbox,
-          params.format, params.size, params.color_space, params.usage)) {
+          params.format, params.size, params.color_space, params.surface_origin,
+          params.alpha_type, params.usage)) {
     DLOG(ERROR) << "SharedImageStub: Unable to create swap chain";
     OnError();
     return;
diff --git a/gpu/ipc/service/shared_image_stub.h b/gpu/ipc/service/shared_image_stub.h
index 781c1dc..c260f215 100644
--- a/gpu/ipc/service/shared_image_stub.h
+++ b/gpu/ipc/service/shared_image_stub.h
@@ -64,6 +64,8 @@
                          SurfaceHandle surface_handle,
                          const gfx::Size& size,
                          const gfx::ColorSpace& color_space,
+                         GrSurfaceOrigin surface_origin,
+                         SkAlphaType alpha_type,
                          uint32_t usage);
   bool UpdateSharedImage(const Mailbox& mailbox,
                          const gfx::GpuFenceHandle& in_fence_handle);
diff --git a/gpu/ipc/service/stream_texture_android.cc b/gpu/ipc/service/stream_texture_android.cc
index d51e90fb..65ed181 100644
--- a/gpu/ipc/service/stream_texture_android.cc
+++ b/gpu/ipc/service/stream_texture_android.cc
@@ -307,7 +307,8 @@
   // TODO(vikassoni): Hardcoding colorspace to SRGB. Figure how if we have a
   // colorspace and wire it here.
   auto shared_image = std::make_unique<SharedImageVideo>(
-      mailbox, coded_size, gfx::ColorSpace::CreateSRGB(), this,
+      mailbox, coded_size, gfx::ColorSpace::CreateSRGB(),
+      kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, this,
       std::move(legacy_mailbox_texture), context_state_, false);
   channel_->shared_image_stub()->factory()->RegisterBacking(
       std::move(shared_image), true /* allow_legacy_mailbox */);
diff --git a/gpu/ipc/shared_image_interface_in_process.cc b/gpu/ipc/shared_image_interface_in_process.cc
index b850bd7..2fb5642 100644
--- a/gpu/ipc/shared_image_interface_in_process.cc
+++ b/gpu/ipc/shared_image_interface_in_process.cc
@@ -170,7 +170,8 @@
   LazyCreateSharedImageFactory();
 
   if (!shared_image_factory_->CreateSharedImage(
-          mailbox, format, size, color_space, surface_handle, usage)) {
+          mailbox, format, size, color_space, surface_origin, alpha_type,
+          surface_handle, usage)) {
     // Signal errors by losing the command buffer.
     command_buffer_helper_->SetError();
     return;
@@ -224,7 +225,8 @@
   LazyCreateSharedImageFactory();
 
   if (!shared_image_factory_->CreateSharedImage(
-          mailbox, format, size, color_space, usage, pixel_data)) {
+          mailbox, format, size, color_space, surface_origin, alpha_type, usage,
+          pixel_data)) {
     // Signal errors by losing the command buffer.
     command_buffer_helper_->SetError();
     return;
@@ -295,7 +297,8 @@
   SurfaceHandle surface_handle = kNullSurfaceHandle;
   if (!shared_image_factory_->CreateSharedImage(
           mailbox, kInProcessCommandBufferClientId, std::move(handle), format,
-          surface_handle, size, color_space, usage)) {
+          surface_handle, size, color_space, surface_origin, alpha_type,
+          usage)) {
     // Signal errors by losing the command buffer.
     // Signal errors by losing the command buffer.
     command_buffer_helper_->SetError();
diff --git a/infra/config/generated/commit-queue.cfg b/infra/config/generated/commit-queue.cfg
index 208fc50..814001f 100644
--- a/infra/config/generated/commit-queue.cfg
+++ b/infra/config/generated/commit-queue.cfg
@@ -138,6 +138,26 @@
         owner_whitelist_group: "project-chromium-robot-committers"
       }
       builders {
+        name: "chromium/codesearch/gen-android-try"
+        includable_only: true
+      }
+      builders {
+        name: "chromium/codesearch/gen-chromiumos-try"
+        includable_only: true
+      }
+      builders {
+        name: "chromium/codesearch/gen-fuchsia-try"
+        includable_only: true
+      }
+      builders {
+        name: "chromium/codesearch/gen-linux-try"
+        includable_only: true
+      }
+      builders {
+        name: "chromium/codesearch/gen-win-try"
+        includable_only: true
+      }
+      builders {
         name: "chromium/try/android-10-arm64-rel"
         includable_only: true
       }
@@ -401,10 +421,6 @@
         location_regexp: ".+/[+]/third_party/closure_compiler/.+"
       }
       builders {
-        name: "chromium/try/codesearch-gen-chromium-win-try"
-        includable_only: true
-      }
-      builders {
         name: "chromium/try/dawn-linux-x64-deps-rel"
         location_regexp: ".+/[+]/gpu/.+"
         location_regexp: ".+/[+]/testing/buildbot/chromium.dawn.json"
diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg
index 3ea0166..e939e35 100644
--- a/infra/config/generated/cr-buildbucket.cfg
+++ b/infra/config/generated/cr-buildbucket.cfg
@@ -9152,7 +9152,7 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"packages\":[{\"cipd_yaml\":\"third_party/android_sdk/cipd/build-tools/25.0.2.yaml\",\"sdk_package_name\":\"build-tools;25.0.2\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/build-tools/27.0.3.yaml\",\"sdk_package_name\":\"build-tools;27.0.3\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/build-tools/29.0.2.yaml\",\"sdk_package_name\":\"build-tools;29.0.2\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/build-tools/30.0.1.yaml\",\"sdk_package_name\":\"build-tools;30.0.1\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/cmdline-tools.yaml\",\"sdk_package_name\":\"cmdline-tools;latest\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/emulator.yaml\",\"sdk_package_name\":\"emulator\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/extras/google/gcm.yaml\",\"sdk_package_name\":\"extras;google;gcm\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/patcher/v4.yaml\",\"sdk_package_name\":\"patcher;v4\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/platforms/android-23.yaml\",\"sdk_package_name\":\"platforms;android-23\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/platforms/android-28.yaml\",\"sdk_package_name\":\"platforms;android-28\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/platforms/android-29.yaml\",\"sdk_package_name\":\"platforms;android-29\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/platforms/android-30.yaml\",\"sdk_package_name\":\"platforms;android-30\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/platform-tools.yaml\",\"sdk_package_name\":\"platform-tools\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/sources/android-28.yaml\",\"sdk_package_name\":\"sources;android-28\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/sources/android-29.yaml\",\"sdk_package_name\":\"sources;android-29\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/system_images/android-23/google_apis/x86.yaml\",\"sdk_package_name\":\"system-images;android-23;google_apis;x86\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/system_images/android-28/google_apis_playstore/x86.yaml\",\"sdk_package_name\":\"system-images;android-28;google_apis_playstore;x86\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/system_images/android-29/google_apis/x86.yaml\",\"sdk_package_name\":\"system-images;android-29;google_apis;x86\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/system_images/android-29/google_apis_playstore/x86.yaml\",\"sdk_package_name\":\"system-images;android-29;google_apis_playstore;x86\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/system_images/android-30/google_apis/x86.yaml\",\"sdk_package_name\":\"system-images;android-30;google_apis;x86\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/system_images/android-30/google_apis_playstore/x86.yaml\",\"sdk_package_name\":\"system-images;android-30;google_apis_playstore;x86\"}],\"recipe\":\"android/sdk_packager\"}"
+      properties: "{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"packages\":[{\"cipd_yaml\":\"third_party/android_sdk/cipd/build-tools/25.0.2.yaml\",\"sdk_package_name\":\"build-tools;25.0.2\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/build-tools/29.0.2.yaml\",\"sdk_package_name\":\"build-tools;29.0.2\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/build-tools/30.0.1.yaml\",\"sdk_package_name\":\"build-tools;30.0.1\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/cmdline-tools.yaml\",\"sdk_package_name\":\"cmdline-tools;latest\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/emulator.yaml\",\"sdk_package_name\":\"emulator\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/extras/google/gcm.yaml\",\"sdk_package_name\":\"extras;google;gcm\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/patcher/v4.yaml\",\"sdk_package_name\":\"patcher;v4\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/platforms/android-29.yaml\",\"sdk_package_name\":\"platforms;android-29\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/platforms/android-30.yaml\",\"sdk_package_name\":\"platforms;android-30\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/platform-tools.yaml\",\"sdk_package_name\":\"platform-tools\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/sources/android-29.yaml\",\"sdk_package_name\":\"sources;android-29\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/system_images/android-29/google_apis/x86.yaml\",\"sdk_package_name\":\"system-images;android-29;google_apis;x86\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/system_images/android-29/google_apis_playstore/x86.yaml\",\"sdk_package_name\":\"system-images;android-29;google_apis_playstore;x86\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/system_images/android-30/google_apis/x86.yaml\",\"sdk_package_name\":\"system-images;android-30;google_apis;x86\"},{\"cipd_yaml\":\"third_party/android_sdk/cipd/system_images/android-30/google_apis_playstore/x86.yaml\",\"sdk_package_name\":\"system-images;android-30;google_apis_playstore;x86\"}],\"recipe\":\"android/sdk_packager\"}"
       execution_timeout_secs: 10800
       build_numbers: YES
       service_account: "chromium-cipd-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -16912,6 +16912,192 @@
   }
 }
 buckets {
+  name: "codesearch"
+  acls {
+    role: WRITER
+    group: "service-account-chromium-tryserver"
+  }
+  acls {
+    group: "all"
+  }
+  acls {
+    role: SCHEDULER
+    group: "project-chromium-tryjob-access"
+  }
+  swarming {
+    builders {
+      name: "gen-android-try"
+      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: "pool:luci.chromium.try"
+      dimensions: "ssd:0"
+      exe {
+        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
+        cipd_version: "refs/heads/master"
+        cmd: "luciexe"
+      }
+      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"mastername\":\"tryserver.chromium.codesearch\",\"recipe\":\"chromium_codesearch\"}"
+      execution_timeout_secs: 32400
+      expiration_secs: 7200
+      caches {
+        name: "win_toolchain"
+        path: "win_toolchain"
+      }
+      build_numbers: YES
+      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
+      resultdb {
+        enable: true
+        bq_exports {
+          project: "luci-resultdb"
+          dataset: "chromium"
+          table: "try_test_results"
+          test_results {}
+        }
+      }
+    }
+    builders {
+      name: "gen-chromiumos-try"
+      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: "pool:luci.chromium.try"
+      dimensions: "ssd:0"
+      exe {
+        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
+        cipd_version: "refs/heads/master"
+        cmd: "luciexe"
+      }
+      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"mastername\":\"tryserver.chromium.codesearch\",\"recipe\":\"chromium_codesearch\"}"
+      execution_timeout_secs: 32400
+      expiration_secs: 7200
+      caches {
+        name: "win_toolchain"
+        path: "win_toolchain"
+      }
+      build_numbers: YES
+      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
+      resultdb {
+        enable: true
+        bq_exports {
+          project: "luci-resultdb"
+          dataset: "chromium"
+          table: "try_test_results"
+          test_results {}
+        }
+      }
+    }
+    builders {
+      name: "gen-fuchsia-try"
+      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: "pool:luci.chromium.try"
+      dimensions: "ssd:0"
+      exe {
+        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
+        cipd_version: "refs/heads/master"
+        cmd: "luciexe"
+      }
+      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"mastername\":\"tryserver.chromium.codesearch\",\"recipe\":\"chromium_codesearch\"}"
+      execution_timeout_secs: 32400
+      expiration_secs: 7200
+      caches {
+        name: "win_toolchain"
+        path: "win_toolchain"
+      }
+      build_numbers: YES
+      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
+      resultdb {
+        enable: true
+        bq_exports {
+          project: "luci-resultdb"
+          dataset: "chromium"
+          table: "try_test_results"
+          test_results {}
+        }
+      }
+    }
+    builders {
+      name: "gen-linux-try"
+      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: "pool:luci.chromium.try"
+      dimensions: "ssd:0"
+      exe {
+        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
+        cipd_version: "refs/heads/master"
+        cmd: "luciexe"
+      }
+      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"mastername\":\"tryserver.chromium.codesearch\",\"recipe\":\"chromium_codesearch\"}"
+      execution_timeout_secs: 32400
+      expiration_secs: 7200
+      caches {
+        name: "win_toolchain"
+        path: "win_toolchain"
+      }
+      build_numbers: YES
+      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
+      resultdb {
+        enable: true
+        bq_exports {
+          project: "luci-resultdb"
+          dataset: "chromium"
+          table: "try_test_results"
+          test_results {}
+        }
+      }
+    }
+    builders {
+      name: "gen-win-try"
+      swarming_host: "chromium-swarm.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      dimensions: "builderless:1"
+      dimensions: "cores:8"
+      dimensions: "cpu:x86-64"
+      dimensions: "os:Windows-10"
+      dimensions: "pool:luci.chromium.try"
+      dimensions: "ssd:0"
+      exe {
+        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
+        cipd_version: "refs/heads/master"
+        cmd: "luciexe"
+      }
+      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"mastername\":\"tryserver.chromium.codesearch\",\"recipe\":\"chromium_codesearch\"}"
+      execution_timeout_secs: 32400
+      expiration_secs: 7200
+      caches {
+        name: "win_toolchain"
+        path: "win_toolchain"
+      }
+      build_numbers: YES
+      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
+      resultdb {
+        enable: true
+        bq_exports {
+          project: "luci-resultdb"
+          dataset: "chromium"
+          table: "try_test_results"
+          test_results {}
+        }
+      }
+    }
+  }
+}
+buckets {
   name: "findit"
   acls {
     identity: "user:findit-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -20827,43 +21013,6 @@
       }
     }
     builders {
-      name: "codesearch-gen-chromium-win-try"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Windows-10"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "luciexe"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"mastername\":\"tryserver.chromium.codesearch\",\"recipe\":\"chromium_codesearch\"}"
-      execution_timeout_secs: 32400
-      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
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
       name: "dawn-linux-x64-deps-rel"
       swarming_host: "chromium-swarm.appspot.com"
       swarming_tags: "vpython:native-python-wrapper"
diff --git a/infra/config/generated/luci-milo.cfg b/infra/config/generated/luci-milo.cfg
index 9a3dd365..dcd7bfd 100644
--- a/infra/config/generated/luci-milo.cfg
+++ b/infra/config/generated/luci-milo.cfg
@@ -14615,6 +14615,26 @@
   }
 }
 consoles {
+  id: "luci.chromium.codesearch"
+  name: "luci.chromium.codesearch"
+  builders {
+    name: "buildbucket/luci.chromium.codesearch/gen-android-try"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.codesearch/gen-chromiumos-try"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.codesearch/gen-fuchsia-try"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.codesearch/gen-linux-try"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.codesearch/gen-win-try"
+  }
+  builder_view_only: true
+}
+consoles {
   id: "luci.chromium.goma"
   name: "luci.chromium.goma"
   repo_url: "https://chromium.googlesource.com/chromium/src"
@@ -15044,9 +15064,6 @@
     name: "buildbucket/luci.chromium.try/closure_compilation"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/codesearch-gen-chromium-win-try"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/fuchsia-angle-rel"
   }
   builders {
@@ -15812,9 +15829,6 @@
 consoles {
   id: "tryserver.chromium.codesearch"
   name: "tryserver.chromium.codesearch"
-  builders {
-    name: "buildbucket/luci.chromium.try/codesearch-gen-chromium-win-try"
-  }
   builder_view_only: true
 }
 consoles {
diff --git a/infra/config/generated/realms.cfg b/infra/config/generated/realms.cfg
index 64a4b5d..bc00b54 100644
--- a/infra/config/generated/realms.cfg
+++ b/infra/config/generated/realms.cfg
@@ -90,6 +90,25 @@
   }
 }
 realms {
+  name: "codesearch"
+  bindings {
+    role: "role/buildbucket.builderServiceAccount"
+    principals: "user:chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
+  }
+  bindings {
+    role: "role/buildbucket.owner"
+    principals: "group:service-account-chromium-tryserver"
+  }
+  bindings {
+    role: "role/buildbucket.reader"
+    principals: "group:all"
+  }
+  bindings {
+    role: "role/buildbucket.triggerer"
+    principals: "group:project-chromium-tryjob-access"
+  }
+}
+realms {
   name: "findit"
   bindings {
     role: "role/buildbucket.builderServiceAccount"
diff --git a/infra/config/generated/tricium-prod.cfg b/infra/config/generated/tricium-prod.cfg
index bebfe2c7..daa23d9a 100644
--- a/infra/config/generated/tricium-prod.cfg
+++ b/infra/config/generated/tricium-prod.cfg
@@ -18,7 +18,7 @@
   path_filters: "*.cc"
   path_filters: "*.cpp"
   path_filters: "*.h"
-  owner: "gbiv@google.com"
+  owner: "gbiv@chromium.org"
   monorail_component: "Infra>Platform>Tricium>Analyzer"
 
   impls {
diff --git a/infra/config/lib/try.star b/infra/config/lib/try.star
index 8997fa0..e70c4f5f 100644
--- a/infra/config/lib/try.star
+++ b/infra/config/lib/try.star
@@ -331,20 +331,6 @@
   )
 
 
-def chromium_codesearch_builder(*, name, os=None, **kwargs):
-  return try_builder(
-      name = name,
-      builderless = True,
-      configure_kitchen = False,
-      executable = 'recipe:chromium_codesearch',
-      mastername = 'tryserver.chromium.codesearch',
-      goma_backend = builders.goma.backend.RBE_PROD,
-      execution_timeout = 9 * time.hour,
-      os = os,
-      **kwargs
-  )
-
-
 def chromium_dawn_builder(*, name, **kwargs):
   return try_builder(
       name = name,
@@ -535,7 +521,6 @@
     chromium_android_builder = chromium_android_builder,
     chromium_angle_builder = chromium_angle_builder,
     chromium_chromiumos_builder = chromium_chromiumos_builder,
-    chromium_codesearch_builder = chromium_codesearch_builder,
     chromium_dawn_builder = chromium_dawn_builder,
     chromium_linux_builder = chromium_linux_builder,
     chromium_mac_builder = chromium_mac_builder,
diff --git a/infra/config/main.star b/infra/config/main.star
index 19298ef..8b760828 100755
--- a/infra/config/main.star
+++ b/infra/config/main.star
@@ -95,6 +95,7 @@
 exec('//notifiers.star')
 
 exec('//subprojects/chromium/subproject.star')
+master_only_exec('//subprojects/codesearch/subproject.star')
 master_only_exec('//subprojects/findit/subproject.star')
 master_only_exec('//subprojects/goma/subproject.star')
 master_only_exec('//subprojects/webrtc/subproject.star')
diff --git a/infra/config/subprojects/README.md b/infra/config/subprojects/README.md
index 7bd73130..3b9fbfa 100644
--- a/infra/config/subprojects/README.md
+++ b/infra/config/subprojects/README.md
@@ -3,6 +3,7 @@
 The following subprojects exist:
 
 * chromium - Builders that test the chromium/src codebase.
+* codesearch - Builders that test codesearch with chromium.
 * findit - Builders that are used by the Sheriff-o-Matic findit service.
 * goma - Builders that test the use of goma by chromium builders.
 * webrtc - Builders that test the integration of WebRTC with chromium.
diff --git a/infra/config/subprojects/chromium/master-only/ci.star b/infra/config/subprojects/chromium/master-only/ci.star
index 361ebdfd..acb947df 100644
--- a/infra/config/subprojects/chromium/master-only/ci.star
+++ b/infra/config/subprojects/chromium/master-only/ci.star
@@ -85,10 +85,6 @@
                 'cipd_yaml': 'third_party/android_sdk/cipd/build-tools/25.0.2.yaml'
             },
             {
-                'sdk_package_name': 'build-tools;27.0.3',
-                'cipd_yaml': 'third_party/android_sdk/cipd/build-tools/27.0.3.yaml'
-            },
-            {
                 'sdk_package_name': 'build-tools;29.0.2',
                 'cipd_yaml': 'third_party/android_sdk/cipd/build-tools/29.0.2.yaml'
             },
@@ -113,14 +109,6 @@
                 'cipd_yaml': 'third_party/android_sdk/cipd/patcher/v4.yaml'
             },
             {
-                'sdk_package_name': 'platforms;android-23',
-                'cipd_yaml': 'third_party/android_sdk/cipd/platforms/android-23.yaml'
-            },
-            {
-                'sdk_package_name': 'platforms;android-28',
-                'cipd_yaml': 'third_party/android_sdk/cipd/platforms/android-28.yaml'
-            },
-            {
                 'sdk_package_name': 'platforms;android-29',
                 'cipd_yaml': 'third_party/android_sdk/cipd/platforms/android-29.yaml'
             },
@@ -133,10 +121,6 @@
                 'cipd_yaml': 'third_party/android_sdk/cipd/platform-tools.yaml'
             },
             {
-                'sdk_package_name': 'sources;android-28',
-                'cipd_yaml': 'third_party/android_sdk/cipd/sources/android-28.yaml'
-            },
-            {
                 'sdk_package_name': 'sources;android-29',
                 'cipd_yaml': 'third_party/android_sdk/cipd/sources/android-29.yaml'
             },
@@ -146,19 +130,6 @@
             #    'cipd_yaml': 'third_party/android_sdk/cipd/sources/android-30.yaml'
             #},
             {
-                'sdk_package_name': 'system-images;android-23;google_apis;x86',
-                'cipd_yaml': 'third_party/android_sdk/cipd/system_images/android-23/google_apis/x86.yaml'
-            },
-            # Missing due to http://b/155847875.
-            #{
-            #    'sdk_package_name': 'system-images;android-28;google_apis;x86',
-            #    'cipd_yaml': 'third_party/android_sdk/cipd/system_images/android-28/google_apis/x86.yaml'
-            #},
-            {
-                'sdk_package_name': 'system-images;android-28;google_apis_playstore;x86',
-                'cipd_yaml': 'third_party/android_sdk/cipd/system_images/android-28/google_apis_playstore/x86.yaml'
-            },
-            {
                 'sdk_package_name': 'system-images;android-29;google_apis;x86',
                 'cipd_yaml': 'third_party/android_sdk/cipd/system_images/android-29/google_apis/x86.yaml'
             },
diff --git a/infra/config/subprojects/chromium/master-only/consoles/luci.chromium.try.star b/infra/config/subprojects/chromium/master-only/consoles/luci.chromium.try.star
index 62eb788..f3f09c1 100644
--- a/infra/config/subprojects/chromium/master-only/consoles/luci.chromium.try.star
+++ b/infra/config/subprojects/chromium/master-only/consoles/luci.chromium.try.star
@@ -46,7 +46,6 @@
         'try/chromeos-kevin-rel',
         'try/chromium_presubmit',
         'try/closure_compilation',
-        'try/codesearch-gen-chromium-win-try',
         'try/fuchsia-angle-rel',
         'try/fuchsia-compile-x64-dbg',
         'try/gpu-fyi-try-android-l-nexus-5-32',
diff --git a/infra/config/subprojects/chromium/master-only/try.star b/infra/config/subprojects/chromium/master-only/try.star
index 4eecf30..663c302 100644
--- a/infra/config/subprojects/chromium/master-only/try.star
+++ b/infra/config/subprojects/chromium/master-only/try.star
@@ -299,12 +299,6 @@
 )
 
 
-try_.chromium_codesearch_builder(
-    name = 'codesearch-gen-chromium-win-try',
-    os = os.WINDOWS_10,
-)
-
-
 try_.chromium_dawn_builder(
     name = 'linux-dawn-rel',
 )
diff --git a/infra/config/subprojects/codesearch/README.md b/infra/config/subprojects/codesearch/README.md
new file mode 100644
index 0000000..7f45bb2
--- /dev/null
+++ b/infra/config/subprojects/codesearch/README.md
@@ -0,0 +1,4 @@
+Definitions of LUCI entities that test codesearch with chromium.
+
+* consoles - Manually curated consoles for codesearch subproject builders.
+* codesearch.star - Builders that test codesearch with chromium.
diff --git a/infra/config/subprojects/codesearch/codesearch.star b/infra/config/subprojects/codesearch/codesearch.star
new file mode 100644
index 0000000..c135e00
--- /dev/null
+++ b/infra/config/subprojects/codesearch/codesearch.star
@@ -0,0 +1,70 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+load('//lib/builders.star', 'cpu', 'goma', 'os')
+load('//lib/try.star', 'try_')
+
+luci.bucket(
+    name = 'codesearch',
+    acls = [
+        acl.entry(
+            roles = acl.BUILDBUCKET_READER,
+            groups = 'all',
+        ),
+        acl.entry(
+            roles = acl.BUILDBUCKET_TRIGGERER,
+            groups = 'project-chromium-tryjob-access',
+        ),
+        acl.entry(
+            roles = acl.BUILDBUCKET_OWNER,
+            groups = 'service-account-chromium-tryserver',
+        ),
+    ],
+)
+
+try_.defaults.bucket.set('codesearch')
+try_.defaults.build_numbers.set(True)
+try_.defaults.builderless.set(True)
+try_.defaults.cores.set(8)
+try_.defaults.cpu.set(cpu.X86_64)
+try_.defaults.cq_group.set('cq')
+try_.defaults.executable.set('recipe:chromium_codesearch')
+try_.defaults.execution_timeout.set(9 * time.hour)
+try_.defaults.expiration_timeout.set(2 * time.hour)
+try_.defaults.goma_backend.set(goma.backend.RBE_PROD)
+try_.defaults.mastername.set('tryserver.chromium.codesearch')
+try_.defaults.os.set(os.LINUX_DEFAULT)
+try_.defaults.pool.set('luci.chromium.try')
+try_.defaults.service_account.set('chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com')
+try_.defaults.swarming_tags.set(['vpython:native-python-wrapper'])
+
+try_.defaults.caches.set([
+    swarming.cache(
+        name = 'win_toolchain',
+        path = 'win_toolchain',
+    ),
+])
+
+try_.builder(
+    name = 'gen-android-try',
+)
+
+try_.builder(
+    name = 'gen-chromiumos-try',
+)
+
+try_.builder(
+    name = 'gen-fuchsia-try',
+)
+
+try_.builder(
+    name = 'gen-linux-try',
+)
+
+try_.builder(
+    name = 'gen-win-try',
+    os = os.WINDOWS_10,
+)
+
+
diff --git a/infra/config/subprojects/codesearch/consoles/luci.chromium.codesearch.star b/infra/config/subprojects/codesearch/consoles/luci.chromium.codesearch.star
new file mode 100644
index 0000000..5e0db056
--- /dev/null
+++ b/infra/config/subprojects/codesearch/consoles/luci.chromium.codesearch.star
@@ -0,0 +1,14 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+luci.list_view(
+    name = 'luci.chromium.codesearch',
+    entries = [
+      'codesearch/gen-android-try',
+      'codesearch/gen-chromiumos-try',
+      'codesearch/gen-fuchsia-try',
+      'codesearch/gen-linux-try',
+      'codesearch/gen-win-try',
+    ],
+)
diff --git a/infra/config/subprojects/codesearch/subproject.star b/infra/config/subprojects/codesearch/subproject.star
new file mode 100644
index 0000000..5d0abe28
--- /dev/null
+++ b/infra/config/subprojects/codesearch/subproject.star
@@ -0,0 +1,7 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+exec('./codesearch.star')
+exec('./consoles/luci.chromium.codesearch.star')
+
diff --git a/infra/config/tricium-prod.cfg b/infra/config/tricium-prod.cfg
index bebfe2c7..daa23d9a 100644
--- a/infra/config/tricium-prod.cfg
+++ b/infra/config/tricium-prod.cfg
@@ -18,7 +18,7 @@
   path_filters: "*.cc"
   path_filters: "*.cpp"
   path_filters: "*.h"
-  owner: "gbiv@google.com"
+  owner: "gbiv@chromium.org"
   monorail_component: "Infra>Platform>Tricium>Analyzer"
 
   impls {
diff --git a/ios/chrome/browser/favicon/BUILD.gn b/ios/chrome/browser/favicon/BUILD.gn
index f6b55494..3e9412e 100644
--- a/ios/chrome/browser/favicon/BUILD.gn
+++ b/ios/chrome/browser/favicon/BUILD.gn
@@ -23,6 +23,7 @@
   deps = [
     "//base",
     "//components/favicon/core",
+    "//components/favicon/core:history_implementation",
     "//components/favicon_base",
     "//components/image_fetcher/core",
     "//components/image_fetcher/ios",
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index d00e4fe..8cc8cea 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -402,7 +402,7 @@
 // Disables the real audio output stream after silent audio has been delivered
 // for too long. Should save quite a bit of power in the muted video case.
 const base::Feature kSuspendMutedAudio{"SuspendMutedAudio",
-                                       base::FEATURE_DISABLED_BY_DEFAULT};
+                                       base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Use shared block-based buffering for media.
 const base::Feature kUseNewMediaCache{"use-new-media-cache",
diff --git a/media/gpu/android/direct_shared_image_video_provider.cc b/media/gpu/android/direct_shared_image_video_provider.cc
index e938341..b7daff6 100644
--- a/media/gpu/android/direct_shared_image_video_provider.cc
+++ b/media/gpu/android/direct_shared_image_video_provider.cc
@@ -239,7 +239,8 @@
   // TODO(vikassoni): This shared image need to be thread safe eventually for
   // webview to work with shared images.
   auto shared_image = std::make_unique<gpu::SharedImageVideo>(
-      mailbox, coded_size, gfx::ColorSpace::CreateSRGB(), std::move(image),
+      mailbox, coded_size, gfx::ColorSpace::CreateSRGB(),
+      kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, std::move(image),
       std::move(texture), std::move(shared_context),
       false /* is_thread_safe */);
 
diff --git a/media/gpu/chromeos/mailbox_video_frame_converter.cc b/media/gpu/chromeos/mailbox_video_frame_converter.cc
index 19c3829..bbe7619 100644
--- a/media/gpu/chromeos/mailbox_video_frame_converter.cc
+++ b/media/gpu/chromeos/mailbox_video_frame_converter.cc
@@ -340,7 +340,8 @@
       mailbox, gpu::kPlatformVideoFramePoolClientId,
       std::move(gpu_memory_buffer_handle), *buffer_format,
       gpu::kNullSurfaceHandle, destination_visible_rect.size(),
-      video_frame->ColorSpace(), shared_image_usage);
+      video_frame->ColorSpace(), kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
+      shared_image_usage);
   if (!success) {
     OnError(FROM_HERE, "Failed to create shared image.");
     return false;
diff --git a/media/renderers/paint_canvas_video_renderer.cc b/media/renderers/paint_canvas_video_renderer.cc
index b61b865..77b11d8 100644
--- a/media/renderers/paint_canvas_video_renderer.cc
+++ b/media/renderers/paint_canvas_video_renderer.cc
@@ -738,6 +738,8 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(VideoImageGenerator);
 };
 
+// TODO(jochin): Add support for all OOP-R specific APIs (eg. GetMailbox() and
+// GetSkImageViaReadback())
 class VideoTextureBacking : public cc::TextureBacking {
  public:
   explicit VideoTextureBacking(sk_sp<SkImage> sk_image)
@@ -748,6 +750,7 @@
   }
   gpu::Mailbox GetMailbox() const override { return mailbox_; }
   sk_sp<SkImage> GetAcceleratedSkImage() override { return sk_image_; }
+  sk_sp<SkImage> GetSkImageViaReadback() override { return nullptr; }
 
  private:
   const sk_sp<SkImage> sk_image_;
diff --git a/net/http/transport_security_state.h b/net/http/transport_security_state.h
index ba863bd6..98603bd 100644
--- a/net/http/transport_security_state.h
+++ b/net/http/transport_security_state.h
@@ -303,10 +303,10 @@
     virtual void Send(const GURL& report_uri,
                       base::StringPiece content_type,
                       base::StringPiece report,
-                      const base::Callback<void()>& success_callback,
-                      const base::Callback<void(const GURL&,
-                                                int /* net_error */,
-                                                int /* http_response_code */)>&
+                      base::OnceCallback<void()> success_callback,
+                      base::OnceCallback<void(const GURL&,
+                                              int /* net_error */,
+                                              int /* http_response_code */)>
                           error_callback) = 0;
 
    protected:
diff --git a/net/http/transport_security_state_unittest.cc b/net/http/transport_security_state_unittest.cc
index 8131e68..f35510d1 100644
--- a/net/http/transport_security_state_unittest.cc
+++ b/net/http/transport_security_state_unittest.cc
@@ -85,7 +85,8 @@
 const char* const kBadPath[] = {
     "sha256/1111111111111111111111111111111111111111111=",
     "sha256/2222222222222222222222222222222222222222222=",
-    "sha256/3333333333333333333333333333333333333333333=", nullptr,
+    "sha256/3333333333333333333333333333333333333333333=",
+    nullptr,
 };
 
 // Constructs a SignedCertificateTimestampAndStatus with the given information
@@ -116,12 +117,12 @@
   MockCertificateReportSender() = default;
   ~MockCertificateReportSender() override = default;
 
-  void Send(const GURL& report_uri,
-            base::StringPiece content_type,
-            base::StringPiece report,
-            const base::Callback<void()>& success_callback,
-            const base::Callback<void(const GURL&, int, int)>& error_callback)
-      override {
+  void Send(
+      const GURL& report_uri,
+      base::StringPiece content_type,
+      base::StringPiece report,
+      base::OnceCallback<void()> success_callback,
+      base::OnceCallback<void(const GURL&, int, int)> error_callback) override {
     latest_report_uri_ = report_uri;
     latest_report_.assign(report.data(), report.size());
     latest_content_type_.assign(content_type.data(), content_type.size());
@@ -153,14 +154,14 @@
   int net_error() { return net_error_; }
 
   // TransportSecurityState::ReportSenderInterface:
-  void Send(const GURL& report_uri,
-            base::StringPiece content_type,
-            base::StringPiece report,
-            const base::Callback<void()>& success_callback,
-            const base::Callback<void(const GURL&, int, int)>& error_callback)
-      override {
+  void Send(
+      const GURL& report_uri,
+      base::StringPiece content_type,
+      base::StringPiece report,
+      base::OnceCallback<void()> success_callback,
+      base::OnceCallback<void(const GURL&, int, int)> error_callback) override {
     ASSERT_FALSE(error_callback.is_null());
-    error_callback.Run(report_uri, net_error_, 0);
+    std::move(error_callback).Run(report_uri, net_error_, 0);
   }
 
  private:
@@ -355,9 +356,7 @@
     SetTransportSecurityStateSourceForTesting(nullptr);
   }
 
-  void SetUp() override {
-    crypto::EnsureOpenSSLInit();
-  }
+  void SetUp() override { crypto::EnsureOpenSSLInit(); }
 
   static void DisableStaticPins(TransportSecurityState* state) {
     state->enable_static_pins_ = false;
diff --git a/net/quic/platform/impl/quic_flags_impl.h b/net/quic/platform/impl/quic_flags_impl.h
index 39a7eb0..edbf5279 100644
--- a/net/quic/platform/impl/quic_flags_impl.h
+++ b/net/quic/platform/impl/quic_flags_impl.h
@@ -11,9 +11,7 @@
 #include <string>
 #include <vector>
 
-#include "base/command_line.h"
 #include "base/export_template.h"
-#include "base/no_destructor.h"
 #include "base/optional.h"
 #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
@@ -22,6 +20,12 @@
 #include "net/quic/quic_flags_list.h"
 #undef QUIC_FLAG
 
+namespace base {
+class CommandLine;
+template <typename T>
+class NoDestructor;
+}  // namespace base
+
 // API compatibility with new-style flags.
 
 inline bool GetQuicFlagImpl(bool flag) {
diff --git a/net/quic/platform/impl/quic_flags_test.cc b/net/quic/platform/impl/quic_flags_test.cc
index 0a77e8d..3bc0b26 100644
--- a/net/quic/platform/impl/quic_flags_test.cc
+++ b/net/quic/platform/impl/quic_flags_test.cc
@@ -4,6 +4,7 @@
 
 #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
 
+#include "base/command_line.h"
 #include "base/optional.h"
 #include "base/stl_util.h"
 #include "base/strings/strcat.h"
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index 1e741249..9d7c17e 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -1108,14 +1108,6 @@
 }
 
 TEST_P(QuicHttpStreamTest, LogGranularQuicErrorIfHandshakeNotConfirmed) {
-  // TODO(nharper): Figure out why this test does not send packets
-  // when TLS is used.
-  if (version_.UsesTls()) {
-    Initialize();
-
-    return;
-  }
-
   // By default the test setup defaults handshake to be confirmed. Manually set
   // it to be not confirmed.
   crypto_client_stream_factory_.set_handshake_mode(
diff --git a/net/url_request/report_sender.cc b/net/url_request/report_sender.cc
index daccbe06..1e30a609 100644
--- a/net/url_request/report_sender.cc
+++ b/net/url_request/report_sender.cc
@@ -13,23 +13,30 @@
 #include "net/http/http_status_code.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_status.h"
+#include "url/gurl.h"
 
 namespace {
 const void* const kUserDataKey = &kUserDataKey;
 
 class CallbackInfo : public base::SupportsUserData::Data {
  public:
-  CallbackInfo(const net::ReportSender::SuccessCallback& success_callback,
-               const net::ReportSender::ErrorCallback& error_callback)
-      : success_callback_(success_callback), error_callback_(error_callback) {}
+  CallbackInfo(net::ReportSender::SuccessCallback success_callback,
+               net::ReportSender::ErrorCallback error_callback)
+      : success_callback_(std::move(success_callback)),
+        error_callback_(std::move(error_callback)) {}
 
   ~CallbackInfo() override = default;
 
-  const net::ReportSender::SuccessCallback& success_callback() const {
-    return success_callback_;
+  void RunSuccessCallback() {
+    if (!success_callback_.is_null())
+      std::move(success_callback_).Run();
   }
-  const net::ReportSender::ErrorCallback& error_callback() const {
-    return error_callback_;
+
+  void RunErrorCallback(const GURL& url,
+                        int net_error,
+                        int http_response_code) {
+    if (!error_callback_.is_null())
+      std::move(error_callback_).Run(url, net_error, http_response_code);
   }
 
  private:
@@ -52,14 +59,14 @@
 void ReportSender::Send(const GURL& report_uri,
                         base::StringPiece content_type,
                         base::StringPiece report,
-                        const SuccessCallback& success_callback,
-                        const ErrorCallback& error_callback) {
+                        SuccessCallback success_callback,
+                        ErrorCallback error_callback) {
   DCHECK(!content_type.empty());
   std::unique_ptr<URLRequest> url_request = request_context_->CreateRequest(
       report_uri, DEFAULT_PRIORITY, this, traffic_annotation_);
   url_request->SetUserData(
-      &kUserDataKey,
-      std::make_unique<CallbackInfo>(success_callback, error_callback));
+      &kUserDataKey, std::make_unique<CallbackInfo>(std::move(success_callback),
+                                                    std::move(error_callback)));
 
   url_request->SetLoadFlags(kLoadFlags);
   url_request->set_allow_credentials(false);
@@ -89,15 +96,12 @@
   DCHECK(callback_info);
   if (net_error != OK) {
     DVLOG(1) << "Failed to send report for " << request->url().host();
-    if (!callback_info->error_callback().is_null())
-      callback_info->error_callback().Run(request->url(), net_error, -1);
+    callback_info->RunErrorCallback(request->url(), net_error, -1);
   } else if (request->GetResponseCode() != net::HTTP_OK) {
-    if (!callback_info->error_callback().is_null())
-      callback_info->error_callback().Run(request->url(), OK,
-                                          request->GetResponseCode());
+    callback_info->RunErrorCallback(request->url(), OK,
+                                    request->GetResponseCode());
   } else {
-    if (!callback_info->success_callback().is_null())
-      callback_info->success_callback().Run();
+    callback_info->RunSuccessCallback();
   }
   CHECK_GT(inflight_requests_.erase(request), 0u);
 }
diff --git a/net/url_request/report_sender.h b/net/url_request/report_sender.h
index 83f581c..1e40236 100644
--- a/net/url_request/report_sender.h
+++ b/net/url_request/report_sender.h
@@ -33,8 +33,8 @@
  public:
   static const int kLoadFlags;
 
-  using SuccessCallback = base::Callback<void()>;
-  using ErrorCallback = base::Callback<
+  using SuccessCallback = base::OnceCallback<void()>;
+  using ErrorCallback = base::OnceCallback<
       void(const GURL&, int /* net_error */, int /* http_response_code */)>;
 
   // Constructs a ReportSender that sends reports with the
@@ -49,8 +49,8 @@
   void Send(const GURL& report_uri,
             base::StringPiece content_type,
             base::StringPiece report,
-            const SuccessCallback& success_callback,
-            const ErrorCallback& error_callback) override;
+            SuccessCallback success_callback,
+            ErrorCallback error_callback) override;
 
   // net::URLRequest::Delegate implementation.
   void OnResponseStarted(URLRequest* request, int net_error) override;
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 83950dc2..5e34dbf 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -11,9 +11,9 @@
 #include "build/build_config.h"
 
 #if defined(OS_WIN)
-#include <windows.h>
 #include <objbase.h>
 #include <shlobj.h>
+#include <windows.h>
 #include <wrl/client.h>
 #endif
 
@@ -218,9 +218,8 @@
 }
 
 // Same as above, but with proxy times.
-void TestLoadTimingNotReusedWithProxy(
-    const LoadTimingInfo& load_timing_info,
-    int connect_timing_flags) {
+void TestLoadTimingNotReusedWithProxy(const LoadTimingInfo& load_timing_info,
+                                      int connect_timing_flags) {
   EXPECT_FALSE(load_timing_info.socket_reused);
   EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
 
@@ -244,8 +243,7 @@
 }
 
 // Same as above, but with a reused socket and proxy times.
-void TestLoadTimingReusedWithProxy(
-    const LoadTimingInfo& load_timing_info) {
+void TestLoadTimingReusedWithProxy(const LoadTimingInfo& load_timing_info) {
   EXPECT_TRUE(load_timing_info.socket_reused);
   EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
 
@@ -258,8 +256,7 @@
             load_timing_info.proxy_resolve_start);
   EXPECT_LE(load_timing_info.proxy_resolve_start,
             load_timing_info.proxy_resolve_end);
-  EXPECT_LE(load_timing_info.proxy_resolve_end,
-            load_timing_info.send_start);
+  EXPECT_LE(load_timing_info.proxy_resolve_end, load_timing_info.send_start);
   EXPECT_LE(load_timing_info.send_start, load_timing_info.send_end);
   EXPECT_LE(load_timing_info.send_end, load_timing_info.receive_headers_start);
   EXPECT_LE(load_timing_info.receive_headers_start,
@@ -278,8 +275,7 @@
   return cookie_list;
 }
 
-void TestLoadTimingCacheHitNoNetwork(
-    const LoadTimingInfo& load_timing_info) {
+void TestLoadTimingCacheHitNoNetwork(const LoadTimingInfo& load_timing_info) {
   EXPECT_FALSE(load_timing_info.socket_reused);
   EXPECT_EQ(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
 
@@ -301,8 +297,7 @@
     !defined(OS_FUCHSIA)
 // Tests load timing in the case that there is no HTTP response.  This can be
 // used to test in the case of errors or non-HTTP requests.
-void TestLoadTimingNoHttpResponse(
-    const LoadTimingInfo& load_timing_info) {
+void TestLoadTimingNoHttpResponse(const LoadTimingInfo& load_timing_info) {
   EXPECT_FALSE(load_timing_info.socket_reused);
   EXPECT_EQ(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
 
@@ -423,13 +418,9 @@
     ASSERT_NE(OK, retval);
     retval_ = retval;
   }
-  void set_redirect_url(const GURL& url) {
-    redirect_url_ = url;
-  }
+  void set_redirect_url(const GURL& url) { redirect_url_ = url; }
 
-  void set_block_on(int block_on) {
-    block_on_ = block_on;
-  }
+  void set_block_on(int block_on) { block_on_ = block_on; }
 
   // Allows the user to check in which state did we block.
   Stage stage_blocked_for_callback() const {
@@ -474,7 +465,7 @@
   int retval_;
 
   GURL redirect_url_;  // Used if non-empty during OnBeforeURLRequest.
-  int block_on_;  // Bit mask: in which stages to block.
+  int block_on_;       // Bit mask: in which stages to block.
 
   // Internal variables, not set by not the user:
   // Last blocked stage waiting for user callback (unused if |block_mode_| !=
@@ -641,12 +632,12 @@
   MockCertificateReportSender() = default;
   ~MockCertificateReportSender() override = default;
 
-  void Send(const GURL& report_uri,
-            base::StringPiece content_type,
-            base::StringPiece report,
-            const base::Callback<void()>& success_callback,
-            const base::Callback<void(const GURL&, int, int)>& error_callback)
-      override {
+  void Send(
+      const GURL& report_uri,
+      base::StringPiece content_type,
+      base::StringPiece report,
+      base::OnceCallback<void()> success_callback,
+      base::OnceCallback<void(const GURL&, int, int)> error_callback) override {
     latest_report_uri_ = report_uri;
     latest_report_.assign(report.data(), report.size());
     latest_content_type_.assign(content_type.data(), content_type.size());
@@ -986,13 +977,9 @@
 class URLRequestInterceptorWithLoadTimingInfo : public URLRequestInterceptor {
  public:
   // Static getters for canned response header and data strings.
-  static std::string ok_data() {
-    return URLRequestTestJob::test_data_1();
-  }
+  static std::string ok_data() { return URLRequestTestJob::test_data_1(); }
 
-  static std::string ok_headers() {
-    return URLRequestTestJob::test_headers();
-  }
+  static std::string ok_headers() { return URLRequestTestJob::test_headers(); }
 
   URLRequestInterceptorWithLoadTimingInfo() = default;
   ~URLRequestInterceptorWithLoadTimingInfo() override = default;
@@ -1127,9 +1114,8 @@
   LoadTimingInfo job_load_timing =
       NormalLoadTimingInfo(now, CONNECT_TIMING_HAS_DNS_TIMES, false);
 
-  LoadTimingInfo load_timing_result =
-      RunURLRequestInterceptorLoadTimingTest(
-          job_load_timing, default_context(), interceptor());
+  LoadTimingInfo load_timing_result = RunURLRequestInterceptorLoadTimingTest(
+      job_load_timing, default_context(), interceptor());
 
   // Nothing should have been changed by the URLRequest.
   EXPECT_EQ(job_load_timing.proxy_resolve_start,
@@ -1159,9 +1145,8 @@
   LoadTimingInfo job_load_timing =
       NormalLoadTimingInfo(now, CONNECT_TIMING_HAS_SSL_TIMES, true);
 
-  LoadTimingInfo load_timing_result =
-      RunURLRequestInterceptorLoadTimingTest(
-          job_load_timing, default_context(), interceptor());
+  LoadTimingInfo load_timing_result = RunURLRequestInterceptorLoadTimingTest(
+      job_load_timing, default_context(), interceptor());
 
   // Nothing should have been changed by the URLRequest.
   EXPECT_EQ(job_load_timing.proxy_resolve_start,
@@ -1205,9 +1190,8 @@
   job_load_timing.connect_timing.connect_end =
       now - base::TimeDelta::FromDays(1);
 
-  LoadTimingInfo load_timing_result =
-      RunURLRequestInterceptorLoadTimingTest(
-          job_load_timing, default_context(), interceptor());
+  LoadTimingInfo load_timing_result = RunURLRequestInterceptorLoadTimingTest(
+      job_load_timing, default_context(), interceptor());
 
   // Proxy times, connect times, and DNS times should all be replaced with
   // request_start.
@@ -1237,9 +1221,8 @@
   job_load_timing.proxy_resolve_start = now - base::TimeDelta::FromDays(4);
   job_load_timing.proxy_resolve_end = now - base::TimeDelta::FromDays(3);
 
-  LoadTimingInfo load_timing_result =
-      RunURLRequestInterceptorLoadTimingTest(
-          job_load_timing, default_context(), interceptor());
+  LoadTimingInfo load_timing_result = RunURLRequestInterceptorLoadTimingTest(
+      job_load_timing, default_context(), interceptor());
 
   // Proxy times and connect times should all be replaced with request_start.
   EXPECT_EQ(load_timing_result.request_start,
@@ -1267,9 +1250,8 @@
   job_load_timing.connect_timing.connect_end =
       now - base::TimeDelta::FromDays(4);
 
-  LoadTimingInfo load_timing_result =
-      RunURLRequestInterceptorLoadTimingTest(
-          job_load_timing, default_context(), interceptor());
+  LoadTimingInfo load_timing_result = RunURLRequestInterceptorLoadTimingTest(
+      job_load_timing, default_context(), interceptor());
 
   // Connect times, and SSL times should be replaced with request_start.
   EXPECT_EQ(load_timing_result.request_start,
@@ -1300,9 +1282,8 @@
   job_load_timing.connect_timing.connect_end =
       now - base::TimeDelta::FromDays(2);
 
-  LoadTimingInfo load_timing_result =
-      RunURLRequestInterceptorLoadTimingTest(
-          job_load_timing, default_context(), interceptor());
+  LoadTimingInfo load_timing_result = RunURLRequestInterceptorLoadTimingTest(
+      job_load_timing, default_context(), interceptor());
 
   // Connect times should be replaced with proxy_resolve_end.
   EXPECT_EQ(load_timing_result.proxy_resolve_end,
@@ -1606,8 +1587,8 @@
     req->Start();
     d.RunUntilComplete();
 
-    EXPECT_TRUE(d.data_received().find("CookieToNotSend=1")
-                != std::string::npos);
+    EXPECT_TRUE(d.data_received().find("CookieToNotSend=1") !=
+                std::string::npos);
     EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
     EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
   }
@@ -1828,8 +1809,8 @@
     req->Start();
     d.RunUntilComplete();
 
-    EXPECT_TRUE(d.data_received().find("CookieToNotSend=1")
-                != std::string::npos);
+    EXPECT_TRUE(d.data_received().find("CookieToNotSend=1") !=
+                std::string::npos);
     EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
     EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
   }
@@ -1846,8 +1827,8 @@
     req->Start();
     d.RunUntilComplete();
 
-    EXPECT_TRUE(d.data_received().find("Cookie: CookieToNotSend=1")
-                == std::string::npos);
+    EXPECT_TRUE(d.data_received().find("Cookie: CookieToNotSend=1") ==
+                std::string::npos);
 
     // LOAD_DO_NOT_SEND_COOKIES does not trigger OnGetCookies.
     EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
@@ -1905,10 +1886,10 @@
     req->Start();
     d.RunUntilComplete();
 
-    EXPECT_TRUE(d.data_received().find("CookieToNotSave=1")
-                == std::string::npos);
-    EXPECT_TRUE(d.data_received().find("CookieToNotUpdate=2")
-                != std::string::npos);
+    EXPECT_TRUE(d.data_received().find("CookieToNotSave=1") ==
+                std::string::npos);
+    EXPECT_TRUE(d.data_received().find("CookieToNotUpdate=2") !=
+                std::string::npos);
 
     EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
     EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
@@ -1946,8 +1927,8 @@
     req->Start();
     d.RunUntilComplete();
 
-    EXPECT_TRUE(d.data_received().find("CookieToNotSend=1")
-                != std::string::npos);
+    EXPECT_TRUE(d.data_received().find("CookieToNotSend=1") !=
+                std::string::npos);
 
     EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
     EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
@@ -1970,8 +1951,8 @@
     req->Start();
     d.RunUntilComplete();
 
-    EXPECT_TRUE(d.data_received().find("Cookie: CookieToNotSend=1")
-                == std::string::npos);
+    EXPECT_TRUE(d.data_received().find("Cookie: CookieToNotSend=1") ==
+                std::string::npos);
 
     EXPECT_EQ(1, network_delegate.blocked_get_cookies_count());
     EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
@@ -2044,10 +2025,10 @@
     req->Start();
     d.RunUntilComplete();
 
-    EXPECT_TRUE(d.data_received().find("CookieToNotSave=1")
-                == std::string::npos);
-    EXPECT_TRUE(d.data_received().find("CookieToNotUpdate=2")
-                != std::string::npos);
+    EXPECT_TRUE(d.data_received().find("CookieToNotSave=1") ==
+                std::string::npos);
+    EXPECT_TRUE(d.data_received().find("CookieToNotUpdate=2") !=
+                std::string::npos);
 
     EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
     EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
@@ -2105,8 +2086,8 @@
     req->Start();
     d.RunUntilComplete();
 
-    EXPECT_TRUE(d.data_received().find("CookieToNotSend=1")
-                != std::string::npos);
+    EXPECT_TRUE(d.data_received().find("CookieToNotSend=1") !=
+                std::string::npos);
 
     EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
     EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
@@ -2124,8 +2105,8 @@
     req->Start();
     d.RunUntilComplete();
 
-    EXPECT_TRUE(d.data_received().find("Cookie: CookieToNotSend=1")
-                == std::string::npos);
+    EXPECT_TRUE(d.data_received().find("Cookie: CookieToNotSend=1") ==
+                std::string::npos);
 
     EXPECT_EQ(1, network_delegate.blocked_get_cookies_count());
     EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
@@ -2179,10 +2160,10 @@
     req->Start();
     d.RunUntilComplete();
 
-    EXPECT_TRUE(d.data_received().find("CookieToNotSave=1")
-                == std::string::npos);
-    EXPECT_TRUE(d.data_received().find("CookieToNotUpdate=2")
-                != std::string::npos);
+    EXPECT_TRUE(d.data_received().find("CookieToNotSave=1") ==
+                std::string::npos);
+    EXPECT_TRUE(d.data_received().find("CookieToNotUpdate=2") !=
+                std::string::npos);
 
     EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
     EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
@@ -2828,7 +2809,6 @@
   }
 }
 
-
 // Check that it is impossible to change the referrer in the extra headers of
 // an URLRequest.
 TEST_F(URLRequestTest, DoNotOverrideReferrer) {
@@ -3009,10 +2989,10 @@
   void HTTPUploadDataOperationTest(const std::string& method) {
     const int kMsgSize = 20000;  // multiple of 10
     const int kIterations = 50;
-    char* uploadBytes = new char[kMsgSize+1];
+    char* uploadBytes = new char[kMsgSize + 1];
     char* ptr = uploadBytes;
     char marker = 'a';
-    for (int idx = 0; idx < kMsgSize/10; idx++) {
+    for (int idx = 0; idx < kMsgSize / 10; idx++) {
       memcpy(ptr, "----------", 10);
       ptr += 10;
       if (idx % 100 == 0) {
@@ -3038,8 +3018,8 @@
 
       d.RunUntilComplete();
 
-      ASSERT_EQ(1, d.response_started_count()) << "request failed. Error: "
-                                               << d.request_status();
+      ASSERT_EQ(1, d.response_started_count())
+          << "request failed. Error: " << d.request_status();
 
       EXPECT_FALSE(d.received_data_before_response());
       EXPECT_EQ(uploadBytes, d.data_received());
@@ -3144,10 +3124,9 @@
 // Tests that we can block and asynchronously return OK in various stages.
 TEST_F(URLRequestTestHTTP, NetworkDelegateBlockAsynchronously) {
   static const BlockingNetworkDelegate::Stage blocking_stages[] = {
-    BlockingNetworkDelegate::ON_BEFORE_URL_REQUEST,
-    BlockingNetworkDelegate::ON_BEFORE_SEND_HEADERS,
-    BlockingNetworkDelegate::ON_HEADERS_RECEIVED
-  };
+      BlockingNetworkDelegate::ON_BEFORE_URL_REQUEST,
+      BlockingNetworkDelegate::ON_BEFORE_SEND_HEADERS,
+      BlockingNetworkDelegate::ON_HEADERS_RECEIVED};
   static const size_t blocking_stages_length = base::size(blocking_stages);
 
   ASSERT_TRUE(http_test_server()->Start());
@@ -4371,8 +4350,8 @@
     log_position = ExpectLogContainsSomewhereAfter(
         entries, log_position + 1, event, NetLogEventPhase::BEGIN);
 
-    log_position = AsyncDelegateLogger::CheckDelegateInfo(entries,
-                                                          log_position + 1);
+    log_position =
+        AsyncDelegateLogger::CheckDelegateInfo(entries, log_position + 1);
 
     ASSERT_LT(log_position, entries.size());
     EXPECT_EQ(event, entries[log_position].type);
@@ -4445,8 +4424,8 @@
     log_position = ExpectLogContainsSomewhereAfter(
         entries, log_position + 1, event, NetLogEventPhase::BEGIN);
 
-    log_position = AsyncDelegateLogger::CheckDelegateInfo(entries,
-                                                          log_position + 1);
+    log_position =
+        AsyncDelegateLogger::CheckDelegateInfo(entries, log_position + 1);
 
     ASSERT_LT(log_position, entries.size());
     EXPECT_EQ(event, entries[log_position].type);
@@ -4575,9 +4554,9 @@
   ASSERT_TRUE(http_test_server()->Start());
 
   const AsyncLoggingUrlRequestDelegate::CancelStage kCancelStages[] = {
-    AsyncLoggingUrlRequestDelegate::CANCEL_ON_RECEIVED_REDIRECT,
-    AsyncLoggingUrlRequestDelegate::CANCEL_ON_RESPONSE_STARTED,
-    AsyncLoggingUrlRequestDelegate::CANCEL_ON_READ_COMPLETED,
+      AsyncLoggingUrlRequestDelegate::CANCEL_ON_RECEIVED_REDIRECT,
+      AsyncLoggingUrlRequestDelegate::CANCEL_ON_RESPONSE_STARTED,
+      AsyncLoggingUrlRequestDelegate::CANCEL_ON_READ_COMPLETED,
   };
 
   for (auto cancel_stage : kCancelStages) {
@@ -4881,8 +4860,8 @@
 
     d.RunUntilComplete();
 
-    ASSERT_EQ(1, d.response_started_count()) << "request failed. Error: "
-                                             << d.request_status();
+    ASSERT_EQ(1, d.response_started_count())
+        << "request failed. Error: " << d.request_status();
 
     EXPECT_FALSE(d.received_data_before_response());
     EXPECT_TRUE(d.data_received().empty());
@@ -4928,8 +4907,8 @@
 
     ASSERT_EQ(size, base::ReadFile(path, buf.get(), size));
 
-    ASSERT_EQ(1, d.response_started_count()) << "request failed. Error: "
-                                             << d.request_status();
+    ASSERT_EQ(1, d.response_started_count())
+        << "request failed. Error: " << d.request_status();
 
     EXPECT_FALSE(d.received_data_before_response());
 
@@ -4990,8 +4969,8 @@
   const std::string expected_data =
       "abcdthis is a longer chunk than before.\r\n\r\n02323";
 
-  ASSERT_EQ(1, d->response_started_count()) << "request failed. Error: "
-                                            << d->request_status();
+  ASSERT_EQ(1, d->response_started_count())
+      << "request failed. Error: " << d->request_status();
 
   EXPECT_FALSE(d->received_data_before_response());
 
@@ -6606,8 +6585,8 @@
     EXPECT_TRUE(d.data_received().find("user/secret") != std::string::npos);
 
     // Make sure we sent the cookie in the restarted transaction.
-    EXPECT_TRUE(d.data_received().find("Cookie: got_challenged=true")
-        != std::string::npos);
+    EXPECT_TRUE(d.data_received().find("Cookie: got_challenged=true") !=
+                std::string::npos);
   }
 
   // Same test as above, except this time the restart is initiated earlier
@@ -6634,8 +6613,8 @@
     EXPECT_TRUE(d.data_received().find("user2/secret") != std::string::npos);
 
     // Make sure we sent the cookie in the restarted transaction.
-    EXPECT_TRUE(d.data_received().find("Cookie: got_challenged=true")
-        != std::string::npos);
+    EXPECT_TRUE(d.data_received().find("Cookie: got_challenged=true") !=
+                std::string::npos);
   }
 }
 
@@ -8798,7 +8777,7 @@
   ASSERT_TRUE(test_server.Start());
 
   bool err_allowed = true;
-  for (int i = 0; i < 2 ; i++, err_allowed = !err_allowed) {
+  for (int i = 0; i < 2; i++, err_allowed = !err_allowed) {
     TestDelegate d;
     {
       d.set_allow_certificate_errors(err_allowed);
@@ -8833,7 +8812,7 @@
   // Iterate from false to true, just so that we do the opposite of the
   // previous test in order to increase test coverage.
   bool err_allowed = false;
-  for (int i = 0; i < 2 ; i++, err_allowed = !err_allowed) {
+  for (int i = 0; i < 2; i++, err_allowed = !err_allowed) {
     TestDelegate d;
     {
       d.set_allow_certificate_errors(err_allowed);
@@ -9035,7 +9014,6 @@
   RegisterDefaultHandlers(&test_server);
   ASSERT_TRUE(test_server.Start());
 
-
   // Per spec, TransportSecurityState expects a domain name, rather than an IP
   // address, so a MockHostResolver is needed to redirect www.somewhere.com to
   // the EmbeddedTestServer.  By default, MockHostResolver maps all hosts
@@ -9166,6 +9144,7 @@
   int on_certificate_requested_count() {
     return on_certificate_requested_count_;
   }
+
  private:
   int on_certificate_requested_count_;
   base::OnceClosure on_certificate_requested_;
@@ -9498,8 +9477,7 @@
   SpawnedTestServer::SSLOptions ssl_options;
   ssl_options.record_resume = true;
   SpawnedTestServer test_server(
-      SpawnedTestServer::TYPE_HTTPS,
-      ssl_options,
+      SpawnedTestServer::TYPE_HTTPS, ssl_options,
       base::FilePath(FILE_PATH_LITERAL("net/data/ssl")));
   ASSERT_TRUE(test_server.Start());
 
@@ -9573,8 +9551,7 @@
   SpawnedTestServer::SSLOptions ssl_options;
   ssl_options.record_resume = true;
   SpawnedTestServer test_server(
-      SpawnedTestServer::TYPE_HTTPS,
-      ssl_options,
+      SpawnedTestServer::TYPE_HTTPS, ssl_options,
       base::FilePath(FILE_PATH_LITERAL("net/data/ssl")));
   ASSERT_TRUE(test_server.Start());
 
@@ -9605,7 +9582,8 @@
   session_context.cert_transparency_verifier =
       default_context_.cert_transparency_verifier();
   session_context.ct_policy_enforcer = default_context_.ct_policy_enforcer();
-  session_context.proxy_resolution_service = default_context_.proxy_resolution_service();
+  session_context.proxy_resolution_service =
+      default_context_.proxy_resolution_service();
   session_context.ssl_config_service = default_context_.ssl_config_service();
   session_context.http_auth_handler_factory =
       default_context_.http_auth_handler_factory();
@@ -9707,8 +9685,7 @@
     delegate_.set_allow_certificate_errors(true);
 
     SpawnedTestServer test_server(
-        SpawnedTestServer::TYPE_HTTPS,
-        ssl_options,
+        SpawnedTestServer::TYPE_HTTPS, ssl_options,
         base::FilePath(FILE_PATH_LITERAL("net/data/ssl")));
     ASSERT_TRUE(test_server.Start());
 
@@ -9794,8 +9771,7 @@
   SpawnedTestServer::SSLOptions ssl_options;
   ssl_options.record_resume = true;
   SpawnedTestServer test_server(
-      SpawnedTestServer::TYPE_HTTPS,
-      ssl_options,
+      SpawnedTestServer::TYPE_HTTPS, ssl_options,
       base::FilePath(FILE_PATH_LITERAL("net/data/ssl")));
   ASSERT_TRUE(test_server.Start());
 
diff --git a/pdf/BUILD.gn b/pdf/BUILD.gn
index cb7a9e9..ebabd30 100644
--- a/pdf/BUILD.gn
+++ b/pdf/BUILD.gn
@@ -16,17 +16,28 @@
 }
 
 if (enable_pdf) {
-  pdf_engine = 0  # 0 PDFium
-
   config("pdf_common_config") {
     configs = [ "//build/config/compiler:noshadowing" ]
 
-    if (pdf_engine == 0) {
-      include_dirs = [ "//third_party/pdfium" ]
-    }
+    include_dirs = [ "//third_party/pdfium" ]
   }
 
   static_library("pdf") {
+    sources = [ "pdf.cc" ]
+
+    configs += [ ":pdf_common_config" ]
+
+    public = [ "pdf.h" ]
+
+    deps = [
+      ":internal",
+      "//base",
+    ]
+  }
+
+  source_set("internal") {
+    visibility = [ ":*" ]
+
     sources = [
       "accessibility.cc",
       "accessibility.h",
@@ -54,12 +65,35 @@
       "paint_manager.h",
       "paint_ready_rect.cc",
       "paint_ready_rect.h",
-      "pdf.cc",
       "pdf_engine.h",
       "pdf_init.cc",
       "pdf_init.h",
       "pdf_transform.cc",
       "pdf_transform.h",
+      "pdfium/pdfium_api_string_buffer_adapter.cc",
+      "pdfium/pdfium_api_string_buffer_adapter.h",
+      "pdfium/pdfium_document.cc",
+      "pdfium/pdfium_document.h",
+      "pdfium/pdfium_engine.cc",
+      "pdfium/pdfium_engine.h",
+      "pdfium/pdfium_engine_exports.cc",
+      "pdfium/pdfium_engine_exports.h",
+      "pdfium/pdfium_form_filler.cc",
+      "pdfium/pdfium_form_filler.h",
+      "pdfium/pdfium_mem_buffer_file_read.cc",
+      "pdfium/pdfium_mem_buffer_file_read.h",
+      "pdfium/pdfium_mem_buffer_file_write.cc",
+      "pdfium/pdfium_mem_buffer_file_write.h",
+      "pdfium/pdfium_page.cc",
+      "pdfium/pdfium_page.h",
+      "pdfium/pdfium_permissions.cc",
+      "pdfium/pdfium_permissions.h",
+      "pdfium/pdfium_print.cc",
+      "pdfium/pdfium_print.h",
+      "pdfium/pdfium_range.cc",
+      "pdfium/pdfium_range.h",
+      "pdfium/pdfium_unsupported_features.cc",
+      "pdfium/pdfium_unsupported_features.h",
       "ppapi_migration/bitmap.cc",
       "ppapi_migration/bitmap.h",
       "ppapi_migration/callback.cc",
@@ -79,71 +113,46 @@
 
     configs += [ ":pdf_common_config" ]
 
-    public = [ "pdf.h" ]
-
-    friend = [
-      ":pdf_unittests",
-      ":pdf_test_utils",
-      ":pdf_ppapi",
-    ]
-
     deps = [
       ":features",
       "//base",
       "//base:i18n",
+      "//gin",
       "//net",
+      "//pdf/pdfium/fuzzers",
       "//ppapi/cpp:objects",
       "//ppapi/cpp/private:internal_module",
+      "//printing",
       "//skia",
+      "//third_party/pdfium",
       "//ui/base",
       "//ui/gfx/range",
     ]
 
-    if (pdf_engine == 0) {
+    if (is_linux) {
       sources += [
-        "pdfium/pdfium_api_string_buffer_adapter.cc",
-        "pdfium/pdfium_api_string_buffer_adapter.h",
-        "pdfium/pdfium_assert_matching_enums.cc",
-        "pdfium/pdfium_document.cc",
-        "pdfium/pdfium_document.h",
-        "pdfium/pdfium_engine.cc",
-        "pdfium/pdfium_engine.h",
-        "pdfium/pdfium_engine_exports.cc",
-        "pdfium/pdfium_engine_exports.h",
-        "pdfium/pdfium_form_filler.cc",
-        "pdfium/pdfium_form_filler.h",
-        "pdfium/pdfium_mem_buffer_file_read.cc",
-        "pdfium/pdfium_mem_buffer_file_read.h",
-        "pdfium/pdfium_mem_buffer_file_write.cc",
-        "pdfium/pdfium_mem_buffer_file_write.h",
-        "pdfium/pdfium_page.cc",
-        "pdfium/pdfium_page.h",
-        "pdfium/pdfium_permissions.cc",
-        "pdfium/pdfium_permissions.h",
-        "pdfium/pdfium_print.cc",
-        "pdfium/pdfium_print.h",
-        "pdfium/pdfium_range.cc",
-        "pdfium/pdfium_range.h",
-        "pdfium/pdfium_unsupported_features.cc",
-        "pdfium/pdfium_unsupported_features.h",
+        "pdfium/pdfium_font_linux.cc",
+        "pdfium/pdfium_font_linux.h",
       ]
-
-      deps += [
-        "//gin",
-        "//pdf/pdfium/fuzzers",
-        "//printing",
-        "//third_party/pdfium",
-      ]
-
-      if (is_linux) {
-        sources += [
-          "pdfium/pdfium_font_linux.cc",
-          "pdfium/pdfium_font_linux.h",
-        ]
-      }
     }
   }
 
+  source_set("assert_enums") {
+    visibility = [ ":*" ]
+
+    sources = [ "pdfium/pdfium_assert_matching_enums.cc" ]
+
+    configs += [ ":pdf_common_config" ]
+
+    deps = [
+      ":internal",
+      ":pdf",
+      "//ppapi/c",
+      "//third_party/pdfium",
+      "//ui/base",
+    ]
+  }
+
   component("pdf_ppapi") {
     sources = [ "pdf_ppapi.cc" ]
 
@@ -154,6 +163,7 @@
     public = [ "pdf_ppapi.h" ]
 
     deps = [
+      ":internal",
       ":pdf",
       "//base",
       "//ppapi/cpp:objects",
@@ -190,7 +200,7 @@
     configs += [ "//build/config/compiler:noshadowing" ]
 
     deps = [
-      ":pdf",
+      ":internal",
       "//base",
       "//ppapi/cpp:objects",
       "//testing/gtest",
@@ -209,54 +219,51 @@
       "out_of_process_instance_unittest.cc",
       "page_orientation_unittest.cc",
       "pdf_transform_unittest.cc",
+      "pdfium/accessibility_unittest.cc",
+      "pdfium/findtext_unittest.cc",
+      "pdfium/pdfium_engine_exports_unittest.cc",
+      "pdfium/pdfium_engine_unittest.cc",
+      "pdfium/pdfium_form_filler_unittest.cc",
+      "pdfium/pdfium_page_unittest.cc",
+      "pdfium/pdfium_permissions_unittest.cc",
+      "pdfium/pdfium_print_unittest.cc",
+      "pdfium/pdfium_test_base.cc",
+      "pdfium/pdfium_test_base.h",
+      "ppapi_migration/geometry_conversions_unittest.cc",
       "range_set_unittest.cc",
     ]
 
-    configs += [ ":pdf_common_config" ]
+    configs += [
+      ":pdf_common_config",
+      "//v8:external_startup_data",
+    ]
 
     data = [ "test/data/" ]
 
     deps = [
+      ":assert_enums",
       ":features",
+      ":internal",
       ":pdf",
       ":pdf_test_utils",
       "//base",
       "//base/test:run_all_unittests",
       "//base/test:test_support",
+      "//gin",
       "//ppapi/c",
       "//ppapi/cpp:objects",
       "//printing",
       "//skia",
       "//testing/gmock",
       "//testing/gtest",
+      "//third_party/pdfium",
+      "//ui/gfx:test_support",
       "//ui/gfx/geometry",
       "//ui/gfx/range",
     ]
 
-    if (pdf_engine == 0) {
-      sources += [
-        "pdfium/accessibility_unittest.cc",
-        "pdfium/findtext_unittest.cc",
-        "pdfium/pdfium_engine_exports_unittest.cc",
-        "pdfium/pdfium_engine_unittest.cc",
-        "pdfium/pdfium_form_filler_unittest.cc",
-        "pdfium/pdfium_page_unittest.cc",
-        "pdfium/pdfium_permissions_unittest.cc",
-        "pdfium/pdfium_print_unittest.cc",
-        "pdfium/pdfium_test_base.cc",
-        "pdfium/pdfium_test_base.h",
-      ]
-
-      configs += [ "//v8:external_startup_data" ]
-
-      deps += [
-        "//gin",
-        "//third_party/pdfium",
-      ]
-
-      if (v8_use_external_startup_data) {
-        data += [ "$root_out_dir/snapshot_blob.bin" ]
-      }
+    if (v8_use_external_startup_data) {
+      data += [ "$root_out_dir/snapshot_blob.bin" ]
     }
   }
 } else {
diff --git a/pdf/ppapi_migration/geometry_conversions.cc b/pdf/ppapi_migration/geometry_conversions.cc
index bb7719e..516c5039 100644
--- a/pdf/ppapi_migration/geometry_conversions.cc
+++ b/pdf/ppapi_migration/geometry_conversions.cc
@@ -13,21 +13,29 @@
 
 namespace chrome_pdf {
 
+gfx::Point PointFromPPPoint(const PP_Point& pp_point) {
+  return gfx::Point(pp_point.x, pp_point.y);
+}
+
+PP_Point PPPointFromPoint(const gfx::Point& point) {
+  return PP_MakePoint(point.x(), point.y());
+}
+
 gfx::Rect RectFromPPRect(const PP_Rect& pp_rect) {
   return gfx::Rect(pp_rect.point.x, pp_rect.point.y, pp_rect.size.width,
                    pp_rect.size.height);
 }
 
+PP_Rect PPRectFromRect(const gfx::Rect& rect) {
+  return PP_MakeRectFromXYWH(rect.x(), rect.y(), rect.width(), rect.height());
+}
+
 gfx::Size SizeFromPPSize(const PP_Size& pp_size) {
   return gfx::Size(pp_size.width, pp_size.height);
 }
 
-gfx::Point PointFromPPPoint(const PP_Point& pp_point) {
-  return gfx::Point(pp_point.x, pp_point.y);
-}
-
-PP_Point PPPointFromPoint(const gfx::Point& point) {
-  return {point.x(), point.y()};
+PP_Size PPSizeFromSize(const gfx::Size& size) {
+  return PP_MakeSize(size.width(), size.height());
 }
 
 }  // namespace chrome_pdf
diff --git a/pdf/ppapi_migration/geometry_conversions.h b/pdf/ppapi_migration/geometry_conversions.h
index 5133485..9783f78 100644
--- a/pdf/ppapi_migration/geometry_conversions.h
+++ b/pdf/ppapi_migration/geometry_conversions.h
@@ -17,11 +17,15 @@
 
 namespace chrome_pdf {
 
-gfx::Rect RectFromPPRect(const PP_Rect& pp_rect);
-gfx::Size SizeFromPPSize(const PP_Size& pp_size);
 gfx::Point PointFromPPPoint(const PP_Point& pp_point);
 PP_Point PPPointFromPoint(const gfx::Point& point);
 
+gfx::Rect RectFromPPRect(const PP_Rect& pp_rect);
+PP_Rect PPRectFromRect(const gfx::Rect& rect);
+
+gfx::Size SizeFromPPSize(const PP_Size& pp_size);
+PP_Size PPSizeFromSize(const gfx::Size& size);
+
 }  // namespace chrome_pdf
 
 #endif  // PDF_PPAPI_MIGRATION_GEOMETRY_CONVERSIONS_H_
diff --git a/pdf/ppapi_migration/geometry_conversions_unittest.cc b/pdf/ppapi_migration/geometry_conversions_unittest.cc
new file mode 100644
index 0000000..93e068d4
--- /dev/null
+++ b/pdf/ppapi_migration/geometry_conversions_unittest.cc
@@ -0,0 +1,78 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "pdf/ppapi_migration/geometry_conversions.h"
+
+#include "ppapi/c/pp_point.h"
+#include "ppapi/c/pp_rect.h"
+#include "ppapi/c/pp_size.h"
+#include "ppapi/cpp/point.h"
+#include "ppapi/cpp/rect.h"
+#include "ppapi/cpp/size.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace chrome_pdf {
+
+TEST(GeometryConversionsTest, PointFromPPPoint) {
+  gfx::Point point = PointFromPPPoint(pp::Point(-1, 2));
+  EXPECT_EQ(point, gfx::Point(-1, 2));
+
+  point = PointFromPPPoint(PP_MakePoint(2, -1));
+  EXPECT_EQ(point, gfx::Point(2, -1));
+}
+
+TEST(GeometryConversionsTest, PPPointFromPoint) {
+  pp::Point pp_cpp_point = PPPointFromPoint(gfx::Point(-1, 2));
+  EXPECT_EQ(pp_cpp_point.x(), -1);
+  EXPECT_EQ(pp_cpp_point.y(), 2);
+
+  PP_Point pp_c_point = PPPointFromPoint(gfx::Point(2, -1));
+  EXPECT_EQ(pp_c_point.x, 2);
+  EXPECT_EQ(pp_c_point.y, -1);
+}
+
+TEST(GeometryConversionsTest, RectFromPPRect) {
+  gfx::Rect rect = RectFromPPRect(pp::Rect(-1, 2, 3, 4));
+  EXPECT_EQ(rect, gfx::Rect(-1, 2, 3, 4));
+
+  rect = RectFromPPRect(PP_MakeRectFromXYWH(2, -1, 4, 3));
+  EXPECT_EQ(rect, gfx::Rect(2, -1, 4, 3));
+}
+
+TEST(GeometryConversionsTest, PPRectFromRect) {
+  pp::Rect pp_cpp_rect = PPRectFromRect(gfx::Rect(-1, 2, 3, 4));
+  EXPECT_EQ(pp_cpp_rect.x(), -1);
+  EXPECT_EQ(pp_cpp_rect.y(), 2);
+  EXPECT_EQ(pp_cpp_rect.width(), 3);
+  EXPECT_EQ(pp_cpp_rect.height(), 4);
+
+  PP_Rect pp_c_rect = PPRectFromRect(gfx::Rect(2, -1, 4, 3));
+  EXPECT_EQ(pp_c_rect.point.x, 2);
+  EXPECT_EQ(pp_c_rect.point.y, -1);
+  EXPECT_EQ(pp_c_rect.size.width, 4);
+  EXPECT_EQ(pp_c_rect.size.height, 3);
+}
+
+TEST(GeometryConversionsTest, SizeFromPPSize) {
+  gfx::Size size = SizeFromPPSize(pp::Size(3, 4));
+  EXPECT_EQ(size, gfx::Size(3, 4));
+
+  size = SizeFromPPSize(PP_MakeSize(4, 3));
+  EXPECT_EQ(size, gfx::Size(4, 3));
+}
+
+TEST(GeometryConversionsTest, PPSizeFromSize) {
+  pp::Size pp_cpp_size = PPSizeFromSize(gfx::Size(3, 4));
+  EXPECT_EQ(pp_cpp_size.width(), 3);
+  EXPECT_EQ(pp_cpp_size.height(), 4);
+
+  PP_Size pp_c_size = PPSizeFromSize(gfx::Size(4, 3));
+  EXPECT_EQ(pp_c_size.width, 4);
+  EXPECT_EQ(pp_c_size.height, 3);
+}
+
+}  // namespace chrome_pdf
diff --git a/printing/print_settings.cc b/printing/print_settings.cc
index 62ba8b1..a3b8bb9 100644
--- a/printing/print_settings.cc
+++ b/printing/print_settings.cc
@@ -10,6 +10,10 @@
 #include "printing/print_job_constants.h"
 #include "printing/units.h"
 
+#if defined(USE_CUPS) && (defined(OS_MACOSX) || defined(OS_CHROMEOS))
+#include <cups/cups.h>
+#endif
+
 namespace printing {
 
 namespace {
@@ -183,6 +187,23 @@
   // The default case is excluded from the above switch statement to ensure that
   // all ColorModel values are determinantly handled.
 }
+
+#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
+std::string GetIppColorModelForMode(int color_mode) {
+  // Accept |UNKNOWN_COLOR_MODEL| for consistency with GetColorModelForMode().
+  if (color_mode == UNKNOWN_COLOR_MODEL)
+    return CUPS_PRINT_COLOR_MODE_MONOCHROME;
+
+  base::Optional<bool> is_color = IsColorModelSelected(color_mode);
+  if (!is_color.has_value()) {
+    NOTREACHED();
+    return std::string();
+  }
+
+  return is_color.value() ? CUPS_PRINT_COLOR_MODE_COLOR
+                          : CUPS_PRINT_COLOR_MODE_MONOCHROME;
+}
+#endif  // defined(OS_MACOSX) || defined(OS_CHROMEOS)
 #endif  // defined(USE_CUPS)
 
 base::Optional<bool> IsColorModelSelected(int color_mode) {
diff --git a/printing/print_settings.h b/printing/print_settings.h
index 24500a6..c701c641 100644
--- a/printing/print_settings.h
+++ b/printing/print_settings.h
@@ -37,7 +37,12 @@
 PRINTING_EXPORT void GetColorModelForMode(int color_mode,
                                           std::string* color_setting_name,
                                           std::string* color_value);
+
+#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
+// Convert from |color_mode| to a print-color-mode value from PWG 5100.13.
+PRINTING_EXPORT std::string GetIppColorModelForMode(int color_mode);
 #endif
+#endif  // defined(USE_CUPS)
 
 // Inform the printing system that it may embed this user-agent string
 // in its output's metadata.
diff --git a/printing/print_settings_unittest.cc b/printing/print_settings_unittest.cc
index 0c7db4a..44a4625 100644
--- a/printing/print_settings_unittest.cc
+++ b/printing/print_settings_unittest.cc
@@ -5,6 +5,7 @@
 #include "printing/print_settings.h"
 
 #include "base/test/gtest_util.h"
+#include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace printing {
@@ -43,6 +44,19 @@
   EXPECT_DCHECK_DEATH(GetColorModelForMode(COLOR_MODEL_LAST + 1,
                                            &color_setting_name, &color_value));
 }
+
+#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
+TEST(PrintSettingsTest, GetIppColorModelForMode) {
+  for (int model = UNKNOWN_COLOR_MODEL; model <= COLOR_MODEL_LAST; ++model)
+    EXPECT_FALSE(GetIppColorModelForMode(model).empty());
+}
+
+TEST(PrintSettingsDeathTest, GetIppColorModelForModeEdges) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  EXPECT_DCHECK_DEATH(GetIppColorModelForMode(UNKNOWN_COLOR_MODEL - 1));
+  EXPECT_DCHECK_DEATH(GetIppColorModelForMode(COLOR_MODEL_LAST + 1));
+}
+#endif  // defined(OS_MACOSX) || defined(OS_CHROMEOS)
 #endif  // defined(USE_CUPS)
 
 }  // namespace printing
diff --git a/printing/printing_context_chromeos.cc b/printing/printing_context_chromeos.cc
index 3d52830..385f52fd 100644
--- a/printing/printing_context_chromeos.cc
+++ b/printing/printing_context_chromeos.cc
@@ -36,20 +36,6 @@
 
 namespace {
 
-// Convert from a ColorMode setting to a print-color-mode value from PWG 5100.13
-const char* GetColorModelForMode(int color_mode) {
-  const char* mode_string;
-  base::Optional<bool> is_color = IsColorModelSelected(color_mode);
-  if (is_color.has_value()) {
-    mode_string = is_color.value() ? CUPS_PRINT_COLOR_MODE_COLOR
-                                   : CUPS_PRINT_COLOR_MODE_MONOCHROME;
-  } else {
-    mode_string = nullptr;
-  }
-
-  return mode_string;
-}
-
 // Returns a new char buffer which is a null-terminated copy of |value|.  The
 // caller owns the returned string.
 char* DuplicateString(const base::StringPiece value) {
@@ -138,7 +124,7 @@
   std::vector<ScopedCupsOption> options;
   options.push_back(
       ConstructOption(kIppColor,
-                      GetColorModelForMode(settings.color())));  // color
+                      GetIppColorModelForMode(settings.color())));  // color
   options.push_back(ConstructOption(kIppDuplex, sides));         // duplexing
   options.push_back(
       ConstructOption(kIppMedia,
diff --git a/printing/printing_context_mac.mm b/printing/printing_context_mac.mm
index 9343860..56bcfbe6 100644
--- a/printing/printing_context_mac.mm
+++ b/printing/printing_context_mac.mm
@@ -6,6 +6,7 @@
 
 #import <AppKit/AppKit.h>
 #import <QuartzCore/QuartzCore.h>
+#include <cups/cups.h>
 
 #import <iomanip>
 #import <numeric>
@@ -16,6 +17,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "printing/print_settings_initializer_mac.h"
+#include "printing/printing_features.h"
 #include "printing/units.h"
 
 namespace printing {
@@ -389,7 +391,12 @@
       static_cast<PMPrintSettings>([print_info_.get() PMPrintSettings]);
   std::string color_setting_name;
   std::string color_value;
-  GetColorModelForMode(color_mode, &color_setting_name, &color_value);
+  if (base::FeatureList::IsEnabled(features::kCupsIppPrintingBackend)) {
+    color_setting_name = CUPS_PRINT_COLOR_MODE;
+    color_value = GetIppColorModelForMode(color_mode);
+  } else {
+    GetColorModelForMode(color_mode, &color_setting_name, &color_value);
+  }
   base::ScopedCFTypeRef<CFStringRef> color_setting(
       base::SysUTF8ToCFStringRef(color_setting_name));
   base::ScopedCFTypeRef<CFStringRef> output_color(
diff --git a/services/device/public/cpp/test/fake_serial_port_manager.cc b/services/device/public/cpp/test/fake_serial_port_manager.cc
index 10b64bc..d943da5 100644
--- a/services/device/public/cpp/test/fake_serial_port_manager.cc
+++ b/services/device/public/cpp/test/fake_serial_port_manager.cc
@@ -47,7 +47,12 @@
     out_stream_ = std::move(producer);
   }
 
-  void Flush(FlushCallback callback) override { NOTREACHED(); }
+  void Flush(device::mojom::SerialPortFlushMode mode,
+             FlushCallback callback) override {
+    NOTREACHED();
+  }
+
+  void Drain(DrainCallback callback) override { NOTREACHED(); }
 
   void GetControlSignals(GetControlSignalsCallback callback) override {
     NOTREACHED();
diff --git a/services/device/public/mojom/serial.mojom b/services/device/public/mojom/serial.mojom
index b24628c5..7bcb679 100644
--- a/services/device/public/mojom/serial.mojom
+++ b/services/device/public/mojom/serial.mojom
@@ -66,6 +66,20 @@
   TWO,
 };
 
+enum SerialPortFlushMode {
+  // Flushes both receive and transmit buffers without discarding any bytes in
+  // the data pipes. This is for compatibility with chrome.serial.flush().
+  kReceiveAndTransmit,
+
+  // Flushes the receive buffers and discards data in the data_pipe_producer by
+  // closing it.
+  kReceive,
+
+  // Flushes the send buffers and discards data in the data_pipe_consumer by
+  // closing it.
+  kTransmit,
+};
+
 struct SerialConnectionOptions {
   uint32 bitrate = 0;
   SerialDataBits data_bits = NONE;
@@ -146,8 +160,12 @@
   // called on |client| to indicate an error.
   StartReading(handle<data_pipe_producer> producer);
 
-  // Flushes input and output buffers.
-  Flush() => (bool success);
+  // Flushes buffers according to the selected |mode|.
+  Flush(SerialPortFlushMode mode) => ();
+
+  // Waits for the data_pipe_consumer passed to StartWriting() to be closed and
+  // all buffered data to be transmitted by the port.
+  Drain() => ();
 
   // Reads current control signals (DCD, CTS, etc.).
   GetControlSignals() => (SerialPortControlSignals signals);
diff --git a/services/device/serial/serial_io_handler.h b/services/device/serial/serial_io_handler.h
index b70906f..cd49076 100644
--- a/services/device/serial/serial_io_handler.h
+++ b/services/device/serial/serial_io_handler.h
@@ -80,7 +80,10 @@
   void CancelWrite(mojom::SerialSendError reason);
 
   // Flushes input and output buffers.
-  virtual bool Flush() const = 0;
+  virtual void Flush(mojom::SerialPortFlushMode mode) const = 0;
+
+  // Drains output buffers.
+  virtual void Drain() = 0;
 
   // Reads current control signals (DCD, CTS, etc.) into an existing
   // DeviceControlSignals structure. Returns |true| iff the signals were
diff --git a/services/device/serial/serial_io_handler_posix.cc b/services/device/serial/serial_io_handler_posix.cc
index 452d8153..640da81 100644
--- a/services/device/serial/serial_io_handler_posix.cc
+++ b/services/device/serial/serial_io_handler_posix.cc
@@ -428,12 +428,27 @@
   }
 }
 
-bool SerialIoHandlerPosix::Flush() const {
-  if (tcflush(file().GetPlatformFile(), TCIOFLUSH) != 0) {
-    VPLOG(1) << "Failed to flush port";
-    return false;
+void SerialIoHandlerPosix::Flush(mojom::SerialPortFlushMode mode) const {
+  int queue_selector;
+  switch (mode) {
+    case mojom::SerialPortFlushMode::kReceiveAndTransmit:
+      queue_selector = TCIOFLUSH;
+      break;
+    case mojom::SerialPortFlushMode::kReceive:
+      queue_selector = TCIFLUSH;
+      break;
+    case mojom::SerialPortFlushMode::kTransmit:
+      queue_selector = TCOFLUSH;
+      break;
   }
-  return true;
+
+  if (tcflush(file().GetPlatformFile(), queue_selector) != 0)
+    VPLOG(1) << "Failed to flush port";
+}
+
+void SerialIoHandlerPosix::Drain() {
+  if (tcdrain(file().GetPlatformFile()) != 0)
+    VPLOG(1) << "Failed to drain port";
 }
 
 mojom::SerialPortControlSignalsPtr SerialIoHandlerPosix::GetControlSignals()
diff --git a/services/device/serial/serial_io_handler_posix.h b/services/device/serial/serial_io_handler_posix.h
index 3d69c6d0..51311d6 100644
--- a/services/device/serial/serial_io_handler_posix.h
+++ b/services/device/serial/serial_io_handler_posix.h
@@ -31,7 +31,8 @@
   bool ConfigurePortImpl() override;
   bool PostOpen() override;
   void PreClose() override;
-  bool Flush() const override;
+  void Flush(mojom::SerialPortFlushMode mode) const override;
+  void Drain() override;
   mojom::SerialPortControlSignalsPtr GetControlSignals() const override;
   bool SetControlSignals(
       const mojom::SerialHostControlSignals& control_signals) override;
diff --git a/services/device/serial/serial_io_handler_win.cc b/services/device/serial/serial_io_handler_win.cc
index 9b273f8..808ad11 100644
--- a/services/device/serial/serial_io_handler_win.cc
+++ b/services/device/serial/serial_io_handler_win.cc
@@ -268,6 +268,11 @@
   DCHECK(pending_read_buffer());
   DCHECK(file().IsValid());
 
+  if (is_comm_pending_) {
+    // Reuse the call to WaitCommEvent() from a canceled read.
+    return;
+  }
+
   if (!SetCommMask(file().GetPlatformFile(), EV_RXCHAR)) {
     VPLOG(1) << "Failed to set serial event flags";
   }
@@ -299,13 +304,23 @@
 void SerialIoHandlerWin::CancelReadImpl() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(file().IsValid());
-  ::CancelIo(file().GetPlatformFile());
+
+  if (is_comm_pending_) {
+    // Clearing the event mask will cause an overlapped call to WaitCommEvent()
+    // to complete immediately.
+    if (!SetCommMask(file().GetPlatformFile(), 0))
+      VPLOG(1) << "Failed to clear event mask";
+  } else {
+    if (!PurgeComm(file().GetPlatformFile(), PURGE_RXABORT))
+      VPLOG(1) << "RX abort failed";
+  }
 }
 
 void SerialIoHandlerWin::CancelWriteImpl() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(file().IsValid());
-  ::CancelIo(file().GetPlatformFile());
+  if (!PurgeComm(file().GetPlatformFile(), PURGE_TXABORT))
+    VPLOG(1) << "TX abort failed";
 }
 
 bool SerialIoHandlerWin::ConfigurePortImpl() {
@@ -370,6 +385,8 @@
     DWORD error) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (context == comm_context_.get()) {
+    is_comm_pending_ = false;
+
     DWORD errors;
     if (!ClearCommError(file().GetPlatformFile(), &errors, nullptr)) {
       VPLOG(1) << "Failed to clear communication error";
@@ -446,12 +463,27 @@
   }
 }
 
-bool SerialIoHandlerWin::Flush() const {
-  if (!PurgeComm(file().GetPlatformFile(), PURGE_RXCLEAR | PURGE_TXCLEAR)) {
-    VPLOG(1) << "Failed to flush serial port";
-    return false;
+void SerialIoHandlerWin::Flush(mojom::SerialPortFlushMode mode) const {
+  DWORD flags;
+  switch (mode) {
+    case mojom::SerialPortFlushMode::kReceiveAndTransmit:
+      flags = PURGE_RXCLEAR | PURGE_TXCLEAR;
+      break;
+    case mojom::SerialPortFlushMode::kReceive:
+      flags = PURGE_RXCLEAR;
+      break;
+    case mojom::SerialPortFlushMode::kTransmit:
+      flags = PURGE_TXCLEAR;
+      break;
   }
-  return true;
+
+  if (!PurgeComm(file().GetPlatformFile(), flags))
+    VPLOG(1) << "Failed to flush serial port";
+}
+
+void SerialIoHandlerWin::Drain() {
+  if (!FlushFileBuffers(file().GetPlatformFile()))
+    VPLOG(1) << "Failed to drain serial port";
 }
 
 mojom::SerialPortControlSignalsPtr SerialIoHandlerWin::GetControlSignals()
diff --git a/services/device/serial/serial_io_handler_win.h b/services/device/serial/serial_io_handler_win.h
index 9c25e8b..979aa7b 100644
--- a/services/device/serial/serial_io_handler_win.h
+++ b/services/device/serial/serial_io_handler_win.h
@@ -26,7 +26,8 @@
   void CancelReadImpl() override;
   void CancelWriteImpl() override;
   bool ConfigurePortImpl() override;
-  bool Flush() const override;
+  void Flush(mojom::SerialPortFlushMode mode) const override;
+  void Drain() override;
   mojom::SerialPortControlSignalsPtr GetControlSignals() const override;
   bool SetControlSignals(
       const mojom::SerialHostControlSignals& control_signals) override;
diff --git a/services/device/serial/serial_port_impl.cc b/services/device/serial/serial_port_impl.cc
index 245f812..01058c9 100644
--- a/services/device/serial/serial_port_impl.cc
+++ b/services/device/serial/serial_port_impl.cc
@@ -22,17 +22,27 @@
     mojo::PendingRemote<mojom::SerialPortConnectionWatcher> watcher,
     scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) {
   // This SerialPortImpl is owned by |receiver| and |watcher|.
-  new SerialPortImpl(path, std::move(receiver), std::move(watcher),
-                     std::move(ui_task_runner));
+  new SerialPortImpl(
+      device::SerialIoHandler::Create(path, std::move(ui_task_runner)),
+      std::move(receiver), std::move(watcher));
+}
+
+// static
+void SerialPortImpl::CreateForTesting(
+    scoped_refptr<SerialIoHandler> io_handler,
+    mojo::PendingReceiver<mojom::SerialPort> receiver,
+    mojo::PendingRemote<mojom::SerialPortConnectionWatcher> watcher) {
+  // This SerialPortImpl is owned by |receiver| and |watcher|.
+  new SerialPortImpl(std::move(io_handler), std::move(receiver),
+                     std::move(watcher));
 }
 
 SerialPortImpl::SerialPortImpl(
-    const base::FilePath& path,
+    scoped_refptr<SerialIoHandler> io_handler,
     mojo::PendingReceiver<mojom::SerialPort> receiver,
-    mojo::PendingRemote<mojom::SerialPortConnectionWatcher> watcher,
-    scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
+    mojo::PendingRemote<mojom::SerialPortConnectionWatcher> watcher)
     : receiver_(this, std::move(receiver)),
-      io_handler_(device::SerialIoHandler::Create(path, ui_task_runner)),
+      io_handler_(std::move(io_handler)),
       watcher_(std::move(watcher)),
       in_stream_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL),
       out_stream_watcher_(FROM_HERE,
@@ -93,8 +103,62 @@
   out_stream_watcher_.ArmOrNotify();
 }
 
-void SerialPortImpl::Flush(FlushCallback callback) {
-  std::move(callback).Run(io_handler_->Flush());
+void SerialPortImpl::Flush(mojom::SerialPortFlushMode mode,
+                           FlushCallback callback) {
+  switch (mode) {
+    case mojom::SerialPortFlushMode::kReceiveAndTransmit:
+      // Do nothing. This case exists to support the chrome.serial.flush()
+      // method.
+      break;
+    case mojom::SerialPortFlushMode::kReceive:
+      io_handler_->CancelRead(mojom::SerialReceiveError::NONE);
+      break;
+    case mojom::SerialPortFlushMode::kTransmit:
+      io_handler_->CancelWrite(mojom::SerialSendError::NONE);
+      break;
+  }
+
+  io_handler_->Flush(mode);
+
+  switch (mode) {
+    case mojom::SerialPortFlushMode::kReceiveAndTransmit:
+      // Do nothing. This case exists to support the chrome.serial.flush()
+      // method.
+      break;
+    case mojom::SerialPortFlushMode::kReceive:
+      if (io_handler_->IsReadPending()) {
+        // Delay closing |out_stream_| because |io_handler_| still holds a
+        // pointer into the shared memory owned by the pipe.
+        read_flush_callback_ = std::move(callback);
+        return;
+      }
+
+      out_stream_watcher_.Cancel();
+      out_stream_.reset();
+      break;
+    case mojom::SerialPortFlushMode::kTransmit:
+      if (io_handler_->IsWritePending()) {
+        // Delay closing |in_stream_| because |io_handler_| still holds a
+        // pointer into the shared memory owned by the pipe.
+        write_flush_callback_ = std::move(callback);
+        return;
+      }
+
+      in_stream_watcher_.Cancel();
+      in_stream_.reset();
+      break;
+  }
+
+  std::move(callback).Run();
+}
+
+void SerialPortImpl::Drain(DrainCallback callback) {
+  if (!in_stream_) {
+    std::move(callback).Run();
+    return;
+  }
+
+  drain_callback_ = std::move(callback);
 }
 
 void SerialPortImpl::GetControlSignals(GetControlSignalsCallback callback) {
@@ -149,6 +213,11 @@
     // The |in_stream_| has been closed.
     in_stream_watcher_.Cancel();
     in_stream_.reset();
+
+    if (drain_callback_) {
+      io_handler_->Drain();
+      std::move(drain_callback_).Run();
+    }
     return;
   }
   // The code should not reach other cases.
@@ -203,7 +272,7 @@
     return;
   }
   // The code should not reach other cases.
-  NOTREACHED();
+  NOTREACHED() << "Unexpected Mojo result: " << result;
 }
 
 void SerialPortImpl::WriteToOutStream(uint32_t bytes_read,
@@ -214,11 +283,20 @@
   if (error != mojom::SerialReceiveError::NONE) {
     out_stream_watcher_.Cancel();
     out_stream_.reset();
-    if (client_) {
+    if (client_)
       client_->OnReadError(error);
-    }
+    if (read_flush_callback_)
+      std::move(read_flush_callback_).Run();
     return;
   }
+
+  if (read_flush_callback_) {
+    std::move(read_flush_callback_).Run();
+    out_stream_watcher_.Cancel();
+    out_stream_.reset();
+    return;
+  }
+
   out_stream_watcher_.ArmOrNotify();
 }
 
diff --git a/services/device/serial/serial_port_impl.h b/services/device/serial/serial_port_impl.h
index 2ba5d31d..1757a55 100644
--- a/services/device/serial/serial_port_impl.h
+++ b/services/device/serial/serial_port_impl.h
@@ -39,12 +39,16 @@
       mojo::PendingRemote<mojom::SerialPortConnectionWatcher> watcher,
       scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
 
+  static void CreateForTesting(
+      scoped_refptr<SerialIoHandler> io_handler,
+      mojo::PendingReceiver<mojom::SerialPort> receiver,
+      mojo::PendingRemote<mojom::SerialPortConnectionWatcher> watcher);
+
  private:
   SerialPortImpl(
-      const base::FilePath& path,
+      scoped_refptr<SerialIoHandler> io_handler,
       mojo::PendingReceiver<mojom::SerialPort> receiver,
-      mojo::PendingRemote<mojom::SerialPortConnectionWatcher> watcher,
-      scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
+      mojo::PendingRemote<mojom::SerialPortConnectionWatcher> watcher);
   ~SerialPortImpl() override;
 
   // mojom::SerialPort methods:
@@ -53,7 +57,8 @@
             OpenCallback callback) override;
   void StartWriting(mojo::ScopedDataPipeConsumerHandle consumer) override;
   void StartReading(mojo::ScopedDataPipeProducerHandle producer) override;
-  void Flush(FlushCallback callback) override;
+  void Flush(mojom::SerialPortFlushMode mode, FlushCallback callback) override;
+  void Drain(DrainCallback callback) override;
   void GetControlSignals(GetControlSignalsCallback callback) override;
   void SetControlSignals(mojom::SerialHostControlSignalsPtr signals,
                          SetControlSignalsCallback callback) override;
@@ -85,6 +90,12 @@
   mojo::ScopedDataPipeProducerHandle out_stream_;
   mojo::SimpleWatcher out_stream_watcher_;
 
+  // Holds the callback for a flush or drain until pending operations have been
+  // completed.
+  FlushCallback read_flush_callback_;
+  FlushCallback write_flush_callback_;
+  DrainCallback drain_callback_;
+
   base::WeakPtrFactory<SerialPortImpl> weak_factory_{this};
   DISALLOW_COPY_AND_ASSIGN(SerialPortImpl);
 };
diff --git a/services/device/serial/serial_port_impl_unittest.cc b/services/device/serial/serial_port_impl_unittest.cc
index 3618b88e..f2e0d33 100644
--- a/services/device/serial/serial_port_impl_unittest.cc
+++ b/services/device/serial/serial_port_impl_unittest.cc
@@ -4,74 +4,214 @@
 
 #include "services/device/serial/serial_port_impl.h"
 
-#include "base/macros.h"
+#include "base/test/bind_test_util.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
+#include "mojo/public/cpp/system/data_pipe.h"
+#include "mojo/public/cpp/system/simple_watcher.h"
 #include "services/device/device_service_test_base.h"
 #include "services/device/public/mojom/serial.mojom.h"
+#include "services/device/serial/serial_io_handler.h"
 
 namespace device {
 
 namespace {
 
+class FakeSerialIoHandler : public SerialIoHandler {
+ public:
+  FakeSerialIoHandler()
+      : SerialIoHandler(base::FilePath(), /*ui_thread_task_runner=*/nullptr) {}
+
+  void Open(const mojom::SerialConnectionOptions& options,
+            OpenCompleteCallback callback) override {
+    std::move(callback).Run(true);
+  }
+
+  void Flush(mojom::SerialPortFlushMode mode) const override {}
+  void Drain() override {}
+
+  mojom::SerialPortControlSignalsPtr GetControlSignals() const override {
+    return mojom::SerialPortControlSignals::New();
+  }
+
+  bool SetControlSignals(
+      const mojom::SerialHostControlSignals& control_signals) override {
+    return true;
+  }
+
+  mojom::SerialConnectionInfoPtr GetPortInfo() const override {
+    return mojom::SerialConnectionInfo::New();
+  }
+
+  void ReadImpl() override {}
+
+  void WriteImpl() override {}
+
+  void CancelReadImpl() override {
+    QueueReadCompleted(/*bytes_read=*/0, mojom::SerialReceiveError::NONE);
+  }
+
+  void CancelWriteImpl() override {
+    QueueWriteCompleted(/*bytes_written=*/0, mojom::SerialSendError::NONE);
+  }
+
+  bool ConfigurePortImpl() override { return true; }
+
+ private:
+  ~FakeSerialIoHandler() override = default;
+};
+
+}  // namespace
+
 class SerialPortImplTest : public DeviceServiceTestBase {
  public:
   SerialPortImplTest() = default;
+  SerialPortImplTest(const SerialPortImplTest& other) = delete;
+  void operator=(const SerialPortImplTest& other) = delete;
   ~SerialPortImplTest() override = default;
 
- protected:
-  DISALLOW_COPY_AND_ASSIGN(SerialPortImplTest);
+  void CreatePort(
+      mojo::Remote<mojom::SerialPort>* port,
+      mojo::SelfOwnedReceiverRef<mojom::SerialPortConnectionWatcher>* watcher) {
+    mojo::PendingRemote<mojom::SerialPortConnectionWatcher> watcher_remote;
+    *watcher = mojo::MakeSelfOwnedReceiver(
+        std::make_unique<mojom::SerialPortConnectionWatcher>(),
+        watcher_remote.InitWithNewPipeAndPassReceiver());
+    SerialPortImpl::CreateForTesting(
+        base::MakeRefCounted<FakeSerialIoHandler>(),
+        port->BindNewPipeAndPassReceiver(), std::move(watcher_remote));
+  }
+
+  void CreateDataPipe(mojo::ScopedDataPipeProducerHandle* producer,
+                      mojo::ScopedDataPipeConsumerHandle* consumer) {
+    MojoCreateDataPipeOptions options;
+    options.struct_size = sizeof(MojoCreateDataPipeOptions);
+    options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE;
+    options.element_num_bytes = 1;
+    options.capacity_num_bytes = 64;
+
+    MojoResult result = mojo::CreateDataPipe(&options, producer, consumer);
+    DCHECK_EQ(result, MOJO_RESULT_OK);
+  }
 };
 
 TEST_F(SerialPortImplTest, WatcherClosedWhenPortClosed) {
   mojo::Remote<mojom::SerialPort> serial_port;
-  mojo::PendingRemote<mojom::SerialPortConnectionWatcher> watcher;
-  auto watcher_receiver = mojo::MakeSelfOwnedReceiver(
-      std::make_unique<mojom::SerialPortConnectionWatcher>(),
-      watcher.InitWithNewPipeAndPassReceiver());
-  SerialPortImpl::Create(
-      base::FilePath(), serial_port.BindNewPipeAndPassReceiver(),
-      std::move(watcher), base::ThreadTaskRunnerHandle::Get());
+  mojo::SelfOwnedReceiverRef<mojom::SerialPortConnectionWatcher> watcher;
+  CreatePort(&serial_port, &watcher);
 
   // To start with both the serial port connection and the connection watcher
   // connection should remain open.
   serial_port.FlushForTesting();
   EXPECT_TRUE(serial_port.is_connected());
-  watcher_receiver->FlushForTesting();
-  EXPECT_TRUE(watcher_receiver);
+  watcher->FlushForTesting();
+  EXPECT_TRUE(watcher);
 
   // When the serial port connection is closed the watcher connection should be
   // closed.
   serial_port.reset();
-  watcher_receiver->FlushForTesting();
-  EXPECT_FALSE(watcher_receiver);
+  watcher->FlushForTesting();
+  EXPECT_FALSE(watcher);
 }
 
 TEST_F(SerialPortImplTest, PortClosedWhenWatcherClosed) {
   mojo::Remote<mojom::SerialPort> serial_port;
-  mojo::PendingRemote<mojom::SerialPortConnectionWatcher> watcher;
-  auto watcher_receiver = mojo::MakeSelfOwnedReceiver(
-      std::make_unique<mojom::SerialPortConnectionWatcher>(),
-      watcher.InitWithNewPipeAndPassReceiver());
-  SerialPortImpl::Create(
-      base::FilePath(), serial_port.BindNewPipeAndPassReceiver(),
-      std::move(watcher), base::ThreadTaskRunnerHandle::Get());
+  mojo::SelfOwnedReceiverRef<mojom::SerialPortConnectionWatcher> watcher;
+  CreatePort(&serial_port, &watcher);
 
   // To start with both the serial port connection and the connection watcher
   // connection should remain open.
   serial_port.FlushForTesting();
   EXPECT_TRUE(serial_port.is_connected());
-  watcher_receiver->FlushForTesting();
-  EXPECT_TRUE(watcher_receiver);
+  watcher->FlushForTesting();
+  EXPECT_TRUE(watcher);
 
   // When the watcher connection is closed, for safety, the serial port
   // connection should also be closed.
-  watcher_receiver->Close();
+  watcher->Close();
   serial_port.FlushForTesting();
   EXPECT_FALSE(serial_port.is_connected());
 }
 
-}  // namespace
+TEST_F(SerialPortImplTest, FlushRead) {
+  mojo::Remote<mojom::SerialPort> serial_port;
+  mojo::SelfOwnedReceiverRef<mojom::SerialPortConnectionWatcher> watcher;
+  CreatePort(&serial_port, &watcher);
+
+  mojo::ScopedDataPipeProducerHandle producer;
+  mojo::ScopedDataPipeConsumerHandle consumer;
+  CreateDataPipe(&producer, &consumer);
+  serial_port->StartReading(std::move(producer));
+
+  // Calling Flush(kReceive) should cause the data pipe to close.
+  base::RunLoop watcher_loop;
+  mojo::SimpleWatcher pipe_watcher(
+      FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC);
+  EXPECT_EQ(pipe_watcher.Watch(consumer.get(), MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+                               MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
+                               base::BindLambdaForTesting(
+                                   [&](MojoResult result,
+                                       const mojo::HandleSignalsState& state) {
+                                     EXPECT_EQ(result, MOJO_RESULT_OK);
+                                     EXPECT_TRUE(state.peer_closed());
+                                     watcher_loop.Quit();
+                                   })),
+            MOJO_RESULT_OK);
+
+  base::RunLoop loop;
+  serial_port->Flush(mojom::SerialPortFlushMode::kReceive, loop.QuitClosure());
+  loop.Run();
+  watcher_loop.Run();
+}
+
+TEST_F(SerialPortImplTest, FlushWrite) {
+  mojo::Remote<mojom::SerialPort> serial_port;
+  mojo::SelfOwnedReceiverRef<mojom::SerialPortConnectionWatcher> watcher;
+  CreatePort(&serial_port, &watcher);
+
+  mojo::ScopedDataPipeProducerHandle producer;
+  mojo::ScopedDataPipeConsumerHandle consumer;
+  CreateDataPipe(&producer, &consumer);
+  serial_port->StartWriting(std::move(consumer));
+
+  // Calling Flush(kTransmit) should cause the data pipe to close.
+  base::RunLoop watcher_loop;
+  mojo::SimpleWatcher pipe_watcher(
+      FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC);
+  EXPECT_EQ(pipe_watcher.Watch(producer.get(), MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+                               MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
+                               base::BindLambdaForTesting(
+                                   [&](MojoResult result,
+                                       const mojo::HandleSignalsState& state) {
+                                     EXPECT_EQ(result, MOJO_RESULT_OK);
+                                     EXPECT_TRUE(state.peer_closed());
+                                     watcher_loop.Quit();
+                                   })),
+            MOJO_RESULT_OK);
+
+  base::RunLoop loop;
+  serial_port->Flush(mojom::SerialPortFlushMode::kTransmit, loop.QuitClosure());
+  loop.Run();
+  watcher_loop.Run();
+}
+
+TEST_F(SerialPortImplTest, Drain) {
+  mojo::Remote<mojom::SerialPort> serial_port;
+  mojo::SelfOwnedReceiverRef<mojom::SerialPortConnectionWatcher> watcher;
+  CreatePort(&serial_port, &watcher);
+
+  mojo::ScopedDataPipeProducerHandle producer;
+  mojo::ScopedDataPipeConsumerHandle consumer;
+  CreateDataPipe(&producer, &consumer);
+  serial_port->StartWriting(std::move(consumer));
+
+  // Drain() will wait for the data pipe to close before replying.
+  producer.reset();
+
+  base::RunLoop loop;
+  serial_port->Drain(loop.QuitClosure());
+  loop.Run();
+}
 
 }  // namespace device
diff --git a/services/network/expect_ct_reporter_unittest.cc b/services/network/expect_ct_reporter_unittest.cc
index 0844929..e2fc979 100644
--- a/services/network/expect_ct_reporter_unittest.cc
+++ b/services/network/expect_ct_reporter_unittest.cc
@@ -48,12 +48,12 @@
       : ReportSender(nullptr, TRAFFIC_ANNOTATION_FOR_TESTS) {}
   ~TestCertificateReportSender() override {}
 
-  void Send(const GURL& report_uri,
-            base::StringPiece content_type,
-            base::StringPiece serialized_report,
-            const base::RepeatingCallback<void()>& success_callback,
-            const base::RepeatingCallback<void(const GURL&, int, int)>&
-                error_callback) override {
+  void Send(
+      const GURL& report_uri,
+      base::StringPiece content_type,
+      base::StringPiece serialized_report,
+      base::OnceCallback<void()> success_callback,
+      base::OnceCallback<void(const GURL&, int, int)> error_callback) override {
     sent_report_count_++;
     latest_report_uri_ = report_uri;
     latest_serialized_report_.assign(serialized_report.data(),
diff --git a/services/network/trust_tokens/trust_token_request_issuance_helper_unittest.cc b/services/network/trust_tokens/trust_token_request_issuance_helper_unittest.cc
index 7799e2a..df04c1c 100644
--- a/services/network/trust_tokens/trust_token_request_issuance_helper_unittest.cc
+++ b/services/network/trust_tokens/trust_token_request_issuance_helper_unittest.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "base/callback.h"
+#include "base/no_destructor.h"
 #include "base/test/task_environment.h"
 #include "net/base/load_flags.h"
 #include "net/base/request_priority.h"
diff --git a/services/network/trust_tokens/trust_token_request_redemption_helper_unittest.cc b/services/network/trust_tokens/trust_token_request_redemption_helper_unittest.cc
index 87661ba..88888c91e 100644
--- a/services/network/trust_tokens/trust_token_request_redemption_helper_unittest.cc
+++ b/services/network/trust_tokens/trust_token_request_redemption_helper_unittest.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "base/callback.h"
+#include "base/no_destructor.h"
 #include "base/test/task_environment.h"
 #include "net/base/load_flags.h"
 #include "net/base/request_priority.h"
diff --git a/services/network/websocket.cc b/services/network/websocket.cc
index dcf9d7cc..160b3ba9 100644
--- a/services/network/websocket.cc
+++ b/services/network/websocket.cc
@@ -11,6 +11,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/command_line.h"
 #include "base/feature_list.h"
 #include "base/location.h"
 #include "base/logging.h"
diff --git a/storage/browser/database/database_quota_client.cc b/storage/browser/database/database_quota_client.cc
index d47179a..e2a6374 100644
--- a/storage/browser/database/database_quota_client.cc
+++ b/storage/browser/database/database_quota_client.cc
@@ -62,13 +62,13 @@
   }
 }
 
-void DidGetQuotaClientOrigins(QuotaClient::GetOriginsCallback callback,
+void DidGetQuotaClientOrigins(QuotaClient::GetOriginsForTypeCallback callback,
                               std::vector<url::Origin>* origins_ptr) {
   std::move(callback).Run(*origins_ptr);
 }
 
 void DidDeleteOriginData(base::SequencedTaskRunner* original_task_runner,
-                         QuotaClient::DeletionCallback callback,
+                         QuotaClient::DeleteOriginDataCallback callback,
                          int result) {
   if (result == net::ERR_IO_PENDING) {
     // The callback will be invoked via
@@ -102,7 +102,7 @@
 
 void DatabaseQuotaClient::GetOriginUsage(const url::Origin& origin,
                                          StorageType type,
-                                         GetUsageCallback callback) {
+                                         GetOriginUsageCallback callback) {
   DCHECK(!callback.is_null());
   DCHECK(db_tracker_.get());
   DCHECK_EQ(type, StorageType::kTemporary);
@@ -114,8 +114,9 @@
       std::move(callback));
 }
 
-void DatabaseQuotaClient::GetOriginsForType(StorageType type,
-                                            GetOriginsCallback callback) {
+void DatabaseQuotaClient::GetOriginsForType(
+    StorageType type,
+    GetOriginsForTypeCallback callback) {
   DCHECK(!callback.is_null());
   DCHECK(db_tracker_.get());
   DCHECK_EQ(type, StorageType::kTemporary);
@@ -129,9 +130,10 @@
                      base::Owned(origins_ptr)));
 }
 
-void DatabaseQuotaClient::GetOriginsForHost(StorageType type,
-                                            const std::string& host,
-                                            GetOriginsCallback callback) {
+void DatabaseQuotaClient::GetOriginsForHost(
+    StorageType type,
+    const std::string& host,
+    GetOriginsForHostCallback callback) {
   DCHECK(!callback.is_null());
   DCHECK(db_tracker_.get());
   DCHECK_EQ(type, StorageType::kTemporary);
@@ -148,7 +150,7 @@
 
 void DatabaseQuotaClient::DeleteOriginData(const url::Origin& origin,
                                            StorageType type,
-                                           DeletionCallback callback) {
+                                           DeleteOriginDataCallback callback) {
   DCHECK(!callback.is_null());
   DCHECK(db_tracker_.get());
   DCHECK_EQ(type, StorageType::kTemporary);
@@ -169,8 +171,9 @@
       net::CompletionOnceCallback(delete_callback));
 }
 
-void DatabaseQuotaClient::PerformStorageCleanup(blink::mojom::StorageType type,
-                                                base::OnceClosure callback) {
+void DatabaseQuotaClient::PerformStorageCleanup(
+    blink::mojom::StorageType type,
+    PerformStorageCleanupCallback callback) {
   DCHECK(!callback.is_null());
   DCHECK_EQ(type, StorageType::kTemporary);
   std::move(callback).Run();
diff --git a/storage/browser/database/database_quota_client.h b/storage/browser/database/database_quota_client.h
index 1a64f08..de235c15 100644
--- a/storage/browser/database/database_quota_client.h
+++ b/storage/browser/database/database_quota_client.h
@@ -33,17 +33,17 @@
   void OnQuotaManagerDestroyed() override;
   void GetOriginUsage(const url::Origin& origin,
                       blink::mojom::StorageType type,
-                      GetUsageCallback callback) override;
+                      GetOriginUsageCallback callback) override;
   void GetOriginsForType(blink::mojom::StorageType type,
-                         GetOriginsCallback callback) override;
+                         GetOriginsForTypeCallback callback) override;
   void GetOriginsForHost(blink::mojom::StorageType type,
                          const std::string& host,
-                         GetOriginsCallback callback) override;
+                         GetOriginsForHostCallback callback) override;
   void DeleteOriginData(const url::Origin& origin,
                         blink::mojom::StorageType type,
-                        DeletionCallback callback) override;
+                        DeleteOriginDataCallback callback) override;
   void PerformStorageCleanup(blink::mojom::StorageType type,
-                             base::OnceClosure callback) override;
+                             PerformStorageCleanupCallback callback) override;
 
  private:
   ~DatabaseQuotaClient() override;
diff --git a/storage/browser/file_system/file_system_quota_client.cc b/storage/browser/file_system/file_system_quota_client.cc
index 790bbab..e9f3f9bf 100644
--- a/storage/browser/file_system/file_system_quota_client.cc
+++ b/storage/browser/file_system/file_system_quota_client.cc
@@ -55,7 +55,7 @@
 }
 
 void DidGetFileSystemQuotaClientOrigins(
-    QuotaClient::GetOriginsCallback callback,
+    QuotaClient::GetOriginsForTypeCallback callback,
     std::vector<url::Origin>* origins_ptr) {
   std::move(callback).Run(*origins_ptr);
 }
@@ -94,7 +94,7 @@
 
 void FileSystemQuotaClient::GetOriginUsage(const url::Origin& origin,
                                            StorageType storage_type,
-                                           GetUsageCallback callback) {
+                                           GetOriginUsageCallback callback) {
   DCHECK(!callback.is_null());
 
   FileSystemType type = QuotaStorageTypeToFileSystemType(storage_type);
@@ -115,8 +115,9 @@
       std::move(callback));
 }
 
-void FileSystemQuotaClient::GetOriginsForType(StorageType storage_type,
-                                              GetOriginsCallback callback) {
+void FileSystemQuotaClient::GetOriginsForType(
+    StorageType storage_type,
+    GetOriginsForTypeCallback callback) {
   DCHECK(!callback.is_null());
 
   auto* origins_ptr = new std::vector<url::Origin>();
@@ -129,9 +130,10 @@
                      base::Owned(origins_ptr)));
 }
 
-void FileSystemQuotaClient::GetOriginsForHost(StorageType storage_type,
-                                              const std::string& host,
-                                              GetOriginsCallback callback) {
+void FileSystemQuotaClient::GetOriginsForHost(
+    StorageType storage_type,
+    const std::string& host,
+    GetOriginsForHostCallback callback) {
   DCHECK(!callback.is_null());
 
   auto* origins_ptr = new std::vector<url::Origin>();
@@ -144,9 +146,10 @@
                      base::Owned(origins_ptr)));
 }
 
-void FileSystemQuotaClient::DeleteOriginData(const url::Origin& origin,
-                                             StorageType type,
-                                             DeletionCallback callback) {
+void FileSystemQuotaClient::DeleteOriginData(
+    const url::Origin& origin,
+    StorageType type,
+    DeleteOriginDataCallback callback) {
   FileSystemType fs_type = QuotaStorageTypeToFileSystemType(type);
   DCHECK(fs_type != kFileSystemTypeUnknown);
 
@@ -157,8 +160,9 @@
       std::move(callback));
 }
 
-void FileSystemQuotaClient::PerformStorageCleanup(StorageType type,
-                                                  base::OnceClosure callback) {
+void FileSystemQuotaClient::PerformStorageCleanup(
+    StorageType type,
+    PerformStorageCleanupCallback callback) {
   FileSystemType fs_type = QuotaStorageTypeToFileSystemType(type);
   DCHECK(fs_type != kFileSystemTypeUnknown);
   file_task_runner()->PostTaskAndReply(
diff --git a/storage/browser/file_system/file_system_quota_client.h b/storage/browser/file_system/file_system_quota_client.h
index 27ddaae..3a4261e 100644
--- a/storage/browser/file_system/file_system_quota_client.h
+++ b/storage/browser/file_system/file_system_quota_client.h
@@ -40,17 +40,17 @@
   void OnQuotaManagerDestroyed() override {}
   void GetOriginUsage(const url::Origin& origin,
                       blink::mojom::StorageType type,
-                      GetUsageCallback callback) override;
+                      GetOriginUsageCallback callback) override;
   void GetOriginsForType(blink::mojom::StorageType type,
-                         GetOriginsCallback callback) override;
+                         GetOriginsForTypeCallback callback) override;
   void GetOriginsForHost(blink::mojom::StorageType type,
                          const std::string& host,
-                         GetOriginsCallback callback) override;
+                         GetOriginsForHostCallback callback) override;
   void DeleteOriginData(const url::Origin& origin,
                         blink::mojom::StorageType type,
-                        DeletionCallback callback) override;
+                        DeleteOriginDataCallback callback) override;
   void PerformStorageCleanup(blink::mojom::StorageType type,
-                             base::OnceClosure callback) override;
+                             PerformStorageCleanupCallback callback) override;
 
  private:
   ~FileSystemQuotaClient() override;
diff --git a/storage/browser/quota/quota_client.h b/storage/browser/quota/quota_client.h
index ac4cff9..bd4de1d 100644
--- a/storage/browser/quota/quota_client.h
+++ b/storage/browser/quota/quota_client.h
@@ -30,11 +30,16 @@
 class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaClient
     : public base::RefCountedThreadSafe<QuotaClient> {
  public:
-  using GetUsageCallback = base::OnceCallback<void(int64_t usage)>;
-  using GetOriginsCallback =
+  // The callback aliases precisely follow mojo conventions, because this
+  // abstract class will become a mojo interface soon. See crbug.com/1016065.
+  using GetOriginUsageCallback = base::OnceCallback<void(int64_t usage)>;
+  using GetOriginsForTypeCallback =
       base::OnceCallback<void(const std::vector<url::Origin>& origins)>;
-  using DeletionCallback =
+  using GetOriginsForHostCallback =
+      base::OnceCallback<void(const std::vector<url::Origin>& origins)>;
+  using DeleteOriginDataCallback =
       base::OnceCallback<void(blink::mojom::QuotaStatusCode status)>;
+  using PerformStorageCleanupCallback = base::OnceClosure;
 
   // Called when the QuotaManager is destroyed.
   virtual void OnQuotaManagerDestroyed() = 0;
@@ -45,32 +50,33 @@
   // Note it is safe to fire the callback after the QuotaClient is destructed.
   virtual void GetOriginUsage(const url::Origin& origin,
                               blink::mojom::StorageType type,
-                              GetUsageCallback callback) = 0;
+                              GetOriginUsageCallback callback) = 0;
 
   // Called by the QuotaManager.
   // Returns a list of origins that has data in the |type| storage.
   // Note it is safe to fire the callback after the QuotaClient is destructed.
   virtual void GetOriginsForType(blink::mojom::StorageType type,
-                                 GetOriginsCallback callback) = 0;
+                                 GetOriginsForTypeCallback callback) = 0;
 
   // Called by the QuotaManager.
   // Returns a list of origins that match the |host|.
   // Note it is safe to fire the callback after the QuotaClient is destructed.
   virtual void GetOriginsForHost(blink::mojom::StorageType type,
                                  const std::string& host,
-                                 GetOriginsCallback callback) = 0;
+                                 GetOriginsForHostCallback callback) = 0;
 
   // Called by the QuotaManager.
   // Note it is safe to fire the callback after the QuotaClient is destructed.
   virtual void DeleteOriginData(const url::Origin& origin,
                                 blink::mojom::StorageType type,
-                                DeletionCallback callback) = 0;
+                                DeleteOriginDataCallback callback) = 0;
 
   // Called by the QuotaManager.
   // Gives the QuotaClient an opportunity to perform a cleanup step after major
   // deletions.
-  virtual void PerformStorageCleanup(blink::mojom::StorageType type,
-                                     base::OnceClosure callback) = 0;
+  virtual void PerformStorageCleanup(
+      blink::mojom::StorageType type,
+      PerformStorageCleanupCallback callback) = 0;
 
  protected:
   friend class RefCountedThreadSafe<QuotaClient>;
diff --git a/storage/browser/quota/usage_tracker_unittest.cc b/storage/browser/quota/usage_tracker_unittest.cc
index 4503f4a..df85bd1a 100644
--- a/storage/browser/quota/usage_tracker_unittest.cc
+++ b/storage/browser/quota/usage_tracker_unittest.cc
@@ -45,7 +45,7 @@
 
   void GetOriginUsage(const url::Origin& origin,
                       StorageType type,
-                      GetUsageCallback callback) override {
+                      GetOriginUsageCallback callback) override {
     EXPECT_EQ(StorageType::kTemporary, type);
     int64_t usage = GetUsage(origin);
     base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -53,7 +53,7 @@
   }
 
   void GetOriginsForType(StorageType type,
-                         GetOriginsCallback callback) override {
+                         GetOriginsForTypeCallback callback) override {
     EXPECT_EQ(StorageType::kTemporary, type);
     std::vector<url::Origin> origins;
     for (const auto& origin_usage_pair : origin_usage_map_)
@@ -64,7 +64,7 @@
 
   void GetOriginsForHost(StorageType type,
                          const std::string& host,
-                         GetOriginsCallback callback) override {
+                         GetOriginsForHostCallback callback) override {
     EXPECT_EQ(StorageType::kTemporary, type);
     std::vector<url::Origin> origins;
     for (const auto& origin_usage_pair : origin_usage_map_) {
@@ -77,7 +77,7 @@
 
   void DeleteOriginData(const url::Origin& origin,
                         StorageType type,
-                        DeletionCallback callback) override {
+                        DeleteOriginDataCallback callback) override {
     EXPECT_EQ(StorageType::kTemporary, type);
     origin_usage_map_.erase(origin);
     base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -85,7 +85,7 @@
   }
 
   void PerformStorageCleanup(blink::mojom::StorageType type,
-                             base::OnceClosure callback) override {
+                             PerformStorageCleanupCallback callback) override {
     std::move(callback).Run();
   }
 
diff --git a/storage/browser/test/mock_quota_client.cc b/storage/browser/test/mock_quota_client.cc
index de9e4a4..a71ec854 100644
--- a/storage/browser/test/mock_quota_client.cc
+++ b/storage/browser/test/mock_quota_client.cc
@@ -83,7 +83,7 @@
 
 void MockQuotaClient::GetOriginUsage(const url::Origin& origin,
                                      blink::mojom::StorageType type,
-                                     GetUsageCallback callback) {
+                                     GetOriginUsageCallback callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(&MockQuotaClient::RunGetOriginUsage,
                                 weak_factory_.GetWeakPtr(), origin, type,
@@ -91,7 +91,7 @@
 }
 
 void MockQuotaClient::GetOriginsForType(blink::mojom::StorageType type,
-                                        GetOriginsCallback callback) {
+                                        GetOriginsForTypeCallback callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(&MockQuotaClient::RunGetOriginsForType,
@@ -100,7 +100,7 @@
 
 void MockQuotaClient::GetOriginsForHost(blink::mojom::StorageType type,
                                         const std::string& host,
-                                        GetOriginsCallback callback) {
+                                        GetOriginsForHostCallback callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(&MockQuotaClient::RunGetOriginsForHost,
                                 weak_factory_.GetWeakPtr(), type, host,
@@ -109,21 +109,22 @@
 
 void MockQuotaClient::DeleteOriginData(const url::Origin& origin,
                                        blink::mojom::StorageType type,
-                                       DeletionCallback callback) {
+                                       DeleteOriginDataCallback callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(&MockQuotaClient::RunDeleteOriginData,
                                 weak_factory_.GetWeakPtr(), origin, type,
                                 std::move(callback)));
 }
 
-void MockQuotaClient::PerformStorageCleanup(blink::mojom::StorageType type,
-                                            base::OnceClosure callback) {
+void MockQuotaClient::PerformStorageCleanup(
+    blink::mojom::StorageType type,
+    PerformStorageCleanupCallback callback) {
   std::move(callback).Run();
 }
 
 void MockQuotaClient::RunGetOriginUsage(const url::Origin& origin,
                                         blink::mojom::StorageType type,
-                                        GetUsageCallback callback) {
+                                        GetOriginUsageCallback callback) {
   auto it = origin_data_.find(std::make_pair(origin, type));
   if (it == origin_data_.end()) {
     std::move(callback).Run(0);
@@ -133,7 +134,7 @@
 }
 
 void MockQuotaClient::RunGetOriginsForType(blink::mojom::StorageType type,
-                                           GetOriginsCallback callback) {
+                                           GetOriginsForTypeCallback callback) {
   std::vector<url::Origin> origins;
   for (const auto& origin_type_usage : origin_data_) {
     if (type == origin_type_usage.first.second)
@@ -144,7 +145,7 @@
 
 void MockQuotaClient::RunGetOriginsForHost(blink::mojom::StorageType type,
                                            const std::string& host,
-                                           GetOriginsCallback callback) {
+                                           GetOriginsForHostCallback callback) {
   std::vector<url::Origin> origins;
   for (const auto& origin_type_usage : origin_data_) {
     if (type == origin_type_usage.first.second &&
@@ -158,7 +159,7 @@
 void MockQuotaClient::RunDeleteOriginData(
     const url::Origin& origin,
     blink::mojom::StorageType storage_type,
-    DeletionCallback callback) {
+    DeleteOriginDataCallback callback) {
   auto error_it = error_origins_.find(std::make_pair(origin, storage_type));
   if (error_it != error_origins_.end()) {
     std::move(callback).Run(
diff --git a/storage/browser/test/mock_quota_client.h b/storage/browser/test/mock_quota_client.h
index 37c8f48c..8fca4a9 100644
--- a/storage/browser/test/mock_quota_client.h
+++ b/storage/browser/test/mock_quota_client.h
@@ -59,32 +59,32 @@
   void OnQuotaManagerDestroyed() override;
   void GetOriginUsage(const url::Origin& origin,
                       blink::mojom::StorageType type,
-                      GetUsageCallback callback) override;
+                      GetOriginUsageCallback callback) override;
   void GetOriginsForType(blink::mojom::StorageType type,
-                         GetOriginsCallback callback) override;
+                         GetOriginsForTypeCallback callback) override;
   void GetOriginsForHost(blink::mojom::StorageType type,
                          const std::string& host,
-                         GetOriginsCallback callback) override;
+                         GetOriginsForHostCallback callback) override;
   void DeleteOriginData(const url::Origin& origin,
                         blink::mojom::StorageType type,
-                        DeletionCallback callback) override;
+                        DeleteOriginDataCallback callback) override;
   void PerformStorageCleanup(blink::mojom::StorageType type,
-                             base::OnceClosure callback) override;
+                             PerformStorageCleanupCallback callback) override;
 
  private:
   ~MockQuotaClient() override;
 
   void RunGetOriginUsage(const url::Origin& origin,
                          blink::mojom::StorageType type,
-                         GetUsageCallback callback);
+                         GetOriginUsageCallback callback);
   void RunGetOriginsForType(blink::mojom::StorageType type,
-                            GetOriginsCallback callback);
+                            GetOriginsForTypeCallback callback);
   void RunGetOriginsForHost(blink::mojom::StorageType type,
                             const std::string& host,
-                            GetOriginsCallback callback);
+                            GetOriginsForTypeCallback callback);
   void RunDeleteOriginData(const url::Origin& origin,
                            blink::mojom::StorageType type,
-                           DeletionCallback callback);
+                           DeleteOriginDataCallback callback);
 
   const scoped_refptr<QuotaManagerProxy> quota_manager_proxy_;
   const QuotaClientType client_type_;
diff --git a/testing/buildbot/chromium.ci.json b/testing/buildbot/chromium.ci.json
index 9413e23..66b47a5 100644
--- a/testing/buildbot/chromium.ci.json
+++ b/testing/buildbot/chromium.ci.json
@@ -134507,6 +134507,18 @@
           "can_use_on_swarming_builders": true,
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
+        "test": "vr_pixeltests",
+        "test_id_prefix": "ninja://chrome/browser/vr:vr_pixeltests/"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
         "test": "weblayer_browsertests",
         "test_id_prefix": "ninja://weblayer/test:weblayer_browsertests/"
       },
@@ -134823,19 +134835,6 @@
       }
     ]
   },
-  "Win x64 Builder Code Coverage": {
-    "additional_compile_targets": [
-      "pdf_fuzzers"
-    ],
-    "scripts": [
-      {
-        "isolate_profile_data": true,
-        "name": "check_network_annotations",
-        "script": "check_network_annotations.py",
-        "swarming": {}
-      }
-    ]
-  },
   "Win10 FYI x64 DX12 Vulkan Debug (NVIDIA)": {
     "isolated_scripts": [
       {
@@ -150222,2379 +150221,6 @@
       }
     ]
   },
-  "Win10 Tests x64 Code Coverage": {
-    "gtest_tests": [
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "absl_hardening_tests",
-        "test_id_prefix": "ninja://third_party/abseil-cpp:absl_hardening_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "accessibility_unittests",
-        "test_id_prefix": "ninja://ui/accessibility:accessibility_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_unittests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "app_shell_unittests",
-        "test_id_prefix": "ninja://extensions/shell:app_shell_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "aura_unittests",
-        "test_id_prefix": "ninja://ui/aura:aura_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "base_unittests",
-        "test_id_prefix": "ninja://base:base_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "base_util_unittests",
-        "test_id_prefix": "ninja://base/util:base_util_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_common_unittests",
-        "test_id_prefix": "ninja://third_party/blink/common:blink_common_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_fuzzer_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/platform:blink_fuzzer_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_heap_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/platform/heap:blink_heap_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_platform_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/platform:blink_platform_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "webkit_unit_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/controller:blink_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "boringssl_crypto_tests",
-        "test_id_prefix": "ninja://third_party/boringssl:boringssl_crypto_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "boringssl_ssl_tests",
-        "test_id_prefix": "ninja://third_party/boringssl:boringssl_ssl_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "browser_switcher_bho_unittests",
-        "test_id_prefix": "ninja://chrome/browser/browser_switcher/bho:browser_switcher_bho_unittests/"
-      },
-      {
-        "args": [
-          "--disable-features=WebRTC-H264WithOpenH264FFmpeg"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 15
-        },
-        "test": "browser_tests",
-        "test_id_prefix": "ninja://chrome/test:browser_tests/"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/pixel_browser_tests.filter",
-          "--browser-ui-tests-verify-pixels",
-          "--enable-pixel-output-in-tests",
-          "--git-revision=${got_revision}"
-        ],
-        "experiment_percentage": 100,
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "pixel_browser_tests",
-        "non_precommit_args": [
-          "--test-launcher-retry-limit=0"
-        ],
-        "precommit_args": [
-          "--gerrit-issue=${patch_issue}",
-          "--gerrit-patchset=${patch_set}",
-          "--buildbucket-id=${buildbucket_build_id}"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chrome-gold@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "browser_tests",
-        "test_id_prefix": "ninja://chrome/test:browser_tests/"
-      },
-      {
-        "args": [
-          "--gtest_filter=-*UsingRealWebcam*"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "capture_unittests",
-        "test_id_prefix": "ninja://media/capture:capture_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "cast_unittests",
-        "test_id_prefix": "ninja://media/cast:cast_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "cc_unittests",
-        "test_id_prefix": "ninja://cc:cc_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "chrome_app_unittests",
-        "test_id_prefix": "ninja://chrome/test:chrome_app_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "chrome_cleaner_unittests",
-        "test_id_prefix": "ninja://chrome/chrome_cleaner:chrome_cleaner_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "chrome_elf_unittests",
-        "test_id_prefix": "ninja://chrome/chrome_elf:chrome_elf_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "chromedriver_unittests",
-        "test_id_prefix": "ninja://chrome/test/chromedriver:chromedriver_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "components_browsertests",
-        "test_id_prefix": "ninja://components:components_browsertests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "components_unittests",
-        "test_id_prefix": "ninja://components:components_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "compositor_unittests",
-        "test_id_prefix": "ninja://ui/compositor:compositor_unittests/"
-      },
-      {
-        "args": [
-          "--disable-features=WebRTC-H264WithOpenH264FFmpeg"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 6
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
-        "args": [
-          "--disable-features=UseSkiaRenderer",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/skia_renderer.content_browsertests.filter"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "non_skia_renderer_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_unsandboxed_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "content_unittests",
-        "test_id_prefix": "ninja://content/test:content_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "courgette_unittests",
-        "test_id_prefix": "ninja://courgette:courgette_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "crashpad_tests",
-        "test_id_prefix": "ninja://third_party/crashpad/crashpad:crashpad_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "cronet_tests",
-        "test_id_prefix": "ninja://components/cronet:cronet_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "cronet_unittests",
-        "test_id_prefix": "ninja://components/cronet:cronet_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "crypto_unittests",
-        "test_id_prefix": "ninja://crypto:crypto_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "delayloads_unittests",
-        "test_id_prefix": "ninja://chrome/test:delayloads_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "device_unittests",
-        "test_id_prefix": "ninja://device:device_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "display_unittests",
-        "test_id_prefix": "ninja://ui/display:display_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "elevation_service_unittests",
-        "test_id_prefix": "ninja://chrome/elevation_service:elevation_service_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "events_unittests",
-        "test_id_prefix": "ninja://ui/events:events_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_unsandboxed_extensions_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_unittests",
-        "test_id_prefix": "ninja://extensions:extensions_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "filesystem_service_unittests",
-        "test_id_prefix": "ninja://components/services/filesystem:filesystem_service_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gcm_unit_tests",
-        "test_id_prefix": "ninja://google_apis/gcm:gcm_unit_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gcp_unittests",
-        "test_id_prefix": "ninja://chrome/credential_provider/test:gcp_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gfx_unittests",
-        "test_id_prefix": "ninja://ui/gfx:gfx_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gin_unittests",
-        "test_id_prefix": "ninja://gin:gin_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "google_apis_unittests",
-        "test_id_prefix": "ninja://google_apis:google_apis_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gpu_unittests",
-        "test_id_prefix": "ninja://gpu:gpu_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gwp_asan_unittests",
-        "test_id_prefix": "ninja://components/gwp_asan:gwp_asan_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "headless_browsertests",
-        "test_id_prefix": "ninja://headless:headless_browsertests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "headless_unittests",
-        "test_id_prefix": "ninja://headless:headless_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "install_static_unittests",
-        "test_id_prefix": "ninja://chrome/install_static:install_static_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "integrity": "high",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "installer_util_unittests",
-        "test_id_prefix": "ninja://chrome/installer/util:installer_util_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      },
-      {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_unsandboxed_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "ipc_tests",
-        "test_id_prefix": "ninja://ipc:ipc_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "jingle_unittests",
-        "test_id_prefix": "ninja://jingle:jingle_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "latency_unittests",
-        "test_id_prefix": "ninja://ui/latency:latency_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "libjingle_xmpp_unittests",
-        "test_id_prefix": "ninja://third_party/libjingle_xmpp:libjingle_xmpp_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "media_blink_unittests",
-        "test_id_prefix": "ninja://media/blink:media_blink_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "media_unittests",
-        "test_id_prefix": "ninja://media:media_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "message_center_unittests",
-        "test_id_prefix": "ninja://ui/message_center:message_center_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "midi_unittests",
-        "test_id_prefix": "ninja://media/midi:midi_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "mojo_core_unittests",
-        "test_id_prefix": "ninja://mojo/core:mojo_core_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "mojo_unittests",
-        "test_id_prefix": "ninja://mojo:mojo_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "nacl_loader_unittests",
-        "test_id_prefix": "ninja://components/nacl/loader:nacl_loader_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "native_theme_unittests",
-        "test_id_prefix": "ninja://ui/native_theme:native_theme_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "net_unittests",
-        "test_id_prefix": "ninja://net:net_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "notification_helper_unittests",
-        "test_id_prefix": "ninja://chrome/notification_helper:notification_helper_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "pdf_unittests",
-        "test_id_prefix": "ninja://pdf:pdf_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "perfetto_unittests",
-        "test_id_prefix": "ninja://third_party/perfetto:perfetto_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "ppapi_unittests",
-        "test_id_prefix": "ninja://ppapi:ppapi_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "printing_unittests",
-        "test_id_prefix": "ninja://printing:printing_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "remoting_unittests",
-        "test_id_prefix": "ninja://remoting:remoting_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "integrity": "high",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "sbox_integration_tests",
-        "test_id_prefix": "ninja://sandbox/win:sbox_integration_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "sbox_unittests",
-        "test_id_prefix": "ninja://sandbox/win:sbox_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "sbox_validation_tests",
-        "test_id_prefix": "ninja://sandbox/win:sbox_validation_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "service_manager_unittests",
-        "test_id_prefix": "ninja://services/service_manager/tests:service_manager_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "services_unittests",
-        "test_id_prefix": "ninja://services:services_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "integrity": "high",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "setup_unittests",
-        "test_id_prefix": "ninja://chrome/installer/setup:setup_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "shell_dialogs_unittests",
-        "test_id_prefix": "ninja://ui/shell_dialogs:shell_dialogs_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "skia_unittests",
-        "test_id_prefix": "ninja://skia:skia_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "snapshot_unittests",
-        "test_id_prefix": "ninja://ui/snapshot:snapshot_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "sql_unittests",
-        "test_id_prefix": "ninja://sql:sql_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "storage_unittests",
-        "test_id_prefix": "ninja://storage:storage_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "sync_integration_tests",
-        "test_id_prefix": "ninja://chrome/test:sync_integration_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "traffic_annotation_auditor_unittests",
-        "test_id_prefix": "ninja://tools/traffic_annotation/auditor:traffic_annotation_auditor_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "ui_base_unittests",
-        "test_id_prefix": "ninja://ui/base:ui_base_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "ui_touch_selection_unittests",
-        "test_id_prefix": "ninja://ui/touch_selection:ui_touch_selection_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "unit_tests",
-        "test_id_prefix": "ninja://chrome/test:unit_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "updater_tests",
-        "test_id_prefix": "ninja://chrome/updater:updater_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "url_unittests",
-        "test_id_prefix": "ninja://url:url_unittests/"
-      },
-      {
-        "args": [
-          "--git-revision=${got_revision}"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "precommit_args": [
-          "--gerrit-issue=${patch_issue}",
-          "--gerrit-patchset=${patch_set}",
-          "--buildbucket-id=${buildbucket_build_id}"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chrome-gold@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "views_examples_unittests",
-        "test_id_prefix": "ninja://ui/views/examples:views_examples_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "views_unittests",
-        "test_id_prefix": "ninja://ui/views:views_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "viz_unittests",
-        "test_id_prefix": "ninja://components/viz:viz_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "vr_common_unittests",
-        "test_id_prefix": "ninja://chrome/browser/vr:vr_common_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "vr_pixeltests",
-        "test_id_prefix": "ninja://chrome/browser/vr:vr_pixeltests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "weblayer_browsertests",
-        "test_id_prefix": "ninja://weblayer/test:weblayer_browsertests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "weblayer_unittests",
-        "test_id_prefix": "ninja://weblayer/test:weblayer_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "wm_unittests",
-        "test_id_prefix": "ninja://ui/wm:wm_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "wtf_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/platform/wtf:wtf_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "zucchini_unittests",
-        "test_id_prefix": "ninja://components/zucchini:zucchini_unittests/"
-      }
-    ],
-    "isolated_scripts": [
-      {
-        "isolate_name": "blink_python_tests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "blink_python_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://:blink_python_tests/"
-      },
-      {
-        "args": [
-          "--num-retries=3",
-          "--target",
-          "Release_x64"
-        ],
-        "isolate_name": "blink_web_tests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "blink_web_tests",
-        "results_handler": "layout tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 28
-        },
-        "test_id_prefix": "ninja://:blink_web_tests/"
-      },
-      {
-        "args": [
-          "--test-type=integration"
-        ],
-        "isolate_name": "chromedriver_py_tests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "chromedriver_py_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test/chromedriver:chromedriver_py_tests/"
-      },
-      {
-        "isolate_name": "chromedriver_replay_unittests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "chromedriver_replay_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test/chromedriver:chromedriver_replay_unittests/"
-      },
-      {
-        "args": [
-          "--gtest-benchmark-name=components_perftests"
-        ],
-        "isolate_name": "components_perftests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [
-            "--smoke-test-mode"
-          ],
-          "script": "//tools/perf/process_perf_results.py"
-        },
-        "name": "components_perftests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://components:components_perftests/"
-      },
-      {
-        "isolate_name": "content_shell_crash_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "content_shell_crash_test",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://content/shell:content_shell_crash_test/"
-      },
-      {
-        "isolate_name": "flatbuffers_unittests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "flatbuffers_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://third_party/flatbuffers:flatbuffers_unittests/"
-      },
-      {
-        "isolate_name": "grit_python_unittests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "grit_python_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://tools/grit:grit_python_unittests/"
-      },
-      {
-        "isolate_name": "metrics_python_tests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "metrics_python_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://tools/metrics:metrics_python_tests/"
-      },
-      {
-        "isolate_name": "mini_installer_tests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "mini_installer_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "integrity": "high",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test/mini_installer:mini_installer_tests/"
-      },
-      {
-        "isolate_name": "mojo_python_unittests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "mojo_python_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://mojo/public/tools:mojo_python_unittests/"
-      },
-      {
-        "experiment_percentage": 100,
-        "isolate_name": "polymer_tools_python_unittests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "polymer_tools_python_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://tools/polymer:polymer_tools_python_unittests/"
-      },
-      {
-        "isolate_name": "telemetry_gpu_unittests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "telemetry_gpu_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_unittests/"
-      },
-      {
-        "args": [
-          "--gtest-benchmark-name=views_perftests"
-        ],
-        "isolate_name": "views_perftests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [
-            "--smoke-test-mode"
-          ],
-          "script": "//tools/perf/process_perf_results.py"
-        },
-        "name": "views_perftests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://ui/views:views_perftests/"
-      }
-    ],
-    "scripts": [
-      {
-        "isolate_profile_data": true,
-        "name": "webkit_lint",
-        "script": "blink_lint_expectations.py",
-        "swarming": {}
-      }
-    ]
-  },
   "Win10 x64 Debug (NVIDIA)": {
     "gtest_tests": [
       {
@@ -153634,547 +151260,6 @@
       }
     ]
   },
-  "Win10 x64 Release (NVIDIA) Code Coverage": {
-    "gtest_tests": [
-      {
-        "args": [
-          "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_unittests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_unittests/"
-      },
-      {
-        "args": [
-          "--enable-gpu",
-          "--test-launcher-bot-mode",
-          "--test-launcher-jobs=1",
-          "--gtest_filter=CastStreamingApiTestWithPixelOutput.EndToEnd*:TabCaptureApiPixelTest.EndToEnd*"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "tab_capture_end2end_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "browser_tests",
-        "test_id_prefix": "ninja://chrome/test:browser_tests/"
-      },
-      {
-        "args": [
-          "--use-cmd-decoder=passthrough",
-          "--use-gl=angle",
-          "--use-gpu-in-tests"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "gl_tests_passthrough",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gl_tests",
-        "test_id_prefix": "ninja://gpu:gl_tests/"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gl_unittests",
-        "test_id_prefix": "ninja://ui/gl:gl_unittests/"
-      },
-      {
-        "args": [
-          "--ignore-runtime-requirements=*"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "xr_browser_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "xr_browser_tests",
-        "test_id_prefix": "ninja://chrome/test:xr_browser_tests/"
-      }
-    ],
-    "isolated_scripts": [
-      {
-        "args": [
-          "context_lost",
-          "--show-stdout",
-          "--browser=release_x64",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "context_lost_passthrough_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "depth_capture",
-          "--show-stdout",
-          "--browser=release_x64",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "depth_capture_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "screenshot_sync",
-          "--show-stdout",
-          "--browser=release_x64",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --disable-features=UseSkiaRenderer",
-          "--dont-restore-color-profile-after-test"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "gl_renderer_screenshot_sync_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "gpu_process",
-          "--show-stdout",
-          "--browser=release_x64",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "gpu_process_launch_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "hardware_accelerated_feature",
-          "--show-stdout",
-          "--browser=release_x64",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "hardware_accelerated_feature_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "info_collection",
-          "--show-stdout",
-          "--browser=release_x64",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu",
-          "--expected-vendor-id",
-          "10de",
-          "--expected-device-id",
-          "1cb3"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "info_collection_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "maps",
-          "--show-stdout",
-          "--browser=release_x64",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle",
-          "--dont-restore-color-profile-after-test",
-          "--test-machine-name",
-          "${buildername}",
-          "--git-revision=${got_revision}"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "maps_pixel_passthrough_test",
-        "precommit_args": [
-          "--gerrit-issue=${patch_issue}",
-          "--gerrit-patchset=${patch_set}",
-          "--buildbucket-id=${buildbucket_build_id}"
-        ],
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "pixel",
-          "--show-stdout",
-          "--browser=release_x64",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle",
-          "--dont-restore-color-profile-after-test",
-          "--test-machine-name",
-          "${buildername}",
-          "--git-revision=${got_revision}"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "pixel_skia_gold_passthrough_test",
-        "precommit_args": [
-          "--gerrit-issue=${patch_issue}",
-          "--gerrit-patchset=${patch_set}",
-          "--buildbucket-id=${buildbucket_build_id}"
-        ],
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "../../tools/perf/run_benchmark",
-          "--benchmarks=rendering.desktop",
-          "--browser=release_x64"
-        ],
-        "isolate_name": "rendering_representative_perf_tests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "rendering_representative_perf_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:rendering_representative_perf_tests/"
-      },
-      {
-        "args": [
-          "screenshot_sync",
-          "--show-stdout",
-          "--browser=release_x64",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle",
-          "--dont-restore-color-profile-after-test"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "screenshot_sync_passthrough_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "trace_test",
-          "--show-stdout",
-          "--browser=release_x64",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "trace_test",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "webgl_conformance",
-          "--show-stdout",
-          "--browser=release_x64",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu",
-          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "webgl_conformance_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      }
-    ]
-  },
   "Win7 (32) Tests": {
     "gtest_tests": [
       {
@@ -159080,6 +156165,18 @@
           "can_use_on_swarming_builders": true,
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
+        "test": "vr_pixeltests",
+        "test_id_prefix": "ninja://chrome/browser/vr:vr_pixeltests/"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
         "test": "weblayer_browsertests",
         "test_id_prefix": "ninja://weblayer/test:weblayer_browsertests/"
       },
@@ -160529,6 +157626,18 @@
           "can_use_on_swarming_builders": true,
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
+        "test": "vr_pixeltests",
+        "test_id_prefix": "ninja://chrome/browser/vr:vr_pixeltests/"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
         "test": "weblayer_browsertests",
         "test_id_prefix": "ninja://weblayer/test:weblayer_browsertests/"
       },
diff --git a/testing/buildbot/chromium.gpu.json b/testing/buildbot/chromium.gpu.json
index 3a5e165a..d359f21 100644
--- a/testing/buildbot/chromium.gpu.json
+++ b/testing/buildbot/chromium.gpu.json
@@ -5539,546 +5539,5 @@
         "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
       }
     ]
-  },
-  "Win10 x64 Release (NVIDIA) Code Coverage": {
-    "gtest_tests": [
-      {
-        "args": [
-          "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_unittests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_unittests/"
-      },
-      {
-        "args": [
-          "--enable-gpu",
-          "--test-launcher-bot-mode",
-          "--test-launcher-jobs=1",
-          "--gtest_filter=CastStreamingApiTestWithPixelOutput.EndToEnd*:TabCaptureApiPixelTest.EndToEnd*"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "tab_capture_end2end_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "browser_tests",
-        "test_id_prefix": "ninja://chrome/test:browser_tests/"
-      },
-      {
-        "args": [
-          "--use-cmd-decoder=passthrough",
-          "--use-gl=angle",
-          "--use-gpu-in-tests"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "gl_tests_passthrough",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gl_tests",
-        "test_id_prefix": "ninja://gpu:gl_tests/"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gl_unittests",
-        "test_id_prefix": "ninja://ui/gl:gl_unittests/"
-      },
-      {
-        "args": [
-          "--ignore-runtime-requirements=*"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "xr_browser_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "xr_browser_tests",
-        "test_id_prefix": "ninja://chrome/test:xr_browser_tests/"
-      }
-    ],
-    "isolated_scripts": [
-      {
-        "args": [
-          "context_lost",
-          "--show-stdout",
-          "--browser=release_x64",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "context_lost_passthrough_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "depth_capture",
-          "--show-stdout",
-          "--browser=release_x64",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "depth_capture_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "screenshot_sync",
-          "--show-stdout",
-          "--browser=release_x64",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --disable-features=UseSkiaRenderer",
-          "--dont-restore-color-profile-after-test"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "gl_renderer_screenshot_sync_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "gpu_process",
-          "--show-stdout",
-          "--browser=release_x64",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "gpu_process_launch_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "hardware_accelerated_feature",
-          "--show-stdout",
-          "--browser=release_x64",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "hardware_accelerated_feature_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "info_collection",
-          "--show-stdout",
-          "--browser=release_x64",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu",
-          "--expected-vendor-id",
-          "10de",
-          "--expected-device-id",
-          "1cb3"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "info_collection_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "maps",
-          "--show-stdout",
-          "--browser=release_x64",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle",
-          "--dont-restore-color-profile-after-test",
-          "--test-machine-name",
-          "${buildername}",
-          "--git-revision=${got_revision}"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "maps_pixel_passthrough_test",
-        "precommit_args": [
-          "--gerrit-issue=${patch_issue}",
-          "--gerrit-patchset=${patch_set}",
-          "--buildbucket-id=${buildbucket_build_id}"
-        ],
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "pixel",
-          "--show-stdout",
-          "--browser=release_x64",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle",
-          "--dont-restore-color-profile-after-test",
-          "--test-machine-name",
-          "${buildername}",
-          "--git-revision=${got_revision}"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "pixel_skia_gold_passthrough_test",
-        "precommit_args": [
-          "--gerrit-issue=${patch_issue}",
-          "--gerrit-patchset=${patch_set}",
-          "--buildbucket-id=${buildbucket_build_id}"
-        ],
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "../../tools/perf/run_benchmark",
-          "--benchmarks=rendering.desktop",
-          "--browser=release_x64"
-        ],
-        "isolate_name": "rendering_representative_perf_tests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "rendering_representative_perf_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:rendering_representative_perf_tests/"
-      },
-      {
-        "args": [
-          "screenshot_sync",
-          "--show-stdout",
-          "--browser=release_x64",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle",
-          "--dont-restore-color-profile-after-test"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "screenshot_sync_passthrough_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "trace_test",
-          "--show-stdout",
-          "--browser=release_x64",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "trace_test",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "webgl_conformance",
-          "--show-stdout",
-          "--browser=release_x64",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu",
-          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "webgl_conformance_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      }
-    ]
   }
 }
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index 1f58cea..9331e428 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -1157,6 +1157,18 @@
           "can_use_on_swarming_builders": true,
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
+        "test": "vr_pixeltests",
+        "test_id_prefix": "ninja://chrome/browser/vr:vr_pixeltests/"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
         "test": "weblayer_browsertests",
         "test_id_prefix": "ninja://weblayer/test:weblayer_browsertests/"
       },
@@ -1463,19 +1475,6 @@
       }
     ]
   },
-  "Win x64 Builder Code Coverage": {
-    "additional_compile_targets": [
-      "pdf_fuzzers"
-    ],
-    "scripts": [
-      {
-        "isolate_profile_data": true,
-        "name": "check_network_annotations",
-        "script": "check_network_annotations.py",
-        "swarming": {}
-      }
-    ]
-  },
   "Win10 Tests x64": {
     "gtest_tests": [
       {
@@ -5753,2379 +5752,6 @@
       }
     ]
   },
-  "Win10 Tests x64 Code Coverage": {
-    "gtest_tests": [
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "absl_hardening_tests",
-        "test_id_prefix": "ninja://third_party/abseil-cpp:absl_hardening_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "accessibility_unittests",
-        "test_id_prefix": "ninja://ui/accessibility:accessibility_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_unittests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "app_shell_unittests",
-        "test_id_prefix": "ninja://extensions/shell:app_shell_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "aura_unittests",
-        "test_id_prefix": "ninja://ui/aura:aura_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "base_unittests",
-        "test_id_prefix": "ninja://base:base_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "base_util_unittests",
-        "test_id_prefix": "ninja://base/util:base_util_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_common_unittests",
-        "test_id_prefix": "ninja://third_party/blink/common:blink_common_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_fuzzer_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/platform:blink_fuzzer_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_heap_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/platform/heap:blink_heap_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_platform_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/platform:blink_platform_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "webkit_unit_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/controller:blink_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "boringssl_crypto_tests",
-        "test_id_prefix": "ninja://third_party/boringssl:boringssl_crypto_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "boringssl_ssl_tests",
-        "test_id_prefix": "ninja://third_party/boringssl:boringssl_ssl_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "browser_switcher_bho_unittests",
-        "test_id_prefix": "ninja://chrome/browser/browser_switcher/bho:browser_switcher_bho_unittests/"
-      },
-      {
-        "args": [
-          "--disable-features=WebRTC-H264WithOpenH264FFmpeg"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 15
-        },
-        "test": "browser_tests",
-        "test_id_prefix": "ninja://chrome/test:browser_tests/"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/pixel_browser_tests.filter",
-          "--browser-ui-tests-verify-pixels",
-          "--enable-pixel-output-in-tests",
-          "--git-revision=${got_revision}"
-        ],
-        "experiment_percentage": 100,
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "pixel_browser_tests",
-        "non_precommit_args": [
-          "--test-launcher-retry-limit=0"
-        ],
-        "precommit_args": [
-          "--gerrit-issue=${patch_issue}",
-          "--gerrit-patchset=${patch_set}",
-          "--buildbucket-id=${buildbucket_build_id}"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chrome-gold@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "browser_tests",
-        "test_id_prefix": "ninja://chrome/test:browser_tests/"
-      },
-      {
-        "args": [
-          "--gtest_filter=-*UsingRealWebcam*"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "capture_unittests",
-        "test_id_prefix": "ninja://media/capture:capture_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "cast_unittests",
-        "test_id_prefix": "ninja://media/cast:cast_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "cc_unittests",
-        "test_id_prefix": "ninja://cc:cc_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "chrome_app_unittests",
-        "test_id_prefix": "ninja://chrome/test:chrome_app_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "chrome_cleaner_unittests",
-        "test_id_prefix": "ninja://chrome/chrome_cleaner:chrome_cleaner_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "chrome_elf_unittests",
-        "test_id_prefix": "ninja://chrome/chrome_elf:chrome_elf_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "chromedriver_unittests",
-        "test_id_prefix": "ninja://chrome/test/chromedriver:chromedriver_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "components_browsertests",
-        "test_id_prefix": "ninja://components:components_browsertests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "components_unittests",
-        "test_id_prefix": "ninja://components:components_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "compositor_unittests",
-        "test_id_prefix": "ninja://ui/compositor:compositor_unittests/"
-      },
-      {
-        "args": [
-          "--disable-features=WebRTC-H264WithOpenH264FFmpeg"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 6
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
-        "args": [
-          "--disable-features=UseSkiaRenderer",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/skia_renderer.content_browsertests.filter"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "non_skia_renderer_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_unsandboxed_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "content_unittests",
-        "test_id_prefix": "ninja://content/test:content_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "courgette_unittests",
-        "test_id_prefix": "ninja://courgette:courgette_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "crashpad_tests",
-        "test_id_prefix": "ninja://third_party/crashpad/crashpad:crashpad_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "cronet_tests",
-        "test_id_prefix": "ninja://components/cronet:cronet_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "cronet_unittests",
-        "test_id_prefix": "ninja://components/cronet:cronet_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "crypto_unittests",
-        "test_id_prefix": "ninja://crypto:crypto_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "delayloads_unittests",
-        "test_id_prefix": "ninja://chrome/test:delayloads_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "device_unittests",
-        "test_id_prefix": "ninja://device:device_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "display_unittests",
-        "test_id_prefix": "ninja://ui/display:display_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "elevation_service_unittests",
-        "test_id_prefix": "ninja://chrome/elevation_service:elevation_service_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "events_unittests",
-        "test_id_prefix": "ninja://ui/events:events_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_unsandboxed_extensions_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_unittests",
-        "test_id_prefix": "ninja://extensions:extensions_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "filesystem_service_unittests",
-        "test_id_prefix": "ninja://components/services/filesystem:filesystem_service_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gcm_unit_tests",
-        "test_id_prefix": "ninja://google_apis/gcm:gcm_unit_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gcp_unittests",
-        "test_id_prefix": "ninja://chrome/credential_provider/test:gcp_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gfx_unittests",
-        "test_id_prefix": "ninja://ui/gfx:gfx_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gin_unittests",
-        "test_id_prefix": "ninja://gin:gin_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "google_apis_unittests",
-        "test_id_prefix": "ninja://google_apis:google_apis_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gpu_unittests",
-        "test_id_prefix": "ninja://gpu:gpu_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gwp_asan_unittests",
-        "test_id_prefix": "ninja://components/gwp_asan:gwp_asan_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "headless_browsertests",
-        "test_id_prefix": "ninja://headless:headless_browsertests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "headless_unittests",
-        "test_id_prefix": "ninja://headless:headless_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "install_static_unittests",
-        "test_id_prefix": "ninja://chrome/install_static:install_static_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "integrity": "high",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "installer_util_unittests",
-        "test_id_prefix": "ninja://chrome/installer/util:installer_util_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      },
-      {
-        "args": [
-          "--enable-features=StorageServiceOutOfProcess"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "storage_service_unsandboxed_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "ipc_tests",
-        "test_id_prefix": "ninja://ipc:ipc_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "jingle_unittests",
-        "test_id_prefix": "ninja://jingle:jingle_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "latency_unittests",
-        "test_id_prefix": "ninja://ui/latency:latency_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "libjingle_xmpp_unittests",
-        "test_id_prefix": "ninja://third_party/libjingle_xmpp:libjingle_xmpp_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "media_blink_unittests",
-        "test_id_prefix": "ninja://media/blink:media_blink_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "media_unittests",
-        "test_id_prefix": "ninja://media:media_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "message_center_unittests",
-        "test_id_prefix": "ninja://ui/message_center:message_center_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "midi_unittests",
-        "test_id_prefix": "ninja://media/midi:midi_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "mojo_core_unittests",
-        "test_id_prefix": "ninja://mojo/core:mojo_core_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "mojo_unittests",
-        "test_id_prefix": "ninja://mojo:mojo_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "nacl_loader_unittests",
-        "test_id_prefix": "ninja://components/nacl/loader:nacl_loader_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "native_theme_unittests",
-        "test_id_prefix": "ninja://ui/native_theme:native_theme_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "net_unittests",
-        "test_id_prefix": "ninja://net:net_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "notification_helper_unittests",
-        "test_id_prefix": "ninja://chrome/notification_helper:notification_helper_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "pdf_unittests",
-        "test_id_prefix": "ninja://pdf:pdf_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "perfetto_unittests",
-        "test_id_prefix": "ninja://third_party/perfetto:perfetto_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "ppapi_unittests",
-        "test_id_prefix": "ninja://ppapi:ppapi_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "printing_unittests",
-        "test_id_prefix": "ninja://printing:printing_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "remoting_unittests",
-        "test_id_prefix": "ninja://remoting:remoting_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "integrity": "high",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "sbox_integration_tests",
-        "test_id_prefix": "ninja://sandbox/win:sbox_integration_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "sbox_unittests",
-        "test_id_prefix": "ninja://sandbox/win:sbox_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "sbox_validation_tests",
-        "test_id_prefix": "ninja://sandbox/win:sbox_validation_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "service_manager_unittests",
-        "test_id_prefix": "ninja://services/service_manager/tests:service_manager_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "services_unittests",
-        "test_id_prefix": "ninja://services:services_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "integrity": "high",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "setup_unittests",
-        "test_id_prefix": "ninja://chrome/installer/setup:setup_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "shell_dialogs_unittests",
-        "test_id_prefix": "ninja://ui/shell_dialogs:shell_dialogs_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "skia_unittests",
-        "test_id_prefix": "ninja://skia:skia_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "snapshot_unittests",
-        "test_id_prefix": "ninja://ui/snapshot:snapshot_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "sql_unittests",
-        "test_id_prefix": "ninja://sql:sql_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "storage_unittests",
-        "test_id_prefix": "ninja://storage:storage_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "sync_integration_tests",
-        "test_id_prefix": "ninja://chrome/test:sync_integration_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "traffic_annotation_auditor_unittests",
-        "test_id_prefix": "ninja://tools/traffic_annotation/auditor:traffic_annotation_auditor_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "ui_base_unittests",
-        "test_id_prefix": "ninja://ui/base:ui_base_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "ui_touch_selection_unittests",
-        "test_id_prefix": "ninja://ui/touch_selection:ui_touch_selection_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "unit_tests",
-        "test_id_prefix": "ninja://chrome/test:unit_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "updater_tests",
-        "test_id_prefix": "ninja://chrome/updater:updater_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "url_unittests",
-        "test_id_prefix": "ninja://url:url_unittests/"
-      },
-      {
-        "args": [
-          "--git-revision=${got_revision}"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "precommit_args": [
-          "--gerrit-issue=${patch_issue}",
-          "--gerrit-patchset=${patch_set}",
-          "--buildbucket-id=${buildbucket_build_id}"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chrome-gold@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "views_examples_unittests",
-        "test_id_prefix": "ninja://ui/views/examples:views_examples_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "views_unittests",
-        "test_id_prefix": "ninja://ui/views:views_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "viz_unittests",
-        "test_id_prefix": "ninja://components/viz:viz_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "vr_common_unittests",
-        "test_id_prefix": "ninja://chrome/browser/vr:vr_common_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "vr_pixeltests",
-        "test_id_prefix": "ninja://chrome/browser/vr:vr_pixeltests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "weblayer_browsertests",
-        "test_id_prefix": "ninja://weblayer/test:weblayer_browsertests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "weblayer_unittests",
-        "test_id_prefix": "ninja://weblayer/test:weblayer_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "wm_unittests",
-        "test_id_prefix": "ninja://ui/wm:wm_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "wtf_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/platform/wtf:wtf_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "zucchini_unittests",
-        "test_id_prefix": "ninja://components/zucchini:zucchini_unittests/"
-      }
-    ],
-    "isolated_scripts": [
-      {
-        "isolate_name": "blink_python_tests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "blink_python_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://:blink_python_tests/"
-      },
-      {
-        "args": [
-          "--num-retries=3",
-          "--target",
-          "Release_x64"
-        ],
-        "isolate_name": "blink_web_tests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "blink_web_tests",
-        "results_handler": "layout tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 28
-        },
-        "test_id_prefix": "ninja://:blink_web_tests/"
-      },
-      {
-        "args": [
-          "--test-type=integration"
-        ],
-        "isolate_name": "chromedriver_py_tests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "chromedriver_py_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test/chromedriver:chromedriver_py_tests/"
-      },
-      {
-        "isolate_name": "chromedriver_replay_unittests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "chromedriver_replay_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test/chromedriver:chromedriver_replay_unittests/"
-      },
-      {
-        "args": [
-          "--gtest-benchmark-name=components_perftests"
-        ],
-        "isolate_name": "components_perftests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [
-            "--smoke-test-mode"
-          ],
-          "script": "//tools/perf/process_perf_results.py"
-        },
-        "name": "components_perftests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://components:components_perftests/"
-      },
-      {
-        "isolate_name": "content_shell_crash_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "content_shell_crash_test",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://content/shell:content_shell_crash_test/"
-      },
-      {
-        "isolate_name": "flatbuffers_unittests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "flatbuffers_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://third_party/flatbuffers:flatbuffers_unittests/"
-      },
-      {
-        "isolate_name": "grit_python_unittests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "grit_python_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://tools/grit:grit_python_unittests/"
-      },
-      {
-        "isolate_name": "metrics_python_tests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "metrics_python_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://tools/metrics:metrics_python_tests/"
-      },
-      {
-        "isolate_name": "mini_installer_tests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "mini_installer_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "integrity": "high",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test/mini_installer:mini_installer_tests/"
-      },
-      {
-        "isolate_name": "mojo_python_unittests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "mojo_python_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://mojo/public/tools:mojo_python_unittests/"
-      },
-      {
-        "experiment_percentage": 100,
-        "isolate_name": "polymer_tools_python_unittests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "polymer_tools_python_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://tools/polymer:polymer_tools_python_unittests/"
-      },
-      {
-        "isolate_name": "telemetry_gpu_unittests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "telemetry_gpu_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_unittests/"
-      },
-      {
-        "args": [
-          "--gtest-benchmark-name=views_perftests"
-        ],
-        "isolate_name": "views_perftests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [
-            "--smoke-test-mode"
-          ],
-          "script": "//tools/perf/process_perf_results.py"
-        },
-        "name": "views_perftests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://ui/views:views_perftests/"
-      }
-    ],
-    "scripts": [
-      {
-        "isolate_profile_data": true,
-        "name": "webkit_lint",
-        "script": "blink_lint_expectations.py",
-        "swarming": {}
-      }
-    ]
-  },
   "Win7 (32) Tests": {
     "gtest_tests": [
       {
@@ -9349,6 +6975,18 @@
           "can_use_on_swarming_builders": true,
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
+        "test": "vr_pixeltests",
+        "test_id_prefix": "ninja://chrome/browser/vr:vr_pixeltests/"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
         "test": "weblayer_browsertests",
         "test_id_prefix": "ninja://weblayer/test:weblayer_browsertests/"
       },
@@ -10798,6 +8436,18 @@
           "can_use_on_swarming_builders": true,
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
+        "test": "vr_pixeltests",
+        "test_id_prefix": "ninja://chrome/browser/vr:vr_pixeltests/"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
         "test": "weblayer_browsertests",
         "test_id_prefix": "ninja://weblayer/test:weblayer_browsertests/"
       },
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 49b0879..c1d6290 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -2523,12 +2523,6 @@
       'android-pie-x86-rel',
       'VR Linux',
       'android-code-coverage-native', # crbug/1018431
-      # These tests fail on Win7, and given that We don't support VR there,
-      # these tests are unnecessary there.
-      # chromium.win
-      'Win 7 Tests x64 (1)',
-      'Win7 Tests (1)',
-      'Win7 Tests (dbg)(1)',
     ],
   },
   'wayland_client_perftests': {
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index cea80595..059e36a 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -2945,21 +2945,6 @@
           'isolated_scripts': 'rendering_desktop_representative_perf_tests_isolated_scripts',
         },
       },
-      # TODO(crbug.com/1004523) Delete 'Win10 x64 Release (NVIDIA) Code Coverage'
-      # when 'Win10 x64 Release (NVIDIA)' has code coverage enabled by default.
-      'Win10 x64 Release (NVIDIA) Code Coverage': {
-        'browser_config': 'release_x64',
-        'os_type': 'win',
-        'mixins': [
-          'isolate_profile_data',
-          'win10_nvidia_quadro_p400_stable',
-        ],
-        'test_suites': {
-          'gtest_tests': 'gpu_win_gtests',
-          'gpu_telemetry_tests': 'gpu_common_win_telemetry_tests',
-          'isolated_scripts': 'rendering_desktop_representative_perf_tests_isolated_scripts',
-        },
-      },
     },
   },
   {
@@ -4943,19 +4928,6 @@
           'scripts': 'check_network_annotations_script',
         },
       },
-      # TODO(crbug.com/1004523) Delete 'Win x64 Builder Code Coverage' when
-      # coverage is turned on in 'Win x64 Builder' by default.
-      'Win x64 Builder Code Coverage': {
-        'mixins': [
-          'isolate_profile_data',
-        ],
-        'additional_compile_targets': [
-          'pdf_fuzzers'
-        ],
-        'test_suites': {
-          'scripts': 'check_network_annotations_script',
-        },
-      },
       # 'Win10 Tests x64' and 'Win7 Tests (1)' should have the same set of
       # additional_compile_targets and test_suites.
       # Added pixel tests on Win 10 only.
@@ -4980,20 +4952,6 @@
           'isolated_scripts': 'chromium_win_dbg_isolated_scripts',
         },
       },
-      # TODO(crbug.com/1004523) Delete 'Win10 Tests x64 Code Coverage' when
-      # coverage is turned on in 'Win10 Tests x64' by default.
-      'Win10 Tests x64 Code Coverage': {
-        'mixins': [
-          'isolate_profile_data',
-          'x86-64',
-          'win10',
-        ],
-        'test_suites': {
-          'gtest_tests': 'chromium_win10_gtests',
-          'isolated_scripts': 'chromium_win_rel_isolated_scripts',
-          'scripts': 'chromium_scripts',
-        },
-      },
       'Win7 (32) Tests': {
         'mixins': [
           'x86-32',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 26ed9b1..3d15a55 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1285,12 +1285,12 @@
             ],
             "experiments": [
                 {
-                    "name": "Enabled12_v1",
+                    "name": "Enabled10_v3",
                     "params": {
-                        "min": "12"
+                        "max_shared_ops": "10"
                     },
                     "enable_features": [
-                        "BrowserThreadPoolAdjustment",
+                        "CacheStorageParallelOps",
                         "CacheStorageSequence"
                     ]
                 }
diff --git a/third_party/android_sdk/cipd/build-tools/27.0.3.yaml b/third_party/android_sdk/cipd/build-tools/27.0.3.yaml
deleted file mode 100644
index 215832d..0000000
--- a/third_party/android_sdk/cipd/build-tools/27.0.3.yaml
+++ /dev/null
@@ -1,13 +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: chromium/third_party/android_sdk/public/build-tools/27.0.3
-description: build-tools Android SDK Build Tools
-root: ../../public/
-data:
-  - dir: build-tools/27.0.3
-# Some tools inspect their argv0 and don't handle CIPD's symlink structure
-# correctly. Install in copy mode so that they can find the other directories
-# relative to themselves.
-install_mode: copy
diff --git a/third_party/android_sdk/cipd/platforms/android-23.yaml b/third_party/android_sdk/cipd/platforms/android-23.yaml
deleted file mode 100644
index f86af72..0000000
--- a/third_party/android_sdk/cipd/platforms/android-23.yaml
+++ /dev/null
@@ -1,13 +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: chromium/third_party/android_sdk/public/platforms/android-23
-description: platforms Android SDK Platforms library
-root: ../../public/
-data:
-  - dir: platforms/android-23
-# Some tools inspect their argv0 and don't handle CIPD's symlink structure
-# correctly. Install in copy mode so that they can find the other directories
-# relative to themselves.
-install_mode: copy
diff --git a/third_party/android_sdk/cipd/platforms/android-28.yaml b/third_party/android_sdk/cipd/platforms/android-28.yaml
deleted file mode 100644
index 6cdd775bc..0000000
--- a/third_party/android_sdk/cipd/platforms/android-28.yaml
+++ /dev/null
@@ -1,13 +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: chromium/third_party/android_sdk/public/platforms/android-28
-description: platforms Android SDK Platforms library
-root: ../../public/
-data:
-  - dir: platforms/android-28
-# Some tools inspect their argv0 and don't handle CIPD's symlink structure
-# correctly. Install in copy mode so that they can find the other directories
-# relative to themselves.
-install_mode: copy
diff --git a/third_party/android_sdk/cipd/sources/android-28.yaml b/third_party/android_sdk/cipd/sources/android-28.yaml
deleted file mode 100644
index 0fbd67e..0000000
--- a/third_party/android_sdk/cipd/sources/android-28.yaml
+++ /dev/null
@@ -1,13 +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: chromium/third_party/android_sdk/public/sources/android-28
-description: sources Android SDK Sources library
-root: ../../public/
-data:
-  - dir: sources/android-28
-# Some tools inspect their argv0 and don't handle CIPD's symlink structure
-# correctly. Install in copy mode so that they can find the other directories
-# relative to themselves.
-install_mode: copy
diff --git a/third_party/android_sdk/cipd/system_images/android-23/google_apis/x86.yaml b/third_party/android_sdk/cipd/system_images/android-23/google_apis/x86.yaml
deleted file mode 100644
index b03e632..0000000
--- a/third_party/android_sdk/cipd/system_images/android-23/google_apis/x86.yaml
+++ /dev/null
@@ -1,9 +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: chromium/third_party/android_sdk/public/system-images/android-23/google_apis/x86
-description: system_images;android-23;google_apis;x86
-root: ../../../../public/
-data:
-  - dir: system-images/android-23/google_apis/x86
diff --git a/third_party/android_sdk/cipd/system_images/android-23/google_apis_playstore/x86.yaml b/third_party/android_sdk/cipd/system_images/android-23/google_apis_playstore/x86.yaml
deleted file mode 100644
index ca352202..0000000
--- a/third_party/android_sdk/cipd/system_images/android-23/google_apis_playstore/x86.yaml
+++ /dev/null
@@ -1,9 +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: chromium/third_party/android_sdk/public/system-images/android-23/google_apis_playstore/x86
-description: system_images;android-23;google_apis_playstore;x86
-root: ../../../../public/
-data:
-  - dir: system-images/android-23/google_apis_playstore/x86
diff --git a/third_party/android_sdk/cipd/system_images/android-28/google_apis/x86.yaml b/third_party/android_sdk/cipd/system_images/android-28/google_apis/x86.yaml
deleted file mode 100644
index fafba16..0000000
--- a/third_party/android_sdk/cipd/system_images/android-28/google_apis/x86.yaml
+++ /dev/null
@@ -1,9 +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: chromium/third_party/android_sdk/public/system-images/android-28/google_apis/x86
-description: system_images;android-28;google_apis;x86
-root: ../../../../public/
-data:
-  - dir: system-images/android-28/google_apis/x86
diff --git a/third_party/android_sdk/cipd/system_images/android-28/google_apis_playstore/x86.yaml b/third_party/android_sdk/cipd/system_images/android-28/google_apis_playstore/x86.yaml
deleted file mode 100644
index 7923ec5d..0000000
--- a/third_party/android_sdk/cipd/system_images/android-28/google_apis_playstore/x86.yaml
+++ /dev/null
@@ -1,9 +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: chromium/third_party/android_sdk/public/system-images/android-28/google_apis_playstore/x86
-description: system_images;android-28;google_apis_playstore;x86
-root: ../../../../public/
-data:
-  - dir: system-images/android-28/google_apis_playstore/x86
diff --git a/third_party/arcore-android-sdk-client/BUILD.gn b/third_party/arcore-android-sdk-client/BUILD.gn
index ee45c80..02d1046d 100644
--- a/third_party/arcore-android-sdk-client/BUILD.gn
+++ b/third_party/arcore-android-sdk-client/BUILD.gn
@@ -5,8 +5,8 @@
 import("//build/config/android/rules.gni")
 
 android_aar_prebuilt("com_google_ar_core_java") {
-  aar_path = "core-partner_chrome-1.10.0.aar"
-  info_path = "core-partner_chrome-1.10.0.info"
+  aar_path = "core-1.18.0.aar"
+  info_path = "core-1.18.0.info"
   extract_native_libraries = true
 
   ignore_proguard_configs = true
diff --git a/third_party/arcore-android-sdk-client/README.chromium b/third_party/arcore-android-sdk-client/README.chromium
index 6a437ec..d5fa82c 100644
--- a/third_party/arcore-android-sdk-client/README.chromium
+++ b/third_party/arcore-android-sdk-client/README.chromium
@@ -1,7 +1,7 @@
 Name: ARCore SDK client library for Chrome
 Short Name: com.google.ar:core-partner_chrome
 URL: https://developers.google.com/ar/develop/java/enable-arcore#dependencies
-Version: 1.10
+Version: 1.18
 License: Apache 2.0
 License File: LICENSE
 Security Critical: yes
@@ -27,6 +27,7 @@
  * https://www.apache.org/licenses/LICENSE-2.0.txt
 
 Changes:
+2020-07-13 - Upgraded SDK binaries to v1.18.
 2020-01-23 - Added override for proguard configs brought by ARCore SDK's .aar.
              This was achieved by extracting proguard.txt from
              core-partner_chrome-1.10.0.aar and commenting out offending
diff --git a/third_party/arcore-android-sdk-client/cipd.yaml b/third_party/arcore-android-sdk-client/cipd.yaml
index a34a1131..8783eedc 100644
--- a/third_party/arcore-android-sdk-client/cipd.yaml
+++ b/third_party/arcore-android-sdk-client/cipd.yaml
@@ -1,4 +1,4 @@
 package: chromium/third_party/arcore-android-sdk-client
 description: ARCore SDK client binaries.
 data:
-  - file: core-partner_chrome-1.10.0.aar
+  - file: core-1.18.0.aar
diff --git a/third_party/arcore-android-sdk-client/core-partner_chrome-1.10.0.info b/third_party/arcore-android-sdk-client/core-1.18.0.info
similarity index 98%
rename from third_party/arcore-android-sdk-client/core-partner_chrome-1.10.0.info
rename to third_party/arcore-android-sdk-client/core-1.18.0.info
index 3b68510..7a92cb8 100644
--- a/third_party/arcore-android-sdk-client/core-partner_chrome-1.10.0.info
+++ b/third_party/arcore-android-sdk-client/core-1.18.0.info
@@ -20,7 +20,7 @@
 ]
 resources = [
   "res/layout/__arcore_education.xml",
-  "res/raw/keep.xml",
+  "res/raw/keep_arcore.xml",
   "res/values-af/values.xml",
   "res/values-am/values.xml",
   "res/values-ar-rEG/values.xml",
diff --git a/third_party/arcore-android-sdk/README.chromium b/third_party/arcore-android-sdk/README.chromium
index 2097ddf9..e5c33b9e 100644
--- a/third_party/arcore-android-sdk/README.chromium
+++ b/third_party/arcore-android-sdk/README.chromium
@@ -1,7 +1,7 @@
 Name: ARCore SDK
 Short Name: arcore
 URL: https://github.com/google-ar/arcore-android-sdk
-Version: 1.5
+Version: 1.18
 License: Apache 2.0
 License File: LICENSE
 Security Critical: yes
@@ -10,20 +10,22 @@
 The ARCore Android SDK provides augmented reality capabilities to Android
 devices.
 
+This dependency is needed to obtain the header file that is required to use the
+ARCore SDK. The actual client binaries can be found in
+third_party/arcore-android-sdk-client.
+
 Local Modifications:
 Added BUILD.gn for compilation in chrome.
 
 Added the test-apks/ subdirectory for storing production versions of AR APKs,
 namely ArCore, for testing.
 
-IMPORTANT: make sure to change chrome/android/java/AndroidManifest.xml
-com.google.ar.core.min_apk_version attribute if a newer version of the
-ARCore APK is required to maintain compatibility with this SDK.
-
 The LICENSE file is taken from
  * https://github.com/google-ar/arcore-unity-sdk/blob/master/LICENSE
 
 Changes:
+2020-07-13 - Upgrade SDK to v1.18.
+             Upgrade test-apks/arcore_current.apk to v1.18.
 2019-12-18 - Upgrade test-apks/arcore_current.apk to v1.14.
 2019-07-22 - Upgrade test-apks/arcore_current.apk to v1.10.
 2019-07-18 - Upgrade SDK to v1.10.
diff --git a/third_party/arcore-android-sdk/test-apks/arcore/apk_version_history.txt b/third_party/arcore-android-sdk/test-apks/arcore/apk_version_history.txt
index 0a54304b..048e319 100644
--- a/third_party/arcore-android-sdk/test-apks/arcore/apk_version_history.txt
+++ b/third_party/arcore-android-sdk/test-apks/arcore/apk_version_history.txt
@@ -4,3 +4,4 @@
 v1.8 86552409cbb27f39204012cac7accf27a42b63ec
 v1.10 0dbc7e2063965f19143b0db577ce4b10bcbe1e9b
 v1.14 7f864ce993380af9c52c12e6ec69b1bfe1c12cc6
+v1.18 2f386ac4b7b635354aa8390cc931e2fcc0fb57fc
\ No newline at end of file
diff --git a/third_party/arcore-android-sdk/test-apks/arcore/arcore_current.apk.sha1 b/third_party/arcore-android-sdk/test-apks/arcore/arcore_current.apk.sha1
index d3b7d93..8c51012 100644
--- a/third_party/arcore-android-sdk/test-apks/arcore/arcore_current.apk.sha1
+++ b/third_party/arcore-android-sdk/test-apks/arcore/arcore_current.apk.sha1
@@ -1 +1 @@
-7f864ce993380af9c52c12e6ec69b1bfe1c12cc6
\ No newline at end of file
+2f386ac4b7b635354aa8390cc931e2fcc0fb57fc
\ No newline at end of file
diff --git a/third_party/blink/renderer/bindings/modules/v8/generated.gni b/third_party/blink/renderer/bindings/modules/v8/generated.gni
index bc9cd57..2979272 100644
--- a/third_party/blink/renderer/bindings/modules/v8/generated.gni
+++ b/third_party/blink/renderer/bindings/modules/v8/generated.gni
@@ -99,6 +99,8 @@
   "$bindings_modules_v8_output_dir/string_or_string_sequence_or_constrain_dom_string_parameters.h",
   "$bindings_modules_v8_output_dir/string_or_unsigned_long.cc",
   "$bindings_modules_v8_output_dir/string_or_unsigned_long.h",
+  "$bindings_modules_v8_output_dir/uint32_array_or_unsigned_long_sequence.cc",
+  "$bindings_modules_v8_output_dir/uint32_array_or_unsigned_long_sequence.h",
   "$bindings_modules_v8_output_dir/unsigned_long_or_unsigned_long_sequence.cc",
   "$bindings_modules_v8_output_dir/unsigned_long_or_unsigned_long_sequence.h",
   "$bindings_modules_v8_output_dir/unsigned_long_enforce_range_sequence_or_gpu_extent_3d_dict.cc",
diff --git a/third_party/blink/renderer/core/animation/animation_test_helper.cc b/third_party/blink/renderer/core/animation/animation_test_helper.cc
index 528c17f27..c30e8111 100644
--- a/third_party/blink/renderer/core/animation/animation_test_helper.cc
+++ b/third_party/blink/renderer/core/animation/animation_test_helper.cc
@@ -71,22 +71,13 @@
   auto style = ComputedStyle::Create();
   StyleResolverState state(document, *element, style.get(), style.get());
   state.SetStyle(style);
-  if (RuntimeEnabledFeatures::CSSCascadeEnabled()) {
-    // We must apply the animation effects via StyleCascade when the cascade
-    // is enabled.
-    StyleCascade cascade(state);
 
-    ActiveInterpolationsMap map;
-    map.Set(PropertyHandle("--unused"), interpolations);
+  ActiveInterpolationsMap map;
+  map.Set(PropertyHandle("--unused"), interpolations);
 
-    cascade.AddInterpolations(&map, CascadeOrigin::kAnimation);
-    cascade.Apply();
-  } else {
-    CSSInterpolationTypesMap map(state.GetDocument().GetPropertyRegistry(),
-                                 state.GetDocument());
-    CSSInterpolationEnvironment environment(map, state, nullptr);
-    InvalidatableInterpolation::ApplyStack(interpolations, environment);
-  }
+  StyleCascade cascade(state);
+  cascade.AddInterpolations(&map, CascadeOrigin::kAnimation);
+  cascade.Apply();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/animation/css_default_interpolation_type.cc b/third_party/blink/renderer/core/animation/css_default_interpolation_type.cc
index f6de4f0..95656fdb 100644
--- a/third_party/blink/renderer/core/animation/css_default_interpolation_type.cc
+++ b/third_party/blink/renderer/core/animation/css_default_interpolation_type.cc
@@ -30,12 +30,10 @@
     return nullptr;
   }
 
-  if (RuntimeEnabledFeatures::CSSCascadeEnabled()) {
-    css_value = To<CSSInterpolationEnvironment>(environment)
-                    .Resolve(GetProperty(), css_value);
-    if (!css_value)
-      return nullptr;
-  }
+  css_value = To<CSSInterpolationEnvironment>(environment)
+                  .Resolve(GetProperty(), css_value);
+  if (!css_value)
+    return nullptr;
 
   return InterpolationValue(std::make_unique<InterpolableList>(0),
                             CSSDefaultNonInterpolableValue::Create(css_value));
diff --git a/third_party/blink/renderer/core/animation/css_interpolation_environment.cc b/third_party/blink/renderer/core/animation/css_interpolation_environment.cc
index 237c8b1a..d0a2bb7 100644
--- a/third_party/blink/renderer/core/animation/css_interpolation_environment.cc
+++ b/third_party/blink/renderer/core/animation/css_interpolation_environment.cc
@@ -13,7 +13,6 @@
 const CSSValue* CSSInterpolationEnvironment::Resolve(
     const PropertyHandle& property,
     const CSSValue* value) const {
-  DCHECK(RuntimeEnabledFeatures::CSSCascadeEnabled());
   DCHECK(cascade_);
   DCHECK(cascade_resolver_);
   if (!value)
diff --git a/third_party/blink/renderer/core/animation/css_interpolation_environment.h b/third_party/blink/renderer/core/animation/css_interpolation_environment.h
index 75764d5..ee0028f30 100644
--- a/third_party/blink/renderer/core/animation/css_interpolation_environment.h
+++ b/third_party/blink/renderer/core/animation/css_interpolation_environment.h
@@ -7,38 +7,24 @@
 
 #include "third_party/blink/renderer/core/animation/interpolation_environment.h"
 #include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 
 namespace blink {
 
 class CascadeResolver;
 class ComputedStyle;
-class CSSVariableResolver;
 class StyleCascade;
 
 class CSSInterpolationEnvironment : public InterpolationEnvironment {
  public:
   explicit CSSInterpolationEnvironment(const InterpolationTypesMap& map,
                                        StyleResolverState& state,
-                                       CSSVariableResolver* variable_resolver)
-      : InterpolationEnvironment(map),
-        state_(&state),
-        style_(state.Style()),
-        variable_resolver_(variable_resolver) {
-    DCHECK(!RuntimeEnabledFeatures::CSSCascadeEnabled());
-  }
-
-  explicit CSSInterpolationEnvironment(const InterpolationTypesMap& map,
-                                       StyleResolverState& state,
                                        StyleCascade* cascade,
                                        CascadeResolver* cascade_resolver)
       : InterpolationEnvironment(map),
         state_(&state),
         style_(state.Style()),
         cascade_(cascade),
-        cascade_resolver_(cascade_resolver) {
-    DCHECK(RuntimeEnabledFeatures::CSSCascadeEnabled());
-  }
+        cascade_resolver_(cascade_resolver) {}
 
   explicit CSSInterpolationEnvironment(const InterpolationTypesMap& map,
                                        const ComputedStyle& style)
@@ -60,25 +46,12 @@
     return *style_;
   }
 
-  bool HasVariableResolver() const {
-    DCHECK(!RuntimeEnabledFeatures::CSSCascadeEnabled());
-    return variable_resolver_;
-  }
-
-  // TODO(crbug.com/985023): This effective violates const.
-  CSSVariableResolver& VariableResolver() const {
-    DCHECK(!RuntimeEnabledFeatures::CSSCascadeEnabled());
-    DCHECK(HasVariableResolver());
-    return *variable_resolver_;
-  }
-
   // TODO(crbug.com/985023): This effective violates const.
   const CSSValue* Resolve(const PropertyHandle&, const CSSValue*) const;
 
  private:
   StyleResolverState* state_ = nullptr;
   const ComputedStyle* style_ = nullptr;
-  CSSVariableResolver* variable_resolver_ = nullptr;
   StyleCascade* cascade_ = nullptr;
   CascadeResolver* cascade_resolver_ = nullptr;
 };
diff --git a/third_party/blink/renderer/core/animation/css_interpolation_type.cc b/third_party/blink/renderer/core/animation/css_interpolation_type.cc
index f1caa26..ffe1dab 100644
--- a/third_party/blink/renderer/core/animation/css_interpolation_type.cc
+++ b/third_party/blink/renderer/core/animation/css_interpolation_type.cc
@@ -21,7 +21,6 @@
 #include "third_party/blink/renderer/core/css/parser/css_tokenizer.h"
 #include "third_party/blink/renderer/core/css/properties/css_property.h"
 #include "third_party/blink/renderer/core/css/property_registration.h"
-#include "third_party/blink/renderer/core/css/resolver/css_variable_resolver.h"
 #include "third_party/blink/renderer/core/css/resolver/style_builder.h"
 #include "third_party/blink/renderer/core/css/resolver/style_cascade.h"
 #include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h"
@@ -46,16 +45,8 @@
     const auto& css_environment = To<CSSInterpolationEnvironment>(environment);
     // TODO(alancutter): Just check the variables referenced instead of doing a
     // full CSSValue resolve.
-    bool omit_animation_tainted = false;
-    const CSSValue* resolved_value = nullptr;
-    if (RuntimeEnabledFeatures::CSSCascadeEnabled()) {
-      resolved_value = css_environment.Resolve(
-          PropertyHandle(CSSProperty::Get(property_)), variable_reference_);
-    } else {
-      const StyleResolverState& state = css_environment.GetState();
-      resolved_value = CSSVariableResolver(state).ResolveVariableReferences(
-          property_, *variable_reference_, omit_animation_tainted);
-    }
+    const CSSValue* resolved_value = css_environment.Resolve(
+        PropertyHandle(CSSProperty::Get(property_)), variable_reference_);
     return DataEquivalent(resolved_value_.Get(), resolved_value);
   }
 
@@ -106,21 +97,12 @@
   bool IsValid(const InterpolationEnvironment& environment,
                const InterpolationValue&) const final {
     const auto& css_environment = To<CSSInterpolationEnvironment>(environment);
+    const CSSValue* resolved = css_environment.Resolve(
+        PropertyHandle(declaration_->GetName()), declaration_);
     scoped_refptr<CSSVariableData> resolved_tokens = nullptr;
-    if (RuntimeEnabledFeatures::CSSCascadeEnabled()) {
-      const CSSValue* resolved = css_environment.Resolve(
-          PropertyHandle(declaration_->GetName()), declaration_);
-      if (const auto* decl = DynamicTo<CSSCustomPropertyDeclaration>(resolved))
-        resolved_tokens = decl->Value();
-    } else {
-      DCHECK(css_environment.HasVariableResolver());
-      bool cycle_detected = false;
-      resolved_tokens = To<CSSInterpolationEnvironment>(environment)
-                            .VariableResolver()
-                            .ResolveCustomPropertyAnimationKeyframe(
-                                *declaration_, cycle_detected);
-      DCHECK(!cycle_detected);
-    }
+    if (const auto* decl = DynamicTo<CSSCustomPropertyDeclaration>(resolved))
+      resolved_tokens = decl->Value();
+
     return DataEquivalent(resolved_tokens, resolved_tokens_);
   }
 
@@ -193,14 +175,8 @@
 
   if (value->IsVariableReferenceValue() ||
       value->IsPendingSubstitutionValue()) {
-    const CSSValue* resolved_value = nullptr;
-    if (RuntimeEnabledFeatures::CSSCascadeEnabled()) {
-      resolved_value = css_environment.Resolve(GetProperty(), value);
-    } else {
-      bool omit_animation_tainted = false;
-      resolved_value = CSSVariableResolver(state).ResolveVariableReferences(
-          CssProperty().PropertyID(), *value, omit_animation_tainted);
-    }
+    const CSSValue* resolved_value =
+        css_environment.Resolve(GetProperty(), value);
 
     DCHECK(resolved_value);
     conversion_checkers.push_back(std::make_unique<ResolvedVariableChecker>(
@@ -238,118 +214,66 @@
   const AtomicString& name = declaration.GetName();
   DCHECK_EQ(GetProperty().CustomPropertyName(), name);
 
-  if (RuntimeEnabledFeatures::CSSCascadeEnabled()) {
-    const CSSValue* value = &declaration;
-    value = css_environment.Resolve(GetProperty(), value);
-    DCHECK(value) << "CSSVarCycleInterpolationType should have handled nullptr";
+  const CSSValue* value = &declaration;
+  value = css_environment.Resolve(GetProperty(), value);
+  DCHECK(value) << "CSSVarCycleInterpolationType should have handled nullptr";
 
-    if (declaration.IsRevert()) {
-      DCHECK(RuntimeEnabledFeatures::CSSRevertEnabled());
-      conversion_checkers.push_back(
-          std::make_unique<RevertChecker>(GetProperty(), value));
-    }
-    if (const auto* resolved_declaration =
-            DynamicTo<CSSCustomPropertyDeclaration>(value)) {
-      // If Resolve returned a different CSSCustomPropertyDeclaration, var()
-      // references were substituted.
-      if (resolved_declaration != &declaration) {
-        conversion_checkers.push_back(
-            std::make_unique<ResolvedRegisteredCustomPropertyChecker>(
-                declaration, resolved_declaration->Value()));
-      }
-    }
-
-    // Unfortunately we transport CSS-wide keywords inside the
-    // CSSCustomPropertyDeclaration. Expand those keywords into real CSSValues
-    // if present.
-    bool is_inherited = Registration().Inherits();
-    if (const auto* resolved_declaration =
-            DynamicTo<CSSCustomPropertyDeclaration>(value)) {
-      if (resolved_declaration->IsInitial(is_inherited))
-        value = CSSInitialValue::Create();
-      else if (resolved_declaration->IsInherit(is_inherited))
-        value = CSSInheritedValue::Create();
-    }
-
-    // Handle CSS-wide keywords (except 'revert', which should have been
-    // handled already).
-    DCHECK(!value->IsRevertValue());
-    if (value->IsInitialValue() || (value->IsUnsetValue() && !is_inherited)) {
-      value = Registration().Initial();
-    } else if (value->IsInheritedValue() ||
-               (value->IsUnsetValue() && is_inherited)) {
-      value = state.ParentStyle()->GetVariableValue(name, is_inherited);
-      if (!value) {
-        value = Registration().Initial();
-      }
-      conversion_checkers.push_back(
-          std::make_unique<InheritedCustomPropertyChecker>(
-              name, is_inherited, value, Registration().Initial()));
-    }
-
-    if (const auto* resolved_declaration =
-            DynamicTo<CSSCustomPropertyDeclaration>(value)) {
-      DCHECK(resolved_declaration->Value());
-      value = resolved_declaration->Value()->ParseForSyntax(
-          registration_->Syntax(),
-          state.GetDocument().GetExecutionContext()->GetSecureContextMode());
-      if (!value)
-        return nullptr;
-    }
-
-    DCHECK(value);
-    return MaybeConvertValue(*value, &state, conversion_checkers);
-  }
-
-  if (!declaration.Value()) {
-    bool is_inherited_property = Registration().Inherits();
-    DCHECK(declaration.IsInitial(is_inherited_property) ||
-           declaration.IsInherit(is_inherited_property));
-
-    const CSSValue* value = nullptr;
-    if (declaration.IsInitial(is_inherited_property)) {
-      value = Registration().Initial();
-    } else {
-      value =
-          state.ParentStyle()->GetVariableValue(name, is_inherited_property);
-      if (!value) {
-        value = Registration().Initial();
-      }
-      conversion_checkers.push_back(
-          std::make_unique<InheritedCustomPropertyChecker>(
-              name, is_inherited_property, value, Registration().Initial()));
-    }
-    if (!value) {
-      return nullptr;
-    }
-
-    return MaybeConvertValue(*value, &state, conversion_checkers);
-  }
-
-  scoped_refptr<CSSVariableData> resolved_tokens;
-  if (declaration.Value()->NeedsVariableResolution()) {
-    CSSVariableResolver& variable_resolver = css_environment.VariableResolver();
-    bool cycle_detected = false;
-    resolved_tokens = variable_resolver.ResolveCustomPropertyAnimationKeyframe(
-        declaration, cycle_detected);
-    DCHECK(!cycle_detected);
+  if (declaration.IsRevert()) {
+    DCHECK(RuntimeEnabledFeatures::CSSRevertEnabled());
     conversion_checkers.push_back(
-        std::make_unique<ResolvedRegisteredCustomPropertyChecker>(
-            declaration, resolved_tokens));
-  } else {
-    resolved_tokens = declaration.Value();
+        std::make_unique<RevertChecker>(GetProperty(), value));
   }
-  const CSSValue* resolved_value =
-      resolved_tokens
-          ? resolved_tokens->ParseForSyntax(registration_->Syntax(),
-                                            state.GetDocument()
-                                                .GetExecutionContext()
-                                                ->GetSecureContextMode())
-          : nullptr;
-  if (!resolved_value) {
-    return nullptr;
+  if (const auto* resolved_declaration =
+          DynamicTo<CSSCustomPropertyDeclaration>(value)) {
+    // If Resolve returned a different CSSCustomPropertyDeclaration, var()
+    // references were substituted.
+    if (resolved_declaration != &declaration) {
+      conversion_checkers.push_back(
+          std::make_unique<ResolvedRegisteredCustomPropertyChecker>(
+              declaration, resolved_declaration->Value()));
+    }
   }
-  return MaybeConvertValue(*resolved_value, &state, conversion_checkers);
+
+  // Unfortunately we transport CSS-wide keywords inside the
+  // CSSCustomPropertyDeclaration. Expand those keywords into real CSSValues
+  // if present.
+  bool is_inherited = Registration().Inherits();
+  if (const auto* resolved_declaration =
+          DynamicTo<CSSCustomPropertyDeclaration>(value)) {
+    if (resolved_declaration->IsInitial(is_inherited))
+      value = CSSInitialValue::Create();
+    else if (resolved_declaration->IsInherit(is_inherited))
+      value = CSSInheritedValue::Create();
+  }
+
+  // Handle CSS-wide keywords (except 'revert', which should have been
+  // handled already).
+  DCHECK(!value->IsRevertValue());
+  if (value->IsInitialValue() || (value->IsUnsetValue() && !is_inherited)) {
+    value = Registration().Initial();
+  } else if (value->IsInheritedValue() ||
+             (value->IsUnsetValue() && is_inherited)) {
+    value = state.ParentStyle()->GetVariableValue(name, is_inherited);
+    if (!value) {
+      value = Registration().Initial();
+    }
+    conversion_checkers.push_back(
+        std::make_unique<InheritedCustomPropertyChecker>(
+            name, is_inherited, value, Registration().Initial()));
+  }
+
+  if (const auto* resolved_declaration =
+          DynamicTo<CSSCustomPropertyDeclaration>(value)) {
+    DCHECK(resolved_declaration->Value());
+    value = resolved_declaration->Value()->ParseForSyntax(
+        registration_->Syntax(),
+        state.GetDocument().GetExecutionContext()->GetSecureContextMode());
+    if (!value)
+      return nullptr;
+  }
+
+  DCHECK(value);
+  return MaybeConvertValue(*value, &state, conversion_checkers);
 }
 
 InterpolationValue CSSInterpolationType::MaybeConvertUnderlyingValue(
@@ -407,25 +331,12 @@
       needs_variable_resolution, KURL(), WTF::TextEncoding());
   const PropertyHandle property = GetProperty();
 
-  if (RuntimeEnabledFeatures::CSSCascadeEnabled()) {
-    // When cascade is enabled, we need to go through the StyleBuilder,
-    // since the computed value is produced during ApplyProperty. (Without
-    // this, we'd end up with values like 10em on the computed style).
-    //
-    // TODO(andruud): Avoid making the CSSCustomPropertyDeclaration by allowing
-    // any CSSValue in CustomProperty::ApplyValue.
-    const CSSValue* value = MakeGarbageCollected<CSSCustomPropertyDeclaration>(
-        property.CustomPropertyName(), std::move(variable_data));
-    StyleBuilder::ApplyProperty(GetProperty().GetCSSPropertyName(), state,
-                                *value);
-    return;
-  }
-
-  ComputedStyle& style = *state.Style();
-  const AtomicString& property_name = property.CustomPropertyName();
-  bool inherits = Registration().Inherits();
-  style.SetVariableData(property_name, std::move(variable_data), inherits);
-  style.SetVariableValue(property_name, css_value, inherits);
+  // TODO(andruud): Avoid making the CSSCustomPropertyDeclaration by allowing
+  // any CSSValue in CustomProperty::ApplyValue.
+  const CSSValue* value = MakeGarbageCollected<CSSCustomPropertyDeclaration>(
+      property.CustomPropertyName(), std::move(variable_data));
+  StyleBuilder::ApplyProperty(GetProperty().GetCSSPropertyName(), state,
+                              *value);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/animation/css_var_cycle_interpolation_type.cc b/third_party/blink/renderer/core/animation/css_var_cycle_interpolation_type.cc
index 6aba5ed..ecf85c20 100644
--- a/third_party/blink/renderer/core/animation/css_var_cycle_interpolation_type.cc
+++ b/third_party/blink/renderer/core/animation/css_var_cycle_interpolation_type.cc
@@ -12,7 +12,6 @@
 #include "third_party/blink/renderer/core/animation/string_keyframe.h"
 #include "third_party/blink/renderer/core/css/css_custom_property_declaration.h"
 #include "third_party/blink/renderer/core/css/property_registration.h"
-#include "third_party/blink/renderer/core/css/resolver/css_variable_resolver.h"
 #include "third_party/blink/renderer/core/css/resolver/style_builder.h"
 #include "third_party/blink/renderer/core/css/resolver/style_cascade.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
@@ -29,14 +28,8 @@
   bool IsValid(const InterpolationEnvironment& environment,
                const InterpolationValue&) const final {
     const auto& css_environment = To<CSSInterpolationEnvironment>(environment);
-    bool cycle_detected = false;
-    if (RuntimeEnabledFeatures::CSSCascadeEnabled()) {
-      cycle_detected = !css_environment.Resolve(
-          PropertyHandle(declaration_->GetName()), declaration_);
-    } else {
-      css_environment.VariableResolver().ResolveCustomPropertyAnimationKeyframe(
-          *declaration_, cycle_detected);
-    }
+    bool cycle_detected = !css_environment.Resolve(
+        PropertyHandle(declaration_->GetName()), declaration_);
     return cycle_detected == cycle_detected_;
   }
 
@@ -71,14 +64,7 @@
 
   const auto& css_environment = To<CSSInterpolationEnvironment>(environment);
 
-  bool cycle_detected = false;
-  if (RuntimeEnabledFeatures::CSSCascadeEnabled()) {
-    cycle_detected = !css_environment.Resolve(GetProperty(), &declaration);
-  } else {
-    css_environment.VariableResolver().ResolveCustomPropertyAnimationKeyframe(
-        declaration, cycle_detected);
-  }
-
+  bool cycle_detected = !css_environment.Resolve(GetProperty(), &declaration);
   conversion_checkers.push_back(
       std::make_unique<CycleChecker>(declaration, cycle_detected));
   return cycle_detected ? CreateCycleDetectedValue() : nullptr;
diff --git a/third_party/blink/renderer/core/animation/transition_interpolation.cc b/third_party/blink/renderer/core/animation/transition_interpolation.cc
index 5cea66c..caf0b90 100644
--- a/third_party/blink/renderer/core/animation/transition_interpolation.cc
+++ b/third_party/blink/renderer/core/animation/transition_interpolation.cc
@@ -49,15 +49,9 @@
 void TransitionInterpolation::Apply(StyleResolverState& state) const {
   CSSInterpolationTypesMap map(state.GetDocument().GetPropertyRegistry(),
                                state.GetDocument());
-  if (RuntimeEnabledFeatures::CSSCascadeEnabled()) {
-    CSSInterpolationEnvironment environment(map, state, nullptr, nullptr);
-    type_.Apply(CurrentInterpolableValue(), CurrentNonInterpolableValue(),
-                environment);
-  } else {
-    CSSInterpolationEnvironment environment(map, state, nullptr);
-    type_.Apply(CurrentInterpolableValue(), CurrentNonInterpolableValue(),
-                environment);
-  }
+  CSSInterpolationEnvironment environment(map, state, nullptr, nullptr);
+  type_.Apply(CurrentInterpolableValue(), CurrentNonInterpolableValue(),
+              environment);
 }
 
 std::unique_ptr<TypedInterpolationValue>
diff --git a/third_party/blink/renderer/core/animation/transition_keyframe.cc b/third_party/blink/renderer/core/animation/transition_keyframe.cc
index 9360706e..599e0d5d 100644
--- a/third_party/blink/renderer/core/animation/transition_keyframe.cc
+++ b/third_party/blink/renderer/core/animation/transition_keyframe.cc
@@ -17,7 +17,6 @@
 #include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 
 namespace blink {
 
@@ -48,16 +47,9 @@
   StyleResolverState state(document, *element);
   state.SetStyle(ComputedStyle::Create());
   CSSInterpolationTypesMap map(document.GetPropertyRegistry(), document);
-
-  if (RuntimeEnabledFeatures::CSSCascadeEnabled()) {
-    CSSInterpolationEnvironment environment(map, state, nullptr, nullptr);
-    value_->GetType().Apply(value_->GetInterpolableValue(),
-                            value_->GetNonInterpolableValue(), environment);
-  } else {
-    CSSInterpolationEnvironment environment(map, state, nullptr);
-    value_->GetType().Apply(value_->GetInterpolableValue(),
-                            value_->GetNonInterpolableValue(), environment);
-  }
+  CSSInterpolationEnvironment environment(map, state, nullptr, nullptr);
+  value_->GetType().Apply(value_->GetInterpolableValue(),
+                          value_->GetNonInterpolableValue(), environment);
 
   const ComputedStyle* style = state.Style();
   String property_value =
diff --git a/third_party/blink/renderer/core/css/BUILD.gn b/third_party/blink/renderer/core/css/BUILD.gn
index 0c1e1cb..5a9abb4 100644
--- a/third_party/blink/renderer/core/css/BUILD.gn
+++ b/third_party/blink/renderer/core/css/BUILD.gn
@@ -485,10 +485,6 @@
     "resolver/css_property_priority.h",
     "resolver/css_to_style_map.cc",
     "resolver/css_to_style_map.h",
-    "resolver/css_variable_animator.cc",
-    "resolver/css_variable_animator.h",
-    "resolver/css_variable_resolver.cc",
-    "resolver/css_variable_resolver.h",
     "resolver/element_resolve_context.cc",
     "resolver/element_resolve_context.h",
     "resolver/element_style_resources.cc",
@@ -675,7 +671,6 @@
     "resolver/cascade_map_test.cc",
     "resolver/cascade_priority_test.cc",
     "resolver/css_variable_data_test.cc",
-    "resolver/css_variable_resolver_test.cc",
     "resolver/font_builder_test.cc",
     "resolver/font_style_resolver_test.cc",
     "resolver/match_result_test.cc",
diff --git a/third_party/blink/renderer/core/css/properties/longhands/custom_property.cc b/third_party/blink/renderer/core/css/properties/longhands/custom_property.cc
index 11fcb59c..23cca084 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/custom_property.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/custom_property.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/core/css/properties/longhands/custom_property.h"
 
 #include "third_party/blink/renderer/core/css/css_custom_property_declaration.h"
+#include "third_party/blink/renderer/core/css/parser/css_parser_context.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser_local_context.h"
 #include "third_party/blink/renderer/core/css/parser/css_variable_parser.h"
 #include "third_party/blink/renderer/core/css/property_registration.h"
@@ -81,7 +82,6 @@
 void CustomProperty::ApplyValue(StyleResolverState& state,
                                 const CSSValue& value) const {
   if (value.IsInvalidVariableValue()) {
-    DCHECK(RuntimeEnabledFeatures::CSSCascadeEnabled());
     state.Style()->SetVariableData(name_, nullptr, IsInherited());
     if (registration_)
       state.Style()->SetVariableValue(name_, nullptr, IsInherited());
@@ -103,14 +103,6 @@
   } else if (inherit) {
     ApplyInherit(state);
   } else {
-    if (!RuntimeEnabledFeatures::CSSCascadeEnabled()) {
-      state.Style()->SetVariableData(name_, declaration.Value(),
-                                     is_inherited_property);
-      if (registration_)
-        state.Style()->SetVariableValue(name_, nullptr, is_inherited_property);
-      return;
-    }
-
     scoped_refptr<CSSVariableData> data = declaration.Value();
     DCHECK(!data->NeedsVariableResolution());
 
diff --git a/third_party/blink/renderer/core/css/properties/longhands/custom_property_test.cc b/third_party/blink/renderer/core/css/properties/longhands/custom_property_test.cc
index 1b206d5..9cc5744 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/custom_property_test.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/custom_property_test.cc
@@ -7,6 +7,7 @@
 #include "third_party/blink/renderer/core/css/css_custom_property_declaration.h"
 #include "third_party/blink/renderer/core/css/css_primitive_value.h"
 #include "third_party/blink/renderer/core/css/css_test_helpers.h"
+#include "third_party/blink/renderer/core/css/parser/css_parser_context.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser_local_context.h"
 #include "third_party/blink/renderer/core/css/parser/css_tokenizer.h"
 #include "third_party/blink/renderer/core/dom/node_computed_style.h"
diff --git a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
index a684758..4000c28 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
@@ -1464,28 +1464,14 @@
 }
 
 void Color::ApplyInitial(StyleResolverState& state) const {
-  if (!RuntimeEnabledFeatures::CSSCascadeEnabled()) {
-    state.SetCascadedColorValue(
-        CSSIdentifierValue::Create(CSSValueID::kInitial));
-    return;
-  }
   state.Style()->SetColor(state.Style()->InitialColorForColorScheme());
 }
 
 void Color::ApplyInherit(StyleResolverState& state) const {
-  if (!RuntimeEnabledFeatures::CSSCascadeEnabled()) {
-    state.SetCascadedColorValue(
-        CSSIdentifierValue::Create(CSSValueID::kInherit));
-    return;
-  }
   state.Style()->SetColor(state.ParentStyle()->GetColor());
 }
 
 void Color::ApplyValue(StyleResolverState& state, const CSSValue& value) const {
-  if (!RuntimeEnabledFeatures::CSSCascadeEnabled()) {
-    state.SetCascadedColorValue(&value);
-    return;
-  }
   // As per the spec, 'color: currentColor' is treated as 'color: inherit'
   auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
   if (identifier_value &&
@@ -1494,7 +1480,6 @@
     return;
   }
   if (auto* initial_color_value = DynamicTo<CSSInitialColorValue>(value)) {
-    DCHECK(RuntimeEnabledFeatures::CSSCascadeEnabled());
     DCHECK_EQ(state.GetElement(), state.GetDocument().documentElement());
     state.Style()->SetColor(state.Style()->InitialColorForColorScheme());
     return;
@@ -2883,31 +2868,17 @@
 }
 
 void InternalVisitedColor::ApplyInitial(StyleResolverState& state) const {
-  if (!RuntimeEnabledFeatures::CSSCascadeEnabled()) {
-    state.SetCascadedVisitedColorValue(
-        CSSIdentifierValue::Create(CSSValueID::kInitial));
-    return;
-  }
   state.Style()->SetInternalVisitedColor(
       state.Style()->InitialColorForColorScheme());
 }
 
 void InternalVisitedColor::ApplyInherit(StyleResolverState& state) const {
-  if (!RuntimeEnabledFeatures::CSSCascadeEnabled()) {
-    state.SetCascadedVisitedColorValue(
-        CSSIdentifierValue::Create(CSSValueID::kInherit));
-    return;
-  }
   auto color = state.ParentStyle()->GetColor();
   state.Style()->SetInternalVisitedColor(color);
 }
 
 void InternalVisitedColor::ApplyValue(StyleResolverState& state,
                                       const CSSValue& value) const {
-  if (!RuntimeEnabledFeatures::CSSCascadeEnabled()) {
-    state.SetCascadedVisitedColorValue(&value);
-    return;
-  }
   auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
   if (identifier_value &&
       identifier_value->GetValueID() == CSSValueID::kCurrentcolor) {
@@ -2915,7 +2886,6 @@
     return;
   }
   if (auto* initial_color_value = DynamicTo<CSSInitialColorValue>(value)) {
-    DCHECK(RuntimeEnabledFeatures::CSSCascadeEnabled());
     DCHECK_EQ(state.GetElement(), state.GetDocument().documentElement());
     state.Style()->SetInternalVisitedColor(
         state.Style()->InitialColorForColorScheme());
diff --git a/third_party/blink/renderer/core/css/property_registration.h b/third_party/blink/renderer/core/css/property_registration.h
index 1fa15b0..cff1e3e 100644
--- a/third_party/blink/renderer/core/css/property_registration.h
+++ b/third_party/blink/renderer/core/css/property_registration.h
@@ -66,9 +66,6 @@
   const scoped_refptr<CSSVariableData> initial_variable_data_;
   const InterpolationTypes interpolation_types_;
   mutable bool referenced_;
-
-  FRIEND_TEST_ALL_PREFIXES(CSSVariableResolverTest,
-                           NeedsResolutionClearedByResolver);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/resolver/css_variable_animator.cc b/third_party/blink/renderer/core/css/resolver/css_variable_animator.cc
deleted file mode 100644
index f137cab..0000000
--- a/third_party/blink/renderer/core/css/resolver/css_variable_animator.cc
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/css/resolver/css_variable_animator.h"
-
-#include "third_party/blink/renderer/core/animation/css_interpolation_environment.h"
-#include "third_party/blink/renderer/core/animation/css_interpolation_types_map.h"
-#include "third_party/blink/renderer/core/animation/invalidatable_interpolation.h"
-#include "third_party/blink/renderer/core/animation/transition_interpolation.h"
-
-namespace blink {
-
-namespace {
-
-HashSet<PropertyHandle> CollectPending(const CSSAnimationUpdate& update) {
-  HashSet<PropertyHandle> pending;
-  for (const auto& entry : update.ActiveInterpolationsForCustomAnimations())
-    pending.insert(entry.key);
-  for (const auto& entry : update.ActiveInterpolationsForCustomTransitions())
-    pending.insert(entry.key);
-  return pending;
-}
-
-const ActiveInterpolations& ActiveInterpolationsForCustomProperty(
-    const CSSAnimationUpdate& update,
-    const PropertyHandle& property) {
-  // Interpolations will never be found in both animations_map and
-  // transitions_map. This condition is ensured by
-  // CSSAnimations::CalculateTransitionUpdateForProperty().
-  const ActiveInterpolationsMap& animations_map =
-      update.ActiveInterpolationsForCustomAnimations();
-  const ActiveInterpolationsMap& transitions_map =
-      update.ActiveInterpolationsForCustomTransitions();
-  const auto& animation = animations_map.find(property);
-  if (animation != animations_map.end()) {
-    DCHECK_EQ(transitions_map.find(property), transitions_map.end());
-    return animation->value;
-  }
-  const auto& transition = transitions_map.find(property);
-  DCHECK_NE(transition, transitions_map.end());
-  return transition->value;
-}
-
-}  // namespace
-
-CSSVariableAnimator::CSSVariableAnimator(StyleResolverState& state)
-    : CSSVariableResolver(state),
-      state_(state),
-      update_(state.AnimationUpdate()),
-      pending_properties_(CollectPending(update_)) {}
-
-void CSSVariableAnimator::ApplyAll() {
-  while (!pending_properties_.IsEmpty()) {
-    PropertyHandle property = *pending_properties_.begin();
-    Apply(property);
-    DCHECK(!pending_properties_.Contains(property));
-  }
-}
-
-void CSSVariableAnimator::ApplyAnimation(const AtomicString& name) {
-  PropertyHandle property(name);
-  if (pending_properties_.Contains(property))
-    Apply(property);
-}
-
-void CSSVariableAnimator::Apply(const PropertyHandle& property) {
-  DCHECK(property.IsCSSCustomProperty());
-  DCHECK(pending_properties_.Contains(property));
-  const ActiveInterpolations& interpolations =
-      ActiveInterpolationsForCustomProperty(update_, property);
-  const Interpolation& interpolation = *interpolations.front();
-  if (IsA<InvalidatableInterpolation>(interpolation)) {
-    CSSInterpolationTypesMap map(state_.GetDocument().GetPropertyRegistry(),
-                                 state_.GetDocument());
-    CSSInterpolationEnvironment environment(map, state_, this);
-    InvalidatableInterpolation::ApplyStack(interpolations, environment);
-  } else {
-    To<TransitionInterpolation>(interpolation).Apply(state_);
-  }
-  pending_properties_.erase(property);
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/css/resolver/css_variable_animator.h b/third_party/blink/renderer/core/css/resolver/css_variable_animator.h
deleted file mode 100644
index 6a284da..0000000
--- a/third_party/blink/renderer/core/css/resolver/css_variable_animator.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_RESOLVER_CSS_VARIABLE_ANIMATOR_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_RESOLVER_CSS_VARIABLE_ANIMATOR_H_
-
-#include "third_party/blink/renderer/core/animation/interpolation.h"
-#include "third_party/blink/renderer/core/animation/property_handle.h"
-#include "third_party/blink/renderer/core/css/resolver/css_variable_resolver.h"
-
-namespace blink {
-
-class StyleResolverState;
-class CSSAnimationUpdate;
-
-// CSSVariableAnimator is a special CSSVariableResolver which can apply
-// animated values during var()-resolution. In other words, it makes sure that
-// if a var()-reference to a currently animating custom property is encountered,
-// we will first apply the animated value for that property before resolving it.
-class CORE_EXPORT CSSVariableAnimator : public CSSVariableResolver {
-  STACK_ALLOCATED();
-
- public:
-  explicit CSSVariableAnimator(StyleResolverState&);
-
-  // Apply all custom property animations. After calling this, the set of
-  // pending properties will be empty and further calls to ApplyAll will have
-  // no effect.
-  void ApplyAll();
-
- protected:
-  void ApplyAnimation(const AtomicString&) override;
-
- private:
-  // Apply the animated value of a single property. The property must exist
-  // in 'pending_properties_'.
-  void Apply(const PropertyHandle&);
-
-  StyleResolverState& state_;
-  const CSSAnimationUpdate& update_;
-  // Set of custom properties with pending animations. We will apply these
-  // one by one until the set is empty.
-  HashSet<PropertyHandle> pending_properties_;
-};
-
-}  // namespace blink
-
-#endif  // CSSVariableAnimator
diff --git a/third_party/blink/renderer/core/css/resolver/css_variable_resolver.cc b/third_party/blink/renderer/core/css/resolver/css_variable_resolver.cc
deleted file mode 100644
index e04870d..0000000
--- a/third_party/blink/renderer/core/css/resolver/css_variable_resolver.cc
+++ /dev/null
@@ -1,545 +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.
-
-#include "third_party/blink/renderer/core/css/resolver/css_variable_resolver.h"
-
-#include "third_party/blink/renderer/core/css/css_custom_property_declaration.h"
-#include "third_party/blink/renderer/core/css/css_invalid_variable_value.h"
-#include "third_party/blink/renderer/core/css/css_pending_substitution_value.h"
-#include "third_party/blink/renderer/core/css/css_property_names.h"
-#include "third_party/blink/renderer/core/css/css_unset_value.h"
-#include "third_party/blink/renderer/core/css/css_variable_data.h"
-#include "third_party/blink/renderer/core/css/css_variable_reference_value.h"
-#include "third_party/blink/renderer/core/css/document_style_environment_variables.h"
-#include "third_party/blink/renderer/core/css/parser/css_parser_token.h"
-#include "third_party/blink/renderer/core/css/parser/css_parser_token_range.h"
-#include "third_party/blink/renderer/core/css/parser/css_property_parser.h"
-#include "third_party/blink/renderer/core/css/parser/css_tokenizer.h"
-#include "third_party/blink/renderer/core/css/property_registry.h"
-#include "third_party/blink/renderer/core/css/resolver/style_builder.h"
-#include "third_party/blink/renderer/core/css/resolver/style_builder_converter.h"
-#include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h"
-#include "third_party/blink/renderer/core/css/resolver/style_resolver_stats.h"
-#include "third_party/blink/renderer/core/css/style_engine.h"
-#include "third_party/blink/renderer/core/css_value_keywords.h"
-#include "third_party/blink/renderer/core/dom/shadow_root.h"
-#include "third_party/blink/renderer/core/style/computed_style.h"
-#include "third_party/blink/renderer/core/style/style_inherited_variables.h"
-#include "third_party/blink/renderer/core/style/style_non_inherited_variables.h"
-#include "third_party/blink/renderer/core/style_property_shorthand.h"
-#include "third_party/blink/renderer/platform/wtf/text/text_encoding.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-
-namespace blink {
-
-CSSVariableResolver::Fallback CSSVariableResolver::ResolveFallback(
-    CSSParserTokenRange range,
-    const Options& options,
-    const PropertyRegistration* registration,
-    Result& result) {
-  if (range.AtEnd())
-    return Fallback::kNone;
-  DCHECK_EQ(range.Peek().GetType(), kCommaToken);
-  range.Consume();
-  size_t first_fallback_token = result.tokens.size();
-  if (!ResolveTokenRange(range, options, result))
-    return Fallback::kFail;
-  if (registration) {
-    CSSParserTokenRange resolved_range(result.tokens);
-    resolved_range = resolved_range.MakeSubRange(
-        &resolved_range.Peek(first_fallback_token), resolved_range.end());
-    const CSSParserContext* context = StrictCSSParserContext(
-        state_.GetDocument().GetExecutionContext()->GetSecureContextMode());
-    const bool is_animation_tainted = false;
-    if (!registration->Syntax().Parse(resolved_range, *context,
-                                      is_animation_tainted))
-      return Fallback::kFail;
-  }
-  return Fallback::kSuccess;
-}
-
-scoped_refptr<CSSVariableData> CSSVariableResolver::ValueForCustomProperty(
-    AtomicString name,
-    const Options& options,
-    bool& unit_cycle) {
-  if (variables_seen_.Contains(name)) {
-    cycle_start_points_.insert(name);
-    return nullptr;
-  }
-
-  const PropertyRegistration* registration =
-      registry_ ? registry_->Registration(name) : nullptr;
-
-  CSSVariableData* variable_data = GetVariableData(name, registration);
-
-  if (!variable_data)
-    return nullptr;
-
-  bool cycle_detected = false;
-  scoped_refptr<CSSVariableData> resolved_data = ResolveCustomPropertyIfNeeded(
-      name, variable_data, options, cycle_detected);
-
-  if (!resolved_data && cycle_detected) {
-    if (options.absolutize)
-      SetInvalidVariable(name, registration);
-    return nullptr;
-  }
-
-  if (resolved_data) {
-    if (IsDisallowedByFontUnitFlags(*resolved_data, options, registration)) {
-      unit_cycle = true;
-      SetInvalidVariable(name, registration);
-      return nullptr;
-    }
-    if (IsDisallowedByAnimationTaintedFlag(*resolved_data, options))
-      return nullptr;
-  }
-
-  if (!registration) {
-    if (resolved_data != variable_data && options.absolutize)
-      SetVariableData(name, registration, resolved_data);
-    return resolved_data;
-  }
-
-  const CSSValue* value = GetVariableValue(name, *registration);
-  const CSSValue* resolved_value = value;
-
-  // The computed value of a registered property must be stored as a CSSValue
-  // on ComputedStyle. If we have resolved this custom property before, we
-  // may already have a CSSValue. If not, we must produce that value now.
-  if (!resolved_value && resolved_data) {
-    resolved_value = resolved_data->ParseForSyntax(
-        registration->Syntax(),
-        state_.GetDocument().GetExecutionContext()->GetSecureContextMode());
-    if (!resolved_value) {
-      // Parsing failed. Set resolved_data to nullptr to indicate that we
-      // currently don't have a token stream matching the registered syntax.
-      resolved_data = nullptr;
-    }
-  }
-
-  // If either parsing or resolution failed, fall back on "unset".
-  if (!resolved_data) {
-    if (registration->Inherits()) {
-      resolved_data = state_.ParentStyle()->GetVariableData(name, true);
-      resolved_value = state_.ParentStyle()->GetVariableValue(name, true);
-    } else {
-      resolved_data = registration->InitialVariableData();
-      resolved_value = registration->Initial();
-    }
-  }
-
-  // Registered custom properties substitute as token sequences equivalent to
-  // their computed values. CSSVariableData instances which represent such token
-  // sequences are called "absolutized".
-  if (resolved_value && !resolved_data->IsAbsolutized()) {
-    resolved_value = &StyleBuilderConverter::ConvertRegisteredPropertyValue(
-        state_, *resolved_value, resolved_data->BaseURL(),
-        resolved_data->Charset());
-    resolved_data =
-        StyleBuilderConverter::ConvertRegisteredPropertyVariableData(
-            *resolved_value, resolved_data->IsAnimationTainted());
-    DCHECK(resolved_data->IsAbsolutized());
-  }
-
-  // If options.absolutize=false, we want to keep the original (non-absolute)
-  // token sequence to retain any var()-references. This makes it possible to
-  // resolve the var()-reference again, using a different (e.g. animated) value.
-  if (options.absolutize && resolved_data != variable_data)
-    SetVariableData(name, registration, resolved_data);
-
-  // The options.absolutize flag does not apply to the computed value, only
-  // to the tokens used for substitution. Hence, store the computed value on
-  // ComputedStyle, regardless of the flag. This is needed to correctly
-  // calculate animations.
-  if (value != resolved_value)
-    SetVariableValue(name, *registration, resolved_value);
-
-  return resolved_data;
-}
-
-scoped_refptr<CSSVariableData> CSSVariableResolver::ResolveCustomProperty(
-    AtomicString name,
-    const CSSVariableData& variable_data,
-    const Options& options,
-    bool& cycle_detected) {
-  DCHECK(variable_data.NeedsVariableResolution());
-
-  Result result;
-  result.is_animation_tainted = variable_data.IsAnimationTainted();
-  result.has_font_units = variable_data.HasFontUnits();
-  result.has_root_font_units = variable_data.HasRootFontUnits();
-  result.absolutized = variable_data.IsAbsolutized();
-  result.backing_strings.AppendVector(variable_data.BackingStrings());
-  DCHECK(!variables_seen_.Contains(name));
-  variables_seen_.insert(name);
-  bool success = ResolveTokenRange(variable_data.Tokens(), options, result);
-  variables_seen_.erase(name);
-
-  if (!cycle_start_points_.IsEmpty())
-    cycle_detected = true;
-  if (!success || cycle_detected) {
-    cycle_start_points_.erase(name);
-    return nullptr;
-  }
-  cycle_detected = false;
-
-  return CSSVariableData::CreateResolved(
-      result.tokens, std::move(result.backing_strings),
-      result.is_animation_tainted, result.has_font_units,
-      result.has_root_font_units, result.absolutized, variable_data.BaseURL(),
-      variable_data.Charset());
-}
-
-scoped_refptr<CSSVariableData>
-CSSVariableResolver::ResolveCustomPropertyIfNeeded(
-    AtomicString name,
-    CSSVariableData* variable_data,
-    const Options& options,
-    bool& cycle_detected) {
-  DCHECK(variable_data);
-  if (!variable_data->NeedsVariableResolution())
-    return variable_data;
-  return ResolveCustomProperty(name, *variable_data, options, cycle_detected);
-}
-
-bool CSSVariableResolver::IsDisallowedByFontUnitFlags(
-    const CSSVariableData& variable_data,
-    const Options& options,
-    const PropertyRegistration* registration) {
-  return (registration && options.disallow_registered_font_units &&
-          variable_data.HasFontUnits()) ||
-         (registration && options.disallow_registered_root_font_units &&
-          variable_data.HasRootFontUnits());
-}
-
-bool CSSVariableResolver::IsDisallowedByAnimationTaintedFlag(
-    const CSSVariableData& variable_data,
-    const Options& options) {
-  return options.disallow_animation_tainted &&
-         variable_data.IsAnimationTainted();
-}
-
-CSSVariableData* CSSVariableResolver::GetVariableData(
-    const AtomicString& name,
-    const PropertyRegistration* registration) {
-  return state_.Style()->GetVariableData(
-      name, !registration || registration->Inherits());
-}
-
-const CSSValue* CSSVariableResolver::GetVariableValue(
-    const AtomicString& name,
-    const PropertyRegistration& registration) {
-  return state_.Style()->GetVariableValue(name, registration.Inherits());
-}
-
-void CSSVariableResolver::SetVariableData(
-    const AtomicString& name,
-    const PropertyRegistration* registration,
-    scoped_refptr<CSSVariableData> variable_data) {
-  if (!registration || registration->Inherits()) {
-    DCHECK(inherited_variables_);
-    inherited_variables_->SetData(name, std::move(variable_data));
-  } else {
-    DCHECK(non_inherited_variables_);
-    non_inherited_variables_->SetData(name, std::move(variable_data));
-  }
-}
-
-void CSSVariableResolver::SetVariableValue(
-    const AtomicString& name,
-    const PropertyRegistration& registration,
-    const CSSValue* value) {
-  if (registration.Inherits()) {
-    DCHECK(inherited_variables_);
-    inherited_variables_->SetValue(name, value);
-  } else {
-    DCHECK(non_inherited_variables_);
-    non_inherited_variables_->SetValue(name, value);
-  }
-}
-
-void CSSVariableResolver::SetInvalidVariable(
-    const AtomicString& name,
-    const PropertyRegistration* registration) {
-  SetVariableData(name, registration, nullptr);
-  if (registration)
-    SetVariableValue(name, *registration, nullptr);
-}
-
-const CSSParserContext* CSSVariableResolver::GetParserContext(
-    const CSSVariableReferenceValue& value) const {
-  // TODO(crbug.com/985028): CSSVariableReferenceValue should always have
-  // a CSSParserContext.
-  if (value.ParserContext())
-    return value.ParserContext();
-  return StrictCSSParserContext(
-      state_.GetDocument().GetExecutionContext()->GetSecureContextMode());
-}
-
-bool CSSVariableResolver::ResolveVariableReference(CSSParserTokenRange range,
-                                                   const Options& options,
-                                                   bool is_env_variable,
-                                                   Result& result) {
-  range.ConsumeWhitespace();
-  DCHECK_EQ(range.Peek().GetType(), kIdentToken);
-  AtomicString variable_name =
-      range.ConsumeIncludingWhitespace().Value().ToAtomicString();
-  DCHECK(range.AtEnd() || (range.Peek().GetType() == kCommaToken));
-
-  if (!variables_seen_.Contains(variable_name)) {
-    ApplyAnimation(variable_name);
-    // Null custom property storage may become non-null after application, we
-    // must refresh these cached values.
-    inherited_variables_ = state_.Style()->InheritedVariables();
-    non_inherited_variables_ = state_.Style()->NonInheritedVariables();
-  }
-
-  const PropertyRegistration* registration = nullptr;
-  if (registry_) {
-    registration = registry_->Registration(variable_name);
-    if (!is_env_variable)
-      registry_->MarkReferenced(variable_name);
-  }
-
-  bool unit_cycle = false;
-  scoped_refptr<CSSVariableData> variable_data =
-      is_env_variable
-          ? ValueForEnvironmentVariable(variable_name)
-          : ValueForCustomProperty(variable_name, options, unit_cycle);
-
-  if (unit_cycle)
-    return false;
-
-  if (!variable_data) {
-    // TODO(alancutter): Append the registered initial custom property value if
-    // we are disallowing an animation tainted value.
-    return ResolveFallback(range, options, registration, result) ==
-           Fallback::kSuccess;
-  }
-
-  if (variable_data->Tokens().size() > kMaxSubstitutionTokens)
-    return false;
-
-  result.tokens.AppendVector(variable_data->Tokens());
-  // TODO(alancutter): Avoid adding backing strings multiple times in a row.
-  result.backing_strings.AppendVector(variable_data->BackingStrings());
-  result.is_animation_tainted |= variable_data->IsAnimationTainted();
-  result.has_font_units |= variable_data->HasFontUnits();
-  result.has_root_font_units |= variable_data->HasRootFontUnits();
-  result.absolutized &= variable_data->IsAbsolutized();
-
-  Result trash;
-  Fallback fallback = ResolveFallback(range, options, registration, trash);
-
-  // For registered properties, the fallback (if present) must be valid, even
-  // if it's not used.
-  if (registration && fallback == Fallback::kFail)
-    return false;
-
-  return true;
-}
-
-scoped_refptr<CSSVariableData> CSSVariableResolver::ValueForEnvironmentVariable(
-    const AtomicString& name) {
-  // If we are in a User Agent Shadow DOM then we should not record metrics.
-  ContainerNode& scope_root = state_.GetTreeScope().RootNode();
-  auto* shadow_root = DynamicTo<ShadowRoot>(&scope_root);
-  bool is_ua_scope = shadow_root && shadow_root->IsUserAgent();
-
-  return state_.GetDocument()
-      .GetStyleEngine()
-      .EnsureEnvironmentVariables()
-      .ResolveVariable(name, !is_ua_scope);
-}
-
-bool CSSVariableResolver::ResolveTokenRange(CSSParserTokenRange range,
-                                            const Options& options,
-                                            Result& result) {
-  bool success = true;
-  while (!range.AtEnd()) {
-    const CSSParserToken& token = range.Peek();
-    if (token.FunctionId() == CSSValueID::kVar ||
-        token.FunctionId() == CSSValueID::kEnv) {
-      success &= ResolveVariableReference(
-          range.ConsumeBlock(), options, token.FunctionId() == CSSValueID::kEnv,
-          result);
-    } else {
-      result.tokens.push_back(range.Consume());
-    }
-  }
-  return success;
-}
-
-const CSSValue* CSSVariableResolver::ResolveVariableReferences(
-    CSSPropertyID id,
-    const CSSValue& value,
-    bool disallow_animation_tainted) {
-  DCHECK(!CSSProperty::Get(id).IsShorthand());
-
-  Options options;
-  options.disallow_animation_tainted = disallow_animation_tainted;
-
-  if (id == CSSPropertyID::kFontSize) {
-    bool is_root =
-        &state_.GetElement() == state_.GetDocument().documentElement();
-    options.disallow_registered_font_units = true;
-    options.disallow_registered_root_font_units = is_root;
-  }
-
-  if (auto* substition_value =
-          DynamicTo<cssvalue::CSSPendingSubstitutionValue>(value)) {
-    return ResolvePendingSubstitutions(id, *substition_value, options);
-  }
-
-  if (auto* variable_reference_value =
-          DynamicTo<CSSVariableReferenceValue>(value)) {
-    return ResolveVariableReferences(id, *variable_reference_value, options);
-  }
-
-  NOTREACHED();
-  return nullptr;
-}
-
-const CSSValue* CSSVariableResolver::ResolveVariableReferences(
-    CSSPropertyID id,
-    const CSSVariableReferenceValue& value,
-    const Options& options) {
-  Result result;
-
-  if (!ResolveTokenRange(value.VariableDataValue()->Tokens(), options,
-                         result)) {
-    return cssvalue::CSSUnsetValue::Create();
-  }
-  const CSSValue* resolved_value = CSSPropertyParser::ParseSingleValue(
-      id, result.tokens, GetParserContext(value));
-  if (!resolved_value)
-    return cssvalue::CSSUnsetValue::Create();
-  return resolved_value;
-}
-
-const CSSValue* CSSVariableResolver::ResolvePendingSubstitutions(
-    CSSPropertyID id,
-    const cssvalue::CSSPendingSubstitutionValue& pending_value,
-    const Options& options) {
-  DCHECK_NE(CSSPropertyID::kVariable, id);
-
-  // For -internal-visited-* properties, we pretend that we're resolving the
-  // unvisited counterpart. This is because the CSSPendingSubstitutionValue
-  // held by the -internal-visited-* property contains a shorthand that expands
-  // to unvisited properties.
-  const CSSProperty& property = CSSProperty::Get(id);
-  CSSPropertyID cache_id = id;
-  if (property.IsVisited())
-    cache_id = property.GetUnvisitedProperty()->PropertyID();
-
-  // Longhands from shorthand references follow this path.
-  HeapHashMap<CSSPropertyID, Member<const CSSValue>>& property_cache =
-      state_.ParsedPropertiesForPendingSubstitutionCache(pending_value);
-
-  const CSSValue* value = property_cache.at(cache_id);
-  if (!value) {
-    // TODO(timloh): We shouldn't retry this for all longhands if the shorthand
-    // ends up invalid.
-    CSSVariableReferenceValue* shorthand_value = pending_value.ShorthandValue();
-    CSSPropertyID shorthand_property_id = pending_value.ShorthandPropertyId();
-
-    Result result;
-    if (ResolveTokenRange(shorthand_value->VariableDataValue()->Tokens(),
-                          options, result)) {
-      HeapVector<CSSPropertyValue, 256> parsed_properties;
-
-      if (CSSPropertyParser::ParseValue(
-              shorthand_property_id, false, CSSParserTokenRange(result.tokens),
-              shorthand_value->ParserContext(), parsed_properties,
-              StyleRule::RuleType::kStyle)) {
-        unsigned parsed_properties_count = parsed_properties.size();
-        for (unsigned i = 0; i < parsed_properties_count; ++i) {
-          property_cache.Set(parsed_properties[i].Id(),
-                             parsed_properties[i].Value());
-        }
-      }
-    }
-    value = property_cache.at(cache_id);
-  }
-
-  if (value)
-    return value;
-
-  return cssvalue::CSSUnsetValue::Create();
-}
-
-scoped_refptr<CSSVariableData>
-CSSVariableResolver::ResolveCustomPropertyAnimationKeyframe(
-    const CSSCustomPropertyDeclaration& keyframe,
-    bool& cycle_detected) {
-  DCHECK(keyframe.Value());
-  DCHECK(keyframe.Value()->NeedsVariableResolution());
-  const AtomicString& name = keyframe.GetName();
-
-  if (variables_seen_.Contains(name)) {
-    cycle_start_points_.insert(name);
-    cycle_detected = true;
-    return nullptr;
-  }
-
-  return ResolveCustomProperty(name, *keyframe.Value(), Options(),
-                               cycle_detected);
-}
-
-void CSSVariableResolver::ResolveVariableDefinitions() {
-  if (!inherited_variables_ && !non_inherited_variables_)
-    return;
-
-  Options options;
-  options.absolutize = true;
-
-  int variable_count = 0;
-  if (inherited_variables_ && inherited_variables_->NeedsResolution()) {
-    for (auto& variable : inherited_variables_->Data()) {
-      bool cycle_detected = false;
-      ValueForCustomProperty(variable.key, options, cycle_detected);
-    }
-    inherited_variables_->ClearNeedsResolution();
-    variable_count += inherited_variables_->Data().size();
-  }
-  if (non_inherited_variables_ && non_inherited_variables_->NeedsResolution()) {
-    for (auto& variable : non_inherited_variables_->Data()) {
-      bool cycle_detected = false;
-      ValueForCustomProperty(variable.key, options, cycle_detected);
-    }
-    non_inherited_variables_->ClearNeedsResolution();
-    variable_count += non_inherited_variables_->Data().size();
-  }
-  INCREMENT_STYLE_STATS_COUNTER(state_.GetDocument().GetStyleEngine(),
-                                custom_properties_applied, variable_count);
-}
-
-void CSSVariableResolver::ComputeRegisteredVariables() {
-  Options options;
-
-  if (inherited_variables_) {
-    for (auto& variable : inherited_variables_->Values()) {
-      bool cycle_detected = false;
-      ValueForCustomProperty(variable.key, options, cycle_detected);
-    }
-  }
-  if (non_inherited_variables_) {
-    for (auto& variable : non_inherited_variables_->Values()) {
-      bool cycle_detected = false;
-      ValueForCustomProperty(variable.key, options, cycle_detected);
-    }
-  }
-}
-
-CSSVariableResolver::CSSVariableResolver(const StyleResolverState& state)
-    : state_(state),
-      inherited_variables_(state.Style()->InheritedVariables()),
-      non_inherited_variables_(state.Style()->NonInheritedVariables()),
-      registry_(state.GetDocument().GetPropertyRegistry()) {
-  DCHECK(!RuntimeEnabledFeatures::CSSCascadeEnabled())
-      << "Use StyleCascade instead";
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/css/resolver/css_variable_resolver.h b/third_party/blink/renderer/core/css/resolver/css_variable_resolver.h
deleted file mode 100644
index eaa6f32..0000000
--- a/third_party/blink/renderer/core/css/resolver/css_variable_resolver.h
+++ /dev/null
@@ -1,237 +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.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_RESOLVER_CSS_VARIABLE_RESOLVER_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_RESOLVER_CSS_VARIABLE_RESOLVER_H_
-
-#include "third_party/blink/renderer/core/css/css_property_names.h"
-#include "third_party/blink/renderer/core/css/parser/css_parser_token.h"
-#include "third_party/blink/renderer/platform/wtf/hash_set.h"
-#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
-#include "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h"
-
-namespace blink {
-
-class CSSCustomPropertyDeclaration;
-class CSSParserTokenRange;
-class CSSVariableData;
-class CSSVariableReferenceValue;
-class CSSParserContext;
-class PropertyRegistration;
-class PropertyRegistry;
-class StyleInheritedVariables;
-class StyleNonInheritedVariables;
-class StyleResolverState;
-
-namespace cssvalue {
-
-class CSSPendingSubstitutionValue;
-
-}
-
-class CORE_EXPORT CSSVariableResolver {
-  STACK_ALLOCATED();
-
- public:
-  explicit CSSVariableResolver(const StyleResolverState&);
-
-  scoped_refptr<CSSVariableData> ResolveCustomPropertyAnimationKeyframe(
-      const CSSCustomPropertyDeclaration& keyframe,
-      bool& cycle_detected);
-
-  void ResolveVariableDefinitions();
-
-  // Shorthand properties are not supported.
-  const CSSValue* ResolveVariableReferences(CSSPropertyID,
-                                            const CSSValue&,
-                                            bool disallow_animation_tainted);
-
-  void ComputeRegisteredVariables();
-
- protected:
-  // Called before looking up the value of some var()-reference to make it
-  // possible to apply animated properties during variable resolution.
-  virtual void ApplyAnimation(const AtomicString& name) {}
-
- private:
-  // The maximum number of tokens that may be produced by a var()
-  // reference.
-  //
-  // https://drafts.csswg.org/css-variables/#long-variables
-  static const size_t kMaxSubstitutionTokens = 16384;
-
-  struct Options {
-    STACK_ALLOCATED();
-
-   public:
-    // Treat any references to animation-tainted custom properties as invalid.
-    //
-    // Custom properties used in @keyframe rules become 'animation-tainted'
-    // (see https://drafts.csswg.org/css-variables/#syntax). References to
-    // animation-tainted custom properties are not allowed for properties
-    // that affect animations.
-    bool disallow_animation_tainted = false;
-
-    // Treat any references to registered custom properties with font-relative
-    // units as invalid.
-    //
-    // This is used when resolving variable references for 'font-size', where
-    // registered custom properties with font-relative units may not be used.
-    //
-    // https://drafts.css-houdini.org/css-properties-values-api-1/#dependency-cycles-via-relative-units
-    bool disallow_registered_font_units = false;
-
-    // Treat any references to registered custom properties with
-    // root-font-relative units as invalid.
-    //
-    // This is used when resolving variable references for 'font-size' on the
-    // root element, where registered custom properties with root-font-relative
-    // units may not be used.
-    //
-    // https://drafts.css-houdini.org/css-properties-values-api-1/#dependency-cycles-via-relative-units
-    bool disallow_registered_root_font_units = false;
-
-    // Absolutize CSSVariableData during variable resolution.
-    //
-    // Absolutization is a process where the substitution tokens of a registered
-    // custom property are "synthetically" created to represent the computed
-    // value of the custom property. For instance, a <length>-registered custom
-    // property may be specified with the value "10em". However, this property
-    // should substitute into others as the computed value, hence an equivalent
-    // token stream is needed. Assuming a font-size of 12px (for instance),
-    // the absolutization process would produce a token stream of "120px".
-    //
-    // Absolutization must take place after high-priority properties have been
-    // applied, to be able to resolve the relative units correctly. However,
-    // registered custom properties must also be usable for the high-priority
-    // properties themselves (e.g. color). When a high-priority property refers
-    // to a custom property with an (inner) var()-reference, that custom
-    // property is resolved "on the fly" with absolutize=false. This means that
-    // the equivalent token stream for the computed value of that custom
-    // property is not stored on ComputedStyle. Storing the token stream on
-    // ComputedStyle can only be done with absolutize=true, otherwise we can
-    // permanently end up with the wrong token stream if an unregistered
-    // property references a registered property, for instance.
-    bool absolutize = false;
-  };
-
-  struct Result {
-    STACK_ALLOCATED();
-
-   public:
-    Vector<CSSParserToken> tokens;
-    Vector<String> backing_strings;
-    bool is_animation_tainted = false;
-    bool has_font_units = false;
-    bool has_root_font_units = false;
-    bool absolutized = false;
-  };
-
-  const CSSValue* ResolvePendingSubstitutions(
-      CSSPropertyID,
-      const cssvalue::CSSPendingSubstitutionValue&,
-      const Options&);
-  const CSSValue* ResolveVariableReferences(CSSPropertyID,
-                                            const CSSVariableReferenceValue&,
-                                            const Options&);
-
-  // These return false if we encounter a reference to an invalid variable with
-  // no fallback.
-
-  // Resolves a range which may contain var() or env() references.
-  bool ResolveTokenRange(CSSParserTokenRange, const Options&, Result&);
-
-  // Return value for ResolveFallback.
-  enum class Fallback {
-    // Fallback not present.
-    kNone,
-    // Fallback present, but resolution failed (i.e. invalid variables
-    // referenced), or the result did not match the syntax registered for
-    // the referenced variable (if applicable).
-    kFail,
-    // Fallback present, resolution succeeded, and syntax matched (if
-    // applicable).
-    kSuccess
-  };
-
-  // Resolves the fallback (if present) of a var() or env() reference, starting
-  // from the comma.
-  Fallback ResolveFallback(CSSParserTokenRange,
-                           const Options&,
-                           const PropertyRegistration*,
-                           Result&);
-  // Resolves the contents of a var() or env() reference.
-  bool ResolveVariableReference(CSSParserTokenRange,
-                                const Options&,
-                                bool is_env_variable,
-                                Result&);
-
-  // These return null if the custom property is invalid.
-
-  // Returns the CSSVariableData for an environment variable.
-  scoped_refptr<CSSVariableData> ValueForEnvironmentVariable(
-      const AtomicString& name);
-  // Returns the CSSVariableData for a custom property, resolving and storing it
-  // if necessary. If a cycle via font-relative units was discovered, the
-  // unit_cycle flag is set to true.
-  //
-  // https://drafts.css-houdini.org/css-properties-values-api-1/#dependency-cycles
-  scoped_refptr<CSSVariableData> ValueForCustomProperty(AtomicString name,
-                                                        const Options&,
-                                                        bool& unit_cycle);
-  // Resolves the CSSVariableData from a custom property declaration.
-  scoped_refptr<CSSVariableData> ResolveCustomProperty(AtomicString name,
-                                                       const CSSVariableData&,
-                                                       const Options&,
-                                                       bool& cycle_detected);
-  // Like ResolveCustomProperty, but returns the incoming CSSVariableData if
-  // no resolution is needed.
-  scoped_refptr<CSSVariableData> ResolveCustomPropertyIfNeeded(
-      AtomicString name,
-      CSSVariableData*,
-      const Options&,
-      bool& cycle_detected);
-
-  bool IsDisallowedByFontUnitFlags(const CSSVariableData&,
-                                   const Options&,
-                                   const PropertyRegistration*);
-
-  bool IsDisallowedByAnimationTaintedFlag(const CSSVariableData&,
-                                          const Options&);
-
-  // The following utilities get/set variables on either StyleInheritedVariables
-  // or StyleNonInheritedVariables, according to their PropertyRegistration.
-
-  CSSVariableData* GetVariableData(const AtomicString& name,
-                                   const PropertyRegistration*);
-  const CSSValue* GetVariableValue(const AtomicString& name,
-                                   const PropertyRegistration&);
-  void SetVariableData(const AtomicString& name,
-                       const PropertyRegistration*,
-                       scoped_refptr<CSSVariableData>);
-  void SetVariableValue(const AtomicString& name,
-                        const PropertyRegistration&,
-                        const CSSValue*);
-  void SetInvalidVariable(const AtomicString& name,
-                          const PropertyRegistration*);
-
-  const CSSParserContext* GetParserContext(
-      const CSSVariableReferenceValue&) const;
-
-  const StyleResolverState& state_;
-  StyleInheritedVariables* inherited_variables_;
-  StyleNonInheritedVariables* non_inherited_variables_;
-  const PropertyRegistry* registry_;
-  HashSet<AtomicString> variables_seen_;
-  // Resolution doesn't finish when a cycle is detected. Fallbacks still
-  // need to be tracked for additional cycles, and invalidation only
-  // applies back to cycle starts.
-  HashSet<AtomicString> cycle_start_points_;
-
-  friend class CSSVariableResolverTest;
-};
-
-}  // namespace blink
-
-#endif  // CSSVariableResolver
diff --git a/third_party/blink/renderer/core/css/resolver/css_variable_resolver_test.cc b/third_party/blink/renderer/core/css/resolver/css_variable_resolver_test.cc
deleted file mode 100644
index 6883487..0000000
--- a/third_party/blink/renderer/core/css/resolver/css_variable_resolver_test.cc
+++ /dev/null
@@ -1,519 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/css/resolver/css_variable_resolver.h"
-#include "third_party/blink/renderer/core/css/css_custom_property_declaration.h"
-#include "third_party/blink/renderer/core/css/css_inherited_value.h"
-#include "third_party/blink/renderer/core/css/css_initial_value.h"
-#include "third_party/blink/renderer/core/css/css_numeric_literal_value.h"
-#include "third_party/blink/renderer/core/css/css_syntax_string_parser.h"
-#include "third_party/blink/renderer/core/css/css_unset_value.h"
-#include "third_party/blink/renderer/core/css/css_variable_reference_value.h"
-#include "third_party/blink/renderer/core/css/document_style_environment_variables.h"
-#include "third_party/blink/renderer/core/css/parser/css_parser_context.h"
-#include "third_party/blink/renderer/core/css/parser/css_tokenizer.h"
-#include "third_party/blink/renderer/core/css/parser/css_variable_parser.h"
-#include "third_party/blink/renderer/core/css/properties/css_property.h"
-#include "third_party/blink/renderer/core/css/properties/longhand.h"
-#include "third_party/blink/renderer/core/css/properties/longhands/custom_property.h"
-#include "third_party/blink/renderer/core/css/property_registration.h"
-#include "third_party/blink/renderer/core/css/property_registry.h"
-#include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h"
-#include "third_party/blink/renderer/core/css/style_engine.h"
-#include "third_party/blink/renderer/core/dom/node_computed_style.h"
-#include "third_party/blink/renderer/core/html/html_element.h"
-#include "third_party/blink/renderer/core/style/computed_style.h"
-#include "third_party/blink/renderer/core/testing/page_test_base.h"
-#include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
-#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
-
-namespace blink {
-
-namespace {
-
-// blue
-static const Color kFallbackTestColor = Color(0, 0, 255);
-
-// black
-static const Color kMainBgTestColor = Color(0, 0, 0);
-
-// red
-static const Color kTestColor = Color(255, 0, 0);
-
-}  // namespace
-
-class CSSVariableResolverTest : public PageTestBase,
-                                private ScopedCSSCascadeForTest {
- public:
-  CSSVariableResolverTest() : ScopedCSSCascadeForTest(false) {}
-
-  void SetUp() override {
-    PageTestBase::SetUp();
-
-    GetStyleEngine().EnsureEnvironmentVariables().SetVariable("test", "red");
-  }
-
-  void SetTestHTML(const String& value) {
-    GetDocument().body()->setInnerHTML(
-        "<style>"
-        "  #target {"
-        "    --main-bg-color: black;"
-        "    --test: red;"
-        "    background-color: " +
-        value +
-        "  }"
-        "</style>"
-        "<div>"
-        "  <div id=target></div>"
-        "</div>");
-    UpdateAllLifecyclePhasesForTest();
-  }
-
-  const CSSCustomPropertyDeclaration* CreateCustomProperty(
-      const String& value) {
-    return CreateCustomProperty("--unused", value);
-  }
-
-  const CSSCustomPropertyDeclaration* CreateCustomProperty(
-      const AtomicString& name,
-      const String& value) {
-    const auto tokens = CSSTokenizer(value).TokenizeToEOF();
-    return CSSVariableParser::ParseDeclarationValue(
-        name, tokens, false,
-        *MakeGarbageCollected<CSSParserContext>(GetDocument()));
-  }
-
-  const CSSVariableReferenceValue* CreateVariableReference(
-      const String& value) {
-    const auto tokens = CSSTokenizer(value).TokenizeToEOF();
-
-    const auto* context = MakeGarbageCollected<CSSParserContext>(GetDocument());
-    const bool is_animation_tainted = false;
-    const bool needs_variable_resolution = true;
-
-    return MakeGarbageCollected<CSSVariableReferenceValue>(
-        CSSVariableData::Create(tokens, is_animation_tainted,
-                                needs_variable_resolution, context->BaseURL(),
-                                context->Charset()),
-        *context);
-  }
-
-  const CSSValue* ResolveVar(StyleResolverState& state,
-                             CSSPropertyID property_id,
-                             const String& value) {
-    const CSSVariableReferenceValue* var = CreateVariableReference(value);
-
-    CSSVariableResolver resolver(state);
-    const bool disallow_animation_tainted = false;
-
-    return resolver.ResolveVariableReferences(property_id, *var,
-                                              disallow_animation_tainted);
-  }
-
-  const CSSValue* CreatePxValue(double px) {
-    return CSSNumericLiteralValue::Create(px,
-                                          CSSPrimitiveValue::UnitType::kPixels);
-  }
-
-  size_t MaxSubstitutionTokens() const {
-    return CSSVariableResolver::kMaxSubstitutionTokens;
-  }
-
-  void SetTestHTMLWithReferencedVariableValue(const String& referenced) {
-    StringBuilder builder;
-    builder.Append("<style>\n");
-    builder.Append("#target {\n");
-    builder.Append("  --x:var(--referenced);\n");
-    builder.Append("  --referenced:");
-    builder.Append(referenced);
-    builder.Append(";\n");
-    builder.Append("}\n");
-    builder.Append("</style>\n");
-    builder.Append("<div id=target></div>\n");
-
-    GetDocument().body()->setInnerHTML(builder.ToString());
-    UpdateAllLifecyclePhasesForTest();
-  }
-};
-
-TEST_F(CSSVariableResolverTest, ParseEnvVariable_Missing_NestedVar) {
-  SetTestHTML("env(missing, var(--main-bg-color))");
-
-  // Check that the element has the background color provided by the
-  // nested variable.
-  Element* target = GetDocument().getElementById("target");
-  EXPECT_EQ(kMainBgTestColor, target->ComputedStyleRef().VisitedDependentColor(
-                                  GetCSSPropertyBackgroundColor()));
-}
-
-TEST_F(CSSVariableResolverTest, ParseEnvVariable_Missing_NestedVar_Fallback) {
-  SetTestHTML("env(missing, var(--missing, blue))");
-
-  // Check that the element has the fallback background color.
-  Element* target = GetDocument().getElementById("target");
-  EXPECT_EQ(kFallbackTestColor,
-            target->ComputedStyleRef().VisitedDependentColor(
-                GetCSSPropertyBackgroundColor()));
-}
-
-TEST_F(CSSVariableResolverTest, ParseEnvVariable_Missing_WithFallback) {
-  SetTestHTML("env(missing, blue)");
-
-  // Check that the element has the fallback background color.
-  Element* target = GetDocument().getElementById("target");
-  EXPECT_EQ(kFallbackTestColor,
-            target->ComputedStyleRef().VisitedDependentColor(
-                GetCSSPropertyBackgroundColor()));
-}
-
-TEST_F(CSSVariableResolverTest, ParseEnvVariable_Valid) {
-  SetTestHTML("env(test)");
-
-  // Check that the element has the background color provided by the variable.
-  Element* target = GetDocument().getElementById("target");
-  EXPECT_EQ(kTestColor, target->ComputedStyleRef().VisitedDependentColor(
-                            GetCSSPropertyBackgroundColor()));
-}
-
-TEST_F(CSSVariableResolverTest, ParseEnvVariable_Valid_WithFallback) {
-  SetTestHTML("env(test, blue)");
-
-  // Check that the element has the background color provided by the variable.
-  Element* target = GetDocument().getElementById("target");
-  EXPECT_EQ(kTestColor, target->ComputedStyleRef().VisitedDependentColor(
-                            GetCSSPropertyBackgroundColor()));
-}
-
-TEST_F(CSSVariableResolverTest, ParseEnvVariable_WhenNested) {
-  SetTestHTML("var(--main-bg-color, env(missing))");
-
-  // Check that the element has the background color provided by var().
-  Element* target = GetDocument().getElementById("target");
-  EXPECT_EQ(kMainBgTestColor, target->ComputedStyleRef().VisitedDependentColor(
-                                  GetCSSPropertyBackgroundColor()));
-}
-
-TEST_F(CSSVariableResolverTest, ParseEnvVariable_WhenNested_WillFallback) {
-  SetTestHTML("var(--missing, env(test))");
-
-  // Check that the element has the background color provided by the variable.
-  Element* target = GetDocument().getElementById("target");
-  EXPECT_EQ(kTestColor, target->ComputedStyleRef().VisitedDependentColor(
-                            GetCSSPropertyBackgroundColor()));
-}
-
-TEST_F(CSSVariableResolverTest, NoResolutionWithoutVar) {
-  scoped_refptr<StyleInheritedVariables> inherited_variables =
-      StyleInheritedVariables::Create();
-  auto non_inherited_variables = std::make_unique<StyleNonInheritedVariables>();
-
-  EXPECT_FALSE(inherited_variables->NeedsResolution());
-  EXPECT_FALSE(non_inherited_variables->NeedsResolution());
-
-  const auto* prop = CreateCustomProperty("#fefefe");
-
-  inherited_variables->SetData("--prop", prop->Value());
-  non_inherited_variables->SetData("--prop", prop->Value());
-
-  EXPECT_FALSE(inherited_variables->NeedsResolution());
-  EXPECT_FALSE(non_inherited_variables->NeedsResolution());
-}
-
-TEST_F(CSSVariableResolverTest, VarNeedsResolution) {
-  scoped_refptr<StyleInheritedVariables> inherited_variables =
-      StyleInheritedVariables::Create();
-  auto non_inherited_variables = std::make_unique<StyleNonInheritedVariables>();
-
-  EXPECT_FALSE(inherited_variables->NeedsResolution());
-  EXPECT_FALSE(non_inherited_variables->NeedsResolution());
-
-  const auto* prop1 = CreateCustomProperty("var(--prop2)");
-  const auto* prop2 = CreateCustomProperty("#fefefe");
-
-  inherited_variables->SetData("--prop1", prop1->Value());
-  non_inherited_variables->SetData("--prop1", prop1->Value());
-
-  EXPECT_TRUE(inherited_variables->NeedsResolution());
-  EXPECT_TRUE(non_inherited_variables->NeedsResolution());
-
-  // While NeedsResolution() == true, add some properties without
-  // var()-references.
-  inherited_variables->SetData("--prop2", prop2->Value());
-  non_inherited_variables->SetData("--prop2", prop2->Value());
-
-  // We should still need resolution even after adding properties that don't
-  // have var-references.
-  EXPECT_TRUE(inherited_variables->NeedsResolution());
-  EXPECT_TRUE(non_inherited_variables->NeedsResolution());
-
-  inherited_variables->ClearNeedsResolution();
-  non_inherited_variables->ClearNeedsResolution();
-
-  EXPECT_FALSE(inherited_variables->NeedsResolution());
-  EXPECT_FALSE(non_inherited_variables->NeedsResolution());
-}
-
-TEST_F(CSSVariableResolverTest, CopiedVariablesRetainNeedsResolution) {
-  scoped_refptr<StyleInheritedVariables> inherited_variables =
-      StyleInheritedVariables::Create();
-  auto non_inherited_variables = std::make_unique<StyleNonInheritedVariables>();
-
-  const auto* prop = CreateCustomProperty("var(--x)");
-
-  inherited_variables->SetData("--prop", prop->Value());
-  non_inherited_variables->SetData("--prop", prop->Value());
-
-  EXPECT_TRUE(inherited_variables->NeedsResolution());
-  EXPECT_TRUE(non_inherited_variables->NeedsResolution());
-  EXPECT_TRUE(inherited_variables->Copy()->NeedsResolution());
-  EXPECT_TRUE(non_inherited_variables->Clone()->NeedsResolution());
-
-  inherited_variables->ClearNeedsResolution();
-  non_inherited_variables->ClearNeedsResolution();
-
-  EXPECT_FALSE(inherited_variables->NeedsResolution());
-  EXPECT_FALSE(non_inherited_variables->NeedsResolution());
-  EXPECT_FALSE(inherited_variables->Copy()->NeedsResolution());
-  EXPECT_FALSE(non_inherited_variables->Clone()->NeedsResolution());
-}
-
-TEST_F(CSSVariableResolverTest, NeedsResolutionClearedByResolver) {
-  // This test is not relevant when CSSCascade is enabled, as we won't store
-  // unresolved CSSVariableData on the ComputedStyle in that case.
-  if (RuntimeEnabledFeatures::CSSCascadeEnabled())
-    return;
-
-  const ComputedStyle* initial = &ComputedStyle::InitialStyle();
-  StyleResolverState state(GetDocument(), *GetDocument().documentElement(),
-                           initial, initial);
-
-  scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
-  style->InheritFrom(*initial);
-  state.SetStyle(std::move(style));
-
-  const auto* prop1 = CreateCustomProperty("--prop1", "var(--prop2)");
-  const auto* prop2 = CreateCustomProperty("--prop2", "#fefefe");
-  const auto* prop3 = CreateCustomProperty("--prop3", "var(--prop2)");
-
-  // Register prop3 to make it non-inherited.
-  base::Optional<CSSSyntaxDefinition> token_syntax =
-      CSSSyntaxStringParser("*").Parse();
-  ASSERT_TRUE(token_syntax);
-  String initial_value_str("foo");
-  const auto tokens = CSSTokenizer(initial_value_str).TokenizeToEOF();
-  const auto* context = MakeGarbageCollected<CSSParserContext>(GetDocument());
-  const CSSValue* initial_value =
-      token_syntax->Parse(CSSParserTokenRange(tokens), *context, false);
-  ASSERT_TRUE(initial_value);
-  ASSERT_TRUE(initial_value->IsVariableReferenceValue());
-  PropertyRegistration* registration =
-      MakeGarbageCollected<PropertyRegistration>(
-          "--prop3", *token_syntax, false, initial_value,
-          To<CSSVariableReferenceValue>(*initial_value).VariableDataValue());
-  GetDocument().EnsurePropertyRegistry().RegisterProperty("--prop3",
-                                                          *registration);
-
-  CustomProperty("--prop1", GetDocument()).ApplyValue(state, *prop1);
-  CustomProperty("--prop2", GetDocument()).ApplyValue(state, *prop2);
-  CustomProperty("--prop3", GetDocument()).ApplyValue(state, *prop3);
-
-  EXPECT_TRUE(state.Style()->InheritedVariables()->NeedsResolution());
-  EXPECT_TRUE(state.Style()->NonInheritedVariables()->NeedsResolution());
-
-  CSSVariableResolver(state).ResolveVariableDefinitions();
-
-  EXPECT_FALSE(state.Style()->InheritedVariables()->NeedsResolution());
-  EXPECT_FALSE(state.Style()->NonInheritedVariables()->NeedsResolution());
-}
-
-TEST_F(CSSVariableResolverTest, DontCrashWhenSettingInheritedNullVariable) {
-  scoped_refptr<StyleInheritedVariables> inherited_variables =
-      StyleInheritedVariables::Create();
-  AtomicString name("--test");
-  inherited_variables->SetData(name, nullptr);
-  inherited_variables->SetValue(name, nullptr);
-}
-
-TEST_F(CSSVariableResolverTest, DontCrashWhenSettingNonInheritedNullVariable) {
-  auto inherited_variables = std::make_unique<StyleNonInheritedVariables>();
-  AtomicString name("--test");
-  inherited_variables->SetData(name, nullptr);
-  inherited_variables->SetValue(name, nullptr);
-}
-
-TEST_F(CSSVariableResolverTest, TokenCountAboveLimitIsInValidForSubstitution) {
-  StringBuilder builder;
-  for (size_t i = 0; i < MaxSubstitutionTokens(); ++i)
-    builder.Append(":");
-  builder.Append(":");
-  builder.Append(";");
-  SetTestHTMLWithReferencedVariableValue(builder.ToString());
-
-  Element* target = GetDocument().getElementById("target");
-  ASSERT_TRUE(target);
-
-  // A custom property with more than MaxSubstitutionTokens() is valid ...
-  const CSSVariableData* referenced =
-      target->ComputedStyleRef().GetVariableData("--referenced");
-  ASSERT_TRUE(referenced);
-  EXPECT_EQ(MaxSubstitutionTokens() + 1, referenced->Tokens().size());
-
-  // ... it is not valid for substitution, however.
-  EXPECT_FALSE(target->ComputedStyleRef().GetVariableData("--x"));
-}
-
-TEST_F(CSSVariableResolverTest, TokenCountAtLimitIsValidForSubstitution) {
-  StringBuilder builder;
-  for (size_t i = 0; i < MaxSubstitutionTokens(); ++i)
-    builder.Append(":");
-  builder.Append(";");
-  SetTestHTMLWithReferencedVariableValue(builder.ToString());
-
-  Element* target = GetDocument().getElementById("target");
-  ASSERT_TRUE(target);
-
-  const CSSVariableData* referenced =
-      target->ComputedStyleRef().GetVariableData("--referenced");
-  ASSERT_TRUE(referenced);
-  EXPECT_EQ(MaxSubstitutionTokens(), referenced->Tokens().size());
-
-  const CSSVariableData* x = target->ComputedStyleRef().GetVariableData("--x");
-  ASSERT_TRUE(x);
-  EXPECT_EQ(MaxSubstitutionTokens(), x->Tokens().size());
-
-  EXPECT_EQ(*referenced, *x);
-}
-
-TEST_F(CSSVariableResolverTest, BillionLaughs) {
-  StringBuilder builder;
-  builder.Append("<style>\n");
-  builder.Append("#target {\n");
-
-  // Produces:
-  //
-  // --x1:lol;
-  // --x2:var(--x1)var(--x1);
-  // --x4:var(--x2)var(--x2);
-  // --x8:var(--x4)var(--x4);
-  // .. etc
-  builder.Append("  --x1:lol;\n");
-
-  size_t tokens = 1;
-  while (tokens <= MaxSubstitutionTokens()) {
-    tokens *= 2;
-    builder.Append("--x");
-    builder.AppendNumber(tokens);
-    builder.Append(":var(--x");
-    builder.AppendNumber(tokens / 2);
-    builder.Append(")");
-    builder.Append("var(--x");
-    builder.AppendNumber(tokens / 2);
-    builder.Append(")");
-    builder.Append(";");
-  }
-
-  builder.AppendNumber(tokens);
-  builder.Append(");\n");
-
-  builder.Append("--ref-last:var(--x");
-  builder.AppendNumber(tokens);
-  builder.Append(");");
-
-  builder.Append("--ref-next-to-last:var(--x");
-  builder.AppendNumber(tokens / 2);
-  builder.Append(");");
-
-  builder.Append("}\n");
-  builder.Append("</style>\n");
-  builder.Append("<div id=target></div>\n");
-
-  GetDocument().body()->setInnerHTML(builder.ToString());
-  UpdateAllLifecyclePhasesForTest();
-
-  Element* target = GetDocument().getElementById("target");
-  ASSERT_TRUE(target);
-
-  // The last --x2^N variable is over the limit. Any reference to that
-  // should be invalid.
-  const CSSVariableData* ref_last =
-      target->ComputedStyleRef().GetVariableData("--ref-last");
-  EXPECT_FALSE(ref_last);
-
-  // The next-to-last (--x2^(N-1)) variable is not over the limit. A reference
-  // to that is still valid.
-  const CSSVariableData* ref_next_to_last =
-      target->ComputedStyleRef().GetVariableData("--ref-next-to-last");
-  ASSERT_TRUE(ref_next_to_last);
-  EXPECT_EQ(tokens / 2, ref_next_to_last->Tokens().size());
-
-  // Ensure that there are a limited number of unique backing strings.
-  // Each variable will have many backing strings, but should point to
-  // a small number of StringImpls.
-
-  HashSet<const StringImpl*> impls;
-  for (const String& string : ref_next_to_last->BackingStrings())
-    impls.insert(string.Impl());
-
-  size_t expected_unique_strings = 0;
-
-  // Each --x2^N property has a unique backing string (for its var-tokens, etc).
-  // For --x1, that unique string is of course "lol".
-  for (size_t i = (tokens / 2); i != 0; i = i >> 1)
-    expected_unique_strings += 1;
-
-  // --ref-next-to-last also has a backing string.
-  expected_unique_strings += 1;
-
-  EXPECT_EQ(expected_unique_strings, impls.size());
-}
-
-TEST_F(CSSVariableResolverTest, CSSWideKeywords) {
-  using CSSUnsetValue = cssvalue::CSSUnsetValue;
-
-  const ComputedStyle* initial = &ComputedStyle::InitialStyle();
-  StyleResolverState state(GetDocument(), *GetDocument().documentElement(),
-                           initial, initial);
-
-  scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
-  style->InheritFrom(*initial);
-  state.SetStyle(std::move(style));
-
-  const CSSValue* whitespace = CreateCustomProperty("--w", " ");
-  StyleBuilder::ApplyProperty(CSSPropertyName("--w"), state, *whitespace);
-
-  // Test initial/inherit/unset for an inherited property:
-  EXPECT_EQ(CSSInitialValue::Create(),
-            ResolveVar(state, CSSPropertyID::kColor, "var(--w) initial"));
-  EXPECT_EQ(CSSInheritedValue::Create(),
-            ResolveVar(state, CSSPropertyID::kColor, "var(--w) inherit"));
-  EXPECT_EQ(CSSUnsetValue::Create(),
-            ResolveVar(state, CSSPropertyID::kColor, "var(--w) unset"));
-
-  // Test initial/inherit/unset for a non-inherited property:
-  EXPECT_EQ(CSSInitialValue::Create(),
-            ResolveVar(state, CSSPropertyID::kWidth, "var(--w) initial"));
-  EXPECT_EQ(CSSInheritedValue::Create(),
-            ResolveVar(state, CSSPropertyID::kWidth, "var(--w) inherit"));
-  EXPECT_EQ(CSSUnsetValue::Create(),
-            ResolveVar(state, CSSPropertyID::kWidth, "var(--w) unset"));
-
-  // Test initial/inherit/unset in fallbacks:
-
-  EXPECT_EQ(CSSInitialValue::Create(),
-            ResolveVar(state, CSSPropertyID::kColor, "var(--u,initial)"));
-  EXPECT_EQ(CSSInheritedValue::Create(),
-            ResolveVar(state, CSSPropertyID::kColor, "var(--u,inherit)"));
-  EXPECT_EQ(CSSUnsetValue::Create(),
-            ResolveVar(state, CSSPropertyID::kColor, "var(--u,unset)"));
-
-  EXPECT_EQ(CSSInitialValue::Create(),
-            ResolveVar(state, CSSPropertyID::kWidth, "var(--u,initial)"));
-  EXPECT_EQ(CSSInheritedValue::Create(),
-            ResolveVar(state, CSSPropertyID::kWidth, "var(--u,inherit)"));
-  EXPECT_EQ(CSSUnsetValue::Create(),
-            ResolveVar(state, CSSPropertyID::kWidth, "var(--u,unset)"));
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder.cc b/third_party/blink/renderer/core/css/resolver/style_builder.cc
index 546f7a0..7b72837 100644
--- a/third_party/blink/renderer/core/css/resolver/style_builder.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_builder.cc
@@ -46,11 +46,9 @@
 #include "third_party/blink/renderer/core/css/properties/css_property_ref.h"
 #include "third_party/blink/renderer/core/css/properties/longhand.h"
 #include "third_party/blink/renderer/core/css/properties/longhands/variable.h"
-#include "third_party/blink/renderer/core/css/resolver/css_variable_resolver.h"
 #include "third_party/blink/renderer/core/css/resolver/style_builder.h"
 #include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 
 namespace blink {
 
@@ -72,27 +70,9 @@
   CSSPropertyID id = property.PropertyID();
   bool is_inherited = property.IsInherited();
 
-  if (RuntimeEnabledFeatures::CSSCascadeEnabled()) {
-    // These values must be resolved by StyleCascade before application:
-    DCHECK(!value.IsVariableReferenceValue());
-    DCHECK(!value.IsPendingSubstitutionValue());
-  } else {
-    if (id != CSSPropertyID::kVariable &&
-        (value.IsVariableReferenceValue() ||
-         value.IsPendingSubstitutionValue())) {
-      bool omit_animation_tainted =
-          CSSAnimations::IsAnimationAffectingProperty(property);
-      const CSSValue* resolved_value =
-          CSSVariableResolver(state).ResolveVariableReferences(
-              id, value, omit_animation_tainted);
-      ApplyProperty(property, state, *resolved_value);
-
-      if (!state.Style()->HasVariableReferenceFromNonInheritedProperty() &&
-          !is_inherited)
-        state.Style()->SetHasVariableReferenceFromNonInheritedProperty();
-      return;
-    }
-  }
+  // These values must be resolved by StyleCascade before application:
+  DCHECK(!value.IsVariableReferenceValue());
+  DCHECK(!value.IsPendingSubstitutionValue());
 
   DCHECK(!property.IsShorthand())
       << "Shorthand property id = " << static_cast<int>(id)
diff --git a/third_party/blink/renderer/core/css/resolver/style_cascade_test.cc b/third_party/blink/renderer/core/css/resolver/style_cascade_test.cc
index cc95a79..72d39b4 100644
--- a/third_party/blink/renderer/core/css/resolver/style_cascade_test.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_cascade_test.cc
@@ -270,13 +270,11 @@
 
 class StyleCascadeTest
     : public PageTestBase,
-      private ScopedCSSCascadeForTest,
       private ScopedCSSRevertForTest,
       private ScopedCSSMatchedPropertiesCacheDependenciesForTest {
  public:
   StyleCascadeTest()
-      : ScopedCSSCascadeForTest(true),
-        ScopedCSSRevertForTest(true),
+      : ScopedCSSRevertForTest(true),
         ScopedCSSMatchedPropertiesCacheDependenciesForTest(true) {}
 
   CSSStyleSheet* CreateSheet(const String& css_text) {
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver.cc b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
index 00e8299..ba3b0cf2 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
@@ -32,14 +32,8 @@
 
 #include "third_party/blink/renderer/core/animation/css/compositor_keyframe_value_factory.h"
 #include "third_party/blink/renderer/core/animation/css/css_animations.h"
-#include "third_party/blink/renderer/core/animation/css_interpolation_environment.h"
-#include "third_party/blink/renderer/core/animation/css_interpolation_types_map.h"
 #include "third_party/blink/renderer/core/animation/element_animations.h"
 #include "third_party/blink/renderer/core/animation/invalidatable_interpolation.h"
-#include "third_party/blink/renderer/core/animation/keyframe_effect.h"
-#include "third_party/blink/renderer/core/animation/transition_interpolation.h"
-#include "third_party/blink/renderer/core/css/css_color_value.h"
-#include "third_party/blink/renderer/core/css/css_custom_ident_value.h"
 #include "third_party/blink/renderer/core/css/css_default_style_sheets.h"
 #include "third_party/blink/renderer/core/css/css_font_selector.h"
 #include "third_party/blink/renderer/core/css/css_identifier_value.h"
@@ -47,23 +41,17 @@
 #include "third_party/blink/renderer/core/css/css_keyframe_rule.h"
 #include "third_party/blink/renderer/core/css/css_keyframes_rule.h"
 #include "third_party/blink/renderer/core/css/css_property_names.h"
-#include "third_party/blink/renderer/core/css/css_property_value_set.h"
-#include "third_party/blink/renderer/core/css/css_reflect_value.h"
 #include "third_party/blink/renderer/core/css/css_rule_list.h"
 #include "third_party/blink/renderer/core/css/css_selector.h"
 #include "third_party/blink/renderer/core/css/css_selector_watch.h"
 #include "third_party/blink/renderer/core/css/css_style_declaration.h"
 #include "third_party/blink/renderer/core/css/css_style_rule.h"
-#include "third_party/blink/renderer/core/css/css_unset_value.h"
-#include "third_party/blink/renderer/core/css/css_value_list.h"
 #include "third_party/blink/renderer/core/css/element_rule_collector.h"
 #include "third_party/blink/renderer/core/css/font_face.h"
 #include "third_party/blink/renderer/core/css/page_rule_collector.h"
 #include "third_party/blink/renderer/core/css/part_names.h"
 #include "third_party/blink/renderer/core/css/properties/css_property.h"
 #include "third_party/blink/renderer/core/css/properties/css_property_ref.h"
-#include "third_party/blink/renderer/core/css/resolver/css_variable_animator.h"
-#include "third_party/blink/renderer/core/css/resolver/css_variable_resolver.h"
 #include "third_party/blink/renderer/core/css/resolver/match_result.h"
 #include "third_party/blink/renderer/core/css/resolver/scoped_style_resolver.h"
 #include "third_party/blink/renderer/core/css/resolver/selector_filter_parent_scope.h"
@@ -94,7 +82,6 @@
 #include "third_party/blink/renderer/core/mathml_names.h"
 #include "third_party/blink/renderer/core/media_type_names.h"
 #include "third_party/blink/renderer/core/probe/core_probes.h"
-#include "third_party/blink/renderer/core/style/style_inherited_variables.h"
 #include "third_party/blink/renderer/core/style/style_initial_data.h"
 #include "third_party/blink/renderer/core/style_property_shorthand.h"
 #include "third_party/blink/renderer/core/svg/svg_element.h"
@@ -790,8 +777,6 @@
 
 static const ComputedStyle* CachedAnimationBaseComputedStyle(
     StyleResolverState& state) {
-  if (!RuntimeEnabledFeatures::CSSCascadeEnabled())
-    return nullptr;
   ElementAnimations* element_animations = GetElementAnimations(state);
   if (!element_animations)
     return nullptr;
@@ -849,8 +834,7 @@
       matching_behavior == kMatchAllRules;
 
   STACK_UNINITIALIZED StyleCascade cascade(state);
-  StyleCascade* cascade_ptr =
-      RuntimeEnabledFeatures::CSSCascadeEnabled() ? &cascade : nullptr;
+  StyleCascade* cascade_ptr = &cascade;
 
   ApplyBaseComputedStyle(element, state, cascade_ptr,
                          cascade.MutableMatchResult(), matching_behavior,
@@ -1000,12 +984,8 @@
     if (state.HasDirAutoAttribute())
       state.Style()->SetSelfOrAncestorHasDirAutoAttribute(true);
 
-    if (RuntimeEnabledFeatures::CSSCascadeEnabled()) {
-      DCHECK(cascade);
-      CascadeAndApplyMatchedProperties(state, *cascade);
-    } else {
-      ApplyMatchedProperties(state, match_result);
-    }
+    DCHECK(cascade);
+    CascadeAndApplyMatchedProperties(state, *cascade);
 
     ApplyCallbackSelectors(state);
 
@@ -1043,20 +1023,14 @@
                            parent_style);
   state.SetStyle(ComputedStyle::Clone(base_style));
   if (value) {
-    if (RuntimeEnabledFeatures::CSSCascadeEnabled()) {
-      STACK_UNINITIALIZED StyleCascade cascade(state);
-      auto* set = MakeGarbageCollected<MutableCSSPropertyValueSet>(
-          state.GetParserMode());
-      set->SetProperty(property.GetCSSProperty().PropertyID(), *value);
-      cascade.MutableMatchResult().FinishAddingUARules();
-      cascade.MutableMatchResult().FinishAddingUserRules();
-      cascade.MutableMatchResult().AddMatchedProperties(set);
-      cascade.Apply();
-    } else {
-      StyleBuilder::ApplyProperty(property.GetCSSPropertyName(), state, *value);
-      state.GetFontBuilder().CreateFont(state.StyleRef(), parent_style);
-      CSSVariableResolver(state).ResolveVariableDefinitions();
-    }
+    STACK_UNINITIALIZED StyleCascade cascade(state);
+    auto* set =
+        MakeGarbageCollected<MutableCSSPropertyValueSet>(state.GetParserMode());
+    set->SetProperty(property.GetCSSProperty().PropertyID(), *value);
+    cascade.MutableMatchResult().FinishAddingUARules();
+    cascade.MutableMatchResult().FinishAddingUserRules();
+    cascade.MutableMatchResult().AddMatchedProperties(set);
+    cascade.Apply();
   }
   return CompositorKeyframeValueFactory::Create(property, *state.Style());
 }
@@ -1080,8 +1054,7 @@
   // user agent rules, don't waste time walking those rules.
 
   STACK_UNINITIALIZED StyleCascade cascade(state);
-  StyleCascade* cascade_ptr =
-      RuntimeEnabledFeatures::CSSCascadeEnabled() ? &cascade : nullptr;
+  StyleCascade* cascade_ptr = &cascade;
 
   if (ShouldComputeBaseComputedStyle(animation_base_computed_style)) {
     if (pseudo_style_request.AllowsInheritance(state.ParentStyle())) {
@@ -1123,10 +1096,7 @@
       return false;
     }
 
-    if (RuntimeEnabledFeatures::CSSCascadeEnabled())
-      CascadeAndApplyMatchedProperties(state, cascade);
-    else
-      ApplyMatchedProperties(state, cascade.GetMatchResult());
+    CascadeAndApplyMatchedProperties(state, cascade);
 
     ApplyCallbackSelectors(state);
 
@@ -1222,25 +1192,7 @@
           GetDocument().GetScopedStyleResolver())
     scoped_resolver->MatchPageRules(collector);
 
-  bool inherited_only = false;
-
-  NeedsApplyPass needs_apply_pass;
-  const MatchResult& result = collector.MatchedResult();
-
-  if (RuntimeEnabledFeatures::CSSCascadeEnabled()) {
-    cascade.Apply();
-  } else {
-    ApplyMatchedProperties<kAnimationPropertyPriority, kUpdateNeedsApplyPass>(
-        state, result.AllRules(), false, inherited_only, needs_apply_pass);
-    ApplyMatchedProperties<kHighPropertyPriority, kCheckNeedsApplyPass>(
-        state, result.AllRules(), false, inherited_only, needs_apply_pass);
-
-    // If our font got dirtied, go ahead and update it now.
-    UpdateFont(state);
-
-    ApplyMatchedProperties<kLowPropertyPriority, kCheckNeedsApplyPass>(
-        state, result.AllRules(), false, inherited_only, needs_apply_pass);
-  }
+  cascade.Apply();
 
   // Now return the style.
   return state.TakeStyle();
@@ -1382,10 +1334,7 @@
     return false;
   }
 
-  if (!state.IsAnimationInterpolationMapReady() ||
-      RuntimeEnabledFeatures::CSSCascadeEnabled()) {
-    CalculateAnimationUpdate(state);
-  }
+  CalculateAnimationUpdate(state);
 
   CSSAnimations::CalculateCompositorAnimationUpdate(
       state.AnimationUpdate(), animating_element, element, *state.Style(),
@@ -1412,35 +1361,20 @@
   const ActiveInterpolationsMap& custom_transitions =
       state.AnimationUpdate().ActiveInterpolationsForCustomTransitions();
 
-  if (RuntimeEnabledFeatures::CSSCascadeEnabled()) {
-    DCHECK(cascade);
-    cascade->AddInterpolations(&standard_animations, CascadeOrigin::kAnimation);
-    cascade->AddInterpolations(&standard_transitions,
-                               CascadeOrigin::kTransition);
-    cascade->AddInterpolations(&custom_animations, CascadeOrigin::kAnimation);
-    cascade->AddInterpolations(&custom_transitions, CascadeOrigin::kTransition);
+  DCHECK(cascade);
+  cascade->AddInterpolations(&standard_animations, CascadeOrigin::kAnimation);
+  cascade->AddInterpolations(&standard_transitions, CascadeOrigin::kTransition);
+  cascade->AddInterpolations(&custom_animations, CascadeOrigin::kAnimation);
+  cascade->AddInterpolations(&custom_transitions, CascadeOrigin::kTransition);
 
-    CascadeFilter filter;
-    if (IsForcedColorsModeEnabled(state))
-      filter = filter.Add(CSSProperty::kIsAffectedByForcedColors, true);
-    if (state.Style()->StyleType() == kPseudoIdMarker)
-      filter = filter.Add(CSSProperty::kValidForMarker, false);
-    filter = filter.Add(CSSProperty::kAnimation, true);
+  CascadeFilter filter;
+  if (IsForcedColorsModeEnabled(state))
+    filter = filter.Add(CSSProperty::kIsAffectedByForcedColors, true);
+  if (state.Style()->StyleType() == kPseudoIdMarker)
+    filter = filter.Add(CSSProperty::kValidForMarker, false);
+  filter = filter.Add(CSSProperty::kAnimation, true);
 
-    cascade->Apply(filter);
-  } else {
-    ApplyAnimatedStandardProperties<kHighPropertyPriority>(state,
-                                                           standard_animations);
-    ApplyAnimatedStandardProperties<kHighPropertyPriority>(
-        state, standard_transitions);
-
-    UpdateFont(state);
-
-    ApplyAnimatedStandardProperties<kLowPropertyPriority>(state,
-                                                          standard_animations);
-    ApplyAnimatedStandardProperties<kLowPropertyPriority>(state,
-                                                          standard_transitions);
-  }
+  cascade->Apply(filter);
 
   // Start loading resources used by animations.
   state.LoadPendingResources();
@@ -1475,238 +1409,6 @@
   return nullptr;
 }
 
-static bool PassesPropertyFilter(ValidPropertyFilter valid_property_filter,
-                                 CSSPropertyID property,
-                                 const Document& document) {
-  switch (valid_property_filter) {
-    case ValidPropertyFilter::kNoFilter:
-      return true;
-    case ValidPropertyFilter::kFirstLetter:
-      return CSSProperty::Get(property).IsValidForFirstLetter();
-    case ValidPropertyFilter::kCue:
-      return CSSProperty::Get(property).IsValidForCue();
-    case ValidPropertyFilter::kMarker:
-      return CSSProperty::Get(property).IsValidForMarker();
-  }
-  NOTREACHED();
-  return true;
-}
-
-template <CSSPropertyPriority priority>
-void StyleResolver::ApplyAnimatedStandardProperties(
-    StyleResolverState& state,
-    const ActiveInterpolationsMap& active_interpolations_map) {
-  static_assert(priority != kResolveVariables,
-                "Use CSSVariableAnimator for custom property animations");
-  // TODO(alancutter): Don't apply presentation attribute animations here,
-  // they should instead apply in
-  // SVGElement::CollectStyleForPresentationAttribute().
-  for (const auto& entry : active_interpolations_map) {
-    CSSPropertyID property =
-        entry.key.IsCSSProperty()
-            ? entry.key.GetCSSProperty().PropertyID()
-            : entry.key.PresentationAttribute().PropertyID();
-    if (!CSSPropertyPriorityData<priority>::PropertyHasPriority(property))
-      continue;
-    if (IsForcedColorsModeEnabled() && entry.key.IsCSSProperty() &&
-        entry.key.GetCSSProperty().IsAffectedByForcedColors() &&
-        state.Style()->ForcedColorAdjust() != EForcedColorAdjust::kNone)
-      continue;
-    if (state.Style()->StyleType() == kPseudoIdMarker &&
-        !PassesPropertyFilter(ValidPropertyFilter::kMarker, property,
-                              state.GetDocument()))
-      continue;
-    const Interpolation& interpolation = *entry.value.front();
-    if (IsA<InvalidatableInterpolation>(interpolation)) {
-      CSSInterpolationTypesMap map(state.GetDocument().GetPropertyRegistry(),
-                                   state.GetDocument());
-      CSSInterpolationEnvironment environment(map, state, nullptr);
-      InvalidatableInterpolation::ApplyStack(entry.value, environment);
-    } else {
-      To<TransitionInterpolation>(interpolation).Apply(state);
-    }
-  }
-}
-
-static inline void ApplyProperty(const CSSProperty& property,
-                                 StyleResolverState& state,
-                                 const CSSValue& value,
-                                 unsigned apply_mask) {
-  if (apply_mask & kApplyMaskRegular)
-    StyleBuilder::ApplyProperty(property, state, value);
-  if (apply_mask & kApplyMaskVisited) {
-    if (const CSSProperty* visited = property.GetVisitedProperty())
-      StyleBuilder::ApplyProperty(*visited, state, value);
-  }
-}
-
-// This method expands the 'all' shorthand property to longhand properties
-// and applies the expanded longhand properties.
-template <CSSPropertyPriority priority>
-void StyleResolver::ApplyAllProperty(StyleResolverState& state,
-                                     const CSSValue& all_value,
-                                     bool inherited_only,
-                                     ValidPropertyFilter valid_property_filter,
-                                     unsigned apply_mask) {
-  // The 'all' property doesn't apply to variables:
-  // https://drafts.csswg.org/css-variables/#defining-variables
-  if (priority == kResolveVariables)
-    return;
-
-  unsigned start_css_property =
-      static_cast<unsigned>(CSSPropertyPriorityData<priority>::First());
-  unsigned end_css_property =
-      static_cast<unsigned>(CSSPropertyPriorityData<priority>::Last());
-
-  for (unsigned i = start_css_property; i <= end_css_property; ++i) {
-    CSSPropertyID property_id = static_cast<CSSPropertyID>(i);
-    const CSSProperty& property_class =
-        CSSProperty::Get(resolveCSSPropertyID(property_id));
-
-    // StyleBuilder does not allow any expanded shorthands.
-    if (property_class.IsShorthand())
-      continue;
-
-    // all shorthand spec says:
-    // The all property is a shorthand that resets all CSS properties
-    // except direction and unicode-bidi.
-    // c.f. https://drafts.csswg.org/css-cascade/#all-shorthand
-    // We skip applyProperty when a given property is unicode-bidi or
-    // direction.
-    if (!property_class.IsAffectedByAll())
-      continue;
-
-    if (!PassesPropertyFilter(valid_property_filter, property_id,
-                              GetDocument()))
-      continue;
-
-    // When hitting matched properties' cache, only inherited properties will be
-    // applied.
-    if (inherited_only && !property_class.IsInherited())
-      continue;
-
-    ApplyProperty(property_class, state, all_value, apply_mask);
-  }
-}
-
-template <CSSPropertyPriority priority>
-static inline void ApplyProperty(
-    const CSSPropertyValueSet::PropertyReference& reference,
-    StyleResolverState& state,
-    unsigned apply_mask) {
-  static_assert(
-      priority != kResolveVariables,
-      "Application of custom properties must use specialized template");
-  DCHECK_NE(reference.Id(), CSSPropertyID::kVariable);
-  ApplyProperty(reference.Property(), state, reference.Value(), apply_mask);
-}
-
-template <>
-inline void ApplyProperty<kResolveVariables>(
-    const CSSPropertyValueSet::PropertyReference& reference,
-    StyleResolverState& state,
-    unsigned apply_mask) {
-  CSSPropertyRef ref(reference.Name(), state.GetDocument());
-  ApplyProperty(ref.GetProperty(), state, reference.Value(), apply_mask);
-}
-
-template <CSSPropertyPriority priority,
-          StyleResolver::ShouldUpdateNeedsApplyPass shouldUpdateNeedsApplyPass>
-void StyleResolver::ApplyProperties(StyleResolverState& state,
-                                    const CSSPropertyValueSet* properties,
-                                    bool is_important,
-                                    bool inherited_only,
-                                    NeedsApplyPass& needs_apply_pass,
-                                    ValidPropertyFilter valid_property_filter,
-                                    unsigned apply_mask,
-                                    ForcedColorFilter forced_colors) {
-  unsigned property_count = properties->PropertyCount();
-  for (unsigned i = 0; i < property_count; ++i) {
-    CSSPropertyValueSet::PropertyReference current = properties->PropertyAt(i);
-    CSSPropertyID property_id = current.Id();
-
-    if (property_id == CSSPropertyID::kAll &&
-        is_important == current.IsImportant()) {
-      if (shouldUpdateNeedsApplyPass) {
-        needs_apply_pass.Set(kAnimationPropertyPriority, is_important);
-        needs_apply_pass.Set(kHighPropertyPriority, is_important);
-        needs_apply_pass.Set(kLowPropertyPriority, is_important);
-      }
-      ApplyAllProperty<priority>(state, current.Value(), inherited_only,
-                                 valid_property_filter, apply_mask);
-      continue;
-    }
-
-    if (shouldUpdateNeedsApplyPass)
-      needs_apply_pass.Set(PriorityForProperty(property_id),
-                           current.IsImportant());
-
-    if (is_important != current.IsImportant())
-      continue;
-
-    if (!PassesPropertyFilter(valid_property_filter, property_id,
-                              GetDocument()))
-      continue;
-
-    if (!CSSPropertyPriorityData<priority>::PropertyHasPriority(property_id))
-      continue;
-
-    if (inherited_only && !current.IsInherited()) {
-      // If the property value is explicitly inherited, we need to apply further
-      // non-inherited properties as they might override the value inherited
-      // here. For this reason we don't allow declarations with explicitly
-      // inherited properties to be cached.
-      DCHECK(!current.Value().IsInheritedValue() ||
-             (!(apply_mask & kApplyMaskRegular) &&
-              (!(apply_mask & kApplyMaskVisited) ||
-               !current.Property().GetVisitedProperty())));
-      continue;
-    }
-
-    if (IsForcedColorsModeEnabled() &&
-        forced_colors == ForcedColorFilter::kEnabled &&
-        !current.Property().IsAffectedByForcedColors()) {
-      continue;
-    }
-
-    ApplyProperty<priority>(current, state, apply_mask);
-  }
-}
-
-template <CSSPropertyPriority priority,
-          StyleResolver::ShouldUpdateNeedsApplyPass shouldUpdateNeedsApplyPass>
-void StyleResolver::ApplyMatchedProperties(StyleResolverState& state,
-                                           const MatchedPropertiesRange& range,
-                                           bool is_important,
-                                           bool inherited_only,
-                                           NeedsApplyPass& needs_apply_pass,
-                                           ForcedColorFilter forced_colors) {
-  DCHECK(!RuntimeEnabledFeatures::CSSCascadeEnabled());
-
-  if (range.IsEmpty())
-    return;
-
-  if (!shouldUpdateNeedsApplyPass &&
-      !needs_apply_pass.Get(priority, is_important))
-    return;
-
-  for (const auto& matched_properties : range) {
-    static_assert(static_cast<int>(kApplyMaskRegular) ==
-                      static_cast<int>(CSSSelector::kMatchLink),
-                  "kApplyMaskRegular and kMatchLink must match");
-    static_assert(static_cast<int>(kApplyMaskVisited) ==
-                      static_cast<int>(CSSSelector::kMatchVisited),
-                  "kApplyMaskVisited and kMatchVisited must match");
-    const unsigned apply_mask = matched_properties.types_.link_match_type;
-    ApplyProperties<priority, shouldUpdateNeedsApplyPass>(
-        state, matched_properties.properties.Get(), is_important,
-        inherited_only, needs_apply_pass,
-        static_cast<ValidPropertyFilter>(
-            matched_properties.types_.valid_property_filter),
-        apply_mask, forced_colors);
-  }
-}
-
 void StyleResolver::InvalidateMatchedPropertiesCache() {
   matched_properties_cache_.Clear();
 }
@@ -1722,80 +1424,6 @@
   was_viewport_resized_ = false;
 }
 
-template <CSSPropertyPriority priority>
-void StyleResolver::ApplyForcedColors(StyleResolverState& state,
-                                      const MatchResult& match_result,
-                                      bool apply_inherited_only,
-                                      NeedsApplyPass& needs_apply_pass) {
-  if (!IsForcedColorsModeEnabled())
-    return;
-  if (state.Style()->ForcedColorAdjust() == EForcedColorAdjust::kNone)
-    return;
-
-  const CSSValue* unset = cssvalue::CSSUnsetValue::Create();
-  unsigned apply_mask = kApplyMaskRegular | kApplyMaskVisited;
-
-  // This simulates 'revert !important' in the user origin.
-  // https://drafts.csswg.org/css-color-adjust-1/#forced-colors-properties
-  if (priority == kHighPropertyPriority) {
-    ApplyProperty(GetCSSPropertyColor(), state, *unset, apply_mask);
-    ApplyUaForcedColors<priority>(state, match_result, apply_inherited_only,
-                                  needs_apply_pass);
-  } else {
-    DCHECK(priority == kLowPropertyPriority);
-    ApplyProperty(GetCSSPropertyBorderBottomColor(), state, *unset, apply_mask);
-    ApplyProperty(GetCSSPropertyBorderLeftColor(), state, *unset, apply_mask);
-    ApplyProperty(GetCSSPropertyBorderRightColor(), state, *unset, apply_mask);
-    ApplyProperty(GetCSSPropertyBorderTopColor(), state, *unset, apply_mask);
-    ApplyProperty(GetCSSPropertyBoxShadow(), state, *unset, apply_mask);
-    ApplyProperty(GetCSSPropertyColumnRuleColor(), state, *unset, apply_mask);
-    ApplyProperty(GetCSSPropertyFill(), state, *unset, apply_mask);
-    ApplyProperty(GetCSSPropertyOutlineColor(), state, *unset, apply_mask);
-    ApplyProperty(GetCSSPropertyStroke(), state, *unset, apply_mask);
-    ApplyProperty(GetCSSPropertyTextDecorationColor(), state, *unset,
-                  apply_mask);
-    ApplyProperty(GetCSSPropertyTextShadow(), state, *unset, apply_mask);
-    ApplyProperty(GetCSSPropertyWebkitTapHighlightColor(), state, *unset,
-                  apply_mask);
-    ApplyProperty(GetCSSPropertyWebkitTextEmphasisColor(), state, *unset,
-                  apply_mask);
-
-    // Background colors compute to the Canvas system color for all values
-    // except for the alpha channel.
-    RGBA32 prev_bg_color = state.Style()->BackgroundColor().GetColor().Rgb();
-    RGBA32 sys_bg_color =
-        LayoutTheme::GetTheme()
-            .SystemColor(CSSValueID::kCanvas, WebColorScheme::kLight)
-            .Rgb();
-    ApplyProperty(GetCSSPropertyBackgroundColor(), state,
-                  *cssvalue::CSSColorValue::Create(sys_bg_color), apply_mask);
-
-    ApplyUaForcedColors<priority>(state, match_result, apply_inherited_only,
-                                  needs_apply_pass);
-
-    RGBA32 current_bg_color = state.Style()->BackgroundColor().GetColor().Rgb();
-    RGBA32 bg_color =
-        MakeRGBA(RedChannel(current_bg_color), GreenChannel(current_bg_color),
-                 BlueChannel(current_bg_color), AlphaChannel(prev_bg_color));
-    ApplyProperty(GetCSSPropertyBackgroundColor(), state,
-                  *cssvalue::CSSColorValue::Create(bg_color), apply_mask);
-  }
-}
-
-template <CSSPropertyPriority priority>
-void StyleResolver::ApplyUaForcedColors(StyleResolverState& state,
-                                        const MatchResult& match_result,
-                                        bool apply_inherited_only,
-                                        NeedsApplyPass& needs_apply_pass) {
-  auto force_colors = ForcedColorFilter::kEnabled;
-  ApplyMatchedProperties<priority, kCheckNeedsApplyPass>(
-      state, match_result.UaRules(), false, apply_inherited_only,
-      needs_apply_pass, force_colors);
-  ApplyMatchedProperties<priority, kCheckNeedsApplyPass>(
-      state, match_result.UaRules(), true, apply_inherited_only,
-      needs_apply_pass, force_colors);
-}
-
 bool StyleResolver::CacheSuccess::EffectiveZoomChanged(
     const ComputedStyle& style) const {
   if (!cached_matched_properties)
@@ -1897,45 +1525,6 @@
   }
 }
 
-void StyleResolver::ApplyCustomProperties(StyleResolverState& state,
-                                          const MatchResult& match_result,
-                                          const CacheSuccess& cache_success,
-                                          NeedsApplyPass& needs_apply_pass) {
-  DCHECK(!cache_success.IsFullCacheHit());
-  bool apply_inherited_only = cache_success.ShouldApplyInheritedOnly();
-
-  // TODO(leviw): We need the proper bit for tracking whether we need to do
-  // this work.
-  ApplyMatchedProperties<kResolveVariables, kUpdateNeedsApplyPass>(
-      state, match_result.UserRules(), false, apply_inherited_only,
-      needs_apply_pass);
-  ApplyMatchedProperties<kResolveVariables, kUpdateNeedsApplyPass>(
-      state, match_result.AuthorRules(), false, apply_inherited_only,
-      needs_apply_pass);
-  ApplyMatchedProperties<kResolveVariables, kCheckNeedsApplyPass>(
-      state, match_result.AuthorRules(), true, apply_inherited_only,
-      needs_apply_pass);
-  ApplyMatchedProperties<kResolveVariables, kCheckNeedsApplyPass>(
-      state, match_result.UserRules(), true, apply_inherited_only,
-      needs_apply_pass);
-}
-
-void StyleResolver::ApplyMatchedAnimationProperties(
-    StyleResolverState& state,
-    const MatchResult& match_result,
-    const CacheSuccess& cache_success,
-    NeedsApplyPass& needs_apply_pass) {
-  DCHECK(!cache_success.IsFullCacheHit());
-  bool apply_inherited_only = cache_success.ShouldApplyInheritedOnly();
-
-  ApplyMatchedProperties<kAnimationPropertyPriority, kUpdateNeedsApplyPass>(
-      state, match_result.AllRules(), false, apply_inherited_only,
-      needs_apply_pass);
-  ApplyMatchedProperties<kAnimationPropertyPriority, kCheckNeedsApplyPass>(
-      state, match_result.AllRules(), true, apply_inherited_only,
-      needs_apply_pass);
-}
-
 void StyleResolver::CalculateAnimationUpdate(StyleResolverState& state) {
   Element* animating_element = state.GetAnimatingElement();
 
@@ -1965,167 +1554,6 @@
   }
 }
 
-void StyleResolver::ApplyMatchedHighPriorityProperties(
-    StyleResolverState& state,
-    const MatchResult& match_result,
-    const CacheSuccess& cache_success,
-    bool& apply_inherited_only,
-    NeedsApplyPass& needs_apply_pass) {
-  // Now we have all of the matched rules in the appropriate order. Walk the
-  // rules and apply high-priority properties first, i.e., those properties that
-  // other properties depend on.  The order is (1) high-priority not important,
-  // (2) high-priority important, (3) normal not important and (4) normal
-  // important.
-  ApplyMatchedProperties<kHighPropertyPriority, kCheckNeedsApplyPass>(
-      state, match_result.AllRules(), false, apply_inherited_only,
-      needs_apply_pass);
-  for (auto range : ImportantAuthorRanges(match_result)) {
-    ApplyMatchedProperties<kHighPropertyPriority, kCheckNeedsApplyPass>(
-        state, range, true, apply_inherited_only, needs_apply_pass);
-  }
-  for (auto range : ImportantUserRanges(match_result)) {
-    ApplyMatchedProperties<kHighPropertyPriority, kCheckNeedsApplyPass>(
-        state, range, true, apply_inherited_only, needs_apply_pass);
-  }
-  ApplyMatchedProperties<kHighPropertyPriority, kCheckNeedsApplyPass>(
-      state, match_result.UaRules(), true, apply_inherited_only,
-      needs_apply_pass);
-
-  if (IsForcedColorsModeEnabled() &&
-      state.Style()->ForcedColorAdjust() != EForcedColorAdjust::kNone) {
-    ApplyForcedColors<kHighPropertyPriority>(
-        state, match_result, apply_inherited_only, needs_apply_pass);
-  }
-
-  if (cache_success.cached_matched_properties &&
-      cache_success.cached_matched_properties->computed_style
-              ->EffectiveZoom() != state.Style()->EffectiveZoom()) {
-    state.GetFontBuilder().DidChangeEffectiveZoom();
-    apply_inherited_only = false;
-  }
-
-  ApplyCascadedColorValue(state);
-
-  // If our font got dirtied, go ahead and update it now.
-  UpdateFont(state);
-
-  // Many properties depend on the font. If it changes we just apply all
-  // properties.
-  if (cache_success.cached_matched_properties &&
-      cache_success.cached_matched_properties->computed_style
-              ->GetFontDescription() != state.Style()->GetFontDescription())
-    apply_inherited_only = false;
-}
-
-void StyleResolver::ApplyMatchedLowPriorityProperties(
-    StyleResolverState& state,
-    const MatchResult& match_result,
-    const CacheSuccess& cache_success,
-    bool& apply_inherited_only,
-    NeedsApplyPass& needs_apply_pass) {
-  // Now do the normal priority UA properties.
-  ApplyMatchedProperties<kLowPropertyPriority, kCheckNeedsApplyPass>(
-      state, match_result.UaRules(), false, apply_inherited_only,
-      needs_apply_pass);
-
-  // Cache the UA properties to pass them to LayoutTheme in
-  // StyleAdjuster::AdjustComputedStyle.
-  state.CacheUserAgentBorderAndBackground();
-
-  // Now do the author and user normal priority properties and all the
-  // !important properties.
-  ApplyMatchedProperties<kLowPropertyPriority, kCheckNeedsApplyPass>(
-      state, match_result.UserRules(), false, apply_inherited_only,
-      needs_apply_pass);
-  ApplyMatchedProperties<kLowPropertyPriority, kCheckNeedsApplyPass>(
-      state, match_result.AuthorRules(), false, apply_inherited_only,
-      needs_apply_pass);
-  for (auto range : ImportantAuthorRanges(match_result)) {
-    ApplyMatchedProperties<kLowPropertyPriority, kCheckNeedsApplyPass>(
-        state, range, true, apply_inherited_only, needs_apply_pass);
-  }
-  for (auto range : ImportantUserRanges(match_result)) {
-    ApplyMatchedProperties<kLowPropertyPriority, kCheckNeedsApplyPass>(
-        state, range, true, apply_inherited_only, needs_apply_pass);
-  }
-
-  if (state.Style()->HasAppearance() && !apply_inherited_only) {
-    // Check whether the final border and background differs from the cached UA
-    // ones.  When there is a partial match in the MatchedPropertiesCache, these
-    // flags will already be set correctly and the value stored in
-    // cacheUserAgentBorderAndBackground is incorrect, so doing this check again
-    // would give the wrong answer.
-    state.Style()->SetHasAuthorBackground(HasAuthorBackground(state));
-    state.Style()->SetHasAuthorBorder(HasAuthorBorder(state));
-  }
-
-  ApplyMatchedProperties<kLowPropertyPriority, kCheckNeedsApplyPass>(
-      state, match_result.UaRules(), true, apply_inherited_only,
-      needs_apply_pass);
-
-  if (IsForcedColorsModeEnabled() &&
-      state.Style()->ForcedColorAdjust() != EForcedColorAdjust::kNone) {
-    ApplyForcedColors<kLowPropertyPriority>(
-        state, match_result, apply_inherited_only, needs_apply_pass);
-  }
-
-  MaybeAddToMatchedPropertiesCache(state, cache_success, match_result);
-
-  DCHECK(!state.GetFontBuilder().FontDirty());
-}
-
-void StyleResolver::ApplyMatchedProperties(StyleResolverState& state,
-                                           const MatchResult& match_result) {
-  DCHECK(!RuntimeEnabledFeatures::CSSCascadeEnabled());
-
-  INCREMENT_STYLE_STATS_COUNTER(GetDocument().GetStyleEngine(),
-                                matched_property_apply, 1);
-
-  CacheSuccess cache_success = ApplyMatchedCache(state, match_result);
-  bool apply_inherited_only = cache_success.ShouldApplyInheritedOnly();
-  NeedsApplyPass needs_apply_pass;
-
-  if (!cache_success.IsFullCacheHit()) {
-    ApplyCustomProperties(state, match_result, cache_success, needs_apply_pass);
-    ApplyMatchedAnimationProperties(state, match_result, cache_success,
-                                    needs_apply_pass);
-    ApplyMatchedHighPriorityProperties(state, match_result, cache_success,
-                                       apply_inherited_only, needs_apply_pass);
-  }
-
-  if (HasAnimationsOrTransitions(state)) {
-    // Calculate pre-animated computed values for all registered properties.
-    // This is needed to calculate the animation update.
-    CSSVariableResolver(state).ComputeRegisteredVariables();
-
-    // Animation update calculation must happen after application of high
-    // priority properties, otherwise we can't resolve em' units, making it
-    // impossible to know if we should transition in some cases.
-    CalculateAnimationUpdate(state);
-
-    if (state.IsAnimatingCustomProperties()) {
-      cache_success.SetFailed();
-
-      CSSVariableAnimator(state).ApplyAll();
-
-      // Apply high priority properties again to re-resolve var() references
-      // to (now-)animated custom properties.
-      // TODO(andruud): Avoid this with https://crbug.com/947004
-      ApplyMatchedHighPriorityProperties(state, match_result, cache_success,
-                                         apply_inherited_only,
-                                         needs_apply_pass);
-    }
-  }
-
-  if (cache_success.IsFullCacheHit())
-    return;
-
-  CSSVariableResolver(state).ResolveVariableDefinitions();
-
-  ApplyMatchedLowPriorityProperties(state, match_result, cache_success,
-                                    apply_inherited_only, needs_apply_pass);
-}
-
 bool StyleResolver::CanReuseBaseComputedStyle(const StyleResolverState& state) {
   ElementAnimations* element_animations = GetElementAnimations(state);
   if (!element_animations || !element_animations->BaseComputedStyle())
@@ -2176,10 +1604,8 @@
   StyleResolverState state(GetDocument(), element);
   STACK_UNINITIALIZED StyleCascade cascade(state);
 
-  ApplyBaseComputedStyle(
-      &element, state,
-      RuntimeEnabledFeatures::CSSCascadeEnabled() ? &cascade : nullptr,
-      cascade.MutableMatchResult(), kMatchAllRules, true);
+  ApplyBaseComputedStyle(&element, state, &cascade,
+                         cascade.MutableMatchResult(), kMatchAllRules, true);
   ApplyInterpolations(state, cascade, interpolations);
 
   return state.TakeStyle();
@@ -2189,16 +1615,8 @@
     StyleResolverState& state,
     StyleCascade& cascade,
     ActiveInterpolationsMap& interpolations) {
-  if (RuntimeEnabledFeatures::CSSCascadeEnabled()) {
-    cascade.AddInterpolations(&interpolations, CascadeOrigin::kAnimation);
-    cascade.Apply();
-  } else {
-    ApplyAnimatedStandardProperties<kHighPropertyPriority>(state,
-                                                           interpolations);
-    UpdateFont(state);
-    ApplyAnimatedStandardProperties<kLowPropertyPriority>(state,
-                                                          interpolations);
-  }
+  cascade.AddInterpolations(&interpolations, CascadeOrigin::kAnimation);
+  cascade.Apply();
 }
 
 scoped_refptr<ComputedStyle>
@@ -2231,7 +1649,6 @@
 
 void StyleResolver::CascadeAndApplyMatchedProperties(StyleResolverState& state,
                                                      StyleCascade& cascade) {
-  DCHECK(RuntimeEnabledFeatures::CSSCascadeEnabled());
   const MatchResult& result = cascade.GetMatchResult();
 
   CacheSuccess cache_success = ApplyMatchedCache(state, result);
@@ -2359,66 +1776,4 @@
          state.Style()->ForcedColorAdjust() != EForcedColorAdjust::kNone;
 }
 
-void StyleResolver::ApplyCascadedColorValue(StyleResolverState& state) {
-  if (RuntimeEnabledFeatures::CSSCascadeEnabled())
-    return;
-
-  if (const CSSValue* color_value = state.GetCascadedColorValue()) {
-    state.SetCascadedColorValue(nullptr);
-    const auto* identifier_value = DynamicTo<CSSIdentifierValue>(color_value);
-    if (identifier_value) {
-      switch (identifier_value->GetValueID()) {
-        case CSSValueID::kCurrentcolor:
-          // As per the spec, 'color: currentColor' is treated as 'color:
-          // inherit'
-        case CSSValueID::kInherit:
-          state.Style()->SetColor(state.ParentStyle()->GetColor());
-          break;
-        case CSSValueID::kInitial:
-          state.Style()->SetColor(state.Style()->InitialColorForColorScheme());
-          break;
-        default:
-          identifier_value = nullptr;
-          break;
-      }
-    }
-    if (!identifier_value) {
-      state.Style()->SetColor(
-          StyleBuilderConverter::ConvertStyleColor(state, *color_value));
-    }
-  } else if (state.GetElement() == GetDocument().documentElement()) {
-    state.Style()->SetColor(state.Style()->InitialColorForColorScheme());
-  }
-
-  if (const CSSValue* visited_color_value =
-          state.GetCascadedVisitedColorValue()) {
-    state.SetCascadedVisitedColorValue(nullptr);
-    const auto* identifier_value =
-        DynamicTo<CSSIdentifierValue>(visited_color_value);
-    if (identifier_value) {
-      switch (identifier_value->GetValueID()) {
-        case CSSValueID::kCurrentcolor:
-          // As per the spec, 'color: currentColor' is treated as 'color:
-          // inherit'
-        case CSSValueID::kInherit:
-          state.Style()->SetInternalVisitedColor(
-              state.ParentStyle()->GetColor());
-          break;
-        case CSSValueID::kInitial:
-          state.Style()->SetInternalVisitedColor(
-              state.Style()->InitialColorForColorScheme());
-          break;
-        default:
-          identifier_value = nullptr;
-          break;
-      }
-    }
-    if (!identifier_value) {
-      state.Style()->SetInternalVisitedColor(
-          StyleBuilderConverter::ConvertStyleColor(state, *visited_color_value,
-                                                   true));
-    }
-  }
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver.h b/third_party/blink/renderer/core/css/resolver/style_resolver.h
index 548d7fa..057b1ecd 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver.h
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver.h
@@ -229,67 +229,11 @@
     bool IsUsableAfterApplyInheritedOnly(const ComputedStyle&) const;
   };
 
-  // These flags indicate whether an apply pass for a given CSSPropertyPriority
-  // and isImportant is required.
-  class NeedsApplyPass {
-   public:
-    bool Get(CSSPropertyPriority priority, bool is_important) const {
-      return flags_[GetIndex(priority, is_important)];
-    }
-    void Set(CSSPropertyPriority priority, bool is_important) {
-      flags_[GetIndex(priority, is_important)] = true;
-    }
-
-   private:
-    static size_t GetIndex(CSSPropertyPriority priority, bool is_important) {
-      DCHECK(priority >= 0 && priority < kPropertyPriorityCount);
-      return priority * 2 + is_important;
-    }
-    bool flags_[kPropertyPriorityCount * 2] = {0};
-  };
-
-  enum class ForcedColorFilter { kEnabled, kDisabled };
-
-  enum ShouldUpdateNeedsApplyPass {
-    kCheckNeedsApplyPass = false,
-    kUpdateNeedsApplyPass = true,
-  };
-
   CacheSuccess ApplyMatchedCache(StyleResolverState&, const MatchResult&);
   void MaybeAddToMatchedPropertiesCache(StyleResolverState&,
                                         const CacheSuccess&,
                                         const MatchResult&);
 
-  void ApplyCustomProperties(StyleResolverState&,
-                             const MatchResult&,
-                             const CacheSuccess&,
-                             NeedsApplyPass&);
-  void ApplyMatchedAnimationProperties(StyleResolverState&,
-                                       const MatchResult&,
-                                       const CacheSuccess&,
-                                       NeedsApplyPass&);
-  void ApplyMatchedHighPriorityProperties(StyleResolverState&,
-                                          const MatchResult&,
-                                          const CacheSuccess&,
-                                          bool& apply_inherited_only,
-                                          NeedsApplyPass&);
-  void ApplyMatchedLowPriorityProperties(StyleResolverState&,
-                                         const MatchResult&,
-                                         const CacheSuccess&,
-                                         bool& apply_inherited_only,
-                                         NeedsApplyPass&);
-  void ApplyMatchedProperties(StyleResolverState&, const MatchResult&);
-  template <CSSPropertyPriority priority>
-  void ApplyForcedColors(StyleResolverState& state,
-                         const MatchResult& match_result,
-                         bool apply_inherited_only,
-                         NeedsApplyPass& needs_apply_pass);
-  template <CSSPropertyPriority priority>
-  void ApplyUaForcedColors(StyleResolverState& state,
-                           const MatchResult& match_result,
-                           bool apply_inherited_only,
-                           NeedsApplyPass& needs_apply_pass);
-
   void CascadeAndApplyMatchedProperties(StyleResolverState&,
                                         StyleCascade& cascade);
 
@@ -300,36 +244,6 @@
 
   void ApplyCallbackSelectors(StyleResolverState&);
 
-  template <CSSPropertyPriority priority, ShouldUpdateNeedsApplyPass>
-  void ApplyMatchedProperties(
-      StyleResolverState&,
-      const MatchedPropertiesRange&,
-      bool important,
-      bool inherited_only,
-      NeedsApplyPass&,
-      ForcedColorFilter forced_colors = ForcedColorFilter::kDisabled);
-  template <CSSPropertyPriority priority, ShouldUpdateNeedsApplyPass>
-  void ApplyProperties(
-      StyleResolverState&,
-      const CSSPropertyValueSet* properties,
-      bool is_important,
-      bool inherited_only,
-      NeedsApplyPass&,
-      ValidPropertyFilter,
-      unsigned apply_mask,
-      ForcedColorFilter forced_colors = ForcedColorFilter::kDisabled);
-  template <CSSPropertyPriority priority>
-  void ApplyAnimatedStandardProperties(StyleResolverState&,
-                                       const ActiveInterpolationsMap&);
-  template <CSSPropertyPriority priority>
-  void ApplyAllProperty(StyleResolverState&,
-                        const CSSValue&,
-                        bool inherited_only,
-                        ValidPropertyFilter,
-                        unsigned apply_mask);
-
-  void ApplyCascadedColorValue(StyleResolverState&);
-
   bool PseudoStyleForElementInternal(Element&,
                                      const PseudoElementStyleRequest&,
                                      StyleResolverState&);
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc b/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc
index cb05992..34e6744e 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc
@@ -202,19 +202,6 @@
   }
 }
 
-HeapHashMap<CSSPropertyID, Member<const CSSValue>>&
-StyleResolverState::ParsedPropertiesForPendingSubstitutionCache(
-    const cssvalue::CSSPendingSubstitutionValue& value) const {
-  HeapHashMap<CSSPropertyID, Member<const CSSValue>>* map =
-      parsed_properties_for_pending_substitution_cache_.at(&value);
-  if (!map) {
-    map = MakeGarbageCollected<
-        HeapHashMap<CSSPropertyID, Member<const CSSValue>>>();
-    parsed_properties_for_pending_substitution_cache_.Set(&value, map);
-  }
-  return *map;
-}
-
 CSSParserMode StyleResolverState::GetParserMode() const {
   return GetDocument().InQuirksMode() ? kHTMLQuirksMode : kHTMLStandardMode;
 }
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver_state.h b/third_party/blink/renderer/core/css/resolver/style_resolver_state.h
index d38585a1..6f9bb36 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver_state.h
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver_state.h
@@ -27,7 +27,6 @@
 #include "base/macros.h"
 #include "third_party/blink/renderer/core/animation/css/css_animation_update.h"
 #include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/css/css_pending_substitution_value.h"
 #include "third_party/blink/renderer/core/css/css_property_name.h"
 #include "third_party/blink/renderer/core/css/css_property_names.h"
 #include "third_party/blink/renderer/core/css/css_to_length_conversion_data.h"
@@ -180,24 +179,6 @@
   void SetHasDirAutoAttribute(bool value) { has_dir_auto_attribute_ = value; }
   bool HasDirAutoAttribute() const { return has_dir_auto_attribute_; }
 
-  const CSSValue* GetCascadedColorValue() const {
-    return cascaded_color_value_;
-  }
-  const CSSValue* GetCascadedVisitedColorValue() const {
-    return cascaded_visited_color_value_;
-  }
-
-  void SetCascadedColorValue(const CSSValue* color) {
-    cascaded_color_value_ = color;
-  }
-  void SetCascadedVisitedColorValue(const CSSValue* color) {
-    cascaded_visited_color_value_ = color;
-  }
-
-  HeapHashMap<CSSPropertyID, Member<const CSSValue>>&
-  ParsedPropertiesForPendingSubstitutionCache(
-      const cssvalue::CSSPendingSubstitutionValue&) const;
-
   CSSParserMode GetParserMode() const;
 
   // If the input CSSValue is a CSSLightDarkValuePair, return the light or dark
@@ -291,9 +272,6 @@
   bool has_dir_auto_attribute_ = false;
   PseudoElementStyleRequest::RequestType pseudo_request_type_;
 
-  const CSSValue* cascaded_color_value_ = nullptr;
-  const CSSValue* cascaded_visited_color_value_ = nullptr;
-
   FontBuilder font_builder_;
 
   std::unique_ptr<CachedUAStyle> cached_ua_style_;
@@ -309,10 +287,6 @@
   // CSSProperty::kComputedValueComparable flag set.
   bool has_incomparable_dependency_ = false;
 
-  mutable HeapHashMap<
-      Member<const cssvalue::CSSPendingSubstitutionValue>,
-      Member<HeapHashMap<CSSPropertyID, Member<const CSSValue>>>>
-      parsed_properties_for_pending_substitution_cache_;
   DISALLOW_COPY_AND_ASSIGN(StyleResolverState);
 };
 
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver_test.cc b/third_party/blink/renderer/core/css/resolver/style_resolver_test.cc
index 24d3c9a1..9341781 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver_test.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver_test.cc
@@ -148,24 +148,6 @@
   EXPECT_TRUE(StyleResolver::CanReuseBaseComputedStyle(state));
 }
 
-TEST_F(StyleResolverTest, NoCrashWhenAnimatingWithoutCascade) {
-  ScopedCSSCascadeForTest scoped_cascade(false);
-
-  GetDocument().documentElement()->setInnerHTML(R"HTML(
-    <style>
-      @keyframes test {
-        from { width: 10px; }
-        to { width: 20px; }
-      }
-      div {
-        animation: test 1s;
-      }
-    </style>
-    <div id="div">Test</div>
-  )HTML");
-  UpdateAllLifecyclePhasesForTest();
-}
-
 TEST_F(StyleResolverTest, AnimationNotMaskedByImportant) {
   GetDocument().documentElement()->setInnerHTML(R"HTML(
     <style>
diff --git a/third_party/blink/renderer/core/frame/remote_frame_view.cc b/third_party/blink/renderer/core/frame/remote_frame_view.cc
index 4b72efa..4984c63 100644
--- a/third_party/blink/renderer/core/frame/remote_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/remote_frame_view.cc
@@ -104,6 +104,8 @@
   if (new_state != last_intersection_state_) {
     last_intersection_state_ = new_state;
     remote_frame_->Client()->UpdateRemoteViewportIntersection(new_state);
+  } else if (needs_frame_rect_propagation_) {
+    PropagateFrameRects();
   }
 }
 
@@ -118,12 +120,15 @@
 }
 
 void RemoteFrameView::UpdateCompositingRect() {
+  IntRect previous_rect = compositing_rect_;
   compositing_rect_ = IntRect();
   LocalFrameView* local_root_view = ParentLocalRootFrameView();
   LayoutEmbeddedContent* owner_layout_object =
       remote_frame_->OwnerLayoutObject();
-  if (!local_root_view || !owner_layout_object)
+  if (!local_root_view || !owner_layout_object) {
+    needs_frame_rect_propagation_ = true;
     return;
+  }
 
   // For main frames we constrain the rect that gets painted to the viewport.
   // If the local frame root is an OOPIF itself, then we use the root's
@@ -166,6 +171,9 @@
   IntPoint compositing_rect_location = compositing_rect_.Location();
   compositing_rect_location.ClampNegativeToZero();
   compositing_rect_.SetLocation(compositing_rect_location);
+
+  if (compositing_rect_ != previous_rect)
+    needs_frame_rect_propagation_ = true;
 }
 
 void RemoteFrameView::Dispose() {
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index ce750e3..d2cd673c 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -4790,8 +4790,8 @@
         if (curr->IsInsideFlowThread())
           static_position += AccumulateStaticOffsetForFlowThread(
               *ToLayoutBox(curr), static_position, static_block_position);
-      } else if (curr->IsInline()) {
-        if (curr->IsInFlowPositioned()) {
+      } else if (curr->IsInline() && curr->IsInFlowPositioned()) {
+        if (!curr->IsInLayoutNGInlineFormattingContext()) {
           if (!curr->StyleRef().LogicalLeft().IsAuto())
             static_position +=
                 ValueForLength(curr->StyleRef().LogicalLeft(),
@@ -4831,8 +4831,8 @@
             static_position -= AccumulateStaticOffsetForFlowThread(
                 *ToLayoutBox(curr), static_position, static_block_position);
         }
-      } else if (curr->IsInline()) {
-        if (curr->IsInFlowPositioned()) {
+      } else if (curr->IsInline() && curr->IsInFlowPositioned()) {
+        if (!curr->IsInLayoutNGInlineFormattingContext()) {
           if (!curr->StyleRef().LogicalLeft().IsAuto())
             static_position -=
                 ValueForLength(curr->StyleRef().LogicalLeft(),
diff --git a/third_party/blink/renderer/core/layout/layout_box_model_object.cc b/third_party/blink/renderer/core/layout/layout_box_model_object.cc
index f87f8509..ed91fe0 100644
--- a/third_party/blink/renderer/core/layout/layout_box_model_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_box_model_object.cc
@@ -37,6 +37,7 @@
 #include "third_party/blink/renderer/core/layout/layout_geometry_map.h"
 #include "third_party/blink/renderer/core/layout/layout_inline.h"
 #include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
 #include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
@@ -763,10 +764,15 @@
 
 PhysicalOffset LayoutBoxModelObject::RelativePositionOffset() const {
   DCHECK(IsRelPositioned());
-  PhysicalOffset offset = AccumulateRelativePositionOffsets();
-
   LayoutBlock* containing_block = ContainingBlock();
 
+  // If this object was placed by LayoutNG it's offset already includes the
+  // relative adjustment.
+  if (IsLayoutNGContainingBlock(containing_block))
+    return PhysicalOffset();
+
+  PhysicalOffset offset = AccumulateRelativePositionOffsets();
+
   // Objects that shrink to avoid floats normally use available line width when
   // computing containing block width. However in the case of relative
   // positioning using percentages, we can't do this. The offset should always
diff --git a/third_party/blink/renderer/core/layout/layout_box_test.cc b/third_party/blink/renderer/core/layout/layout_box_test.cc
index cd39782..42c5469 100644
--- a/third_party/blink/renderer/core/layout/layout_box_test.cc
+++ b/third_party/blink/renderer/core/layout/layout_box_test.cc
@@ -1016,34 +1016,61 @@
   // because relative offset doesn't contribute to box location.
 
   const auto* normal = GetLayoutBoxByElementId("normal");
-  EXPECT_EQ(LayoutPoint(90, 100), normal->Location());
-  EXPECT_EQ(PhysicalOffset(90, 100), normal->PhysicalLocation());
-  EXPECT_EQ(PhysicalOffset(88, 77), normal->OffsetForInFlowPosition());
-
   const auto* vlr = GetLayoutBoxByElementId("vlr");
-  EXPECT_EQ(LayoutPoint(190, 30), vlr->Location());
-  EXPECT_EQ(PhysicalOffset(190, 30), vlr->PhysicalLocation());
-  EXPECT_EQ(PhysicalOffset(88, 77), vlr->OffsetForInFlowPosition());
-
   const auto* vrl = GetLayoutBoxByElementId("vrl");
-  EXPECT_EQ(LayoutPoint(165, 30), vrl->Location());
-  EXPECT_EQ(PhysicalOffset(225, 30), vrl->PhysicalLocation());
-  EXPECT_EQ(PhysicalOffset(88, 77), vrl->OffsetForInFlowPosition());
-
   const auto* rtl = GetLayoutBoxByElementId("rtl");
-  EXPECT_EQ(LayoutPoint(340, 100), rtl->Location());
-  EXPECT_EQ(PhysicalOffset(340, 100), rtl->PhysicalLocation());
-  EXPECT_EQ(PhysicalOffset(88, 77), rtl->OffsetForInFlowPosition());
-
   const auto* rtl_vlr = GetLayoutBoxByElementId("rtl-vlr");
-  EXPECT_EQ(LayoutPoint(190, 134), rtl_vlr->Location());
-  EXPECT_EQ(PhysicalOffset(190, 134), rtl_vlr->PhysicalLocation());
-  EXPECT_EQ(PhysicalOffset(88, 77), rtl_vlr->OffsetForInFlowPosition());
-
   const auto* rtl_vrl = GetLayoutBoxByElementId("rtl-vrl");
-  EXPECT_EQ(LayoutPoint(165, 134), rtl_vrl->Location());
-  EXPECT_EQ(PhysicalOffset(225, 134), rtl_vrl->PhysicalLocation());
-  EXPECT_EQ(PhysicalOffset(88, 77), rtl_vrl->OffsetForInFlowPosition());
+
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    EXPECT_EQ(LayoutPoint(178, 177), normal->Location());
+    EXPECT_EQ(PhysicalOffset(178, 177), normal->PhysicalLocation());
+    EXPECT_EQ(PhysicalOffset(0, 0), normal->OffsetForInFlowPosition());
+
+    EXPECT_EQ(LayoutPoint(278, 107), vlr->Location());
+    EXPECT_EQ(PhysicalOffset(278, 107), vlr->PhysicalLocation());
+    EXPECT_EQ(PhysicalOffset(0, 0), vlr->OffsetForInFlowPosition());
+
+    EXPECT_EQ(LayoutPoint(77, 107), vrl->Location());
+    EXPECT_EQ(PhysicalOffset(313, 107), vrl->PhysicalLocation());
+    EXPECT_EQ(PhysicalOffset(0, 0), vrl->OffsetForInFlowPosition());
+
+    EXPECT_EQ(LayoutPoint(428, 177), rtl->Location());
+    EXPECT_EQ(PhysicalOffset(428, 177), rtl->PhysicalLocation());
+    EXPECT_EQ(PhysicalOffset(0, 0), rtl->OffsetForInFlowPosition());
+
+    EXPECT_EQ(LayoutPoint(278, 211), rtl_vlr->Location());
+    EXPECT_EQ(PhysicalOffset(278, 211), rtl_vlr->PhysicalLocation());
+    EXPECT_EQ(PhysicalOffset(0, 0), rtl_vlr->OffsetForInFlowPosition());
+
+    EXPECT_EQ(LayoutPoint(77, 211), rtl_vrl->Location());
+    EXPECT_EQ(PhysicalOffset(313, 211), rtl_vrl->PhysicalLocation());
+    EXPECT_EQ(PhysicalOffset(0, 0), rtl_vrl->OffsetForInFlowPosition());
+  } else {
+    EXPECT_EQ(LayoutPoint(90, 100), normal->Location());
+    EXPECT_EQ(PhysicalOffset(90, 100), normal->PhysicalLocation());
+    EXPECT_EQ(PhysicalOffset(88, 77), normal->OffsetForInFlowPosition());
+
+    EXPECT_EQ(LayoutPoint(190, 30), vlr->Location());
+    EXPECT_EQ(PhysicalOffset(190, 30), vlr->PhysicalLocation());
+    EXPECT_EQ(PhysicalOffset(88, 77), vlr->OffsetForInFlowPosition());
+
+    EXPECT_EQ(LayoutPoint(165, 30), vrl->Location());
+    EXPECT_EQ(PhysicalOffset(225, 30), vrl->PhysicalLocation());
+    EXPECT_EQ(PhysicalOffset(88, 77), vrl->OffsetForInFlowPosition());
+
+    EXPECT_EQ(LayoutPoint(340, 100), rtl->Location());
+    EXPECT_EQ(PhysicalOffset(340, 100), rtl->PhysicalLocation());
+    EXPECT_EQ(PhysicalOffset(88, 77), rtl->OffsetForInFlowPosition());
+
+    EXPECT_EQ(LayoutPoint(190, 134), rtl_vlr->Location());
+    EXPECT_EQ(PhysicalOffset(190, 134), rtl_vlr->PhysicalLocation());
+    EXPECT_EQ(PhysicalOffset(88, 77), rtl_vlr->OffsetForInFlowPosition());
+
+    EXPECT_EQ(LayoutPoint(165, 134), rtl_vrl->Location());
+    EXPECT_EQ(PhysicalOffset(225, 134), rtl_vrl->PhysicalLocation());
+    EXPECT_EQ(PhysicalOffset(88, 77), rtl_vrl->OffsetForInFlowPosition());
+  }
 }
 
 TEST_P(LayoutBoxTest, LocationOfFloatLeftChildWithContainerScrollbars) {
diff --git a/third_party/blink/renderer/core/layout/layout_geometry_map_test.cc b/third_party/blink/renderer/core/layout/layout_geometry_map_test.cc
index 381b7eb..e86a057 100644
--- a/third_party/blink/renderer/core/layout/layout_geometry_map_test.cc
+++ b/third_party/blink/renderer/core/layout/layout_geometry_map_test.cc
@@ -490,8 +490,14 @@
   }
 
   rgm.PopMappingsToAncestor(span->Layer());
-  EXPECT_EQ(PhysicalRect(203, 104, 10, 8), rgm.MapToAncestor(rect, container));
-  EXPECT_EQ(PhysicalRect(263, 154, 10, 8), rgm.MapToAncestor(rect, nullptr));
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    EXPECT_EQ(PhysicalRect(3, 4, 10, 8), rgm.MapToAncestor(rect, container));
+    EXPECT_EQ(PhysicalRect(63, 54, 10, 8), rgm.MapToAncestor(rect, nullptr));
+  } else {
+    EXPECT_EQ(PhysicalRect(203, 104, 10, 8),
+              rgm.MapToAncestor(rect, container));
+    EXPECT_EQ(PhysicalRect(263, 154, 10, 8), rgm.MapToAncestor(rect, nullptr));
+  }
 
   rgm.PushMappingsToAncestor(floating, span);
   if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
diff --git a/third_party/blink/renderer/core/layout/layout_object_test.cc b/third_party/blink/renderer/core/layout/layout_object_test.cc
index 1b17999..846632a 100644
--- a/third_party/blink/renderer/core/layout/layout_object_test.cc
+++ b/third_party/blink/renderer/core/layout/layout_object_test.cc
@@ -381,7 +381,10 @@
       EPosition::kFixed));
 
   auto offset = layout_object->OffsetFromContainer(span_layout_object);
-  EXPECT_EQ(PhysicalOffset(20, 10), offset);
+  if (RuntimeEnabledFeatures::LayoutNGEnabled())
+    EXPECT_EQ(PhysicalOffset(22, 11), offset);
+  else
+    EXPECT_EQ(PhysicalOffset(20, 10), offset);
 
   // Sanity check: Make sure we don't generate anonymous objects.
   EXPECT_EQ(nullptr, body_layout_object->SlowFirstChild()->NextSibling());
@@ -445,8 +448,8 @@
   LayoutObject* span =
       ToLayoutBoxModelObject(GetLayoutObjectByElementId("span"));
   if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
-    // 10px for margin.
-    EXPECT_EQ(PhysicalOffset(10, 0), float_obj->OffsetFromAncestor(span));
+    // 10px for margin + 40px for inset.
+    EXPECT_EQ(PhysicalOffset(50, 0), float_obj->OffsetFromAncestor(span));
   } else {
     // 10px for margin, -40px because float is to the left of the span.
     EXPECT_EQ(PhysicalOffset(-30, 0), float_obj->OffsetFromAncestor(span));
diff --git a/third_party/blink/renderer/core/layout/layout_view_test.cc b/third_party/blink/renderer/core/layout/layout_view_test.cc
index ce2abae..125f676c 100644
--- a/third_party/blink/renderer/core/layout/layout_view_test.cc
+++ b/third_party/blink/renderer/core/layout/layout_view_test.cc
@@ -270,7 +270,10 @@
   result = HitTestResult();
   GetLayoutView().HitTest(HitTestLocation(PhysicalOffset(101, 131)), result);
   EXPECT_EQ(text2, result.InnerNode());
-  EXPECT_EQ(PhysicalOffset(51, 1), result.LocalPoint());
+  if (RuntimeEnabledFeatures::LayoutNGEnabled())
+    EXPECT_EQ(PhysicalOffset(51, 31), result.LocalPoint());
+  else
+    EXPECT_EQ(PhysicalOffset(51, 1), result.LocalPoint());
   EXPECT_EQ(PositionWithAffinity(Position(text2, 0), TextAffinity::kDownstream),
             result.GetPosition());
 }
@@ -380,7 +383,10 @@
   result = HitTestResult();
   GetLayoutView().HitTest(HitTestLocation(PhysicalOffset(81, 151)), result);
   EXPECT_EQ(text2, result.InnerNode());
-  EXPECT_EQ(PhysicalOffset(1, 51), result.LocalPoint());
+  if (RuntimeEnabledFeatures::LayoutNGEnabled())
+    EXPECT_EQ(PhysicalOffset(31, 51), result.LocalPoint());
+  else
+    EXPECT_EQ(PhysicalOffset(1, 51), result.LocalPoint());
   EXPECT_EQ(PositionWithAffinity(Position(text2, 0), TextAffinity::kDownstream),
             result.GetPosition());
 }
@@ -503,7 +509,10 @@
   result = HitTestResult();
   GetLayoutView().HitTest(HitTestLocation(PhysicalOffset(219, 151)), result);
   EXPECT_EQ(text2, result.InnerNode());
-  EXPECT_EQ(PhysicalOffset(199, 51), result.LocalPoint());
+  if (RuntimeEnabledFeatures::LayoutNGEnabled())
+    EXPECT_EQ(PhysicalOffset(169, 51), result.LocalPoint());
+  else
+    EXPECT_EQ(PhysicalOffset(199, 51), result.LocalPoint());
   EXPECT_EQ(PositionWithAffinity(Position(text2, 0), TextAffinity::kDownstream),
             result.GetPosition());
 }
diff --git a/third_party/blink/renderer/core/layout/map_coordinates_test.cc b/third_party/blink/renderer/core/layout/map_coordinates_test.cc
index 22aefbe8..b9dfdc85 100644
--- a/third_party/blink/renderer/core/layout/map_coordinates_test.cc
+++ b/third_party/blink/renderer/core/layout/map_coordinates_test.cc
@@ -176,7 +176,10 @@
   ASSERT_TRUE(text->IsText());
   PhysicalOffset mapped_point =
       MapLocalToAncestor(text, text->ContainingBlock(), PhysicalOffset(10, 30));
-  EXPECT_EQ(PhysicalOffset(17, 34), mapped_point);
+  if (RuntimeEnabledFeatures::LayoutNGEnabled())
+    EXPECT_EQ(PhysicalOffset(10, 30), mapped_point);
+  else
+    EXPECT_EQ(PhysicalOffset(17, 34), mapped_point);
   mapped_point =
       MapAncestorToLocal(text, text->ContainingBlock(), mapped_point);
   EXPECT_EQ(PhysicalOffset(10, 30), mapped_point);
@@ -190,7 +193,10 @@
   LayoutObject* target = GetLayoutObjectByElementId("target");
   PhysicalOffset mapped_point = MapLocalToAncestor(
       target, ToLayoutBoxModelObject(target->Parent()), PhysicalOffset(10, 10));
-  EXPECT_EQ(PhysicalOffset(60, 110), mapped_point);
+  if (RuntimeEnabledFeatures::LayoutNGEnabled())
+    EXPECT_EQ(PhysicalOffset(10, 10), mapped_point);
+  else
+    EXPECT_EQ(PhysicalOffset(60, 110), mapped_point);
   mapped_point = MapAncestorToLocal(
       target, ToLayoutBoxModelObject(target->Parent()), mapped_point);
   EXPECT_EQ(PhysicalOffset(10, 10), mapped_point);
@@ -212,22 +218,37 @@
 
   PhysicalOffset mapped_point =
       MapLocalToAncestor(target, containing_block, PhysicalOffset(20, 10));
-  EXPECT_EQ(PhysicalOffset(75, 116), mapped_point);
+  if (RuntimeEnabledFeatures::LayoutNGEnabled())
+    EXPECT_EQ(PhysicalOffset(20, 10), mapped_point);
+  else
+    EXPECT_EQ(PhysicalOffset(75, 116), mapped_point);
   mapped_point = MapAncestorToLocal(target, containing_block, mapped_point);
   EXPECT_EQ(PhysicalOffset(20, 10), mapped_point);
 
   // Walk each ancestor in the chain separately, to verify each step on the way.
   mapped_point = MapLocalToAncestor(target, parent, PhysicalOffset(20, 10));
-  EXPECT_EQ(PhysicalOffset(70, 110), mapped_point);
+  if (RuntimeEnabledFeatures::LayoutNGEnabled())
+    EXPECT_EQ(PhysicalOffset(20, 10), mapped_point);
+  else
+    EXPECT_EQ(PhysicalOffset(70, 110), mapped_point);
 
   mapped_point = MapLocalToAncestor(parent, containing_block, mapped_point);
-  EXPECT_EQ(PhysicalOffset(75, 116), mapped_point);
+  if (RuntimeEnabledFeatures::LayoutNGEnabled())
+    EXPECT_EQ(PhysicalOffset(20, 10), mapped_point);
+  else
+    EXPECT_EQ(PhysicalOffset(75, 116), mapped_point);
 
   mapped_point = MapAncestorToLocal(parent, containing_block, mapped_point);
-  EXPECT_EQ(PhysicalOffset(70, 110), mapped_point);
+  if (RuntimeEnabledFeatures::LayoutNGEnabled())
+    EXPECT_EQ(PhysicalOffset(20, 10), mapped_point);
+  else
+    EXPECT_EQ(PhysicalOffset(70, 110), mapped_point);
 
   mapped_point = MapAncestorToLocal(target, parent, mapped_point);
-  EXPECT_EQ(PhysicalOffset(20, 10), mapped_point);
+  if (RuntimeEnabledFeatures::LayoutNGEnabled())
+    EXPECT_EQ(PhysicalOffset(20, 10), mapped_point);
+  else
+    EXPECT_EQ(PhysicalOffset(20, 10), mapped_point);
 }
 
 TEST_F(MapCoordinatesTest, RelPosBlock) {
diff --git a/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h b/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h
index 3c01e9f..92dfba2 100644
--- a/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h
+++ b/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h
@@ -203,6 +203,20 @@
     return LayoutRectOutsets(top, right, bottom, left);
   }
 
+  NGPhysicalBoxStrut& operator+=(const NGPhysicalBoxStrut& other) {
+    top += other.top;
+    right += other.right;
+    bottom += other.bottom;
+    left += other.left;
+    return *this;
+  }
+
+  NGPhysicalBoxStrut operator+(const NGPhysicalBoxStrut& other) const {
+    NGPhysicalBoxStrut result(*this);
+    result += other;
+    return result;
+  }
+
   bool operator==(const NGPhysicalBoxStrut& other) const {
     return top == other.top && right == other.right && bottom == other.bottom &&
            left == other.left;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc
index bb2d2a1..8673a7e 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc
@@ -12,6 +12,7 @@
 #include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_relative_utils.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
 #include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h"
 
@@ -186,13 +187,14 @@
 }
 
 NGInlineBoxState* NGInlineLayoutStateStack::OnCloseTag(
+    const NGConstraintSpace& space,
     NGLogicalLineItems* line_box,
     NGInlineBoxState* box,
     FontBaseline baseline_type,
     bool has_end_edge) {
   DCHECK_EQ(box, &stack_.back());
   box->has_end_edge = has_end_edge;
-  EndBoxState(box, line_box, baseline_type);
+  EndBoxState(space, box, line_box, baseline_type);
   // TODO(kojii): When the algorithm restarts from a break token, the stack may
   // underflow. We need either synthesize a missing box state, or push all
   // parents on initialize.
@@ -200,14 +202,15 @@
   return &stack_.back();
 }
 
-void NGInlineLayoutStateStack::OnEndPlaceItems(NGLogicalLineItems* line_box,
+void NGInlineLayoutStateStack::OnEndPlaceItems(const NGConstraintSpace& space,
+                                               NGLogicalLineItems* line_box,
                                                FontBaseline baseline_type) {
   for (auto it = stack_.rbegin(); it != stack_.rend(); ++it) {
     NGInlineBoxState* box = &(*it);
     if (!box->has_end_edge && box->needs_box_fragment &&
         box->style->BoxDecorationBreak() == EBoxDecorationBreak::kClone)
       box->has_end_edge = true;
-    EndBoxState(box, line_box, baseline_type);
+    EndBoxState(space, box, line_box, baseline_type);
   }
 
   // Up to this point, the offset of inline boxes are stored in placeholder so
@@ -220,11 +223,12 @@
   }
 }
 
-void NGInlineLayoutStateStack::EndBoxState(NGInlineBoxState* box,
+void NGInlineLayoutStateStack::EndBoxState(const NGConstraintSpace& space,
+                                           NGInlineBoxState* box,
                                            NGLogicalLineItems* line_box,
                                            FontBaseline baseline_type) {
   if (box->needs_box_fragment)
-    AddBoxData(box, line_box);
+    AddBoxData(space, box, line_box);
 
   PositionPending position_pending =
       ApplyBaselineShift(box, line_box, baseline_type);
@@ -273,7 +277,8 @@
 }
 
 // Add a |BoxData|, for each close-tag that needs a box fragment.
-void NGInlineLayoutStateStack::AddBoxData(NGInlineBoxState* box,
+void NGInlineLayoutStateStack::AddBoxData(const NGConstraintSpace& space,
+                                          NGInlineBoxState* box,
                                           NGLogicalLineItems* line_box) {
   DCHECK(box->needs_box_fragment);
   DCHECK(box->style);
@@ -315,6 +320,8 @@
   // An empty box fragment is still flat that we do not have to defer.
   // Also, placeholders cannot be reordred if empty.
   placeholder.rect.offset.inline_offset += box_data.margin_line_left;
+  placeholder.rect.offset +=
+      ComputeRelativeOffsetForInline(space, *box_data.item->Style());
   LayoutUnit advance = box_data.margin_border_padding_line_left +
                        box_data.margin_border_padding_line_right;
   box_data.rect.size.inline_size =
@@ -566,6 +573,37 @@
   return position;
 }
 
+void NGInlineLayoutStateStack::ApplyRelativePositioning(
+    const NGConstraintSpace& space,
+    NGLogicalLineItems* line_box) {
+  if (box_data_list_.IsEmpty())
+    return;
+
+  // The final position of any inline boxes, (<span>, etc) are stored on
+  // |BoxData::rect|. As we don't have a mapping from |NGLogicalLineItem| to
+  // |BoxData| we store the accumulated relative offsets, and then apply the
+  // final adjustment at the end of this function.
+  Vector<LogicalOffset, 32> accumulated_offsets(line_box->size());
+
+  for (BoxData& box_data : box_data_list_) {
+    unsigned start = box_data.fragment_start;
+    unsigned end = box_data.fragment_end;
+    const LogicalOffset relative_offset =
+        ComputeRelativeOffsetForInline(space, *box_data.item->Style());
+
+    // Move all children for this box.
+    for (unsigned index = start; index < end; index++) {
+      auto& child = (*line_box)[index];
+      child.rect.offset += relative_offset;
+      accumulated_offsets[index] += relative_offset;
+    }
+  }
+
+  // Apply the final accumulated relative position offset for each box.
+  for (BoxData& box_data : box_data_list_)
+    box_data.rect.offset += accumulated_offsets[box_data.fragment_start];
+}
+
 void NGInlineLayoutStateStack::CreateBoxFragments(
     NGLogicalLineItems* line_box) {
   DCHECK(!box_data_list_.IsEmpty());
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h
index 6f58b80..e99b47cd 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h
@@ -132,13 +132,16 @@
                               NGLogicalLineItems* line_box);
 
   // Pop a box state stack.
-  NGInlineBoxState* OnCloseTag(NGLogicalLineItems*,
+  NGInlineBoxState* OnCloseTag(const NGConstraintSpace& space,
+                               NGLogicalLineItems*,
                                NGInlineBoxState*,
                                FontBaseline,
                                bool has_end_edge = true);
 
   // Compute all the pending positioning at the end of a line.
-  void OnEndPlaceItems(NGLogicalLineItems*, FontBaseline);
+  void OnEndPlaceItems(const NGConstraintSpace& space,
+                       NGLogicalLineItems*,
+                       FontBaseline);
 
   bool HasBoxFragments() const { return !box_data_list_.IsEmpty(); }
 
@@ -169,6 +172,8 @@
   // Compute inline positions of fragments and boxes.
   LayoutUnit ComputeInlinePositions(NGLogicalLineItems*, LayoutUnit position);
 
+  void ApplyRelativePositioning(const NGConstraintSpace&, NGLogicalLineItems*);
+
   // Create box fragments. This function turns a flat list of children into
   // a box tree.
   void CreateBoxFragments(NGLogicalLineItems*);
@@ -180,12 +185,17 @@
  private:
   // End of a box state, either explicitly by close tag, or implicitly at the
   // end of a line.
-  void EndBoxState(NGInlineBoxState*, NGLogicalLineItems*, FontBaseline);
+  void EndBoxState(const NGConstraintSpace&,
+                   NGInlineBoxState*,
+                   NGLogicalLineItems*,
+                   FontBaseline);
 
   void AddBoxFragmentPlaceholder(NGInlineBoxState*,
                                  NGLogicalLineItems*,
                                  FontBaseline);
-  void AddBoxData(NGInlineBoxState*, NGLogicalLineItems*);
+  void AddBoxData(const NGConstraintSpace&,
+                  NGInlineBoxState*,
+                  NGLogicalLineItems*);
 
   enum PositionPending { kPositionNotPending, kPositionPending };
 
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
index cb8fb22..2d97cf6 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
@@ -31,6 +31,7 @@
 #include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_positioned_float.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_relative_utils.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_space_utils.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
@@ -108,8 +109,8 @@
     NGInlineBoxState* box) {
   if (UNLIKELY(quirks_mode_ && !item.IsEmptyItem()))
     box->EnsureTextMetrics(*item.Style(), baseline_type_);
-  box = box_states_->OnCloseTag(&line_box_, box, baseline_type_,
-                                item.HasEndEdge());
+  box = box_states_->OnCloseTag(ConstraintSpace(), &line_box_, box,
+                                baseline_type_, item.HasEndEdge());
   // Just clear |NeedsLayout| flags. Culled inline boxes do not need paint
   // invalidations. If this object produces box fragments,
   // |NGInlineBoxStateStack| takes care of invalidations.
@@ -217,6 +218,7 @@
 
   bool has_out_of_flow_positioned_items = false;
   bool has_floating_items = false;
+  bool has_relative_positioned_items = false;
 
   // List items trigger strict line height, i.e. we make room for the line box
   // strut, for *every* line. This matches other browsers. The intention may
@@ -273,6 +275,8 @@
       box = HandleCloseTag(item, item_result, box);
     } else if (item.Type() == NGInlineItem::kAtomicInline) {
       box = PlaceAtomicInline(item, *line_info, &item_result);
+      has_relative_positioned_items |=
+          item.Style()->GetPosition() == EPosition::kRelative;
     } else if (item.Type() == NGInlineItem::kListMarker) {
       PlaceListMarker(item, &item_result, *line_info);
     } else if (item.Type() == NGInlineItem::kOutOfFlowPositioned) {
@@ -302,12 +306,14 @@
         line_box_.AddChild(item.GetLayoutObject(), item.BidiLevel());
       }
       has_floating_items = true;
+      has_relative_positioned_items |=
+          item.Style()->GetPosition() == EPosition::kRelative;
     } else if (item.Type() == NGInlineItem::kBidiControl) {
       line_box_.AddChild(item.BidiLevel());
     }
   }
 
-  box_states_->OnEndPlaceItems(&line_box_, baseline_type_);
+  box_states_->OnEndPlaceItems(ConstraintSpace(), &line_box_, baseline_type_);
 
   if (UNLIKELY(Node().IsBidiEnabled())) {
     box_states_->PrepareForReorder(&line_box_);
@@ -387,6 +393,15 @@
                          exclusion_space);
   }
 
+  // Apply any relative positioned offsets to *items* which have relative
+  // positioning, (atomic-inlines, and floats). This will only move the
+  // individual item.
+  if (has_relative_positioned_items)
+    PlaceRelativePositionedItems();
+
+  // Apply any relative positioned offsets to any boxes (and their children).
+  box_states_->ApplyRelativePositioning(ConstraintSpace(), &line_box_);
+
   NGAnnotationMetrics annotation_metrics;
   if (Node().HasRuby() &&
       !RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
@@ -550,7 +565,8 @@
   NGInlineBoxState* box =
       box_states_->OnOpenTag(item, *item_result, baseline_type_, line_box_);
   PlaceLayoutResult(item_result, box, box->margin_inline_start);
-  return box_states_->OnCloseTag(&line_box_, box, baseline_type_);
+  return box_states_->OnCloseTag(ConstraintSpace(), &line_box_, box,
+                                 baseline_type_);
 }
 
 // Place a NGLayoutResult into the line box.
@@ -748,6 +764,19 @@
   }
 }
 
+void NGInlineLayoutAlgorithm::PlaceRelativePositionedItems() {
+  for (auto& child : line_box_) {
+    const auto* physical_fragment = child.PhysicalFragment();
+    if (!physical_fragment)
+      continue;
+    if (physical_fragment->IsText())
+      continue;
+
+    child.rect.offset += ComputeRelativeOffsetForInline(
+        ConstraintSpace(), physical_fragment->Style());
+  }
+}
+
 // Place a list marker.
 void NGInlineLayoutAlgorithm::PlaceListMarker(const NGInlineItem& item,
                                               NGInlineItemResult* item_result,
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h
index 05b15a0..c15d729 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h
@@ -100,6 +100,7 @@
                             const NGLineHeightMetrics&,
                             const NGLineLayoutOpportunity&,
                             NGExclusionSpace*);
+  void PlaceRelativePositionedItems();
   void PlaceListMarker(const NGInlineItem&,
                        NGInlineItemResult*,
                        const NGLineInfo&);
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc
index 2cb44b8..28efed0 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc
@@ -34,13 +34,19 @@
   has_orthogonal_flow_roots_ = false;
   has_descendant_that_depends_on_percentage_block_size_ = false;
   has_block_fragmentation_ = false;
-  may_have_descendant_above_block_start_ = false;
 }
 
 void NGLineBoxFragmentBuilder::SetIsEmptyLineBox() {
   line_box_type_ = NGPhysicalLineBoxFragment::kEmptyLineBox;
 }
 
+void NGLineBoxFragmentBuilder::AddChild(
+    const NGPhysicalContainerFragment& child,
+    const LogicalOffset& child_offset) {
+  PropagateChildData(child, child_offset);
+  AddChildInternal(&child, child_offset);
+}
+
 void NGLineBoxFragmentBuilder::AddChildren(NGLogicalLineItems& children) {
   children_.ReserveCapacity(children.size());
 
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h
index 47540975..b309bc5 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h
@@ -71,6 +71,13 @@
     break_token_ = std::move(break_token);
   }
 
+  void AddChild(scoped_refptr<const NGPhysicalTextFragment> child,
+                const LogicalOffset& offset) {
+    AddChildInternal(child, offset);
+  }
+
+  void AddChild(const NGPhysicalContainerFragment&, const LogicalOffset&);
+
   // Add all items in ChildList. Skips null Child if any.
   void AddChildren(NGLogicalLineItems&);
 
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc
index 1ce15d8..69a0ec6 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc
@@ -95,7 +95,6 @@
     const ComputedStyle& container_style,
     TextHeightType height_type) const {
   const WritingMode container_writing_mode = container_style.GetWritingMode();
-  const TextDirection container_direction = container_style.Direction();
   PhysicalRect overflow;
   for (const auto& child : Children()) {
     PhysicalRect child_scroll_overflow =
@@ -106,16 +105,6 @@
       AdjustScrollableOverflowForHanging(LocalRect(), container_writing_mode,
                                          &child_scroll_overflow);
     }
-
-    // For implementation reasons, text nodes inherit computed style from their
-    // container, including everything, also non-inherited properties. So, if
-    // the container has a relative offset, this will be falsely reflected on
-    // text children. We need to guard against this.
-    if (!child->IsText()) {
-      child_scroll_overflow.offset +=
-          ComputeRelativeOffset(child->Style(), container_writing_mode,
-                                container_direction, container.Size());
-    }
     overflow.Unite(child_scroll_overflow);
   }
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
index bee690c..20eee05 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
@@ -18,6 +18,7 @@
 #include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_positioned_float.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_relative_utils.h"
 #include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
 
 namespace blink {
@@ -196,6 +197,37 @@
     PropagateBreak(child_layout_result);
 }
 
+void NGBoxFragmentBuilder::AddChild(const NGPhysicalContainerFragment& child,
+                                    const LogicalOffset& child_offset,
+                                    const LayoutInline* inline_container) {
+  LogicalOffset adjusted_offset = child_offset;
+
+  if (child.IsCSSBox() &&
+      box_type_ != NGPhysicalBoxFragment::NGBoxType::kInlineBox) {
+    // Apply the relative position offset.
+    const auto& box_child = To<NGPhysicalBoxFragment>(child);
+    if (box_child.Style().GetPosition() == EPosition::kRelative) {
+      adjusted_offset += ComputeRelativeOffsetForBoxFragment(
+          box_child, GetWritingDirection(), child_available_size_);
+    }
+
+    // The |may_have_descendant_above_block_start_| flag is used to determine
+    // if a fragment can be re-used when preceding floats are present. This is
+    // relatively rare, and is true if:
+    //  - An inflow child is positioned above our block-start edge.
+    //  - Any inflow descendants (within the same formatting-context) which
+    //    *may* have a child positioned above our block-start edge.
+    if ((child_offset.block_offset < LayoutUnit() &&
+         !box_child.IsOutOfFlowPositioned()) ||
+        (!box_child.IsFormattingContextRoot() &&
+         box_child.MayHaveDescendantAboveBlockStart()))
+      may_have_descendant_above_block_start_ = true;
+  }
+
+  PropagateChildData(child, adjusted_offset, inline_container);
+  AddChildInternal(&child, adjusted_offset);
+}
+
 void NGBoxFragmentBuilder::AddBreakToken(
     scoped_refptr<const NGBreakToken> token,
     bool is_in_parallel_flow) {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
index 6ea9056..ca5a2ea2 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
@@ -201,6 +201,15 @@
   // descendants, propagating fragmentainer breaks, and more.
   void AddResult(const NGLayoutResult&, const LogicalOffset);
 
+  void AddChild(scoped_refptr<const NGPhysicalTextFragment> child,
+                const LogicalOffset& offset) {
+    AddChildInternal(child, offset);
+  }
+
+  void AddChild(const NGPhysicalContainerFragment&,
+                const LogicalOffset&,
+                const LayoutInline* inline_container = nullptr);
+
   // Manually add a break token to the builder. Note that we're assuming that
   // this break token is for content in the same flow as this parent.
   void AddBreakToken(scoped_refptr<const NGBreakToken>,
@@ -492,6 +501,7 @@
   NGBlockNode column_spanner_ = nullptr;
 
   NGPhysicalFragment::NGBoxType box_type_;
+  bool may_have_descendant_above_block_start_ = false;
   bool is_fieldset_container_ = false;
   bool is_initial_block_size_indefinite_ = false;
   bool is_inline_formatting_context_;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
index 069997a..6d0b8193 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
@@ -167,6 +167,10 @@
     return static_cast<WritingMode>(bitfields_.writing_mode);
   }
 
+  WritingDirectionMode GetWritingDirection() const {
+    return {GetWritingMode(), Direction()};
+  }
+
   bool IsOrthogonalWritingModeRoot() const {
     return bitfields_.is_orthogonal_writing_mode_root;
   }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
index 2b45940..8757357 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
@@ -25,14 +25,6 @@
 
 }  // namespace
 
-void NGContainerFragmentBuilder::AddChild(
-    const NGPhysicalContainerFragment& child,
-    const LogicalOffset& child_offset,
-    const LayoutInline* inline_container) {
-  PropagateChildData(child, child_offset, inline_container);
-  AddChildInternal(&child, child_offset);
-}
-
 void NGContainerFragmentBuilder::ReplaceChild(
     wtf_size_t index,
     const NGPhysicalContainerFragment& new_child,
@@ -48,51 +40,25 @@
     const LogicalOffset& child_offset,
     const LayoutInline* inline_container) {
   // Collect the child's out of flow descendants.
-  // child_offset is offset of inline_start/block_start vertex.
-  // Candidates need offset of top/left vertex.
-  if (child.HasOutOfFlowPositionedDescendants()) {
-    const auto& out_of_flow_descendants =
-        child.OutOfFlowPositionedDescendants();
-    PhysicalSize child_size = child.Size();
+  for (const auto& descendant : child.OutOfFlowPositionedDescendants()) {
+    NGLogicalStaticPosition static_position =
+        descendant.static_position.ConvertToLogical(GetWritingMode(),
+                                                    Direction(), child.Size());
+    static_position.offset += child_offset;
 
-    // We can end up in a case where we need to account for the relative
-    // position of an element to correctly determine the static position of a
-    // descendant. E.g.
-    // <div id="fixed_container">
-    //   <div style="position: relative; top: 10px;">
-    //     <div style="position: fixed;"></div>
-    //   </div>
-    // </div>
-    // TODO(layout-dev): This code should eventually be removed once we handle
-    // relative positioned objects directly in the fragment tree.
-    LogicalOffset offset = child_offset;
-    if (const LayoutBox* child_box =
-            ToLayoutBoxOrNull(child.GetLayoutObject())) {
-      offset += PhysicalOffset(child_box->OffsetForInFlowPosition())
-                    .ConvertToLogical(GetWritingMode(), Direction(),
-                                      PhysicalSize(), PhysicalSize());
-    }
+    const LayoutInline* new_inline_container = descendant.inline_container;
+    if (!new_inline_container &&
+        IsInlineContainerForNode(descendant.node, inline_container))
+      new_inline_container = inline_container;
 
-    for (const auto& descendant : out_of_flow_descendants) {
-      NGLogicalStaticPosition static_position =
-          descendant.static_position.ConvertToLogical(GetWritingMode(),
-                                                      Direction(), child_size);
-      static_position.offset += offset;
-
-      const LayoutInline* new_inline_container = descendant.inline_container;
-      if (!descendant.inline_container &&
-          IsInlineContainerForNode(descendant.node, inline_container))
-        new_inline_container = inline_container;
-
-      // |oof_positioned_candidates_| should not have duplicated entries.
-      DCHECK(std::none_of(
-          oof_positioned_candidates_.begin(), oof_positioned_candidates_.end(),
-          [&descendant](const NGLogicalOutOfFlowPositionedNode& node) {
-            return node.node == descendant.node;
-          }));
-      oof_positioned_candidates_.emplace_back(descendant.node, static_position,
-                                              new_inline_container);
-    }
+    // |oof_positioned_candidates_| should not have duplicated entries.
+    DCHECK(std::none_of(
+        oof_positioned_candidates_.begin(), oof_positioned_candidates_.end(),
+        [&descendant](const NGLogicalOutOfFlowPositionedNode& node) {
+          return node.node == descendant.node;
+        }));
+    oof_positioned_candidates_.emplace_back(descendant.node, static_position,
+                                            new_inline_container);
   }
 
   if (const NGPhysicalBoxFragment* fragment =
@@ -151,18 +117,6 @@
     }
   }
 
-  // The |may_have_descendant_above_block_start_| flag is used to determine if
-  // a fragment can be re-used when preceding floats are present. This is
-  // relatively rare, and is true if:
-  //  - An inflow child is positioned above our block-start edge.
-  //  - Any inflow descendants (within the same formatting-context) which *may*
-  //    have a child positioned above our block-start edge.
-  if ((child_offset.block_offset < LayoutUnit() &&
-       !child.IsOutOfFlowPositioned()) ||
-      (!child.IsFormattingContextRoot() && !child.IsLineBox() &&
-       child.MayHaveDescendantAboveBlockStart()))
-    may_have_descendant_above_block_start_ = true;
-
   // Compute |has_floating_descendants_for_paint_| to optimize tree traversal
   // in paint.
   if (!has_floating_descendants_for_paint_) {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
index 097936d..671fa8e 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
@@ -77,15 +77,6 @@
     unpositioned_list_marker_ = marker;
   }
 
-  void AddChild(const NGPhysicalContainerFragment&,
-                const LogicalOffset&,
-                const LayoutInline* inline_container = nullptr);
-
-  void AddChild(scoped_refptr<const NGPhysicalTextFragment> child,
-                const LogicalOffset& offset) {
-    AddChildInternal(child, offset);
-  }
-
   void ReplaceChild(wtf_size_t index,
                     const NGPhysicalContainerFragment& new_child,
                     const LogicalOffset offset);
@@ -271,7 +262,6 @@
   bool has_descendant_that_depends_on_percentage_block_size_ = false;
   bool has_block_fragmentation_ = false;
   bool is_fragmentation_context_root_ = false;
-  bool may_have_descendant_above_block_start_ = false;
 
   bool has_oof_candidate_that_needs_block_offset_adjustment_ = false;
 };
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc
index 933c69e..82012a0 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc
@@ -231,7 +231,6 @@
   if (legend_break_token)
     legend_margins.block_start = LayoutUnit();
 
-  LogicalOffset legend_offset;
   scoped_refptr<const NGLayoutResult> result;
   scoped_refptr<const NGLayoutResult> previous_result;
   LayoutUnit block_offset = legend_margins.block_start;
@@ -327,9 +326,12 @@
   // pushed so that the center of the border will be flush with the center
   // of the border-box of the legend.
   // TODO(mstensho): inline alignment
-  legend_offset = LogicalOffset(
+  //
+  // NOTE: For painting purposes, this must be kept in sync with:
+  // NGFieldsetPainter::PaintFieldsetDecorationBackground
+  LogicalOffset legend_offset = {
       BorderScrollbarPadding().inline_start + legend_margins.inline_start,
-      block_offset);
+      block_offset};
 
   container_builder_.AddResult(*result, legend_offset);
   return NGBreakStatus::kContinue;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.cc b/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.cc
index 8d72e4ba..ccf3b50 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.cc
@@ -177,28 +177,26 @@
 // Store |ink_overflow| as |SmallRawValue| if possible and returns |true|.
 // Returns |false| if |ink_overflow| is too large for |SmallRawValue|.
 bool NGInkOverflow::TrySetOutsets(Type type,
-                                  const PhysicalRect& ink_overflow,
-                                  const PhysicalSize& size) {
+                                  LayoutUnit left_outset,
+                                  LayoutUnit top_outset,
+                                  LayoutUnit right_outset,
+                                  LayoutUnit bottom_outset) {
   CheckType(type);
   const LayoutUnit max_small_value(
       LayoutUnit::FromRawValue(std::numeric_limits<SmallRawValue>::max()));
-  const LayoutUnit left_outset = -ink_overflow.X();
   if (left_outset > max_small_value)
     return false;
-  const LayoutUnit top_outset = -ink_overflow.Y();
   if (top_outset > max_small_value)
     return false;
-  const LayoutUnit right_outset = ink_overflow.Right() - size.width;
   if (right_outset > max_small_value)
     return false;
-  const LayoutUnit bottom_outset = ink_overflow.Bottom() - size.height;
   if (bottom_outset > max_small_value)
     return false;
   Reset(type);
-  outsets_[0] = left_outset.ClampNegativeToZero().RawValue();
-  outsets_[1] = top_outset.ClampNegativeToZero().RawValue();
-  outsets_[2] = right_outset.ClampNegativeToZero().RawValue();
-  outsets_[3] = bottom_outset.ClampNegativeToZero().RawValue();
+  outsets_[0] = left_outset.RawValue();
+  outsets_[1] = top_outset.RawValue();
+  outsets_[2] = right_outset.RawValue();
+  outsets_[3] = bottom_outset.RawValue();
   return true;
 }
 
@@ -210,9 +208,20 @@
   CheckType(type);
   DCHECK(HasOverflow(ink_overflow, size));
 
-  if (TrySetOutsets(type, ink_overflow, size))
+  const LayoutUnit left_outset = (-ink_overflow.X()).ClampNegativeToZero();
+  const LayoutUnit top_outset = (-ink_overflow.Y()).ClampNegativeToZero();
+  const LayoutUnit right_outset =
+      (ink_overflow.Right() - size.width).ClampNegativeToZero();
+  const LayoutUnit bottom_outset =
+      (ink_overflow.Bottom() - size.height).ClampNegativeToZero();
+
+  if (TrySetOutsets(type, left_outset, top_outset, right_outset, bottom_outset))
     return SetType(new_small_type);
 
+  const PhysicalRect adjusted_ink_overflow(
+      -left_outset, -top_outset, left_outset + size.width + right_outset,
+      top_outset + size.height + bottom_outset);
+
   switch (type) {
     case kSelfAndContents:
       Reset(type);
@@ -221,12 +230,12 @@
     case kNone:
     case kSmallSelf:
     case kSmallContents:
-      single_ = new NGSingleInkOverflow(ink_overflow);
+      single_ = new NGSingleInkOverflow(adjusted_ink_overflow);
       return SetType(new_type);
     case kSelf:
     case kContents:
       DCHECK(single_);
-      single_->ink_overflow = ink_overflow;
+      single_->ink_overflow = adjusted_ink_overflow;
       return SetType(new_type);
   }
   NOTREACHED();
diff --git a/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.h b/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.h
index 2d9afd0..7c15a5f 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.h
@@ -121,8 +121,10 @@
   Type SetType(Type type);
 
   bool TrySetOutsets(Type type,
-                     const PhysicalRect& ink_overflow,
-                     const PhysicalSize& size);
+                     LayoutUnit left_outset,
+                     LayoutUnit top_outset,
+                     LayoutUnit right_outset,
+                     LayoutUnit bottom_outset);
   Type SetSingle(Type type,
                  const PhysicalRect& ink_overflow,
                  const PhysicalSize& size,
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_utils.cc b/third_party/blink/renderer/core/layout/ng/ng_layout_utils.cc
index db86d7a..96a66ab 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_layout_utils.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_layout_utils.cc
@@ -464,7 +464,8 @@
       !is_margin_strut_equal)
     return false;
 
-  const auto& physical_fragment = cached_layout_result.PhysicalFragment();
+  const auto& physical_fragment =
+      To<NGPhysicalBoxFragment>(cached_layout_result.PhysicalFragment());
 
   // Check we have a descendant that *may* be positioned above the block-start
   // edge. We abort if either the old or new space has floats, as we don't keep
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
index d01c51d..61b61767 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
@@ -121,6 +121,8 @@
   }
 
   is_first_for_node_ = builder->is_first_for_node_;
+  may_have_descendant_above_block_start_ =
+      builder->may_have_descendant_above_block_start_;
   is_fieldset_container_ = builder->is_fieldset_container_;
   is_legacy_layout_root_ = builder->is_legacy_layout_root_;
   is_painted_atomically_ =
@@ -207,17 +209,9 @@
     PhysicalRect overflow;
     if (height_type == TextHeightType::kNormalHeight || BoxType() != kInlineBox)
       overflow = PhysicalRect({}, Size());
-    WritingMode container_writing_mode = Style().GetWritingMode();
-    TextDirection container_direction = Style().Direction();
     for (const auto& child_fragment : PostLayoutChildren()) {
       PhysicalRect child_overflow =
           child_fragment->ScrollableOverflowForPropagation(*this, height_type);
-      if (child_fragment->Style() != Style()) {
-        PhysicalOffset relative_offset = ComputeRelativeOffset(
-            child_fragment->Style(), container_writing_mode,
-            container_direction, Size());
-        child_overflow.offset += relative_offset;
-      }
       child_overflow.offset += child_fragment.Offset();
       overflow.Unite(child_overflow);
     }
@@ -287,8 +281,6 @@
       DCHECK(child.IsFloatingOrOutOfFlowPositioned());
       PhysicalRect child_scrollable_overflow =
           child.ScrollableOverflowForPropagation(container, height_type);
-      child_scrollable_overflow.offset += ComputeRelativeOffset(
-          child.Style(), writing_mode, direction, container.Size());
       child_scrollable_overflow.offset += child_offset;
       AddChild(child_scrollable_overflow);
     }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
index 312cec5..ddd755b5 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
@@ -167,6 +167,12 @@
   // Return true if this is the first fragment generated from a node.
   bool IsFirstForNode() const { return is_first_for_node_; }
 
+  // Returns true if we have a descendant within this formatting context, which
+  // is potentially above our block-start edge.
+  bool MayHaveDescendantAboveBlockStart() const {
+    return may_have_descendant_above_block_start_;
+  }
+
 #if DCHECK_IS_ON()
   void CheckSameForSimplifiedLayout(const NGPhysicalBoxFragment&,
                                     bool check_same_block_size) const;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc
index e326e390..ea7728a 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc
@@ -52,8 +52,6 @@
   has_adjoining_object_descendants_ =
       builder->has_adjoining_object_descendants_;
   has_orthogonal_flow_roots_ = builder->has_orthogonal_flow_roots_;
-  may_have_descendant_above_block_start_ =
-      builder->may_have_descendant_above_block_start_;
   depends_on_percentage_block_size_ = DependsOnPercentageBlockSize(*builder);
 
   PhysicalSize size = Size();
@@ -172,7 +170,6 @@
          (cursor.Current().Item()->BoxFragment() == this ||
           cursor.Current().Item()->LineBoxFragment() == this));
   const WritingMode container_writing_mode = container_style.GetWritingMode();
-  const TextDirection container_direction = container_style.Direction();
   for (NGInlineCursor descendants = cursor.CursorForDescendants();
        descendants;) {
     const NGFragmentItem* item = descendants.CurrentItem();
@@ -215,9 +212,6 @@
             child_box->ScrollableOverflowForPropagation(container, height_type);
         child_scroll_overflow.offset += item->OffsetInContainerBlock();
       }
-      child_scroll_overflow.offset +=
-          ComputeRelativeOffset(child_box->Style(), container_writing_mode,
-                                container_direction, container.Size());
       overflow->Unite(child_scroll_overflow);
       descendants.MoveToNextSkippingChildren();
       continue;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h
index ad28769e..0a50bd5 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h
@@ -138,12 +138,6 @@
   // TODO(ikilpatrick): Remove this flag as its not used anymore.
   bool HasOrthogonalFlowRoots() const { return has_orthogonal_flow_roots_; }
 
-  // Returns true if we have a descendant within this formatting context, which
-  // is potentially above our block-start edge.
-  bool MayHaveDescendantAboveBlockStart() const {
-    return may_have_descendant_above_block_start_;
-  }
-
   // Returns true if we aren't able to re-use this fragment if the
   // |NGConstraintSpace::PercentageResolutionBlockSize| changes.
   bool DependsOnPercentageBlockSize() const {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
index e31ff7a..465fe25 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
@@ -354,15 +354,28 @@
 }
 
 const NGPhysicalFragment* NGPhysicalFragment::PostLayout() const {
-  if (IsBox() && !IsInlineBox()) {
-    if (const auto* block = DynamicTo<LayoutBlockFlow>(GetLayoutObject())) {
-      if (block->IsRelayoutBoundary()) {
-        const NGPhysicalFragment* new_fragment = block->CurrentFragment();
-        if (new_fragment && new_fragment != this)
-          return new_fragment;
-      }
+  const auto* layout_box = ToLayoutBoxOrNull(GetLayoutObject());
+  if (UNLIKELY(!layout_box))
+    return nullptr;
+
+  DCHECK_GT(layout_box->PhysicalFragmentCount(), 0u);
+  if (layout_box->PhysicalFragmentCount() == 1) {
+    const NGPhysicalFragment* post_layout = layout_box->GetPhysicalFragment(0);
+    DCHECK(post_layout);
+    if (UNLIKELY(post_layout && post_layout != this)) {
+      // Relayout boundary is the only case this can happen. crbug.com/829028
+      DCHECK(layout_box->IsRelayoutBoundary());
+      return post_layout;
     }
+  } else {
+    // TODO(crbug.com/829028): Block fragmentation not supported yet.
+    DCHECK(!layout_box->IsRelayoutBoundary());
   }
+  DCHECK(std::any_of(layout_box->PhysicalFragments().begin(),
+                     layout_box->PhysicalFragments().end(),
+                     [this](const NGPhysicalFragment& fragment) {
+                       return this == &fragment;
+                     }));
   return nullptr;
 }
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
index b569ed2..9eadb09 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
@@ -429,7 +429,6 @@
   unsigned has_floating_descendants_for_paint_ : 1;
   unsigned has_adjoining_object_descendants_ : 1;
   unsigned has_orthogonal_flow_roots_ : 1;
-  unsigned may_have_descendant_above_block_start_ : 1;
   unsigned depends_on_percentage_block_size_ : 1;
 
   // The following bitfields are only to be used by NGPhysicalLineBoxFragment
@@ -457,6 +456,7 @@
   unsigned is_math_fraction_ : 1;
   // base (line box) or resolve (text) direction
   unsigned base_or_resolved_direction_ : 1;  // TextDirection
+  unsigned may_have_descendant_above_block_start_ : 1;
 
   // The following are only used by NGPhysicalBoxFragment but are initialized
   // for all types to allow methods using them to be inlined.
diff --git a/third_party/blink/renderer/core/layout/ng/ng_relative_utils.cc b/third_party/blink/renderer/core/layout/ng/ng_relative_utils.cc
index e9837e0..76ed235 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_relative_utils.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_relative_utils.cc
@@ -7,68 +7,131 @@
 #include "base/optional.h"
 #include "third_party/blink/renderer/core/layout/geometry/physical_offset.h"
 #include "third_party/blink/renderer/core/layout/geometry/physical_size.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
 #include "third_party/blink/renderer/platform/geometry/length_functions.h"
 
 namespace blink {
 
-// Returns the child's relative position wrt the containing fragment.
-PhysicalOffset ComputeRelativeOffset(const ComputedStyle& child_style,
-                                     WritingMode container_writing_mode,
-                                     TextDirection container_direction,
-                                     PhysicalSize container_size) {
-  PhysicalOffset offset;
+LogicalOffset ComputeRelativeOffset(
+    const ComputedStyle& child_style,
+    WritingDirectionMode container_writing_direction,
+    const LogicalSize& available_size) {
   if (child_style.GetPosition() != EPosition::kRelative)
-    return offset;
+    return LogicalOffset();
 
   base::Optional<LayoutUnit> left, right, top, bottom;
 
+  const PhysicalSize physical_size = ToPhysicalSize(
+      available_size, container_writing_direction.GetWritingMode());
+
   if (!child_style.Left().IsAuto())
-    left = MinimumValueForLength(child_style.Left(), container_size.width);
+    left = MinimumValueForLength(child_style.Left(), physical_size.width);
   if (!child_style.Right().IsAuto())
-    right = MinimumValueForLength(child_style.Right(), container_size.width);
+    right = MinimumValueForLength(child_style.Right(), physical_size.width);
   if (!child_style.Top().IsAuto())
-    top = MinimumValueForLength(child_style.Top(), container_size.height);
+    top = MinimumValueForLength(child_style.Top(), physical_size.height);
   if (!child_style.Bottom().IsAuto())
-    bottom = MinimumValueForLength(child_style.Bottom(), container_size.height);
+    bottom = MinimumValueForLength(child_style.Bottom(), physical_size.height);
 
-  // Common case optimization
+  // Common case optimization.
   if (!left && !right && !top && !bottom)
-    return offset;
+    return LogicalOffset();
 
-  // Implements confict resolution rules from spec:
-  // https://www.w3.org/TR/css-position-3/#rel-pos
+  // Conflict resolution rules: https://www.w3.org/TR/css-position-3/#rel-pos
   if (!left && !right) {
     left = LayoutUnit();
     right = LayoutUnit();
-  }
-  if (!left)
+  } else if (!left) {
     left = -*right;
-  if (!right)
+  } else if (!right) {
     right = -*left;
+  }
+
   if (!top && !bottom) {
     top = LayoutUnit();
     bottom = LayoutUnit();
-  }
-  if (!top)
+  } else if (!top) {
     top = -*bottom;
-  if (!bottom)
+  } else if (!bottom) {
     bottom = -*top;
-
-  if (IsHorizontalWritingMode(container_writing_mode)) {
-    if (IsLtr(container_direction))
-      offset.left = *left;
-    else
-      offset.left = -*right;
-    offset.top = *top;
-  } else {
-    if (IsLtr(container_direction))
-      offset.top = *top;
-    else
-      offset.top = -*bottom;
-    offset.left = *left;
   }
-  return offset;
+
+  switch (container_writing_direction.GetWritingMode()) {
+    case WritingMode::kHorizontalTb:
+      return container_writing_direction.IsLtr() ? LogicalOffset(*left, *top)
+                                                 : LogicalOffset(*right, *top);
+    case WritingMode::kVerticalRl:
+    case WritingMode::kSidewaysRl:
+      return container_writing_direction.IsLtr()
+                 ? LogicalOffset(*top, *right)
+                 : LogicalOffset(*bottom, *right);
+    case WritingMode::kVerticalLr:
+      return container_writing_direction.IsLtr()
+                 ? LogicalOffset(*top, *left)
+                 : LogicalOffset(*bottom, *left);
+    case WritingMode::kSidewaysLr:
+      return container_writing_direction.IsLtr() ? LogicalOffset(*bottom, *left)
+                                                 : LogicalOffset(*top, *left);
+    default:
+      NOTREACHED();
+      return LogicalOffset();
+  }
+}
+
+LogicalOffset ComputeRelativeOffsetForBoxFragment(
+    const NGPhysicalBoxFragment& fragment,
+    WritingDirectionMode container_writing_direction,
+    const LogicalSize& available_size) {
+  const auto& child_style = fragment.Style();
+  DCHECK_EQ(child_style.GetPosition(), EPosition::kRelative);
+
+  LogicalOffset relative_offset = ComputeRelativeOffset(
+      child_style, container_writing_direction, available_size);
+
+  const auto* block_flow =
+      DynamicTo<LayoutBlockFlow>(fragment.GetLayoutObject());
+  if (!block_flow)
+    return relative_offset;
+
+  // We may be within a split-inline. This isn't ideal, but we need to walk up
+  // our inline ancestor chain applying any relative offsets.
+  for (const LayoutObject* layout_object =
+           block_flow->InlineElementContinuation();
+       layout_object && layout_object->IsLayoutInline();
+       layout_object = layout_object->Parent()) {
+    relative_offset += ComputeRelativeOffset(
+        layout_object->StyleRef(), container_writing_direction, available_size);
+  }
+
+  return relative_offset;
+}
+
+LogicalOffset ComputeRelativeOffsetForInline(const NGConstraintSpace& space,
+                                             const ComputedStyle& child_style) {
+  if (child_style.GetPosition() != EPosition::kRelative)
+    return LogicalOffset();
+
+  // The confliction resolution rules work based off the block's writing-mode
+  // and direction, not the child's container. E.g.
+  // <span style="direction: rtl;">
+  //   <span style="position: relative; left: 100px; right: -50px;"></span>
+  // </span>
+  // In the above example "left" wins.
+  const WritingDirectionMode writing_direction = space.GetWritingDirection();
+  LogicalOffset relative_offset = ComputeRelativeOffset(
+      child_style, writing_direction, space.AvailableSize());
+
+  // Lines are built in a line-logical coordinate system:
+  // https://drafts.csswg.org/css-writing-modes-3/#line-directions
+  // Reverse the offset direction if we are in a RTL, or flipped writing-mode.
+  if (writing_direction.IsRtl())
+    relative_offset.inline_offset = -relative_offset.inline_offset;
+  if (writing_direction.IsFlippedLines())
+    relative_offset.block_offset = -relative_offset.block_offset;
+
+  return relative_offset;
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/ng_relative_utils.h b/third_party/blink/renderer/core/layout/ng/ng_relative_utils.h
index e15d5563..1257d23 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_relative_utils.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_relative_utils.h
@@ -12,16 +12,25 @@
 namespace blink {
 
 class ComputedStyle;
-struct PhysicalOffset;
+class NGConstraintSpace;
+class NGPhysicalBoxFragment;
 
-// Implements the relative positioning spec:
+// Implements relative positioning:
 // https://www.w3.org/TR/css-position-3/#rel-pos
 // Returns the relative position offset as defined by |child_style|.
-CORE_EXPORT PhysicalOffset
+CORE_EXPORT LogicalOffset
 ComputeRelativeOffset(const ComputedStyle& child_style,
-                      WritingMode container_writing_mode,
-                      TextDirection container_direction,
-                      PhysicalSize container_size);
+                      WritingDirectionMode container_writing_direction,
+                      const LogicalSize& available_size);
+
+CORE_EXPORT LogicalOffset ComputeRelativeOffsetForBoxFragment(
+    const NGPhysicalBoxFragment& fragment,
+    WritingDirectionMode container_writing_direction,
+    const LogicalSize& available_size);
+
+CORE_EXPORT LogicalOffset
+ComputeRelativeOffsetForInline(const NGConstraintSpace& space,
+                               const ComputedStyle& child_style);
 
 }  // namespace blink
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_relative_utils_test.cc b/third_party/blink/renderer/core/layout/ng/ng_relative_utils_test.cc
index 763839f..d09ca75 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_relative_utils_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_relative_utils_test.cc
@@ -12,8 +12,6 @@
 namespace blink {
 namespace {
 
-const LayoutUnit kHorizontalSize{100};
-const LayoutUnit kVerticalSize{200};
 const LayoutUnit kLeft{3};
 const LayoutUnit kRight{5};
 const LayoutUnit kTop{7};
@@ -26,7 +24,6 @@
   void SetUp() override {
     style_ = ComputedStyle::Create();
     style_->SetPosition(EPosition::kRelative);
-    container_size_ = PhysicalSize{kHorizontalSize, kVerticalSize};
   }
 
   void SetTRBL(LayoutUnit top,
@@ -43,92 +40,102 @@
   }
 
   scoped_refptr<ComputedStyle> style_;
-  PhysicalSize container_size_;
+  LogicalSize container_size_;
 };
 
 TEST_F(NGRelativeUtilsTest, HorizontalTB) {
-  PhysicalOffset offset;
+  LogicalOffset offset;
 
   // Everything auto defaults to kZero,kZero
   SetTRBL(kAuto, kAuto, kAuto, kAuto);
-  offset = ComputeRelativeOffset(*style_, WritingMode::kHorizontalTb,
-                                 TextDirection::kLtr, container_size_);
-  EXPECT_EQ(offset.left, kZero);
-  EXPECT_EQ(offset.top, kZero);
+  offset = ComputeRelativeOffset(
+      *style_, {WritingMode::kHorizontalTb, TextDirection::kLtr},
+      container_size_);
+  EXPECT_EQ(offset.inline_offset, kZero);
+  EXPECT_EQ(offset.block_offset, kZero);
 
   // Set all sides
   SetTRBL(kTop, kRight, kBottom, kLeft);
 
   // kLtr
-  offset = ComputeRelativeOffset(*style_, WritingMode::kHorizontalTb,
-                                 TextDirection::kLtr, container_size_);
-  EXPECT_EQ(offset.left, kLeft);
-  EXPECT_EQ(offset.top, kTop);
+  offset = ComputeRelativeOffset(
+      *style_, {WritingMode::kHorizontalTb, TextDirection::kLtr},
+      container_size_);
+  EXPECT_EQ(offset.inline_offset, kLeft);
+  EXPECT_EQ(offset.block_offset, kTop);
 
   // kRtl
-  offset = ComputeRelativeOffset(*style_, WritingMode::kHorizontalTb,
-                                 TextDirection::kRtl, container_size_);
-  EXPECT_EQ(offset.left, -kRight);
-  EXPECT_EQ(offset.top, kTop);
+  offset = ComputeRelativeOffset(
+      *style_, {WritingMode::kHorizontalTb, TextDirection::kRtl},
+      container_size_);
+  EXPECT_EQ(offset.inline_offset, kRight);
+  EXPECT_EQ(offset.block_offset, kTop);
 
   // Set only non-default sides
   SetTRBL(kAuto, kRight, kBottom, kAuto);
-  offset = ComputeRelativeOffset(*style_, WritingMode::kHorizontalTb,
-                                 TextDirection::kLtr, container_size_);
-  EXPECT_EQ(offset.left, -kRight);
-  EXPECT_EQ(offset.top, -kBottom);
+  offset = ComputeRelativeOffset(
+      *style_, {WritingMode::kHorizontalTb, TextDirection::kLtr},
+      container_size_);
+  EXPECT_EQ(offset.inline_offset, -kRight);
+  EXPECT_EQ(offset.block_offset, -kBottom);
 }
 
 TEST_F(NGRelativeUtilsTest, VerticalRightLeft) {
-  PhysicalOffset offset;
+  LogicalOffset offset;
 
   // Set all sides
   SetTRBL(kTop, kRight, kBottom, kLeft);
 
   // kLtr
-  offset = ComputeRelativeOffset(*style_, WritingMode::kVerticalRl,
-                                 TextDirection::kLtr, container_size_);
-  EXPECT_EQ(offset.top, kTop);
-  EXPECT_EQ(offset.left, kLeft);
+  offset = ComputeRelativeOffset(
+      *style_, {WritingMode::kVerticalRl, TextDirection::kLtr},
+      container_size_);
+  EXPECT_EQ(offset.inline_offset, kTop);
+  EXPECT_EQ(offset.block_offset, kRight);
 
   // kRtl
-  offset = ComputeRelativeOffset(*style_, WritingMode::kVerticalRl,
-                                 TextDirection::kRtl, container_size_);
-  EXPECT_EQ(offset.top, -kBottom);
-  EXPECT_EQ(offset.left, kLeft);
+  offset = ComputeRelativeOffset(
+      *style_, {WritingMode::kVerticalRl, TextDirection::kRtl},
+      container_size_);
+  EXPECT_EQ(offset.inline_offset, kBottom);
+  EXPECT_EQ(offset.block_offset, kRight);
 
   // Set only non-default sides
-  SetTRBL(kAuto, kRight, kBottom, kAuto);
-  offset = ComputeRelativeOffset(*style_, WritingMode::kVerticalRl,
-                                 TextDirection::kLtr, container_size_);
-  EXPECT_EQ(offset.top, -kBottom);
-  EXPECT_EQ(offset.left, -kRight);
+  SetTRBL(kAuto, kAuto, kBottom, kLeft);
+  offset = ComputeRelativeOffset(
+      *style_, {WritingMode::kVerticalRl, TextDirection::kLtr},
+      container_size_);
+  EXPECT_EQ(offset.inline_offset, -kBottom);
+  EXPECT_EQ(offset.block_offset, -kLeft);
 }
 
 TEST_F(NGRelativeUtilsTest, VerticalLeftRight) {
-  PhysicalOffset offset;
+  LogicalOffset offset;
 
   // Set all sides
   SetTRBL(kTop, kRight, kBottom, kLeft);
 
   // kLtr
-  offset = ComputeRelativeOffset(*style_, WritingMode::kVerticalLr,
-                                 TextDirection::kLtr, container_size_);
-  EXPECT_EQ(offset.top, kTop);
-  EXPECT_EQ(offset.left, kLeft);
+  offset = ComputeRelativeOffset(
+      *style_, {WritingMode::kVerticalLr, TextDirection::kLtr},
+      container_size_);
+  EXPECT_EQ(offset.inline_offset, kTop);
+  EXPECT_EQ(offset.block_offset, kLeft);
 
   // kRtl
-  offset = ComputeRelativeOffset(*style_, WritingMode::kVerticalLr,
-                                 TextDirection::kRtl, container_size_);
-  EXPECT_EQ(offset.top, -kBottom);
-  EXPECT_EQ(offset.left, kLeft);
+  offset = ComputeRelativeOffset(
+      *style_, {WritingMode::kVerticalLr, TextDirection::kRtl},
+      container_size_);
+  EXPECT_EQ(offset.inline_offset, kBottom);
+  EXPECT_EQ(offset.block_offset, kLeft);
 
   // Set only non-default sides
   SetTRBL(kAuto, kRight, kBottom, kAuto);
-  offset = ComputeRelativeOffset(*style_, WritingMode::kVerticalLr,
-                                 TextDirection::kLtr, container_size_);
-  EXPECT_EQ(offset.top, -kBottom);
-  EXPECT_EQ(offset.left, -kRight);
+  offset = ComputeRelativeOffset(
+      *style_, {WritingMode::kVerticalLr, TextDirection::kLtr},
+      container_size_);
+  EXPECT_EQ(offset.inline_offset, -kBottom);
+  EXPECT_EQ(offset.block_offset, -kRight);
 }
 
 }  // namespace
diff --git a/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc
index f21885d..ccabccb 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc
@@ -15,6 +15,7 @@
 #include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_relative_utils.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_space_utils.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 
@@ -232,6 +233,15 @@
                            previous_physical_container_size_)
           .ToLogical(old_fragment.Offset(), new_fragment.Size());
 
+  // Un-apply the relative position offset.
+  if (const auto* box_child = DynamicTo<NGPhysicalBoxFragment>(*old_fragment)) {
+    if (box_child->Style().GetPosition() == EPosition::kRelative) {
+      child_offset -= ComputeRelativeOffsetForBoxFragment(
+          *box_child, ConstraintSpace().GetWritingDirection(),
+          container_builder_.ChildAvailableSize());
+    }
+  }
+
   // Add the new fragment to the builder.
   container_builder_.AddChild(new_fragment, child_offset);
 }
diff --git a/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc b/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc
index 77080c6..cd4ce78 100644
--- a/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc
+++ b/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc
@@ -843,11 +843,10 @@
 
   rect = target_visual_rect;
 
-  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
-    CheckVisualRect(*target, *span, rect, PhysicalRect(0, 0, 33, 44));
-  } else {
+  if (RuntimeEnabledFeatures::LayoutNGEnabled())
+    CheckVisualRect(*target, *span, rect, PhysicalRect(200, 100, 33, 44));
+  else
     CheckVisualRect(*target, *span, rect, PhysicalRect(-200, -100, 33, 44));
-  }
 }
 
 TEST_P(VisualRectMappingTest, FloatUnderInlineVerticalRL) {
@@ -884,7 +883,7 @@
   // the right edge of the coordinate space whose width is 600.
   rect = target_visual_rect;
   if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
-    CheckVisualRect(*target, *span, rect, PhysicalRect(600 - 33, 0, 33, 44));
+    CheckVisualRect(*target, *span, rect, PhysicalRect(367, 100, 33, 44));
   } else {
     CheckVisualRect(*target, *span, rect,
                     PhysicalRect(600 + 200 - 33, -100, 33, 44));
@@ -914,7 +913,10 @@
   EXPECT_EQ(EnclosingIntRect(rect), target->FirstFragment().VisualRect());
 
   rect = target_visual_rect;
-  CheckVisualRect(*target, *span, rect, PhysicalRect(0, 0, 33, 44));
+  if (RuntimeEnabledFeatures::LayoutNGEnabled())
+    CheckVisualRect(*target, *span, rect, PhysicalRect(200, 100, 33, 44));
+  else
+    CheckVisualRect(*target, *span, rect, PhysicalRect(0, 0, 33, 44));
 }
 
 TEST_P(VisualRectMappingTest, InlineBlockVerticalRL) {
@@ -944,7 +946,10 @@
   // space shifted by the inline's relative offset. |target|'s left is -33 from
   // the right edge of the coordinate space whose width is 600.
   rect = target_visual_rect;
-  CheckVisualRect(*target, *span, rect, PhysicalRect(600 - 33, 0, 33, 44));
+  if (RuntimeEnabledFeatures::LayoutNGEnabled())
+    CheckVisualRect(*target, *span, rect, PhysicalRect(367, 100, 33, 44));
+  else
+    CheckVisualRect(*target, *span, rect, PhysicalRect(600 - 33, 0, 33, 44));
 }
 
 TEST_P(VisualRectMappingTest, AbsoluteUnderRelativeInline) {
@@ -970,7 +975,10 @@
   EXPECT_EQ(EnclosingIntRect(rect), target->FirstFragment().VisualRect());
 
   rect = target_visual_rect;
-  CheckVisualRect(*target, *span, rect, PhysicalRect(100, 50, 33, 44));
+  if (RuntimeEnabledFeatures::LayoutNGEnabled())
+    CheckVisualRect(*target, *span, rect, PhysicalRect(300, 150, 33, 44));
+  else
+    CheckVisualRect(*target, *span, rect, PhysicalRect(100, 50, 33, 44));
 }
 
 TEST_P(VisualRectMappingTest, AbsoluteUnderRelativeInlineVerticalRL) {
@@ -1000,7 +1008,10 @@
   // space shifted by the inline's relative offset. |target|'s left is 100 from
   // the right edge of the coordinate space whose width is 600.
   rect = target_visual_rect;
-  CheckVisualRect(*target, *span, rect, PhysicalRect(600 + 100, 50, 33, 44));
+  if (RuntimeEnabledFeatures::LayoutNGEnabled())
+    CheckVisualRect(*target, *span, rect, PhysicalRect(500, 150, 33, 44));
+  else
+    CheckVisualRect(*target, *span, rect, PhysicalRect(600 + 100, 50, 33, 44));
 }
 
 TEST_P(VisualRectMappingTest, ShouldAccountForPreserve3d) {
diff --git a/third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.cc
index 6d94c26..e6d2ed4 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.h"
 
 #include "third_party/blink/renderer/core/layout/layout_box.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
 #include "third_party/blink/renderer/core/paint/background_image_geometry.h"
 #include "third_party/blink/renderer/core/paint/box_decoration_data.h"
@@ -55,8 +56,27 @@
   const ComputedStyle& style = fieldset_.Style();
   PhysicalRect legend_border_box;
   if (legend) {
-    legend_border_box.offset = legend->Offset();
     legend_border_box.size = (*legend)->Size();
+
+    // Recalculate the legend offset without the relative position offset.
+    const WritingDirectionMode writing_direction = style.GetWritingDirection();
+    const LogicalSize logical_fieldset_size =
+        fieldset_size.ConvertToLogical(writing_direction.GetWritingMode());
+    const NGBoxStrut border_padding =
+        (fragment.Borders() + fragment.Padding())
+            .ConvertToLogical(writing_direction.GetWritingMode(),
+                              writing_direction.Direction());
+    const NGBoxStrut legend_margins = ComputeMarginsFor(
+        (*legend)->Style(),
+        (logical_fieldset_size.inline_size - border_padding.InlineSum())
+            .ClampNegativeToZero(),
+        writing_direction.GetWritingMode(), writing_direction.Direction());
+
+    const LogicalOffset offset = {
+        border_padding.inline_start + legend_margins.inline_start,
+        legend_margins.block_start};
+    legend_border_box.offset = offset.ConvertToPhysical(
+        writing_direction, fieldset_size, legend_border_box.size);
   }
   FieldsetPaintInfo fieldset_paint_info(style, fieldset_size, fieldset_borders,
                                         legend_border_box);
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc
index 8a7e6dec..cd48054 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -58,6 +58,7 @@
 #include "third_party/blink/renderer/core/frame/local_frame.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/frame/visual_viewport.h"
 #include "third_party/blink/renderer/core/html_names.h"
 #include "third_party/blink/renderer/core/layout/fragmentainer_iterator.h"
 #include "third_party/blink/renderer/core/layout/geometry/transform_state.h"
@@ -1938,6 +1939,22 @@
   if (result.GetHitTestRequest().IgnoreClipping())
     clip_behavior = kIgnoreOverflowClip;
 
+  // For the global root scroller, hit test the layout viewport scrollbars
+  // first, as they are visually presented on top of the content.
+  if (GetLayoutObject().IsGlobalRootScroller()) {
+    // There are a number of early outs below that don't apply to the the
+    // global root scroller.
+    DCHECK(!Transform());
+    DCHECK(!Preserves3D());
+    DCHECK(!layout_object.HasClipPath());
+    if (scrollable_area_) {
+      IntPoint point = scrollable_area_->ConvertFromRootFrameToVisualViewport(
+          RoundedIntPoint(recursion_data.location.Point()));
+      if (scrollable_area_->HitTestOverflowControls(result, point))
+        return this;
+    }
+  }
+
   // We can only reach an SVG foreign object's PaintLayer from
   // LayoutSVGForeignObject::NodeAtFloatPoint (because
   // IsReplacedNormalFlowStacking() true for LayoutSVGForeignObject),
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
index b245859..fa826613 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -490,6 +490,15 @@
   return view->GetFrameView()->ConvertFromRootFrame(point_in_root_frame);
 }
 
+IntPoint PaintLayerScrollableArea::ConvertFromRootFrameToVisualViewport(
+    const IntPoint& point_in_root_frame) const {
+  LocalFrameView* frame_view = GetLayoutBox()->GetFrameView();
+  DCHECK(frame_view);
+  const auto* page = frame_view->GetPage();
+  const auto& viewport = page->GetVisualViewport();
+  return viewport.RootFrameToViewport(point_in_root_frame);
+}
+
 int PaintLayerScrollableArea::ScrollSize(
     ScrollbarOrientation orientation) const {
   IntSize scroll_dimensions =
@@ -925,6 +934,19 @@
   return max(page_step, 1);
 }
 
+bool PaintLayerScrollableArea::IsRootFrameLayoutViewport() const {
+  LocalFrame* frame = GetLayoutBox()->GetFrame();
+  if (!frame || !frame->View())
+    return false;
+
+  RootFrameViewport* root_frame_viewport =
+      frame->View()->GetRootFrameViewport();
+  if (!root_frame_viewport)
+    return false;
+
+  return &root_frame_viewport->LayoutViewport() == this;
+}
+
 LayoutBox* PaintLayerScrollableArea::GetLayoutBox() const {
   return layer_ ? layer_->GetLayoutBox() : nullptr;
 }
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
index 0e7d8db..c06dff5 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
@@ -304,6 +304,7 @@
       const Scrollbar&,
       const IntPoint&) const override;
   IntPoint ConvertFromRootFrame(const IntPoint&) const override;
+  IntPoint ConvertFromRootFrameToVisualViewport(const IntPoint&) const override;
   int ScrollSize(ScrollbarOrientation) const override;
   FloatPoint ScrollPosition() const override {
     return FloatPoint(ScrollOrigin()) + GetScrollOffset();
@@ -482,6 +483,7 @@
   bool RestoreScrollAnchor(const SerializedAnchor&) override;
   ScrollAnchor* GetScrollAnchor() override { return &scroll_anchor_; }
   bool IsPaintLayerScrollableArea() const override { return true; }
+  bool IsRootFrameLayoutViewport() const override;
 
   LayoutBox* GetLayoutBox() const override;
 
diff --git a/third_party/blink/renderer/core/paint/paint_layer_test.cc b/third_party/blink/renderer/core/paint/paint_layer_test.cc
index 621d811..3bbebef 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_test.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_test.cc
@@ -1574,34 +1574,51 @@
   EXPECT_EQ(container, span->ContainingLayer());
 
   if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
-    EXPECT_EQ(PhysicalOffset(0, 0), floating->LocationWithoutPositionOffset());
-    EXPECT_EQ(PhysicalOffset(50, 50),
+    EXPECT_EQ(PhysicalOffset(150, 150),
+              floating->LocationWithoutPositionOffset());
+    EXPECT_EQ(PhysicalOffset(0, 0),
               floating->GetLayoutObject().OffsetForInFlowPosition());
+    EXPECT_EQ(PhysicalOffset(150, 150),
+              floating->VisualOffsetFromAncestor(span));
+    EXPECT_EQ(PhysicalOffset(183, 183),
+              floating->VisualOffsetFromAncestor(container));
   } else {
     EXPECT_EQ(PhysicalOffset(33, 33),
               floating->LocationWithoutPositionOffset());
     EXPECT_EQ(PhysicalOffset(50, 50),
               floating->GetLayoutObject().OffsetForInFlowPosition());
-  }
-  EXPECT_EQ(PhysicalOffset(50, 50), absolute->LocationWithoutPositionOffset());
-  EXPECT_EQ(PhysicalOffset(33, 33), span->LocationWithoutPositionOffset());
-  EXPECT_EQ(PhysicalOffset(100, 100),
-            span->GetLayoutObject().OffsetForInFlowPosition());
-  EXPECT_EQ(PhysicalOffset(20, 20), container->LocationWithoutPositionOffset());
-
-  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
-    EXPECT_EQ(PhysicalOffset(50, 50), floating->VisualOffsetFromAncestor(span));
-    EXPECT_EQ(PhysicalOffset(183, 183),
-              floating->VisualOffsetFromAncestor(container));
-  } else {
     EXPECT_EQ(PhysicalOffset(-50, -50),
               floating->VisualOffsetFromAncestor(span));
     EXPECT_EQ(PhysicalOffset(83, 83),
               floating->VisualOffsetFromAncestor(container));
   }
-  EXPECT_EQ(PhysicalOffset(50, 50), absolute->VisualOffsetFromAncestor(span));
-  EXPECT_EQ(PhysicalOffset(183, 183),
-            absolute->VisualOffsetFromAncestor(container));
+
+  EXPECT_EQ(PhysicalOffset(20, 20), container->LocationWithoutPositionOffset());
+
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    EXPECT_EQ(PhysicalOffset(33, 33), span->LocationWithoutPositionOffset());
+    EXPECT_EQ(PhysicalOffset(0, 0),
+              span->GetLayoutObject().OffsetForInFlowPosition());
+  } else {
+    EXPECT_EQ(PhysicalOffset(33, 33), span->LocationWithoutPositionOffset());
+    EXPECT_EQ(PhysicalOffset(100, 100),
+              span->GetLayoutObject().OffsetForInFlowPosition());
+  }
+
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    EXPECT_EQ(PhysicalOffset(150, 150),
+              absolute->LocationWithoutPositionOffset());
+    EXPECT_EQ(PhysicalOffset(150, 150),
+              absolute->VisualOffsetFromAncestor(span));
+    EXPECT_EQ(PhysicalOffset(183, 183),
+              absolute->VisualOffsetFromAncestor(container));
+  } else {
+    EXPECT_EQ(PhysicalOffset(50, 50),
+              absolute->LocationWithoutPositionOffset());
+    EXPECT_EQ(PhysicalOffset(50, 50), absolute->VisualOffsetFromAncestor(span));
+    EXPECT_EQ(PhysicalOffset(183, 183),
+              absolute->VisualOffsetFromAncestor(container));
+  }
 }
 
 TEST_P(PaintLayerTest, FloatLayerUnderInlineLayerScrolled) {
@@ -1631,19 +1648,26 @@
   EXPECT_EQ(container, span->Parent());
   EXPECT_EQ(container, span->ContainingLayer());
 
-  EXPECT_EQ(PhysicalOffset(0, 0), span->LocationWithoutPositionOffset());
-  EXPECT_EQ(PhysicalOffset(100, 100),
-            span->GetLayoutObject().OffsetForInFlowPosition());
-  EXPECT_EQ(LayoutSize(0, 400),
-            span->ContainingLayer()->PixelSnappedScrolledContentOffset());
   if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
-    EXPECT_EQ(PhysicalOffset(0, 0), floating->LocationWithoutPositionOffset());
-    EXPECT_EQ(PhysicalOffset(50, 50),
+    EXPECT_EQ(PhysicalOffset(0, 0), span->LocationWithoutPositionOffset());
+    EXPECT_EQ(PhysicalOffset(0, 0),
+              span->GetLayoutObject().OffsetForInFlowPosition());
+    EXPECT_EQ(LayoutSize(0, 400),
+              span->ContainingLayer()->PixelSnappedScrolledContentOffset());
+    EXPECT_EQ(PhysicalOffset(150, 150),
+              floating->LocationWithoutPositionOffset());
+    EXPECT_EQ(PhysicalOffset(0, 0),
               floating->GetLayoutObject().OffsetForInFlowPosition());
-    EXPECT_EQ(PhysicalOffset(50, 50), floating->VisualOffsetFromAncestor(span));
+    EXPECT_EQ(PhysicalOffset(150, 150),
+              floating->VisualOffsetFromAncestor(span));
     EXPECT_EQ(PhysicalOffset(150, -250),
               floating->VisualOffsetFromAncestor(container));
   } else {
+    EXPECT_EQ(PhysicalOffset(0, 0), span->LocationWithoutPositionOffset());
+    EXPECT_EQ(PhysicalOffset(100, 100),
+              span->GetLayoutObject().OffsetForInFlowPosition());
+    EXPECT_EQ(LayoutSize(0, 400),
+              span->ContainingLayer()->PixelSnappedScrolledContentOffset());
     EXPECT_EQ(PhysicalOffset(0, 0), floating->LocationWithoutPositionOffset());
     EXPECT_EQ(PhysicalOffset(50, 50),
               floating->GetLayoutObject().OffsetForInFlowPosition());
@@ -1674,16 +1698,32 @@
   EXPECT_EQ(span, floating->Parent());
   EXPECT_EQ(span, floating->ContainingLayer());
 
-  EXPECT_EQ(PhysicalOffset(33, 33), floating->LocationWithoutPositionOffset());
-  EXPECT_EQ(PhysicalOffset(50, 50),
-            floating->GetLayoutObject().OffsetForInFlowPosition());
-  EXPECT_EQ(PhysicalOffset(0, 0), span->LocationWithoutPositionOffset());
-  EXPECT_EQ(PhysicalOffset(100, 100),
-            span->GetLayoutObject().OffsetForInFlowPosition());
-  EXPECT_EQ(PhysicalOffset(83, 83), floating->VisualOffsetFromAncestor(span));
-  EXPECT_EQ(PhysicalOffset(183, 183),
-            floating->VisualOffsetFromAncestor(
-                GetDocument().GetLayoutView()->Layer()));
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    EXPECT_EQ(PhysicalOffset(183, 183),
+              floating->LocationWithoutPositionOffset());
+    EXPECT_EQ(PhysicalOffset(0, 0),
+              floating->GetLayoutObject().OffsetForInFlowPosition());
+    EXPECT_EQ(PhysicalOffset(0, 0), span->LocationWithoutPositionOffset());
+    EXPECT_EQ(PhysicalOffset(0, 0),
+              span->GetLayoutObject().OffsetForInFlowPosition());
+    EXPECT_EQ(PhysicalOffset(183, 183),
+              floating->VisualOffsetFromAncestor(span));
+    EXPECT_EQ(PhysicalOffset(183, 183),
+              floating->VisualOffsetFromAncestor(
+                  GetDocument().GetLayoutView()->Layer()));
+  } else {
+    EXPECT_EQ(PhysicalOffset(33, 33),
+              floating->LocationWithoutPositionOffset());
+    EXPECT_EQ(PhysicalOffset(50, 50),
+              floating->GetLayoutObject().OffsetForInFlowPosition());
+    EXPECT_EQ(PhysicalOffset(0, 0), span->LocationWithoutPositionOffset());
+    EXPECT_EQ(PhysicalOffset(100, 100),
+              span->GetLayoutObject().OffsetForInFlowPosition());
+    EXPECT_EQ(PhysicalOffset(83, 83), floating->VisualOffsetFromAncestor(span));
+    EXPECT_EQ(PhysicalOffset(183, 183),
+              floating->VisualOffsetFromAncestor(
+                  GetDocument().GetLayoutView()->Layer()));
+  }
 }
 
 TEST_P(PaintLayerTest, FloatLayerUnderFloatUnderInlineLayer) {
@@ -1708,18 +1748,27 @@
     EXPECT_EQ(span->Parent(), floating->ContainingLayer());
   }
 
-  EXPECT_EQ(PhysicalOffset(33, 33), floating->LocationWithoutPositionOffset());
-  EXPECT_EQ(PhysicalOffset(50, 50),
-            floating->GetLayoutObject().OffsetForInFlowPosition());
-  EXPECT_EQ(PhysicalOffset(0, 0), span->LocationWithoutPositionOffset());
-  EXPECT_EQ(PhysicalOffset(100, 100),
-            span->GetLayoutObject().OffsetForInFlowPosition());
   if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
-    EXPECT_EQ(PhysicalOffset(83, 83), floating->VisualOffsetFromAncestor(span));
+    EXPECT_EQ(PhysicalOffset(0, 0), span->LocationWithoutPositionOffset());
+    EXPECT_EQ(PhysicalOffset(0, 0),
+              span->GetLayoutObject().OffsetForInFlowPosition());
+    EXPECT_EQ(PhysicalOffset(183, 183),
+              floating->LocationWithoutPositionOffset());
+    EXPECT_EQ(PhysicalOffset(0, 0),
+              floating->GetLayoutObject().OffsetForInFlowPosition());
+    EXPECT_EQ(PhysicalOffset(183, 183),
+              floating->VisualOffsetFromAncestor(span));
     EXPECT_EQ(PhysicalOffset(183, 183),
               floating->VisualOffsetFromAncestor(
                   GetDocument().GetLayoutView()->Layer()));
   } else {
+    EXPECT_EQ(PhysicalOffset(0, 0), span->LocationWithoutPositionOffset());
+    EXPECT_EQ(PhysicalOffset(100, 100),
+              span->GetLayoutObject().OffsetForInFlowPosition());
+    EXPECT_EQ(PhysicalOffset(33, 33),
+              floating->LocationWithoutPositionOffset());
+    EXPECT_EQ(PhysicalOffset(50, 50),
+              floating->GetLayoutObject().OffsetForInFlowPosition());
     EXPECT_EQ(PhysicalOffset(-17, -17),
               floating->VisualOffsetFromAncestor(span));
     EXPECT_EQ(PhysicalOffset(83, 83),
@@ -1754,22 +1803,36 @@
     EXPECT_EQ(span->Parent(), floating_parent->ContainingLayer());
   }
 
-  EXPECT_EQ(PhysicalOffset(0, 0), floating->LocationWithoutPositionOffset());
-  EXPECT_EQ(PhysicalOffset(50, 50),
-            floating->GetLayoutObject().OffsetForInFlowPosition());
-  EXPECT_EQ(PhysicalOffset(33, 33),
-            floating_parent->LocationWithoutPositionOffset());
-  EXPECT_EQ(PhysicalOffset(0, 0), span->LocationWithoutPositionOffset());
-  EXPECT_EQ(PhysicalOffset(100, 100),
-            span->GetLayoutObject().OffsetForInFlowPosition());
   if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
-    EXPECT_EQ(PhysicalOffset(83, 83), floating->VisualOffsetFromAncestor(span));
-    EXPECT_EQ(PhysicalOffset(33, 33),
+    EXPECT_EQ(PhysicalOffset(50, 50),
+              floating->LocationWithoutPositionOffset());
+    EXPECT_EQ(PhysicalOffset(0, 0),
+              floating->GetLayoutObject().OffsetForInFlowPosition());
+    EXPECT_EQ(PhysicalOffset(133, 133),
+              floating_parent->LocationWithoutPositionOffset());
+    EXPECT_EQ(PhysicalOffset(0, 0), span->LocationWithoutPositionOffset());
+    EXPECT_EQ(PhysicalOffset(0, 0),
+              span->GetLayoutObject().OffsetForInFlowPosition());
+    EXPECT_EQ(PhysicalOffset(0, 0),
+              span->GetLayoutObject().OffsetForInFlowPosition());
+    EXPECT_EQ(PhysicalOffset(183, 183),
+              floating->VisualOffsetFromAncestor(span));
+    EXPECT_EQ(PhysicalOffset(133, 133),
               floating_parent->VisualOffsetFromAncestor(span));
     EXPECT_EQ(PhysicalOffset(183, 183),
               floating->VisualOffsetFromAncestor(
                   GetDocument().GetLayoutView()->Layer()));
   } else {
+    EXPECT_EQ(PhysicalOffset(0, 0), floating->LocationWithoutPositionOffset());
+    EXPECT_EQ(PhysicalOffset(50, 50),
+              floating->GetLayoutObject().OffsetForInFlowPosition());
+    EXPECT_EQ(PhysicalOffset(33, 33),
+              floating_parent->LocationWithoutPositionOffset());
+    EXPECT_EQ(PhysicalOffset(0, 0), span->LocationWithoutPositionOffset());
+    EXPECT_EQ(PhysicalOffset(100, 100),
+              span->GetLayoutObject().OffsetForInFlowPosition());
+    EXPECT_EQ(PhysicalOffset(100, 100),
+              span->GetLayoutObject().OffsetForInFlowPosition());
     EXPECT_EQ(PhysicalOffset(-17, -17),
               floating->VisualOffsetFromAncestor(span));
     EXPECT_EQ(PhysicalOffset(-67, -67),
@@ -1803,19 +1866,24 @@
     EXPECT_EQ(span->Parent(), child->ContainingLayer());
   }
 
-  EXPECT_EQ(PhysicalOffset(33, 33), child->LocationWithoutPositionOffset());
-  EXPECT_EQ(PhysicalOffset(50, 50),
-            child->GetLayoutObject().OffsetForInFlowPosition());
   EXPECT_EQ(PhysicalOffset(0, 0), span->LocationWithoutPositionOffset());
-  EXPECT_EQ(PhysicalOffset(100, 100),
-            span->GetLayoutObject().OffsetForInFlowPosition());
   if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
-    EXPECT_EQ(PhysicalOffset(83, 83), child->VisualOffsetFromAncestor(span));
+    EXPECT_EQ(PhysicalOffset(183, 183), child->LocationWithoutPositionOffset());
+    EXPECT_EQ(PhysicalOffset(0, 0),
+              child->GetLayoutObject().OffsetForInFlowPosition());
+    EXPECT_EQ(PhysicalOffset(0, 0),
+              span->GetLayoutObject().OffsetForInFlowPosition());
+    EXPECT_EQ(PhysicalOffset(183, 183), child->VisualOffsetFromAncestor(span));
     EXPECT_EQ(PhysicalOffset(183, 183),
               child->VisualOffsetFromAncestor(
                   GetDocument().GetLayoutView()->Layer()));
 
   } else {
+    EXPECT_EQ(PhysicalOffset(33, 33), child->LocationWithoutPositionOffset());
+    EXPECT_EQ(PhysicalOffset(50, 50),
+              child->GetLayoutObject().OffsetForInFlowPosition());
+    EXPECT_EQ(PhysicalOffset(100, 100),
+              span->GetLayoutObject().OffsetForInFlowPosition());
     EXPECT_EQ(PhysicalOffset(-17, -17), child->VisualOffsetFromAncestor(span));
     EXPECT_EQ(PhysicalOffset(83, 83),
               child->VisualOffsetFromAncestor(
@@ -2940,4 +3008,43 @@
       target->EnclosingDirectlyCompositableLayerCrossingFrameBoundaries());
 }
 
+TEST_P(PaintLayerTest, GlobalRootScrollerHitTest) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      :root {
+        clip-path: circle(30%);
+        background:blue;
+        transform: rotate(30deg);
+        transform-style: preserve-3d;
+      }
+      #perspective {
+        perspective:100px;
+      }
+      #threedee {
+        transform: rotate3d(1, 1, 1, 45deg);
+        width:100px; height:200px;
+      }
+    </style>
+    <div id="perspective">
+      <div id="threedee"></div>
+    </div>
+  )HTML");
+  GetDocument().GetPage()->SetPageScaleFactor(2);
+  UpdateAllLifecyclePhasesForTest();
+
+  const HitTestRequest hit_request(HitTestRequest::kActive);
+  const HitTestLocation location(IntPoint(400, 300));
+  HitTestResult result;
+  GetLayoutView().HitTestNoLifecycleUpdate(location, result);
+  EXPECT_EQ(result.InnerNode(), GetDocument().documentElement());
+  EXPECT_EQ(result.GetScrollbar(), nullptr);
+
+  if (GetDocument().GetPage()->GetScrollbarTheme().AllowsHitTest()) {
+    const HitTestLocation location_scrollbar(IntPoint(790, 300));
+    HitTestResult result_scrollbar;
+    EXPECT_EQ(result_scrollbar.InnerNode(), &GetDocument());
+    EXPECT_NE(result_scrollbar.GetScrollbar(), nullptr);
+  }
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/scroll/scrollable_area.cc b/third_party/blink/renderer/core/scroll/scrollable_area.cc
index ee01f8b..c2a6757 100644
--- a/third_party/blink/renderer/core/scroll/scrollable_area.cc
+++ b/third_party/blink/renderer/core/scroll/scrollable_area.cc
@@ -972,6 +972,19 @@
   // We shouldn't be injecting scrolls for the visual viewport scrollbar, since
   // it is not hit-testable.
   DCHECK(GetLayoutBox());
+
+  if (granularity == ScrollGranularity::kScrollByPrecisePixel ||
+      granularity == ScrollGranularity::kScrollByPixel) {
+    // Pixel-based deltas need to be scaled up by the input event scale factor,
+    // since the GSUs will be scaled down by that factor when being handled.
+    float scale = 1;
+    LocalFrameView* root_view =
+        GetLayoutBox()->GetFrame()->LocalFrameRoot().View();
+    if (root_view)
+      scale = root_view->InputEventsScaleFactor();
+    delta.Scale(scale);
+  }
+
   GetChromeClient()->InjectGestureScrollEvent(
       *GetLayoutBox()->GetFrame(), device,
       gfx::Vector2dF(delta.Width(), delta.Height()), granularity,
diff --git a/third_party/blink/renderer/core/scroll/scrollable_area.h b/third_party/blink/renderer/core/scroll/scrollable_area.h
index f0eb978..861c487 100644
--- a/third_party/blink/renderer/core/scroll/scrollable_area.h
+++ b/third_party/blink/renderer/core/scroll/scrollable_area.h
@@ -292,6 +292,11 @@
     NOTREACHED();
     return point_in_root_frame;
   }
+  virtual IntPoint ConvertFromRootFrameToVisualViewport(
+      const IntPoint& point_in_root_frame) const {
+    NOTREACHED();
+    return point_in_root_frame;
+  }
 
   virtual Scrollbar* HorizontalScrollbar() const { return nullptr; }
   virtual Scrollbar* VerticalScrollbar() const { return nullptr; }
@@ -472,6 +477,10 @@
   virtual bool IsPaintLayerScrollableArea() const { return false; }
   virtual bool IsRootFrameViewport() const { return false; }
 
+  // Returns true if this is the layout viewport associated with the
+  // RootFrameViewport.
+  virtual bool IsRootFrameLayoutViewport() const { return false; }
+
   virtual bool VisualViewportSuppliesScrollbars() const { return false; }
 
   // Returns true if the scroller adjusts the scroll offset to compensate
diff --git a/third_party/blink/renderer/core/scroll/scrollbar.cc b/third_party/blink/renderer/core/scroll/scrollbar.cc
index ef2efa5..d0adbb3 100644
--- a/third_party/blink/renderer/core/scroll/scrollbar.cc
+++ b/third_party/blink/renderer/core/scroll/scrollbar.cc
@@ -737,8 +737,19 @@
 IntPoint Scrollbar::ConvertFromRootFrame(
     const IntPoint& point_in_root_frame) const {
   if (scrollable_area_) {
-    IntPoint parent_point =
-        scrollable_area_->ConvertFromRootFrame(point_in_root_frame);
+    IntPoint parent_point;
+    if (scrollable_area_->IsRootFrameLayoutViewport()) {
+      // When operating on the root frame viewport's scrollbar, use the visual
+      // viewport relative position, instead of root frame-relative position.
+      // This allows us to operate on the layout viewport's scrollbar when there
+      // is a page scale factor and visual viewport offsets, since the layout
+      // viewport scrollbars are not affected by these.
+      parent_point = scrollable_area_->ConvertFromRootFrameToVisualViewport(
+          point_in_root_frame);
+    } else {
+      parent_point =
+          scrollable_area_->ConvertFromRootFrame(point_in_root_frame);
+    }
     return scrollable_area_
         ->ConvertFromContainingEmbeddedContentViewToScrollbar(*this,
                                                               parent_point);
diff --git a/third_party/blink/renderer/core/style/computed_style.cc b/third_party/blink/renderer/core/style/computed_style.cc
index 85afd48d..1cb7f1c 100644
--- a/third_party/blink/renderer/core/style/computed_style.cc
+++ b/third_party/blink/renderer/core/style/computed_style.cc
@@ -299,9 +299,8 @@
   if (!non_inherited_equal && old_style.ChildHasExplicitInheritance()) {
     return Difference::kInherited;
   }
-  bool variables_independent = RuntimeEnabledFeatures::CSSCascadeEnabled() &&
-                               !old_style.HasVariableReference() &&
-                               !old_style.HasVariableDeclaration();
+  bool variables_independent =
+      !old_style.HasVariableReference() && !old_style.HasVariableDeclaration();
   bool inherited_variables_equal = old_style.InheritedVariablesEqual(new_style);
   if (!inherited_variables_equal && !variables_independent)
     return Difference::kInherited;
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 e1009c3f3..bdd2834 100644
--- a/third_party/blink/renderer/core/style/computed_style_test.cc
+++ b/third_party/blink/renderer/core/style/computed_style_test.cc
@@ -698,20 +698,12 @@
       std::make_unique<DummyPageHolder>(IntSize(0, 0), nullptr);
   const ComputedStyle* initial = &ComputedStyle::InitialStyle();
 
-  auto* ua_context = MakeGarbageCollected<CSSParserContext>(
-      kUASheetMode, SecureContextMode::kInsecureContext);
-  const CSSValue* internal_light_dark = CSSParser::ParseSingleValue(
-      CSSPropertyID::kColor, "-internal-light-dark(black, white)", ua_context);
-
   ColorSchemeHelper color_scheme_helper(dummy_page_holder_->GetDocument());
   color_scheme_helper.SetPreferredColorScheme(PreferredColorScheme::kDark);
   StyleResolverState state(dummy_page_holder_->GetDocument(),
                            *dummy_page_holder_->GetDocument().documentElement(),
                            initial, initial);
 
-  StyleResolver& resolver =
-      dummy_page_holder_->GetDocument().GetStyleResolver();
-
   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
   state.SetStyle(style);
 
@@ -721,51 +713,27 @@
   CSSValueList* light_value = CSSValueList::CreateSpaceSeparated();
   light_value->Append(*CSSIdentifierValue::Create(CSSValueID::kLight));
 
-  {
-    ScopedCSSCascadeForTest scoped_cascade_enabled(false);
+  auto* color_declaration = ParseDeclarationBlock(
+      "color:-internal-light-dark(black, white)", CSSParserMode::kUASheetMode);
+  auto* dark_declaration = ParseDeclarationBlock("color-scheme:dark");
+  auto* light_declaration = ParseDeclarationBlock("color-scheme:light");
 
-    To<Longhand>(GetCSSPropertyColor()).ApplyValue(state, *internal_light_dark);
-    To<Longhand>(GetCSSPropertyColorScheme()).ApplyValue(state, *dark_value);
-    resolver.ApplyCascadedColorValue(state);
-    EXPECT_EQ(Color::kWhite,
-              style->VisitedDependentColor(GetCSSPropertyColor()));
+  StyleCascade cascade1(state);
+  cascade1.MutableMatchResult().AddMatchedProperties(color_declaration);
+  cascade1.MutableMatchResult().AddMatchedProperties(dark_declaration);
+  cascade1.Apply();
+  EXPECT_EQ(Color::kWhite, style->VisitedDependentColor(GetCSSPropertyColor()));
 
-    To<Longhand>(GetCSSPropertyColor()).ApplyValue(state, *internal_light_dark);
-    To<Longhand>(GetCSSPropertyColorScheme()).ApplyValue(state, *light_value);
-    resolver.ApplyCascadedColorValue(state);
-    EXPECT_EQ(Color::kBlack,
-              style->VisitedDependentColor(GetCSSPropertyColor()));
-  }
-
-  {
-    ScopedCSSCascadeForTest scoped_cascade_enabled(true);
-
-    auto* color_declaration =
-        ParseDeclarationBlock("color:-internal-light-dark(black, white)",
-                              CSSParserMode::kUASheetMode);
-    auto* dark_declaration = ParseDeclarationBlock("color-scheme:dark");
-    auto* light_declaration = ParseDeclarationBlock("color-scheme:light");
-
-    StyleCascade cascade1(state);
-    cascade1.MutableMatchResult().AddMatchedProperties(color_declaration);
-    cascade1.MutableMatchResult().AddMatchedProperties(dark_declaration);
-    cascade1.Apply();
-    EXPECT_EQ(Color::kWhite,
-              style->VisitedDependentColor(GetCSSPropertyColor()));
-
-    StyleCascade cascade2(state);
-    cascade2.MutableMatchResult().AddMatchedProperties(color_declaration);
-    cascade2.MutableMatchResult().AddMatchedProperties(light_declaration);
-    cascade2.Apply();
-    EXPECT_EQ(Color::kBlack,
-              style->VisitedDependentColor(GetCSSPropertyColor()));
-  }
+  StyleCascade cascade2(state);
+  cascade2.MutableMatchResult().AddMatchedProperties(color_declaration);
+  cascade2.MutableMatchResult().AddMatchedProperties(light_declaration);
+  cascade2.Apply();
+  EXPECT_EQ(Color::kBlack, style->VisitedDependentColor(GetCSSPropertyColor()));
 }
 
 TEST(ComputedStyleTest, ApplyInternalLightDarkBackgroundImage) {
   using css_test_helpers::ParseDeclarationBlock;
 
-  ScopedCSSCascadeForTest scoped_cascade_enabled(true);
   ScopedCSSColorSchemeForTest scoped_property_enabled(true);
   ScopedCSSColorSchemeUARenderingForTest scoped_ua_enabled(true);
 
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util.cc b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util.cc
index 7cc4754..9a7248a 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util.cc
@@ -283,7 +283,7 @@
 }
 
 MediaStreamSource::Capabilities ComputeCapabilitiesForVideoSource(
-    const WebString& device_id,
+    const String& device_id,
     const media::VideoCaptureFormats& formats,
     media::VideoFacingMode facing_mode,
     bool is_device_capture,
@@ -293,7 +293,7 @@
   if (is_device_capture) {
     capabilities.facing_mode = ToPlatformFacingMode(facing_mode);
     if (group_id)
-      capabilities.group_id = WebString::FromUTF8(*group_id);
+      capabilities.group_id = String::FromUTF8(*group_id);
   }
   if (!formats.empty()) {
     int max_width = 1;
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util.h b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util.h
index e86759f..5ec959eb 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util.h
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util.h
@@ -15,6 +15,7 @@
 #include "third_party/blink/renderer/platform/mediastream/media_constraints.h"
 #include "third_party/blink/renderer/platform/mediastream/media_stream_audio_processor_options.h"
 #include "third_party/blink/renderer/platform/mediastream/media_stream_source.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
 
@@ -336,7 +337,7 @@
 // |formats|. |facing_mode| is valid only in case of video device capture.
 MODULES_EXPORT MediaStreamSource::Capabilities
 ComputeCapabilitiesForVideoSource(
-    const blink::WebString& device_id,
+    const String& device_id,
     const media::VideoCaptureFormats& formats,
     media::VideoFacingMode facing_mode,
     bool is_device_capture,
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_processor.cc b/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
index ea08baa..c4914103 100644
--- a/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
+++ b/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
@@ -1215,8 +1215,8 @@
     String device_id(device.id.data());
     source->SetCapabilities(ComputeCapabilitiesForVideoSource(
         // TODO(crbug.com/704136): Change ComputeCapabilitiesForVideoSource to
-        // operate over WTF::Vector and WTF::String.
-        blink::WebString::FromUTF8(device.id),
+        // operate over WTF::Vector.
+        String::FromUTF8(device.id),
         ToStdVector(*current_request_info_->GetNativeVideoFormats(device_id)),
         device.video_facing, current_request_info_->is_video_device_capture(),
         device.group_id));
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
index 6b8552b..6053ac60 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
@@ -2707,18 +2707,15 @@
   if (!native_transport.get()) {
     return nullptr;
   }
-  auto transport_locator =
-      dtls_transports_by_native_transport_.find(native_transport);
-  if (transport_locator != dtls_transports_by_native_transport_.end()) {
-    auto transport = transport_locator->value;
-    transport->ChangeState(information);
-    return transport;
+  auto& transport = dtls_transports_by_native_transport_
+                        .insert(native_transport.get(), nullptr)
+                        .stored_value->value;
+  if (!transport) {
+    RTCIceTransport* ice_transport =
+        CreateOrUpdateIceTransport(native_transport->ice_transport());
+    transport = MakeGarbageCollected<RTCDtlsTransport>(
+        GetExecutionContext(), std::move(native_transport), ice_transport);
   }
-  RTCDtlsTransport* transport = MakeGarbageCollected<RTCDtlsTransport>(
-      GetExecutionContext(), native_transport,
-      CreateOrUpdateIceTransport(native_transport->ice_transport()));
-  dtls_transports_by_native_transport_.insert(native_transport.get(),
-                                              transport);
   transport->ChangeState(information);
   return transport;
 }
@@ -2728,14 +2725,13 @@
   if (!ice_transport.get()) {
     return nullptr;
   }
-  auto transport_locator =
-      ice_transports_by_native_transport_.find(ice_transport);
-  if (transport_locator != ice_transports_by_native_transport_.end()) {
-    return transport_locator->value;
+  auto& transport =
+      ice_transports_by_native_transport_.insert(ice_transport, nullptr)
+          .stored_value->value;
+  if (!transport) {
+    transport = RTCIceTransport::Create(GetExecutionContext(),
+                                        std::move(ice_transport), this);
   }
-  RTCIceTransport* transport =
-      RTCIceTransport::Create(GetExecutionContext(), ice_transport, this);
-  ice_transports_by_native_transport_.insert(ice_transport.get(), transport);
   return transport;
 }
 
diff --git a/third_party/blink/renderer/modules/serial/serial_port.cc b/third_party/blink/renderer/modules/serial/serial_port.cc
index 8166b072..8e01d322 100644
--- a/third_party/blink/renderer/modules/serial/serial_port.cc
+++ b/third_party/blink/renderer/modules/serial/serial_port.cc
@@ -449,12 +449,27 @@
   closing_ = false;
 }
 
+void SerialPort::Flush(
+    device::mojom::blink::SerialPortFlushMode mode,
+    device::mojom::blink::SerialPort::FlushCallback callback) {
+  DCHECK(port_.is_bound());
+  port_->Flush(mode, std::move(callback));
+}
+
+void SerialPort::Drain(
+    device::mojom::blink::SerialPort::DrainCallback callback) {
+  DCHECK(port_.is_bound());
+  port_->Drain(std::move(callback));
+}
+
 void SerialPort::UnderlyingSourceClosed() {
+  DCHECK(readable_);
   readable_ = nullptr;
   underlying_source_ = nullptr;
 }
 
 void SerialPort::UnderlyingSinkClosed() {
+  DCHECK(writable_);
   writable_ = nullptr;
   underlying_sink_ = nullptr;
 }
diff --git a/third_party/blink/renderer/modules/serial/serial_port.h b/third_party/blink/renderer/modules/serial/serial_port.h
index d56e4b5..8ae0edea 100644
--- a/third_party/blink/renderer/modules/serial/serial_port.h
+++ b/third_party/blink/renderer/modules/serial/serial_port.h
@@ -59,11 +59,15 @@
 
   const base::UnguessableToken& token() const { return info_->token; }
 
-  void UnderlyingSourceClosed();
-  void UnderlyingSinkClosed();
   ScriptPromise ContinueClose(ScriptState*);
   void AbortClose();
 
+  void Flush(device::mojom::blink::SerialPortFlushMode mode,
+             device::mojom::blink::SerialPort::FlushCallback callback);
+  void Drain(device::mojom::blink::SerialPort::DrainCallback callback);
+  void UnderlyingSourceClosed();
+  void UnderlyingSinkClosed();
+
   void ContextDestroyed();
   void Trace(Visitor*) const override;
 
diff --git a/third_party/blink/renderer/modules/serial/serial_port_underlying_sink.cc b/third_party/blink/renderer/modules/serial/serial_port_underlying_sink.cc
index 4ac7043f..0e4f03e 100644
--- a/third_party/blink/renderer/modules/serial/serial_port_underlying_sink.cc
+++ b/third_party/blink/renderer/modules/serial/serial_port_underlying_sink.cc
@@ -38,7 +38,7 @@
   // There can only be one call to write() in progress at a time.
   DCHECK(buffer_source_.IsNull());
   DCHECK_EQ(0u, offset_);
-  DCHECK(!pending_write_);
+  DCHECK(!pending_operation_);
 
   if (pending_exception_) {
     DOMException* exception = pending_exception_;
@@ -54,8 +54,9 @@
   if (exception_state.HadException())
     return ScriptPromise();
 
-  pending_write_ = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
-  ScriptPromise promise = pending_write_->Promise();
+  pending_operation_ =
+      MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+  ScriptPromise promise = pending_operation_->Promise();
 
   WriteData();
   return promise;
@@ -65,22 +66,24 @@
                                               ExceptionState& exception_state) {
   // The specification guarantees that this will only be called after all
   // pending writes have been completed.
-  DCHECK(!pending_write_);
+  DCHECK(!pending_operation_);
 
   watcher_.Cancel();
   data_pipe_.reset();
-  serial_port_->UnderlyingSinkClosed();
 
   if (pending_exception_) {
     DOMException* exception = pending_exception_;
     pending_exception_ = nullptr;
     exception_state.RethrowV8Exception(ToV8(exception, script_state));
+    serial_port_->UnderlyingSinkClosed();
     return ScriptPromise();
   }
 
-  // TODO(crbug.com/989656): close() should wait for data to be flushed before
-  // resolving. This will require waiting for |data_pipe_| to close.
-  return ScriptPromise::CastUndefined(script_state);
+  pending_operation_ =
+      MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+  serial_port_->Drain(WTF::Bind(&SerialPortUnderlyingSink::OnFlushOrDrain,
+                                WrapPersistent(this)));
+  return pending_operation_->Promise();
 }
 
 ScriptPromise SerialPortUnderlyingSink::abort(ScriptState* script_state,
@@ -88,22 +91,38 @@
                                               ExceptionState& exception_state) {
   // The specification guarantees that this will only be called after all
   // pending writes have been completed.
-  // TODO(crbug.com/969653): abort() should trigger a purge of the serial write
-  // buffers.
-  return close(script_state, exception_state);
+  DCHECK(!pending_operation_);
+
+  watcher_.Cancel();
+  data_pipe_.reset();
+
+  if (pending_exception_) {
+    DOMException* exception = pending_exception_;
+    pending_exception_ = nullptr;
+    exception_state.RethrowV8Exception(ToV8(exception, script_state));
+    serial_port_->UnderlyingSinkClosed();
+    return ScriptPromise();
+  }
+
+  pending_operation_ =
+      MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+  serial_port_->Flush(device::mojom::blink::SerialPortFlushMode::kTransmit,
+                      WTF::Bind(&SerialPortUnderlyingSink::OnFlushOrDrain,
+                                WrapPersistent(this)));
+  return pending_operation_->Promise();
 }
 
 void SerialPortUnderlyingSink::SignalErrorOnClose(DOMException* exception) {
-  if (data_pipe_ || !pending_write_) {
+  if (data_pipe_ || !pending_operation_) {
     // Pipe is still open or we don't have a write operation that can be failed.
     // Wait for PipeClosed() to be called.
     pending_exception_ = exception;
     return;
   }
 
-  if (pending_write_) {
-    pending_write_->Reject(exception);
-    pending_write_ = nullptr;
+  if (pending_operation_) {
+    pending_operation_->Reject(exception);
+    pending_operation_ = nullptr;
     serial_port_->UnderlyingSinkClosed();
   }
 }
@@ -112,7 +131,7 @@
   visitor->Trace(serial_port_);
   visitor->Trace(pending_exception_);
   visitor->Trace(buffer_source_);
-  visitor->Trace(pending_write_);
+  visitor->Trace(pending_operation_);
   UnderlyingSinkBase::Trace(visitor);
 }
 
@@ -130,9 +149,25 @@
   }
 }
 
+void SerialPortUnderlyingSink::OnFlushOrDrain() {
+  ScriptPromiseResolver* resolver = pending_operation_;
+  pending_operation_ = nullptr;
+
+  DOMException* exception = pending_exception_;
+  pending_exception_ = nullptr;
+
+  serial_port_->UnderlyingSinkClosed();
+
+  if (exception) {
+    resolver->Reject(exception);
+  } else {
+    resolver->Resolve();
+  }
+}
+
 void SerialPortUnderlyingSink::WriteData() {
   DCHECK(data_pipe_);
-  DCHECK(pending_write_);
+  DCHECK(pending_operation_);
   DCHECK(!buffer_source_.IsNull());
 
   const uint8_t* data = nullptr;
@@ -167,8 +202,8 @@
       if (offset_ == length) {
         buffer_source_ = ArrayBufferOrArrayBufferView();
         offset_ = 0;
-        pending_write_->Resolve();
-        pending_write_ = nullptr;
+        pending_operation_->Resolve();
+        pending_operation_ = nullptr;
         break;
       }
       FALLTHROUGH;
@@ -184,7 +219,7 @@
 }
 
 void SerialPortUnderlyingSink::PipeClosed() {
-  DCHECK(pending_write_);
+  DCHECK(pending_operation_);
 
   watcher_.Cancel();
   data_pipe_.reset();
@@ -193,8 +228,8 @@
     DOMException* exception = pending_exception_;
     pending_exception_ = nullptr;
     serial_port_->UnderlyingSinkClosed();
-    pending_write_->Reject(exception);
-    pending_write_ = nullptr;
+    pending_operation_->Reject(exception);
+    pending_operation_ = nullptr;
   }
 }
 
diff --git a/third_party/blink/renderer/modules/serial/serial_port_underlying_sink.h b/third_party/blink/renderer/modules/serial/serial_port_underlying_sink.h
index b5ec5a3..ca45ab6 100644
--- a/third_party/blink/renderer/modules/serial/serial_port_underlying_sink.h
+++ b/third_party/blink/renderer/modules/serial/serial_port_underlying_sink.h
@@ -41,6 +41,7 @@
 
  private:
   void OnHandleReady(MojoResult, const mojo::HandleSignalsState&);
+  void OnFlushOrDrain();
   void WriteData();
   void PipeClosed();
 
@@ -51,7 +52,11 @@
 
   ArrayBufferOrArrayBufferView buffer_source_;
   uint32_t offset_ = 0;
-  Member<ScriptPromiseResolver> pending_write_;
+
+  // Only one outstanding call to write(), close() or abort() is allowed at a
+  // time. This holds the ScriptPromiseResolver for the Promise returned by any
+  // of these functions.
+  Member<ScriptPromiseResolver> pending_operation_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/serial/serial_port_underlying_source.cc b/third_party/blink/renderer/modules/serial/serial_port_underlying_source.cc
index c36181b..a4961ad 100644
--- a/third_party/blink/renderer/modules/serial/serial_port_underlying_source.cc
+++ b/third_party/blink/renderer/modules/serial/serial_port_underlying_source.cc
@@ -4,10 +4,12 @@
 
 #include "third_party/blink/renderer/modules/serial/serial_port_underlying_source.h"
 
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/streams/readable_stream_default_controller_with_script_scope.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
 #include "third_party/blink/renderer/modules/serial/serial_port.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
 
 namespace blink {
 
@@ -41,12 +43,16 @@
 
 ScriptPromise SerialPortUnderlyingSource::Cancel(ScriptState* script_state,
                                                  ScriptValue reason) {
-  // TODO(crbug.com/989653): Rather than calling Close(), cancel() should
-  // trigger a purge of the serial read buffer and wait for the pipe to close to
-  // indicate the purge has been completed.
+  DCHECK(data_pipe_);
+
   Close();
-  ExpectPipeClose();
-  return ScriptPromise::CastUndefined(script_state);
+
+  auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+  serial_port_->Flush(
+      device::mojom::blink::SerialPortFlushMode::kReceive,
+      WTF::Bind(&SerialPortUnderlyingSource::OnFlush, WrapPersistent(this),
+                WrapPersistent(resolver)));
+  return resolver->Promise();
 }
 
 void SerialPortUnderlyingSource::ContextDestroyed() {
@@ -136,6 +142,11 @@
   }
 }
 
+void SerialPortUnderlyingSource::OnFlush(ScriptPromiseResolver* resolver) {
+  serial_port_->UnderlyingSourceClosed();
+  resolver->Resolve();
+}
+
 void SerialPortUnderlyingSource::ExpectPipeClose() {
   if (data_pipe_) {
     // The pipe is still open. Wait for PipeClosed() to be called.
diff --git a/third_party/blink/renderer/modules/serial/serial_port_underlying_source.h b/third_party/blink/renderer/modules/serial/serial_port_underlying_source.h
index 4d7d8b9..88e02cc 100644
--- a/third_party/blink/renderer/modules/serial/serial_port_underlying_source.h
+++ b/third_party/blink/renderer/modules/serial/serial_port_underlying_source.h
@@ -12,6 +12,7 @@
 namespace blink {
 
 class DOMException;
+class ScriptPromiseResolver;
 class SerialPort;
 
 class SerialPortUnderlyingSource : public UnderlyingSourceBase {
@@ -37,6 +38,7 @@
 
   void ArmWatcher();
   void OnHandleReady(MojoResult, const mojo::HandleSignalsState&);
+  void OnFlush(ScriptPromiseResolver*);
   void ExpectPipeClose();
   void PipeClosed();
   void Close();
diff --git a/third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.cc b/third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.cc
index 5366dab..6720d463 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.cc
@@ -49,4 +49,16 @@
                                    array.GetAsLongSequence().size());
 }
 
+// static
+base::span<const uint32_t> WebGLMultiDrawCommon::MakeSpan(
+    const Uint32ArrayOrUnsignedLongSequence& array) {
+  if (array.IsUint32Array()) {
+    return base::span<const uint32_t>(
+        array.GetAsUint32Array().View()->Data(),
+        array.GetAsUint32Array().View()->lengthAsSizeT());
+  }
+  return base::span<const uint32_t>(array.GetAsUnsignedLongSequence().data(),
+                                    array.GetAsUnsignedLongSequence().size());
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.h b/third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.h
index d9c3a843..fad98f3 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.h
@@ -7,6 +7,7 @@
 
 #include "base/containers/span.h"
 #include "third_party/blink/renderer/bindings/modules/v8/int32_array_or_long_sequence.h"
+#include "third_party/blink/renderer/bindings/modules/v8/uint32_array_or_unsigned_long_sequence.h"
 #include "third_party/blink/renderer/modules/webgl/webgl_extension.h"
 
 namespace blink {
@@ -27,6 +28,9 @@
 
   static base::span<const int32_t> MakeSpan(
       const Int32ArrayOrLongSequence& array);
+
+  static base::span<const uint32_t> MakeSpan(
+      const Uint32ArrayOrUnsignedLongSequence& array);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced_base_vertex_base_instance.cc b/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced_base_vertex_base_instance.cc
index 9bdd5fe..94f2dd1 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced_base_vertex_base_instance.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced_base_vertex_base_instance.cc
@@ -61,7 +61,7 @@
         GLuint counts_offset,
         const base::span<const int32_t> instance_counts,
         GLuint instance_counts_offset,
-        const base::span<const int32_t> baseinstances,
+        const base::span<const uint32_t> baseinstances,
         GLuint baseinstances_offset,
         GLsizei drawcount) {
   WebGLExtensionScopedContext scoped(this);
@@ -87,8 +87,7 @@
   scoped.Context()->ContextGL()->MultiDrawArraysInstancedBaseInstanceWEBGL(
       mode, &firsts[firsts_offset], &counts[counts_offset],
       &instance_counts[instance_counts_offset],
-      reinterpret_cast<const GLuint*>(&baseinstances[baseinstances_offset]),
-      drawcount);
+      &baseinstances[baseinstances_offset], drawcount);
 }
 
 void WebGLMultiDrawInstancedBaseVertexBaseInstance::
@@ -103,7 +102,7 @@
         GLuint instance_counts_offset,
         const base::span<const int32_t> basevertices,
         GLuint basevertices_offset,
-        const base::span<const int32_t> baseinstances,
+        const base::span<const uint32_t> baseinstances,
         GLuint baseinstances_offset,
         GLsizei drawcount) {
   WebGLExtensionScopedContext scoped(this);
@@ -140,8 +139,7 @@
           mode, &counts[counts_offset], type, &offsets[offsets_offset],
           &instance_counts[instance_counts_offset],
           &basevertices[basevertices_offset],
-          reinterpret_cast<const GLuint*>(&baseinstances[baseinstances_offset]),
-          drawcount);
+          &baseinstances[baseinstances_offset], drawcount);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced_base_vertex_base_instance.h b/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced_base_vertex_base_instance.h
index c8032122..ba852de3 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced_base_vertex_base_instance.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced_base_vertex_base_instance.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL_MULTI_DRAW_INSTANCED_BASE_VERTEX_BASE_INSTANCE_H_
 
 #include "third_party/blink/renderer/bindings/modules/v8/int32_array_or_long_sequence.h"
+#include "third_party/blink/renderer/bindings/modules/v8/uint32_array_or_unsigned_long_sequence.h"
 #include "third_party/blink/renderer/modules/webgl/webgl_extension.h"
 #include "third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
@@ -32,7 +33,7 @@
       GLuint counts_offset,
       Int32ArrayOrLongSequence instance_counts_list,
       GLuint instance_counts_offset,
-      Int32ArrayOrLongSequence baseinstances_list,
+      Uint32ArrayOrUnsignedLongSequence baseinstances_list,
       GLuint baseinstances_offset,
       GLsizei drawcount) {
     multiDrawArraysInstancedBaseInstanceImpl(
@@ -52,7 +53,7 @@
       GLuint instance_counts_offset,
       Int32ArrayOrLongSequence basevertices_list,
       GLuint basevertices_offset,
-      Int32ArrayOrLongSequence baseinstances_list,
+      Uint32ArrayOrUnsignedLongSequence baseinstances_list,
       GLuint baseinstances_offset,
       GLsizei drawcount) {
     multiDrawElementsInstancedBaseVertexBaseInstanceImpl(
@@ -72,7 +73,7 @@
       GLuint counts_offset,
       const base::span<const int32_t> instance_counts,
       GLuint instance_counts_offset,
-      const base::span<const int32_t> baseinstances,
+      const base::span<const uint32_t> baseinstances,
       GLuint baseinstances_offset,
       GLsizei drawcount);
 
@@ -87,7 +88,7 @@
       GLuint instance_counts_offset,
       const base::span<const int32_t> basevertices,
       GLuint basevertices_offset,
-      const base::span<const int32_t> baseinstances,
+      const base::span<const uint32_t> baseinstances,
       GLuint baseinstances_offset,
       GLsizei drawcount);
 };
diff --git a/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced_base_vertex_base_instance.idl b/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced_base_vertex_base_instance.idl
index f630fd8..c29508a 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced_base_vertex_base_instance.idl
+++ b/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced_base_vertex_base_instance.idl
@@ -14,7 +14,7 @@
       GLuint countsOffset,
       (Int32Array or sequence<long>) instanceCountsList,
       GLuint instanceCountsOffset,
-      (Int32Array or sequence<long>) baseInstancesList,
+      (Uint32Array or sequence<unsigned long>) baseInstancesList,
       GLuint baseInstancesOffset,
       GLsizei drawcount);
 
@@ -29,7 +29,7 @@
       GLuint instanceCountsOffset,
       (Int32Array or sequence<long>) baseVerticesList,
       GLuint baseVerticesOffset,
-      (Int32Array or sequence<long>) baseInstancesList,
+      (Uint32Array or sequence<unsigned long>) baseInstancesList,
       GLuint baseInstancesOffset,
       GLsizei drawcount);
 };
diff --git a/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc b/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc
index 8cf8f75..d851c3ad 100644
--- a/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc
+++ b/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc
@@ -12,6 +12,7 @@
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "gpu/command_buffer/client/raster_interface.h"
 #include "gpu/command_buffer/client/shared_image_interface.h"
+#include "gpu/command_buffer/common/capabilities.h"
 #include "gpu/command_buffer/common/sync_token.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/web_graphics_context_3d_provider.h"
@@ -281,6 +282,20 @@
 
   gpu::raster::RasterInterface* shared_ri =
       context_provider_wrapper->ContextProvider()->RasterInterface();
+
+  if (context_provider_wrapper->ContextProvider()
+          ->GetCapabilities()
+          .supports_oop_raster) {
+    DCHECK_EQ(shared_image_texture_id, 0u);
+    shared_ri->WaitSyncTokenCHROMIUM(
+        mailbox_ref_->GetOrCreateSyncToken(context_provider_wrapper)
+            .GetConstData());
+    skia_context_provider_wrapper_ = context_provider_wrapper;
+    texture_backing_ = sk_make_sp<MailboxTextureBacking>(
+        mailbox_, sk_image_info_, std::move(context_provider_wrapper));
+    return;
+  }
+
   GrContext* shared_gr_context =
       context_provider_wrapper->ContextProvider()->GetGrContext();
   DCHECK(shared_ri &&
@@ -327,8 +342,8 @@
 
   if (sk_image) {
     skia_context_provider_wrapper_ = std::move(context_provider_wrapper);
-    texture_backing_ = sk_sp<MailboxTextureBacking>(
-        new MailboxTextureBacking(std::move(sk_image), sk_image_info_));
+    texture_backing_ =
+        sk_make_sp<MailboxTextureBacking>(std::move(sk_image), sk_image_info_);
   }
 }
 
diff --git a/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h b/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h
index 6dee737..2bd02e8 100644
--- a/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h
+++ b/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h
@@ -175,7 +175,7 @@
   base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper_;
   scoped_refptr<MailboxRef> mailbox_ref_;
 
-  // The context this SkImage is bound to.
+  // The context this TextureBacking is bound to.
   base::WeakPtr<WebGraphicsContext3DProviderWrapper>
       skia_context_provider_wrapper_;
   sk_sp<MailboxTextureBacking> texture_backing_;
diff --git a/third_party/blink/renderer/platform/graphics/mailbox_texture_backing.cc b/third_party/blink/renderer/platform/graphics/mailbox_texture_backing.cc
index f141901..5a3d48e 100644
--- a/third_party/blink/renderer/platform/graphics/mailbox_texture_backing.cc
+++ b/third_party/blink/renderer/platform/graphics/mailbox_texture_backing.cc
@@ -4,12 +4,23 @@
 
 #include "third_party/blink/renderer/platform/graphics/mailbox_texture_backing.h"
 
+#include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
+#include "third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_wrapper.h"
+
 namespace blink {
 
 MailboxTextureBacking::MailboxTextureBacking(sk_sp<SkImage> sk_image,
                                              const SkImageInfo& info)
     : sk_image_(std::move(sk_image)), sk_image_info_(info) {}
 
+MailboxTextureBacking::MailboxTextureBacking(
+    const gpu::Mailbox& mailbox,
+    const SkImageInfo& info,
+    base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper)
+    : mailbox_(mailbox),
+      sk_image_info_(info),
+      context_provider_wrapper_(std::move(context_provider_wrapper)) {}
+
 const SkImageInfo& MailboxTextureBacking::GetSkImageInfo() {
   return sk_image_info_;
 }
@@ -22,4 +33,23 @@
   return sk_image_;
 }
 
+sk_sp<SkImage> MailboxTextureBacking::GetSkImageViaReadback() {
+  if (!context_provider_wrapper_)
+    return nullptr;
+  // TODO(jochin): Consider doing some caching and using discardable memory.
+  sk_sp<SkData> image_pixels =
+      TryAllocateSkData(sk_image_info_.computeMinByteSize());
+  if (!image_pixels)
+    return nullptr;
+  uint8_t* writable_pixels =
+      static_cast<uint8_t*>(image_pixels->writable_data());
+  gpu::raster::RasterInterface* ri =
+      context_provider_wrapper_->ContextProvider()->RasterInterface();
+  ri->ReadbackImagePixels(mailbox_, sk_image_info_,
+                          sk_image_info_.minRowBytes(), 0, 0, writable_pixels);
+
+  return SkImage::MakeRasterData(sk_image_info_, std::move(image_pixels),
+                                 sk_image_info_.minRowBytes());
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/mailbox_texture_backing.h b/third_party/blink/renderer/platform/graphics/mailbox_texture_backing.h
index 8fc1c3b..f7a58369 100644
--- a/third_party/blink/renderer/platform/graphics/mailbox_texture_backing.h
+++ b/third_party/blink/renderer/platform/graphics/mailbox_texture_backing.h
@@ -7,22 +7,32 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_MAILBOX_TEXTURE_BACKING_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_MAILBOX_TEXTURE_BACKING_H_
 
+#include "base/memory/weak_ptr.h"
+#include "gpu/command_buffer/client/raster_interface.h"
 #include "gpu/command_buffer/common/mailbox.h"
 
 namespace blink {
+class WebGraphicsContext3DProviderWrapper;
 
 class MailboxTextureBacking : public TextureBacking {
  public:
   explicit MailboxTextureBacking(sk_sp<SkImage> sk_image,
                                  const SkImageInfo& info);
+  explicit MailboxTextureBacking(
+      const gpu::Mailbox& mailbox,
+      const SkImageInfo& info,
+      base::WeakPtr<WebGraphicsContext3DProviderWrapper>
+          context_provider_wrapper);
   const SkImageInfo& GetSkImageInfo() override;
   gpu::Mailbox GetMailbox() const override;
   sk_sp<SkImage> GetAcceleratedSkImage() override;
+  sk_sp<SkImage> GetSkImageViaReadback() override;
 
  private:
   const sk_sp<SkImage> sk_image_;
-  const SkImageInfo sk_image_info_;
   const gpu::Mailbox mailbox_;
+  const SkImageInfo sk_image_info_;
+  base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index c4dccfb..1861060c 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -393,10 +393,6 @@
       status: "test",
     },
     {
-      name: "CSSCascade",
-      status: "stable",
-    },
-    {
       // Support for the CSS color-scheme property from the css-color-adjust spec.
       // https://drafts.csswg.org/css-color-adjust/#color-scheme-prop
       name: "CSSColorScheme",
@@ -472,7 +468,6 @@
     // Enables dependency support for the MatchedPropertiesCache.
     {
       name: "CSSMatchedPropertiesCacheDependencies",
-      depends_on: ["CSSCascade"]
     },
     {
       name: "CSSMathStyle",
@@ -542,7 +537,6 @@
     {
       name: "CSSRevert",
       status: "stable",
-      depends_on: ["CSSCascade"],
     },
     // Support for declarative parts of scroll-animations-1, i.e.
     // the animation-timeline property and the @scroll-timeline rule.
diff --git a/third_party/blink/web_tests/FlagExpectations/composite-after-paint b/third_party/blink/web_tests/FlagExpectations/composite-after-paint
index 542c1dd3..64202b2 100644
--- a/third_party/blink/web_tests/FlagExpectations/composite-after-paint
+++ b/third_party/blink/web_tests/FlagExpectations/composite-after-paint
@@ -64,3 +64,7 @@
 
 compositing/gestures/gesture-tapHighlight-composited-img.html [ Pass Failure ]
 http/tests/images/image-decode-in-frame.html [ Pass Failure ]
+
+# CompositeAfterPaint positions and scales root scrollbars incorrectly when
+# a page scale factor is applied.
+crbug.com/1106550 virtual/threaded-prefer-compositing/fast/scrolling/scrollbars/mouse-scrolling-on-div-scrollbar-thumb-scaled.html [ Failure ]
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
index 9400811..b64b385e 100644
--- a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
+++ b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
@@ -68,6 +68,9 @@
 crbug.com/591099 external/wpt/css/css-position/position-absolute-center-004.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-position/position-absolute-crash-chrome-006.html [ Crash ]
 crbug.com/591099 external/wpt/css/css-position/position-absolute-dynamic-overflow-002.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-position/position-relative-001.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-position/position-relative-002.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-position/position-relative-004.html [ Failure ]
 
 ### external/wpt/css/css-position/static-position/
 crbug.com/591099 external/wpt/css/css-position/static-position/htb-ltr-rtl.tentative.html [ Failure ]
@@ -601,9 +604,7 @@
 crbug.com/1035582 external/wpt/css/css-text-decor/text-decoration-subelements-001.html [ Failure ]
 crbug.com/1035582 paint/background/background-clip-text-descendants.html [ Failure ]
 crbug.com/1035582 tables/mozilla/bugs/bug2479-3.html [ Failure ]
-crbug.com/1035582 virtual/cascade/fast/forms/datetimelocal/datetimelocal-appearance-basic.html [ Failure ]
 crbug.com/1035582 virtual/composite-after-paint/paint/background/background-clip-text-descendants.html [ Failure ]
-crbug.com/1035582 virtual/forced-high-contrast-cascade/external/wpt/forced-colors-mode/forced-colors-mode-14.html [ Failure ]
 crbug.com/1035582 virtual/scalefactor200withzoom/fast/hidpi/static/popup-menu-appearance.html [ Failure ]
 crbug.com/1035582 fast/hidpi/scrollbar-appearance-increase-device-scale-factor.html [ Failure ]
 crbug.com/1035582 paint/invalidation/overflow/float-overflow-right.html [ Failure ]
diff --git a/third_party/blink/web_tests/NeverFixTests b/third_party/blink/web_tests/NeverFixTests
index 2218a0a0..c1def0d 100644
--- a/third_party/blink/web_tests/NeverFixTests
+++ b/third_party/blink/web_tests/NeverFixTests
@@ -68,7 +68,6 @@
 [ Mac ] fast/forms/select/menulist-onchange-fired-with-key-up-down.html [ Skip ]
 [ Mac ] fast/forms/select/popup-with-display-none-optgroup.html [ Skip ]
 [ Mac ] fast/forms/select-popup/* [ Skip ]
-[ Mac ] virtual/cascade/fast/forms/select-popup/* [ Skip ]
 
 # These tests are specific to Windows and Linux.
 [ Mac ] fast/forms/calendar-picker/date-open-picker-with-f4-key.html [ Skip ]
@@ -151,6 +150,11 @@
 external/wpt/feature-policy/experimental-features/vertical-scroll-touch-block-manual.tentative.html [ Skip ]
 [ Linux ] virtual/threaded/external/wpt/feature-policy/experimental-features/vertical-scroll-touch-block-manual.tentative.html [ Pass ]
 
+# This test requires a compositor to pass as root scrollbar scrolling is always
+# done on the compositor thread.
+fast/scrolling/scrollbars/mouse-scrolling-on-div-scrollbar-thumb-scaled.html [ Skip ]
+virtual/threaded-prefer-compositing/fast/scrolling/scrollbars/mouse-scrolling-on-div-scrollbar-thumb-scaled.html [ Pass ]
+
 # Only run fake-Android tests on Linux
 [ Mac ] virtual/android/* [ Skip ]
 [ Win ] virtual/android/* [ Skip ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index b412d47a..8ba26a2 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2689,6 +2689,18 @@
 crbug.com/1105958 external/wpt/payment-request/payment-is-showing.https.html [ Timeout ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 [ Mac10.10 ] virtual/omt-worker-fetch/external/wpt/service-workers/cache-storage/serviceworker/cache-abort.https.html [ Failure Timeout ]
+crbug.com/626703 [ Mac10.10 ] virtual/cors/external/wpt/service-workers/cache-storage/serviceworker/cache-abort.https.html [ Timeout ]
+crbug.com/626703 [ Mac10.10 ] virtual/cache-storage-sequence/external/wpt/service-workers/cache-storage/serviceworker/cache-abort.https.html [ Failure Timeout ]
+crbug.com/626703 [ Mac10.10 ] virtual/cors/external/wpt/service-workers/cache-storage/window/cache-abort.https.html [ Failure Timeout ]
+crbug.com/626703 [ Mac10.10 ] virtual/cache-storage-sequence/external/wpt/service-workers/cache-storage/window/cache-abort.https.html [ Failure Timeout ]
+crbug.com/626703 [ Mac10.10 ] virtual/omt-worker-fetch/external/wpt/service-workers/cache-storage/window/cache-abort.https.html [ Failure Timeout ]
+crbug.com/626703 [ Mac10.10 ] virtual/cors/external/wpt/service-workers/cache-storage/worker/cache-abort.https.html [ Failure Timeout ]
+crbug.com/626703 [ Mac10.10 ] external/wpt/service-workers/cache-storage/serviceworker/cache-abort.https.html [ Failure Timeout ]
+crbug.com/626703 [ Mac10.10 ] virtual/cache-storage-eager-reading/external/wpt/service-workers/cache-storage/window/cache-abort.https.html [ Failure Timeout ]
+crbug.com/626703 [ Mac10.10 ] virtual/cache-storage-sequence/external/wpt/service-workers/cache-storage/worker/cache-abort.https.html [ Failure Timeout ]
+crbug.com/626703 [ Mac10.10 ] external/wpt/service-workers/cache-storage/window/cache-abort.https.html [ Failure Timeout ]
+crbug.com/626703 [ Mac10.10 ] virtual/omt-worker-fetch/external/wpt/service-workers/cache-storage/worker/cache-abort.https.html [ Failure Timeout ]
 crbug.com/626703 [ Mac10.10 ] virtual/cache-storage-eager-reading/external/wpt/service-workers/cache-storage/serviceworker/cache-abort.https.html [ Failure Timeout ]
 crbug.com/626703 [ Mac10.11 ] virtual/cache-storage-eager-reading/external/wpt/service-workers/cache-storage/serviceworker/cache-abort.https.html [ Failure Timeout ]
 crbug.com/626703 [ Mac10.12 ] virtual/cache-storage-eager-reading/external/wpt/service-workers/cache-storage/serviceworker/cache-abort.https.html [ Failure Timeout ]
@@ -3043,7 +3055,6 @@
 crbug.com/626703 [ Mac10.10 ] virtual/web-components-v0-disabled/external/wpt/html/dom/idlharness.https.html?include=HTML.\* [ Failure Timeout ]
 crbug.com/626703 [ Win7 ] external/wpt/content-security-policy/object-src/object-src-no-url-allowed.html [ Timeout ]
 crbug.com/626703 [ Win7 ] external/wpt/content-security-policy/plugin-types/plugintypes-nourl-allowed.html [ Timeout ]
-crbug.com/626703 [ Mac10.11 ] virtual/cascade/external/wpt/css/css-paint-api/parse-input-arguments-018.https.html [ Failure ]
 crbug.com/626703 [ Linux ] external/wpt/service-workers/service-worker/ready.https.window.html [ Timeout ]
 crbug.com/626703 [ Mac ] external/wpt/service-workers/service-worker/ready.https.window.html [ Timeout ]
 crbug.com/626703 [ Win ] external/wpt/service-workers/service-worker/ready.https.window.html [ Timeout ]
@@ -6059,16 +6070,9 @@
 # Expected failures for forced colors mode tests when the corresponding flags
 # are not enabled.
 crbug.com/970285 external/wpt/forced-colors-mode/* [ Failure ]
-[ Linux ] virtual/forced-high-contrast-cascade/* [ Pass ]
-[ Win ] virtual/forced-high-contrast-cascade/* [ Pass ]
-[ Fuchsia ] virtual/forced-high-contrast-cascade/* [ Pass ]
-[ Linux ] virtual/forced-high-contrast-colors/* [ Pass ]
-[ Win ] virtual/forced-high-contrast-colors/* [ Pass ]
-[ Fuchsia ] virtual/forced-high-contrast-colors/* [ Pass ]
 
 # Virtual forced colors mode tests should fail on macOS since macOS high
 # contrast does not imply forced colors mode.
-crbug.com/970285 [ Mac ] virtual/forced-high-contrast-cascade/* [ Failure ]
 crbug.com/970285 [ Mac ] virtual/forced-high-contrast-colors/* [ Failure ]
 
 # Expected failures for dark mode tests when the corresponding flags
@@ -6489,7 +6493,6 @@
 
 # Sheriff 2020-01-28
 crbug.com/1046201 [ Mac ] fast/forms/calendar-picker/calendar-picker-appearance-zoom125.html [ Pass Failure ]
-crbug.com/1046201 [ Win10 ] virtual/cascade/fast/forms/calendar-picker/calendar-picker-appearance-zoom125.html [ Pass Failure ]
 crbug.com/1046440 fast/loader/submit-form-while-parsing-2.html [ Pass Failure Timeout ]
 
 # Sheriff 2020-01-29
@@ -6854,7 +6857,6 @@
 crbug.com/1011811 http/tests/devtools/persistence/automapping-sourcemap.js [ Pass Failure ]
 
 # Sheriff 2020-06-03
-crbug.com/1090822 [ Mac10.10 ] virtual/cascade/fast/forms/month/month-appearance-basic.html [ Pass Failure ]
 crbug.com/1083293 [ Linux ] media/video-aspect-ratio.html [ Pass Failure ]
 
 # Sheriff 2020-06-04
@@ -7007,3 +7009,15 @@
 crbug.com/1094436 http/tests/devtools/persistence/automapping-urlencoded-paths.js [ Pass Failure ]
 crbug.com/1094436 http/tests/devtools/sources/debugger-ui/snippet-edit-breakpoint.js [ Pass Timeout ]
 crbug.com/1094436 http/tests/devtools/sources/debugger/navigator-view.js [ Pass Failure Crash ]
+
+# Sheriff 2020-07-17
+crbug.com/1106861 virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker.html [ Skip ]
+crbug.com/1106861 virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.html [ Skip ]
+crbug.com/1106861 virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.serviceworker.html [ Skip ]
+crbug.com/1106861 external/wpt/fetch/api/abort/general.any.worker.html [ Skip ]
+crbug.com/1106861 virtual/cors/external/wpt/fetch/api/abort/general.any.sharedworker.html [ Skip ]
+crbug.com/1106861 virtual/cors/external/wpt/fetch/api/abort/general.any.worker.html [ Skip ]
+crbug.com/1106861 virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.worker.html [ Skip ]
+crbug.com/1106861 external/wpt/fetch/api/abort/general.any.html [ Skip ]
+crbug.com/1106861 virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.sharedworker.html [ Skip ]
+crbug.com/1106861 external/wpt/fetch/api/abort/general.any.sharedworker.html [ Skip ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index 1886bd02..0137f9b9 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -589,63 +589,6 @@
     "args": ["--enable-blink-features=MeasureMemory,ForceEagerMeasureMemory"]
   },
   {
-    "prefix": "cascade",
-    "bases": ["animations/custom-properties",
-              "animations/interpolation",
-              "external/wpt/css/css-cascade",
-              "external/wpt/css/css-paint-api",
-              "external/wpt/css/css-properties-values-api",
-              "external/wpt/css/css-scoping",
-              "external/wpt/css/css-typed-om",
-              "external/wpt/css/css-variables",
-              "fast/css/variables",
-              "fast/forms/select/select-autofilled.html",
-              "fast/forms/001.html",
-              "fast/forms/button-style-color.html",
-              "fast/forms/calendar-picker/calendar-picker-appearance-zoom125.html",
-              "fast/forms/color/color-suggestion-picker-appearance.html",
-              "fast/forms/date/date-appearance-basic.html",
-              "fast/forms/datetimelocal/datetimelocal-appearance-basic.html",
-              "fast/forms/fieldset/fieldset-align.html",
-              "fast/forms/month/month-appearance-basic.html",
-              "fast/forms/select/basic-selects.html",
-              "fast/forms/select-popup/popup-menu-appearance-zoom090.html",
-              "fast/forms/select-popup/popup-menu-appearance-zoom110.html",
-              "fast/forms/submit/submit-appearance-basic.html",
-              "fast/forms/text/text-appearance-basic.html",
-              "fast/forms/textarea/textarea-appearance-basic.html",
-              "external/wpt/css/css-writing-modes/block-flow-direction-vlr-022.xht",
-              "external/wpt/css/css-writing-modes/block-flow-direction-vrl-021.xht",
-              "external/wpt/css/css-logical/cascading-001.html",
-              "external/wpt/css/css-logical/inheritance.html",
-              "external/wpt/css/css-logical/logical-box-border-color.html",
-              "external/wpt/css/css-logical/logical-box-border-shorthands.html",
-              "external/wpt/css/css-logical/logical-box-border-style.html",
-              "external/wpt/css/css-logical/logical-box-border-width.html",
-              "external/wpt/css/css-logical/logical-box-inset.html",
-              "external/wpt/css/css-logical/logical-box-margin.html",
-              "external/wpt/css/css-logical/logical-box-padding.html",
-              "external/wpt/css/css-logical/logical-box-size.html",
-              "external/wpt/css/css-logical/logicalprops-block-size-vlr.html",
-              "external/wpt/css/css-logical/logicalprops-block-size.html",
-              "external/wpt/css/css-logical/logicalprops-inline-size-vlr.html",
-              "external/wpt/css/css-logical/logicalprops-inline-size.html",
-              "fast/borders/border-image-outset-in-shorthand.html",
-              "fast/borders/border-image-repeat-round.html",
-              "fast/borders/border-image-repeat.html",
-              "fast/borders/border-image-slices.html",
-              "fast/borders/border-image-source.html",
-              "fast/backgrounds/mask-composite.html",
-              "fast/css/acid2.html"],
-    "args": ["--enable-blink-features=CSSCascade"]
-  },
-  {
-    "prefix": "forced-high-contrast-cascade",
-    "bases": ["external/wpt/forced-colors-mode"],
-    "args": ["--force-high-contrast",
-             "--enable-blink-features=CSSCascade,ForcedColors"]
-  },
-  {
     "prefix": "payment-request-mandatory-total",
     "bases": ["http/tests/payments/payment-request-app-store-billing-mandatory-total.html"],
     "args": ["--disable-blink-features=PaymentRequestTotalOptional"]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index e2d8a5c0..7385b826b 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -199979,10 +199979,18 @@
     ],
     "api": {
      "abort": {
+      "general.any-expected.txt": [
+       "47a8c8daf950e2e32cc2474cc9870f6e1a93513c",
+       []
+      ],
       "general.any.serviceworker-expected.txt": [
        "5392aa4db3549a33abfded207bc95b7699cee200",
        []
       ],
+      "general.any.sharedworker-expected.txt": [
+       "47a8c8daf950e2e32cc2474cc9870f6e1a93513c",
+       []
+      ],
       "keepalive-expected.txt": [
        "af3cbab5e8e828a79d36ec52ce773cd1e0da39d6",
        []
@@ -200267,7 +200275,7 @@
       ],
       "resources": {
        "cache.py": [
-        "10122f6439615c840e33d52314bdc14bfb443420",
+        "ca0bd644b4f798c4fa64d1041b628a3740bc0bac",
         []
        ],
        "hello.txt": [
@@ -200282,7 +200290,7 @@
      },
      "resources": {
       "authentication.py": [
-       "b65047d765703b8e4400396a306b026316fc6d09",
+       "8b6b00b0873b38e57e579f3d7f2651fb97917b81",
        []
       ],
       "bad-chunk-encoding.py": [
@@ -200294,11 +200302,11 @@
        []
       ],
       "cache.py": [
-       "899638716a100a66c06cebbf92c31de7c705498b",
+       "4de751e30bfc6a5f6a8b02cd3ed47aa666d193e6",
        []
       ],
       "clean-stash.py": [
-       "3ae731052692e048a07d65a6e015fe5a76362098",
+       "ee8c69ac446ea979f63c0f82afd3061610b4b523",
        []
       ],
       "cors-top.txt": [
@@ -200326,7 +200334,7 @@
        []
       ],
       "inspect-headers.py": [
-       "10a12eb883a17c701d909cde650799f21ec898c1",
+       "9ed566e607b0e07d70ac6a183c0a9a025bcade5f",
        []
       ],
       "keepalive-iframe.html": [
@@ -200334,11 +200342,11 @@
        []
       ],
       "method.py": [
-       "795ad1ff11d085d82cb010b969753b94cbe06b53",
+       "c1a111b4cdf98dc6d8db702b0cc20d43825779bd",
        []
       ],
       "preflight.py": [
-       "a2552c2565ad9be6d17dea1cb6a90ff9eb211190",
+       "f983ef952272a75a6706d3cdfabb08aced7efc7b",
        []
       ],
       "redirect-empty-location.py": [
@@ -200378,7 +200386,7 @@
        []
       ],
       "trickle.py": [
-       "9b3aa37b25c9c99fe1fc6a988cd79ea6c793c287",
+       "5091a2b3fddce7e9a44cf6ef94e922f79d913693",
        []
       ],
       "utils.js": [
@@ -200432,7 +200440,7 @@
     "content-encoding": {
      "resources": {
       "bad-gzip-body.py": [
-       "b2f8cfefd7e491260648e33adfe9fbd3f8f72fe6",
+       "a79b94ed041d0e0852e71bdd5cdba57897a1f198",
        []
       ]
      }
@@ -200893,7 +200901,7 @@
     },
     "redirect-navigate": {
      "302-found-post-handler.py": [
-      "23bf4b2c522b7c00ab6bd0fc3eb99f0737d512ec",
+      "40a224f6565bae3e2c4b32f77e2bf4fd5d5451ee",
       []
      ],
      "resources": {
@@ -216176,7 +216184,7 @@
      []
     ],
     "appmanifest.idl": [
-     "0d24849b9f7657aed65b8d1dd147cf7001e26599",
+     "926a4fc2022e71c28aa4a2ae3d1adc12104ee1ab",
      []
     ],
     "audio-output.idl": [
@@ -216652,7 +216660,7 @@
      []
     ],
     "service-workers.idl": [
-     "c01fcab7f2d92491899907bc3c0505e8a4d4ba63",
+     "3d5e63a81204baa3099a2415be3a73d369aa31e3",
      []
     ],
     "shape-detection-api.idl": [
@@ -224190,7 +224198,7 @@
      }
     },
     "idlharness.https.any.serviceworker-expected.txt": [
-     "a568348cfd3a3e40a3e9354811cd1ccda4c193cf",
+     "0fe200903d7854203e69fc5eca393afd9f718998",
      []
     ],
     "idlharness.https.any.sharedworker-expected.txt": [
@@ -237748,7 +237756,7 @@
      []
     ],
     "RTCPeerConnection-helper.js": [
-     "07626bd0ccc39e93034beaf1f745bbc49a9438c1",
+     "cf31d2f0008c95ac1566f3c7e21fbeda0992d7e3",
      []
     ],
     "RTCPeerConnection-iceGatheringState-expected.txt": [
@@ -401409,7 +401417,7 @@
      ]
     ],
     "RTCPeerConnection-setRemoteDescription-offer.html": [
-     "b4702446613255daec7db5325f64089a917fdee9",
+     "a50e969637294aec8eeafe682da5d258e2a90de5",
      [
       null,
       {}
@@ -401793,7 +401801,7 @@
       ]
      ],
      "candidate-exchange.https.html": [
-      "532bc4d0d13d72170f9e521cbeda7d2e656e317f",
+      "82178953b6bbe3faccfd949817cf59e8d1dfa1ab",
       [
        null,
        {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/contain-flexbox-outline.html b/third_party/blink/web_tests/external/wpt/css/css-contain/contain-flexbox-outline.html
new file mode 100644
index 0000000..39cf816
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/contain-flexbox-outline.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<title>Test `contain: strict` to Flexbox does not crash</title>
+<link rel="help" href="https://www.w3.org/TR/css-contain-1/#contain-property">
+<link rel="author" href="mailto:kojii@chromium.org">
+<style>
+body {
+  contain: strict;
+  display: flex;
+}
+html {
+  outline: 1px auto;
+}
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="target"></div>
+<div id="log"></div>
+<script>
+test(() => {
+  document.body.offsetTop;
+  target.style.width = '100px';
+  document.body.offsetTop;
+}, "Pass if no crash");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-position/position-relative-001.html b/third_party/blink/web_tests/external/wpt/css/css-position/position-relative-001.html
new file mode 100644
index 0000000..7ec9e4f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-position/position-relative-001.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<link rel="help" href="https://crbug.com/1058690">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="A percent inset resolves against the available size.">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="width: 100px; height: 100px; background: red;">
+  <span style="position: relative; top: 100%; left: 100%;">
+    <div style="width: 100px; height: 100px; background: green; position: relative; top: -100px; left: -100px;"></div>
+  </span>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-position/position-relative-002.html b/third_party/blink/web_tests/external/wpt/css/css-position/position-relative-002.html
new file mode 100644
index 0000000..7e176be
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-position/position-relative-002.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<link rel="help" href="https://crbug.com/1058690">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="A percent inset resolves against the available size.">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="width: 100px; height: 100px; background: red;">
+  <span style="position: relative; top: 100px; left: 100px;">
+    <div style="width: 100px; height: 100px; background: green; position: relative; top: -100%; left: -100%;"></div>
+  </span>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-position/position-relative-003.html b/third_party/blink/web_tests/external/wpt/css/css-position/position-relative-003.html
new file mode 100644
index 0000000..7a0040c4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-position/position-relative-003.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<link rel="help" href="https://crbug.com/1058690">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="A percent inset resolves against the available size.">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="width: 100px; height: 100px; background: red;">
+  <span style="position: relative; top: 100%; left: 100%;">
+    <span style="position: relative; top: -100px; left: -100px;">
+      <div style="width: 100px; height: 100px; background: green; position: fixed;"></div>
+    </span>
+  </span>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-position/position-relative-004.html b/third_party/blink/web_tests/external/wpt/css/css-position/position-relative-004.html
new file mode 100644
index 0000000..aac4520f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-position/position-relative-004.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<link rel="help" href="https://crbug.com/1058690">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="A percent inset resolves against the available size when it dynamically changes.">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="target" style="contain: paint; width: 100px; background: red; line-height: 0;">
+  <span style="position: relative; top: -100%;">
+    <span style="position: relative; top: 100px;">
+      <div style="position: fixed; width: 100px; height: 100px; background: green;"></div>
+    </span>
+  </span>
+</div>
+<script>
+document.body.offsetTop;
+document.getElementById('target').style.height = '100px';
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-position/position-relative-005.html b/third_party/blink/web_tests/external/wpt/css/css-position/position-relative-005.html
new file mode 100644
index 0000000..f1ad084
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-position/position-relative-005.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<link rel="help" href="https://crbug.com/1058690">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="A percent inset resolves against the available size when it dynamically changes.">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="target" style="width: 100px; background: red; line-height: 0;">
+  <span style="position: relative; top: -100%;">
+    <span style="position: relative; top: 100px;">
+      <div style="position: absolute; width: 100px; height: 100px; background: green;"></div>
+    </span>
+  </span>
+</div>
+<script>
+document.body.offsetTop;
+document.getElementById('target').style.height = '100px';
+</script>
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/fetch/api/abort/general.any-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/abort/general.any-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/platform/win/external/wpt/fetch/api/abort/general.any-expected.txt
rename to third_party/blink/web_tests/external/wpt/fetch/api/abort/general.any-expected.txt
diff --git a/third_party/blink/web_tests/virtual/cors/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/virtual/cors/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
rename to third_party/blink/web_tests/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/resources/cache.py b/third_party/blink/web_tests/external/wpt/fetch/api/request/resources/cache.py
index 10122f64..ca0bd644 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/request/resources/cache.py
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/resources/cache.py
@@ -1,24 +1,26 @@
+from wptserve.utils import isomorphic_decode
+
 def main(request, response):
-    token = request.GET.first("token", None)
-    if "querystate" in request.GET:
+    token = request.GET.first(b"token", None)
+    if b"querystate" in request.GET:
         from json import JSONEncoder
-        response.headers.set("Content-Type", "text/plain")
+        response.headers.set(b"Content-Type", b"text/plain")
         return JSONEncoder().encode(request.server.stash.take(token))
-    content = request.GET.first("content", None)
-    tag = request.GET.first("tag", None)
-    date = request.GET.first("date", None)
-    expires = request.GET.first("expires", None)
-    vary = request.GET.first("vary", None)
-    cc = request.GET.first("cache_control", None)
-    redirect = request.GET.first("redirect", None)
-    inm = request.headers.get("If-None-Match", None)
-    ims = request.headers.get("If-Modified-Since", None)
-    pragma = request.headers.get("Pragma", None)
-    cache_control = request.headers.get("Cache-Control", None)
-    ignore = "ignore" in request.GET
+    content = request.GET.first(b"content", None)
+    tag = request.GET.first(b"tag", None)
+    date = request.GET.first(b"date", None)
+    expires = request.GET.first(b"expires", None)
+    vary = request.GET.first(b"vary", None)
+    cc = request.GET.first(b"cache_control", None)
+    redirect = request.GET.first(b"redirect", None)
+    inm = request.headers.get(b"If-None-Match", None)
+    ims = request.headers.get(b"If-Modified-Since", None)
+    pragma = request.headers.get(b"Pragma", None)
+    cache_control = request.headers.get(b"Cache-Control", None)
+    ignore = b"ignore" in request.GET
 
     if tag:
-        tag = '"%s"' % tag
+        tag = b'"%s"' % tag
 
     server_state = request.server.stash.take(token)
     if not server_state:
@@ -26,40 +28,40 @@
     state = dict()
     if not ignore:
         if inm:
-            state["If-None-Match"] = inm
+            state[u"If-None-Match"] = isomorphic_decode(inm)
         if ims:
-            state["If-Modified-Since"] = ims
+            state[u"If-Modified-Since"] = isomorphic_decode(ims)
         if pragma:
-            state["Pragma"] = pragma
+            state[u"Pragma"] = isomorphic_decode(pragma)
         if cache_control:
-            state["Cache-Control"] = cache_control
+            state[u"Cache-Control"] = isomorphic_decode(cache_control)
     server_state.append(state)
     request.server.stash.put(token, server_state)
 
     if tag:
-        response.headers.set("ETag", '%s' % tag)
+        response.headers.set(b"ETag", b'%s' % tag)
     elif date:
-        response.headers.set("Last-Modified", date)
+        response.headers.set(b"Last-Modified", date)
     if expires:
-        response.headers.set("Expires", expires)
+        response.headers.set(b"Expires", expires)
     if vary:
-        response.headers.set("Vary", vary)
+        response.headers.set(b"Vary", vary)
     if cc:
-        response.headers.set("Cache-Control", cc)
+        response.headers.set(b"Cache-Control", cc)
 
     # The only-if-cached redirect tests wants CORS to be okay, the other tests
     # are all same-origin anyways and don't care.
-    response.headers.set("Access-Control-Allow-Origin", "*")
+    response.headers.set(b"Access-Control-Allow-Origin", b"*")
 
     if redirect:
-        response.headers.set("Location", redirect)
-        response.status = (302, "Redirect")
-        return ""
+        response.headers.set(b"Location", redirect)
+        response.status = (302, b"Redirect")
+        return b""
     elif ((inm is not None and inm == tag) or
           (ims is not None and ims == date)):
-        response.status = (304, "Not Modified")
-        return ""
+        response.status = (304, b"Not Modified")
+        return b""
     else:
-        response.status = (200, "OK")
-        response.headers.set("Content-Type", "text/plain")
+        response.status = (200, b"OK")
+        response.headers.set(b"Content-Type", b"text/plain")
         return content
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/resources/authentication.py b/third_party/blink/web_tests/external/wpt/fetch/api/resources/authentication.py
index b65047d..8b6b00b 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/resources/authentication.py
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/resources/authentication.py
@@ -2,13 +2,13 @@
     user = request.auth.username
     password = request.auth.password
 
-    if user == "user" and password == "password":
-        return "Authentication done"
+    if user == b"user" and password == b"password":
+        return b"Authentication done"
 
-    realm = "test"
-    if "realm" in request.GET:
-        realm = request.GET.first("realm")
+    realm = b"test"
+    if b"realm" in request.GET:
+        realm = request.GET.first(b"realm")
 
-    return ((401, "Unauthorized"),
-            [("WWW-Authenticate", 'Basic realm="' + realm + '"')],
-            "Please login with credentials 'user' and 'password'")
+    return ((401, b"Unauthorized"),
+            [(b"WWW-Authenticate", b'Basic realm="' + realm + b'"')],
+            b"Please login with credentials 'user' and 'password'")
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/resources/cache.py b/third_party/blink/web_tests/external/wpt/fetch/api/resources/cache.py
index 89963871..4de751e 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/resources/cache.py
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/resources/cache.py
@@ -1,18 +1,18 @@
-ETAG = '"123abc"'
-CONTENT_TYPE = "text/plain"
-CONTENT = "lorem ipsum dolor sit amet"
+ETAG = b'"123abc"'
+CONTENT_TYPE = b"text/plain"
+CONTENT = b"lorem ipsum dolor sit amet"
 
 
 def main(request, response):
     # let caching kick in if possible (conditional GET)
-    etag = request.headers.get("If-None-Match", None)
+    etag = request.headers.get(b"If-None-Match", None)
     if etag == ETAG:
-        response.headers.set("X-HTTP-STATUS", 304)
-        response.status = (304, "Not Modified")
-        return ""
+        response.headers.set(b"X-HTTP-STATUS", 304)
+        response.status = (304, b"Not Modified")
+        return b""
 
     # cache miss, so respond with the actual content
-    response.status = (200, "OK")
-    response.headers.set("ETag", ETAG)
-    response.headers.set("Content-Type", CONTENT_TYPE)
+    response.status = (200, b"OK")
+    response.headers.set(b"ETag", ETAG)
+    response.headers.set(b"Content-Type", CONTENT_TYPE)
     return CONTENT
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/resources/clean-stash.py b/third_party/blink/web_tests/external/wpt/fetch/api/resources/clean-stash.py
index 3ae7310..ee8c69a 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/resources/clean-stash.py
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/resources/clean-stash.py
@@ -1,6 +1,6 @@
 def main(request, response):
-    token = request.GET.first("token")
+    token = request.GET.first(b"token")
     if request.server.stash.take(token) is not None:
-        return "1"
+        return b"1"
     else:
-        return "0"
+        return b"0"
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/resources/inspect-headers.py b/third_party/blink/web_tests/external/wpt/fetch/api/resources/inspect-headers.py
index 10a12eb..9ed566e 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/resources/inspect-headers.py
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/resources/inspect-headers.py
@@ -1,24 +1,24 @@
 def main(request, response):
     headers = []
-    if "headers" in request.GET:
-        checked_headers = request.GET.first("headers").split("|")
+    if b"headers" in request.GET:
+        checked_headers = request.GET.first(b"headers").split(b"|")
         for header in checked_headers:
             if header in request.headers:
-                headers.append(("x-request-" + header, request.headers.get(header, "")))
+                headers.append((b"x-request-" + header, request.headers.get(header, b"")))
 
-    if "cors" in request.GET:
-        if "Origin" in request.headers:
-            headers.append(("Access-Control-Allow-Origin", request.headers.get("Origin", "")))
+    if b"cors" in request.GET:
+        if b"Origin" in request.headers:
+            headers.append((b"Access-Control-Allow-Origin", request.headers.get(b"Origin", b"")))
         else:
-            headers.append(("Access-Control-Allow-Origin", "*"))
-        headers.append(("Access-Control-Allow-Credentials", "true"))
-        headers.append(("Access-Control-Allow-Methods", "GET, POST, HEAD"))
-        exposed_headers = ["x-request-" + header for header in checked_headers]
-        headers.append(("Access-Control-Expose-Headers", ", ".join(exposed_headers)))
-        if "allow_headers" in request.GET:
-            headers.append(("Access-Control-Allow-Headers", request.GET['allow_headers']))
+            headers.append((b"Access-Control-Allow-Origin", b"*"))
+        headers.append((b"Access-Control-Allow-Credentials", b"true"))
+        headers.append((b"Access-Control-Allow-Methods", b"GET, POST, HEAD"))
+        exposed_headers = [b"x-request-" + header for header in checked_headers]
+        headers.append((b"Access-Control-Expose-Headers", b", ".join(exposed_headers)))
+        if b"allow_headers" in request.GET:
+            headers.append((b"Access-Control-Allow-Headers", request.GET[b'allow_headers']))
         else:
-            headers.append(("Access-Control-Allow-Headers", ", ".join(request.headers)))
+            headers.append((b"Access-Control-Allow-Headers", b", ".join(request.headers)))
 
-    headers.append(("content-type", "text/plain"))
-    return headers, ""
+    headers.append((b"content-type", b"text/plain"))
+    return headers, b""
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/resources/method.py b/third_party/blink/web_tests/external/wpt/fetch/api/resources/method.py
index 795ad1ff..c1a111b4 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/resources/method.py
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/resources/method.py
@@ -1,16 +1,18 @@
+from wptserve.utils import isomorphic_encode
+
 def main(request, response):
     headers = []
-    if "cors" in request.GET:
-        headers.append(("Access-Control-Allow-Origin", "*"))
-        headers.append(("Access-Control-Allow-Credentials", "true"))
-        headers.append(("Access-Control-Allow-Methods", "GET, POST, PUT, FOO"))
-        headers.append(("Access-Control-Allow-Headers", "x-test, x-foo"))
-        headers.append(("Access-Control-Expose-Headers", "x-request-method"))
+    if b"cors" in request.GET:
+        headers.append((b"Access-Control-Allow-Origin", b"*"))
+        headers.append((b"Access-Control-Allow-Credentials", b"true"))
+        headers.append((b"Access-Control-Allow-Methods", b"GET, POST, PUT, FOO"))
+        headers.append((b"Access-Control-Allow-Headers", b"x-test, x-foo"))
+        headers.append((b"Access-Control-Expose-Headers", b"x-request-method"))
 
-    headers.append(("x-request-method", request.method))
-    headers.append(("x-request-content-type", request.headers.get("Content-Type", "NO")))
-    headers.append(("x-request-content-length", request.headers.get("Content-Length", "NO")))
-    headers.append(("x-request-content-encoding", request.headers.get("Content-Encoding", "NO")))
-    headers.append(("x-request-content-language", request.headers.get("Content-Language", "NO")))
-    headers.append(("x-request-content-location", request.headers.get("Content-Location", "NO")))
+    headers.append((b"x-request-method", isomorphic_encode(request.method)))
+    headers.append((b"x-request-content-type", request.headers.get(b"Content-Type", b"NO")))
+    headers.append((b"x-request-content-length", request.headers.get(b"Content-Length", b"NO")))
+    headers.append((b"x-request-content-encoding", request.headers.get(b"Content-Encoding", b"NO")))
+    headers.append((b"x-request-content-language", request.headers.get(b"Content-Language", b"NO")))
+    headers.append((b"x-request-content-location", request.headers.get(b"Content-Location", b"NO")))
     return headers, request.body
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/resources/preflight.py b/third_party/blink/web_tests/external/wpt/fetch/api/resources/preflight.py
index a2552c2..f983ef9 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/resources/preflight.py
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/resources/preflight.py
@@ -1,58 +1,58 @@
 def main(request, response):
-    headers = [("Content-Type", "text/plain")]
-    stashed_data = {'control_request_headers': "", 'preflight': "0", 'preflight_referrer': ""}
+    headers = [(b"Content-Type", b"text/plain")]
+    stashed_data = {b'control_request_headers': b"", b'preflight': b"0", b'preflight_referrer': b""}
 
     token = None
-    if "token" in request.GET:
-        token = request.GET.first("token")
+    if b"token" in request.GET:
+        token = request.GET.first(b"token")
 
-    if "origin" in request.GET:
-        for origin in request.GET['origin'].split(", "):
-            headers.append(("Access-Control-Allow-Origin", origin))
+    if b"origin" in request.GET:
+        for origin in request.GET[b'origin'].split(b", "):
+            headers.append((b"Access-Control-Allow-Origin", origin))
     else:
-        headers.append(("Access-Control-Allow-Origin", "*"))
+        headers.append((b"Access-Control-Allow-Origin", b"*"))
 
-    if "clear-stash" in request.GET:
+    if b"clear-stash" in request.GET:
         if request.server.stash.take(token) is not None:
-            return headers, "1"
+            return headers, b"1"
         else:
-            return headers, "0"
+            return headers, b"0"
 
-    if "credentials" in request.GET:
-        headers.append(("Access-Control-Allow-Credentials", "true"))
+    if b"credentials" in request.GET:
+        headers.append((b"Access-Control-Allow-Credentials", b"true"))
 
-    if request.method == "OPTIONS":
-        if not "Access-Control-Request-Method" in request.headers:
-            response.set_error(400, "No Access-Control-Request-Method header")
-            return "ERROR: No access-control-request-method in preflight!"
+    if request.method == u"OPTIONS":
+        if not b"Access-Control-Request-Method" in request.headers:
+            response.set_error(400, u"No Access-Control-Request-Method header")
+            return b"ERROR: No access-control-request-method in preflight!"
 
-        if request.headers.get("Accept", "") != "*/*":
-            response.set_error(400, "Request does not have 'Accept: */*' header")
-            return "ERROR: Invalid access in preflight!"
+        if request.headers.get(b"Accept", b"") != b"*/*":
+            response.set_error(400, u"Request does not have 'Accept: */*' header")
+            return b"ERROR: Invalid access in preflight!"
 
-        if "control_request_headers" in request.GET:
-            stashed_data['control_request_headers'] = request.headers.get("Access-Control-Request-Headers", None)
+        if b"control_request_headers" in request.GET:
+            stashed_data[b'control_request_headers'] = request.headers.get(b"Access-Control-Request-Headers", None)
 
-        if "max_age" in request.GET:
-            headers.append(("Access-Control-Max-Age", request.GET['max_age']))
+        if b"max_age" in request.GET:
+            headers.append((b"Access-Control-Max-Age", request.GET[b'max_age']))
 
-        if "allow_headers" in request.GET:
-            headers.append(("Access-Control-Allow-Headers", request.GET['allow_headers']))
+        if b"allow_headers" in request.GET:
+            headers.append((b"Access-Control-Allow-Headers", request.GET[b'allow_headers']))
 
-        if "allow_methods" in request.GET:
-            headers.append(("Access-Control-Allow-Methods", request.GET['allow_methods']))
+        if b"allow_methods" in request.GET:
+            headers.append((b"Access-Control-Allow-Methods", request.GET[b'allow_methods']))
 
         preflight_status = 200
-        if "preflight_status" in request.GET:
-            preflight_status = int(request.GET.first("preflight_status"))
+        if b"preflight_status" in request.GET:
+            preflight_status = int(request.GET.first(b"preflight_status"))
 
-        stashed_data['preflight'] = "1"
-        stashed_data['preflight_referrer'] = request.headers.get("Referer", "")
-        stashed_data['preflight_user_agent'] = request.headers.get("User-Agent", "")
+        stashed_data[b'preflight'] = b"1"
+        stashed_data[b'preflight_referrer'] = request.headers.get(b"Referer", b"")
+        stashed_data[b'preflight_user_agent'] = request.headers.get(b"User-Agent", b"")
         if token:
             request.server.stash.put(token, stashed_data)
 
-        return preflight_status, headers, ""
+        return preflight_status, headers, b""
 
 
     if token:
@@ -60,19 +60,19 @@
         if data:
             stashed_data = data
 
-    if "checkUserAgentHeaderInPreflight" in request.GET and request.headers.get("User-Agent") != stashed_data['preflight_user_agent']:
-        return 400, headers, "ERROR: No user-agent header in preflight"
+    if b"checkUserAgentHeaderInPreflight" in request.GET and request.headers.get(b"User-Agent") != stashed_data[b'preflight_user_agent']:
+        return 400, headers, b"ERROR: No user-agent header in preflight"
 
     #use x-* headers for returning value to bodyless responses
-    headers.append(("Access-Control-Expose-Headers", "x-did-preflight, x-control-request-headers, x-referrer, x-preflight-referrer, x-origin"))
-    headers.append(("x-did-preflight", stashed_data['preflight']))
-    if stashed_data['control_request_headers'] != None:
-        headers.append(("x-control-request-headers", stashed_data['control_request_headers']))
-    headers.append(("x-preflight-referrer", stashed_data['preflight_referrer']))
-    headers.append(("x-referrer", request.headers.get("Referer", "")))
-    headers.append(("x-origin", request.headers.get("Origin", "")))
+    headers.append((b"Access-Control-Expose-Headers", b"x-did-preflight, x-control-request-headers, x-referrer, x-preflight-referrer, x-origin"))
+    headers.append((b"x-did-preflight", stashed_data[b'preflight']))
+    if stashed_data[b'control_request_headers'] != None:
+        headers.append((b"x-control-request-headers", stashed_data[b'control_request_headers']))
+    headers.append((b"x-preflight-referrer", stashed_data[b'preflight_referrer']))
+    headers.append((b"x-referrer", request.headers.get(b"Referer", b"")))
+    headers.append((b"x-origin", request.headers.get(b"Origin", b"")))
 
     if token:
         request.server.stash.put(token, stashed_data)
 
-    return headers, ""
+    return headers, b""
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/resources/trickle.py b/third_party/blink/web_tests/external/wpt/fetch/api/resources/trickle.py
index 9b3aa37..5091a2b 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/resources/trickle.py
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/resources/trickle.py
@@ -12,5 +12,5 @@
     response.write_status_headers()
     time.sleep(delay)
     for i in xrange(count):
-        response.writer.write_content(u"TEST_TRICKLE\n")
+        response.writer.write_content(b"TEST_TRICKLE\n")
         time.sleep(delay)
diff --git a/third_party/blink/web_tests/external/wpt/fetch/content-encoding/resources/bad-gzip-body.py b/third_party/blink/web_tests/external/wpt/fetch/content-encoding/resources/bad-gzip-body.py
index b2f8cfe..a79b94e 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/content-encoding/resources/bad-gzip-body.py
+++ b/third_party/blink/web_tests/external/wpt/fetch/content-encoding/resources/bad-gzip-body.py
@@ -1,3 +1,3 @@
 def main(request, response):
-    headers = [("Content-Encoding", "gzip")]
-    return headers, "not actually gzip"
+    headers = [(b"Content-Encoding", b"gzip")]
+    return headers, b"not actually gzip"
diff --git a/third_party/blink/web_tests/external/wpt/fetch/redirect-navigate/302-found-post-handler.py b/third_party/blink/web_tests/external/wpt/fetch/redirect-navigate/302-found-post-handler.py
index 23bf4b2..40a224f 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/redirect-navigate/302-found-post-handler.py
+++ b/third_party/blink/web_tests/external/wpt/fetch/redirect-navigate/302-found-post-handler.py
@@ -1,13 +1,15 @@
+from wptserve.utils import isomorphic_encode
+
 def main(request, response):
-    if request.method == "POST":
+    if request.method == u"POST":
         response.add_required_headers = False
         response.writer.write_status(302)
-        response.writer.write_header("Location", request.url)
+        response.writer.write_header(b"Location", isomorphic_encode(request.url))
         response.writer.end_headers()
-        response.writer.write("")
-    elif request.method == "GET":
-        return ([("Content-Type", "text/plain")],
-                "OK")
+        response.writer.write(b"")
+    elif request.method == u"GET":
+        return ([(b"Content-Type", b"text/plain")],
+                b"OK")
     else:
-        return ([("Content-Type", "text/plain")],
-                "FAIL")
\ No newline at end of file
+        return ([(b"Content-Type", b"text/plain")],
+                b"FAIL")
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/appmanifest.idl b/third_party/blink/web_tests/external/wpt/interfaces/appmanifest.idl
index 0d24849b9..926a4fc2 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/appmanifest.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/appmanifest.idl
@@ -8,7 +8,11 @@
    DOMString lang;
    USVString name;
    USVString short_name;
+   USVString description;
    sequence<ManifestImageResource> icons;
+   sequence<ManifestImageResource> screenshots;
+   sequence<USVString> categories;
+   DOMString iarc_rating_id;
    USVString start_url;
    DisplayModeType display = "browser";
    OrientationLockType orientation;
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/service-workers.idl b/third_party/blink/web_tests/external/wpt/interfaces/service-workers.idl
index c01fcab7..3d5e63a 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/service-workers.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/service-workers.idl
@@ -173,6 +173,7 @@
   readonly attribute DOMString clientId;
   readonly attribute DOMString resultingClientId;
   readonly attribute DOMString replacesClientId;
+  readonly attribute Promise<void> handled;
 
   void respondWith(Promise<Response> r);
 };
@@ -183,6 +184,7 @@
   DOMString clientId = "";
   DOMString resultingClientId = "";
   DOMString replacesClientId = "";
+  Promise<void> handled;
 };
 
 [Exposed=ServiceWorker]
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/idlharness.https.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/service-workers/idlharness.https.any.serviceworker-expected.txt
index a568348c..0fe2009 100644
--- a/third_party/blink/web_tests/external/wpt/service-workers/idlharness.https.any.serviceworker-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/service-workers/idlharness.https.any.serviceworker-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 294 tests; 252 PASS, 42 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 296 tests; 252 PASS, 44 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS idl_test setup
 PASS idl_test validation
 PASS Partial interface Navigator: original interface defined
@@ -216,6 +216,7 @@
 PASS FetchEvent interface: attribute clientId
 PASS FetchEvent interface: attribute resultingClientId
 FAIL FetchEvent interface: attribute replacesClientId assert_true: The prototype object must have a property "replacesClientId" expected true got false
+FAIL FetchEvent interface: attribute handled assert_true: The prototype object must have a property "handled" expected true got false
 PASS FetchEvent interface: operation respondWith(Promise<Response>)
 FAIL FetchEvent must be primary interface of new FetchEvent("type") assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'FetchEvent': 2 arguments required, but only 1 present."
 FAIL Stringification of new FetchEvent("type") assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'FetchEvent': 2 arguments required, but only 1 present."
@@ -224,6 +225,7 @@
 FAIL FetchEvent interface: new FetchEvent("type") must inherit property "clientId" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'FetchEvent': 2 arguments required, but only 1 present."
 FAIL FetchEvent interface: new FetchEvent("type") must inherit property "resultingClientId" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'FetchEvent': 2 arguments required, but only 1 present."
 FAIL FetchEvent interface: new FetchEvent("type") must inherit property "replacesClientId" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'FetchEvent': 2 arguments required, but only 1 present."
+FAIL FetchEvent interface: new FetchEvent("type") must inherit property "handled" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'FetchEvent': 2 arguments required, but only 1 present."
 FAIL FetchEvent interface: new FetchEvent("type") must inherit property "respondWith(Promise<Response>)" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'FetchEvent': 2 arguments required, but only 1 present."
 FAIL FetchEvent interface: calling respondWith(Promise<Response>) on new FetchEvent("type") with too few arguments must throw TypeError assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'FetchEvent': 2 arguments required, but only 1 present."
 FAIL ExtendableEvent interface: new FetchEvent("type") must inherit property "waitUntil(Promise<any>)" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'FetchEvent': 2 arguments required, but only 1 present."
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-helper.js b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-helper.js
index 07626bd..cf31d2f 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-helper.js
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-helper.js
@@ -232,6 +232,12 @@
   }
 }
 
+async function waitForIceGatheringState(pc, wantedStates) {
+  while (!wantedStates.includes(pc.iceGatheringState)) {
+    await waitUntilEvent(pc, 'icegatheringstatechange');
+  }
+}
+
 // Resolves when RTP packets have been received.
 async function listenForSSRCs(t, receiver) {
   while (true) {
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-offer.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-offer.html
index b470244..a50e9696 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-offer.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-offer.html
@@ -325,4 +325,16 @@
     await pc1.setRemoteDescription(answer);
   }, 'repeated sRD(offer) works');
 
+  promise_test(async t => {
+    const pc1 = new RTCPeerConnection();
+    t.add_cleanup(() => pc1.close());
+    const pc2 = new RTCPeerConnection();
+    t.add_cleanup(() => pc2.close());
+    pc1.addTransceiver('video');
+    await exchangeOfferAnswer(pc1, pc2);
+    await waitForIceGatheringState(pc1, ['complete']);
+    await exchangeOfferAnswer(pc1, pc2);
+    await waitForIceStateChange(pc2, ['connected', 'completed']);
+  }, 'sRD(reoffer) with candidates and without trickle works');
+
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/protocol/candidate-exchange.https.html b/third_party/blink/web_tests/external/wpt/webrtc/protocol/candidate-exchange.https.html
index 532bc4d..8217895 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/protocol/candidate-exchange.https.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/protocol/candidate-exchange.https.html
@@ -10,23 +10,6 @@
 <body>
 <script>
 
-function iceGatheringCompleteWaiter(pc) {
-  const waiter = new Promise((resolve) => {
-    const eventHandler = () => {
-      if (pc.iceGatheringState == 'complete') {
-        pc.removeEventListener('icegatheringstatechange', eventHandler, false);
-        resolve();
-      }
-    };
-    if (pc.iceGatheringState == 'complete') {
-      resolve();
-    } else {
-      pc.addEventListener('icegatheringstatechange', eventHandler, false);
-    }
-  });
-  return waiter;
-}
-
 class StateLogger {
   constructor(source, eventname, field) {
     source.addEventListener(eventname, event => {
@@ -74,7 +57,7 @@
   // Candidates from PC2 are not delivered to pc1, so pc1 will use
   // peer-reflexive candidates.
   await exchangeOfferAnswer(pc1, pc2);
-  const waiter = iceGatheringCompleteWaiter(pc1);
+  const waiter = waitForIceGatheringState(pc1, ['complete']);
   await waiter;
   for (const candidate of candidates) {
     if (candidate) {
@@ -105,7 +88,7 @@
   // Candidates from pc1 are not delivered to pc2.  so pc2 will use
   // peer-reflexive candidates.
   await exchangeOfferAnswer(pc1, pc2);
-  const waiter = iceGatheringCompleteWaiter(pc2);
+  const waiter = waitForIceGatheringState(pc2, ['complete']);
   await waiter;
   for (const candidate of candidates) {
     if (candidate) {
@@ -174,7 +157,7 @@
   await Promise.all([pc1.setLocalDescription(offer),
                      pc2.setRemoteDescription(offer)]);
   const answer = await pc2.createAnswer();
-  await iceGatheringCompleteWaiter(pc1);
+  await waitForIceGatheringState(pc1, ['complete']);
   await pc2.setLocalDescription(answer).then(() => {
     for (const candidate of pc1ToPc2Candidates) {
       if (candidate) {
@@ -182,7 +165,7 @@
       }
     }
   });
-  await iceGatheringCompleteWaiter(pc2);
+  await waitForIceGatheringState(pc2, ['complete']);
   pc1.setRemoteDescription(answer).then(async () => {
     for (const candidate of pc2ToPc1Candidates) {
       if (candidate) {
diff --git a/third_party/blink/web_tests/fast/scrolling/scrollbars/mouse-scrolling-on-div-scrollbar-thumb-scaled.html b/third_party/blink/web_tests/fast/scrolling/scrollbars/mouse-scrolling-on-div-scrollbar-thumb-scaled.html
new file mode 100644
index 0000000..235cce6
--- /dev/null
+++ b/third_party/blink/web_tests/fast/scrolling/scrollbars/mouse-scrolling-on-div-scrollbar-thumb-scaled.html
@@ -0,0 +1,143 @@
+<!DOCTYPE html>
+<title>Tests mouse interactions on a scrollbar thumbs under page scale.</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/gesture-util.js"></script>
+<script src="../../../resources/blink-coordinates-util.js"></script>
+<script src="../../../resources/scrollbar-util.js"></script>
+<style>
+html { overflow:scroll; }
+body { margin: 0 }
+.appearance {
+  width: 100px;
+  height: 100px;
+  overflow: scroll;
+  border: 1px solid black;
+}
+#standard {
+  position: absolute;
+  top: 100px;
+  left: 0px;
+}
+#rotated {
+  position: absolute;
+  top: 100px;
+  left: 105px;
+  transform:rotate(90deg);
+}
+.space {
+  height: 1000px;
+  width: 1000px;
+}
+</style>
+
+<div id="standard" class="appearance">
+  <div class="space"></div>
+</div>
+<div id="rotated" class="appearance">
+  <div class="space"></div>
+</div>
+<div style="height:8000px"></div>
+<script>
+let platform = navigator.userAgent.includes("Linux") ? "linux" :
+               navigator.userAgent.includes("Windows") ? "win" :
+               navigator.userAgent.includes("Mac OS X") ? "mac" :
+               (() => { throw "Platform unsupported. See crbug.com/953847"; })();
+
+window.onload = () => {
+  const PAGE_SCALE_FACTOR = 2;
+  internals.setPageScaleFactor(PAGE_SCALE_FACTOR);
+  const VISUAL_VIEWPORT_Y_OFFSET = 50;
+  internals.setVisualViewportOffset(0, VISUAL_VIEWPORT_Y_OFFSET);
+
+  const TRACK_WIDTH = calculateScrollbarThickness();
+  const BUTTON_WIDTH = calculateScrollbarButtonWidth();
+
+  const MOUSE_DELTA = 10;
+  const EXPECTED_SCROLL_DELTA = {linux: 183, win: 120, mac: 70}[platform];
+
+  promise_test (async (test) => {
+    let unreached_click = test.unreached_func("Scrollbars must be hit, preventing click events");
+    window.addEventListener("click", unreached_click);
+
+    const standardDiv = document.getElementById("standard");
+    resetScrollOffset(standardDiv);
+    let point = verticalThumb(standardDiv);
+    let {x, y} = scaleCssToDIPixels(point);
+
+    await mouseMoveTo(x, y);
+    await mouseDownAt(x, y);
+    await mouseMoveTo(x, y + MOUSE_DELTA);
+    await mouseUpAt(x, y + MOUSE_DELTA);
+    assert_approx_equals(standardDiv.scrollTop, EXPECTED_SCROLL_DELTA, 1, "Vertical thumb drag downwards did not scroll as expected");
+
+    window.removeEventListener("click", unreached_click);
+  }, "Test mouse drags while page scaled on div scrollbar thumb.");
+
+  promise_test(async (test) => {
+    const rotatedDiv = document.getElementById("rotated");
+    const rotatedRect = rotatedDiv.getBoundingClientRect();
+
+    let unreached_click = test.unreached_func("Scrollbars must be hit, preventing click events");
+    window.addEventListener("click", unreached_click);
+
+    // The scrollbar for a 90deg rotated div is at the bottom right of the
+    // div's client rect. Inset from the right by the button width (and a bit more) to
+    let x = rotatedRect.right - BUTTON_WIDTH - 2;
+    let y = rotatedRect.bottom - TRACK_WIDTH / 2 - VISUAL_VIEWPORT_Y_OFFSET;
+    x *= PAGE_SCALE_FACTOR;
+    y *= PAGE_SCALE_FACTOR;
+
+    resetScrollOffset(rotatedDiv);
+    await waitForCompositorCommit();
+
+    await mouseMoveTo(x, y);
+    await mouseDownAt(x, y);
+    await mouseMoveTo(x - MOUSE_DELTA, y);
+    await mouseUpAt(x - MOUSE_DELTA, y);
+    assert_approx_equals(rotatedDiv.scrollTop, EXPECTED_SCROLL_DELTA, 1, "Vertical thumb drag downwards on rotated scroller did not scroll as expected");
+
+    window.removeEventListener("click", unreached_click);
+  }, "Test mouse drags with page scale on div with rotation scrollbar thumb.");
+
+  promise_test(async (test) => {
+    let unreached_click = test.unreached_func("Scrollbars must be hit, preventing click events");
+    window.addEventListener("click", unreached_click);
+
+    const TOTAL_ROOT_SCROLL_DELTA = window.innerHeight - 3 * BUTTON_WIDTH;
+    const FIRST_DELTA = 10;
+
+    // Don't scale the points since the root viewport scrollbars are not scaled.
+    let { x, y } = verticalThumb(document.scrollingElement);
+
+    await mouseMoveTo(x, y);
+    await mouseDownAt(x, y);
+    await mouseMoveTo(x, y + FIRST_DELTA);
+    await mouseUpAt(x, y + FIRST_DELTA);
+
+    const EXPECTED_FIRST_VIEWPORT_DELTA = {linux: 200, win: 200, mac: 192}[platform];
+
+    assert_equals(document.scrollingElement.scrollTop, 0,
+        "Vertical thumb drag downwards on root scrollbars should not scroll layout viewport");
+    assert_equals(visualViewport.pageTop, EXPECTED_FIRST_VIEWPORT_DELTA,
+        "Vertical thumb drag downwards on root scroller did not scroll visual viewport as expected");
+
+    await mouseMoveTo(x, y + FIRST_DELTA);
+    await mouseDownAt(x, y + FIRST_DELTA);
+    await mouseMoveTo(x, y + TOTAL_ROOT_SCROLL_DELTA - FIRST_DELTA);
+    await mouseUpAt(x, y + TOTAL_ROOT_SCROLL_DELTA - FIRST_DELTA);
+
+    // There are differences between main thread vs. compositor thread, in that
+    // scrolling the root scrollbar on the main thread doesn't account for the
+    // visual viewport size in its offset calculations, so this test only passes
+    // when threaded compositing is enabled.
+    assert_equals(document.scrollingElement.scrollTop, 7400 + TRACK_WIDTH,
+        "Vertical thumb drag downwards on root scrollbars did not scroll layout viewport as expected");
+    assert_equals(visualViewport.pageTop, 7700 + TRACK_WIDTH,
+        "Vertical thumb drag downwards on root scroller did not scroll visual viewport as expected");
+
+    window.removeEventListener("click", unreached_click);
+  }, "Test mouse drags on root scrollbar thumb.");
+}
+</script>
+
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/stacked-float-under-composited-inline-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/stacked-float-under-composited-inline-expected.txt
index 479221e..d6581d1 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/stacked-float-under-composited-inline-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/stacked-float-under-composited-inline-expected.txt
@@ -7,7 +7,7 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutNGBlockFlow (relative positioned) (floating) DIV id='float'",
+      "name": "LayoutInline (relative positioned) SPAN",
       "position": [158, 158],
       "bounds": [100, 100],
       "contentsOpaque": true,
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/fast/css/percent-top-relative-container-height-unspecified-expected.png b/third_party/blink/web_tests/flag-specific/disable-layout-ng/fast/css/percent-top-relative-container-height-unspecified-expected.png
new file mode 100644
index 0000000..20b11cd
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/fast/css/percent-top-relative-container-height-unspecified-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/paint/invalidation/compositing/composited-float-under-composited-inline-expected.txt b/third_party/blink/web_tests/paint/invalidation/compositing/composited-float-under-composited-inline-expected.txt
index 728f98e..27b109d 100644
--- a/third_party/blink/web_tests/paint/invalidation/compositing/composited-float-under-composited-inline-expected.txt
+++ b/third_party/blink/web_tests/paint/invalidation/compositing/composited-float-under-composited-inline-expected.txt
@@ -8,8 +8,8 @@
     },
     {
       "name": "LayoutInline (relative positioned) SPAN",
-      "position": [108, 108],
-      "drawsContent": false
+      "position": [8, 8],
+      "bounds": [200, 100]
     },
     {
       "name": "LayoutNGBlockFlow (relative positioned) (floating) DIV id='float'",
diff --git a/third_party/blink/web_tests/paint/invalidation/compositing/composited-float-under-composited-inline-individual-expected.txt b/third_party/blink/web_tests/paint/invalidation/compositing/composited-float-under-composited-inline-individual-expected.txt
index 728f98e..27b109d 100644
--- a/third_party/blink/web_tests/paint/invalidation/compositing/composited-float-under-composited-inline-individual-expected.txt
+++ b/third_party/blink/web_tests/paint/invalidation/compositing/composited-float-under-composited-inline-individual-expected.txt
@@ -8,8 +8,8 @@
     },
     {
       "name": "LayoutInline (relative positioned) SPAN",
-      "position": [108, 108],
-      "drawsContent": false
+      "position": [8, 8],
+      "bounds": [200, 100]
     },
     {
       "name": "LayoutNGBlockFlow (relative positioned) (floating) DIV id='float'",
diff --git a/third_party/blink/web_tests/paint/invalidation/compositing/stacked-float-under-composited-inline-expected.txt b/third_party/blink/web_tests/paint/invalidation/compositing/stacked-float-under-composited-inline-expected.txt
index 63f5ebc..27c04c3 100644
--- a/third_party/blink/web_tests/paint/invalidation/compositing/stacked-float-under-composited-inline-expected.txt
+++ b/third_party/blink/web_tests/paint/invalidation/compositing/stacked-float-under-composited-inline-expected.txt
@@ -8,11 +8,10 @@
     },
     {
       "name": "LayoutInline (relative positioned) SPAN",
-      "position": [158, 158],
-      "bounds": [100, 100],
-      "contentsOpaque": true,
+      "position": [8, 8],
+      "bounds": [250, 250],
       "invalidations": [
-        [0, 0, 100, 100]
+        [150, 150, 100, 100]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/platform/linux/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
similarity index 100%
copy from third_party/blink/web_tests/platform/linux/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
copy to third_party/blink/web_tests/platform/linux/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/platform/win/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
rename to third_party/blink/web_tests/platform/linux/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
diff --git a/third_party/blink/web_tests/platform/linux/fast/css/percent-top-relative-container-height-unspecified-expected.png b/third_party/blink/web_tests/platform/linux/fast/css/percent-top-relative-container-height-unspecified-expected.png
index 20b11cd..213a24a 100644
--- a/third_party/blink/web_tests/platform/linux/fast/css/percent-top-relative-container-height-unspecified-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/css/percent-top-relative-container-height-unspecified-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/cors/external/wpt/fetch/api/abort/general.any.worker-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/platform/linux/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
rename to third_party/blink/web_tests/platform/linux/virtual/cors/external/wpt/fetch/api/abort/general.any.worker-expected.txt
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/fetch/api/abort/general.any-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/fetch/api/abort/general.any-expected.txt
index 99afa96..5392aa4 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/fetch/api/abort/general.any-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/fetch/api/abort/general.any-expected.txt
@@ -34,15 +34,15 @@
 PASS Already aborted signal does not make request
 PASS Already aborted signal can be used for many fetches
 PASS Signal can be used to abort other fetches, even if another fetch succeeded before aborting
-PASS Underlying connection is closed when aborting after receiving response
-PASS Underlying connection is closed when aborting after receiving response - no-cors
-PASS Fetch aborted & connection closed when aborted after calling response.arrayBuffer()
-PASS Fetch aborted & connection closed when aborted after calling response.blob()
-PASS Fetch aborted & connection closed when aborted after calling response.formData()
-PASS Fetch aborted & connection closed when aborted after calling response.json()
-PASS Fetch aborted & connection closed when aborted after calling response.text()
+FAIL Underlying connection is closed when aborting after receiving response assert_equals: Connection is open expected "open" but got "closed"
+FAIL Underlying connection is closed when aborting after receiving response - no-cors assert_equals: Connection is open expected "open" but got "closed"
+FAIL Fetch aborted & connection closed when aborted after calling response.arrayBuffer() assert_equals: Connection is open expected "open" but got "closed"
+FAIL Fetch aborted & connection closed when aborted after calling response.blob() assert_equals: Connection is open expected "open" but got "closed"
+FAIL Fetch aborted & connection closed when aborted after calling response.formData() assert_equals: Connection is open expected "open" but got "closed"
+FAIL Fetch aborted & connection closed when aborted after calling response.json() assert_equals: Connection is open expected "open" but got "closed"
+FAIL Fetch aborted & connection closed when aborted after calling response.text() assert_equals: Connection is open expected "open" but got "closed"
 PASS Stream errors once aborted. Underlying connection closed.
-PASS Stream errors once aborted, after reading. Underlying connection closed.
+FAIL Stream errors once aborted, after reading. Underlying connection closed. assert_unreached: Should have rejected: undefined Reached unreachable code
 PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
 FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
 PASS Signal state is cloned
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
deleted file mode 100644
index 99afa96..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-This is a testharness.js-based test.
-PASS Aborting rejects with AbortError
-PASS Aborting rejects with AbortError - no-cors
-PASS TypeError from request constructor takes priority - RequestInit's window is not null
-PASS TypeError from request constructor takes priority - Input URL is not valid
-PASS TypeError from request constructor takes priority - Input URL has credentials
-PASS TypeError from request constructor takes priority - RequestInit's mode is navigate
-PASS TypeError from request constructor takes priority - RequestInit's referrer is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is forbidden
-PASS TypeError from request constructor takes priority - RequestInit's mode is no-cors and method is not simple
-PASS TypeError from request constructor takes priority - RequestInit's cache mode is only-if-cached and mode is not same-origin
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode cors
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode no-cors
-PASS TypeError from request constructor takes priority - Bad referrerPolicy init parameter value
-PASS TypeError from request constructor takes priority - Bad mode init parameter value
-PASS TypeError from request constructor takes priority - Bad credentials init parameter value
-PASS TypeError from request constructor takes priority - Bad cache init parameter value
-PASS TypeError from request constructor takes priority - Bad redirect init parameter value
-PASS Request objects have a signal property
-PASS Signal on request object
-PASS Signal on request object created from request object
-PASS Signal on request object created from request object, with signal on second request
-PASS Signal on request object created from request object, with signal on second request overriding another
-PASS Signal retained after unrelated properties are overridden by fetch
-PASS Signal removed by setting to null
-PASS Already aborted signal rejects immediately
-PASS Request is still 'used' if signal is aborted before fetching
-PASS response.arrayBuffer() rejects if already aborted
-PASS response.blob() rejects if already aborted
-PASS response.formData() rejects if already aborted
-PASS response.json() rejects if already aborted
-PASS response.text() rejects if already aborted
-PASS Already aborted signal does not make request
-PASS Already aborted signal can be used for many fetches
-PASS Signal can be used to abort other fetches, even if another fetch succeeded before aborting
-PASS Underlying connection is closed when aborting after receiving response
-PASS Underlying connection is closed when aborting after receiving response - no-cors
-PASS Fetch aborted & connection closed when aborted after calling response.arrayBuffer()
-PASS Fetch aborted & connection closed when aborted after calling response.blob()
-PASS Fetch aborted & connection closed when aborted after calling response.formData()
-PASS Fetch aborted & connection closed when aborted after calling response.json()
-PASS Fetch aborted & connection closed when aborted after calling response.text()
-PASS Stream errors once aborted. Underlying connection closed.
-PASS Stream errors once aborted, after reading. Underlying connection closed.
-PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
-FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
-PASS Signal state is cloned
-PASS Clone aborts with original controller
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
deleted file mode 100644
index 99afa96..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-This is a testharness.js-based test.
-PASS Aborting rejects with AbortError
-PASS Aborting rejects with AbortError - no-cors
-PASS TypeError from request constructor takes priority - RequestInit's window is not null
-PASS TypeError from request constructor takes priority - Input URL is not valid
-PASS TypeError from request constructor takes priority - Input URL has credentials
-PASS TypeError from request constructor takes priority - RequestInit's mode is navigate
-PASS TypeError from request constructor takes priority - RequestInit's referrer is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is forbidden
-PASS TypeError from request constructor takes priority - RequestInit's mode is no-cors and method is not simple
-PASS TypeError from request constructor takes priority - RequestInit's cache mode is only-if-cached and mode is not same-origin
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode cors
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode no-cors
-PASS TypeError from request constructor takes priority - Bad referrerPolicy init parameter value
-PASS TypeError from request constructor takes priority - Bad mode init parameter value
-PASS TypeError from request constructor takes priority - Bad credentials init parameter value
-PASS TypeError from request constructor takes priority - Bad cache init parameter value
-PASS TypeError from request constructor takes priority - Bad redirect init parameter value
-PASS Request objects have a signal property
-PASS Signal on request object
-PASS Signal on request object created from request object
-PASS Signal on request object created from request object, with signal on second request
-PASS Signal on request object created from request object, with signal on second request overriding another
-PASS Signal retained after unrelated properties are overridden by fetch
-PASS Signal removed by setting to null
-PASS Already aborted signal rejects immediately
-PASS Request is still 'used' if signal is aborted before fetching
-PASS response.arrayBuffer() rejects if already aborted
-PASS response.blob() rejects if already aborted
-PASS response.formData() rejects if already aborted
-PASS response.json() rejects if already aborted
-PASS response.text() rejects if already aborted
-PASS Already aborted signal does not make request
-PASS Already aborted signal can be used for many fetches
-PASS Signal can be used to abort other fetches, even if another fetch succeeded before aborting
-PASS Underlying connection is closed when aborting after receiving response
-PASS Underlying connection is closed when aborting after receiving response - no-cors
-PASS Fetch aborted & connection closed when aborted after calling response.arrayBuffer()
-PASS Fetch aborted & connection closed when aborted after calling response.blob()
-PASS Fetch aborted & connection closed when aborted after calling response.formData()
-PASS Fetch aborted & connection closed when aborted after calling response.json()
-PASS Fetch aborted & connection closed when aborted after calling response.text()
-PASS Stream errors once aborted. Underlying connection closed.
-PASS Stream errors once aborted, after reading. Underlying connection closed.
-PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
-FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
-PASS Signal state is cloned
-PASS Clone aborts with original controller
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/fetch/api/abort/general.any.worker-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/fetch/api/abort/general.any.worker-expected.txt
deleted file mode 100644
index 99afa96..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/fetch/api/abort/general.any.worker-expected.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-This is a testharness.js-based test.
-PASS Aborting rejects with AbortError
-PASS Aborting rejects with AbortError - no-cors
-PASS TypeError from request constructor takes priority - RequestInit's window is not null
-PASS TypeError from request constructor takes priority - Input URL is not valid
-PASS TypeError from request constructor takes priority - Input URL has credentials
-PASS TypeError from request constructor takes priority - RequestInit's mode is navigate
-PASS TypeError from request constructor takes priority - RequestInit's referrer is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is forbidden
-PASS TypeError from request constructor takes priority - RequestInit's mode is no-cors and method is not simple
-PASS TypeError from request constructor takes priority - RequestInit's cache mode is only-if-cached and mode is not same-origin
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode cors
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode no-cors
-PASS TypeError from request constructor takes priority - Bad referrerPolicy init parameter value
-PASS TypeError from request constructor takes priority - Bad mode init parameter value
-PASS TypeError from request constructor takes priority - Bad credentials init parameter value
-PASS TypeError from request constructor takes priority - Bad cache init parameter value
-PASS TypeError from request constructor takes priority - Bad redirect init parameter value
-PASS Request objects have a signal property
-PASS Signal on request object
-PASS Signal on request object created from request object
-PASS Signal on request object created from request object, with signal on second request
-PASS Signal on request object created from request object, with signal on second request overriding another
-PASS Signal retained after unrelated properties are overridden by fetch
-PASS Signal removed by setting to null
-PASS Already aborted signal rejects immediately
-PASS Request is still 'used' if signal is aborted before fetching
-PASS response.arrayBuffer() rejects if already aborted
-PASS response.blob() rejects if already aborted
-PASS response.formData() rejects if already aborted
-PASS response.json() rejects if already aborted
-PASS response.text() rejects if already aborted
-PASS Already aborted signal does not make request
-PASS Already aborted signal can be used for many fetches
-PASS Signal can be used to abort other fetches, even if another fetch succeeded before aborting
-PASS Underlying connection is closed when aborting after receiving response
-PASS Underlying connection is closed when aborting after receiving response - no-cors
-PASS Fetch aborted & connection closed when aborted after calling response.arrayBuffer()
-PASS Fetch aborted & connection closed when aborted after calling response.blob()
-PASS Fetch aborted & connection closed when aborted after calling response.formData()
-PASS Fetch aborted & connection closed when aborted after calling response.json()
-PASS Fetch aborted & connection closed when aborted after calling response.text()
-PASS Stream errors once aborted. Underlying connection closed.
-PASS Stream errors once aborted, after reading. Underlying connection closed.
-PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
-FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
-PASS Signal state is cloned
-PASS Clone aborts with original controller
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/html/semantics/interactive-elements/the-dialog-element/dialog-form-submission-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/html/semantics/interactive-elements/the-dialog-element/dialog-form-submission-expected.txt
deleted file mode 100644
index 759a28e..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/html/semantics/interactive-elements/the-dialog-element/dialog-form-submission-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-This is a testharness.js-based test.
-PASS click the form submission button should close the dialog
-PASS form submission should return correct value
-PASS no returnValue when there's no result.
-FAIL input image button should return the coordianates assert_equals: returnValue should be the offsets of the click expected "20.5,20.5" but got "20,20"
-PASS formmethod attribute should use dialog form submission
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/service-workers/cache-storage/worker/cache-abort.https-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/service-workers/cache-storage/worker/cache-abort.https-expected.txt
new file mode 100644
index 0000000..cde71626
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/service-workers/cache-storage/worker/cache-abort.https-expected.txt
@@ -0,0 +1,12 @@
+This is a testharness.js-based test.
+PASS put() on an already-aborted request should reject with AbortError
+PASS put() synchronously followed by abort should reject with AbortError
+FAIL put() followed by abort after headers received should reject with AbortError assert_unreached: Should have rejected: put should reject Reached unreachable code
+PASS add() on an already-aborted request should reject with AbortError
+PASS add() synchronously followed by abort should reject with AbortError
+FAIL add() followed by abort after headers received should reject with AbortError assert_unreached: Should have rejected: add should reject Reached unreachable code
+PASS addAll() on an already-aborted request should reject with AbortError
+PASS addAll() synchronously followed by abort should reject with AbortError
+FAIL addAll() followed by abort after headers received should reject with AbortError assert_unreached: Should have rejected: addAll should reject Reached unreachable code
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/cors/external/wpt/fetch/api/abort/general.any-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/cors/external/wpt/fetch/api/abort/general.any-expected.txt
deleted file mode 100644
index 99afa96..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/cors/external/wpt/fetch/api/abort/general.any-expected.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-This is a testharness.js-based test.
-PASS Aborting rejects with AbortError
-PASS Aborting rejects with AbortError - no-cors
-PASS TypeError from request constructor takes priority - RequestInit's window is not null
-PASS TypeError from request constructor takes priority - Input URL is not valid
-PASS TypeError from request constructor takes priority - Input URL has credentials
-PASS TypeError from request constructor takes priority - RequestInit's mode is navigate
-PASS TypeError from request constructor takes priority - RequestInit's referrer is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is forbidden
-PASS TypeError from request constructor takes priority - RequestInit's mode is no-cors and method is not simple
-PASS TypeError from request constructor takes priority - RequestInit's cache mode is only-if-cached and mode is not same-origin
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode cors
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode no-cors
-PASS TypeError from request constructor takes priority - Bad referrerPolicy init parameter value
-PASS TypeError from request constructor takes priority - Bad mode init parameter value
-PASS TypeError from request constructor takes priority - Bad credentials init parameter value
-PASS TypeError from request constructor takes priority - Bad cache init parameter value
-PASS TypeError from request constructor takes priority - Bad redirect init parameter value
-PASS Request objects have a signal property
-PASS Signal on request object
-PASS Signal on request object created from request object
-PASS Signal on request object created from request object, with signal on second request
-PASS Signal on request object created from request object, with signal on second request overriding another
-PASS Signal retained after unrelated properties are overridden by fetch
-PASS Signal removed by setting to null
-PASS Already aborted signal rejects immediately
-PASS Request is still 'used' if signal is aborted before fetching
-PASS response.arrayBuffer() rejects if already aborted
-PASS response.blob() rejects if already aborted
-PASS response.formData() rejects if already aborted
-PASS response.json() rejects if already aborted
-PASS response.text() rejects if already aborted
-PASS Already aborted signal does not make request
-PASS Already aborted signal can be used for many fetches
-PASS Signal can be used to abort other fetches, even if another fetch succeeded before aborting
-PASS Underlying connection is closed when aborting after receiving response
-PASS Underlying connection is closed when aborting after receiving response - no-cors
-PASS Fetch aborted & connection closed when aborted after calling response.arrayBuffer()
-PASS Fetch aborted & connection closed when aborted after calling response.blob()
-PASS Fetch aborted & connection closed when aborted after calling response.formData()
-PASS Fetch aborted & connection closed when aborted after calling response.json()
-PASS Fetch aborted & connection closed when aborted after calling response.text()
-PASS Stream errors once aborted. Underlying connection closed.
-PASS Stream errors once aborted, after reading. Underlying connection closed.
-PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
-FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
-PASS Signal state is cloned
-PASS Clone aborts with original controller
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
index 99afa96..47a8c8da 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
@@ -34,13 +34,13 @@
 PASS Already aborted signal does not make request
 PASS Already aborted signal can be used for many fetches
 PASS Signal can be used to abort other fetches, even if another fetch succeeded before aborting
-PASS Underlying connection is closed when aborting after receiving response
-PASS Underlying connection is closed when aborting after receiving response - no-cors
-PASS Fetch aborted & connection closed when aborted after calling response.arrayBuffer()
-PASS Fetch aborted & connection closed when aborted after calling response.blob()
-PASS Fetch aborted & connection closed when aborted after calling response.formData()
-PASS Fetch aborted & connection closed when aborted after calling response.json()
-PASS Fetch aborted & connection closed when aborted after calling response.text()
+FAIL Underlying connection is closed when aborting after receiving response assert_equals: Connection is open expected "open" but got "closed"
+FAIL Underlying connection is closed when aborting after receiving response - no-cors assert_equals: Connection is open expected "open" but got "closed"
+FAIL Fetch aborted & connection closed when aborted after calling response.arrayBuffer() assert_equals: Connection is open expected "open" but got "closed"
+FAIL Fetch aborted & connection closed when aborted after calling response.blob() assert_equals: Connection is open expected "open" but got "closed"
+FAIL Fetch aborted & connection closed when aborted after calling response.formData() assert_equals: Connection is open expected "open" but got "closed"
+FAIL Fetch aborted & connection closed when aborted after calling response.json() assert_equals: Connection is open expected "open" but got "closed"
+FAIL Fetch aborted & connection closed when aborted after calling response.text() assert_equals: Connection is open expected "open" but got "closed"
 PASS Stream errors once aborted. Underlying connection closed.
 PASS Stream errors once aborted, after reading. Underlying connection closed.
 PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/cors/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/cors/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
index 99afa96..5392aa4 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/cors/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/cors/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
@@ -34,15 +34,15 @@
 PASS Already aborted signal does not make request
 PASS Already aborted signal can be used for many fetches
 PASS Signal can be used to abort other fetches, even if another fetch succeeded before aborting
-PASS Underlying connection is closed when aborting after receiving response
-PASS Underlying connection is closed when aborting after receiving response - no-cors
-PASS Fetch aborted & connection closed when aborted after calling response.arrayBuffer()
-PASS Fetch aborted & connection closed when aborted after calling response.blob()
-PASS Fetch aborted & connection closed when aborted after calling response.formData()
-PASS Fetch aborted & connection closed when aborted after calling response.json()
-PASS Fetch aborted & connection closed when aborted after calling response.text()
+FAIL Underlying connection is closed when aborting after receiving response assert_equals: Connection is open expected "open" but got "closed"
+FAIL Underlying connection is closed when aborting after receiving response - no-cors assert_equals: Connection is open expected "open" but got "closed"
+FAIL Fetch aborted & connection closed when aborted after calling response.arrayBuffer() assert_equals: Connection is open expected "open" but got "closed"
+FAIL Fetch aborted & connection closed when aborted after calling response.blob() assert_equals: Connection is open expected "open" but got "closed"
+FAIL Fetch aborted & connection closed when aborted after calling response.formData() assert_equals: Connection is open expected "open" but got "closed"
+FAIL Fetch aborted & connection closed when aborted after calling response.json() assert_equals: Connection is open expected "open" but got "closed"
+FAIL Fetch aborted & connection closed when aborted after calling response.text() assert_equals: Connection is open expected "open" but got "closed"
 PASS Stream errors once aborted. Underlying connection closed.
-PASS Stream errors once aborted, after reading. Underlying connection closed.
+FAIL Stream errors once aborted, after reading. Underlying connection closed. assert_unreached: Should have rejected: undefined Reached unreachable code
 PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
 FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
 PASS Signal state is cloned
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/cors/external/wpt/fetch/api/abort/general.any.worker-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/cors/external/wpt/fetch/api/abort/general.any.worker-expected.txt
deleted file mode 100644
index 99afa96..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/cors/external/wpt/fetch/api/abort/general.any.worker-expected.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-This is a testharness.js-based test.
-PASS Aborting rejects with AbortError
-PASS Aborting rejects with AbortError - no-cors
-PASS TypeError from request constructor takes priority - RequestInit's window is not null
-PASS TypeError from request constructor takes priority - Input URL is not valid
-PASS TypeError from request constructor takes priority - Input URL has credentials
-PASS TypeError from request constructor takes priority - RequestInit's mode is navigate
-PASS TypeError from request constructor takes priority - RequestInit's referrer is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is forbidden
-PASS TypeError from request constructor takes priority - RequestInit's mode is no-cors and method is not simple
-PASS TypeError from request constructor takes priority - RequestInit's cache mode is only-if-cached and mode is not same-origin
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode cors
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode no-cors
-PASS TypeError from request constructor takes priority - Bad referrerPolicy init parameter value
-PASS TypeError from request constructor takes priority - Bad mode init parameter value
-PASS TypeError from request constructor takes priority - Bad credentials init parameter value
-PASS TypeError from request constructor takes priority - Bad cache init parameter value
-PASS TypeError from request constructor takes priority - Bad redirect init parameter value
-PASS Request objects have a signal property
-PASS Signal on request object
-PASS Signal on request object created from request object
-PASS Signal on request object created from request object, with signal on second request
-PASS Signal on request object created from request object, with signal on second request overriding another
-PASS Signal retained after unrelated properties are overridden by fetch
-PASS Signal removed by setting to null
-PASS Already aborted signal rejects immediately
-PASS Request is still 'used' if signal is aborted before fetching
-PASS response.arrayBuffer() rejects if already aborted
-PASS response.blob() rejects if already aborted
-PASS response.formData() rejects if already aborted
-PASS response.json() rejects if already aborted
-PASS response.text() rejects if already aborted
-PASS Already aborted signal does not make request
-PASS Already aborted signal can be used for many fetches
-PASS Signal can be used to abort other fetches, even if another fetch succeeded before aborting
-PASS Underlying connection is closed when aborting after receiving response
-PASS Underlying connection is closed when aborting after receiving response - no-cors
-PASS Fetch aborted & connection closed when aborted after calling response.arrayBuffer()
-PASS Fetch aborted & connection closed when aborted after calling response.blob()
-PASS Fetch aborted & connection closed when aborted after calling response.formData()
-PASS Fetch aborted & connection closed when aborted after calling response.json()
-PASS Fetch aborted & connection closed when aborted after calling response.text()
-PASS Stream errors once aborted. Underlying connection closed.
-PASS Stream errors once aborted, after reading. Underlying connection closed.
-PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
-FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
-PASS Signal state is cloned
-PASS Clone aborts with original controller
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any-expected.txt
deleted file mode 100644
index 99afa96..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any-expected.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-This is a testharness.js-based test.
-PASS Aborting rejects with AbortError
-PASS Aborting rejects with AbortError - no-cors
-PASS TypeError from request constructor takes priority - RequestInit's window is not null
-PASS TypeError from request constructor takes priority - Input URL is not valid
-PASS TypeError from request constructor takes priority - Input URL has credentials
-PASS TypeError from request constructor takes priority - RequestInit's mode is navigate
-PASS TypeError from request constructor takes priority - RequestInit's referrer is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is forbidden
-PASS TypeError from request constructor takes priority - RequestInit's mode is no-cors and method is not simple
-PASS TypeError from request constructor takes priority - RequestInit's cache mode is only-if-cached and mode is not same-origin
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode cors
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode no-cors
-PASS TypeError from request constructor takes priority - Bad referrerPolicy init parameter value
-PASS TypeError from request constructor takes priority - Bad mode init parameter value
-PASS TypeError from request constructor takes priority - Bad credentials init parameter value
-PASS TypeError from request constructor takes priority - Bad cache init parameter value
-PASS TypeError from request constructor takes priority - Bad redirect init parameter value
-PASS Request objects have a signal property
-PASS Signal on request object
-PASS Signal on request object created from request object
-PASS Signal on request object created from request object, with signal on second request
-PASS Signal on request object created from request object, with signal on second request overriding another
-PASS Signal retained after unrelated properties are overridden by fetch
-PASS Signal removed by setting to null
-PASS Already aborted signal rejects immediately
-PASS Request is still 'used' if signal is aborted before fetching
-PASS response.arrayBuffer() rejects if already aborted
-PASS response.blob() rejects if already aborted
-PASS response.formData() rejects if already aborted
-PASS response.json() rejects if already aborted
-PASS response.text() rejects if already aborted
-PASS Already aborted signal does not make request
-PASS Already aborted signal can be used for many fetches
-PASS Signal can be used to abort other fetches, even if another fetch succeeded before aborting
-PASS Underlying connection is closed when aborting after receiving response
-PASS Underlying connection is closed when aborting after receiving response - no-cors
-PASS Fetch aborted & connection closed when aborted after calling response.arrayBuffer()
-PASS Fetch aborted & connection closed when aborted after calling response.blob()
-PASS Fetch aborted & connection closed when aborted after calling response.formData()
-PASS Fetch aborted & connection closed when aborted after calling response.json()
-PASS Fetch aborted & connection closed when aborted after calling response.text()
-PASS Stream errors once aborted. Underlying connection closed.
-PASS Stream errors once aborted, after reading. Underlying connection closed.
-PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
-FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
-PASS Signal state is cloned
-PASS Clone aborts with original controller
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
deleted file mode 100644
index 99afa96..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-This is a testharness.js-based test.
-PASS Aborting rejects with AbortError
-PASS Aborting rejects with AbortError - no-cors
-PASS TypeError from request constructor takes priority - RequestInit's window is not null
-PASS TypeError from request constructor takes priority - Input URL is not valid
-PASS TypeError from request constructor takes priority - Input URL has credentials
-PASS TypeError from request constructor takes priority - RequestInit's mode is navigate
-PASS TypeError from request constructor takes priority - RequestInit's referrer is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is forbidden
-PASS TypeError from request constructor takes priority - RequestInit's mode is no-cors and method is not simple
-PASS TypeError from request constructor takes priority - RequestInit's cache mode is only-if-cached and mode is not same-origin
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode cors
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode no-cors
-PASS TypeError from request constructor takes priority - Bad referrerPolicy init parameter value
-PASS TypeError from request constructor takes priority - Bad mode init parameter value
-PASS TypeError from request constructor takes priority - Bad credentials init parameter value
-PASS TypeError from request constructor takes priority - Bad cache init parameter value
-PASS TypeError from request constructor takes priority - Bad redirect init parameter value
-PASS Request objects have a signal property
-PASS Signal on request object
-PASS Signal on request object created from request object
-PASS Signal on request object created from request object, with signal on second request
-PASS Signal on request object created from request object, with signal on second request overriding another
-PASS Signal retained after unrelated properties are overridden by fetch
-PASS Signal removed by setting to null
-PASS Already aborted signal rejects immediately
-PASS Request is still 'used' if signal is aborted before fetching
-PASS response.arrayBuffer() rejects if already aborted
-PASS response.blob() rejects if already aborted
-PASS response.formData() rejects if already aborted
-PASS response.json() rejects if already aborted
-PASS response.text() rejects if already aborted
-PASS Already aborted signal does not make request
-PASS Already aborted signal can be used for many fetches
-PASS Signal can be used to abort other fetches, even if another fetch succeeded before aborting
-PASS Underlying connection is closed when aborting after receiving response
-PASS Underlying connection is closed when aborting after receiving response - no-cors
-PASS Fetch aborted & connection closed when aborted after calling response.arrayBuffer()
-PASS Fetch aborted & connection closed when aborted after calling response.blob()
-PASS Fetch aborted & connection closed when aborted after calling response.formData()
-PASS Fetch aborted & connection closed when aborted after calling response.json()
-PASS Fetch aborted & connection closed when aborted after calling response.text()
-PASS Stream errors once aborted. Underlying connection closed.
-PASS Stream errors once aborted, after reading. Underlying connection closed.
-PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
-FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
-PASS Signal state is cloned
-PASS Clone aborts with original controller
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
deleted file mode 100644
index 195db3494..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-This is a testharness.js-based test.
-PASS Aborting rejects with AbortError
-PASS Aborting rejects with AbortError - no-cors
-PASS TypeError from request constructor takes priority - RequestInit's window is not null
-PASS TypeError from request constructor takes priority - Input URL is not valid
-PASS TypeError from request constructor takes priority - Input URL has credentials
-PASS TypeError from request constructor takes priority - RequestInit's mode is navigate
-PASS TypeError from request constructor takes priority - RequestInit's referrer is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is forbidden
-PASS TypeError from request constructor takes priority - RequestInit's mode is no-cors and method is not simple
-PASS TypeError from request constructor takes priority - RequestInit's cache mode is only-if-cached and mode is not same-origin
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode cors
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode no-cors
-PASS TypeError from request constructor takes priority - Bad referrerPolicy init parameter value
-PASS TypeError from request constructor takes priority - Bad mode init parameter value
-PASS TypeError from request constructor takes priority - Bad credentials init parameter value
-PASS TypeError from request constructor takes priority - Bad cache init parameter value
-PASS TypeError from request constructor takes priority - Bad redirect init parameter value
-PASS Request objects have a signal property
-PASS Signal on request object
-PASS Signal on request object created from request object
-PASS Signal on request object created from request object, with signal on second request
-PASS Signal on request object created from request object, with signal on second request overriding another
-PASS Signal retained after unrelated properties are overridden by fetch
-PASS Signal removed by setting to null
-PASS Already aborted signal rejects immediately
-PASS Request is still 'used' if signal is aborted before fetching
-PASS response.arrayBuffer() rejects if already aborted
-PASS response.blob() rejects if already aborted
-PASS response.formData() rejects if already aborted
-PASS response.json() rejects if already aborted
-PASS response.text() rejects if already aborted
-PASS Already aborted signal does not make request
-PASS Already aborted signal can be used for many fetches
-PASS Signal can be used to abort other fetches, even if another fetch succeeded before aborting
-PASS Underlying connection is closed when aborting after receiving response
-FAIL Underlying connection is closed when aborting after receiving response - no-cors assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.arrayBuffer() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.blob() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.formData() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.json() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.text() assert_equals: Connection is open expected "open" but got "closed"
-PASS Stream errors once aborted. Underlying connection closed.
-PASS Stream errors once aborted, after reading. Underlying connection closed.
-PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
-FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
-PASS Signal state is cloned
-PASS Clone aborts with original controller
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/cors/external/wpt/fetch/api/abort/general.any.worker-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.worker-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/platform/mac-mac10.14/virtual/cors/external/wpt/fetch/api/abort/general.any.worker-expected.txt
rename to third_party/blink/web_tests/platform/mac-mac10.10/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.worker-expected.txt
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.11/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/platform/mac/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
rename to third_party/blink/web_tests/platform/mac-mac10.11/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/fetch/api/abort/general.any.worker-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.11/external/wpt/fetch/api/abort/general.any.worker-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/fetch/api/abort/general.any.worker-expected.txt
rename to third_party/blink/web_tests/platform/mac-mac10.11/external/wpt/fetch/api/abort/general.any.worker-expected.txt
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
index 47a8c8da..5392aa4 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
@@ -42,7 +42,7 @@
 FAIL Fetch aborted & connection closed when aborted after calling response.json() assert_equals: Connection is open expected "open" but got "closed"
 FAIL Fetch aborted & connection closed when aborted after calling response.text() assert_equals: Connection is open expected "open" but got "closed"
 PASS Stream errors once aborted. Underlying connection closed.
-PASS Stream errors once aborted, after reading. Underlying connection closed.
+FAIL Stream errors once aborted, after reading. Underlying connection closed. assert_unreached: Should have rejected: undefined Reached unreachable code
 PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
 FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
 PASS Signal state is cloned
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/platform/mac-mac10.13/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any-expected.txt
rename to third_party/blink/web_tests/platform/mac-mac10.11/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any-expected.txt
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/platform/mac-mac10.14/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
rename to third_party/blink/web_tests/platform/mac-mac10.11/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.worker-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.worker-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/platform/mac-retina/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.worker-expected.txt
rename to third_party/blink/web_tests/platform/mac-mac10.11/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.worker-expected.txt
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
similarity index 100%
copy from third_party/blink/web_tests/platform/win/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
copy to third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/cors/external/wpt/fetch/api/abort/general.any-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/cors/external/wpt/fetch/api/abort/general.any-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/platform/mac-mac10.11/virtual/cors/external/wpt/fetch/api/abort/general.any-expected.txt
rename to third_party/blink/web_tests/platform/mac-mac10.12/virtual/cors/external/wpt/fetch/api/abort/general.any-expected.txt
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
similarity index 100%
copy from third_party/blink/web_tests/platform/mac-mac10.14/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
copy to third_party/blink/web_tests/platform/mac-mac10.12/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
diff --git a/third_party/blink/web_tests/virtual/cors/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/cors/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
similarity index 100%
copy from third_party/blink/web_tests/virtual/cors/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
copy to third_party/blink/web_tests/platform/mac-mac10.12/virtual/cors/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/cors/external/wpt/fetch/api/abort/general.any.worker-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/cors/external/wpt/fetch/api/abort/general.any.worker-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/platform/mac-mac10.13/virtual/cors/external/wpt/fetch/api/abort/general.any.worker-expected.txt
rename to third_party/blink/web_tests/platform/mac-mac10.12/virtual/cors/external/wpt/fetch/api/abort/general.any.worker-expected.txt
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/platform/mac-mac10.14/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
rename to third_party/blink/web_tests/platform/mac-mac10.12/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.worker-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.worker-expected.txt
index 47a8c8da..5392aa4 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.worker-expected.txt
@@ -42,7 +42,7 @@
 FAIL Fetch aborted & connection closed when aborted after calling response.json() assert_equals: Connection is open expected "open" but got "closed"
 FAIL Fetch aborted & connection closed when aborted after calling response.text() assert_equals: Connection is open expected "open" but got "closed"
 PASS Stream errors once aborted. Underlying connection closed.
-PASS Stream errors once aborted, after reading. Underlying connection closed.
+FAIL Stream errors once aborted, after reading. Underlying connection closed. assert_unreached: Should have rejected: undefined Reached unreachable code
 PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
 FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
 PASS Signal state is cloned
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/cors/external/wpt/fetch/api/abort/general.any-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.13/external/wpt/fetch/api/abort/general.any-expected.txt
similarity index 100%
copy from third_party/blink/web_tests/platform/mac-mac10.11/virtual/cors/external/wpt/fetch/api/abort/general.any-expected.txt
copy to third_party/blink/web_tests/platform/mac-mac10.13/external/wpt/fetch/api/abort/general.any-expected.txt
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.13/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
rename to third_party/blink/web_tests/platform/mac-mac10.13/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/cors/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/platform/mac-mac10.13/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
rename to third_party/blink/web_tests/platform/mac-mac10.13/virtual/cors/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.worker-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.worker-expected.txt
index 5392aa4..47a8c8da 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.worker-expected.txt
@@ -42,7 +42,7 @@
 FAIL Fetch aborted & connection closed when aborted after calling response.json() assert_equals: Connection is open expected "open" but got "closed"
 FAIL Fetch aborted & connection closed when aborted after calling response.text() assert_equals: Connection is open expected "open" but got "closed"
 PASS Stream errors once aborted. Underlying connection closed.
-FAIL Stream errors once aborted, after reading. Underlying connection closed. assert_unreached: Should have rejected: undefined Reached unreachable code
+PASS Stream errors once aborted, after reading. Underlying connection closed.
 PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
 FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
 PASS Signal state is cloned
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/external/wpt/fetch/api/abort/general.any-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.14/external/wpt/fetch/api/abort/general.any-expected.txt
index 47a8c8da..5392aa4 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.14/external/wpt/fetch/api/abort/general.any-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/external/wpt/fetch/api/abort/general.any-expected.txt
@@ -42,7 +42,7 @@
 FAIL Fetch aborted & connection closed when aborted after calling response.json() assert_equals: Connection is open expected "open" but got "closed"
 FAIL Fetch aborted & connection closed when aborted after calling response.text() assert_equals: Connection is open expected "open" but got "closed"
 PASS Stream errors once aborted. Underlying connection closed.
-PASS Stream errors once aborted, after reading. Underlying connection closed.
+FAIL Stream errors once aborted, after reading. Underlying connection closed. assert_unreached: Should have rejected: undefined Reached unreachable code
 PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
 FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
 PASS Signal state is cloned
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/cors/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/platform/mac-mac10.14/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
rename to third_party/blink/web_tests/platform/mac-mac10.14/virtual/cors/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
diff --git a/third_party/blink/web_tests/platform/mac-retina/external/wpt/fetch/api/abort/general.any-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/platform/mac-retina/external/wpt/fetch/api/abort/general.any-expected.txt
rename to third_party/blink/web_tests/platform/mac-mac10.14/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any-expected.txt
diff --git a/third_party/blink/web_tests/platform/linux/virtual/cors/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt b/third_party/blink/web_tests/platform/mac-retina/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
similarity index 97%
rename from third_party/blink/web_tests/platform/linux/virtual/cors/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
rename to third_party/blink/web_tests/platform/mac-retina/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
index 5392aa4..50ca5c5c 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/cors/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-retina/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
@@ -34,7 +34,7 @@
 PASS Already aborted signal does not make request
 PASS Already aborted signal can be used for many fetches
 PASS Signal can be used to abort other fetches, even if another fetch succeeded before aborting
-FAIL Underlying connection is closed when aborting after receiving response assert_equals: Connection is open expected "open" but got "closed"
+FAIL Underlying connection is closed when aborting after receiving response assert_equals: Connection is open expected (string) "open" but got (object) null
 FAIL Underlying connection is closed when aborting after receiving response - no-cors assert_equals: Connection is open expected "open" but got "closed"
 FAIL Fetch aborted & connection closed when aborted after calling response.arrayBuffer() assert_equals: Connection is open expected "open" but got "closed"
 FAIL Fetch aborted & connection closed when aborted after calling response.blob() assert_equals: Connection is open expected "open" but got "closed"
diff --git a/third_party/blink/web_tests/platform/mac-retina/external/wpt/fetch/api/abort/general.any.worker-expected.txt b/third_party/blink/web_tests/platform/mac-retina/external/wpt/fetch/api/abort/general.any.worker-expected.txt
deleted file mode 100644
index 47a8c8da..0000000
--- a/third_party/blink/web_tests/platform/mac-retina/external/wpt/fetch/api/abort/general.any.worker-expected.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-This is a testharness.js-based test.
-PASS Aborting rejects with AbortError
-PASS Aborting rejects with AbortError - no-cors
-PASS TypeError from request constructor takes priority - RequestInit's window is not null
-PASS TypeError from request constructor takes priority - Input URL is not valid
-PASS TypeError from request constructor takes priority - Input URL has credentials
-PASS TypeError from request constructor takes priority - RequestInit's mode is navigate
-PASS TypeError from request constructor takes priority - RequestInit's referrer is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is forbidden
-PASS TypeError from request constructor takes priority - RequestInit's mode is no-cors and method is not simple
-PASS TypeError from request constructor takes priority - RequestInit's cache mode is only-if-cached and mode is not same-origin
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode cors
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode no-cors
-PASS TypeError from request constructor takes priority - Bad referrerPolicy init parameter value
-PASS TypeError from request constructor takes priority - Bad mode init parameter value
-PASS TypeError from request constructor takes priority - Bad credentials init parameter value
-PASS TypeError from request constructor takes priority - Bad cache init parameter value
-PASS TypeError from request constructor takes priority - Bad redirect init parameter value
-PASS Request objects have a signal property
-PASS Signal on request object
-PASS Signal on request object created from request object
-PASS Signal on request object created from request object, with signal on second request
-PASS Signal on request object created from request object, with signal on second request overriding another
-PASS Signal retained after unrelated properties are overridden by fetch
-PASS Signal removed by setting to null
-PASS Already aborted signal rejects immediately
-PASS Request is still 'used' if signal is aborted before fetching
-PASS response.arrayBuffer() rejects if already aborted
-PASS response.blob() rejects if already aborted
-PASS response.formData() rejects if already aborted
-PASS response.json() rejects if already aborted
-PASS response.text() rejects if already aborted
-PASS Already aborted signal does not make request
-PASS Already aborted signal can be used for many fetches
-PASS Signal can be used to abort other fetches, even if another fetch succeeded before aborting
-FAIL Underlying connection is closed when aborting after receiving response assert_equals: Connection is open expected "open" but got "closed"
-FAIL Underlying connection is closed when aborting after receiving response - no-cors assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.arrayBuffer() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.blob() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.formData() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.json() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.text() assert_equals: Connection is open expected "open" but got "closed"
-PASS Stream errors once aborted. Underlying connection closed.
-PASS Stream errors once aborted, after reading. Underlying connection closed.
-PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
-FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
-PASS Signal state is cloned
-PASS Clone aborts with original controller
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/cors/external/wpt/fetch/api/abort/general.any-expected.txt b/third_party/blink/web_tests/platform/mac-retina/virtual/cors/external/wpt/fetch/api/abort/general.any-expected.txt
deleted file mode 100644
index 47a8c8da..0000000
--- a/third_party/blink/web_tests/platform/mac-retina/virtual/cors/external/wpt/fetch/api/abort/general.any-expected.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-This is a testharness.js-based test.
-PASS Aborting rejects with AbortError
-PASS Aborting rejects with AbortError - no-cors
-PASS TypeError from request constructor takes priority - RequestInit's window is not null
-PASS TypeError from request constructor takes priority - Input URL is not valid
-PASS TypeError from request constructor takes priority - Input URL has credentials
-PASS TypeError from request constructor takes priority - RequestInit's mode is navigate
-PASS TypeError from request constructor takes priority - RequestInit's referrer is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is forbidden
-PASS TypeError from request constructor takes priority - RequestInit's mode is no-cors and method is not simple
-PASS TypeError from request constructor takes priority - RequestInit's cache mode is only-if-cached and mode is not same-origin
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode cors
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode no-cors
-PASS TypeError from request constructor takes priority - Bad referrerPolicy init parameter value
-PASS TypeError from request constructor takes priority - Bad mode init parameter value
-PASS TypeError from request constructor takes priority - Bad credentials init parameter value
-PASS TypeError from request constructor takes priority - Bad cache init parameter value
-PASS TypeError from request constructor takes priority - Bad redirect init parameter value
-PASS Request objects have a signal property
-PASS Signal on request object
-PASS Signal on request object created from request object
-PASS Signal on request object created from request object, with signal on second request
-PASS Signal on request object created from request object, with signal on second request overriding another
-PASS Signal retained after unrelated properties are overridden by fetch
-PASS Signal removed by setting to null
-PASS Already aborted signal rejects immediately
-PASS Request is still 'used' if signal is aborted before fetching
-PASS response.arrayBuffer() rejects if already aborted
-PASS response.blob() rejects if already aborted
-PASS response.formData() rejects if already aborted
-PASS response.json() rejects if already aborted
-PASS response.text() rejects if already aborted
-PASS Already aborted signal does not make request
-PASS Already aborted signal can be used for many fetches
-PASS Signal can be used to abort other fetches, even if another fetch succeeded before aborting
-FAIL Underlying connection is closed when aborting after receiving response assert_equals: Connection is open expected "open" but got "closed"
-FAIL Underlying connection is closed when aborting after receiving response - no-cors assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.arrayBuffer() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.blob() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.formData() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.json() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.text() assert_equals: Connection is open expected "open" but got "closed"
-PASS Stream errors once aborted. Underlying connection closed.
-PASS Stream errors once aborted, after reading. Underlying connection closed.
-PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
-FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
-PASS Signal state is cloned
-PASS Clone aborts with original controller
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/cors/external/wpt/fetch/api/abort/general.any.worker-expected.txt b/third_party/blink/web_tests/platform/mac-retina/virtual/cors/external/wpt/fetch/api/abort/general.any.worker-expected.txt
similarity index 100%
copy from third_party/blink/web_tests/platform/mac-mac10.13/virtual/cors/external/wpt/fetch/api/abort/general.any.worker-expected.txt
copy to third_party/blink/web_tests/platform/mac-retina/virtual/cors/external/wpt/fetch/api/abort/general.any.worker-expected.txt
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any-expected.txt b/third_party/blink/web_tests/platform/mac-retina/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any-expected.txt
similarity index 100%
copy from third_party/blink/web_tests/platform/mac-mac10.13/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any-expected.txt
copy to third_party/blink/web_tests/platform/mac-retina/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any-expected.txt
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt b/third_party/blink/web_tests/platform/mac-retina/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
index 5392aa4..47a8c8da 100644
--- a/third_party/blink/web_tests/platform/mac-retina/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-retina/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
@@ -42,7 +42,7 @@
 FAIL Fetch aborted & connection closed when aborted after calling response.json() assert_equals: Connection is open expected "open" but got "closed"
 FAIL Fetch aborted & connection closed when aborted after calling response.text() assert_equals: Connection is open expected "open" but got "closed"
 PASS Stream errors once aborted. Underlying connection closed.
-FAIL Stream errors once aborted, after reading. Underlying connection closed. assert_unreached: Should have rejected: undefined Reached unreachable code
+PASS Stream errors once aborted, after reading. Underlying connection closed.
 PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
 FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
 PASS Signal state is cloned
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/fetch/api/abort/general.any-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/fetch/api/abort/general.any-expected.txt
deleted file mode 100644
index 5392aa4..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/fetch/api/abort/general.any-expected.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-This is a testharness.js-based test.
-PASS Aborting rejects with AbortError
-PASS Aborting rejects with AbortError - no-cors
-PASS TypeError from request constructor takes priority - RequestInit's window is not null
-PASS TypeError from request constructor takes priority - Input URL is not valid
-PASS TypeError from request constructor takes priority - Input URL has credentials
-PASS TypeError from request constructor takes priority - RequestInit's mode is navigate
-PASS TypeError from request constructor takes priority - RequestInit's referrer is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is forbidden
-PASS TypeError from request constructor takes priority - RequestInit's mode is no-cors and method is not simple
-PASS TypeError from request constructor takes priority - RequestInit's cache mode is only-if-cached and mode is not same-origin
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode cors
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode no-cors
-PASS TypeError from request constructor takes priority - Bad referrerPolicy init parameter value
-PASS TypeError from request constructor takes priority - Bad mode init parameter value
-PASS TypeError from request constructor takes priority - Bad credentials init parameter value
-PASS TypeError from request constructor takes priority - Bad cache init parameter value
-PASS TypeError from request constructor takes priority - Bad redirect init parameter value
-PASS Request objects have a signal property
-PASS Signal on request object
-PASS Signal on request object created from request object
-PASS Signal on request object created from request object, with signal on second request
-PASS Signal on request object created from request object, with signal on second request overriding another
-PASS Signal retained after unrelated properties are overridden by fetch
-PASS Signal removed by setting to null
-PASS Already aborted signal rejects immediately
-PASS Request is still 'used' if signal is aborted before fetching
-PASS response.arrayBuffer() rejects if already aborted
-PASS response.blob() rejects if already aborted
-PASS response.formData() rejects if already aborted
-PASS response.json() rejects if already aborted
-PASS response.text() rejects if already aborted
-PASS Already aborted signal does not make request
-PASS Already aborted signal can be used for many fetches
-PASS Signal can be used to abort other fetches, even if another fetch succeeded before aborting
-FAIL Underlying connection is closed when aborting after receiving response assert_equals: Connection is open expected "open" but got "closed"
-FAIL Underlying connection is closed when aborting after receiving response - no-cors assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.arrayBuffer() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.blob() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.formData() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.json() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.text() assert_equals: Connection is open expected "open" but got "closed"
-PASS Stream errors once aborted. Underlying connection closed.
-FAIL Stream errors once aborted, after reading. Underlying connection closed. assert_unreached: Should have rejected: undefined Reached unreachable code
-PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
-FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
-PASS Signal state is cloned
-PASS Clone aborts with original controller
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/mac/fast/css/percent-top-relative-container-height-unspecified-expected.png b/third_party/blink/web_tests/platform/mac/fast/css/percent-top-relative-container-height-unspecified-expected.png
index a5bce7a..f430306 100644
--- a/third_party/blink/web_tests/platform/mac/fast/css/percent-top-relative-container-height-unspecified-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/css/percent-top-relative-container-height-unspecified-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/cors/external/wpt/fetch/api/abort/general.any-expected.txt b/third_party/blink/web_tests/platform/mac/virtual/cors/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
similarity index 98%
rename from third_party/blink/web_tests/platform/mac-mac10.14/virtual/cors/external/wpt/fetch/api/abort/general.any-expected.txt
rename to third_party/blink/web_tests/platform/mac/virtual/cors/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
index 47a8c8da..37378aa 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/cors/external/wpt/fetch/api/abort/general.any-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/virtual/cors/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
@@ -36,7 +36,7 @@
 PASS Signal can be used to abort other fetches, even if another fetch succeeded before aborting
 FAIL Underlying connection is closed when aborting after receiving response assert_equals: Connection is open expected "open" but got "closed"
 FAIL Underlying connection is closed when aborting after receiving response - no-cors assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.arrayBuffer() assert_equals: Connection is open expected "open" but got "closed"
+FAIL Fetch aborted & connection closed when aborted after calling response.arrayBuffer() assert_equals: Connection is open expected (string) "open" but got (object) null
 FAIL Fetch aborted & connection closed when aborted after calling response.blob() assert_equals: Connection is open expected "open" but got "closed"
 FAIL Fetch aborted & connection closed when aborted after calling response.formData() assert_equals: Connection is open expected "open" but got "closed"
 FAIL Fetch aborted & connection closed when aborted after calling response.json() assert_equals: Connection is open expected "open" but got "closed"
diff --git a/third_party/blink/web_tests/platform/mac/virtual/cors/external/wpt/fetch/api/abort/general.any.worker-expected.txt b/third_party/blink/web_tests/platform/mac/virtual/cors/external/wpt/fetch/api/abort/general.any.worker-expected.txt
deleted file mode 100644
index 47a8c8da..0000000
--- a/third_party/blink/web_tests/platform/mac/virtual/cors/external/wpt/fetch/api/abort/general.any.worker-expected.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-This is a testharness.js-based test.
-PASS Aborting rejects with AbortError
-PASS Aborting rejects with AbortError - no-cors
-PASS TypeError from request constructor takes priority - RequestInit's window is not null
-PASS TypeError from request constructor takes priority - Input URL is not valid
-PASS TypeError from request constructor takes priority - Input URL has credentials
-PASS TypeError from request constructor takes priority - RequestInit's mode is navigate
-PASS TypeError from request constructor takes priority - RequestInit's referrer is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is forbidden
-PASS TypeError from request constructor takes priority - RequestInit's mode is no-cors and method is not simple
-PASS TypeError from request constructor takes priority - RequestInit's cache mode is only-if-cached and mode is not same-origin
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode cors
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode no-cors
-PASS TypeError from request constructor takes priority - Bad referrerPolicy init parameter value
-PASS TypeError from request constructor takes priority - Bad mode init parameter value
-PASS TypeError from request constructor takes priority - Bad credentials init parameter value
-PASS TypeError from request constructor takes priority - Bad cache init parameter value
-PASS TypeError from request constructor takes priority - Bad redirect init parameter value
-PASS Request objects have a signal property
-PASS Signal on request object
-PASS Signal on request object created from request object
-PASS Signal on request object created from request object, with signal on second request
-PASS Signal on request object created from request object, with signal on second request overriding another
-PASS Signal retained after unrelated properties are overridden by fetch
-PASS Signal removed by setting to null
-PASS Already aborted signal rejects immediately
-PASS Request is still 'used' if signal is aborted before fetching
-PASS response.arrayBuffer() rejects if already aborted
-PASS response.blob() rejects if already aborted
-PASS response.formData() rejects if already aborted
-PASS response.json() rejects if already aborted
-PASS response.text() rejects if already aborted
-PASS Already aborted signal does not make request
-PASS Already aborted signal can be used for many fetches
-PASS Signal can be used to abort other fetches, even if another fetch succeeded before aborting
-FAIL Underlying connection is closed when aborting after receiving response assert_equals: Connection is open expected "open" but got "closed"
-FAIL Underlying connection is closed when aborting after receiving response - no-cors assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.arrayBuffer() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.blob() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.formData() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.json() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.text() assert_equals: Connection is open expected "open" but got "closed"
-PASS Stream errors once aborted. Underlying connection closed.
-PASS Stream errors once aborted, after reading. Underlying connection closed.
-PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
-FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
-PASS Signal state is cloned
-PASS Clone aborts with original controller
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/cors/external/wpt/fetch/api/abort/general.any.worker-expected.txt b/third_party/blink/web_tests/platform/mac/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.worker-expected.txt
similarity index 100%
copy from third_party/blink/web_tests/platform/mac-mac10.14/virtual/cors/external/wpt/fetch/api/abort/general.any.worker-expected.txt
copy to third_party/blink/web_tests/platform/mac/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.worker-expected.txt
diff --git a/third_party/blink/web_tests/platform/mac-retina/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/platform/mac-retina/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
rename to third_party/blink/web_tests/platform/win/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
diff --git a/third_party/blink/web_tests/platform/win/fast/css/percent-top-relative-container-height-unspecified-expected.png b/third_party/blink/web_tests/platform/win/fast/css/percent-top-relative-container-height-unspecified-expected.png
index 2b617f2e..0c3ad70 100644
--- a/third_party/blink/web_tests/platform/win/fast/css/percent-top-relative-container-height-unspecified-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/css/percent-top-relative-container-height-unspecified-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt b/third_party/blink/web_tests/platform/win/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
deleted file mode 100644
index 47a8c8da..0000000
--- a/third_party/blink/web_tests/platform/win/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-This is a testharness.js-based test.
-PASS Aborting rejects with AbortError
-PASS Aborting rejects with AbortError - no-cors
-PASS TypeError from request constructor takes priority - RequestInit's window is not null
-PASS TypeError from request constructor takes priority - Input URL is not valid
-PASS TypeError from request constructor takes priority - Input URL has credentials
-PASS TypeError from request constructor takes priority - RequestInit's mode is navigate
-PASS TypeError from request constructor takes priority - RequestInit's referrer is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is forbidden
-PASS TypeError from request constructor takes priority - RequestInit's mode is no-cors and method is not simple
-PASS TypeError from request constructor takes priority - RequestInit's cache mode is only-if-cached and mode is not same-origin
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode cors
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode no-cors
-PASS TypeError from request constructor takes priority - Bad referrerPolicy init parameter value
-PASS TypeError from request constructor takes priority - Bad mode init parameter value
-PASS TypeError from request constructor takes priority - Bad credentials init parameter value
-PASS TypeError from request constructor takes priority - Bad cache init parameter value
-PASS TypeError from request constructor takes priority - Bad redirect init parameter value
-PASS Request objects have a signal property
-PASS Signal on request object
-PASS Signal on request object created from request object
-PASS Signal on request object created from request object, with signal on second request
-PASS Signal on request object created from request object, with signal on second request overriding another
-PASS Signal retained after unrelated properties are overridden by fetch
-PASS Signal removed by setting to null
-PASS Already aborted signal rejects immediately
-PASS Request is still 'used' if signal is aborted before fetching
-PASS response.arrayBuffer() rejects if already aborted
-PASS response.blob() rejects if already aborted
-PASS response.formData() rejects if already aborted
-PASS response.json() rejects if already aborted
-PASS response.text() rejects if already aborted
-PASS Already aborted signal does not make request
-PASS Already aborted signal can be used for many fetches
-PASS Signal can be used to abort other fetches, even if another fetch succeeded before aborting
-FAIL Underlying connection is closed when aborting after receiving response assert_equals: Connection is open expected "open" but got "closed"
-FAIL Underlying connection is closed when aborting after receiving response - no-cors assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.arrayBuffer() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.blob() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.formData() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.json() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.text() assert_equals: Connection is open expected "open" but got "closed"
-PASS Stream errors once aborted. Underlying connection closed.
-PASS Stream errors once aborted, after reading. Underlying connection closed.
-PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
-FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
-PASS Signal state is cloned
-PASS Clone aborts with original controller
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/win/virtual/cors/external/wpt/fetch/api/abort/general.any.worker-expected.txt b/third_party/blink/web_tests/platform/win/virtual/cors/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/platform/win/virtual/cors/external/wpt/fetch/api/abort/general.any.worker-expected.txt
rename to third_party/blink/web_tests/platform/win/virtual/cors/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
diff --git a/third_party/blink/web_tests/platform/win/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt b/third_party/blink/web_tests/platform/win/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
deleted file mode 100644
index 47a8c8da..0000000
--- a/third_party/blink/web_tests/platform/win/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-This is a testharness.js-based test.
-PASS Aborting rejects with AbortError
-PASS Aborting rejects with AbortError - no-cors
-PASS TypeError from request constructor takes priority - RequestInit's window is not null
-PASS TypeError from request constructor takes priority - Input URL is not valid
-PASS TypeError from request constructor takes priority - Input URL has credentials
-PASS TypeError from request constructor takes priority - RequestInit's mode is navigate
-PASS TypeError from request constructor takes priority - RequestInit's referrer is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is forbidden
-PASS TypeError from request constructor takes priority - RequestInit's mode is no-cors and method is not simple
-PASS TypeError from request constructor takes priority - RequestInit's cache mode is only-if-cached and mode is not same-origin
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode cors
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode no-cors
-PASS TypeError from request constructor takes priority - Bad referrerPolicy init parameter value
-PASS TypeError from request constructor takes priority - Bad mode init parameter value
-PASS TypeError from request constructor takes priority - Bad credentials init parameter value
-PASS TypeError from request constructor takes priority - Bad cache init parameter value
-PASS TypeError from request constructor takes priority - Bad redirect init parameter value
-PASS Request objects have a signal property
-PASS Signal on request object
-PASS Signal on request object created from request object
-PASS Signal on request object created from request object, with signal on second request
-PASS Signal on request object created from request object, with signal on second request overriding another
-PASS Signal retained after unrelated properties are overridden by fetch
-PASS Signal removed by setting to null
-PASS Already aborted signal rejects immediately
-PASS Request is still 'used' if signal is aborted before fetching
-PASS response.arrayBuffer() rejects if already aborted
-PASS response.blob() rejects if already aborted
-PASS response.formData() rejects if already aborted
-PASS response.json() rejects if already aborted
-PASS response.text() rejects if already aborted
-PASS Already aborted signal does not make request
-PASS Already aborted signal can be used for many fetches
-PASS Signal can be used to abort other fetches, even if another fetch succeeded before aborting
-FAIL Underlying connection is closed when aborting after receiving response assert_equals: Connection is open expected "open" but got "closed"
-FAIL Underlying connection is closed when aborting after receiving response - no-cors assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.arrayBuffer() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.blob() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.formData() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.json() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.text() assert_equals: Connection is open expected "open" but got "closed"
-PASS Stream errors once aborted. Underlying connection closed.
-PASS Stream errors once aborted, after reading. Underlying connection closed.
-PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
-FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
-PASS Signal state is cloned
-PASS Clone aborts with original controller
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/win/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt b/third_party/blink/web_tests/platform/win/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
deleted file mode 100644
index 47a8c8da..0000000
--- a/third_party/blink/web_tests/platform/win/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-This is a testharness.js-based test.
-PASS Aborting rejects with AbortError
-PASS Aborting rejects with AbortError - no-cors
-PASS TypeError from request constructor takes priority - RequestInit's window is not null
-PASS TypeError from request constructor takes priority - Input URL is not valid
-PASS TypeError from request constructor takes priority - Input URL has credentials
-PASS TypeError from request constructor takes priority - RequestInit's mode is navigate
-PASS TypeError from request constructor takes priority - RequestInit's referrer is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is forbidden
-PASS TypeError from request constructor takes priority - RequestInit's mode is no-cors and method is not simple
-PASS TypeError from request constructor takes priority - RequestInit's cache mode is only-if-cached and mode is not same-origin
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode cors
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode no-cors
-PASS TypeError from request constructor takes priority - Bad referrerPolicy init parameter value
-PASS TypeError from request constructor takes priority - Bad mode init parameter value
-PASS TypeError from request constructor takes priority - Bad credentials init parameter value
-PASS TypeError from request constructor takes priority - Bad cache init parameter value
-PASS TypeError from request constructor takes priority - Bad redirect init parameter value
-PASS Request objects have a signal property
-PASS Signal on request object
-PASS Signal on request object created from request object
-PASS Signal on request object created from request object, with signal on second request
-PASS Signal on request object created from request object, with signal on second request overriding another
-PASS Signal retained after unrelated properties are overridden by fetch
-PASS Signal removed by setting to null
-PASS Already aborted signal rejects immediately
-PASS Request is still 'used' if signal is aborted before fetching
-PASS response.arrayBuffer() rejects if already aborted
-PASS response.blob() rejects if already aborted
-PASS response.formData() rejects if already aborted
-PASS response.json() rejects if already aborted
-PASS response.text() rejects if already aborted
-PASS Already aborted signal does not make request
-PASS Already aborted signal can be used for many fetches
-PASS Signal can be used to abort other fetches, even if another fetch succeeded before aborting
-FAIL Underlying connection is closed when aborting after receiving response assert_equals: Connection is open expected "open" but got "closed"
-FAIL Underlying connection is closed when aborting after receiving response - no-cors assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.arrayBuffer() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.blob() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.formData() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.json() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.text() assert_equals: Connection is open expected "open" but got "closed"
-PASS Stream errors once aborted. Underlying connection closed.
-PASS Stream errors once aborted, after reading. Underlying connection closed.
-PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
-FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
-PASS Signal state is cloned
-PASS Clone aborts with original controller
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/win7/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt b/third_party/blink/web_tests/platform/win7/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
deleted file mode 100644
index 47a8c8da..0000000
--- a/third_party/blink/web_tests/platform/win7/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-This is a testharness.js-based test.
-PASS Aborting rejects with AbortError
-PASS Aborting rejects with AbortError - no-cors
-PASS TypeError from request constructor takes priority - RequestInit's window is not null
-PASS TypeError from request constructor takes priority - Input URL is not valid
-PASS TypeError from request constructor takes priority - Input URL has credentials
-PASS TypeError from request constructor takes priority - RequestInit's mode is navigate
-PASS TypeError from request constructor takes priority - RequestInit's referrer is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is forbidden
-PASS TypeError from request constructor takes priority - RequestInit's mode is no-cors and method is not simple
-PASS TypeError from request constructor takes priority - RequestInit's cache mode is only-if-cached and mode is not same-origin
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode cors
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode no-cors
-PASS TypeError from request constructor takes priority - Bad referrerPolicy init parameter value
-PASS TypeError from request constructor takes priority - Bad mode init parameter value
-PASS TypeError from request constructor takes priority - Bad credentials init parameter value
-PASS TypeError from request constructor takes priority - Bad cache init parameter value
-PASS TypeError from request constructor takes priority - Bad redirect init parameter value
-PASS Request objects have a signal property
-PASS Signal on request object
-PASS Signal on request object created from request object
-PASS Signal on request object created from request object, with signal on second request
-PASS Signal on request object created from request object, with signal on second request overriding another
-PASS Signal retained after unrelated properties are overridden by fetch
-PASS Signal removed by setting to null
-PASS Already aborted signal rejects immediately
-PASS Request is still 'used' if signal is aborted before fetching
-PASS response.arrayBuffer() rejects if already aborted
-PASS response.blob() rejects if already aborted
-PASS response.formData() rejects if already aborted
-PASS response.json() rejects if already aborted
-PASS response.text() rejects if already aborted
-PASS Already aborted signal does not make request
-PASS Already aborted signal can be used for many fetches
-PASS Signal can be used to abort other fetches, even if another fetch succeeded before aborting
-FAIL Underlying connection is closed when aborting after receiving response assert_equals: Connection is open expected "open" but got "closed"
-FAIL Underlying connection is closed when aborting after receiving response - no-cors assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.arrayBuffer() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.blob() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.formData() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.json() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.text() assert_equals: Connection is open expected "open" but got "closed"
-PASS Stream errors once aborted. Underlying connection closed.
-PASS Stream errors once aborted, after reading. Underlying connection closed.
-PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
-FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
-PASS Signal state is cloned
-PASS Clone aborts with original controller
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/win7/virtual/cors/external/wpt/fetch/api/abort/general.any-expected.txt b/third_party/blink/web_tests/platform/win7/virtual/cors/external/wpt/fetch/api/abort/general.any-expected.txt
deleted file mode 100644
index 5392aa4..0000000
--- a/third_party/blink/web_tests/platform/win7/virtual/cors/external/wpt/fetch/api/abort/general.any-expected.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-This is a testharness.js-based test.
-PASS Aborting rejects with AbortError
-PASS Aborting rejects with AbortError - no-cors
-PASS TypeError from request constructor takes priority - RequestInit's window is not null
-PASS TypeError from request constructor takes priority - Input URL is not valid
-PASS TypeError from request constructor takes priority - Input URL has credentials
-PASS TypeError from request constructor takes priority - RequestInit's mode is navigate
-PASS TypeError from request constructor takes priority - RequestInit's referrer is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is invalid
-PASS TypeError from request constructor takes priority - RequestInit's method is forbidden
-PASS TypeError from request constructor takes priority - RequestInit's mode is no-cors and method is not simple
-PASS TypeError from request constructor takes priority - RequestInit's cache mode is only-if-cached and mode is not same-origin
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode cors
-PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode no-cors
-PASS TypeError from request constructor takes priority - Bad referrerPolicy init parameter value
-PASS TypeError from request constructor takes priority - Bad mode init parameter value
-PASS TypeError from request constructor takes priority - Bad credentials init parameter value
-PASS TypeError from request constructor takes priority - Bad cache init parameter value
-PASS TypeError from request constructor takes priority - Bad redirect init parameter value
-PASS Request objects have a signal property
-PASS Signal on request object
-PASS Signal on request object created from request object
-PASS Signal on request object created from request object, with signal on second request
-PASS Signal on request object created from request object, with signal on second request overriding another
-PASS Signal retained after unrelated properties are overridden by fetch
-PASS Signal removed by setting to null
-PASS Already aborted signal rejects immediately
-PASS Request is still 'used' if signal is aborted before fetching
-PASS response.arrayBuffer() rejects if already aborted
-PASS response.blob() rejects if already aborted
-PASS response.formData() rejects if already aborted
-PASS response.json() rejects if already aborted
-PASS response.text() rejects if already aborted
-PASS Already aborted signal does not make request
-PASS Already aborted signal can be used for many fetches
-PASS Signal can be used to abort other fetches, even if another fetch succeeded before aborting
-FAIL Underlying connection is closed when aborting after receiving response assert_equals: Connection is open expected "open" but got "closed"
-FAIL Underlying connection is closed when aborting after receiving response - no-cors assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.arrayBuffer() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.blob() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.formData() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.json() assert_equals: Connection is open expected "open" but got "closed"
-FAIL Fetch aborted & connection closed when aborted after calling response.text() assert_equals: Connection is open expected "open" but got "closed"
-PASS Stream errors once aborted. Underlying connection closed.
-FAIL Stream errors once aborted, after reading. Underlying connection closed. assert_unreached: Should have rejected: undefined Reached unreachable code
-PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
-FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
-PASS Signal state is cloned
-PASS Clone aborts with original controller
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/win7/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt b/third_party/blink/web_tests/platform/win7/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
index 5392aa4..47a8c8da 100644
--- a/third_party/blink/web_tests/platform/win7/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
+++ b/third_party/blink/web_tests/platform/win7/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
@@ -42,7 +42,7 @@
 FAIL Fetch aborted & connection closed when aborted after calling response.json() assert_equals: Connection is open expected "open" but got "closed"
 FAIL Fetch aborted & connection closed when aborted after calling response.text() assert_equals: Connection is open expected "open" but got "closed"
 PASS Stream errors once aborted. Underlying connection closed.
-FAIL Stream errors once aborted, after reading. Underlying connection closed. assert_unreached: Should have rejected: undefined Reached unreachable code
+PASS Stream errors once aborted, after reading. Underlying connection closed.
 PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
 FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
 PASS Signal state is cloned
diff --git a/third_party/blink/web_tests/platform/win7/virtual/cors/external/wpt/fetch/api/abort/general.any.worker-expected.txt b/third_party/blink/web_tests/platform/win7/virtual/cors/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/platform/win7/virtual/cors/external/wpt/fetch/api/abort/general.any.worker-expected.txt
rename to third_party/blink/web_tests/platform/win7/virtual/cors/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
diff --git a/third_party/blink/web_tests/platform/win7/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt b/third_party/blink/web_tests/platform/win7/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
index 743794e3..5392aa4 100644
--- a/third_party/blink/web_tests/platform/win7/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
+++ b/third_party/blink/web_tests/platform/win7/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
@@ -34,7 +34,7 @@
 PASS Already aborted signal does not make request
 PASS Already aborted signal can be used for many fetches
 PASS Signal can be used to abort other fetches, even if another fetch succeeded before aborting
-FAIL Underlying connection is closed when aborting after receiving response assert_equals: Connection is open expected (string) "open" but got (object) null
+FAIL Underlying connection is closed when aborting after receiving response assert_equals: Connection is open expected "open" but got "closed"
 FAIL Underlying connection is closed when aborting after receiving response - no-cors assert_equals: Connection is open expected "open" but got "closed"
 FAIL Fetch aborted & connection closed when aborted after calling response.arrayBuffer() assert_equals: Connection is open expected "open" but got "closed"
 FAIL Fetch aborted & connection closed when aborted after calling response.blob() assert_equals: Connection is open expected "open" but got "closed"
@@ -42,7 +42,7 @@
 FAIL Fetch aborted & connection closed when aborted after calling response.json() assert_equals: Connection is open expected "open" but got "closed"
 FAIL Fetch aborted & connection closed when aborted after calling response.text() assert_equals: Connection is open expected "open" but got "closed"
 PASS Stream errors once aborted. Underlying connection closed.
-PASS Stream errors once aborted, after reading. Underlying connection closed.
+FAIL Stream errors once aborted, after reading. Underlying connection closed. assert_unreached: Should have rejected: undefined Reached unreachable code
 PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
 FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
 PASS Signal state is cloned
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt b/third_party/blink/web_tests/platform/win7/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
similarity index 100%
copy from third_party/blink/web_tests/platform/win/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
copy to third_party/blink/web_tests/platform/win7/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any.sharedworker-expected.txt
diff --git a/third_party/blink/web_tests/resources/scrollbar-util.js b/third_party/blink/web_tests/resources/scrollbar-util.js
index 4cd6d04..2533b70 100644
--- a/third_party/blink/web_tests/resources/scrollbar-util.js
+++ b/third_party/blink/web_tests/resources/scrollbar-util.js
@@ -25,6 +25,14 @@
     return widthBefore - widthAfter;
 }
 
+// Returns the width of a acrollbar button. On platforms where there are no
+// scrollbar buttons (i.e. there are overlay scrollbars) returns 0.
+function calculateScrollbarButtonWidth() {
+    if (internals.overlayScrollbarsEnabled)
+        return 0;
+    return calculateScrollbarThickness();
+}
+
 // Resets scroll offsets (only supports LTR for now).
 function resetScrollOffset(scrollElement) {
   if(scrollElement !== undefined) {
@@ -90,6 +98,7 @@
   coordinates).
 */
 function downArrow(scroller) {
+  assert_true(!internals.overlayScrollbarsEnabled);
   const scrollerRect = scroller.getBoundingClientRect();
   const TRACK_WIDTH = calculateScrollbarThickness();
   const BUTTON_WIDTH = TRACK_WIDTH;
@@ -102,6 +111,7 @@
 }
 
 function upArrow(scroller) {
+  assert_true(!internals.overlayScrollbarsEnabled);
   const scrollerRect = scroller.getBoundingClientRect();
   const TRACK_WIDTH = calculateScrollbarThickness();
   const BUTTON_WIDTH = TRACK_WIDTH;
@@ -113,6 +123,7 @@
 }
 
 function leftArrow(scroller) {
+  assert_true(!internals.overlayScrollbarsEnabled);
   const scrollerRect = scroller.getBoundingClientRect();
   const TRACK_WIDTH = calculateScrollbarThickness();
   const BUTTON_WIDTH = TRACK_WIDTH;
@@ -124,6 +135,7 @@
 }
 
 function rightArrow(scroller) {
+  assert_true(!internals.overlayScrollbarsEnabled);
   const scrollerRect = scroller.getBoundingClientRect();
   const TRACK_WIDTH = calculateScrollbarThickness();
   const BUTTON_WIDTH = TRACK_WIDTH;
@@ -134,3 +146,22 @@
   };
   return cssClientToCssVisual(right_arrow);
 }
+
+// Returns a point that falls within the given scroller's vertical thumb part.
+function verticalThumb(scroller) {
+  assert_equals(scroller.scrollTop, 0, "verticalThumb() requires scroller to have scrollTop of 0");
+  const TRACK_WIDTH = calculateScrollbarThickness();
+  const BUTTON_WIDTH = calculateScrollbarButtonWidth();
+
+  if (scroller === document.documentElement) {
+    // HTML element is special, since scrollbars are not part of its client rect
+    // and page scale doesn't affect the scrollbars. Use window properties instead.
+    let x = window.innerWidth - TRACK_WIDTH / 2;
+    let y = BUTTON_WIDTH + 6;
+    return {x: x, y: y};
+  }
+  const scrollerRect = scroller.getBoundingClientRect();
+  const thumbPoint = { x : scrollerRect.right - TRACK_WIDTH / 2,
+                       y : scrollerRect.top + BUTTON_WIDTH + 2 };
+  return cssClientToCssVisual(thumbPoint);
+}
diff --git a/third_party/blink/web_tests/virtual/cascade/README.md b/third_party/blink/web_tests/virtual/cascade/README.md
deleted file mode 100644
index e33581a..0000000
--- a/third_party/blink/web_tests/virtual/cascade/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a virtual test suite for the Cascade Project.
-
-Flag: CSSCascade
-
-https://crbug.com/947004
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/fetch/api/abort/general.any-expected.txt b/third_party/blink/web_tests/virtual/cors/external/wpt/fetch/api/abort/general.any-expected.txt
similarity index 100%
copy from third_party/blink/web_tests/platform/win/external/wpt/fetch/api/abort/general.any-expected.txt
copy to third_party/blink/web_tests/virtual/cors/external/wpt/fetch/api/abort/general.any-expected.txt
diff --git a/third_party/blink/web_tests/platform/linux/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt b/third_party/blink/web_tests/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
similarity index 100%
copy from third_party/blink/web_tests/platform/linux/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
copy to third_party/blink/web_tests/virtual/cors/external/wpt/fetch/api/abort/general.any.serviceworker-expected.txt
diff --git a/third_party/blink/web_tests/virtual/forced-high-contrast-cascade/README.md b/third_party/blink/web_tests/virtual/forced-high-contrast-cascade/README.md
deleted file mode 100644
index 83e853c..0000000
--- a/third_party/blink/web_tests/virtual/forced-high-contrast-cascade/README.md
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a virtual test suite for the Cascade Project. It tests that
-forced-colors works when CSSCascade is enabled.
-
-Flags: CSSCascade,ForcedColors
-
-https://crbug.com/947004
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any-expected.txt b/third_party/blink/web_tests/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any-expected.txt
similarity index 100%
copy from third_party/blink/web_tests/platform/mac-mac10.13/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any-expected.txt
copy to third_party/blink/web_tests/virtual/omt-worker-fetch/external/wpt/fetch/api/abort/general.any-expected.txt
diff --git a/third_party/blink/web_tests/wpt_internal/serial/resources/serial-test-utils.js b/third_party/blink/web_tests/wpt_internal/serial/resources/serial-test-utils.js
index 60c972d..f5829657 100644
--- a/third_party/blink/web_tests/wpt_internal/serial/resources/serial-test-utils.js
+++ b/third_party/blink/web_tests/wpt_internal/serial/resources/serial-test-utils.js
@@ -28,7 +28,7 @@
   let actualLength = 0;
 
   while (true) {
-    let { value, done } = await reader.read();
+    let {value, done} = await reader.read();
     chunks.push(value);
     actualLength += value.byteLength;
 
@@ -69,7 +69,8 @@
   }
 
   cancel() {
-    this.watcher_.cancel();
+    if (this.watcher_)
+      this.watcher_.cancel();
     this.consumer_.close();
   }
 
@@ -93,15 +94,18 @@
   }
 
   async write(chunk, controller) {
-    let {result, numBytes} = this._producer.writeData(chunk);
-    if (result == Mojo.RESULT_OK) {
-      if (numBytes < chunk.byteLength)
-        return this.write(chunk.slice(numBytes), controller);
-    } else if (result == Mojo.RESULT_FAILED_PRECONDITION) {
-      throw new DOMException("The pipe is closed.", "InvalidStateError");
-    } else if (result == Mojo.RESULT_SHOULD_WAIT) {
-      await this.writable();
-      return this.write(chunk, controller);
+    while (true) {
+      let {result, numBytes} = this._producer.writeData(chunk);
+      if (result == Mojo.RESULT_OK) {
+        if (numBytes == chunk.byteLength) {
+          return;
+        }
+        chunk = chunk.slice(numBytes);
+      } else if (result == Mojo.RESULT_FAILED_PRECONDITION) {
+        throw new DOMException('The pipe is closed.', 'InvalidStateError');
+      } else if (result == Mojo.RESULT_SHOULD_WAIT) {
+        await this.writable();
+      }
     }
   }
 
@@ -145,14 +149,17 @@
   }
 
   write(data) {
-    this.writer_.write(data);
+    return this.writer_.write(data);
   }
 
-  async read() {
-    let reader = this.readable_.getReader();
-    let result = await reader.read();
-    reader.releaseLock();
-    return result;
+  read() {
+    return this.reader_.read();
+  }
+
+  // Reads from the port until at least |targetLength| is read or the stream is
+  // closed. The data is returned as a combined Uint8Array.
+  readWithLength(targetLength) {
+    return readWithLength(this.reader_, targetLength);
   }
 
   simulateReadError(error) {
@@ -172,7 +179,8 @@
   }
 
   simulateWriteError(error) {
-    this.readable_.cancel();
+    this.reader_.cancel();
+    this.reader_ = undefined;
     this.readable_ = undefined;
     this.client_.onSendError(error);
   }
@@ -229,6 +237,7 @@
 
   async startWriting(in_stream) {
     this.readable_ = new ReadableStream(new DataPipeSource(in_stream));
+    this.reader_ = this.readable_.getReader();
     if (this.readableResolver_) {
       this.readableResolver_();
       this.readableResolver_ = undefined;
@@ -246,8 +255,24 @@
     }
   }
 
-  async flush() {
-    return { success: false };
+  async flush(mode) {
+    switch (mode) {
+      case device.mojom.SerialPortFlushMode.kReceive:
+        this.writer_.abort();
+        this.writer_.releaseLock();
+        this.writer_ = undefined;
+        this.writable_ = undefined;
+        break;
+      case device.mojom.SerialPortFlushMode.kTransmit:
+        this.reader_.cancel();
+        this.reader_ = undefined;
+        this.readable_ = undefined;
+        break;
+    }
+  }
+
+  async drain() {
+    await this.reader_.closed;
   }
 
   async getControlSignals() {
diff --git a/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_cancel.https.window.js b/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_cancel.https.window.js
index 561f982..bc413b0 100644
--- a/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_cancel.https.window.js
+++ b/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_cancel.https.window.js
@@ -7,7 +7,6 @@
 
 serial_test(async (t, fake) => {
   const {port, fakePort} = await getFakeSerialPort(fake);
-  // Select a buffer size smaller than the amount of data transferred.
   await port.open({baudrate: 9600, buffersize: 64});
 
   const reader = port.readable.getReader();
@@ -19,3 +18,37 @@
 
   await port.close();
 }, 'Can cancel while reading');
+
+serial_test(async (t, fake) => {
+  const {port, fakePort} = await getFakeSerialPort(fake);
+  await port.open({baudrate: 9600, buffersize: 64});
+
+  const reader = port.readable.getReader();
+
+  await fakePort.writable();
+  const data = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
+  await fakePort.write(data);
+
+  await reader.cancel();
+  await port.close();
+}, 'Cancel discards a small amount of data waiting to be read');
+
+serial_test(async (t, fake) => {
+  const {port, fakePort} = await getFakeSerialPort(fake);
+  // Select a buffer size smaller than the amount of data transferred.
+  await port.open({baudrate: 9600, buffersize: 64});
+
+  const reader = port.readable.getReader();
+
+  await fakePort.writable();
+  const data = new Uint8Array(1024);
+  // Writing will fail because there was more data to send than could fit in the
+  // buffer and none of it was read.
+  const writePromise =
+      promise_rejects_dom(t, 'InvalidStateError', fakePort.write(data));
+
+  await reader.cancel();
+  await writePromise;
+
+  await port.close();
+}, 'Cancel discards a large amount of data waiting to be read');
diff --git a/third_party/blink/web_tests/wpt_internal/serial/serialPort_writable.https.window.js b/third_party/blink/web_tests/wpt_internal/serial/serialPort_writable.https.window.js
index 796ed6a..fc0978f0 100644
--- a/third_party/blink/web_tests/wpt_internal/serial/serialPort_writable.https.window.js
+++ b/third_party/blink/web_tests/wpt_internal/serial/serialPort_writable.https.window.js
@@ -45,7 +45,7 @@
   const writer = port.writable.getWriter();
   const data = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
   let writePromise = writer.write(data);
-  writer.close();
+  writer.releaseLock();
 
   await fakePort.readable();
   let {value, done} = await fakePort.read();
@@ -66,12 +66,10 @@
   for (let i = 0; i < data.byteLength; ++i)
     data[i] = i & 0xff;
   writer.write(data);
-  writer.close();
+  writer.releaseLock();
 
   await fakePort.readable();
-  const reader = fakePort.readable_.getReader();
-  const value = await readWithLength(reader, data.byteLength);
-  reader.releaseLock();
+  const value = await fakePort.readWithLength(data.byteLength);
   compareArrays(data, value);
 
   await port.close();
@@ -95,7 +93,7 @@
 
   writer = port.writable.getWriter();
   let writePromise = writer.write(data);
-  writer.close();
+  writer.releaseLock();
   await fakePort.readable();
   let {value, done} = await fakePort.read();
   await writePromise;
@@ -124,6 +122,64 @@
 serial_test(async (t, fake) => {
   const {port, fakePort} = await getFakeSerialPort(fake);
 
+  await port.open({baudrate: 9600, buffersize: 64});
+  const originalWritable = port.writable;
+  assert_true(originalWritable instanceof WritableStream);
+
+  let writer = originalWritable.getWriter();
+  let data = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
+  // The buffer size is large enough to allow this write to complete without
+  // the data being read from the fake port.
+  await writer.write(data);
+  await writer.abort();
+
+  assert_true(port.writable instanceof WritableStream);
+  assert_true(port.writable !== originalWritable);
+  writer = port.writable.getWriter();
+  data = new Uint8Array([9, 10, 11, 12, 13, 14, 15, 16]);
+  const writePromise = writer.write(data);
+  writer.releaseLock();
+
+  await fakePort.readable();
+  const {value, done} = await fakePort.read();
+  await writePromise;
+  compareArrays(value, data);
+
+  await port.close();
+  assert_equals(port.writable, null);
+}, 'abort() discards the write buffer');
+
+serial_test(async (t, fake) => {
+  const {port, fakePort} = await getFakeSerialPort(fake);
+  // Select a buffer size smaller than the amount of data transferred.
+  await port.open({baudrate: 9600, buffersize: 64});
+
+  const writer = port.writable.getWriter();
+  const data = new Uint8Array(1024);  // Much larger than buffersize above.
+  for (let i = 0; i < data.byteLength; ++i)
+    data[i] = i & 0xff;
+  writer.write(data);
+
+  let readComplete = false;
+  let writePromise = writer.close().then(() => {
+    assert_true(readComplete);
+  });
+
+  await fakePort.readable();
+  let readPromise = fakePort.readWithLength(data.byteLength).then(result => {
+    readComplete = true;
+    return result;
+  });
+  const value = await readPromise;
+  compareArrays(data, value);
+  await writePromise;
+
+  await port.close();
+}, 'close() waits for the write buffer to be cleared');
+
+serial_test(async (t, fake) => {
+  const {port, fakePort} = await getFakeSerialPort(fake);
+
   await port.open({baudrate: 9600});
   assert_true(port.writable instanceof WritableStream);
 
diff --git a/tools/directory_metadata/README.md b/tools/directory_metadata/README.md
deleted file mode 100644
index 26386d61..0000000
--- a/tools/directory_metadata/README.md
+++ /dev/null
@@ -1,52 +0,0 @@
-# Chromium METADATA files
-
-METADATA.chromium files are a source-focused mechanism by which owners can
-provide users of their code important information, including:
-
-* The team responsible for the code.
-* The Monorail component where bugs should be filed.
-* The OS type.
-
-METADATA.chromium files are structured protobuf files that are amenable to
-programmatic interaction.
-
-## Contents
-
-This directory contains the
-[proto definition](https://source.chromium.org/chromium/chromium/src/+/master:tools/directory_metadata/directory_metadata.proto)
-for METADATA.chromium files, which is the source of truth about
-METADATA.chromium file contents.
-
-Historical information can be found in the
-[original proposal](https://docs.google.com/document/d/17WMlceIMwge2ZiCvBWaBuk0w60YgieBd-ly3I8XsbzU/preview).
-
-## Usage
-
-METADATA.chromium files apply to all contents of a directory including its
-subdirectories.
-
-There is no inheritance mechanism, so any information in METADATA.chromium files
-in parent directories is ignored.
-
-For example, given the files below, the value of the `os` field for
-a/b/METADATA.chromium would be `OS_UNSPECIFIED` regardless of the contents of
-a/METADATA.chromium.
-
-**a/METADATA.chromium**
-```
-monorail {
-  project: "chromium"
-  component: "Component"
-}
-team_email: "team@chromium.org"
-os: OS_LINUX
-```
-
-**a/b/METADATA.chromium**
-```
-monorail {
-  project: "chromium"
-  component: "Component>Foo"
-}
-team_email: "foo-team@chromium.org"
-```
diff --git a/tools/directory_metadata/directory_metadata.proto b/tools/directory_metadata/directory_metadata.proto
deleted file mode 100644
index 07be50b..0000000
--- a/tools/directory_metadata/directory_metadata.proto
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-syntax = "proto3";
-
-// Metadata information for a directory.
-message Metadata {
-  // Monorail metadata. Its component field should always map to the same
-  // team_email field (see below) for every directory that it is listed in.
-  Monorail monorail = 1;
-  // The team responsible for the directory. Only a single email is allowed.
-  // For example, “team-email@chromium.org”.
-  string team_email = 2;
-  // The code in this directory is specific to this OS.
-  OS os = 3;
-  // Whether wpt-importer should notify the team about new failures.
-  bool wpt_notify = 4;
-  // Reserved for metadata information for third-party code. See
-  // https://opensource.google/docs/thirdparty/metadata/
-  reserved 13;
-  reserved "third_party";
-}
-
-// Supported OS to tag a directory.
-enum OS {
-  OS_UNSPECIFIED = 0;
-  OS_LINUX = 1;
-  OS_WINDOWS = 2;
-  OS_MAC = 3;
-  OS_ANDROID = 4;
-  OS_IOS = 5;
-  OS_CHROME = 6;
-  OS_FUCHSIA = 7;
-}
-
-// Monorail specific metadata.
-message Monorail {
-  // The Monorail project. For example, “chromium”.
-  string project = 1;
-  // The Monorail component. For example, “UI>Browser>Zoom”.
-  // Only a single component is allowed.
-  string component = 2;
-}
diff --git a/tools/directory_metadata/directory_metadata_pb2.py b/tools/directory_metadata/directory_metadata_pb2.py
deleted file mode 100644
index 3847d2d..0000000
--- a/tools/directory_metadata/directory_metadata_pb2.py
+++ /dev/null
@@ -1,195 +0,0 @@
-# Generated by the protocol buffer compiler.  DO NOT EDIT!
-# source: directory_metadata.proto
-
-import sys
-_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
-from google.protobuf.internal import enum_type_wrapper
-from google.protobuf import descriptor as _descriptor
-from google.protobuf import message as _message
-from google.protobuf import reflection as _reflection
-from google.protobuf import symbol_database as _symbol_database
-# @@protoc_insertion_point(imports)
-
-_sym_db = _symbol_database.Default()
-
-
-
-
-DESCRIPTOR = _descriptor.FileDescriptor(
-  name='directory_metadata.proto',
-  package='',
-  syntax='proto3',
-  serialized_options=None,
-  serialized_pb=_b('\n\x18\x64irectory_metadata.proto\"s\n\x08Metadata\x12\x1b\n\x08monorail\x18\x01 \x01(\x0b\x32\t.Monorail\x12\x12\n\nteam_email\x18\x02 \x01(\t\x12\x0f\n\x02os\x18\x03 \x01(\x0e\x32\x03.OS\x12\x12\n\nwpt_notify\x18\x04 \x01(\x08J\x04\x08\r\x10\x0eR\x0bthird_party\".\n\x08Monorail\x12\x0f\n\x07project\x18\x01 \x01(\t\x12\x11\n\tcomponent\x18\x02 \x01(\t*}\n\x02OS\x12\x12\n\x0eOS_UNSPECIFIED\x10\x00\x12\x0c\n\x08OS_LINUX\x10\x01\x12\x0e\n\nOS_WINDOWS\x10\x02\x12\n\n\x06OS_MAC\x10\x03\x12\x0e\n\nOS_ANDROID\x10\x04\x12\n\n\x06OS_IOS\x10\x05\x12\r\n\tOS_CHROME\x10\x06\x12\x0e\n\nOS_FUCHSIA\x10\x07\x62\x06proto3')
-)
-
-_OS = _descriptor.EnumDescriptor(
-  name='OS',
-  full_name='OS',
-  filename=None,
-  file=DESCRIPTOR,
-  values=[
-    _descriptor.EnumValueDescriptor(
-      name='OS_UNSPECIFIED', index=0, number=0,
-      serialized_options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='OS_LINUX', index=1, number=1,
-      serialized_options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='OS_WINDOWS', index=2, number=2,
-      serialized_options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='OS_MAC', index=3, number=3,
-      serialized_options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='OS_ANDROID', index=4, number=4,
-      serialized_options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='OS_IOS', index=5, number=5,
-      serialized_options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='OS_CHROME', index=6, number=6,
-      serialized_options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='OS_FUCHSIA', index=7, number=7,
-      serialized_options=None,
-      type=None),
-  ],
-  containing_type=None,
-  serialized_options=None,
-  serialized_start=193,
-  serialized_end=318,
-)
-_sym_db.RegisterEnumDescriptor(_OS)
-
-OS = enum_type_wrapper.EnumTypeWrapper(_OS)
-OS_UNSPECIFIED = 0
-OS_LINUX = 1
-OS_WINDOWS = 2
-OS_MAC = 3
-OS_ANDROID = 4
-OS_IOS = 5
-OS_CHROME = 6
-OS_FUCHSIA = 7
-
-
-
-_METADATA = _descriptor.Descriptor(
-  name='Metadata',
-  full_name='Metadata',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='monorail', full_name='Metadata.monorail', index=0,
-      number=1, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='team_email', full_name='Metadata.team_email', index=1,
-      number=2, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='os', full_name='Metadata.os', index=2,
-      number=3, type=14, cpp_type=8, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='wpt_notify', full_name='Metadata.wpt_notify', index=3,
-      number=4, type=8, cpp_type=7, label=1,
-      has_default_value=False, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  serialized_options=None,
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=28,
-  serialized_end=143,
-)
-
-
-_MONORAIL = _descriptor.Descriptor(
-  name='Monorail',
-  full_name='Monorail',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='project', full_name='Monorail.project', index=0,
-      number=1, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='component', full_name='Monorail.component', index=1,
-      number=2, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  serialized_options=None,
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=145,
-  serialized_end=191,
-)
-
-_METADATA.fields_by_name['monorail'].message_type = _MONORAIL
-_METADATA.fields_by_name['os'].enum_type = _OS
-DESCRIPTOR.message_types_by_name['Metadata'] = _METADATA
-DESCRIPTOR.message_types_by_name['Monorail'] = _MONORAIL
-DESCRIPTOR.enum_types_by_name['OS'] = _OS
-_sym_db.RegisterFileDescriptor(DESCRIPTOR)
-
-Metadata = _reflection.GeneratedProtocolMessageType('Metadata', (_message.Message,), dict(
-  DESCRIPTOR = _METADATA,
-  __module__ = 'directory_metadata_pb2'
-  # @@protoc_insertion_point(class_scope:Metadata)
-  ))
-_sym_db.RegisterMessage(Metadata)
-
-Monorail = _reflection.GeneratedProtocolMessageType('Monorail', (_message.Message,), dict(
-  DESCRIPTOR = _MONORAIL,
-  __module__ = 'directory_metadata_pb2'
-  # @@protoc_insertion_point(class_scope:Monorail)
-  ))
-_sym_db.RegisterMessage(Monorail)
-
-
-# @@protoc_insertion_point(module_scope)
diff --git a/tools/json_schema_compiler/feature_compiler.py b/tools/json_schema_compiler/feature_compiler.py
index abe870e6..fbdeaf6 100644
--- a/tools/json_schema_compiler/feature_compiler.py
+++ b/tools/json_schema_compiler/feature_compiler.py
@@ -8,6 +8,7 @@
 import copy
 from datetime import datetime
 from functools import partial
+import json
 import os
 import re
 import sys
@@ -67,6 +68,10 @@
 }  // namespace extensions
 """
 
+# Legacy keys for the allow and blocklists.
+LEGACY_ALLOWLIST_KEY = 'whitelist'
+LEGACY_BLOCKLIST_KEY = 'blacklist'
+
 # Returns true if the list 'l' only contains strings that are a hex-encoded SHA1
 # hashes.
 def ListContainsOnlySha1Hashes(l):
@@ -119,7 +124,7 @@
         str: {},
         'shared': True
     },
-    'blacklist': {
+    LEGACY_BLOCKLIST_KEY: {
         list: {
             'subtype':
             str,
@@ -168,8 +173,8 @@
     },
     'dependencies': {
         list: {
-            # We allow an empty list of dependencies for child features that want
-            # to override their parents' dependency set.
+            # We allow an empty list of dependencies for child features that
+            # want to override their parents' dependency set.
             'allow_empty': True,
             'subtype': str
         }
@@ -254,7 +259,7 @@
         str: {},
         'shared': True
     },
-    'whitelist': {
+    LEGACY_ALLOWLIST_KEY: {
         list: {
             'subtype':
             str,
@@ -309,6 +314,61 @@
     return True
   return reverse_reference_value == ('"%s"' % feature.name)
 
+# Verifies that a feature with an allowlist is not available to hosted apps,
+# returning true on success.
+def DoesNotHaveAllowlistForHostedApps(value):
+  if not LEGACY_ALLOWLIST_KEY in value:
+    return True
+
+  # Hack Alert: |value| here has the code for the generated C++ feature. Since
+  # we're looking at the individual values, we do a bit of yucky back-parsing
+  # to get a better look at the feature. This would be cleaner if we were
+  # operating on the JSON feature itself, but we currently never generate a
+  # JSON-based feature object that has all the values inherited from its
+  # parents. Since this is the only scenario we need this type of validation,
+  # doing it in a slightly ugly way isn't too bad. If we need more of these,
+  # we should find a smoother way to do it (e.g. first generate JSON-based
+  # features with inherited properties, do any necessary validation, then
+  # generate the C++ code strings).
+
+  # The feature did not specify extension types; this is fine for e.g.
+  # API features (which would typically rely on a permission feature, which
+  # is required to specify types).
+  if not 'extension_types' in value:
+    return True
+
+  types = value['extension_types']
+  # |types| looks like "{Manifest::TYPE_1, Manifest::TYPE_2}", so just looking
+  # for the "TYPE_HOSTED_APP substring is sufficient.
+  if 'TYPE_HOSTED_APP' not in types:
+    return True
+
+  # Helper to convert our C++ string array like "{\"aaa\", \"bbb\"}" (which is
+  # what the allowlist looks like) to a python list of strings.
+  def cpp_list_to_list(cpp_list):
+    assert type(cpp_list) is str
+    assert cpp_list[0] is '{'
+    assert cpp_list[-1] is '}'
+    new_list = json.loads('[%s]' % cpp_list[1:-1])
+    assert type(new_list) is list
+    return new_list
+
+  # Exceptions (see the feature files).
+  # DO NOT ADD MORE.
+  HOSTED_APP_EXCEPTIONS = [
+      '99060B01DE911EB85FD630C8BA6320C9186CA3AB',
+      'B44D08FD98F1523ED5837D78D0A606EA9D6206E5',
+      '2653F6F6C39BC6EEBD36A09AFB92A19782FF7EB4',
+  ]
+
+  allowlist = cpp_list_to_list(value[LEGACY_ALLOWLIST_KEY])
+  for entry in allowlist:
+    if entry not in HOSTED_APP_EXCEPTIONS:
+      return False
+
+  return True
+
+
 SIMPLE_FEATURE_CPP_CLASSES = ({
   'APIFeature': 'SimpleFeature',
   'ManifestFeature': 'ManifestFeature',
@@ -320,6 +380,8 @@
   'all': [
     (partial(HasAtLeastOneProperty, ['channel', 'dependencies']),
      'Features must specify either a channel or dependencies'),
+    (DoesNotHaveAllowlistForHostedApps,
+     'Hosted apps are not allowed to use restricted features')
   ],
   'APIFeature': [
     (partial(HasProperty, 'contexts'),
@@ -388,10 +450,10 @@
 
     # TODO(devlin): Remove this hack as part of 842387.
     set_key = key
-    if key == "whitelist":
-      set_key = "allowlist"
-    elif key == "blacklist":
-      set_key = "blocklist"
+    if key == LEGACY_ALLOWLIST_KEY:
+      set_key = 'allowlist'
+    elif key == LEGACY_BLOCKLIST_KEY:
+      set_key = 'blocklist'
 
     c.Append('feature->set_%s(%s);' % (set_key, feature_values[key]))
   return c
diff --git a/tools/json_schema_compiler/feature_compiler_test.py b/tools/json_schema_compiler/feature_compiler_test.py
index e7874cb9..43c3762 100755
--- a/tools/json_schema_compiler/feature_compiler_test.py
+++ b/tools/json_schema_compiler/feature_compiler_test.py
@@ -371,6 +371,64 @@
     self._hasError(
         f, 'list should only have hex-encoded SHA1 hashes of extension ids')
 
+  def testHostedAppsCantUseAllowlistedFeatures_SimpleFeature(self):
+    f = self._parseFeature({
+        'extension_types': ['extension', 'hosted_app'],
+        'whitelist': ['0123456789ABCDEF0123456789ABCDEF01234567'],
+        'channel': 'beta',
+    })
+    f.Validate('PermissionFeature', {})
+    self._hasError(f, 'Hosted apps are not allowed to use restricted features')
+
+  def testHostedAppsCantUseAllowlistedFeatures_ComplexFeature(self):
+    c = feature_compiler.FeatureCompiler(
+        None, None, 'PermissionFeature', None, None, None)
+    c._CompileFeature('invalid_feature',
+        [{
+          'extension_types': ['extension'],
+          'channel': 'beta',
+        }, {
+          'channel': 'beta',
+          'extension_types': ['hosted_app'],
+          'whitelist': ['0123456789ABCDEF0123456789ABCDEF01234567'],
+        }])
+    c._CompileFeature('valid_feature',
+        [{
+          'extension_types': ['extension'],
+          'channel': 'beta',
+          'whitelist': ['0123456789ABCDEF0123456789ABCDEF01234567'],
+        }, {
+          'channel': 'beta',
+          'extension_types': ['hosted_app'],
+        }])
+
+    valid_feature = c._features.get('valid_feature')
+    self.assertTrue(valid_feature)
+    self.assertFalse(valid_feature.GetErrors())
+
+    invalid_feature = c._features.get('invalid_feature')
+    self.assertTrue(invalid_feature)
+    self._hasError(invalid_feature,
+                   'Hosted apps are not allowed to use restricted features')
+
+
+  def testHostedAppsCantUseAllowlistedFeatures_ChildFeature(self):
+    c = feature_compiler.FeatureCompiler(
+        None, None, 'PermissionFeature', None, None, None)
+    c._CompileFeature('parent',
+        {
+          'extension_types': ['hosted_app'],
+          'channel': 'beta',
+        })
+
+    c._CompileFeature('parent.child',
+        {
+          'whitelist': ['0123456789ABCDEF0123456789ABCDEF01234567']
+        })
+    feature = c._features.get('parent.child')
+    self.assertTrue(feature)
+    self._hasError(feature,
+                   'Hosted apps are not allowed to use restricted features')
 
 if __name__ == '__main__':
   unittest.main()
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 8fb5fc1..5451e3d 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -821,11 +821,11 @@
     },
 
     'tryserver.chromium.codesearch': {
-      'codesearch-gen-chromium-android-try': 'codesearch_gen_chromium_android_bot',
-      'codesearch-gen-chromium-chromiumos-try': 'codesearch_gen_chromium_chromiumos_bot',
-      'codesearch-gen-chromium-fuchsia-try': 'codesearch_gen_chromium_fuchsia_bot',
-      'codesearch-gen-chromium-linux-try': 'codesearch_gen_chromium_bot',
-      'codesearch-gen-chromium-win-try': 'codesearch_gen_chromium_bot',
+      'gen-android-try': 'codesearch_gen_chromium_android_bot',
+      'gen-chromiumos-try': 'codesearch_gen_chromium_chromiumos_bot',
+      'gen-fuchsia-try': 'codesearch_gen_chromium_fuchsia_bot',
+      'gen-linux-try': 'codesearch_gen_chromium_bot',
+      'gen-win-try': 'codesearch_gen_chromium_bot',
     },
 
     'tryserver.chromium.dawn': {
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 7b2860a..6d03f2291 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -25578,7 +25578,7 @@
 </histogram>
 
 <histogram name="Chrome.MessageLoopProblem" enum="MessageLoopProblems"
-    expires_after="M86">
+    expires_after="2021-07-31">
   <owner>fdoray@chromium.org</owner>
   <owner>gab@chromium.org</owner>
   <summary>
@@ -67976,7 +67976,6 @@
     expires_after="2020-02-16">
   <owner>sky@chromium.org</owner>
   <owner>mpearson@chromium.org</owner>
-  <owner>gab@chromium.org</owner>
   <summary>
     Number of items in in-memory keyword_search_terms table. Recorded on profile
     open.
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 7b6cf35..0f719dc 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -1,16 +1,16 @@
 {
     "trace_processor_shell": {
         "win": {
-            "hash": "2ccd0e79a314e7ee6f6541d707cf5a0018768287",
-            "remote_path": "perfetto_binaries/trace_processor_shell/win/c0f23a129f67b27198beac0193cb16814d36485a/trace_processor_shell.exe"
+            "hash": "2764aecc271e8b45a4cb1c5df71627d99502ddb9",
+            "remote_path": "perfetto_binaries/trace_processor_shell/win/0997f358ce073f83d6a4bba44ffce2d772077577/trace_processor_shell.exe"
         },
         "mac": {
-            "hash": "a66f305fecc7fac84c46bc5556c317c9fd0fb4bd",
-            "remote_path": "perfetto_binaries/trace_processor_shell/mac/c0f23a129f67b27198beac0193cb16814d36485a/trace_processor_shell"
+            "hash": "585a35a5bb0157912bdbc75d9636d158745417a3",
+            "remote_path": "perfetto_binaries/trace_processor_shell/mac/0997f358ce073f83d6a4bba44ffce2d772077577/trace_processor_shell"
         },
         "linux": {
-            "hash": "580d7c6bd17f3c70bb84c283ec28191196e03451",
-            "remote_path": "perfetto_binaries/trace_processor_shell/linux/c0f23a129f67b27198beac0193cb16814d36485a/trace_processor_shell"
+            "hash": "db2aac375f29db374ad7aa1d26412d873aea0508",
+            "remote_path": "perfetto_binaries/trace_processor_shell/linux/0997f358ce073f83d6a4bba44ffce2d772077577/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/ui/base/models/menu_model.cc b/ui/base/models/menu_model.cc
index 40f1e40..3207075 100644
--- a/ui/base/models/menu_model.cc
+++ b/ui/base/models/menu_model.cc
@@ -19,6 +19,10 @@
   return true;
 }
 
+bool MenuModel::IsAlertedAt(int index) const {
+  return false;
+}
+
 bool MenuModel::IsNewFeatureAt(int index) const {
   return false;
 }
diff --git a/ui/base/models/menu_model.h b/ui/base/models/menu_model.h
index 4c08fbf..c746b37 100644
--- a/ui/base/models/menu_model.h
+++ b/ui/base/models/menu_model.h
@@ -113,6 +113,10 @@
   // Returns true if the menu item is visible.
   virtual bool IsVisibleAt(int index) const;
 
+  // Returns true if the item is rendered specially to draw attention
+  // for in-product help.
+  virtual bool IsAlertedAt(int index) const;
+
   // Returns true if the menu item grants access to a new feature that we want
   // to show off to users (items marked as new will receive a "New" badge when
   // the appropriate flag is enabled).
diff --git a/ui/base/models/simple_menu_model.cc b/ui/base/models/simple_menu_model.cc
index 1fc029c..0c37f6e2 100644
--- a/ui/base/models/simple_menu_model.cc
+++ b/ui/base/models/simple_menu_model.cc
@@ -39,6 +39,10 @@
   return true;
 }
 
+bool SimpleMenuModel::Delegate::IsCommandIdAlerted(int command_id) const {
+  return false;
+}
+
 bool SimpleMenuModel::Delegate::IsItemForCommandIdDynamic(
     int command_id) const {
   return false;
@@ -436,6 +440,14 @@
          items_[ValidateItemIndex(index)].visible;
 }
 
+bool SimpleMenuModel::IsAlertedAt(int index) const {
+  const int command_id = GetCommandIdAt(index);
+  if (!delegate_ || command_id == kSeparatorId || command_id == kTitleId)
+    return false;
+
+  return delegate_->IsCommandIdAlerted(command_id);
+}
+
 bool SimpleMenuModel::IsNewFeatureAt(int index) const {
   return items_[ValidateItemIndex(index)].is_new_feature;
 }
diff --git a/ui/base/models/simple_menu_model.h b/ui/base/models/simple_menu_model.h
index 3067f9b..5f1116b 100644
--- a/ui/base/models/simple_menu_model.h
+++ b/ui/base/models/simple_menu_model.h
@@ -41,6 +41,10 @@
     // Delegate should return true if |command_id| should be visible.
     virtual bool IsCommandIdVisible(int command_id) const;
 
+    // Determines if |command_id| should be rendered with an alert for
+    // in-product help.
+    virtual bool IsCommandIdAlerted(int command_id) const;
+
     // Some command ids have labels and icons that change over time.
     virtual bool IsItemForCommandIdDynamic(int command_id) const;
     virtual base::string16 GetLabelForCommandId(int command_id) const;
@@ -186,6 +190,7 @@
   ui::ButtonMenuItemModel* GetButtonMenuItemAt(int index) const override;
   bool IsEnabledAt(int index) const override;
   bool IsVisibleAt(int index) const override;
+  bool IsAlertedAt(int index) const override;
   bool IsNewFeatureAt(int index) const override;
   void ActivatedAt(int index) override;
   void ActivatedAt(int index, int event_flags) override;
diff --git a/ui/base/models/simple_menu_model_unittest.cc b/ui/base/models/simple_menu_model_unittest.cc
index cbab6c3..b38debbc 100644
--- a/ui/base/models/simple_menu_model_unittest.cc
+++ b/ui/base/models/simple_menu_model_unittest.cc
@@ -16,6 +16,8 @@
 
 namespace {
 
+constexpr int kAlertedCommandId = 2;
+
 class DelegateBase : public SimpleMenuModel::Delegate {
  public:
   DelegateBase() : SimpleMenuModel::Delegate() {}
@@ -37,6 +39,10 @@
     return command_id < 100;
   }
 
+  bool IsCommandIdAlerted(int command_id) const override {
+    return command_id == kAlertedCommandId;
+  }
+
   void ExecuteCommand(int command_id, int event_flags) override {}
 
   bool IsItemForCommandIdDynamic(int command_id) const override {
@@ -147,6 +153,18 @@
   ASSERT_FALSE(simple_menu_model.IsEnabledAt(0));
 }
 
+TEST(SimpleMenuModelTest, IsAlertedAtViaDelegate) {
+  DelegateBase delegate;
+  SimpleMenuModel simple_menu_model(&delegate);
+  simple_menu_model.AddItem(kAlertedCommandId,
+                            base::ASCIIToUTF16("alerted item"));
+  simple_menu_model.AddItem(kAlertedCommandId + 1,
+                            base::ASCIIToUTF16("non-alerted item"));
+
+  EXPECT_TRUE(simple_menu_model.IsAlertedAt(0));
+  EXPECT_FALSE(simple_menu_model.IsAlertedAt(1));
+}
+
 TEST(SimpleMenuModelTest, SetIsNewFeatureAt) {
   SimpleMenuModel simple_menu_model(nullptr);
   simple_menu_model.AddItem(/*command_id*/ 5,
diff --git a/ui/views/OWNERS b/ui/views/OWNERS
index 0489f00..08b8b933 100644
--- a/ui/views/OWNERS
+++ b/ui/views/OWNERS
@@ -1,4 +1,8 @@
-# Prefer tapted@ for mac specific changes.
+# Note: Unless you want a specific reviewer's expertise, please send CLs to
+# chromium-ui-views-reviews@google.com rather than to specific individuals.
+# These CLs will be automatically reassigned to a reviewer within about
+# 5 minutes. This approach helps our team to load-balance incoming reviews.
+# Googlers can read more about this at go/gwsq-gerrit.
 
 kylixrd@chromium.org
 msw@chromium.org
@@ -9,7 +13,7 @@
 tapted@chromium.org
 weili@chromium.org
 
-# Prefer ellyjones@ for any changes to these files.
+# Prefer ellyjones@ or tapted@ for mac specific changes.
 per-file *_mac.*=ellyjones@chromium.org
 per-file *_cocoa.*=ellyjones@chromium.org
 per-file *.mm=ellyjones@chromium.org
diff --git a/ui/views/bubble/bubble_dialog_delegate_view.cc b/ui/views/bubble/bubble_dialog_delegate_view.cc
index e2d0136..adbad16 100644
--- a/ui/views/bubble/bubble_dialog_delegate_view.cc
+++ b/ui/views/bubble/bubble_dialog_delegate_view.cc
@@ -344,7 +344,7 @@
   if (CustomShadowsSupported() && GetParams().round_corners) {
     border->SetCornerRadius(
         base::FeatureList::IsEnabled(features::kEnableMDRoundedCornersOnDialogs)
-            ? provider->GetCornerRadiusMetric(views::EMPHASIS_HIGH)
+            ? provider->GetCornerRadiusMetric(views::EMPHASIS_MEDIUM)
             : 2);
   }
 
diff --git a/ui/views/controls/menu/menu_model_adapter.cc b/ui/views/controls/menu/menu_model_adapter.cc
index 7d0d04e..b0b1cf9 100644
--- a/ui/views/controls/menu/menu_model_adapter.cc
+++ b/ui/views/controls/menu/menu_model_adapter.cc
@@ -118,7 +118,11 @@
       icon.IsVectorIcon() ? ui::ThemedVectorIcon(icon.GetVectorIcon())
                           : ui::ThemedVectorIcon(),
       *type, ui::NORMAL_SEPARATOR);
+
+  if (model->IsAlertedAt(model_index))
+    menu_item_view->SetAlerted();
   menu_item_view->set_is_new(model->IsNewFeatureAt(model_index));
+
   return menu_item_view;
 }
 
diff --git a/ui/views/controls/menu/menu_model_adapter_unittest.cc b/ui/views/controls/menu/menu_model_adapter_unittest.cc
index 377ef30..111b070d 100644
--- a/ui/views/controls/menu/menu_model_adapter_unittest.cc
+++ b/ui/views/controls/menu/menu_model_adapter_unittest.cc
@@ -78,6 +78,8 @@
 
   bool IsVisibleAt(int index) const override { return items_[index].visible; }
 
+  bool IsAlertedAt(int index) const override { return items_[index].alerted; }
+
   bool IsNewFeatureAt(int index) const override {
     return items_[index].new_feature;
   }
@@ -121,6 +123,7 @@
     ui::MenuModel* submenu;
     bool enabled;
     bool visible;
+    bool alerted = false;
     bool new_feature = false;
   };
 
@@ -147,6 +150,7 @@
   SubmenuModel() : MenuModelBase(kSubmenuIdBase) {
     items_.emplace_back(TYPE_COMMAND, "submenu item 0", nullptr, false, true);
     items_.emplace_back(TYPE_COMMAND, "submenu item 1", nullptr);
+    items_[1].alerted = true;
   }
 
   ~SubmenuModel() override = default;
@@ -252,6 +256,9 @@
     // Check visibility.
     EXPECT_EQ(model_item.visible, item->GetVisible());
 
+    // Check alert state.
+    EXPECT_EQ(model_item.alerted, item->is_alerted());
+
     // Check new feature flag.
     EXPECT_EQ(model_item.new_feature, item->is_new());
 
@@ -333,7 +340,10 @@
     // Check visibility.
     EXPECT_EQ(model_item.visible, item->GetVisible());
 
-    // Check visibility.
+    // Check alert state.
+    EXPECT_EQ(model_item.alerted, item->is_alerted());
+
+    // Check new feature flag.
     EXPECT_EQ(model_item.new_feature, item->is_new());
 
     // Check activation.
diff --git a/ui/views/window/dialog_delegate.cc b/ui/views/window/dialog_delegate.cc
index c388215..0e3bfdd 100644
--- a/ui/views/window/dialog_delegate.cc
+++ b/ui/views/window/dialog_delegate.cc
@@ -247,7 +247,7 @@
       border->SetCornerRadius(
           base::FeatureList::IsEnabled(
               features::kEnableMDRoundedCornersOnDialogs)
-              ? provider->GetCornerRadiusMetric(views::EMPHASIS_HIGH)
+              ? provider->GetCornerRadiusMetric(views::EMPHASIS_MEDIUM)
               : 2);
     }
     frame->SetFootnoteView(delegate->DisownFootnoteView());
diff --git a/weblayer/public/java/org/chromium/weblayer/Tab.java b/weblayer/public/java/org/chromium/weblayer/Tab.java
index 17649d8..5d57082 100644
--- a/weblayer/public/java/org/chromium/weblayer/Tab.java
+++ b/weblayer/public/java/org/chromium/weblayer/Tab.java
@@ -282,12 +282,12 @@
         return mMediaCaptureController;
     }
 
-    public void registerTabCallback(@Nullable TabCallback callback) {
+    public void registerTabCallback(@NonNull TabCallback callback) {
         ThreadCheck.ensureOnUiThread();
         mCallbacks.addObserver(callback);
     }
 
-    public void unregisterTabCallback(@Nullable TabCallback callback) {
+    public void unregisterTabCallback(@NonNull TabCallback callback) {
         ThreadCheck.ensureOnUiThread();
         mCallbacks.removeObserver(callback);
     }