diff --git a/DEPS b/DEPS
index bbc3bd4..5d28798 100644
--- a/DEPS
+++ b/DEPS
@@ -144,7 +144,7 @@
   # 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': '77950aa0a8d29a91824000754f0a18a1b0664770',
+  'skia_revision': '8a5759d9902178a4a5e7225a3cd240b581987ef6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -156,7 +156,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': 'a71549b1129783d2c4ebc1e986bed553c48c4c7e',
+  'angle_revision': '02407743bd7261c37abae0f7e4962ea324662122',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -207,7 +207,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'da50ef4e8d1543e274937308395c97c9957c55c5',
+  'catapult_revision': '1855bc3168eed83649a33dc11f8042097da52d36',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -279,7 +279,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': '0e338ff98624e2873b1636d58491740764b3e029',
+  'dawn_revision': '07b5be3bc5df96b6488bb129eb39248dea078a20',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -808,7 +808,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '496d1cd2da511875ca0031c921428d7700ffd64b',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'e1edd548c20ffa519e97c18aeac4ab07dbc645b8',
       'condition': 'checkout_linux',
   },
 
@@ -823,7 +823,7 @@
 
   # For Linux and Chromium OS.
   'src/third_party/cros_system_api': {
-      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '7fce758d67707de0c1dd99c72663999c2978ae97',
+      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '80a8441a9d67a14025a9541ff1e6a0f728376040',
       'condition': 'checkout_linux',
   },
 
@@ -833,7 +833,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '73065b2067bc1516728a1e6251df751db98f0fba',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'c420221f1d94fd0799e9e7aed40928bf1b321a97',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1206,7 +1206,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '05c925d2e7f0ffd5ef6d603bcbda90398c48e9e2',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  'cde26f18fbf1a91dc06c99c68b3692c920dc826e',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1415,7 +1415,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@32b89794cac6c8f25acf2549f68ee5db6e5f9ee8',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@1f680135e59287c6f128ae3814dca5f05977107f',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn
index 78bb27a..f28aa1a 100644
--- a/android_webview/BUILD.gn
+++ b/android_webview/BUILD.gn
@@ -706,7 +706,7 @@
     "//components/about_ui",
     "//components/autofill/android:provider",
     "//components/autofill/content/browser",
-    "//components/autofill/content/common:mojo_interfaces",
+    "//components/autofill/content/common/mojom",
     "//components/autofill/content/renderer",
     "//components/cdm/browser",
     "//components/cdm/renderer",
diff --git a/android_webview/browser/aw_content_browser_overlay_manifest.cc b/android_webview/browser/aw_content_browser_overlay_manifest.cc
index b9a104f..d192cef 100644
--- a/android_webview/browser/aw_content_browser_overlay_manifest.cc
+++ b/android_webview/browser/aw_content_browser_overlay_manifest.cc
@@ -6,7 +6,7 @@
 
 #include "android_webview/common/js_java_interaction/interfaces.mojom.h"
 #include "base/no_destructor.h"
-#include "components/autofill/content/common/autofill_driver.mojom.h"
+#include "components/autofill/content/common/mojom/autofill_driver.mojom.h"
 #include "components/safe_browsing/common/safe_browsing.mojom.h"
 #include "components/services/heap_profiling/public/mojom/heap_profiling_client.mojom.h"
 #include "components/spellcheck/common/spellcheck.mojom.h"
diff --git a/android_webview/browser/aw_content_renderer_overlay_manifest.cc b/android_webview/browser/aw_content_renderer_overlay_manifest.cc
index 3c8e877..4fd8876 100644
--- a/android_webview/browser/aw_content_renderer_overlay_manifest.cc
+++ b/android_webview/browser/aw_content_renderer_overlay_manifest.cc
@@ -6,7 +6,7 @@
 
 #include "android_webview/common/js_java_interaction/interfaces.mojom.h"
 #include "base/no_destructor.h"
-#include "components/autofill/content/common/autofill_agent.mojom.h"
+#include "components/autofill/content/common/mojom/autofill_agent.mojom.h"
 #include "components/safe_browsing/common/safe_browsing.mojom.h"
 #include "content/public/common/service_names.mojom.h"
 #include "services/service_manager/public/cpp/manifest_builder.h"
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 8c94497..599d3b07 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -1086,6 +1086,7 @@
     "wm/desks/desks_bar_view.h",
     "wm/desks/desks_controller.cc",
     "wm/desks/desks_controller.h",
+    "wm/desks/desks_histogram_enums.h",
     "wm/desks/desks_util.cc",
     "wm/desks/desks_util.h",
     "wm/desks/new_desk_button.cc",
diff --git a/ash/accelerators/accelerator_controller_impl.cc b/ash/accelerators/accelerator_controller_impl.cc
index dfd721e..29f17bd 100644
--- a/ash/accelerators/accelerator_controller_impl.cc
+++ b/ash/accelerators/accelerator_controller_impl.cc
@@ -277,7 +277,8 @@
   }
 
   if (desk_to_activate) {
-    desks_controller->ActivateDesk(desk_to_activate);
+    desks_controller->ActivateDesk(desk_to_activate,
+                                   DesksSwitchSource::kDeskSwitchShortcut);
   } else {
     const bool going_left = accelerator.key_code() == ui::VKEY_OEM_4;
     for (auto* root : Shell::GetAllRootWindows())
@@ -329,7 +330,9 @@
         /*going_left=*/accelerator.key_code() == ui::VKEY_OEM_4);
   }
 
-  desks_controller->MoveWindowFromActiveDeskTo(window_to_move, target_desk);
+  desks_controller->MoveWindowFromActiveDeskTo(
+      window_to_move, target_desk,
+      DesksMoveWindowFromActiveDeskSource::kShortcut);
 
   if (in_overview) {
     // We should not exit overview as a result of this shortcut.
@@ -352,9 +355,9 @@
 
   // Add a new desk and switch to it.
   const size_t new_desk_index = desks_controller->desks().size();
-  desks_controller->NewDesk();
+  desks_controller->NewDesk(DesksCreationRemovalSource::kKeyboard);
   const Desk* desk = desks_controller->desks()[new_desk_index].get();
-  desks_controller->ActivateDesk(desk);
+  desks_controller->ActivateDesk(desk, DesksSwitchSource::kNewDeskShortcut);
   base::RecordAction(base::UserMetricsAction("Accel_Desks_NewDesk"));
 }
 
@@ -373,7 +376,8 @@
 
   // TODO(afakhry): Finalize the desk removal animation outside of overview with
   // UX. https://crbug.com/977434.
-  desks_controller->RemoveDesk(desks_controller->active_desk());
+  desks_controller->RemoveDesk(desks_controller->active_desk(),
+                               DesksCreationRemovalSource::kKeyboard);
   base::RecordAction(base::UserMetricsAction("Accel_Desks_RemoveDesk"));
 }
 
diff --git a/ash/app_list/app_list_controller_impl.cc b/ash/app_list/app_list_controller_impl.cc
index 98b0178..d563c2f 100644
--- a/ash/app_list/app_list_controller_impl.cc
+++ b/ash/app_list/app_list_controller_impl.cc
@@ -1161,6 +1161,17 @@
     client_->OnSearchResultVisibilityChanged(id, visibility);
 }
 
+void AppListControllerImpl::NotifySearchResultsForLogging(
+    const base::string16& raw_query,
+    const ash::SearchResultIdWithPositionIndices& results,
+    int position_index) {
+  if (client_) {
+    base::string16 query;
+    base::TrimWhitespace(raw_query, base::TRIM_ALL, &query);
+    client_->NotifySearchResultsForLogging(query, results, position_index);
+  }
+}
+
 bool AppListControllerImpl::IsAssistantAllowedAndEnabled() const {
   if (!chromeos::switches::IsAssistantEnabled())
     return false;
diff --git a/ash/app_list/app_list_controller_impl.h b/ash/app_list/app_list_controller_impl.h
index 47e7436..b6891d1 100644
--- a/ash/app_list/app_list_controller_impl.h
+++ b/ash/app_list/app_list_controller_impl.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "ash/app_list/app_list_metrics.h"
@@ -200,6 +201,10 @@
   ash::AssistantViewDelegate* GetAssistantViewDelegate() override;
   void OnSearchResultVisibilityChanged(const std::string& id,
                                        bool visibility) override;
+  void NotifySearchResultsForLogging(
+      const base::string16& raw_query,
+      const ash::SearchResultIdWithPositionIndices& results,
+      int position_index) override;
   bool IsAssistantAllowedAndEnabled() const override;
   bool ShouldShowAssistantPrivacyInfo() const override;
   void MaybeIncreaseAssistantPrivacyInfoShownCount() override;
diff --git a/ash/app_list/app_list_view_delegate.h b/ash/app_list/app_list_view_delegate.h
index 5b46a16c..d48ebbb 100644
--- a/ash/app_list/app_list_view_delegate.h
+++ b/ash/app_list/app_list_view_delegate.h
@@ -5,7 +5,9 @@
 #ifndef ASH_APP_LIST_APP_LIST_VIEW_DELEGATE_H_
 #define ASH_APP_LIST_APP_LIST_VIEW_DELEGATE_H_
 
+#include <memory>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "ash/app_list/app_list_metrics.h"
@@ -169,6 +171,18 @@
   virtual void OnSearchResultVisibilityChanged(const std::string& id,
                                                bool visibility) = 0;
 
+  // Called if a search result item got clicked, or a list of search result has
+  // been shown to the user after a certain amount of time. |raw_query| is the
+  // raw query that produced the results, |results| is a list of items that were
+  // being shown to the users and their corresponding position indices of them
+  // (see |SearchResultIdWithPositionIndex| for more details),
+  // |position_index| is the position index of the clicked item (if no item got
+  // clicked, |position_index| will be -1).
+  virtual void NotifySearchResultsForLogging(
+      const base::string16& raw_query,
+      const ash::SearchResultIdWithPositionIndices& results,
+      int position_index) = 0;
+
   // Returns true if the Assistant feature is allowed and enabled.
   virtual bool IsAssistantAllowedAndEnabled() const = 0;
 
diff --git a/ash/app_list/test/app_list_test_view_delegate.cc b/ash/app_list/test/app_list_test_view_delegate.cc
index a6f4b18..b0fe470 100644
--- a/ash/app_list/test/app_list_test_view_delegate.cc
+++ b/ash/app_list/test/app_list_test_view_delegate.cc
@@ -167,6 +167,11 @@
     const std::string& id,
     bool visibility) {}
 
+void AppListTestViewDelegate::NotifySearchResultsForLogging(
+    const base::string16& raw_query,
+    const ash::SearchResultIdWithPositionIndices& results,
+    int position_index) {}
+
 bool AppListTestViewDelegate::IsAssistantAllowedAndEnabled() const {
   return false;
 }
diff --git a/ash/app_list/test/app_list_test_view_delegate.h b/ash/app_list/test/app_list_test_view_delegate.h
index 3ef4b8fc..3d14ef6 100644
--- a/ash/app_list/test/app_list_test_view_delegate.h
+++ b/ash/app_list/test/app_list_test_view_delegate.h
@@ -10,6 +10,7 @@
 #include <map>
 #include <memory>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "ash/app_list/app_list_view_delegate.h"
@@ -101,6 +102,10 @@
   ash::AssistantViewDelegate* GetAssistantViewDelegate() override;
   void OnSearchResultVisibilityChanged(const std::string& id,
                                        bool visibility) override;
+  void NotifySearchResultsForLogging(
+      const base::string16& raw_query,
+      const ash::SearchResultIdWithPositionIndices& results,
+      int position_index) override;
   bool IsAssistantAllowedAndEnabled() const override;
   bool ShouldShowAssistantPrivacyInfo() const override;
   void MaybeIncreaseAssistantPrivacyInfoShownCount() override;
diff --git a/ash/app_list/test/test_app_list_client.h b/ash/app_list/test/test_app_list_client.h
index 4463ee4..197dc45 100644
--- a/ash/app_list/test/test_app_list_client.h
+++ b/ash/app_list/test/test_app_list_client.h
@@ -5,7 +5,10 @@
 #ifndef ASH_APP_LIST_TEST_TEST_APP_LIST_CLIENT_H_
 #define ASH_APP_LIST_TEST_TEST_APP_LIST_CLIENT_H_
 
+#include <memory>
 #include <string>
+#include <utility>
+#include <vector>
 
 #include "ash/public/cpp/app_list/app_list_client.h"
 #include "base/macros.h"
@@ -58,6 +61,10 @@
       override {}
   void OnSearchResultVisibilityChanged(const std::string& id,
                                        bool visibility) override {}
+  void NotifySearchResultsForLogging(
+      const base::string16& trimmed_query,
+      const ash::SearchResultIdWithPositionIndices& results,
+      int position_index) override {}
 
  private:
   DISALLOW_COPY_AND_ASSIGN(TestAppListClient);
diff --git a/ash/app_list/views/search_result_list_view.cc b/ash/app_list/views/search_result_list_view.cc
index 32923c00..8f465c2 100644
--- a/ash/app_list/views/search_result_list_view.cc
+++ b/ash/app_list/views/search_result_list_view.cc
@@ -6,6 +6,9 @@
 
 #include <algorithm>
 #include <memory>
+#include <string>
+#include <type_traits>
+#include <utility>
 #include <vector>
 
 #include "ash/app_list/app_list_metrics.h"
@@ -32,6 +35,8 @@
 namespace {
 
 constexpr int kMaxResults = 5;
+constexpr base::TimeDelta kImpressionThreshold =
+    base::TimeDelta::FromSeconds(3);
 
 constexpr SkColor kListVerticalBarIconColor =
     SkColorSetARGB(0xFF, 0xE8, 0xEA, 0xED);
@@ -110,6 +115,17 @@
   }
 }
 
+ash::SearchResultIdWithPositionIndices GetSearchResultsForLogging(
+    std::vector<SearchResultView*> search_result_views) {
+  ash::SearchResultIdWithPositionIndices results;
+  for (const auto* item : search_result_views) {
+    if (item->result()) {
+      results.emplace_back(ash::SearchResultIdWithPositionIndex(
+          item->result()->id(), item->index_in_container()));
+    }
+  }
+  return results;
+}
 }  // namespace
 
 SearchResultListView::SearchResultListView(AppListMainView* main_view,
@@ -195,12 +211,33 @@
     }
   }
 
+  // Logic for logging impression of items that were shown to user.
+  // Each time DoUpdate() called, start a timer that will be fired after a
+  // certain amount of time |kImpressionThreshold|. If during the waiting time,
+  // there's another DoUpdate() called, reset the timer and start a new timer
+  // with updated result list.
+  if (impression_timer_.IsRunning())
+    impression_timer_.Stop();
+  impression_timer_.Start(FROM_HERE, kImpressionThreshold, this,
+                          &SearchResultListView::LogImpressions);
+
   set_container_score(
       display_results.empty() ? 0 : display_results.front()->display_score());
 
   return display_results.size();
 }
 
+void SearchResultListView::LogImpressions() {
+  // Since no items is actually clicked, send the position index of clicked item
+  // as -1.
+  if (main_view_->search_box_view()->is_search_box_active()) {
+    view_delegate_->NotifySearchResultsForLogging(
+        view_delegate_->GetSearchModel()->search_box()->text(),
+        GetSearchResultsForLogging(search_result_views_),
+        -1 /* position_index */);
+  }
+}
+
 void SearchResultListView::Layout() {
   results_container_->SetBoundsRect(GetLocalBounds());
 }
@@ -224,6 +261,10 @@
                                  view_delegate_->GetSearchModel());
     view_delegate_->LogResultLaunchHistogram(
         SearchResultLaunchLocation::kResultList, view->index_in_container());
+    view_delegate_->NotifySearchResultsForLogging(
+        view_delegate_->GetSearchModel()->search_box()->text(),
+        GetSearchResultsForLogging(search_result_views_),
+        view->index_in_container());
     view_delegate_->OpenSearchResult(
         view->result()->id(), event_flags,
         ash::AppListLaunchedFrom::kLaunchedFromSearchBox,
diff --git a/ash/app_list/views/search_result_list_view.h b/ash/app_list/views/search_result_list_view.h
index 783bafa..fe1b6f9b 100644
--- a/ash/app_list/views/search_result_list_view.h
+++ b/ash/app_list/views/search_result_list_view.h
@@ -12,6 +12,7 @@
 #include "ash/app_list/views/search_result_view.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
 #include "ui/views/view.h"
 
 namespace app_list {
@@ -65,6 +66,9 @@
   // Overridden from views::View:
   void Layout() override;
   int GetHeightForWidth(int w) const override;
+  // Log the set of recommendations (impression) that were shown to the user
+  // after a priod of time.
+  void LogImpressions();
 
   AppListMainView* main_view_;          // Owned by views hierarchy.
   AppListViewDelegate* view_delegate_;  // Not owned.
@@ -73,6 +77,9 @@
 
   std::vector<SearchResultView*> search_result_views_;  // Not owned.
 
+  // Used for logging impression shown to users.
+  base::OneShotTimer impression_timer_;
+
   DISALLOW_COPY_AND_ASSIGN(SearchResultListView);
 };
 
diff --git a/ash/public/cpp/app_list/app_list_client.h b/ash/public/cpp/app_list/app_list_client.h
index 669792a..c849ee6 100644
--- a/ash/public/cpp/app_list/app_list_client.h
+++ b/ash/public/cpp/app_list/app_list_client.h
@@ -128,6 +128,11 @@
       mojo::PendingReceiver<content::mojom::NavigableContentsFactory>
           receiver) = 0;
 
+  virtual void NotifySearchResultsForLogging(
+      const base::string16& trimmed_query,
+      const ash::SearchResultIdWithPositionIndices& results,
+      int position_index) = 0;
+
  protected:
   virtual ~AppListClient() = default;
 };
diff --git a/ash/public/cpp/app_list/app_list_types.h b/ash/public/cpp/app_list/app_list_types.h
index 415e66e0..017e7cb33 100644
--- a/ash/public/cpp/app_list/app_list_types.h
+++ b/ash/public/cpp/app_list/app_list_types.h
@@ -300,6 +300,22 @@
   bool notify_visibility_change = false;
 };
 
+// A struct holding a search result id and its corresponding position index that
+// was being shown to the user.
+struct SearchResultIdWithPositionIndex {
+  SearchResultIdWithPositionIndex(std::string result_id, int index)
+      : id(result_id), position_index(index) {}
+
+  // The id of the result.
+  std::string id;
+
+  // The position index of the result.
+  int position_index;
+};
+
+using SearchResultIdWithPositionIndices =
+    std::vector<SearchResultIdWithPositionIndex>;
+
 }  // namespace ash
 
 #endif  // ASH_PUBLIC_CPP_APP_LIST_APP_LIST_TYPES_H_
diff --git a/ash/wm/desks/desk_mini_view.cc b/ash/wm/desks/desk_mini_view.cc
index a6472c4..81f236d6 100644
--- a/ash/wm/desks/desk_mini_view.cc
+++ b/ash/wm/desks/desk_mini_view.cc
@@ -191,7 +191,7 @@
 
   auto* controller = DesksController::Get();
   DCHECK(controller->CanRemoveDesks());
-  controller->RemoveDesk(desk_);
+  controller->RemoveDesk(desk_, DesksCreationRemovalSource::kButton);
 }
 
 void DeskMiniView::OnContentChanged() {
diff --git a/ash/wm/desks/desk_preview_view.cc b/ash/wm/desks/desk_preview_view.cc
index 77389c8..a08790b 100644
--- a/ash/wm/desks/desk_preview_view.cc
+++ b/ash/wm/desks/desk_preview_view.cc
@@ -65,7 +65,10 @@
 
 // Recursively mirrors |source_layer| and its children and adds them as children
 // of |parent|, taking into account the given |layers_data|.
-void MirrorLayerTree(ui::Layer* source_layer,
+// The transforms of the mirror layers of the direct children of
+// |desk_container_layer| will be reset to identity.
+void MirrorLayerTree(ui::Layer* desk_container_layer,
+                     ui::Layer* source_layer,
                      ui::Layer* parent,
                      const base::flat_map<ui::Layer*, LayerData>& layers_data) {
   const auto iter = layers_data.find(source_layer);
@@ -78,7 +81,7 @@
   parent->Add(mirror);
 
   for (auto* child : source_layer->children())
-    MirrorLayerTree(child, mirror, layers_data);
+    MirrorLayerTree(desk_container_layer, child, mirror, layers_data);
 
   mirror->set_sync_bounds_with_source(true);
   if (layer_data.should_force_mirror_visible) {
@@ -90,9 +93,8 @@
   // Windows in overview mode are transformed into their positions in the grid,
   // but we want to show a preview of the windows in their untransformed state
   // outside of overview mode.
-  // TODO(afakhry): Is it safe to do this for all layers in the subtree, or
-  // should we limit this for the mirrors of the top level windows' layers?
-  mirror->SetTransform(gfx::Transform());
+  if (source_layer->parent() == desk_container_layer)
+    mirror->SetTransform(gfx::Transform());
 }
 
 // Gathers the needed data about the layers in the subtree rooted at the layer
@@ -191,8 +193,9 @@
   mirrored_content_root_layer->set_name("mirrored contents root layer");
   base::flat_map<ui::Layer*, LayerData> layers_data;
   GetLayersData(desk_container, &layers_data);
-  MirrorLayerTree(desk_container->layer(), mirrored_content_root_layer.get(),
-                  layers_data);
+  auto* desk_container_layer = desk_container->layer();
+  MirrorLayerTree(desk_container_layer, desk_container_layer,
+                  mirrored_content_root_layer.get(), layers_data);
 
   // Add the root of the mirrored layer tree as a child of the
   // |desk_mirrored_contents_view_|'s layer.
diff --git a/ash/wm/desks/desks_bar_view.cc b/ash/wm/desks/desks_bar_view.cc
index 4dfa6b3..6d0bb22 100644
--- a/ash/wm/desks/desks_bar_view.cc
+++ b/ash/wm/desks/desks_bar_view.cc
@@ -236,7 +236,7 @@
   auto* controller = DesksController::Get();
   if (sender == new_desk_button_) {
     if (controller->CanCreateDesks()) {
-      controller->NewDesk();
+      controller->NewDesk(DesksCreationRemovalSource::kButton);
       UpdateNewDeskButtonState();
     }
     return;
@@ -244,7 +244,8 @@
 
   for (auto& mini_view : mini_views_) {
     if (mini_view.get() == sender) {
-      controller->ActivateDesk(mini_view->desk());
+      controller->ActivateDesk(mini_view->desk(),
+                               DesksSwitchSource::kMiniViewButton);
       return;
     }
   }
diff --git a/ash/wm/desks/desks_controller.cc b/ash/wm/desks/desks_controller.cc
index 9ffb1d5..64f3afa 100644
--- a/ash/wm/desks/desks_controller.cc
+++ b/ash/wm/desks/desks_controller.cc
@@ -19,6 +19,7 @@
 #include "ash/wm/window_util.h"
 #include "base/auto_reset.h"
 #include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/stl_util.h"
 #include "ui/aura/window_tree_host.h"
 #include "ui/compositor/compositor.h"
@@ -28,6 +29,21 @@
 
 namespace {
 
+constexpr char kNewDeskHistogramName[] = "Ash.Desks.NewDesk";
+constexpr char kDesksCountHistogramName[] = "Ash.Desks.DesksCount";
+constexpr char kRemoveDeskHistogramName[] = "Ash.Desks.RemoveDesk";
+constexpr char kDeskSwitchHistogramName[] = "Ash.Desks.DesksSwitch";
+constexpr char kMoveWindowFromActiveDeskHistogramName[] =
+    "Ash.Desks.MoveWindowFromActiveDesk";
+constexpr char kNumberOfWindowsOnDesk_1_HistogramName[] =
+    "Ash.Desks.NumberOfWindowsOnDesk_1";
+constexpr char kNumberOfWindowsOnDesk_2_HistogramName[] =
+    "Ash.Desks.NumberOfWindowsOnDesk_2";
+constexpr char kNumberOfWindowsOnDesk_3_HistogramName[] =
+    "Ash.Desks.NumberOfWindowsOnDesk_3";
+constexpr char kNumberOfWindowsOnDesk_4_HistogramName[] =
+    "Ash.Desks.NumberOfWindowsOnDesk_4";
+
 // Appends the given |windows| to the end of the currently active overview mode
 // session such that the most-recently used window is added first. If
 // |should_animate| is true, the windows will animate to their positions in the
@@ -71,7 +87,7 @@
     available_container_ids_.push(id);
 
   // There's always one default desk.
-  NewDesk();
+  NewDesk(DesksCreationRemovalSource::kButton);
   active_desk_ = desks_.back().get();
   active_desk_->Activate(/*update_window_activation=*/true);
 }
@@ -98,7 +114,6 @@
 }
 
 bool DesksController::CanCreateDesks() const {
-  // TODO(afakhry): Disable creating new desks in tablet mode.
   return desks_.size() < desks_util::kMaxNumberOfDesks;
 }
 
@@ -120,7 +135,7 @@
   return desks_.size() > 1;
 }
 
-void DesksController::NewDesk() {
+void DesksController::NewDesk(DesksCreationRemovalSource source) {
   DCHECK(CanCreateDesks());
   DCHECK(!available_container_ids_.empty());
 
@@ -129,11 +144,15 @@
   desks_.emplace_back(std::make_unique<Desk>(available_container_ids_.front()));
   available_container_ids_.pop();
 
+  UMA_HISTOGRAM_ENUMERATION(kNewDeskHistogramName, source);
+  ReportDesksCountHistogram();
+
   for (auto& observer : observers_)
     observer.OnDeskAdded(desks_.back().get());
 }
 
-void DesksController::RemoveDesk(const Desk* desk) {
+void DesksController::RemoveDesk(const Desk* desk,
+                                 DesksCreationRemovalSource source) {
   DCHECK(CanRemoveDesks());
 
   base::AutoReset<bool> in_progress(&are_desks_being_modified_, true);
@@ -212,8 +231,7 @@
     // window activation. Activation should remain on the dummy
     // "OverviewModeFocusedWidget" while overview mode is active.
     removed_desk->MoveWindowsToDesk(target_desk);
-    ActivateDeskInternal(target_desk,
-                         /*update_window_activation=*/!in_overview);
+    ActivateDesk(target_desk, DesksSwitchSource::kDeskRemoved);
 
     // Desk activation should not change overview mode state.
     DCHECK_EQ(in_overview, overview_controller->InOverviewSession());
@@ -247,16 +265,22 @@
   if (will_switch_desks)
     MaybeRestoreSplitView(/*refresh_snapped_windows=*/true);
 
+  UMA_HISTOGRAM_ENUMERATION(kRemoveDeskHistogramName, source);
+  ReportDesksCountHistogram();
+  ReportNumberOfWindowsPerDeskHistogram();
+
   DCHECK_LE(available_container_ids_.size(), desks_util::kMaxNumberOfDesks);
 }
 
-void DesksController::ActivateDesk(const Desk* desk) {
+void DesksController::ActivateDesk(const Desk* desk, DesksSwitchSource source) {
   DCHECK(HasDesk(desk));
 
+  UMA_HISTOGRAM_ENUMERATION(kDeskSwitchHistogramName, source);
+
+  OverviewController* overview_controller = Shell::Get()->overview_controller();
+  const bool in_overview = overview_controller->InOverviewSession();
   if (desk == active_desk_) {
-    OverviewController* overview_controller =
-        Shell::Get()->overview_controller();
-    if (overview_controller->InOverviewSession()) {
+    if (in_overview) {
       // Selecting the active desk's mini_view in overview mode is allowed and
       // should just exit overview mode normally.
       overview_controller->EndOverview();
@@ -264,6 +288,11 @@
     return;
   }
 
+  if (source == DesksSwitchSource::kDeskRemoved) {
+    ActivateDeskInternal(desk, /*update_window_activation=*/!in_overview);
+    return;
+  }
+
   // New desks are always added at the end of the list to the right of existing
   // desks. Therefore, desks at lower indices are located on the left of desks
   // with higher indices.
@@ -282,8 +311,10 @@
     animator->TakeStartingDeskScreenshot();
 }
 
-void DesksController::MoveWindowFromActiveDeskTo(aura::Window* window,
-                                                 Desk* target_desk) {
+void DesksController::MoveWindowFromActiveDeskTo(
+    aura::Window* window,
+    Desk* target_desk,
+    DesksMoveWindowFromActiveDeskSource source) {
   DCHECK_NE(active_desk_, target_desk);
 
   base::AutoReset<bool> in_progress(&are_desks_being_modified_, true);
@@ -309,6 +340,9 @@
     return;
   }
 
+  UMA_HISTOGRAM_ENUMERATION(kMoveWindowFromActiveDeskHistogramName, source);
+  ReportNumberOfWindowsPerDeskHistogram();
+
   // A window moving out of the active desk cannot be active.
   wm::DeactivateWindow(window);
 }
@@ -416,7 +450,7 @@
   if (!window_desk || window_desk == active_desk_)
     return;
 
-  ActivateDesk(window_desk);
+  ActivateDesk(window_desk, DesksSwitchSource::kWindowActivated);
 }
 
 void DesksController::OnWindowActivated(ActivationReason reason,
@@ -475,4 +509,41 @@
   return nullptr;
 }
 
+void DesksController::ReportNumberOfWindowsPerDeskHistogram() const {
+  for (size_t i = 0; i < desks_.size(); ++i) {
+    const size_t windows_count = desks_[i]->windows().size();
+    switch (i) {
+      case 0:
+        UMA_HISTOGRAM_COUNTS_100(kNumberOfWindowsOnDesk_1_HistogramName,
+                                 windows_count);
+        break;
+
+      case 1:
+        UMA_HISTOGRAM_COUNTS_100(kNumberOfWindowsOnDesk_2_HistogramName,
+                                 windows_count);
+        break;
+
+      case 2:
+        UMA_HISTOGRAM_COUNTS_100(kNumberOfWindowsOnDesk_3_HistogramName,
+                                 windows_count);
+        break;
+
+      case 3:
+        UMA_HISTOGRAM_COUNTS_100(kNumberOfWindowsOnDesk_4_HistogramName,
+                                 windows_count);
+        break;
+
+      default:
+        NOTREACHED();
+        break;
+    }
+  }
+}
+
+void DesksController::ReportDesksCountHistogram() const {
+  DCHECK_LE(desks_.size(), desks_util::kMaxNumberOfDesks);
+  UMA_HISTOGRAM_EXACT_LINEAR(kDesksCountHistogramName, desks_.size(),
+                             desks_util::kMaxNumberOfDesks);
+}
+
 }  // namespace ash
diff --git a/ash/wm/desks/desks_controller.h b/ash/wm/desks/desks_controller.h
index 8137dd5..0ae2e95d 100644
--- a/ash/wm/desks/desks_controller.h
+++ b/ash/wm/desks/desks_controller.h
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "ash/ash_export.h"
+#include "ash/wm/desks/desks_histogram_enums.h"
 #include "ash/wm/desks/root_window_desk_switch_animator.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
@@ -85,23 +86,25 @@
   Desk* GetPreviousDesk() const;
 
   // Creates a new desk. CanCreateDesks() must be checked before calling this.
-  void NewDesk();
+  void NewDesk(DesksCreationRemovalSource source);
 
   // Removes and deletes the given |desk|. |desk| must already exist, and
   // CanRemoveDesks() must be checked before this.
-  void RemoveDesk(const Desk* desk);
+  void RemoveDesk(const Desk* desk, DesksCreationRemovalSource source);
 
   // Performs the desk switch animation on all root windows to activate the
   // given |desk| and to deactivate the currently active one. |desk| has to be
   // an existing desk. The active window on the currently active desk will be
   // deactivated, and the most-recently used window from the newly-activated
   // desk will be activated.
-  void ActivateDesk(const Desk* desk);
+  void ActivateDesk(const Desk* desk, DesksSwitchSource source);
 
   // Moves |window| (which must belong to the currently active desk) to
   // |target_desk| (which must be a different desk). If |window| is minimized,
   // it will be unminimized after it's moved to |target_desk|.
-  void MoveWindowFromActiveDeskTo(aura::Window* window, Desk* target_desk);
+  void MoveWindowFromActiveDeskTo(aura::Window* window,
+                                  Desk* target_desk,
+                                  DesksMoveWindowFromActiveDeskSource source);
 
   // Called explicitly by the RootWindowController when a root window has been
   // added or about to be removed in order to update all the available desks.
@@ -141,6 +144,12 @@
   // to any desk.
   const Desk* FindDeskOfWindow(aura::Window* window) const;
 
+  // Reports the number of windows per each available desk. This called when a
+  // desk switch occurs.
+  void ReportNumberOfWindowsPerDeskHistogram() const;
+
+  void ReportDesksCountHistogram() const;
+
   std::vector<std::unique_ptr<Desk>> desks_;
 
   Desk* active_desk_ = nullptr;
diff --git a/ash/wm/desks/desks_histogram_enums.h b/ash/wm/desks/desks_histogram_enums.h
new file mode 100644
index 0000000..866918b
--- /dev/null
+++ b/ash/wm/desks/desks_histogram_enums.h
@@ -0,0 +1,43 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_WM_DESKS_DESKS_HISTOGRAM_ENUMS_H_
+#define ASH_WM_DESKS_DESKS_HISTOGRAM_ENUMS_H_
+
+namespace ash {
+
+// These values are logged to UMA. Entries should not be renumbered and
+// numeric values should never be reused. Please keep in sync with
+// DesksCreationRemovalSource in src/tools/metrics/histograms/enums.xml.
+enum class DesksCreationRemovalSource {
+  kButton = 0,
+  kKeyboard = 1,
+  kMaxValue = kKeyboard,
+};
+
+// These values are logged to UMA. Entries should not be renumbered and
+// numeric values should never be reused. Please keep in sync with
+// DesksMoveWindowFromActiveDeskSource in
+// src/tools/metrics/histograms/enums.xml.
+enum class DesksMoveWindowFromActiveDeskSource {
+  kDragAndDrop = 0,
+  kShortcut = 1,
+  kMaxValue = kShortcut,
+};
+
+// These values are logged to UMA. Entries should not be renumbered and
+// numeric values should never be reused. Please keep in sync with
+// DesksSwitchSource in src/tools/metrics/histograms/enums.xml.
+enum class DesksSwitchSource {
+  kNewDeskShortcut = 0,
+  kDeskRemoved = 1,
+  kDeskSwitchShortcut = 2,
+  kMiniViewButton = 3,
+  kWindowActivated = 4,
+  kMaxValue = kWindowActivated,
+};
+
+}  // namespace ash
+
+#endif  // ASH_WM_DESKS_DESKS_HISTOGRAM_ENUMS_H_
diff --git a/ash/wm/desks/desks_test_util.cc b/ash/wm/desks/desks_test_util.cc
index fbc796f..b9b4f0d 100644
--- a/ash/wm/desks/desks_test_util.cc
+++ b/ash/wm/desks/desks_test_util.cc
@@ -39,7 +39,8 @@
 void ActivateDesk(const Desk* desk) {
   ASSERT_FALSE(desk->is_active());
   DeskSwitchAnimationWaiter waiter;
-  DesksController::Get()->ActivateDesk(desk);
+  DesksController::Get()->ActivateDesk(desk,
+                                       DesksSwitchSource::kMiniViewButton);
   waiter.Wait();
   ASSERT_TRUE(desk->is_active());
 }
diff --git a/ash/wm/desks/desks_unittests.cc b/ash/wm/desks/desks_unittests.cc
index c88b108..45a94d0b 100644
--- a/ash/wm/desks/desks_unittests.cc
+++ b/ash/wm/desks/desks_unittests.cc
@@ -50,6 +50,14 @@
 
 namespace {
 
+void NewDesk() {
+  DesksController::Get()->NewDesk(DesksCreationRemovalSource::kButton);
+}
+
+void RemoveDesk(const Desk* desk) {
+  DesksController::Get()->RemoveDesk(desk, DesksCreationRemovalSource::kButton);
+}
+
 std::unique_ptr<aura::Window> CreateTransientWindow(
     aura::Window* transient_parent,
     const gfx::Rect& bounds) {
@@ -263,7 +271,7 @@
 
   // Add desks until no longer possible.
   while (controller->CanCreateDesks())
-    controller->NewDesk();
+    NewDesk();
 
   // Expect we've reached the max number of desks, and we've been notified only
   // with the newly created desks.
@@ -274,7 +282,7 @@
   // Remove all desks until no longer possible, and expect that there's always
   // one default desk remaining.
   while (controller->CanRemoveDesks())
-    controller->RemoveDesk(observer.desks().back());
+    RemoveDesk(observer.desks().back());
 
   EXPECT_EQ(1u, controller->desks().size());
   EXPECT_FALSE(controller->CanRemoveDesks());
@@ -377,9 +385,9 @@
             desk_1->GetDeskContainerForRoot(root));
 
   // Create three new desks, and activate one of the middle ones.
-  controller->NewDesk();
-  controller->NewDesk();
-  controller->NewDesk();
+  NewDesk();
+  NewDesk();
+  NewDesk();
   ASSERT_EQ(4u, controller->desks().size());
   const Desk* desk_2 = controller->desks()[1].get();
   const Desk* desk_3 = controller->desks()[2].get();
@@ -400,7 +408,7 @@
   // Remove the active desk, which is in the middle, activation should move to
   // the left, so desk 1 should be activated.
   EXPECT_FALSE(controller->AreDesksBeingModified());
-  controller->RemoveDesk(desk_2);
+  RemoveDesk(desk_2);
   EXPECT_FALSE(controller->AreDesksBeingModified());
   ASSERT_EQ(3u, controller->desks().size());
   EXPECT_EQ(desk_1, controller->active_desk());
@@ -414,7 +422,7 @@
   // Remove the active desk, it's the first one on the left, so desk_3 (on the
   // right) will be activated.
   EXPECT_FALSE(controller->AreDesksBeingModified());
-  controller->RemoveDesk(desk_1);
+  RemoveDesk(desk_1);
   EXPECT_FALSE(controller->AreDesksBeingModified());
   ASSERT_EQ(2u, controller->desks().size());
   EXPECT_EQ(desk_3, controller->active_desk());
@@ -426,7 +434,7 @@
 
 TEST_F(DesksTest, TestWindowPositioningPaused) {
   auto* controller = DesksController::Get();
-  controller->NewDesk();
+  NewDesk();
 
   // Create two windows whose window positioning is managed.
   const auto win0_bounds = gfx::Rect{10, 20, 250, 100};
@@ -443,13 +451,14 @@
   // Moving one window to the second desk should not affect the bounds of either
   // windows.
   Desk* desk_2 = controller->desks()[1].get();
-  controller->MoveWindowFromActiveDeskTo(win1.get(), desk_2);
+  controller->MoveWindowFromActiveDeskTo(
+      win1.get(), desk_2, DesksMoveWindowFromActiveDeskSource::kDragAndDrop);
   EXPECT_EQ(win0_bounds, win0->GetBoundsInScreen());
   EXPECT_EQ(win1_bounds, win1->GetBoundsInScreen());
 
   // Removing a desk, which results in moving its windows to another desk should
   // not affect the positions of those managed windows.
-  controller->RemoveDesk(desk_2);
+  RemoveDesk(desk_2);
   EXPECT_EQ(win0_bounds, win0->GetBoundsInScreen());
   EXPECT_EQ(win1_bounds, win1->GetBoundsInScreen());
 }
@@ -466,9 +475,9 @@
   EXPECT_TRUE(desk_1->is_active());
 
   // Create three new desks, and activate one of the middle ones.
-  controller->NewDesk();
-  controller->NewDesk();
-  controller->NewDesk();
+  NewDesk();
+  NewDesk();
+  NewDesk();
   ASSERT_EQ(4u, controller->desks().size());
   const Desk* desk_2 = controller->desks()[1].get();
   const Desk* desk_3 = controller->desks()[2].get();
@@ -516,7 +525,7 @@
             desks_util::GetDeskContainerForContext(win1.get()));
 
   // Create a new desk and activate it.
-  controller->NewDesk();
+  NewDesk();
   const Desk* desk_2 = controller->desks()[1].get();
   EXPECT_TRUE(desk_2->windows().empty());
   ActivateDesk(desk_2);
@@ -537,7 +546,7 @@
 
   // Remove the inactive desk 1, and expect that its windows, including
   // transient will move to desk 2.
-  controller->RemoveDesk(desk_1);
+  RemoveDesk(desk_1);
   EXPECT_EQ(1u, controller->desks().size());
   EXPECT_EQ(desk_2, controller->active_desk());
   EXPECT_EQ(3u, desk_2->windows().size());
@@ -549,8 +558,8 @@
 
 TEST_F(DesksTest, TransientModalChildren) {
   auto* controller = DesksController::Get();
-  controller->NewDesk();
-  controller->NewDesk();
+  NewDesk();
+  NewDesk();
   ASSERT_EQ(3u, controller->desks().size());
   Desk* desk_1 = controller->desks()[0].get();
   Desk* desk_2 = controller->desks()[1].get();
@@ -573,7 +582,7 @@
   // Remove desk_1, and expect that all its windows (including the transient
   // modal child and its parent) are moved to desk_2, and that their z-order
   // within the container is preserved.
-  controller->RemoveDesk(desk_1);
+  RemoveDesk(desk_1);
   EXPECT_EQ(desk_2, controller->active_desk());
   ASSERT_EQ(3u, desk_2->windows().size());
   auto* desk_2_container = desk_2->GetDeskContainerForRoot(root);
@@ -584,7 +593,8 @@
 
   // Move only the modal child window to desk_3, and expect that its parent will
   // move along with it, and their z-order is preserved.
-  controller->MoveWindowFromActiveDeskTo(win1.get(), desk_3);
+  controller->MoveWindowFromActiveDeskTo(
+      win1.get(), desk_3, DesksMoveWindowFromActiveDeskSource::kDragAndDrop);
   ASSERT_EQ(1u, desk_2->windows().size());
   ASSERT_EQ(2u, desk_3->windows().size());
   EXPECT_EQ(win2.get(), desk_2_container->children()[0]);
@@ -613,7 +623,7 @@
   // Create a new desk and activate it. Expect it's not tracking any windows
   // yet.
   auto* controller = DesksController::Get();
-  controller->NewDesk();
+  NewDesk();
   ASSERT_EQ(2u, controller->desks().size());
   Desk* desk_1 = controller->desks()[0].get();
   const Desk* desk_2 = controller->desks()[1].get();
@@ -670,7 +680,7 @@
   // desk.
   TestDeskObserver observer;
   desk_1->AddObserver(&observer);
-  controller->RemoveDesk(desk_2);
+  RemoveDesk(desk_2);
   EXPECT_EQ(1u, controller->desks().size());
   EXPECT_EQ(desk_1, controller->active_desk());
   EXPECT_EQ(4u, desk_1->windows().size());
@@ -694,9 +704,9 @@
   auto* controller = DesksController::Get();
 
   // Create three desks other than the default initial desk.
-  controller->NewDesk();
-  controller->NewDesk();
-  controller->NewDesk();
+  NewDesk();
+  NewDesk();
+  NewDesk();
   ASSERT_EQ(4u, controller->desks().size());
 
   // Create two windows on desk_1.
@@ -769,9 +779,9 @@
   auto* controller = DesksController::Get();
 
   // Create three desks other than the default initial desk.
-  controller->NewDesk();
-  controller->NewDesk();
-  controller->NewDesk();
+  NewDesk();
+  NewDesk();
+  NewDesk();
   ASSERT_EQ(4u, controller->desks().size());
 
   // Enter overview mode.
@@ -808,9 +818,9 @@
   auto* controller = DesksController::Get();
 
   // Create three desks other than the default initial desk.
-  controller->NewDesk();
-  controller->NewDesk();
-  controller->NewDesk();
+  NewDesk();
+  NewDesk();
+  NewDesk();
   ASSERT_EQ(4u, controller->desks().size());
 
   // Create two windows on desk_1.
@@ -886,7 +896,7 @@
   auto* controller = DesksController::Get();
 
   // Create one desk other than the default initial desk.
-  controller->NewDesk();
+  NewDesk();
   ASSERT_EQ(2u, controller->desks().size());
 
   // Create two windows on desk_1.
@@ -965,7 +975,7 @@
 
   // Create one more desk other than the default initial desk, so the desks bar
   // shows up in overview mode.
-  controller->NewDesk();
+  NewDesk();
   ASSERT_EQ(2u, controller->desks().size());
 
   // Enter overview mode, and click on `desk_1`'s mini_view, and expect that
@@ -986,7 +996,7 @@
 
 TEST_F(DesksTest, MinimizedWindow) {
   auto* controller = DesksController::Get();
-  controller->NewDesk();
+  NewDesk();
   ASSERT_EQ(2u, controller->desks().size());
   const Desk* desk_1 = controller->desks()[0].get();
   const Desk* desk_2 = controller->desks()[1].get();
@@ -1022,7 +1032,7 @@
 
 TEST_P(DesksTest, DragWindowToDesk) {
   auto* controller = DesksController::Get();
-  controller->NewDesk();
+  NewDesk();
   ASSERT_EQ(2u, controller->desks().size());
   const Desk* desk_1 = controller->desks()[0].get();
   const Desk* desk_2 = controller->desks()[1].get();
@@ -1109,7 +1119,7 @@
 
 TEST_P(DesksTest, DragMinimizedWindowToDesk) {
   auto* controller = DesksController::Get();
-  controller->NewDesk();
+  NewDesk();
   ASSERT_EQ(2u, controller->desks().size());
   const Desk* desk_2 = controller->desks()[1].get();
 
@@ -1161,7 +1171,7 @@
 
 TEST_P(DesksTest, DragWindowToNonMiniViewPoints) {
   auto* controller = DesksController::Get();
-  controller->NewDesk();
+  NewDesk();
   ASSERT_EQ(2u, controller->desks().size());
 
   auto window = CreateTestWindow(gfx::Rect(0, 0, 250, 100));
@@ -1213,7 +1223,7 @@
   auto win0 = CreateTestWindow(gfx::Rect(0, 0, 250, 100));
   auto win1 = CreateTestWindow(gfx::Rect(50, 50, 200, 200));
   auto* controller = DesksController::Get();
-  controller->NewDesk();
+  NewDesk();
   ASSERT_EQ(2u, controller->desks().size());
   const Desk* desk_2 = controller->desks()[1].get();
   ActivateDesk(desk_2);
@@ -1258,7 +1268,7 @@
   auto win0 = CreateTestWindow(gfx::Rect(0, 0, 250, 100));
   auto win1 = CreateTestWindow(gfx::Rect(50, 50, 200, 200));
   auto* controller = DesksController::Get();
-  controller->NewDesk();
+  NewDesk();
   ASSERT_EQ(2u, controller->desks().size());
   const Desk* desk_2 = controller->desks()[1].get();
   ActivateDesk(desk_2);
@@ -1305,7 +1315,7 @@
 
 TEST_F(TabletModeDesksTest, Backdrops) {
   auto* controller = DesksController::Get();
-  controller->NewDesk();
+  NewDesk();
   ASSERT_EQ(2u, controller->desks().size());
   const Desk* desk_1 = controller->desks()[0].get();
   const Desk* desk_2 = controller->desks()[1].get();
@@ -1406,7 +1416,7 @@
   // the desks bar is visible.
   overview_controller->EndOverview();
   EXPECT_FALSE(overview_controller->InOverviewSession());
-  controller->NewDesk();
+  NewDesk();
   overview_controller->StartOverview();
   EXPECT_TRUE(overview_controller->InOverviewSession());
   overview_grid = GetOverviewGridForRoot(Shell::GetPrimaryRootWindow());
@@ -1425,7 +1435,7 @@
   // correct, and there are no crashes as desks are removed.
   auto* desks_controller = DesksController::Get();
   for (size_t i = 0; i < 2 * desks_util::kMaxNumberOfDesks; ++i) {
-    desks_controller->NewDesk();
+    NewDesk();
     ASSERT_EQ(2u, desks_controller->desks().size());
     const Desk* desk_1 = desks_controller->desks()[0].get();
     const Desk* desk_2 = desks_controller->desks()[1].get();
@@ -1441,7 +1451,7 @@
     }
     // Remove the active desk, and expect that now desk_2 should have a hidden
     // backdrop, while the container of the removed desk_1 should have none.
-    desks_controller->RemoveDesk(desk_1);
+    RemoveDesk(desk_1);
     {
       SCOPED_TRACE("Check backdrops after desk removal");
       EXPECT_TRUE(desk_2->is_active());
@@ -1456,7 +1466,7 @@
 TEST_F(TabletModeDesksTest, RestoreSplitViewOnDeskSwitch) {
   // Create two desks with two snapped windows in each.
   auto* desks_controller = DesksController::Get();
-  desks_controller->NewDesk();
+  NewDesk();
   ASSERT_EQ(2u, desks_controller->desks().size());
   Desk* desk_1 = desks_controller->desks()[0].get();
   Desk* desk_2 = desks_controller->desks()[1].get();
@@ -1497,7 +1507,7 @@
 
 TEST_F(TabletModeDesksTest, SnappedStateRetainedOnSwitchingDesksFromOverview) {
   auto* desks_controller = DesksController::Get();
-  desks_controller->NewDesk();
+  NewDesk();
   ASSERT_EQ(2u, desks_controller->desks().size());
   auto win1 = CreateTestWindow(gfx::Rect(0, 0, 250, 100));
   auto win2 = CreateTestWindow(gfx::Rect(0, 0, 250, 100));
@@ -1560,7 +1570,7 @@
   // Setup two desks, one (desk_1) with two snapped windows, and the other
   // (desk_2) with only one snapped window.
   auto* desks_controller = DesksController::Get();
-  desks_controller->NewDesk();
+  NewDesk();
   ASSERT_EQ(2u, desks_controller->desks().size());
   Desk* desk_1 = desks_controller->desks()[0].get();
   Desk* desk_2 = desks_controller->desks()[1].get();
@@ -1594,7 +1604,7 @@
 
 TEST_F(TabletModeDesksTest, RemovingDesksWithSplitView) {
   auto* desks_controller = DesksController::Get();
-  desks_controller->NewDesk();
+  NewDesk();
   ASSERT_EQ(2u, desks_controller->desks().size());
   Desk* desk_2 = desks_controller->desks()[1].get();
   auto win1 = CreateTestWindow(gfx::Rect(0, 0, 250, 100));
@@ -1610,7 +1620,7 @@
   EXPECT_EQ(win2.get(), split_view_controller->right_window());
 
   // Removing desk_2 will cause both snapped windows to merge in SplitView.
-  desks_controller->RemoveDesk(desk_2);
+  RemoveDesk(desk_2);
   EXPECT_EQ(win1.get(), split_view_controller->left_window());
   EXPECT_EQ(win2.get(), split_view_controller->right_window());
   EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller->state());
@@ -1618,7 +1628,7 @@
 
 TEST_F(TabletModeDesksTest, RemoveDeskWithMaximizedWindowAndMergeWithSnapped) {
   auto* desks_controller = DesksController::Get();
-  desks_controller->NewDesk();
+  NewDesk();
   ASSERT_EQ(2u, desks_controller->desks().size());
   Desk* desk_2 = desks_controller->desks()[1].get();
   auto win1 = CreateTestWindow(gfx::Rect(0, 0, 250, 100));
@@ -1635,7 +1645,7 @@
 
   // Removing desk_2 will cause us to enter overview mode without any crashes.
   // SplitView will remain left snapped.
-  desks_controller->RemoveDesk(desk_2);
+  RemoveDesk(desk_2);
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
   EXPECT_EQ(win1.get(), split_view_controller->left_window());
   EXPECT_EQ(nullptr, split_view_controller->right_window());
@@ -1644,7 +1654,7 @@
 
 TEST_F(TabletModeDesksTest, BackdropsStacking) {
   auto* desks_controller = DesksController::Get();
-  desks_controller->NewDesk();
+  NewDesk();
   ASSERT_EQ(2u, desks_controller->desks().size());
   Desk* desk_1 = desks_controller->desks()[0].get();
   Desk* desk_2 = desks_controller->desks()[1].get();
@@ -1690,8 +1700,8 @@
 
 TEST_F(DesksTest, MiniViewsTouchGestures) {
   auto* controller = DesksController::Get();
-  controller->NewDesk();
-  controller->NewDesk();
+  NewDesk();
+  NewDesk();
   ASSERT_EQ(3u, controller->desks().size());
   auto* overview_controller = Shell::Get()->overview_controller();
   overview_controller->StartOverview();
@@ -1762,7 +1772,7 @@
 
 TEST_F(DesksWithSplitViewTest, SuccessfulDragToDeskRemovesSplitViewIndicators) {
   auto* controller = DesksController::Get();
-  controller->NewDesk();
+  NewDesk();
   ASSERT_EQ(2u, controller->desks().size());
   auto window = CreateTestWindow(gfx::Rect(0, 0, 250, 100));
   wm::ActivateWindow(window.get());
@@ -1879,7 +1889,7 @@
   // Create two desks with two windows on each, one window that belongs to the
   // first user, and the other belongs to the second.
   auto* controller = DesksController::Get();
-  controller->NewDesk();
+  NewDesk();
   ASSERT_EQ(2u, controller->desks().size());
   Desk* desk_1 = controller->desks()[0].get();
   Desk* desk_2 = controller->desks()[1].get();
@@ -2004,8 +2014,8 @@
   auto* controller = DesksController::Get();
   // Create a few desks and remove them outside and inside overview using the
   // shortcut.
-  controller->NewDesk();
-  controller->NewDesk();
+  NewDesk();
+  NewDesk();
   ASSERT_EQ(3u, controller->desks().size());
   Desk* desk_1 = controller->desks()[0].get();
   Desk* desk_2 = controller->desks()[1].get();
@@ -2028,7 +2038,7 @@
 
 TEST_F(DesksAcceleratorsTest, LeftRightDeskActivation) {
   auto* controller = DesksController::Get();
-  controller->NewDesk();
+  NewDesk();
   ASSERT_EQ(2u, controller->desks().size());
   Desk* desk_1 = controller->desks()[0].get();
   Desk* desk_2 = controller->desks()[1].get();
@@ -2061,7 +2071,7 @@
 
 TEST_F(DesksAcceleratorsTest, MoveWindowLeftRightDesk) {
   auto* controller = DesksController::Get();
-  controller->NewDesk();
+  NewDesk();
   ASSERT_EQ(2u, controller->desks().size());
   Desk* desk_1 = controller->desks()[0].get();
   Desk* desk_2 = controller->desks()[1].get();
@@ -2104,7 +2114,7 @@
 
 TEST_F(DesksAcceleratorsTest, MoveWindowLeftRightDeskOverview) {
   auto* controller = DesksController::Get();
-  controller->NewDesk();
+  NewDesk();
   ASSERT_EQ(2u, controller->desks().size());
   Desk* desk_1 = controller->desks()[0].get();
   Desk* desk_2 = controller->desks()[1].get();
diff --git a/ash/wm/overview/overview_grid.cc b/ash/wm/overview/overview_grid.cc
index 7ed98f1b..ef8942b 100644
--- a/ash/wm/overview/overview_grid.cc
+++ b/ash/wm/overview/overview_grid.cc
@@ -1230,7 +1230,9 @@
     if (target_desk == desks_controller->active_desk())
       return false;
 
-    desks_controller->MoveWindowFromActiveDeskTo(dragged_window, target_desk);
+    desks_controller->MoveWindowFromActiveDeskTo(
+        dragged_window, target_desk,
+        DesksMoveWindowFromActiveDeskSource::kDragAndDrop);
     return true;
   }
 
diff --git a/ash/wm/overview/overview_window_drag_controller_unittest.cc b/ash/wm/overview/overview_window_drag_controller_unittest.cc
index 7584bb4..1ffd667 100644
--- a/ash/wm/overview/overview_window_drag_controller_unittest.cc
+++ b/ash/wm/overview/overview_window_drag_controller_unittest.cc
@@ -223,7 +223,7 @@
        SwitchDragToCloseToNormalDragWhendraggedToDesk) {
   UpdateDisplay("600x800");
   auto* controller = DesksController::Get();
-  controller->NewDesk();
+  controller->NewDesk(DesksCreationRemovalSource::kButton);
   ASSERT_EQ(2u, controller->desks().size());
 
   auto window = CreateTestWindow(gfx::Rect(0, 0, 250, 100));
diff --git a/ash/wm/window_cycle_controller_unittest.cc b/ash/wm/window_cycle_controller_unittest.cc
index 8512f8b..350f129 100644
--- a/ash/wm/window_cycle_controller_unittest.cc
+++ b/ash/wm/window_cycle_controller_unittest.cc
@@ -697,7 +697,7 @@
   auto win0 = CreateTestWindow(gfx::Rect(0, 0, 250, 100));
   auto win1 = CreateTestWindow(gfx::Rect(50, 50, 200, 200));
   auto* desks_controller = DesksController::Get();
-  desks_controller->NewDesk();
+  desks_controller->NewDesk(DesksCreationRemovalSource::kButton);
   ASSERT_EQ(2u, desks_controller->desks().size());
   const Desk* desk_2 = desks_controller->desks()[1].get();
   ActivateDesk(desk_2);
diff --git a/base/immediate_crash.h b/base/immediate_crash.h
index 935fb00..94ee14f 100644
--- a/base/immediate_crash.h
+++ b/base/immediate_crash.h
@@ -33,33 +33,32 @@
 //   Note: this last bullet point may no longer be true, and may be removed in
 //   the future.
 
-// TODO(https://crbug.com/958675): TRAP_SEQUENCE_() was previously split into
-// two macro helpers to make it easier to simplify it to one instruction in
-// followups. TRAP_SEQUENCE2_() will be renamed and collapsed into
-// TRAP_SEQUENCE_() assuming nothing goes wrong...
+// Note: TRAP_SEQUENCE Is currently split into two macro helpers due to the fact
+// that clang emits an actual instruction for __builtin_unreachable() on certain
+// platforms (see https://crbug.com/958675). In addition, the int3/bkpt/brk will
+// be removed in followups, so splitting it up like this now makes it easy to
+// land the followups.
 
 #if defined(COMPILER_GCC)
 
 #if defined(OS_NACL)
 
 // Crash report accuracy is not guaranteed on NaCl.
-#define TRAP_SEQUENCE2_() __builtin_trap()
+#define TRAP_SEQUENCE1_() __builtin_trap()
+#define TRAP_SEQUENCE2_() asm volatile("")
 
 #elif defined(ARCH_CPU_X86_FAMILY)
 
-// In theory, it should be possible to use just int3. However, there are a
-// number of crashes with SIGILL as the exception code, so it seems likely that
-// there's a signal handler that allows execution to continue after SIGTRAP.
+// TODO(https://crbug.com/958675): In theory, it should be possible to use just
+// int3. However, there are a number of crashes with SIGILL as the exception
+// code, so it seems likely that there's a signal handler that allows execution
+// to continue after SIGTRAP.
+#define TRAP_SEQUENCE1_() asm volatile("int3")
 
 #if defined(OS_MACOSX)
 // Intentionally empty: __builtin_unreachable() is always part of the sequence
 // (see IMMEDIATE_CRASH below) and already emits a ud2 on Mac.
 #define TRAP_SEQUENCE2_() asm volatile("")
-#elif defined(OS_LINUX)
-// TODO(dcheng): Remove int3 on Linux as well. Removing it is preventing
-// IMMEDIATE_CRASH() from being detected as abnormal program termination on
-// Linux.
-#define TRAP_SEQUENCE2_() asm volatile("int3;ud2")
 #else
 #define TRAP_SEQUENCE2_() asm volatile("ud2")
 #endif  // defined(OS_MACOSX)
@@ -70,22 +69,23 @@
 // as a 32 bit userspace app on arm64. There doesn't seem to be any way to
 // cause a SIGTRAP from userspace without using a syscall (which would be a
 // problem for sandboxing).
-// TODO(dcheng): This likely will no longer generate a SIGTRAP, update this
-// comment to what it does generate?
+// TODO(https://crbug.com/958675): Remove bkpt from this sequence.
+#define TRAP_SEQUENCE1_() asm volatile("bkpt #0")
 #define TRAP_SEQUENCE2_() asm volatile("udf #0")
 
 #elif defined(ARCH_CPU_ARM64)
 
 // This will always generate a SIGTRAP on arm64.
-// TODO(dcheng): This likely will no longer generate a SIGTRAP, update this
-// comment to what it does generate?
+// TODO(https://crbug.com/958675): Remove brk from this sequence.
+#define TRAP_SEQUENCE1_() asm volatile("brk #0")
 #define TRAP_SEQUENCE2_() asm volatile("hlt #0")
 
 #else
 
 // Crash report accuracy will not be guaranteed on other architectures, but at
 // least this will crash as expected.
-#define TRAP_SEQUENCE2_() __builtin_trap()
+#define TRAP_SEQUENCE1_() __builtin_trap()
+#define TRAP_SEQUENCE2_() asm volatile("")
 
 #endif  // ARCH_CPU_*
 
@@ -94,16 +94,20 @@
 #if !defined(__clang__)
 
 // MSVC x64 doesn't support inline asm, so use the MSVC intrinsic.
-#define TRAP_SEQUENCE2_() __debugbreak()
+#define TRAP_SEQUENCE1_() __debugbreak()
+#define TRAP_SEQUENCE2_()
 
 #elif defined(ARCH_CPU_ARM64)
 
+#define TRAP_SEQUENCE1_() __asm volatile("brk #0\n")
 // Intentionally empty: __builtin_unreachable() is always part of the sequence
 // (see IMMEDIATE_CRASH below) and already emits a ud2 on Win64
 #define TRAP_SEQUENCE2_() __asm volatile("")
 
 #else
 
+#define TRAP_SEQUENCE1_() asm volatile("int3")
+
 #if defined(ARCH_CPU_64_BITS)
 // Intentionally empty: __builtin_unreachable() is always part of the sequence
 // (see IMMEDIATE_CRASH below) and already emits a ud2 on Win64
@@ -122,6 +126,7 @@
 
 #define TRAP_SEQUENCE_() \
   do {                   \
+    TRAP_SEQUENCE1_();   \
     TRAP_SEQUENCE2_();   \
   } while (false)
 
diff --git a/base/immediate_crash_unittest.cc b/base/immediate_crash_unittest.cc
index 1b538aeb..8fc9d38 100644
--- a/base/immediate_crash_unittest.cc
+++ b/base/immediate_crash_unittest.cc
@@ -38,19 +38,14 @@
   NativeLibraryLoadError load_error;
   FilePath helper_library_path;
 #if !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
-  // Appending the library name to DIR_EXE isn't necessary on all platforms (and
-  // can even break in some places):
-  // - on Android M, DIR_EXE == /system/bin when running base_unittests.
-  // - on Fuchsia, NativeLibrary knows where to look already, since it
-  //   understands the platform convention that libraries are not colocated with
-  //   the binary.
+  // On Android M, DIR_EXE == /system/bin when running base_unittests.
+  // On Fuchsia, NativeLibrary understands the native convention that libraries
+  // are not colocated with the binary.
   ASSERT_TRUE(PathService::Get(DIR_EXE, &helper_library_path));
 #endif
   helper_library_path = helper_library_path.AppendASCII(
       GetNativeLibraryName("immediate_crash_test_helper"));
 #if defined(OS_ANDROID) && defined(COMPONENT_BUILD)
-  // Android component builds use a unique shared library suffix to avoid naming
-  // collisions.
   helper_library_path = helper_library_path.ReplaceExtension(".cr.so");
 #endif
   // TODO(dcheng): Shouldn't GetNativeLibraryName just return a FilePath?
@@ -91,10 +86,8 @@
 
   // Look for two IMMEDIATE_CRASH() opcode sequences.
   for (int i = 0; i < 2; ++i) {
-#if defined(OS_LINUX)
-    // INT3
+    // INT 3
     EXPECT_EQ(0xCC, *++it);
-#endif  // defined(OS_LINUX)
     // UD2
     EXPECT_EQ(0x0F, *++it);
     EXPECT_EQ(0x0B, *++it);
@@ -127,6 +120,8 @@
 
   // Look for two IMMEDIATE_CRASH() opcode sequences.
   for (int i = 0; i < 2; ++i) {
+    // BKPT #0
+    EXPECT_EQ(0xBE00, *++it);
     // UDF #0
     EXPECT_EQ(0xDE00, *++it);
   }
@@ -148,6 +143,8 @@
 
   // Look for two IMMEDIATE_CRASH() opcode sequences.
   for (int i = 0; i < 2; ++i) {
+    // BRK #0
+    EXPECT_EQ(0XD4200000, *++it);
     // HLT #0
     EXPECT_EQ(0xD4400000, *++it);
   }
diff --git a/build/android/gyp/apkbuilder.py b/build/android/gyp/apkbuilder.py
index 9058e39..3ec75056 100755
--- a/build/android/gyp/apkbuilder.py
+++ b/build/android/gyp/apkbuilder.py
@@ -17,6 +17,10 @@
 import finalize_apk
 
 from util import build_utils
+from util import zipalign
+
+# Input dex.jar files are zipaligned.
+zipalign.ApplyZipFileZipAlignFix()
 
 
 # Taken from aapt's Package.cpp:
diff --git a/build/android/gyp/apkbuilder.pydeps b/build/android/gyp/apkbuilder.pydeps
index 3ae0331..24abfbc 100644
--- a/build/android/gyp/apkbuilder.pydeps
+++ b/build/android/gyp/apkbuilder.pydeps
@@ -6,3 +6,4 @@
 util/__init__.py
 util/build_utils.py
 util/md5_check.py
+util/zipalign.py
diff --git a/build/android/gyp/dex.py b/build/android/gyp/dex.py
index 9c551b9..a2e17b4 100755
--- a/build/android/gyp/dex.py
+++ b/build/android/gyp/dex.py
@@ -4,9 +4,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import json
+import argparse
 import logging
-import optparse
 import os
 import re
 import shutil
@@ -15,82 +14,59 @@
 import zipfile
 
 from util import build_utils
+from util import zipalign
 
 sys.path.insert(1, os.path.join(os.path.dirname(__file__), os.path.pardir))
 
 import convert_dex_profile
 
 
-def _CheckFilePathEndsWithJar(parser, file_path):
-  if not file_path.endswith(".jar"):
-    parser.error("%s does not end in .jar" % file_path)
-
-
-def _CheckFilePathsEndWithJar(parser, file_paths):
-  for file_path in file_paths:
-    _CheckFilePathEndsWithJar(parser, file_path)
-
-
 def _ParseArgs(args):
   args = build_utils.ExpandFileArgs(args)
+  parser = argparse.ArgumentParser()
 
-  parser = optparse.OptionParser()
   build_utils.AddDepfileOption(parser)
+  parser.add_argument('--output', required=True, help='Dex output path.')
+  parser.add_argument('--input-list', help='GN-list of additional input paths.')
+  parser.add_argument(
+      '--main-dex-list-path',
+      help='File containing a list of the classes to include in the main dex.')
+  parser.add_argument(
+      '--multi-dex',
+      action='store_true',
+      help='Allow multiple dex files within output.')
+  parser.add_argument('--d8-jar-path', required=True, help='Path to D8 jar.')
+  parser.add_argument(
+      '--release',
+      action='store_true',
+      help='Run D8 in release mode. Release mode maximises main dex and '
+      'deletes non-essential line number information (vs debug which minimizes '
+      'main dex and keeps all line number information, and then some.')
+  parser.add_argument(
+      '--min-api', help='Minimum Android API level compatibility.')
+  parser.add_argument('inputs', nargs='*', help='Input .jar files.')
 
-  parser.add_option('--output-directory',
-                    default=os.getcwd(),
-                    help='Path to the output build directory.')
-  parser.add_option('--dex-path', help='Dex output path.')
-  parser.add_option('--configuration-name',
-                    help='The build CONFIGURATION_NAME.')
-  parser.add_option('--proguard-enabled',
-                    help='"true" if proguard is enabled.')
-  parser.add_option('--debug-build-proguard-enabled',
-                    help='"true" if proguard is enabled for debug build.')
-  parser.add_option('--proguard-enabled-input-path',
-                    help=('Path to dex in Release mode when proguard '
-                          'is enabled.'))
-  parser.add_option('--inputs', help='A list of additional input paths.')
-  parser.add_option('--excluded-paths',
-                    help='A list of paths to exclude from the dex file.')
-  parser.add_option('--main-dex-list-path',
-                    help='A file containing a list of the classes to '
-                         'include in the main dex.')
-  parser.add_option('--multidex-configuration-path',
-                    help='A JSON file containing multidex build configuration.')
-  parser.add_option('--multi-dex', default=False, action='store_true',
-                    help='Generate multiple dex files.')
-  parser.add_option('--d8-jar-path', help='Path to D8 jar.')
-  parser.add_option('--release', action='store_true', default=False,
-                    help='Run D8 in release mode. Release mode maximises main '
-                    'dex and deletes non-essential line number information '
-                    '(vs debug which minimizes main dex and keeps all line '
-                    'number information, and then some.')
-  parser.add_option('--min-api',
-                    help='Minimum Android API level compatibility.')
-
-  parser.add_option('--dexlayout-profile',
-                    help=('Text profile for dexlayout. If present, a dexlayout '
-                          'pass will happen'))
-  parser.add_option('--profman-path',
-                    help=('Path to ART profman binary. There should be a '
-                          'lib/ directory at the same path containing shared '
-                          'libraries (shared with dexlayout).'))
-  parser.add_option('--dexlayout-path',
-                    help=('Path to ART dexlayout binary. There should be a '
-                          'lib/ directory at the same path containing shared '
-                          'libraries (shared with dexlayout).'))
-  parser.add_option('--dexdump-path', help='Path to dexdump binary.')
-  parser.add_option(
+  group = parser.add_argument_group('Dexlayout')
+  group.add_argument(
+      '--dexlayout-profile',
+      help=('Text profile for dexlayout. If present, a dexlayout '
+            'pass will happen'))
+  group.add_argument(
+      '--profman-path',
+      help=('Path to ART profman binary. There should be a lib/ directory at '
+            'the same path with shared libraries (shared with dexlayout).'))
+  group.add_argument(
+      '--dexlayout-path',
+      help=('Path to ART dexlayout binary. There should be a lib/ directory at '
+            'the same path with shared libraries (shared with dexlayout).'))
+  group.add_argument('--dexdump-path', help='Path to dexdump binary.')
+  group.add_argument(
       '--proguard-mapping-path',
       help=('Path to proguard map from obfuscated symbols in the jar to '
-            'unobfuscated symbols present in the code. If not '
-            'present, the jar is assumed not to be obfuscated.'))
+            'unobfuscated symbols present in the code. If not present, the jar '
+            'is assumed not to be obfuscated.'))
 
-  options, paths = parser.parse_args(args)
-
-  required_options = ('d8_jar_path',)
-  build_utils.CheckOptions(options, parser, required=required_options)
+  options = parser.parse_args(args)
 
   if options.dexlayout_profile:
     build_utils.CheckOptions(
@@ -98,67 +74,19 @@
         parser,
         required=('profman_path', 'dexlayout_path', 'dexdump_path'))
   elif options.proguard_mapping_path is not None:
-    raise Exception('Unexpected proguard mapping without dexlayout')
-
-  if options.multidex_configuration_path:
-    with open(options.multidex_configuration_path) as multidex_config_file:
-      multidex_config = json.loads(multidex_config_file.read())
-    options.multi_dex = multidex_config.get('enabled', False)
+    parser.error('Unexpected proguard mapping without dexlayout')
 
   if options.main_dex_list_path and not options.multi_dex:
-    logging.warning('--main-dex-list-path is unused if multidex is not enabled')
+    parser.error('--main-dex-list-path is unused if multidex is not enabled')
 
-  if options.inputs:
-    options.inputs = build_utils.ParseGnList(options.inputs)
-    _CheckFilePathsEndWithJar(parser, options.inputs)
-  if options.excluded_paths:
-    options.excluded_paths = build_utils.ParseGnList(options.excluded_paths)
+  if options.input_list:
+    options.inputs += build_utils.ParseGnList(options.input_list)
 
-  if options.proguard_enabled_input_path:
-    _CheckFilePathEndsWithJar(parser, options.proguard_enabled_input_path)
-  _CheckFilePathsEndWithJar(parser, paths)
-
-  return options, paths
-
-
-def _MoveTempDexFile(tmp_dex_dir, dex_path):
-  """Move the temp dex file out of |tmp_dex_dir|.
-
-  Args:
-    tmp_dex_dir: Path to temporary directory created with tempfile.mkdtemp().
-      The directory should have just a single file.
-    dex_path: Target path to move dex file to.
-
-  Raises:
-    Exception if there are multiple files in |tmp_dex_dir|.
-  """
-  tempfiles = os.listdir(tmp_dex_dir)
-  if len(tempfiles) > 1:
-    raise Exception('%d files created, expected 1' % len(tempfiles))
-
-  tmp_dex_path = os.path.join(tmp_dex_dir, tempfiles[0])
-  shutil.move(tmp_dex_path, dex_path)
-
-
-def _NoClassFiles(jar_paths):
-  """Returns True if there are no .class files in the given JARs.
-
-  Args:
-    jar_paths: list of strings representing JAR file paths.
-
-  Returns:
-    (bool) True if no .class files are found.
-  """
-  for jar_path in jar_paths:
-    with zipfile.ZipFile(jar_path) as jar:
-      if any(name.endswith('.class') for name in jar.namelist()):
-        return False
-  return True
+  return options
 
 
 def _RunD8(dex_cmd, input_paths, output_path):
-  dex_cmd += ['--output', output_path]
-  dex_cmd += input_paths
+  dex_cmd = dex_cmd + ['--output', output_path] + input_paths
   build_utils.CheckOutput(dex_cmd, print_stderr=False)
 
 
@@ -242,7 +170,7 @@
   output_files = os.listdir(dexlayout_output_dir)
   if not output_files:
     raise Exception('dexlayout unexpectedly produced no output')
-  return [os.path.join(dexlayout_output_dir, f) for f in output_files]
+  return sorted([os.path.join(dexlayout_output_dir, f) for f in output_files])
 
 
 def _ZipMultidex(file_dir, dex_files):
@@ -284,37 +212,44 @@
   return zip_name
 
 
-def _ZipSingleDex(dex_file, zip_name):
-  """Zip up a single dex file.
+def _ZipAligned(dex_files, output_path):
+  """Creates a .dex.jar with 4-byte aligned files.
 
   Args:
-    dex_file: A dexfile whose name is ignored.
-    zip_name: The output file in which to write the zip.
+    dex_files: List of dex files.
+    output_path: The output file in which to write the zip.
   """
-  build_utils.DoZip([('classes.dex', dex_file)], zip_name)
+  with zipfile.ZipFile(output_path, 'w') as z:
+    for i, dex_file in enumerate(dex_files):
+      name = 'classes{}.dex'.format(i + 1 if i > 0 else '')
+      zipalign.AddToZipHermetic(z, name, src_path=dex_file, alignment=4)
 
 
-def main(args):
-  options, paths = _ParseArgs(args)
-  if ((options.proguard_enabled == 'true'
-          and options.configuration_name == 'Release')
-      or (options.debug_build_proguard_enabled == 'true'
-          and options.configuration_name == 'Debug')):
-    paths = [options.proguard_enabled_input_path]
+def _PerformDexlayout(tmp_dir, tmp_dex_output, options):
+  if options.proguard_mapping_path is not None:
+    matching_profile = os.path.join(tmp_dir, 'obfuscated_profile')
+    convert_dex_profile.ObfuscateProfile(
+        options.dexlayout_profile, tmp_dex_output,
+        options.proguard_mapping_path, options.dexdump_path, matching_profile)
+  else:
+    logging.warning('No obfuscation for %s', options.dexlayout_profile)
+    matching_profile = options.dexlayout_profile
+  binary_profile = _CreateBinaryProfile(matching_profile, tmp_dex_output,
+                                        options.profman_path, tmp_dir)
+  output_files = _LayoutDex(binary_profile, tmp_dex_output,
+                            options.dexlayout_path, tmp_dir)
+  if len(output_files) > 1:
+    return _ZipMultidex(tmp_dir, output_files)
 
-  if options.inputs:
-    paths += options.inputs
+  if zipfile.is_zipfile(output_files[0]):
+    return output_files[0]
 
-  if options.excluded_paths:
-    # Excluded paths are relative to the output directory.
-    exclude_paths = options.excluded_paths
-    paths = [p for p in paths if not
-             os.path.relpath(p, options.output_directory) in exclude_paths]
+  final_output = os.path.join(tmp_dir, 'dex_classes.zip')
+  _ZipAligned(output_files, final_output)
+  return final_output
 
-  input_paths = list(paths)
-  if options.multi_dex and options.main_dex_list_path:
-    input_paths.append(options.main_dex_list_path)
 
+def _PerformDexing(options):
   dex_cmd = ['java', '-jar', options.d8_jar_path, '--no-desugaring']
   if options.multi_dex and options.main_dex_list_path:
     dex_cmd += ['--main-dex-list', options.main_dex_list_path]
@@ -323,62 +258,39 @@
   if options.min_api:
     dex_cmd += ['--min-api', options.min_api]
 
-  is_dex = options.dex_path.endswith('.dex')
-  is_jar = options.dex_path.endswith('.jar')
-
   with build_utils.TempDir() as tmp_dir:
     tmp_dex_dir = os.path.join(tmp_dir, 'tmp_dex_dir')
     os.mkdir(tmp_dex_dir)
-    if is_jar and _NoClassFiles(paths):
-      # Handle case where no classfiles are specified in inputs
-      # by creating an empty JAR
-      with zipfile.ZipFile(options.dex_path, 'w') as outfile:
-        outfile.comment = 'empty'
-    else:
-      # .dex files can't specify a name for D8. Instead, we output them to a
-      # temp directory then move them after the command has finished running
-      # (see _MoveTempDexFile). For other files, tmp_dex_dir is None.
-      _RunD8(dex_cmd, paths, tmp_dex_dir)
+    _RunD8(dex_cmd, options.inputs, tmp_dex_dir)
+    dex_files = [os.path.join(tmp_dex_dir, f) for f in os.listdir(tmp_dex_dir)]
 
-    tmp_dex_output = os.path.join(tmp_dir, 'tmp_dex_output')
-    if is_dex:
-      _MoveTempDexFile(tmp_dex_dir, tmp_dex_output)
+    if not options.output.endswith('.dex'):
+      tmp_dex_output = os.path.join(tmp_dir, 'tmp_dex_output.zip')
+      _ZipAligned(sorted(dex_files), tmp_dex_output)
     else:
-      # d8 supports outputting to a .zip, but does not have deterministic file
-      # ordering: https://issuetracker.google.com/issues/119945929
-      build_utils.ZipDir(tmp_dex_output, tmp_dex_dir)
+      # Output to a .dex file.
+      if len(dex_files) > 1:
+        raise Exception('%d files created, expected 1' % len(dex_files))
+      tmp_dex_output = dex_files[0]
 
     if options.dexlayout_profile:
-      if options.proguard_mapping_path is not None:
-        matching_profile = os.path.join(tmp_dir, 'obfuscated_profile')
-        convert_dex_profile.ObfuscateProfile(
-            options.dexlayout_profile, tmp_dex_output,
-            options.proguard_mapping_path, options.dexdump_path,
-            matching_profile)
-      else:
-        logging.warning('No obfuscation for %s', options.dexlayout_profile)
-        matching_profile = options.dexlayout_profile
-      binary_profile = _CreateBinaryProfile(matching_profile, tmp_dex_output,
-                                            options.profman_path, tmp_dir)
-      output_files = _LayoutDex(binary_profile, tmp_dex_output,
-                                options.dexlayout_path, tmp_dir)
-      target = None
-      if len(output_files) > 1:
-        target = _ZipMultidex(tmp_dir, output_files)
-      else:
-        output = output_files[0]
-        if not zipfile.is_zipfile(output):
-          target = os.path.join(tmp_dir, 'dex_classes.zip')
-          _ZipSingleDex(output, target)
-        else:
-          target = output
-      shutil.move(os.path.join(tmp_dir, target), tmp_dex_output)
+      tmp_dex_output = _PerformDexlayout(tmp_dir, tmp_dex_output, options)
 
     # The dex file is complete and can be moved out of tmp_dir.
-    shutil.move(tmp_dex_output, options.dex_path)
+    shutil.move(tmp_dex_output, options.output)
+
+
+def main(args):
+  options = _ParseArgs(args)
+
+  input_paths = list(options.inputs)
+  if options.multi_dex and options.main_dex_list_path:
+    input_paths.append(options.main_dex_list_path)
+
+  _PerformDexing(options)
 
   build_utils.WriteDepfile(
-      options.depfile, options.dex_path, input_paths, add_pydeps=False)
+      options.depfile, options.output, input_paths, add_pydeps=False)
 
 
 if __name__ == '__main__':
diff --git a/build/android/gyp/dex.pydeps b/build/android/gyp/dex.pydeps
index e5ecbd2..5fe5b2b99 100644
--- a/build/android/gyp/dex.pydeps
+++ b/build/android/gyp/dex.pydeps
@@ -6,3 +6,4 @@
 util/__init__.py
 util/build_utils.py
 util/md5_check.py
+util/zipalign.py
diff --git a/build/android/gyp/util/build_utils.py b/build/android/gyp/util/build_utils.py
index fabd1e3..4653d99 100644
--- a/build/android/gyp/util/build_utils.py
+++ b/build/android/gyp/util/build_utils.py
@@ -34,10 +34,6 @@
     os.path.abspath(os.path.join(os.path.dirname(__file__),
                                  os.pardir, os.pardir, os.pardir, os.pardir)))
 
-HERMETIC_TIMESTAMP = (2001, 1, 1, 0, 0, 0)
-_HERMETIC_FILE_ATTR = (0o644 << 16)
-
-
 try:
   string_types = basestring
 except NameError:
@@ -314,13 +310,24 @@
   return extracted
 
 
-def AddToZipHermetic(zip_file, zip_path, src_path=None, data=None,
+def HermeticZipInfo(*args, **kwargs):
+  """Creates a ZipInfo with a constant timestamp and external_attr."""
+  ret = zipfile.ZipInfo(*args, **kwargs)
+  ret.date_time = (2001, 1, 1, 0, 0, 0)
+  ret.external_attr = (0o644 << 16)
+  return ret
+
+
+def AddToZipHermetic(zip_file,
+                     zip_path,
+                     src_path=None,
+                     data=None,
                      compress=None):
   """Adds a file to the given ZipFile with a hard-coded modified time.
 
   Args:
     zip_file: ZipFile instance to add the file to.
-    zip_path: Destination path within the zip file.
+    zip_path: Destination path within the zip file (or ZipInfo instance).
     src_path: Path of the source file. Mutually exclusive with |data|.
     data: File data as a string.
     compress: Whether to enable compression. Default is taken from ZipFile
@@ -328,9 +335,13 @@
   """
   assert (src_path is None) != (data is None), (
       '|src_path| and |data| are mutually exclusive.')
+  if isinstance(zip_path, zipfile.ZipInfo):
+    zipinfo = zip_path
+    zip_path = zipinfo.filename
+  else:
+    zipinfo = HermeticZipInfo(filename=zip_path)
+
   _CheckZipPath(zip_path)
-  zipinfo = zipfile.ZipInfo(filename=zip_path, date_time=HERMETIC_TIMESTAMP)
-  zipinfo.external_attr = _HERMETIC_FILE_ATTR
 
   if src_path and os.path.islink(src_path):
     zipinfo.filename = zip_path
diff --git a/build/android/gyp/util/zipalign.py b/build/android/gyp/util/zipalign.py
new file mode 100644
index 0000000..0110df6
--- /dev/null
+++ b/build/android/gyp/util/zipalign.py
@@ -0,0 +1,94 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import struct
+import sys
+import zipfile
+
+from util import build_utils
+
+_FIXED_ZIP_HEADER_LEN = 30
+
+
+def _PatchedDecodeExtra(self):
+  # Try to decode the extra field.
+  extra = self.extra
+  unpack = struct.unpack
+  while len(extra) >= 4:
+    tp, ln = unpack('<HH', extra[:4])
+    if tp == 1:
+      if ln >= 24:
+        counts = unpack('<QQQ', extra[4:28])
+      elif ln == 16:
+        counts = unpack('<QQ', extra[4:20])
+      elif ln == 8:
+        counts = unpack('<Q', extra[4:12])
+      elif ln == 0:
+        counts = ()
+      else:
+        raise RuntimeError, "Corrupt extra field %s" % (ln, )
+
+      idx = 0
+
+      # ZIP64 extension (large files and/or large archives)
+      if self.file_size in (0xffffffffffffffffL, 0xffffffffL):
+        self.file_size = counts[idx]
+        idx += 1
+
+      if self.compress_size == 0xFFFFFFFFL:
+        self.compress_size = counts[idx]
+        idx += 1
+
+      if self.header_offset == 0xffffffffL:
+        self.header_offset = counts[idx]
+        idx += 1
+
+    extra = extra[ln + 4:]
+
+
+def ApplyZipFileZipAlignFix():
+  """Fix zipfile.ZipFile() to be able to open zipaligned .zip files.
+
+  Android's zip alignment uses not-quite-valid zip headers to perform alignment.
+  Python < 3.4 crashes when trying to load them.
+  https://bugs.python.org/issue14315
+  """
+  if sys.version_info < (3, 4):
+    zipfile.ZipInfo._decodeExtra = (  # pylint: disable=protected-access
+        _PatchedDecodeExtra)
+
+
+def _SetAlignment(zip_obj, zip_info, alignment):
+  """Sets a ZipInfo's extra field such that the file will be aligned.
+
+  Args:
+    zip_obj: The ZipFile object that is being written.
+    zip_info: The ZipInfo object about to be written.
+    alignment: The amount of alignment (e.g. 4, or 4*1024).
+  """
+  cur_offset = zip_obj.fp.tell()
+  header_size = _FIXED_ZIP_HEADER_LEN + len(zip_info.filename)
+  padding_needed = (header_size - cur_offset) % alignment
+
+  # Extra field used to 4-byte align classes.dex. Alignment speeds up
+  # execution when dex files are used via incremental install.
+  zip_info.extra = b'\0' * padding_needed
+
+
+def AddToZipHermetic(zip_file,
+                     zip_path,
+                     src_path=None,
+                     data=None,
+                     compress=None,
+                     alignment=None):
+  """Same as build_utils.AddToZipHermetic(), but with alignment.
+
+  Args:
+    alignment: If set, align the data of the entry to this many bytes.
+  """
+  zipinfo = build_utils.HermeticZipInfo(filename=zip_path)
+  if alignment:
+    _SetAlignment(zip_file, zipinfo, alignment)
+  build_utils.AddToZipHermetic(
+      zip_file, zipinfo, src_path=src_path, data=data, compress=compress)
diff --git a/build/android/resource_sizes.py b/build/android/resource_sizes.py
index fc668ff..ddcc6e7 100755
--- a/build/android/resource_sizes.py
+++ b/build/android/resource_sizes.py
@@ -18,7 +18,6 @@
 import os
 import posixpath
 import re
-import struct
 import sys
 import tempfile
 import zipfile
@@ -47,50 +46,13 @@
 
 with host_paths.SysPath(_BUILD_UTILS_PATH, 0):
   from util import build_utils # pylint: disable=import-error
+  from util import zipalign  # pylint: disable=import-error
 
 with host_paths.SysPath(_APK_PATCH_SIZE_ESTIMATOR_PATH):
   import apk_patch_size_estimator # pylint: disable=import-error
 
 
-# Python had a bug in zipinfo parsing that triggers on ChromeModern.apk
-# https://bugs.python.org/issue14315
-def _PatchedDecodeExtra(self):
-  # Try to decode the extra field.
-  extra = self.extra
-  unpack = struct.unpack
-  while len(extra) >= 4:
-    tp, ln = unpack('<HH', extra[:4])
-    if tp == 1:
-      if ln >= 24:
-        counts = unpack('<QQQ', extra[4:28])
-      elif ln == 16:
-        counts = unpack('<QQ', extra[4:20])
-      elif ln == 8:
-        counts = unpack('<Q', extra[4:12])
-      elif ln == 0:
-        counts = ()
-      else:
-        raise RuntimeError, "Corrupt extra field %s"%(ln,)
-
-      idx = 0
-
-      # ZIP64 extension (large files and/or large archives)
-      if self.file_size in (0xffffffffffffffffL, 0xffffffffL):
-        self.file_size = counts[idx]
-        idx += 1
-
-      if self.compress_size == 0xFFFFFFFFL:
-        self.compress_size = counts[idx]
-        idx += 1
-
-      if self.header_offset == 0xffffffffL:
-        self.header_offset = counts[idx]
-        idx += 1
-
-    extra = extra[ln + 4:]
-
-zipfile.ZipInfo._decodeExtra = (  # pylint: disable=protected-access
-    _PatchedDecodeExtra)
+zipalign.ApplyZipFileZipAlignFix()
 
 # Captures an entire config from aapt output.
 _AAPT_CONFIG_PATTERN = r'config %s:(.*?)config [a-zA-Z-]+:'
diff --git a/build/android/resource_sizes.pydeps b/build/android/resource_sizes.pydeps
index 865f501..0de7e1a7 100644
--- a/build/android/resource_sizes.pydeps
+++ b/build/android/resource_sizes.pydeps
@@ -55,6 +55,7 @@
 gyp/util/__init__.py
 gyp/util/build_utils.py
 gyp/util/md5_check.py
+gyp/util/zipalign.py
 method_count.py
 pylib/__init__.py
 pylib/constants/__init__.py
diff --git a/build/chromeos/test_runner.py b/build/chromeos/test_runner.py
index 6437758..b5eefd0 100755
--- a/build/chromeos/test_runner.py
+++ b/build/chromeos/test_runner.py
@@ -451,13 +451,6 @@
               vpython_spec_path),
       ])
 
-    # Load vivid before running capture_unittests
-    # TODO(crbug.com/904730): Once we start loading vivid in init service,
-    # we can remove this code.
-    if self._test_exe == 'capture_unittests':
-      device_test_script_contents.append(
-          'echo "test0000" | sudo -S modprobe vivid n_devs=1 node_types=0x1')
-
     test_invocation = (
         './%s --test-launcher-shard-index=%d '
         '--test-launcher-total-shards=%d' % (
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index 8798d2c2..c4a8508f 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -1301,13 +1301,11 @@
           invoker.output,
         ]
 
-        _rebased_output = rebase_path(invoker.output, root_build_dir)
-
         args = [
           "--depfile",
           rebase_path(depfile, root_build_dir),
-          "--dex-path",
-          _rebased_output,
+          "--output",
+          rebase_path(outputs[0], root_build_dir),
         ]
 
         if (_proguard_enabled) {
@@ -1328,7 +1326,7 @@
 
         if (defined(invoker.input_dex_classpath)) {
           inputs += [ invoker.build_config ]
-          args += [ "--inputs=@FileArg(${invoker.input_dex_classpath})" ]
+          args += [ "--input-list=@FileArg(${invoker.input_dex_classpath})" ]
         }
 
         inputs += _dexing_jars
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 8d8aa49..229830bee 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8907212163018088496
\ No newline at end of file
+8907184702725321600
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index cd0eae4..ceb1964 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-8907212488043371600
\ No newline at end of file
+8907184320698320384
\ No newline at end of file
diff --git a/build/mac_toolchain.py b/build/mac_toolchain.py
index a7407a93..fefdba7a 100755
--- a/build/mac_toolchain.py
+++ b/build/mac_toolchain.py
@@ -152,6 +152,14 @@
   args = [
       'cipd', 'ensure', '-root', binaries_root, '-ensure-file', '-'
   ]
+
+  # Buildbot slaves need to use explicit credentials. LUCI bots should NOT set
+  # this variable. This is temporary code used to make official Xcode bots
+  # happy. https://crbug.com/986488
+  creds = os.environ.get('MAC_TOOLCHAIN_CREDS')
+  if creds:
+    args.extend(['--service-account-json', creds])
+
   p = subprocess.Popen(
       args, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
       stderr=subprocess.PIPE)
@@ -190,9 +198,9 @@
   # Use puppet's sudoers script to accept the license if its available.
   license_accept_script = '/usr/local/bin/xcode_accept_license.py'
   if os.path.exists(license_accept_script):
-    args = ['sudo', license_accept_script, '--xcode_version',
+    args = ['sudo', license_accept_script, '--xcode-version',
             cipd_xcode_version, '--license-version', cipd_license_version]
-    subprocess.call(args)
+    subprocess.check_call(args)
     return 0
 
   # Otherwise manually accept the license. This will prompt for sudo.
@@ -200,12 +208,12 @@
   sys.stdout.flush()
   args = ['sudo', 'defaults', 'write', current_license_path,
           'IDEXcodeVersionForAgreedToGMLicense', cipd_xcode_version]
-  subprocess.call(args)
+  subprocess.check_call(args)
   args = ['sudo', 'defaults', 'write', current_license_path,
           'IDELastGMLicenseAgreedTo', cipd_license_version]
-  subprocess.call(args)
+  subprocess.check_call(args)
   args = ['sudo', 'plutil', '-convert', 'xml1', current_license_path]
-  subprocess.call(args)
+  subprocess.check_call(args)
 
   return 0
 
diff --git a/cc/test/render_pass_test_utils.cc b/cc/test/render_pass_test_utils.cc
index 96524b32..6ff1bf3 100644
--- a/cc/test/render_pass_test_utils.cc
+++ b/cc/test/render_pass_test_utils.cc
@@ -107,8 +107,8 @@
   return quad;
 }
 
-void AddRenderPassQuad(viz::RenderPass* to_pass,
-                       viz::RenderPass* contributing_pass) {
+viz::RenderPassDrawQuad* AddRenderPassQuad(viz::RenderPass* to_pass,
+                                           viz::RenderPass* contributing_pass) {
   gfx::Rect output_rect = contributing_pass->output_rect;
   viz::SharedQuadState* shared_state =
       to_pass->CreateAndAppendSharedQuadState();
@@ -119,6 +119,7 @@
   quad->SetNew(shared_state, output_rect, output_rect, contributing_pass->id, 0,
                gfx::RectF(), gfx::Size(), false, gfx::Vector2dF(),
                gfx::PointF(), gfx::RectF(), false, 1.0f);
+  return quad;
 }
 
 void AddRenderPassQuad(viz::RenderPass* to_pass,
diff --git a/cc/test/render_pass_test_utils.h b/cc/test/render_pass_test_utils.h
index f96ed99..0b852b54 100644
--- a/cc/test/render_pass_test_utils.h
+++ b/cc/test/render_pass_test_utils.h
@@ -64,8 +64,8 @@
                                             const gfx::Transform& transform);
 
 // Adds a render pass quad to an existing render pass.
-void AddRenderPassQuad(viz::RenderPass* to_pass,
-                       viz::RenderPass* contributing_pass);
+viz::RenderPassDrawQuad* AddRenderPassQuad(viz::RenderPass* to_pass,
+                                           viz::RenderPass* contributing_pass);
 
 // Adds a render pass quad with the given mask resource, filter, and transform.
 void AddRenderPassQuad(viz::RenderPass* to_pass,
diff --git a/chrome/VERSION b/chrome/VERSION
index fa4b8e3..d9d8172 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=77
 MINOR=0
-BUILD=3861
+BUILD=3862
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java
index 0aa40b40..57840d35a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java
@@ -785,6 +785,7 @@
         List<Long> themeColors = new ArrayList<>();
         List<Long> backgroundColors = new ArrayList<>();
         List<Long> lastUpdateCheckTimesMs = new ArrayList<>();
+        List<Long> lastUpdateCompletionTimeMs = new ArrayList<>();
         List<Boolean> relaxUpdates = new ArrayList<>();
         List<String> updateStatuses = new ArrayList<>();
 
@@ -816,15 +817,19 @@
                     WebappDataStorage storage =
                             WebappRegistry.getInstance().getWebappDataStorage(webApkInfo.id());
                     long lastUpdateCheckTimeMsForStorage = 0;
+                    long lastUpdateCompletionTimeMsInStorage = 0;
                     boolean relaxUpdatesForStorage = false;
                     String updateStatus = WebappDataStorage.NOT_UPDATABLE;
                     if (storage != null) {
                         lastUpdateCheckTimeMsForStorage =
                                 storage.getLastCheckForWebManifestUpdateTimeMs();
+                        lastUpdateCompletionTimeMsInStorage =
+                                storage.getLastWebApkUpdateRequestCompletionTimeMs();
                         relaxUpdatesForStorage = storage.shouldRelaxUpdates();
                         updateStatus = storage.getUpdateStatus();
                     }
                     lastUpdateCheckTimesMs.add(lastUpdateCheckTimeMsForStorage);
+                    lastUpdateCompletionTimeMs.add(lastUpdateCompletionTimeMsInStorage);
                     relaxUpdates.add(relaxUpdatesForStorage);
                     updateStatuses.add(updateStatus);
                 }
@@ -841,6 +846,7 @@
                 CollectionUtil.longListToLongArray(themeColors),
                 CollectionUtil.longListToLongArray(backgroundColors),
                 CollectionUtil.longListToLongArray(lastUpdateCheckTimesMs),
+                CollectionUtil.longListToLongArray(lastUpdateCompletionTimeMs),
                 CollectionUtil.booleanListToBooleanArray(relaxUpdates),
                 updateStatuses.toArray(new String[0]));
     }
@@ -858,6 +864,6 @@
             String[] shortNames, String[] packageNames, String[] ids, int[] shellApkVersions,
             int[] versionCodes, String[] uris, String[] scopes, String[] manifestUrls,
             String[] manifestStartUrls, int[] displayModes, int[] orientations, long[] themeColors,
-            long[] backgroundColors, long[] lastUpdateCheckTimesMs, boolean[] relaxUpdates,
-            String[] updateStatuses);
+            long[] backgroundColors, long[] lastUpdateCheckTimesMs,
+            long[] lastUpdateCompletionTimeMs, boolean[] relaxUpdates, String[] updateStatuses);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
index 9ecb9496..7b86064 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
@@ -313,13 +313,14 @@
         });
 
         if (!mNativeInitializationComplete) {
-            tasks.add(UiThreadTaskTraits.DEFAULT, () -> {
-                int startupMode = getBrowserStartupController().getStartupMode(
-                        delegate.startServiceManagerOnly());
-                onFinishNativeInitialization(startupMode);
-            });
+            tasks.add(UiThreadTaskTraits.DEFAULT, this::onFinishNativeInitialization);
         }
 
+        int startupMode =
+                getBrowserStartupController().getStartupMode(delegate.startServiceManagerOnly());
+        tasks.add(UiThreadTaskTraits.BEST_EFFORT,
+                () -> { BackgroundTaskSchedulerExternalUma.reportStartupMode(startupMode); });
+
         if (isAsync) {
             // We want to start this queue once the C++ startup tasks have run; allow the
             // C++ startup to run asynchonously, and set it up to start the Java queue once
@@ -400,7 +401,7 @@
         SpeechRecognition.initialize();
     }
 
-    private void onFinishNativeInitialization(int startupMode) {
+    private void onFinishNativeInitialization() {
         if (mNativeInitializationComplete) return;
 
         mNativeInitializationComplete = true;
@@ -436,8 +437,6 @@
         // TODO(crbug.com/960767): Remove this in M77.
         ServiceManagerStartupUtils.cleanupSharedPreferences();
 
-        BackgroundTaskSchedulerExternalUma.reportStartupMode(startupMode);
-
         PostTask.postTask(
                 TaskTraits.BEST_EFFORT_MAY_BLOCK, LibraryPrefetcher::maybePinOrderedCodeInMemory);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDataStorage.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDataStorage.java
index 5579e709..c95f2027 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDataStorage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDataStorage.java
@@ -456,7 +456,7 @@
      * Returns the time, in milliseconds, that the last WebAPK update request completed
      * (successfully or unsuccessfully). This time needs to be set when the WebAPK is registered.
      */
-    long getLastWebApkUpdateRequestCompletionTimeMs() {
+    public long getLastWebApkUpdateRequestCompletionTimeMs() {
         return mPreferences.getLong(KEY_LAST_UPDATE_REQUEST_COMPLETE_TIME, TIMESTAMP_INVALID);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
index 03234a2..3ee1109 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
@@ -643,6 +643,7 @@
                 }
 
                 if (!mGestureDetector.isScrolling()) {
+                    cancelAnimation();
 
                     // This onLayoutChange() will be called after the user enters fullscreen video
                     // mode. Ensure the sheet state is reset to peek so that the sheet does not
@@ -651,7 +652,6 @@
                             && mFullscreenManager.getPersistentFullscreenMode() && isSheetOpen()) {
                         setSheetState(SheetState.PEEK, false);
                     } else {
-                        if (isRunningSettleAnimation()) return;
                         setSheetState(mCurrentState, false);
                     }
                 }
@@ -1153,16 +1153,8 @@
             // If the toolbar is not laid out yet and has a fixed height layout parameter, we assume
             // that the toolbar will have this height in the future.
             ViewGroup.LayoutParams layoutParams = toolbarView.getLayoutParams();
-            if (layoutParams != null) {
-                if (layoutParams.height > 0) {
-                    toolbarHeight = layoutParams.height;
-                } else {
-                    toolbarView.measure(
-                            MeasureSpec.makeMeasureSpec((int) mContainerWidth, MeasureSpec.EXACTLY),
-                            MeasureSpec.makeMeasureSpec(
-                                    (int) mContainerHeight, MeasureSpec.AT_MOST));
-                    toolbarHeight = toolbarView.getMeasuredHeight();
-                }
+            if (layoutParams != null && layoutParams.height > 0) {
+                toolbarHeight = layoutParams.height;
             }
         }
         return (toolbarHeight + mToolbarShadowHeight) / mContainerHeight;
@@ -1272,9 +1264,6 @@
             @SheetState int state, boolean animate, @StateChangeReason int reason) {
         assert state != SheetState.SCROLLING && state != SheetState.NONE;
 
-        // No-op if we're already animating toward the requested state.
-        if (state == mCurrentState && animate && isRunningSettleAnimation()) return;
-
         if (state == SheetState.HALF && shouldSkipHalfState()) {
             state = SheetState.FULL;
         }
@@ -1597,7 +1586,9 @@
 
         // The SCROLLING state is used when animating the sheet height or when the user is swiping
         // the sheet. If it is the latter, we should not change the sheet height.
-        if (animate && isRunningSettleAnimation()) return;
+        cancelAnimation();
+        if (mCurrentState == SheetState.SCROLLING) return;
+
         setSheetState(mCurrentState, animate);
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/profiling_host/ProfilingProcessHostAndroidTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/profiling_host/ProfilingProcessHostAndroidTest.java
index dd82001..6c7c49e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/profiling_host/ProfilingProcessHostAndroidTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/profiling_host/ProfilingProcessHostAndroidTest.java
@@ -97,6 +97,7 @@
         Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", true, false));
     }
 
+    @DisabledTest(message = "https://crbug.com/986667")
     @Test
     @MediumTest
     public void testModeBrowserAndAllUtility() throws Exception {
diff --git a/chrome/app/BUILD.gn b/chrome/app/BUILD.gn
index 5815a61..fbb5c2da 100644
--- a/chrome/app/BUILD.gn
+++ b/chrome/app/BUILD.gn
@@ -425,7 +425,7 @@
     "//chrome/common:page_load_metrics_mojom",
     "//chrome/common/media_router/mojo:media_router",
     "//chrome/test/data:web_ui_test_bindings",
-    "//components/autofill/content/common:mojo_interfaces",
+    "//components/autofill/content/common/mojom",
     "//components/contextual_search/content/common/mojom",
     "//components/data_reduction_proxy/core/common:interfaces",
     "//components/dom_distiller/content/common/mojom",
@@ -521,7 +521,7 @@
     "//base",
     "//chrome/common:mojo_bindings",
     "//chrome/common:search_mojom",
-    "//components/autofill/content/common:mojo_interfaces",
+    "//components/autofill/content/common/mojom",
     "//components/dom_distiller/content/common/mojom",
     "//components/metrics/public/interfaces:call_stack_mojo_bindings",
     "//components/rappor/public/interfaces",
diff --git a/chrome/app/chrome_content_browser_overlay_manifest.cc b/chrome/app/chrome_content_browser_overlay_manifest.cc
index faf0b60..899cbed 100644
--- a/chrome/app/chrome_content_browser_overlay_manifest.cc
+++ b/chrome/app/chrome_content_browser_overlay_manifest.cc
@@ -25,7 +25,7 @@
 #include "chrome/common/page_load_metrics/page_load_metrics.mojom.h"
 #include "chrome/common/prerender.mojom.h"
 #include "chrome/test/data/webui/web_ui_test.mojom.h"
-#include "components/autofill/content/common/autofill_driver.mojom.h"
+#include "components/autofill/content/common/mojom/autofill_driver.mojom.h"
 #include "components/contextual_search/content/common/mojom/contextual_search_js_api_service.mojom.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy.mojom.h"
 #include "components/dom_distiller/content/common/mojom/distillability_service.mojom.h"
diff --git a/chrome/app/chrome_content_renderer_overlay_manifest.cc b/chrome/app/chrome_content_renderer_overlay_manifest.cc
index c5e21ba..11bc4f6 100644
--- a/chrome/app/chrome_content_renderer_overlay_manifest.cc
+++ b/chrome/app/chrome_content_renderer_overlay_manifest.cc
@@ -10,7 +10,7 @@
 #include "chrome/common/content_settings_renderer.mojom.h"
 #include "chrome/common/prerender.mojom.h"
 #include "chrome/common/search.mojom.h"
-#include "components/autofill/content/common/autofill_agent.mojom.h"
+#include "components/autofill/content/common/mojom/autofill_agent.mojom.h"
 #include "components/dom_distiller/content/common/mojom/distiller_page_notifier_service.mojom.h"
 #include "components/safe_browsing/common/safe_browsing.mojom.h"
 #include "components/services/heap_profiling/public/mojom/heap_profiling_client.mojom.h"
diff --git a/chrome/app/chrome_renderer_manifest.cc b/chrome/app/chrome_renderer_manifest.cc
index d086ebde5..2bdac3d9 100644
--- a/chrome/app/chrome_renderer_manifest.cc
+++ b/chrome/app/chrome_renderer_manifest.cc
@@ -7,6 +7,7 @@
 #include "base/no_destructor.h"
 #include "build/build_config.h"
 #include "chrome/common/constants.mojom.h"
+#include "chrome/common/media/webrtc_logging.mojom.h"
 #include "components/safe_browsing/common/safe_browsing.mojom.h"
 #include "components/spellcheck/common/spellcheck.mojom.h"
 #include "services/service_manager/public/cpp/manifest_builder.h"
@@ -17,6 +18,7 @@
           .WithServiceName(chrome::mojom::kRendererServiceName)
           .ExposeCapability("browser",
                             service_manager::Manifest::InterfaceList<
+                                chrome::mojom::WebRtcLoggingAgent,
                                 safe_browsing::mojom::PhishingModelSetter,
                                 spellcheck::mojom::SpellChecker>())
           .RequireCapability(chrome::mojom::kServiceName, "renderer")
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 07d9f78..a54f295 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -3727,7 +3727,7 @@
     Backup couldn't be completed due to an error
   </message>
   <message name="IDS_CROSTINI_EXPORT_NOTIFICATION_MESSAGE_FAILED_IN_PROGRESS" desc="Message displayed in the notification when export (backup) of the Linux container fails due to another being in progress.">
-    Backup currently in progress for <ph name="CONTAINER_ID">$1<ex>(termina, penguin)</ex></ph>
+    Linux backup currently in progress
   </message>
   <message name="IDS_CROSTINI_IMPORT_NOTIFICATION_TITLE_RUNNING" desc="Title displayed in the notification while import (restore) of the Linux container is in progress.">
     Restoring Linux apps &amp; files
@@ -3745,7 +3745,7 @@
     Restoring couldn't be completed due to an error
   </message>
   <message name="IDS_CROSTINI_IMPORT_NOTIFICATION_MESSAGE_FAILED_IN_PROGRESS" desc="Message displayed in the notification when import (restore) of the Linux container fails due to another being in progress.">
-    Restore currently in progress for <ph name="CONTAINER_ID">$1<ex>(termina, penguin)</ex></ph>
+    Linux restore currently in progress
   </message>
   <message name="IDS_CROSTINI_IMPORT_NOTIFICATION_MESSAGE_FAILED_ARCHITECTURE" desc="Message displayed in the notification when import (restore) of the Linux container fails due to architecture mismatch.">
     Cannot import container architecture type <ph name="ARCHITECTURE_CONTAINER">$1<ex>arm64</ex></ph> with this device which is <ph name="ARCHITECTURE_DEVICE">$2<ex>x86_64</ex></ph>. You can try restoring this container into a different device, or you can access the files inside this container image by opening in Files app.
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_EXPORT_NOTIFICATION_MESSAGE_FAILED_IN_PROGRESS.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_EXPORT_NOTIFICATION_MESSAGE_FAILED_IN_PROGRESS.png.sha1
index 2268b15..ea2017e 100644
--- a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_EXPORT_NOTIFICATION_MESSAGE_FAILED_IN_PROGRESS.png.sha1
+++ b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_EXPORT_NOTIFICATION_MESSAGE_FAILED_IN_PROGRESS.png.sha1
@@ -1 +1 @@
-3519b1b96658bf54a93cb2df6d8b5d711522c9f7
\ No newline at end of file
+1aef0ca7aca195b84ea1054fb9f39888b6080324
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_IMPORT_NOTIFICATION_MESSAGE_FAILED_IN_PROGRESS.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_IMPORT_NOTIFICATION_MESSAGE_FAILED_IN_PROGRESS.png.sha1
index 2268b15..19932ed1 100644
--- a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_IMPORT_NOTIFICATION_MESSAGE_FAILED_IN_PROGRESS.png.sha1
+++ b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_IMPORT_NOTIFICATION_MESSAGE_FAILED_IN_PROGRESS.png.sha1
@@ -1 +1 @@
-3519b1b96658bf54a93cb2df6d8b5d711522c9f7
\ No newline at end of file
+d161e914ad82ea787e184e89ba0e5f3b095ba32c
\ No newline at end of file
diff --git a/chrome/browser/android/shortcut_helper.cc b/chrome/browser/android/shortcut_helper.cc
index 4da3d1e..5b4235c 100644
--- a/chrome/browser/android/shortcut_helper.cc
+++ b/chrome/browser/android/shortcut_helper.cc
@@ -370,6 +370,7 @@
     const JavaParamRef<jlongArray>& jtheme_colors,
     const JavaParamRef<jlongArray>& jbackground_colors,
     const JavaParamRef<jlongArray>& jlast_update_check_times_ms,
+    const JavaParamRef<jlongArray>& jlast_update_completion_times_ms,
     const JavaParamRef<jbooleanArray>& jrelax_updates,
     const JavaParamRef<jobjectArray>& jupdateStatuses) {
   DCHECK(jcallback_pointer);
@@ -410,6 +411,9 @@
   std::vector<int64_t> last_update_check_times_ms;
   base::android::JavaLongArrayToInt64Vector(env, jlast_update_check_times_ms,
                                             &last_update_check_times_ms);
+  std::vector<int64_t> last_update_completion_times_ms;
+  base::android::JavaLongArrayToInt64Vector(
+      env, jlast_update_completion_times_ms, &last_update_completion_times_ms);
   std::vector<bool> relax_updates;
   base::android::JavaBooleanArrayToBoolVector(env, jrelax_updates,
                                               &relax_updates);
@@ -431,6 +435,7 @@
   DCHECK(short_names.size() == theme_colors.size());
   DCHECK(short_names.size() == background_colors.size());
   DCHECK(short_names.size() == last_update_check_times_ms.size());
+  DCHECK(short_names.size() == last_update_completion_times_ms.size());
   DCHECK(short_names.size() == relax_updates.size());
   DCHECK(short_names.size() == update_statuses.size());
 
@@ -447,6 +452,7 @@
         JavaColorToOptionalSkColor(theme_colors[i]),
         JavaColorToOptionalSkColor(background_colors[i]),
         base::Time::FromJavaTime(last_update_check_times_ms[i]),
+        base::Time::FromJavaTime(last_update_completion_times_ms[i]),
         relax_updates[i], std::move(update_statuses[i])));
   }
 
diff --git a/chrome/browser/android/webapk/webapk_info.cc b/chrome/browser/android/webapk/webapk_info.cc
index f2d36b59..2ab569f4 100644
--- a/chrome/browser/android/webapk/webapk_info.cc
+++ b/chrome/browser/android/webapk/webapk_info.cc
@@ -21,6 +21,7 @@
                        base::Optional<SkColor> theme_color,
                        base::Optional<SkColor> background_color,
                        base::Time last_update_check_time,
+                       base::Time last_update_completion_time,
                        bool relax_updates,
                        std::string update_status)
     : name(std::move(name)),
@@ -38,6 +39,7 @@
       theme_color(theme_color),
       background_color(background_color),
       last_update_check_time(last_update_check_time),
+      last_update_completion_time(last_update_completion_time),
       relax_updates(relax_updates),
       update_status(std::move(update_status)) {}
 
diff --git a/chrome/browser/android/webapk/webapk_info.h b/chrome/browser/android/webapk/webapk_info.h
index d035bb3..dc8b7dd 100644
--- a/chrome/browser/android/webapk/webapk_info.h
+++ b/chrome/browser/android/webapk/webapk_info.h
@@ -35,6 +35,7 @@
              base::Optional<SkColor> theme_color,
              base::Optional<SkColor> background_color,
              base::Time last_update_check_time,
+             base::Time last_update_completion_time,
              bool relax_updates,
              std::string update_status);
   ~WebApkInfo();
@@ -69,6 +70,7 @@
   base::Optional<SkColor> theme_color;
   base::Optional<SkColor> background_color;
   base::Time last_update_check_time;
+  base::Time last_update_completion_time;
   bool relax_updates;
 
   // Update Status of the WebAPK.
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 51ff368..ca4cf3d8 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -430,7 +430,7 @@
 
   // Cancel any uploads to release the system url request context references.
   if (webrtc_log_uploader_)
-    webrtc_log_uploader_->StartShutdown();
+    webrtc_log_uploader_->Shutdown();
 
   sessions::SessionIdGenerator::GetInstance()->Shutdown();
 
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index d2efbdc..61489a7 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -1459,14 +1459,9 @@
 #endif
   host->AddFilter(new prerender::PrerenderMessageFilter(id, profile));
   host->AddFilter(new TtsMessageFilter(host->GetBrowserContext()));
-  WebRtcLoggingHandlerHost* webrtc_logging_handler_host =
-      new WebRtcLoggingHandlerHost(id, profile,
-                                   g_browser_process->webrtc_log_uploader());
-  host->AddFilter(webrtc_logging_handler_host);
-  host->SetUserData(
-      WebRtcLoggingHandlerHost::kWebRtcLoggingHandlerHostKey,
-      std::make_unique<base::UserDataAdapter<WebRtcLoggingHandlerHost>>(
-          webrtc_logging_handler_host));
+
+  WebRtcLoggingHandlerHost::AttachToRenderProcessHost(
+      host, g_browser_process->webrtc_log_uploader());
 
   // The audio manager outlives the host, so it's safe to hand a raw pointer to
   // it to the AudioDebugRecordingsHandler, which is owned by the host.
@@ -2486,9 +2481,10 @@
   return allow;
 }
 
-bool ChromeContentBrowserClient::AllowSignedExchange(
+bool ChromeContentBrowserClient::AllowSignedExchangeOnIO(
     content::ResourceContext* resource_context) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK(!base::FeatureList::IsEnabled(features::kNavigationLoaderOnUI));
   // Null-check safe_browsing_service_ as in unit tests |resource_context| is a
   // MockResourceContext and the cast doesn't work.
   if (!safe_browsing_service_)
@@ -2497,6 +2493,13 @@
   return io_data->signed_exchange_enabled()->GetValue();
 }
 
+bool ChromeContentBrowserClient::AllowSignedExchange(
+    content::BrowserContext* browser_context) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  Profile* profile = Profile::FromBrowserContext(browser_context);
+  return profile->GetPrefs()->GetBoolean(prefs::kSignedHTTPExchangeEnabled);
+}
+
 bool ChromeContentBrowserClient::AllowGetCookie(
     const GURL& url,
     const GURL& first_party,
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index d0e2ef2..1d3dc5ff 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -235,7 +235,9 @@
                          content::BrowserContext* context,
                          int render_process_id,
                          int render_frame_id) override;
-  bool AllowSignedExchange(content::ResourceContext* resource_context) override;
+  bool AllowSignedExchangeOnIO(
+      content::ResourceContext* resource_context) override;
+  bool AllowSignedExchange(content::BrowserContext* browser_context) override;
   bool AllowGetCookie(const GURL& url,
                       const GURL& first_party,
                       const net::CookieList& cookie_list,
diff --git a/chrome/browser/chromeos/crostini/crostini_export_import.cc b/chrome/browser/chromeos/crostini/crostini_export_import.cc
index 9c75a38..b901db0 100644
--- a/chrome/browser/chromeos/crostini/crostini_export_import.cc
+++ b/chrome/browser/chromeos/crostini/crostini_export_import.cc
@@ -9,7 +9,6 @@
 #include "base/bind.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "chrome/browser/chromeos/crostini/crostini_manager_factory.h"
 #include "chrome/browser/chromeos/crostini/crostini_util.h"
@@ -24,7 +23,6 @@
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/text/bytes_formatting.h"
 
 namespace crostini {
 
@@ -159,27 +157,37 @@
 
 void CrostiniExportImport::Start(
     ExportImportType type,
-    const ContainerId& container_id,
+    ContainerId container_id,
     base::FilePath path,
     CrostiniManager::CrostiniResultCallback callback) {
-  notifications_[container_id] =
-      std::make_unique<CrostiniExportImportNotification>(
-          profile_, this, type, GetUniqueNotificationId(), path);
+  auto* notification = CrostiniExportImportNotification::Create(
+      profile_, type, GetUniqueNotificationId(), path);
+
+  auto it = notifications_.find(container_id);
+  if (it != notifications_.end()) {
+    // An operation is in progress for this container, display an error to
+    // the user and exit.
+    notification->SetStatusFailedConcurrentOperation(it->second->type());
+    return;
+  } else {
+    notifications_.emplace_hint(it, container_id, notification);
+  }
 
   switch (type) {
     case ExportImportType::EXPORT:
       guest_os::GuestOsSharePath::GetForProfile(profile_)->SharePath(
           kCrostiniDefaultVmName, path.DirName(), false,
           base::BindOnce(&CrostiniExportImport::ExportAfterSharing,
-                         weak_ptr_factory_.GetWeakPtr(), container_id,
-                         path.BaseName(), std::move(callback)));
+                         weak_ptr_factory_.GetWeakPtr(),
+                         std::move(container_id), path.BaseName(),
+                         std::move(callback)));
       break;
     case ExportImportType::IMPORT:
       guest_os::GuestOsSharePath::GetForProfile(profile_)->SharePath(
           kCrostiniDefaultVmName, path, false,
           base::BindOnce(&CrostiniExportImport::ImportAfterSharing,
-                         weak_ptr_factory_.GetWeakPtr(), container_id,
-                         std::move(callback)));
+                         weak_ptr_factory_.GetWeakPtr(),
+                         std::move(container_id), std::move(callback)));
       break;
   }
 }
@@ -197,8 +205,7 @@
     auto it = notifications_.find(container_id);
     DCHECK(it != notifications_.end()) << ContainerIdToString(container_id)
                                        << " has no notification to update";
-    it->second->UpdateStatus(CrostiniExportImportNotification::Status::FAILED,
-                             0);
+    RemoveNotification(it).SetStatusFailed();
     return;
   }
   CrostiniManager::GetForProfile(profile_)->ExportLxdContainer(
@@ -218,29 +225,36 @@
   DCHECK(it != notifications_.end())
       << ContainerIdToString(container_id) << " has no notification to update";
 
-  CrostiniExportImportNotification::Status status =
-      CrostiniExportImportNotification::Status::DONE;
   ExportContainerResult enum_hist_result = ExportContainerResult::kSuccess;
-  if (result == crostini::CrostiniResult::SUCCESS) {
-    UMA_HISTOGRAM_LONG_TIMES("Crostini.BackupTimeSuccess",
-                             base::Time::Now() - start);
+  if (result == CrostiniResult::SUCCESS) {
+    switch (it->second->status()) {
+      case CrostiniExportImportNotification::Status::RUNNING:
+        UMA_HISTOGRAM_LONG_TIMES("Crostini.BackupTimeSuccess",
+                                 base::Time::Now() - start);
+        RemoveNotification(it).SetStatusDone();
+        break;
+      default:
+        NOTREACHED();
+    }
   } else {
     LOG(ERROR) << "Error exporting " << int(result);
-    status = CrostiniExportImportNotification::Status::FAILED;
     switch (result) {
-      case crostini::CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_VM_STOPPED:
+      case CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_VM_STOPPED:
         enum_hist_result = ExportContainerResult::kFailedVmStopped;
         break;
-      case crostini::CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_VM_STARTED:
+      case CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_VM_STARTED:
         enum_hist_result = ExportContainerResult::kFailedVmStarted;
         break;
       default:
+        DCHECK(result == CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED);
         enum_hist_result = ExportContainerResult::kFailed;
     }
     UMA_HISTOGRAM_LONG_TIMES("Crostini.BackupTimeFailed",
                              base::Time::Now() - start);
+    DCHECK(it->second->status() ==
+           CrostiniExportImportNotification::Status::RUNNING);
+    RemoveNotification(it).SetStatusFailed();
   }
-  it->second->UpdateStatus(status, 0);
   UMA_HISTOGRAM_ENUMERATION("Crostini.Backup", enum_hist_result);
   std::move(callback).Run(result);
 }
@@ -259,15 +273,11 @@
   switch (status) {
     // Rescale PACK:1-100 => 0-50.
     case ExportContainerProgressStatus::PACK:
-      it->second->UpdateStatus(
-          CrostiniExportImportNotification::Status::RUNNING,
-          progress_percent / 2);
+      it->second->SetStatusRunning(progress_percent / 2);
       break;
     // Rescale DOWNLOAD:1-100 => 50-100.
     case ExportContainerProgressStatus::DOWNLOAD:
-      it->second->UpdateStatus(
-          CrostiniExportImportNotification::Status::RUNNING,
-          50 + progress_percent / 2);
+      it->second->SetStatusRunning(50 + progress_percent / 2);
       break;
     default:
       LOG(WARNING) << "Unknown Export progress status " << int(status);
@@ -290,8 +300,7 @@
   // TODO(juwa): investigate more accurate approximations of percent.
   const auto percent = (files_percent + bytes_percent) / 2.0;
 
-  it->second->UpdateStatus(CrostiniExportImportNotification::Status::RUNNING,
-                           static_cast<int>(percent));
+  it->second->SetStatusRunning(static_cast<int>(percent));
 }
 
 void CrostiniExportImport::ImportAfterSharing(
@@ -306,8 +315,7 @@
     auto it = notifications_.find(container_id);
     DCHECK(it != notifications_.end()) << ContainerIdToString(container_id)
                                        << " has no notification to update";
-    it->second->UpdateStatus(CrostiniExportImportNotification::Status::FAILED,
-                             0);
+    RemoveNotification(it).SetStatusFailed();
     return;
   }
   CrostiniManager::GetForProfile(profile_)->ImportLxdContainer(
@@ -323,38 +331,57 @@
     CrostiniManager::CrostiniResultCallback callback,
     CrostiniResult result) {
   auto it = notifications_.find(container_id);
-  DCHECK(it != notifications_.end())
-      << ContainerIdToString(container_id) << " has no notification to update";
-  CrostiniExportImportNotification::Status status =
-      CrostiniExportImportNotification::Status::DONE;
+
   ImportContainerResult enum_hist_result = ImportContainerResult::kSuccess;
-  if (result == crostini::CrostiniResult::SUCCESS) {
+  if (result == CrostiniResult::SUCCESS) {
     UMA_HISTOGRAM_LONG_TIMES("Crostini.RestoreTimeSuccess",
                              base::Time::Now() - start);
+    DCHECK(it != notifications_.end()) << ContainerIdToString(container_id)
+                                       << " has no notification to update";
+    switch (it->second->status()) {
+      case CrostiniExportImportNotification::Status::RUNNING:
+        RemoveNotification(it).SetStatusDone();
+        break;
+      default:
+        NOTREACHED();
+    }
   } else {
     LOG(ERROR) << "Error importing " << int(result);
-    status = CrostiniExportImportNotification::Status::FAILED;
     switch (result) {
-      case crostini::CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_VM_STOPPED:
+      case CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_VM_STOPPED:
         enum_hist_result = ImportContainerResult::kFailedVmStopped;
         break;
-      case crostini::CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_VM_STARTED:
+      case CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_VM_STARTED:
         enum_hist_result = ImportContainerResult::kFailedVmStarted;
         break;
-      case crostini::CrostiniResult::
-          CONTAINER_EXPORT_IMPORT_FAILED_ARCHITECTURE:
+      case CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_ARCHITECTURE:
         enum_hist_result = ImportContainerResult::kFailedArchitecture;
         break;
-      case crostini::CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_SPACE:
+      case CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_SPACE:
         enum_hist_result = ImportContainerResult::kFailedSpace;
         break;
       default:
+        DCHECK(result == CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED);
         enum_hist_result = ImportContainerResult::kFailed;
     }
+    // If the operation didn't start successfully or the vm stops during the
+    // import, then the notification status will not have been set in
+    // OnImportContainerProgress, so it needs to be updated.
+    if (result == CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED ||
+        result == CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_VM_STOPPED ||
+        result == CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_VM_STARTED) {
+      DCHECK(it != notifications_.end()) << ContainerIdToString(container_id)
+                                         << " has no notification to update";
+      DCHECK(it->second->status() ==
+             CrostiniExportImportNotification::Status::RUNNING);
+      RemoveNotification(it).SetStatusFailed();
+    } else {
+      DCHECK(it == notifications_.end()) << ContainerIdToString(container_id)
+                                         << " has unexpected notification";
+    }
     UMA_HISTOGRAM_LONG_TIMES("Crostini.RestoreTimeFailed",
                              base::Time::Now() - start);
   }
-  it->second->UpdateStatus(status, 0);
   UMA_HISTOGRAM_ENUMERATION("Crostini.Restore", enum_hist_result);
 
   // Restart from CrostiniManager.
@@ -380,28 +407,21 @@
   switch (status) {
     // Rescale UPLOAD:1-100 => 0-50.
     case ImportContainerProgressStatus::UPLOAD:
-      it->second->UpdateStatus(
-          CrostiniExportImportNotification::Status::RUNNING,
-          progress_percent / 2);
+      it->second->SetStatusRunning(progress_percent / 2);
       break;
     // Rescale UNPACK:1-100 => 50-100.
     case ImportContainerProgressStatus::UNPACK:
-      it->second->UpdateStatus(
-          CrostiniExportImportNotification::Status::RUNNING,
-          50 + progress_percent / 2);
+      it->second->SetStatusRunning(50 + progress_percent / 2);
       break;
     // Failure, set error message.
     case ImportContainerProgressStatus::FAILURE_ARCHITECTURE:
-      it->second->set_message_failed(l10n_util::GetStringFUTF16(
-          IDS_CROSTINI_IMPORT_NOTIFICATION_MESSAGE_FAILED_ARCHITECTURE,
-          base::ASCIIToUTF16(architecture_container),
-          base::ASCIIToUTF16(architecture_device)));
+      RemoveNotification(it).SetStatusFailedArchitectureMismatch(
+          architecture_container, architecture_device);
       break;
     case ImportContainerProgressStatus::FAILURE_SPACE:
       DCHECK_GE(minimum_required_space, available_space);
-      it->second->set_message_failed(l10n_util::GetStringFUTF16(
-          IDS_CROSTINI_IMPORT_NOTIFICATION_MESSAGE_FAILED_SPACE,
-          ui::FormatBytes(minimum_required_space - available_space)));
+      RemoveNotification(it).SetStatusFailedInsufficientSpace(
+          minimum_required_space - available_space);
       break;
     default:
       LOG(WARNING) << "Unknown Export progress status " << int(status);
@@ -413,22 +433,18 @@
                             next_notification_id_++);
 }
 
-void CrostiniExportImport::NotificationCompleted(
-    CrostiniExportImportNotification* notification) {
-  for (auto it = notifications_.begin(); it != notifications_.end(); ++it) {
-    if (it->second.get() == notification) {
-      notifications_.erase(it);
-      return;
-    }
-  }
-  // Notification should always exist when this is called.
-  NOTREACHED();
+CrostiniExportImportNotification& CrostiniExportImport::RemoveNotification(
+    std::map<ContainerId, CrostiniExportImportNotification*>::iterator it) {
+  DCHECK(it != notifications_.end());
+  auto& notification = *it->second;
+  notifications_.erase(it);
+  return notification;
 }
 
 CrostiniExportImportNotification*
 CrostiniExportImport::GetNotificationForTesting(ContainerId container_id) {
   auto it = notifications_.find(container_id);
-  return it != notifications_.end() ? it->second.get() : nullptr;
+  return it != notifications_.end() ? it->second : nullptr;
 }
 
 }  // namespace crostini
diff --git a/chrome/browser/chromeos/crostini/crostini_export_import.h b/chrome/browser/chromeos/crostini/crostini_export_import.h
index 2c1a04a..64a92b2 100644
--- a/chrome/browser/chromeos/crostini/crostini_export_import.h
+++ b/chrome/browser/chromeos/crostini/crostini_export_import.h
@@ -82,9 +82,6 @@
                        base::FilePath path,
                        CrostiniManager::CrostiniResultCallback callback);
 
-  // Called by the notification when it is closed so it can be destroyed.
-  void NotificationCompleted(CrostiniExportImportNotification* notification);
-
   CrostiniExportImportNotification* GetNotificationForTesting(
       ContainerId container_id);
 
@@ -105,7 +102,7 @@
                     void* params) override;
 
   void Start(ExportImportType type,
-             const ContainerId& container_id,
+             ContainerId container_id,
              base::FilePath path,
              CrostiniManager::CrostiniResultCallback callback);
 
@@ -159,10 +156,12 @@
 
   std::string GetUniqueNotificationId();
 
+  CrostiniExportImportNotification& RemoveNotification(
+      std::map<ContainerId, CrostiniExportImportNotification*>::iterator it);
+
   Profile* profile_;
   scoped_refptr<ui::SelectFileDialog> select_folder_dialog_;
-  std::map<ContainerId, std::unique_ptr<CrostiniExportImportNotification>>
-      notifications_;
+  std::map<ContainerId, CrostiniExportImportNotification*> notifications_;
   // Notifications must have unique-per-profile identifiers.
   // A non-static member on a profile-keyed-service will suffice.
   int next_notification_id_;
diff --git a/chrome/browser/chromeos/crostini/crostini_export_import_notification.cc b/chrome/browser/chromeos/crostini/crostini_export_import_notification.cc
index cc7afb6d..52eb82f 100644
--- a/chrome/browser/chromeos/crostini/crostini_export_import_notification.cc
+++ b/chrome/browser/chromeos/crostini/crostini_export_import_notification.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/text/bytes_formatting.h"
 #include "ui/message_center/public/cpp/message_center_constants.h"
 #include "ui/message_center/public/cpp/notification.h"
 #include "ui/message_center/public/cpp/notification_delegate.h"
@@ -28,44 +29,14 @@
 
 CrostiniExportImportNotification::CrostiniExportImportNotification(
     Profile* profile,
-    CrostiniExportImport* service,
     ExportImportType type,
     const std::string& notification_id,
     const base::FilePath& path)
     : profile_(profile),
-      service_(service),
       type_(type),
       path_(path),
       weak_ptr_factory_(this) {
-  // Messages.
-  switch (type) {
-    case ExportImportType::EXPORT:
-      title_running_ = l10n_util::GetStringUTF16(
-          IDS_CROSTINI_EXPORT_NOTIFICATION_TITLE_RUNNING);
-      title_done_ = l10n_util::GetStringUTF16(
-          IDS_CROSTINI_EXPORT_NOTIFICATION_TITLE_DONE);
-      message_done_ = l10n_util::GetStringUTF16(
-          IDS_CROSTINI_EXPORT_NOTIFICATION_MESSAGE_DONE);
-      title_failed_ = l10n_util::GetStringUTF16(
-          IDS_CROSTINI_EXPORT_NOTIFICATION_TITLE_FAILED);
-      message_failed_ = l10n_util::GetStringUTF16(
-          IDS_CROSTINI_EXPORT_NOTIFICATION_MESSAGE_FAILED);
-      break;
-    case ExportImportType::IMPORT:
-      title_running_ = l10n_util::GetStringUTF16(
-          IDS_CROSTINI_IMPORT_NOTIFICATION_TITLE_RUNNING);
-      title_done_ = l10n_util::GetStringUTF16(
-          IDS_CROSTINI_IMPORT_NOTIFICATION_TITLE_DONE);
-      message_done_ = l10n_util::GetStringUTF16(
-          IDS_CROSTINI_IMPORT_NOTIFICATION_MESSAGE_DONE);
-      title_failed_ = l10n_util::GetStringUTF16(
-          IDS_CROSTINI_IMPORT_NOTIFICATION_TITLE_FAILED);
-      message_failed_ = l10n_util::GetStringUTF16(
-          IDS_CROSTINI_IMPORT_NOTIFICATION_MESSAGE_FAILED);
-      break;
-    default:
-      NOTREACHED();
-  }
+  DCHECK(type == ExportImportType::EXPORT || type == ExportImportType::IMPORT);
 
   message_center::RichNotificationData rich_notification_data;
   rich_notification_data.vector_small_image = &kNotificationLinuxIcon;
@@ -84,47 +55,107 @@
       base::MakeRefCounted<message_center::ThunkNotificationDelegate>(
           weak_ptr_factory_.GetWeakPtr()));
 
-  UpdateStatus(Status::RUNNING, 0);
+  SetStatusRunning(0);
 }
 
 CrostiniExportImportNotification::~CrostiniExportImportNotification() = default;
 
-void CrostiniExportImportNotification::UpdateStatus(Status status,
-                                                    int progress_percent) {
-  status_ = status;
-  switch (status) {
-    case Status::RUNNING:
-      if (closed_) {
-        return;
-      }
-      notification_->set_type(message_center::NOTIFICATION_TYPE_PROGRESS);
-      notification_->set_progress(progress_percent);
-      notification_->set_title(title_running_);
-      notification_->set_message(
-          GetTimeRemainingMessage(started_, progress_percent));
-      notification_->set_never_timeout(true);
-      break;
-    case Status::DONE:
-      notification_->set_type(message_center::NOTIFICATION_TYPE_SIMPLE);
-      if (type_ == ExportImportType::EXPORT) {
-        notification_->set_buttons({message_center::ButtonInfo(
-            l10n_util::GetStringUTF16(IDS_DOWNLOAD_LINK_SHOW))});
-      }
-      notification_->set_title(title_done_);
-      notification_->set_message(message_done_);
-      notification_->set_never_timeout(false);
-      break;
-    case Status::FAILED:
-      notification_->set_type(message_center::NOTIFICATION_TYPE_SIMPLE);
-      notification_->set_accent_color(
-          ash::kSystemNotificationColorCriticalWarning);
-      notification_->set_title(title_failed_);
-      notification_->set_message(message_failed_);
-      notification_->set_never_timeout(false);
-      break;
-    default:
-      NOTREACHED();
+void CrostiniExportImportNotification::SetStatusRunning(int progress_percent) {
+  status_ = Status::RUNNING;
+
+  if (closed_) {
+    return;
   }
+
+  notification_->set_type(message_center::NOTIFICATION_TYPE_PROGRESS);
+  notification_->set_accent_color(ash::kSystemNotificationColorNormal);
+  notification_->set_title(l10n_util::GetStringUTF16(
+      type_ == ExportImportType::EXPORT
+          ? IDS_CROSTINI_EXPORT_NOTIFICATION_TITLE_RUNNING
+          : IDS_CROSTINI_IMPORT_NOTIFICATION_TITLE_RUNNING));
+  notification_->set_message(
+      GetTimeRemainingMessage(started_, progress_percent));
+  notification_->set_buttons({});
+  notification_->set_never_timeout(true);
+  notification_->set_progress(progress_percent);
+
+  NotificationDisplayService::GetForProfile(profile_)->Display(
+      NotificationHandler::Type::TRANSIENT, *notification_,
+      /*metadata=*/nullptr);
+}
+
+void CrostiniExportImportNotification::SetStatusDone() {
+  status_ = Status::DONE;
+
+  notification_->set_type(message_center::NOTIFICATION_TYPE_SIMPLE);
+  notification_->set_accent_color(ash::kSystemNotificationColorNormal);
+  notification_->set_title(l10n_util::GetStringUTF16(
+      type_ == ExportImportType::EXPORT
+          ? IDS_CROSTINI_EXPORT_NOTIFICATION_TITLE_DONE
+          : IDS_CROSTINI_IMPORT_NOTIFICATION_TITLE_DONE));
+  notification_->set_message(l10n_util::GetStringUTF16(
+      type_ == ExportImportType::EXPORT
+          ? IDS_CROSTINI_EXPORT_NOTIFICATION_MESSAGE_DONE
+          : IDS_CROSTINI_IMPORT_NOTIFICATION_MESSAGE_DONE));
+  notification_->set_buttons(
+      type_ == ExportImportType::EXPORT
+          ? std::vector<message_center::ButtonInfo>{message_center::ButtonInfo(
+                l10n_util::GetStringUTF16(IDS_DOWNLOAD_LINK_SHOW))}
+          : std::vector<message_center::ButtonInfo>{});
+  notification_->set_never_timeout(false);
+
+  NotificationDisplayService::GetForProfile(profile_)->Display(
+      NotificationHandler::Type::TRANSIENT, *notification_,
+      /*metadata=*/nullptr);
+}
+
+void CrostiniExportImportNotification::SetStatusFailed() {
+  SetStatusFailed(l10n_util::GetStringUTF16(
+      type_ == ExportImportType::EXPORT
+          ? IDS_CROSTINI_EXPORT_NOTIFICATION_MESSAGE_FAILED
+          : IDS_CROSTINI_IMPORT_NOTIFICATION_MESSAGE_FAILED));
+}
+
+void CrostiniExportImportNotification::SetStatusFailedArchitectureMismatch(
+    const std::string& architecture_container,
+    const std::string& architecture_device) {
+  DCHECK(type_ == ExportImportType::IMPORT);
+  SetStatusFailed(l10n_util::GetStringFUTF16(
+      IDS_CROSTINI_IMPORT_NOTIFICATION_MESSAGE_FAILED_ARCHITECTURE,
+      base::ASCIIToUTF16(architecture_container),
+      base::ASCIIToUTF16(architecture_device)));
+}
+
+void CrostiniExportImportNotification::SetStatusFailedInsufficientSpace(
+    uint64_t additional_required_space) {
+  DCHECK(type_ == ExportImportType::IMPORT);
+  SetStatusFailed(l10n_util::GetStringFUTF16(
+      IDS_CROSTINI_IMPORT_NOTIFICATION_MESSAGE_FAILED_SPACE,
+      ui::FormatBytes(additional_required_space)));
+}
+
+void CrostiniExportImportNotification::SetStatusFailedConcurrentOperation(
+    ExportImportType in_progress_operation_type) {
+  SetStatusFailed(l10n_util::GetStringUTF16(
+      in_progress_operation_type == ExportImportType::EXPORT
+          ? IDS_CROSTINI_EXPORT_NOTIFICATION_MESSAGE_FAILED_IN_PROGRESS
+          : IDS_CROSTINI_IMPORT_NOTIFICATION_MESSAGE_FAILED_IN_PROGRESS));
+}
+
+void CrostiniExportImportNotification::SetStatusFailed(
+    const base::string16& message) {
+  status_ = Status::FAILED;
+
+  notification_->set_type(message_center::NOTIFICATION_TYPE_SIMPLE);
+  notification_->set_accent_color(ash::kSystemNotificationColorCriticalWarning);
+  notification_->set_title(l10n_util::GetStringUTF16(
+      type_ == ExportImportType::EXPORT
+          ? IDS_CROSTINI_EXPORT_NOTIFICATION_TITLE_FAILED
+          : IDS_CROSTINI_IMPORT_NOTIFICATION_TITLE_FAILED));
+  notification_->set_message(message);
+  notification_->set_buttons({});
+  notification_->set_never_timeout(false);
+
   NotificationDisplayService::GetForProfile(profile_)->Display(
       NotificationHandler::Type::TRANSIENT, *notification_,
       /*metadata=*/nullptr);
@@ -133,7 +164,7 @@
 void CrostiniExportImportNotification::Close(bool by_user) {
   closed_ = true;
   if (status_ != Status::RUNNING) {
-    service_->NotificationCompleted(this);
+    delete this;
   }
 }
 
diff --git a/chrome/browser/chromeos/crostini/crostini_export_import_notification.h b/chrome/browser/chromeos/crostini/crostini_export_import_notification.h
index 436ccf3..b8a2fca 100644
--- a/chrome/browser/chromeos/crostini/crostini_export_import_notification.h
+++ b/chrome/browser/chromeos/crostini/crostini_export_import_notification.h
@@ -11,6 +11,7 @@
 #include "base/files/file_path.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
+#include "chrome/browser/chromeos/crostini/crostini_util.h"
 #include "ui/message_center/public/cpp/notification_delegate.h"
 
 class Profile;
@@ -21,8 +22,6 @@
 
 namespace crostini {
 
-class CrostiniExportImport;
-
 enum class ExportImportType;
 
 // Notification for Crostini export and import.
@@ -31,20 +30,32 @@
  public:
   enum class Status { RUNNING, DONE, FAILED };
 
-  CrostiniExportImportNotification(Profile* profile,
-                                   CrostiniExportImport* service,
-                                   ExportImportType type,
-                                   const std::string& notification_id,
-                                   const base::FilePath& path);
-  virtual ~CrostiniExportImportNotification();
-
-  void UpdateStatus(Status status, int progress_percent);
-  void set_message_failed(const base::string16& message) {
-    message_failed_ = message;
+  // Used to construct CrostiniExportImportNotification to ensure it controls
+  // its lifetime.
+  static CrostiniExportImportNotification* Create(
+      Profile* profile,
+      ExportImportType type,
+      const std::string& notification_id,
+      const base::FilePath& path) {
+    return new CrostiniExportImportNotification(profile, type, notification_id,
+                                                path);
   }
 
+  virtual ~CrostiniExportImportNotification();
+
+  void SetStatusRunning(int progress_percent);
+  void SetStatusDone();
+  void SetStatusFailed();
+  void SetStatusFailedArchitectureMismatch(
+      const std::string& architecture_container,
+      const std::string& architecture_device);
+  void SetStatusFailedInsufficientSpace(uint64_t additional_required_space);
+  void SetStatusFailedConcurrentOperation(
+      ExportImportType in_progress_operation_type);
+
+  Status status() const { return status_; }
+  ExportImportType type() const { return type_; }
   // Getters for testing.
-  Status get_status() { return status_; }
   message_center::Notification* get_notification() {
     return notification_.get();
   }
@@ -55,19 +66,19 @@
              const base::Optional<base::string16>& reply) override;
 
  private:
+  CrostiniExportImportNotification(Profile* profile,
+                                   ExportImportType type,
+                                   const std::string& notification_id,
+                                   const base::FilePath& path);
+
+  void SetStatusFailed(const base::string16& message);
+
   Profile* profile_;
-  // These notifications are owned by the export service.
-  CrostiniExportImport* service_;
   ExportImportType type_;
   base::FilePath path_;
   Status status_ = Status::RUNNING;
   // Time when the operation started.  Used for estimating time remaining.
   base::TimeTicks started_ = base::TimeTicks::Now();
-  base::string16 title_running_;
-  base::string16 title_done_;
-  base::string16 message_done_;
-  base::string16 title_failed_;
-  base::string16 message_failed_;
   std::unique_ptr<message_center::Notification> notification_;
   bool closed_ = false;
   base::WeakPtrFactory<CrostiniExportImportNotification> weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/crostini/crostini_export_import_unittest.cc b/chrome/browser/chromeos/crostini/crostini_export_import_unittest.cc
index 69917a1..c1db7e93 100644
--- a/chrome/browser/chromeos/crostini/crostini_export_import_unittest.cc
+++ b/chrome/browser/chromeos/crostini/crostini_export_import_unittest.cc
@@ -138,7 +138,7 @@
   CrostiniExportImportNotification* notification =
       crostini_export_import()->GetNotificationForTesting(container_id_);
   ASSERT_NE(notification, nullptr);
-  EXPECT_EQ(notification->get_status(),
+  EXPECT_EQ(notification->status(),
             CrostiniExportImportNotification::Status::RUNNING);
   EXPECT_EQ(notification->get_notification()->progress(), 0);
 
@@ -146,7 +146,7 @@
   SendExportProgress(vm_tools::cicerone::
                          ExportLxdContainerProgressSignal_Status_EXPORTING_PACK,
                      {.progress_percent = 20});
-  EXPECT_EQ(notification->get_status(),
+  EXPECT_EQ(notification->status(),
             CrostiniExportImportNotification::Status::RUNNING);
   EXPECT_EQ(notification->get_notification()->progress(), 10);
 
@@ -155,7 +155,7 @@
       vm_tools::cicerone::
           ExportLxdContainerProgressSignal_Status_EXPORTING_DOWNLOAD,
       {.progress_percent = 20});
-  EXPECT_EQ(notification->get_status(),
+  EXPECT_EQ(notification->status(),
             CrostiniExportImportNotification::Status::RUNNING);
   EXPECT_EQ(notification->get_notification()->progress(), 60);
 
@@ -165,14 +165,14 @@
       vm_tools::cicerone::
           ExportLxdContainerProgressSignal_Status_EXPORTING_DOWNLOAD,
       {.progress_percent = 40});
-  EXPECT_EQ(notification->get_status(),
+  EXPECT_EQ(notification->status(),
             CrostiniExportImportNotification::Status::RUNNING);
   EXPECT_EQ(notification->get_notification()->progress(), 60);
 
   // Done.
   SendExportProgress(
       vm_tools::cicerone::ExportLxdContainerProgressSignal_Status_DONE);
-  EXPECT_EQ(notification->get_status(),
+  EXPECT_EQ(notification->status(),
             CrostiniExportImportNotification::Status::DONE);
 }
 
@@ -183,7 +183,7 @@
   CrostiniExportImportNotification* notification =
       crostini_export_import()->GetNotificationForTesting(container_id_);
   ASSERT_NE(notification, nullptr);
-  EXPECT_EQ(notification->get_status(),
+  EXPECT_EQ(notification->status(),
             CrostiniExportImportNotification::Status::RUNNING);
   EXPECT_EQ(notification->get_notification()->progress(), 0);
 
@@ -195,7 +195,7 @@
        .total_bytes = 100,
        .files_streamed = 30,
        .bytes_streamed = 10});
-  EXPECT_EQ(notification->get_status(),
+  EXPECT_EQ(notification->status(),
             CrostiniExportImportNotification::Status::RUNNING);
   EXPECT_EQ(notification->get_notification()->progress(), 20);
 
@@ -207,7 +207,7 @@
        .total_bytes = 100,
        .files_streamed = 55,
        .bytes_streamed = 66});
-  EXPECT_EQ(notification->get_status(),
+  EXPECT_EQ(notification->status(),
             CrostiniExportImportNotification::Status::RUNNING);
   EXPECT_EQ(notification->get_notification()->progress(), 60);
 
@@ -220,14 +220,14 @@
        .total_bytes = 100,
        .files_streamed = 90,
        .bytes_streamed = 85});
-  EXPECT_EQ(notification->get_status(),
+  EXPECT_EQ(notification->status(),
             CrostiniExportImportNotification::Status::RUNNING);
   EXPECT_EQ(notification->get_notification()->progress(), 60);
 
   // Done.
   SendExportProgress(
       vm_tools::cicerone::ExportLxdContainerProgressSignal_Status_DONE);
-  EXPECT_EQ(notification->get_status(),
+  EXPECT_EQ(notification->status(),
             CrostiniExportImportNotification::Status::DONE);
 }
 
@@ -241,7 +241,7 @@
   // Failed.
   SendExportProgress(
       vm_tools::cicerone::ExportLxdContainerProgressSignal_Status_FAILED);
-  EXPECT_EQ(notification->get_status(),
+  EXPECT_EQ(notification->status(),
             CrostiniExportImportNotification::Status::FAILED);
 }
 
@@ -252,7 +252,7 @@
   CrostiniExportImportNotification* notification =
       crostini_export_import()->GetNotificationForTesting(container_id_);
   ASSERT_NE(notification, nullptr);
-  EXPECT_EQ(notification->get_status(),
+  EXPECT_EQ(notification->status(),
             CrostiniExportImportNotification::Status::RUNNING);
   EXPECT_EQ(notification->get_notification()->progress(), 0);
 
@@ -261,7 +261,7 @@
       vm_tools::cicerone::
           ImportLxdContainerProgressSignal_Status_IMPORTING_UPLOAD,
       {.progress_percent = 20});
-  EXPECT_EQ(notification->get_status(),
+  EXPECT_EQ(notification->status(),
             CrostiniExportImportNotification::Status::RUNNING);
   EXPECT_EQ(notification->get_notification()->progress(), 10);
 
@@ -270,7 +270,7 @@
       vm_tools::cicerone::
           ImportLxdContainerProgressSignal_Status_IMPORTING_UNPACK,
       {.progress_percent = 20});
-  EXPECT_EQ(notification->get_status(),
+  EXPECT_EQ(notification->status(),
             CrostiniExportImportNotification::Status::RUNNING);
   EXPECT_EQ(notification->get_notification()->progress(), 60);
 
@@ -280,14 +280,14 @@
       vm_tools::cicerone::
           ImportLxdContainerProgressSignal_Status_IMPORTING_UNPACK,
       {.progress_percent = 40});
-  EXPECT_EQ(notification->get_status(),
+  EXPECT_EQ(notification->status(),
             CrostiniExportImportNotification::Status::RUNNING);
   EXPECT_EQ(notification->get_notification()->progress(), 60);
 
   // Done.
   SendImportProgress(
       vm_tools::cicerone::ImportLxdContainerProgressSignal_Status_DONE);
-  EXPECT_EQ(notification->get_status(),
+  EXPECT_EQ(notification->status(),
             CrostiniExportImportNotification::Status::DONE);
 }
 
@@ -301,7 +301,7 @@
   // Failed.
   SendImportProgress(
       vm_tools::cicerone::ImportLxdContainerProgressSignal_Status_FAILED);
-  EXPECT_EQ(notification->get_status(),
+  EXPECT_EQ(notification->status(),
             CrostiniExportImportNotification::Status::FAILED);
   std::string msg("Restoring couldn't be completed due to an error");
   EXPECT_EQ(notification->get_notification()->message(),
@@ -319,7 +319,7 @@
   SendImportProgress(
       vm_tools::cicerone::
           ImportLxdContainerProgressSignal_Status_FAILED_ARCHITECTURE);
-  EXPECT_EQ(notification->get_status(),
+  EXPECT_EQ(notification->status(),
             CrostiniExportImportNotification::Status::FAILED);
   std::string msg(
       "Cannot import container architecture type arch_con with this device "
@@ -344,7 +344,7 @@
           .available_space = 20ul * 1'024 * 1'024 * 1'024,    // 20Gb
           .min_required_space = 35ul * 1'024 * 1'024 * 1'024  // 35Gb
       });
-  EXPECT_EQ(notification->get_status(),
+  EXPECT_EQ(notification->status(),
             CrostiniExportImportNotification::Status::FAILED);
   std::string msg =
       "Cannot restore due to lack of storage space. Free up 15.0 GB from the "
diff --git a/chrome/browser/chromeos/login/demo_mode/demo_session.cc b/chrome/browser/chromeos/login/demo_mode/demo_session.cc
index 30586fb..5cc475ca 100644
--- a/chrome/browser/chromeos/login/demo_mode/demo_session.cc
+++ b/chrome/browser/chromeos/login/demo_mode/demo_session.cc
@@ -171,7 +171,8 @@
 // Returns the list of locales (and related info) supported by demo mode.
 std::vector<ash::LocaleInfo> GetSupportedLocales() {
   const base::flat_set<std::string> kSupportedLocales(
-      {"da", "en-GB", "en-US", "fi", "fr", "fr-CA", "nb", "nl", "sv"});
+      {"da", "de", "en-GB", "en-US", "fi", "fr", "fr-CA", "ja", "nb", "nl",
+       "sv"});
 
   const std::vector<std::string>& available_locales =
       l10n_util::GetAvailableLocales();
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index e02896ff..baecbf5 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -761,6 +761,7 @@
   # browser, then we can clean up these dependencies.
   public_deps = [
     "//chrome/browser/extensions/api:api_registration",
+    "//chrome/common",
     "//chrome/common/extensions/api",
     "//components/safe_browsing:csd_proto",
     "//components/safe_browsing/db:util",
@@ -785,7 +786,6 @@
     "//chrome/browser/safe_browsing",
     "//chrome/browser/web_applications/components",
     "//chrome/browser/web_applications/extensions",
-    "//chrome/common",
     "//chrome/common/extensions/api:extensions_features",
     "//chrome/common/safe_browsing:proto",
     "//chrome/services/removable_storage_writer/public/mojom",
diff --git a/chrome/browser/extensions/api/BUILD.gn b/chrome/browser/extensions/api/BUILD.gn
index d6ca561..96fe20b6 100644
--- a/chrome/browser/extensions/api/BUILD.gn
+++ b/chrome/browser/extensions/api/BUILD.gn
@@ -21,6 +21,7 @@
 
   deps = [
     # Different APIs include headers from these targets.
+    "//chrome/common:mojo_bindings",
     "//content/public/browser",
     "//extensions/browser",
 
diff --git a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.cc b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.cc
index 8efee87..3896f0b 100644
--- a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.cc
+++ b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.cc
@@ -176,7 +176,7 @@
   return rph;
 }
 
-scoped_refptr<WebRtcLoggingHandlerHost>
+WebRtcLoggingHandlerHost*
 WebrtcLoggingPrivateFunction::LoggingHandlerFromRequest(
     const api::webrtc_logging_private::RequestInfo& request,
     const std::string& security_origin) {
@@ -185,12 +185,10 @@
     // SetError() will have been called by RphFromRequest().
     return nullptr;
   }
-
-  return base::UserDataAdapter<WebRtcLoggingHandlerHost>::Get(
-      host, WebRtcLoggingHandlerHost::kWebRtcLoggingHandlerHostKey);
+  return WebRtcLoggingHandlerHost::FromRenderProcessHost(host);
 }
 
-scoped_refptr<WebRtcLoggingHandlerHost>
+WebRtcLoggingHandlerHost*
 WebrtcLoggingPrivateFunctionWithGenericCallback::PrepareTask(
     const api::webrtc_logging_private::RequestInfo& request,
     const std::string& security_origin,
@@ -248,21 +246,16 @@
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
   WebRtcLoggingHandlerHost::GenericDoneCallback callback;
-  scoped_refptr<WebRtcLoggingHandlerHost> webrtc_logging_handler_host =
+  WebRtcLoggingHandlerHost* webrtc_logging_handler_host =
       PrepareTask(params->request, params->security_origin, &callback);
-  if (!webrtc_logging_handler_host.get())
+  if (!webrtc_logging_handler_host)
     return false;
 
   std::unique_ptr<MetaDataMap> meta_data(new MetaDataMap());
   for (const MetaDataEntry& entry : params->meta_data)
     (*meta_data)[entry.key] = entry.value;
 
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(&WebRtcLoggingHandlerHost::SetMetaData,
-                     webrtc_logging_handler_host, std::move(meta_data),
-                     callback));
-
+  webrtc_logging_handler_host->SetMetaData(std::move(meta_data), callback);
   return true;
 }
 
@@ -271,16 +264,12 @@
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
   WebRtcLoggingHandlerHost::GenericDoneCallback callback;
-  scoped_refptr<WebRtcLoggingHandlerHost> webrtc_logging_handler_host =
+  WebRtcLoggingHandlerHost* webrtc_logging_handler_host =
       PrepareTask(params->request, params->security_origin, &callback);
-  if (!webrtc_logging_handler_host.get())
+  if (!webrtc_logging_handler_host)
     return false;
 
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(&WebRtcLoggingHandlerHost::StartLogging,
-                     webrtc_logging_handler_host, callback));
-
+  webrtc_logging_handler_host->StartLogging(callback);
   return true;
 }
 
@@ -289,9 +278,9 @@
       SetUploadOnRenderClose::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
-  scoped_refptr<WebRtcLoggingHandlerHost> webrtc_logging_handler_host(
+  WebRtcLoggingHandlerHost* webrtc_logging_handler_host(
       LoggingHandlerFromRequest(params->request, params->security_origin));
-  if (!webrtc_logging_handler_host.get())
+  if (!webrtc_logging_handler_host)
     return false;
 
   webrtc_logging_handler_host->set_upload_log_on_render_close(
@@ -313,16 +302,12 @@
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
   WebRtcLoggingHandlerHost::GenericDoneCallback callback;
-  scoped_refptr<WebRtcLoggingHandlerHost> webrtc_logging_handler_host =
+  WebRtcLoggingHandlerHost* webrtc_logging_handler_host =
       PrepareTask(params->request, params->security_origin, &callback);
-  if (!webrtc_logging_handler_host.get())
+  if (!webrtc_logging_handler_host)
     return false;
 
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(&WebRtcLoggingHandlerHost::StopLogging,
-                     webrtc_logging_handler_host, callback));
-
+  webrtc_logging_handler_host->StopLogging(callback);
   return true;
 }
 
@@ -331,19 +316,15 @@
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
   WebRtcLoggingHandlerHost::GenericDoneCallback callback;
-  scoped_refptr<WebRtcLoggingHandlerHost> webrtc_logging_handler_host =
+  WebRtcLoggingHandlerHost* webrtc_logging_handler_host =
       PrepareTask(params->request, params->security_origin, &callback);
-  if (!webrtc_logging_handler_host.get())
+  if (!webrtc_logging_handler_host)
     return false;
 
   const std::string local_log_id(HashIdWithOrigin(params->security_origin,
                                                   params->log_id));
 
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(&WebRtcLoggingHandlerHost::StoreLog,
-                     webrtc_logging_handler_host, local_log_id, callback));
-
+  webrtc_logging_handler_host->StoreLog(local_log_id, callback);
   return true;
 }
 
@@ -352,9 +333,9 @@
       UploadStored::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
-  scoped_refptr<WebRtcLoggingHandlerHost> logging_handler(
-      LoggingHandlerFromRequest(params->request, params->security_origin));
-  if (!logging_handler.get())
+  WebRtcLoggingHandlerHost* logging_handler =
+      LoggingHandlerFromRequest(params->request, params->security_origin);
+  if (!logging_handler)
     return false;
 
   WebRtcLoggingHandlerHost::UploadDoneCallback callback = base::Bind(
@@ -363,11 +344,7 @@
   const std::string local_log_id(HashIdWithOrigin(params->security_origin,
                                                   params->log_id));
 
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(&WebRtcLoggingHandlerHost::UploadStoredLog,
-                     logging_handler, local_log_id, callback));
-
+  logging_handler->UploadStoredLog(local_log_id, callback);
   return true;
 }
 
@@ -375,18 +352,15 @@
   std::unique_ptr<Upload::Params> params(Upload::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
-  scoped_refptr<WebRtcLoggingHandlerHost> logging_handler(
-      LoggingHandlerFromRequest(params->request, params->security_origin));
-  if (!logging_handler.get())
+  WebRtcLoggingHandlerHost* logging_handler =
+      LoggingHandlerFromRequest(params->request, params->security_origin);
+  if (!logging_handler)
     return false;
 
   WebRtcLoggingHandlerHost::UploadDoneCallback callback = base::Bind(
       &WebrtcLoggingPrivateUploadFunction::FireCallback, this);
 
-  base::PostTaskWithTraits(FROM_HERE, {BrowserThread::IO},
-                           base::BindOnce(&WebRtcLoggingHandlerHost::UploadLog,
-                                          logging_handler, callback));
-
+  logging_handler->UploadLog(callback);
   return true;
 }
 
@@ -395,16 +369,12 @@
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
   WebRtcLoggingHandlerHost::GenericDoneCallback callback;
-  scoped_refptr<WebRtcLoggingHandlerHost> webrtc_logging_handler_host =
+  WebRtcLoggingHandlerHost* webrtc_logging_handler_host =
       PrepareTask(params->request, params->security_origin, &callback);
-  if (!webrtc_logging_handler_host.get())
+  if (!webrtc_logging_handler_host)
     return false;
 
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(&WebRtcLoggingHandlerHost::DiscardLog,
-                     webrtc_logging_handler_host, callback));
-
+  webrtc_logging_handler_host->DiscardLog(callback);
   return true;
 }
 
@@ -430,25 +400,19 @@
     return false;
   }
 
-  scoped_refptr<WebRtcLoggingHandlerHost> webrtc_logging_handler_host(
-      base::UserDataAdapter<WebRtcLoggingHandlerHost>::Get(
-          host, WebRtcLoggingHandlerHost::kWebRtcLoggingHandlerHostKey));
+  WebRtcLoggingHandlerHost* webrtc_logging_handler_host =
+      WebRtcLoggingHandlerHost::FromRenderProcessHost(host);
 
   WebRtcLoggingHandlerHost::GenericDoneCallback callback = base::Bind(
       &WebrtcLoggingPrivateStartRtpDumpFunction::FireCallback, this);
 
   // This call cannot fail.
   content::RenderProcessHost::WebRtcStopRtpDumpCallback stop_callback =
-      host->StartRtpDump(params->incoming,
-                         params->outgoing,
+      host->StartRtpDump(params->incoming, params->outgoing,
                          base::Bind(&WebRtcLoggingHandlerHost::OnRtpPacket,
-                                    webrtc_logging_handler_host));
+                                    webrtc_logging_handler_host->GetWeakPtr()));
 
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(&WebRtcLoggingHandlerHost::StartRtpDump,
-                     webrtc_logging_handler_host, type, callback,
-                     stop_callback));
+  webrtc_logging_handler_host->StartRtpDump(type, callback, stop_callback);
   return true;
 }
 
@@ -474,17 +438,13 @@
     return false;
   }
 
-  scoped_refptr<WebRtcLoggingHandlerHost> webrtc_logging_handler_host(
-      base::UserDataAdapter<WebRtcLoggingHandlerHost>::Get(
-          host, WebRtcLoggingHandlerHost::kWebRtcLoggingHandlerHostKey));
+  WebRtcLoggingHandlerHost* webrtc_logging_handler_host =
+      WebRtcLoggingHandlerHost::FromRenderProcessHost(host);
 
   WebRtcLoggingHandlerHost::GenericDoneCallback callback = base::Bind(
       &WebrtcLoggingPrivateStopRtpDumpFunction::FireCallback, this);
 
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(&WebRtcLoggingHandlerHost::StopRtpDump,
-                     webrtc_logging_handler_host, type, callback));
+  webrtc_logging_handler_host->StopRtpDump(type, callback);
   return true;
 }
 
@@ -567,10 +527,9 @@
     return false;
   }
 
-  scoped_refptr<WebRtcLoggingHandlerHost> webrtc_logging_handler_host(
-      base::UserDataAdapter<WebRtcLoggingHandlerHost>::Get(
-          host, WebRtcLoggingHandlerHost::kWebRtcLoggingHandlerHostKey));
-  if (!webrtc_logging_handler_host.get()) {
+  WebRtcLoggingHandlerHost* webrtc_logging_handler_host =
+      WebRtcLoggingHandlerHost::FromRenderProcessHost(host);
+  if (!webrtc_logging_handler_host) {
     SetError("WebRTC logging handler not found.");
     return false;
   }
@@ -579,13 +538,9 @@
       base::BindRepeating(
           &WebrtcLoggingPrivateStartEventLoggingFunction::FireCallback, this);
 
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::UI},
-      base::BindOnce(&WebRtcLoggingHandlerHost::StartEventLogging,
-                     webrtc_logging_handler_host, params->session_id,
-                     params->max_log_size_bytes, params->output_period_ms,
-                     params->web_app_id, callback));
-
+  webrtc_logging_handler_host->StartEventLogging(
+      params->session_id, params->max_log_size_bytes, params->output_period_ms,
+      params->web_app_id, callback);
   return true;
 }
 
@@ -618,10 +573,9 @@
   // that should be granted access to the logs directory.
   content::RenderProcessHost* host = render_frame_host()->GetProcess();
 
-  scoped_refptr<WebRtcLoggingHandlerHost> webrtc_logging_handler_host(
-      base::UserDataAdapter<WebRtcLoggingHandlerHost>::Get(
-          host, WebRtcLoggingHandlerHost::kWebRtcLoggingHandlerHostKey));
-  if (!webrtc_logging_handler_host.get()) {
+  WebRtcLoggingHandlerHost* webrtc_logging_handler_host =
+      WebRtcLoggingHandlerHost::FromRenderProcessHost(host);
+  if (!webrtc_logging_handler_host) {
     FireErrorCallback("WebRTC logging handler not found.");
     return true;
   }
diff --git a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.h b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.h
index cd28a537..34b1124 100644
--- a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.h
+++ b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.h
@@ -32,7 +32,7 @@
       const api::webrtc_logging_private::RequestInfo& request,
       const std::string& security_origin);
 
-  scoped_refptr<WebRtcLoggingHandlerHost> LoggingHandlerFromRequest(
+  WebRtcLoggingHandlerHost* LoggingHandlerFromRequest(
       const api::webrtc_logging_private::RequestInfo& request,
       const std::string& security_origin);
 };
@@ -46,10 +46,10 @@
   // a generic callback object for when the task is completed.
   // If the logging handler can't be found for the given request+origin, the
   // returned ptr will be null.
-  scoped_refptr<WebRtcLoggingHandlerHost> PrepareTask(
-    const api::webrtc_logging_private::RequestInfo& request,
-    const std::string& security_origin,
-    WebRtcLoggingHandlerHost::GenericDoneCallback* callback);
+  WebRtcLoggingHandlerHost* PrepareTask(
+      const api::webrtc_logging_private::RequestInfo& request,
+      const std::string& security_origin,
+      WebRtcLoggingHandlerHost::GenericDoneCallback* callback);
 
   // Must be called on UI thread.
   void FireCallback(bool success, const std::string& error_message);
diff --git a/chrome/browser/media/router/BUILD.gn b/chrome/browser/media/router/BUILD.gn
index 041e41a..1689408 100644
--- a/chrome/browser/media/router/BUILD.gn
+++ b/chrome/browser/media/router/BUILD.gn
@@ -152,6 +152,8 @@
         "providers/openscreen/network_service_quic_packet_writer.cc",
         "providers/openscreen/network_service_quic_packet_writer.h",
         "providers/openscreen/platform/logging.cc",
+        "providers/openscreen/platform/task_runner.cc",
+        "providers/openscreen/platform/task_runner.h",
         "providers/openscreen/platform/time.cc",
       ]
 
diff --git a/chrome/browser/media/router/providers/openscreen/platform/task_runner.cc b/chrome/browser/media/router/providers/openscreen/platform/task_runner.cc
new file mode 100644
index 0000000..2633d3c
--- /dev/null
+++ b/chrome/browser/media/router/providers/openscreen/platform/task_runner.cc
@@ -0,0 +1,46 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <chrono>  // NOLINT
+#include <utility>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
+#include "base/time/time.h"
+
+#include "chrome/browser/media/router/providers/openscreen/platform/task_runner.h"
+
+namespace openscreen {
+namespace platform {
+
+namespace {
+void ExecuteTask(TaskRunner::Task task) {
+  task();
+}
+}  // namespace
+
+ChromeTaskRunner::ChromeTaskRunner(
+    scoped_refptr<base::SequencedTaskRunner> task_runner) {
+  task_runner_ = task_runner;
+}
+
+ChromeTaskRunner::~ChromeTaskRunner() = default;
+
+void ChromeTaskRunner::PostPackagedTask(TaskRunner::Task task) {
+  task_runner_->PostTask(FROM_HERE,
+                         base::BindOnce(ExecuteTask, std::move(task)));
+}
+
+void ChromeTaskRunner::PostPackagedTaskWithDelay(TaskRunner::Task task,
+                                                 Clock::duration delay) {
+  auto time_delta = base::TimeDelta::FromMilliseconds(
+      std::chrono::duration_cast<std::chrono::milliseconds>(delay).count());
+  task_runner_->PostDelayedTask(
+      FROM_HERE, base::BindOnce(ExecuteTask, std::move(task)), time_delta);
+}
+
+}  // namespace platform
+}  // namespace openscreen
diff --git a/chrome/browser/media/router/providers/openscreen/platform/task_runner.h b/chrome/browser/media/router/providers/openscreen/platform/task_runner.h
new file mode 100644
index 0000000..6dd7fd19
--- /dev/null
+++ b/chrome/browser/media/router/providers/openscreen/platform/task_runner.h
@@ -0,0 +1,37 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MEDIA_ROUTER_PROVIDERS_OPENSCREEN_PLATFORM_TASK_RUNNER_H_
+#define CHROME_BROWSER_MEDIA_ROUTER_PROVIDERS_OPENSCREEN_PLATFORM_TASK_RUNNER_H_
+
+#include "base/single_thread_task_runner.h"
+#include "third_party/openscreen/src/platform/api/task_runner.h"
+
+namespace openscreen {
+namespace platform {
+
+class ChromeTaskRunner final : public TaskRunner {
+ public:
+  explicit ChromeTaskRunner(
+      scoped_refptr<base::SequencedTaskRunner> task_runner);
+
+  ChromeTaskRunner(const ChromeTaskRunner&) = delete;
+  ChromeTaskRunner(ChromeTaskRunner&&) = delete;
+  ChromeTaskRunner& operator=(const ChromeTaskRunner&) = delete;
+  ChromeTaskRunner& operator=(ChromeTaskRunner&&) = delete;
+
+  // TaskRunner overrides
+  ~ChromeTaskRunner() final;
+  void PostPackagedTask(TaskRunner::Task task) final;
+  void PostPackagedTaskWithDelay(TaskRunner::Task task,
+                                 Clock::duration delay) final;
+
+ private:
+  scoped_refptr<base::SequencedTaskRunner> task_runner_;
+};
+
+}  // namespace platform
+}  // namespace openscreen
+
+#endif  // CHROME_BROWSER_MEDIA_ROUTER_PROVIDERS_OPENSCREEN_PLATFORM_TASK_RUNNER_H_
diff --git a/chrome/browser/media/webrtc/webrtc_log_uploader.cc b/chrome/browser/media/webrtc/webrtc_log_uploader.cc
index ff329ad..a89794d6 100644
--- a/chrome/browser/media/webrtc/webrtc_log_uploader.cc
+++ b/chrome/browser/media/webrtc/webrtc_log_uploader.cc
@@ -18,18 +18,15 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/task/post_task.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/media/webrtc/webrtc_logging_handler_host.h"
-#include "chrome/browser/net/system_network_context_manager.h"
 #include "components/version_info/version_info.h"
 #include "components/webrtc_logging/browser/log_cleanup.h"
 #include "components/webrtc_logging/browser/text_log_list.h"
 #include "components/webrtc_logging/common/partial_circular_buffer.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "content/public/browser/browser_thread.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
 #include "net/base/load_flags.h"
 #include "net/base/mime_util.h"
 #include "net/base/net_errors.h"
@@ -41,8 +38,6 @@
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
 #include "third_party/zlib/zlib.h"
 
-using content::BrowserThread;
-
 namespace {
 
 const int kLogCountLimit = 5;
@@ -100,18 +95,19 @@
 WebRtcLogUploadDoneData::~WebRtcLogUploadDoneData() {}
 
 WebRtcLogUploader::WebRtcLogUploader()
-    : background_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
+    : main_task_runner_(base::SequencedTaskRunnerHandle::Get()),
+      background_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
           {base::MayBlock(), base::TaskPriority::BEST_EFFORT})) {}
 
 WebRtcLogUploader::~WebRtcLogUploader() {
-  DCHECK_CALLED_ON_VALID_THREAD(create_thread_checker_);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
   DCHECK(pending_uploads_.empty());
-  DCHECK(shutting_down_);
+  DCHECK(shutdown_);
 }
 
 bool WebRtcLogUploader::ApplyForStartLogging() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  if (log_count_ < kLogCountLimit && !shutting_down_) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
+  if (log_count_ < kLogCountLimit && !shutdown_) {
     ++log_count_;
     return true;
   }
@@ -180,11 +176,10 @@
     return;
   }
 
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(&WebRtcLogUploader::UploadCompressedLog,
-                     base::Unretained(this), upload_done_data,
-                     std::move(post_data)));
+  main_task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&WebRtcLogUploader::UploadCompressedLog,
+                                base::Unretained(this), upload_done_data,
+                                std::move(post_data)));
 }
 
 void WebRtcLogUploader::UploadStoredLog(
@@ -205,8 +200,8 @@
     base::UmaHistogramSparse(
         "WebRtcTextLogging.UploadFailureReason",
         WebRtcLoggingHandlerHost::UploadFailureReason::kStoredLogNotFound);
-    base::PostTaskWithTraits(
-        FROM_HERE, {BrowserThread::UI},
+    main_task_runner_->PostTask(
+        FROM_HERE,
         base::BindOnce(upload_data.callback, false, "", "Log doesn't exist."));
     return;
   }
@@ -296,29 +291,29 @@
                     pickle.size());
   }
 
-  base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI},
-                           base::BindOnce(done_callback, true, ""));
+  main_task_runner_->PostTask(FROM_HERE,
+                              base::BindOnce(done_callback, true, ""));
 
-  base::PostTaskWithTraits(FROM_HERE, {BrowserThread::IO},
-                           base::BindOnce(&WebRtcLogUploader::DecreaseLogCount,
-                                          base::Unretained(this)));
+  main_task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&WebRtcLogUploader::DecreaseLogCount,
+                                base::Unretained(this)));
 }
 
-void WebRtcLogUploader::StartShutdown() {
-  DCHECK_CALLED_ON_VALID_THREAD(create_thread_checker_);
+void WebRtcLogUploader::Shutdown() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
+  DCHECK(!shutdown_);
 
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(&WebRtcLogUploader::ShutdownOnIOThread,
-                     base::Unretained(this)));
+  // Clear the pending uploads list, which will reset all URL loaders.
+  pending_uploads_.clear();
+  shutdown_ = true;
 }
 
 void WebRtcLogUploader::OnSimpleLoaderComplete(
     SimpleURLLoaderList::iterator it,
     const WebRtcLogUploadDoneData& upload_done_data,
     std::unique_ptr<std::string> response_body) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DCHECK(!shutting_down_);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
+  DCHECK(!shutdown_);
   network::SimpleURLLoader* loader = it->get();
   base::Optional<int> response_code;
   if (loader->ResponseInfo() && loader->ResponseInfo()->headers) {
@@ -346,33 +341,6 @@
                               upload_done_data);
 }
 
-void WebRtcLogUploader::InitURLLoaderFactoryIfNeeded() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DCHECK(!shutting_down_);
-
-  if (url_loader_factory_.is_bound())
-    return;
-
-  // Clone UI thread URLLoaderFactory for use on the IO thread.
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::UI},
-      base::BindOnce(
-          [](network::mojom::URLLoaderFactoryRequest loader_factory_request) {
-            g_browser_process->shared_url_loader_factory()->Clone(
-                std::move(loader_factory_request));
-          },
-          mojo::MakeRequest(&url_loader_factory_)));
-  // Need to set an error handler so that the class will monitor the state of
-  // the Mojo pipe. Without this, an errored out pipe would only be noticed
-  // after the URLLoaderFactory is used, and a request failed as a result.
-  url_loader_factory_.set_connection_error_handler(base::BindOnce(
-      &WebRtcLogUploader::OnFactoryConnectionClosed, base::Unretained(this)));
-}
-
-void WebRtcLogUploader::OnFactoryConnectionClosed() {
-  url_loader_factory_.reset();
-}
-
 void WebRtcLogUploader::SetupMultipart(
     std::string* post_data,
     const std::string& compressed_log,
@@ -477,14 +445,14 @@
 void WebRtcLogUploader::UploadCompressedLog(
     const WebRtcLogUploadDoneData& upload_done_data,
     std::unique_ptr<std::string> post_data) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
 
   DecreaseLogCount();
 
   // We don't log upload failure to UMA in case of shutting down for
   // consistency, since there are other cases during shutdown were we don't get
   // a chance to log.
-  if (shutting_down_)
+  if (shutdown_)
     return;
 
   std::string content_type = kWebrtcLogUploadContentType;
@@ -530,28 +498,17 @@
   auto it = pending_uploads_.insert(pending_uploads_.begin(),
                                     std::move(simple_url_loader));
   network::SimpleURLLoader* raw_loader = it->get();
-  InitURLLoaderFactoryIfNeeded();
   raw_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
-      url_loader_factory_.get(),
+      g_browser_process->shared_url_loader_factory().get(),
       base::BindOnce(&WebRtcLogUploader::OnSimpleLoaderComplete,
                      base::Unretained(this), std::move(it), upload_done_data));
 }
 
 void WebRtcLogUploader::DecreaseLogCount() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
   --log_count_;
 }
 
-void WebRtcLogUploader::ShutdownOnIOThread() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DCHECK(!shutting_down_);
-
-  // Clear the pending uploads list, which will reset all URL loaders.
-  pending_uploads_.clear();
-  url_loader_factory_.reset();
-  shutting_down_ = true;
-}
-
 void WebRtcLogUploader::WriteCompressedLogToFile(
     const std::string& compressed_log,
     const base::FilePath& log_file_path) {
@@ -648,38 +605,34 @@
     int network_error_code,
     const std::string& report_id,
     const WebRtcLogUploadDoneData& upload_done_data) {
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(&WebRtcLoggingHandlerHost::UploadLogDone,
-                     upload_done_data.host));
-  if (!upload_done_data.callback.is_null()) {
-    const bool success = response_code == net::HTTP_OK;
-    std::string error_message;
-    if (success) {
-      base::UmaHistogramSparse("WebRtcTextLogging.UploadSuccessful",
-                               upload_done_data.web_app_id);
+  if (upload_done_data.callback.is_null())
+    return;
+
+  const bool success = response_code == net::HTTP_OK;
+  std::string error_message;
+  if (success) {
+    base::UmaHistogramSparse("WebRtcTextLogging.UploadSuccessful",
+                             upload_done_data.web_app_id);
+  } else {
+    base::UmaHistogramSparse("WebRtcTextLogging.UploadFailed",
+                             upload_done_data.web_app_id);
+    if (response_code.has_value()) {
+      base::UmaHistogramSparse("WebRtcTextLogging.UploadFailureReason",
+                               response_code.value());
     } else {
-      base::UmaHistogramSparse("WebRtcTextLogging.UploadFailed",
-                               upload_done_data.web_app_id);
-      if (response_code.has_value()) {
-        base::UmaHistogramSparse("WebRtcTextLogging.UploadFailureReason",
-                                 response_code.value());
-      } else {
-        DCHECK_NE(network_error_code, net::OK);
-        base::UmaHistogramSparse(
-            "WebRtcTextLogging.UploadFailureReason",
-            WebRtcLoggingHandlerHost::UploadFailureReason::kNetworkError);
-        base::UmaHistogramSparse("WebRtcTextLogging.UploadFailureNetErrorCode",
-                                 std::abs(network_error_code));
-      }
-      error_message =
-          base::StrCat({"Uploading failed, response code: ",
-                        response_code.has_value()
-                            ? base::NumberToString(response_code.value())
-                            : "<no value>"});
+      DCHECK_NE(network_error_code, net::OK);
+      base::UmaHistogramSparse(
+          "WebRtcTextLogging.UploadFailureReason",
+          WebRtcLoggingHandlerHost::UploadFailureReason::kNetworkError);
+      base::UmaHistogramSparse("WebRtcTextLogging.UploadFailureNetErrorCode",
+                               std::abs(network_error_code));
     }
-    base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI},
-                             base::BindOnce(upload_done_data.callback, success,
-                                            report_id, error_message));
+    error_message = base::StrCat(
+        {"Uploading failed, response code: ",
+         response_code.has_value() ? base::NumberToString(response_code.value())
+                                   : "<no value>"});
   }
+  main_task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(upload_done_data.callback, success, report_id,
+                                error_message));
 }
diff --git a/chrome/browser/media/webrtc/webrtc_log_uploader.h b/chrome/browser/media/webrtc/webrtc_log_uploader.h
index bbb470ef..9fbb587 100644
--- a/chrome/browser/media/webrtc/webrtc_log_uploader.h
+++ b/chrome/browser/media/webrtc/webrtc_log_uploader.h
@@ -14,11 +14,12 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "base/optional.h"
+#include "base/sequence_checker.h"
 #include "base/sequenced_task_runner.h"
-#include "base/threading/thread_checker.h"
 #include "chrome/browser/media/webrtc/webrtc_logging_handler_host.h"
-#include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "url/gurl.h"
 
 namespace network {
 class SimpleURLLoader;
@@ -34,7 +35,6 @@
   ~WebRtcLogUploadDoneData();
 
   WebRtcLoggingHandlerHost::UploadDoneCallback callback;
-  scoped_refptr<WebRtcLoggingHandlerHost> host;
   std::string local_log_id;
   // Used for statistics. See |WebRtcLoggingHandlerHost::web_app_id_|.
   int web_app_id;
@@ -86,8 +86,8 @@
 
   // Cancels URL fetcher operation by deleting all URL fetchers. This cancels
   // any pending uploads and releases SystemURLRequestContextGetter references.
-  // Sets |shutting_down_| which prevent new fetchers to be created.
-  void StartShutdown();
+  // Sets |shutdown_| which prevents new fetchers from being created.
+  void Shutdown();
 
   // For testing purposes. If called, the multipart will not be uploaded, but
   // written to |post_data_| instead.
@@ -116,10 +116,6 @@
   FRIEND_TEST_ALL_PREFIXES(WebRtcLogUploaderTest,
                            AddUploadedLogInfoToUploadListFile);
 
-  void InitURLLoaderFactoryIfNeeded();
-
-  void OnFactoryConnectionClosed();
-
   // Sets up a multipart body to be uploaded. The body is produced according
   // to RFC 2046.
   void SetupMultipart(std::string* post_data,
@@ -135,8 +131,6 @@
 
   void DecreaseLogCount();
 
-  void ShutdownOnIOThread();
-
   // Must be called on the FILE thread.
   void WriteCompressedLogToFile(const std::string& compressed_log,
                                 const base::FilePath& log_file_path);
@@ -187,32 +181,31 @@
                               const WebRtcLogUploadDoneData& upload_done_data,
                               std::unique_ptr<std::string> response_body);
 
-  // This is the UI thread for Chromium. Some other thread for tests.
-  THREAD_CHECKER(create_thread_checker_);
+  SEQUENCE_CHECKER(main_sequence_checker_);
+
+  // Main sequence where this class was constructed.
+  scoped_refptr<base::SequencedTaskRunner> main_task_runner_;
 
   // Background sequence where we run background, potentially blocking,
   // operations.
   scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
 
-  // Keeps track of number of currently open logs. Must be accessed on the IO
-  // thread.
+  // Keeps track of number of currently open logs. Must only be accessed from
+  // the main sequence.
   int log_count_ = 0;
 
   // For testing purposes, see OverrideUploadWithBufferForTesting. Only accessed
-  // on the FILE thread.
+  // on the background sequence
   std::string* post_data_ = nullptr;
 
   // For testing purposes.
   GURL upload_url_for_testing_;
 
-  // Only accessed on the IO thread.
+  // Only accessed on the main sequence.
   SimpleURLLoaderList pending_uploads_;
 
-  // When shutting down, don't create new URL loaders.
-  bool shutting_down_ = false;
-
-  // URLLoaderFactory bound to the IO thread.
-  network::mojom::URLLoaderFactoryPtr url_loader_factory_;
+  // When true, don't create new URL loaders.
+  bool shutdown_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(WebRtcLogUploader);
 };
diff --git a/chrome/browser/media/webrtc/webrtc_log_uploader_unittest.cc b/chrome/browser/media/webrtc/webrtc_log_uploader_unittest.cc
index 5f8a28e..4d9d21b1 100644
--- a/chrome/browser/media/webrtc/webrtc_log_uploader_unittest.cc
+++ b/chrome/browser/media/webrtc/webrtc_log_uploader_unittest.cc
@@ -19,10 +19,8 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/task/post_task.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/time/time.h"
-#include "chrome/test/base/testing_profile.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 const char kTestTime[] = "time";
@@ -190,14 +188,14 @@
     run_loop.Run();
   }
 
-  void FlushIOThread() {
+  void FlushRunLoop() {
     base::RunLoop run_loop;
-    base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO},
-                             run_loop.QuitClosure());
+    base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                     run_loop.QuitClosure());
     run_loop.Run();
   }
 
-  content::TestBrowserThreadBundle thread_bundle_;
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
   base::FilePath test_list_path_;
 };
 
@@ -235,8 +233,8 @@
   ASSERT_TRUE(VerifyNumberOfLines(expected_line_limit));
   ASSERT_TRUE(VerifyLastLineHasLocalStorageInfoOnly());
 
-  webrtc_log_uploader->StartShutdown();
-  FlushIOThread();
+  webrtc_log_uploader->Shutdown();
+  FlushRunLoop();
 }
 
 TEST_F(WebRtcLogUploaderTest, AddUploadedLogInfoToUploadListFile) {
@@ -263,8 +261,8 @@
   ASSERT_TRUE(VerifyNumberOfLines(2));
   ASSERT_TRUE(VerifyLastLineHasUploadInfoOnly());
 
-  webrtc_log_uploader->StartShutdown();
-  FlushIOThread();
+  webrtc_log_uploader->Shutdown();
+  FlushRunLoop();
 }
 
 TEST_F(WebRtcLogUploaderTest, AddRtpDumpsToPostedData) {
@@ -293,13 +291,8 @@
   WebRtcLogUploadDoneData upload_done_data;
   upload_done_data.log_path = temp_dir.GetPath().AppendASCII("log");
 
-  std::unique_ptr<Profile> profile(new TestingProfile());
-  scoped_refptr<WebRtcLoggingHandlerHost> host(new WebRtcLoggingHandlerHost(
-      -1, profile.get(), webrtc_log_uploader.get()));
-
   upload_done_data.incoming_rtp_dump = incoming_dump;
   upload_done_data.outgoing_rtp_dump = outgoing_dump;
-  upload_done_data.host = host.get();
 
   std::unique_ptr<WebRtcLogBuffer> log(new WebRtcLogBuffer());
   log->SetComplete();
@@ -317,6 +310,6 @@
   VerifyRtpDumpInMultipart(post_data, "rtpdump_recv", incoming_dump_content);
   VerifyRtpDumpInMultipart(post_data, "rtpdump_send", outgoing_dump_content);
 
-  webrtc_log_uploader->StartShutdown();
-  FlushIOThread();
+  webrtc_log_uploader->Shutdown();
+  FlushRunLoop();
 }
diff --git a/chrome/browser/media/webrtc/webrtc_logging_handler_host.cc b/chrome/browser/media/webrtc/webrtc_logging_handler_host.cc
index 98dd8a6..a99a049 100644
--- a/chrome/browser/media/webrtc/webrtc_logging_handler_host.cc
+++ b/chrome/browser/media/webrtc/webrtc_logging_handler_host.cc
@@ -13,57 +13,55 @@
 #include "base/logging.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/task/post_task.h"
+#include "base/task_runner_util.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "build/build_config.h"
-#include "chrome/browser/bad_message.h"
+#include "chrome/browser/chrome_service.h"
 #include "chrome/browser/media/webrtc/webrtc_event_log_manager.h"
 #include "chrome/browser/media/webrtc/webrtc_log_uploader.h"
 #include "chrome/browser/media/webrtc/webrtc_rtp_dump_handler.h"
-#include "chrome/common/media/webrtc_logging_messages.h"
+#include "chrome/common/constants.mojom.h"
 #include "components/webrtc_logging/browser/text_log_list.h"
 #include "content/public/browser/browser_context.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/render_process_host.h"
+#include "services/service_manager/public/cpp/connector.h"
 
 #if defined(OS_LINUX) || defined(OS_CHROMEOS)
 #include "content/public/browser/child_process_security_policy.h"
 #include "storage/browser/fileapi/isolated_context.h"
 #endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
 
-using content::BrowserThread;
 using webrtc_event_logging::WebRtcEventLogManager;
 
-// Key used to attach the handler to the RenderProcessHost.
-const char WebRtcLoggingHandlerHost::kWebRtcLoggingHandlerHostKey[] =
-    "kWebRtcLoggingHandlerHostKey";
+namespace {
 
-WebRtcLoggingHandlerHost::WebRtcLoggingHandlerHost(
-    int render_process_id,
-    content::BrowserContext* browser_context,
-    WebRtcLogUploader* log_uploader)
-    : BrowserMessageFilter(WebRtcLoggingMsgStart),
-      render_process_id_(render_process_id),
-      browser_context_directory_path_(browser_context->GetPath()),
-      upload_log_on_render_close_(false),
-      text_log_handler_(new WebRtcTextLogHandler(render_process_id)),
-      rtp_dump_handler_(),
-      stop_rtp_dump_callback_(),
-      log_uploader_(log_uploader) {
-  DCHECK(!browser_context_directory_path_.empty());
-  DCHECK(log_uploader_);
+// Key used to attach the handler to the RenderProcessHost.
+constexpr char kRenderProcessHostKey[] = "kWebRtcLoggingHandlerHostKey";
+
+}  // namespace
+
+// static
+void WebRtcLoggingHandlerHost::AttachToRenderProcessHost(
+    content::RenderProcessHost* host,
+    WebRtcLogUploader* log_uploader) {
+  host->SetUserData(
+      kRenderProcessHostKey,
+      base::WrapUnique<base::SupportsUserData::Data>(
+          new WebRtcLoggingHandlerHost(host->GetID(), host->GetBrowserContext(),
+                                       log_uploader)));
 }
 
-WebRtcLoggingHandlerHost::~WebRtcLoggingHandlerHost() {
-  // If we hit this, then we might be leaking a log reference count (see
-  // ApplyForStartLogging).
-  DCHECK_EQ(WebRtcTextLogHandler::CLOSED, text_log_handler_->GetState());
+// static
+WebRtcLoggingHandlerHost* WebRtcLoggingHandlerHost::FromRenderProcessHost(
+    content::RenderProcessHost* host) {
+  return static_cast<WebRtcLoggingHandlerHost*>(
+      host->GetUserData(kRenderProcessHostKey));
 }
 
 void WebRtcLoggingHandlerHost::SetMetaData(
     std::unique_ptr<MetaDataMap> meta_data,
     const GenericDoneCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!callback.is_null());
 
   // Set the web app ID if there's a "client" key, otherwise leave it unchanged.
@@ -80,33 +78,47 @@
 
 void WebRtcLoggingHandlerHost::StartLogging(
     const GenericDoneCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!callback.is_null());
 
   // Request a log_slot from the LogUploader and start logging.
   if (text_log_handler_->StartLogging(log_uploader_, callback)) {
     // Start logging in the renderer. The callback has already been fired since
     // there is no acknowledgement when the renderer actually starts.
-    Send(new WebRtcLoggingMsg_StartLogging());
+    content::RenderProcessHost* host =
+        content::RenderProcessHost::FromID(render_process_id_);
+
+    // OK for this to replace an existing logging_agent_ connection.
+    ChromeService::GetInstance()->connector()->Connect(
+        service_manager::ServiceFilter::ByNameWithIdInGroup(
+            chrome::mojom::kRendererServiceName,
+            host->GetChildIdentity().instance_id(),
+            host->GetChildIdentity().instance_group()),
+        logging_agent_.BindNewPipeAndPassReceiver());
+
+    logging_agent_.set_disconnect_handler(
+        base::BindOnce(&WebRtcLoggingHandlerHost::OnAgentDisconnected,
+                       weak_factory_.GetWeakPtr()));
+
+    logging_agent_->Start(receiver_.BindNewPipeAndPassRemote());
   }
 }
 
 void WebRtcLoggingHandlerHost::StopLogging(
     const GenericDoneCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!callback.is_null());
 
   // Change the state to STOPPING and disable logging in the browser.
   if (text_log_handler_->StopLogging(callback)) {
-    // Stop logging in the renderer. OnLoggingStoppedInRenderer will be called
-    // when this is done to change the state from STOPPING to STOPPED and fire
-    // the callback.
-    Send(new WebRtcLoggingMsg_StopLogging());
+    // Stop logging in the renderer. OnStopped will be called when this is done
+    // to change the state from STOPPING to STOPPED and fire the callback.
+    logging_agent_->Stop();
   }
 }
 
 void WebRtcLoggingHandlerHost::UploadLog(const UploadDoneCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!callback.is_null());
 
   // This functions uploads both text logs (mandatory) and RTP dumps (optional).
@@ -120,52 +132,41 @@
 
   base::PostTaskAndReplyWithResult(
       log_uploader_->background_task_runner().get(), FROM_HERE,
-      base::Bind(&WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists,
-                 this),
-      base::Bind(&WebRtcLoggingHandlerHost::TriggerUpload, this, callback));
+      base::BindOnce(log_directory_getter_),
+      base::BindOnce(&WebRtcLoggingHandlerHost::TriggerUpload,
+                     weak_factory_.GetWeakPtr(), callback));
 }
 
 void WebRtcLoggingHandlerHost::UploadStoredLog(
     const std::string& log_id,
     const UploadDoneCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!callback.is_null());
 
   base::UmaHistogramSparse("WebRtcTextLogging.UploadStoredStarted",
                            web_app_id_);
 
-  log_uploader_->background_task_runner()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&WebRtcLoggingHandlerHost::UploadStoredLogOnFileThread,
-                     this, log_id, web_app_id_, callback));
-}
-
-void WebRtcLoggingHandlerHost::UploadStoredLogOnFileThread(
-    const std::string& log_id,
-    int web_app_id,
-    const UploadDoneCallback& callback) {
-  DCHECK(log_uploader_->background_task_runner()->RunsTasksInCurrentSequence());
+  // Make this a method call on log_uploader_
 
   WebRtcLogUploadDoneData upload_data;
-  upload_data.log_path = GetLogDirectoryAndEnsureExists();
   upload_data.callback = callback;
-  upload_data.host = this;
   upload_data.local_log_id = log_id;
-  upload_data.web_app_id = web_app_id;
+  upload_data.web_app_id = web_app_id_;
 
-  log_uploader_->UploadStoredLog(upload_data);
-}
-
-void WebRtcLoggingHandlerHost::UploadLogDone() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  // The logging state changed to CLOSED when we released the logs prior to
-  // uploading. We can't check the state because a new log might have started
-  // already, so there is nothing for us to do here. In the future, we might
-  // want to use this function to clean up files stored on disc.
+  log_uploader_->background_task_runner()->PostTask(
+      FROM_HERE, base::BindOnce(
+                     [](WebRtcLogUploader* log_uploader,
+                        WebRtcLogUploadDoneData upload_data,
+                        base::RepeatingCallback<base::FilePath(void)>
+                            log_directory_getter) {
+                       upload_data.log_path = log_directory_getter.Run();
+                       log_uploader->UploadStoredLog(upload_data);
+                     },
+                     log_uploader_, upload_data, log_directory_getter_));
 }
 
 void WebRtcLoggingHandlerHost::DiscardLog(const GenericDoneCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!callback.is_null());
 
   if (!text_log_handler_->ExpectLoggingStateStopped(callback)) {
@@ -183,7 +184,7 @@
 void WebRtcLoggingHandlerHost::StoreLog(
     const std::string& log_id,
     const GenericDoneCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!callback.is_null());
 
   if (!text_log_handler_->ExpectLoggingStateStopped(callback)) {
@@ -192,13 +193,12 @@
   }
 
   if (rtp_dump_handler_) {
-    base::PostTaskWithTraits(
-        FROM_HERE, {BrowserThread::UI},
-        base::BindOnce(stop_rtp_dump_callback_, true, true));
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(stop_rtp_dump_callback_, true, true));
 
     rtp_dump_handler_->StopOngoingDumps(
         base::Bind(&WebRtcLoggingHandlerHost::StoreLogContinue,
-                   this, log_id, callback));
+                   weak_factory_.GetWeakPtr(), log_id, callback));
     return;
   }
 
@@ -208,7 +208,7 @@
 void WebRtcLoggingHandlerHost::StoreLogContinue(
     const std::string& log_id,
     const GenericDoneCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!callback.is_null());
 
   std::unique_ptr<WebRtcLogPaths> log_paths(new WebRtcLogPaths());
@@ -216,19 +216,18 @@
 
   base::PostTaskAndReplyWithResult(
       log_uploader_->background_task_runner().get(), FROM_HERE,
-      base::Bind(&WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists,
-                 this),
-      base::Bind(&WebRtcLoggingHandlerHost::StoreLogInDirectory, this, log_id,
-                 base::Passed(&log_paths), callback));
+      base::BindOnce(log_directory_getter_),
+      base::BindOnce(&WebRtcLoggingHandlerHost::StoreLogInDirectory,
+                     weak_factory_.GetWeakPtr(), log_id,
+                     base::Passed(&log_paths), callback));
 }
 
-
 void WebRtcLoggingHandlerHost::StartRtpDump(
     RtpDumpType type,
     const GenericDoneCallback& callback,
     const content::RenderProcessHost::WebRtcStopRtpDumpCallback&
         stop_callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(stop_rtp_dump_callback_.is_null() ||
          stop_rtp_dump_callback_ == stop_callback);
 
@@ -237,10 +236,9 @@
   if (!rtp_dump_handler_) {
     base::PostTaskAndReplyWithResult(
         log_uploader_->background_task_runner().get(), FROM_HERE,
-        base::Bind(&WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists,
-                   this),
-        base::Bind(&WebRtcLoggingHandlerHost::CreateRtpDumpHandlerAndStart,
-                   this, type, callback));
+        base::BindOnce(log_directory_getter_),
+        base::BindOnce(&WebRtcLoggingHandlerHost::CreateRtpDumpHandlerAndStart,
+                       weak_factory_.GetWeakPtr(), type, callback));
     return;
   }
 
@@ -250,7 +248,7 @@
 void WebRtcLoggingHandlerHost::StopRtpDump(
     RtpDumpType type,
     const GenericDoneCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!callback.is_null());
 
   if (!rtp_dump_handler_) {
@@ -259,8 +257,8 @@
   }
 
   if (!stop_rtp_dump_callback_.is_null()) {
-    base::PostTaskWithTraits(
-        FROM_HERE, {BrowserThread::UI},
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
         base::BindOnce(stop_rtp_dump_callback_,
                        type == RTP_DUMP_INCOMING || type == RTP_DUMP_BOTH,
                        type == RTP_DUMP_OUTGOING || type == RTP_DUMP_BOTH));
@@ -275,7 +273,7 @@
     int output_period_ms,
     size_t web_app_id,
     const StartEventLoggingCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   WebRtcEventLogManager::GetInstance()->StartRemoteLogging(
       render_process_id_, session_id, max_log_size_bytes, output_period_ms,
       web_app_id, callback);
@@ -285,24 +283,23 @@
 void WebRtcLoggingHandlerHost::GetLogsDirectory(
     const LogsDirectoryCallback& callback,
     const LogsDirectoryErrorCallback& error_callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!callback.is_null());
   base::PostTaskAndReplyWithResult(
       log_uploader_->background_task_runner().get(), FROM_HERE,
-      base::Bind(&WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists,
-                 this),
-      base::Bind(&WebRtcLoggingHandlerHost::GrantLogsDirectoryAccess, this,
-                 callback, error_callback));
+      base::BindOnce(log_directory_getter_),
+      base::BindOnce(&WebRtcLoggingHandlerHost::GrantLogsDirectoryAccess,
+                     weak_factory_.GetWeakPtr(), callback, error_callback));
 }
 
 void WebRtcLoggingHandlerHost::GrantLogsDirectoryAccess(
     const LogsDirectoryCallback& callback,
     const LogsDirectoryErrorCallback& error_callback,
     const base::FilePath& logs_path) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (logs_path.empty()) {
-    base::PostTaskWithTraits(
-        FROM_HERE, {BrowserThread::UI},
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
         base::BindOnce(error_callback, "Logs directory not available"));
     return;
   }
@@ -324,9 +321,8 @@
   policy->GrantReadFileSystem(render_process_id_, file_system.id());
   // Delete is needed to prevent accumulation of files.
   policy->GrantDeleteFromFileSystem(render_process_id_, file_system.id());
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::UI},
-      base::BindOnce(callback, file_system.id(), registered_name));
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(callback, file_system.id(), registered_name));
 }
 #endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
 
@@ -335,21 +331,7 @@
     size_t header_length,
     size_t packet_length,
     bool incoming) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(&WebRtcLoggingHandlerHost::DumpRtpPacketOnIOThread, this,
-                     std::move(packet_header), header_length, packet_length,
-                     incoming));
-}
-
-void WebRtcLoggingHandlerHost::DumpRtpPacketOnIOThread(
-    std::unique_ptr<uint8_t[]> packet_header,
-    size_t header_length,
-    size_t packet_length,
-    bool incoming) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // |rtp_dump_handler_| could be NULL if we are waiting for the FILE thread to
   // create/ensure the log directory.
@@ -359,115 +341,98 @@
   }
 }
 
-void WebRtcLoggingHandlerHost::OnChannelClosing() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+void WebRtcLoggingHandlerHost::OnAddMessages(
+    std::vector<chrome::mojom::WebRtcLoggingMessagePtr> messages) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  if (!text_log_handler_->GetChannelIsClosing()) {
-    switch (text_log_handler_->GetState()) {
-      case WebRtcTextLogHandler::STARTING:
-      case WebRtcTextLogHandler::STARTED:
-      case WebRtcTextLogHandler::STOPPING:
-      case WebRtcTextLogHandler::STOPPED:
-        text_log_handler_->ChannelClosing();
-        if (upload_log_on_render_close_) {
-          base::PostTaskAndReplyWithResult(
-              log_uploader_->background_task_runner().get(), FROM_HERE,
-              base::BindOnce(
-                  &WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists,
-                  this),
-              base::BindOnce(&WebRtcLoggingHandlerHost::TriggerUpload, this,
-                             UploadDoneCallback()));
-        } else {
-          log_uploader_->LoggingStoppedDontUpload();
-          text_log_handler_->DiscardLog();
-        }
-        break;
-      case WebRtcTextLogHandler::CLOSED:
-        // Do nothing
-        break;
-      default:
-        NOTREACHED();
-    }
-  }
-
-  content::BrowserMessageFilter::OnChannelClosing();
-}
-
-void WebRtcLoggingHandlerHost::OnDestruct() const {
-  BrowserThread::DeleteOnIOThread::Destruct(this);
-}
-
-bool WebRtcLoggingHandlerHost::OnMessageReceived(const IPC::Message& message) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(WebRtcLoggingHandlerHost, message)
-    IPC_MESSAGE_HANDLER(WebRtcLoggingMsg_AddLogMessages, OnAddLogMessages)
-    IPC_MESSAGE_HANDLER(WebRtcLoggingMsg_LoggingStopped,
-                        OnLoggingStoppedInRenderer)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-
-  return handled;
-}
-
-void WebRtcLoggingHandlerHost::OnAddLogMessages(
-    const std::vector<WebRtcLoggingMessageData>& messages) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   if (text_log_handler_->GetState() == WebRtcTextLogHandler::STARTED ||
       text_log_handler_->GetState() == WebRtcTextLogHandler::STOPPING) {
-    for (auto& message : messages) {
-      text_log_handler_->LogWebRtcLoggingMessageData(message);
-    }
+    for (auto& message : messages)
+      text_log_handler_->LogWebRtcLoggingMessage(message.get());
   }
 }
 
-void WebRtcLoggingHandlerHost::OnLoggingStoppedInRenderer() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+void WebRtcLoggingHandlerHost::OnStopped() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   if (text_log_handler_->GetState() != WebRtcTextLogHandler::STOPPING) {
     // If an out-of-order response is received, stop_callback_ may be invalid,
     // and must not be invoked.
-    DLOG(ERROR) << "OnLoggingStoppedInRenderer invoked in state "
+    DLOG(ERROR) << "OnStopped invoked in state "
                 << text_log_handler_->GetState();
-    bad_message::ReceivedBadMessage(
-        this, bad_message::WRLHH_LOGGING_STOPPED_BAD_STATE);
+    mojo::ReportBadMessage("WRLHH: OnStopped invoked in unexpected state.");
     return;
   }
   text_log_handler_->StopDone();
 }
 
-base::FilePath WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists() {
-  DCHECK(log_uploader_->background_task_runner()->RunsTasksInCurrentSequence());
+WebRtcLoggingHandlerHost::WebRtcLoggingHandlerHost(
+    int render_process_id,
+    content::BrowserContext* browser_context,
+    WebRtcLogUploader* log_uploader)
+    : receiver_(this),
+      render_process_id_(render_process_id),
+      log_directory_getter_(base::BindRepeating(
+          &WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists,
+          browser_context->GetPath())),
+      upload_log_on_render_close_(false),
+      text_log_handler_(
+          std::make_unique<WebRtcTextLogHandler>(render_process_id)),
+      rtp_dump_handler_(),
+      stop_rtp_dump_callback_(),
+      log_uploader_(log_uploader) {
+  DCHECK(log_uploader_);
+}
 
-  // Since we can be alive after the RenderProcessHost and the BrowserContext
-  // (profile) have gone away, we could create the log directory here after a
-  // profile has been deleted and removed from disk. If that happens it will be
-  // cleaned up (at a higher level) the next browser restart.
-  base::FilePath log_dir_path =
-      webrtc_logging::TextLogList::GetWebRtcLogDirectoryForBrowserContextPath(
-          browser_context_directory_path_);
-  base::File::Error error;
-  if (!base::CreateDirectoryAndGetError(log_dir_path, &error)) {
-    DLOG(ERROR) << "Could not create WebRTC log directory, error: " << error;
-    return base::FilePath();
+WebRtcLoggingHandlerHost::~WebRtcLoggingHandlerHost() {
+  // If we hit this, then we might be leaking a log reference count (see
+  // ApplyForStartLogging).
+  DCHECK_EQ(WebRtcTextLogHandler::CLOSED, text_log_handler_->GetState());
+}
+
+void WebRtcLoggingHandlerHost::OnAgentDisconnected() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (text_log_handler_->GetChannelIsClosing())
+    return;
+
+  switch (text_log_handler_->GetState()) {
+    case WebRtcTextLogHandler::STARTING:
+    case WebRtcTextLogHandler::STARTED:
+    case WebRtcTextLogHandler::STOPPING:
+    case WebRtcTextLogHandler::STOPPED:
+      text_log_handler_->ChannelClosing();
+      if (upload_log_on_render_close_) {
+        base::PostTaskAndReplyWithResult(
+            log_uploader_->background_task_runner().get(), FROM_HERE,
+            base::BindOnce(log_directory_getter_),
+            base::BindOnce(&WebRtcLoggingHandlerHost::TriggerUpload,
+                           weak_factory_.GetWeakPtr(), UploadDoneCallback()));
+      } else {
+        log_uploader_->LoggingStoppedDontUpload();
+        text_log_handler_->DiscardLog();
+      }
+      break;
+    case WebRtcTextLogHandler::CLOSED:
+      // Do nothing
+      break;
+    default:
+      NOTREACHED();
   }
-  return log_dir_path;
 }
 
 void WebRtcLoggingHandlerHost::TriggerUpload(
     const UploadDoneCallback& callback,
     const base::FilePath& log_directory) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (rtp_dump_handler_) {
-    base::PostTaskWithTraits(
-        FROM_HERE, {BrowserThread::UI},
-        base::BindOnce(stop_rtp_dump_callback_, true, true));
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(stop_rtp_dump_callback_, true, true));
 
     rtp_dump_handler_->StopOngoingDumps(
         base::Bind(&WebRtcLoggingHandlerHost::DoUploadLogAndRtpDumps,
-                   this,
-                   log_directory,
-                   callback));
+                   weak_factory_.GetWeakPtr(), log_directory, callback));
     return;
   }
 
@@ -479,7 +444,7 @@
     std::unique_ptr<WebRtcLogPaths> log_paths,
     const GenericDoneCallback& done_callback,
     const base::FilePath& directory) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // If channel is not closing, storing is only allowed when in STOPPED state.
   // If channel is closing, storing is allowed for all states except CLOSED.
@@ -490,10 +455,9 @@
        text_logging_state != WebRtcTextLogHandler::STOPPED) ||
       (channel_is_closing &&
        text_log_handler_->GetState() == WebRtcTextLogHandler::CLOSED)) {
-    base::PostTaskWithTraits(
-        FROM_HERE, {content::BrowserThread::UI},
-        base::BindOnce(done_callback, false,
-                       "Logging not stopped or no log open."));
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(done_callback, false,
+                                  "Logging not stopped or no log open."));
     return;
   }
 
@@ -515,7 +479,7 @@
 void WebRtcLoggingHandlerHost::DoUploadLogAndRtpDumps(
     const base::FilePath& log_directory,
     const UploadDoneCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // If channel is not closing, upload is only allowed when in STOPPED state.
   // If channel is closing, uploading is allowed for all states except CLOSED.
@@ -536,17 +500,15 @@
       base::UmaHistogramSparse("WebRtcTextLogging.UploadFailureReason",
                                UploadFailureReason::kInvalidState);
     }
-    base::PostTaskWithTraits(
-        FROM_HERE, {content::BrowserThread::UI},
-        base::BindOnce(callback, false, "",
-                       "Logging not stopped or no log open."));
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(callback, false, "",
+                                  "Logging not stopped or no log open."));
     return;
   }
 
   WebRtcLogUploadDoneData upload_done_data;
   upload_done_data.log_path = log_directory;
   upload_done_data.callback = callback;
-  upload_done_data.host = this;
   upload_done_data.web_app_id = web_app_id_;
   ReleaseRtpDumps(&upload_done_data);
 
@@ -567,7 +529,7 @@
     RtpDumpType type,
     const GenericDoneCallback& callback,
     const base::FilePath& dump_dir) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // |rtp_dump_handler_| may be non-NULL if StartRtpDump is called again before
   // GetLogDirectoryAndEnsureExists returns on the FILE thread for a previous
@@ -580,7 +542,7 @@
 
 void WebRtcLoggingHandlerHost::DoStartRtpDump(
     RtpDumpType type, const GenericDoneCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(rtp_dump_handler_);
 
   std::string error;
@@ -589,7 +551,7 @@
 }
 
 bool WebRtcLoggingHandlerHost::ReleaseRtpDumps(WebRtcLogPaths* log_paths) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(log_paths);
 
   if (!rtp_dump_handler_)
@@ -610,10 +572,29 @@
     const GenericDoneCallback& callback,
     bool success,
     const std::string& error_message) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!callback.is_null());
   DCHECK_EQ(success, error_message.empty());
 
-  base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI},
-                           base::BindOnce(callback, success, error_message));
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(callback, success, error_message));
+}
+
+// static
+base::FilePath WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists(
+    const base::FilePath& browser_context_directory_path) {
+  DCHECK(!browser_context_directory_path.empty());
+  // Since we can be alive after the RenderProcessHost and the BrowserContext
+  // (profile) have gone away, we could create the log directory here after a
+  // profile has been deleted and removed from disk. If that happens it will be
+  // cleaned up (at a higher level) the next browser restart.
+  base::FilePath log_dir_path =
+      webrtc_logging::TextLogList::GetWebRtcLogDirectoryForBrowserContextPath(
+          browser_context_directory_path);
+  base::File::Error error;
+  if (!base::CreateDirectoryAndGetError(log_dir_path, &error)) {
+    DLOG(ERROR) << "Could not create WebRTC log directory, error: " << error;
+    return base::FilePath();
+  }
+  return log_dir_path;
 }
diff --git a/chrome/browser/media/webrtc/webrtc_logging_handler_host.h b/chrome/browser/media/webrtc/webrtc_logging_handler_host.h
index 32541d6..326e24e 100644
--- a/chrome/browser/media/webrtc/webrtc_logging_handler_host.h
+++ b/chrome/browser/media/webrtc/webrtc_logging_handler_host.h
@@ -15,15 +15,17 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/supports_user_data.h"
 #include "build/build_config.h"
 #include "chrome/browser/media/webrtc/rtp_dump_type.h"
 #include "chrome/browser/media/webrtc/webrtc_text_log_handler.h"
-#include "content/public/browser/browser_message_filter.h"
+#include "chrome/common/media/webrtc_logging.mojom.h"
 #include "content/public/browser/render_process_host.h"
+#include "mojo/public/cpp/bindings/remote.h"
 
 class WebRtcLogUploader;
 class WebRtcRtpDumpHandler;
-struct WebRtcLoggingMessageData;
 
 namespace content {
 class BrowserContext;
@@ -38,15 +40,16 @@
 typedef std::map<std::string, std::string> MetaDataMap;
 
 // WebRtcLoggingHandlerHost handles operations regarding the WebRTC logging:
-// - Opens a shared memory buffer that the handler in the render process
-//   writes to.
+// - Opens a connection to a WebRtcLoggingAgent that runs in the render process
+//   and generates log messages.
 // - Writes basic machine info to the log.
 // - Informs the handler in the render process when to stop logging.
-// - Closes the shared memory (and thereby discarding it) or triggers uploading
-//   of the log.
-// - Detects when channel, i.e. renderer, is going away and possibly triggers
-//   uploading the log.
-class WebRtcLoggingHandlerHost : public content::BrowserMessageFilter {
+// - Closes the connection to the WebRtcLoggingAgent (and thereby discarding it)
+//   or triggers uploading of the log.
+// - Detects when the agent (e.g., because of a tab closure or crash) is going
+//   away and possibly triggers uploading the log.
+class WebRtcLoggingHandlerHost : public base::SupportsUserData::Data,
+                                 public chrome::mojom::WebRtcLoggingClient {
  public:
   typedef base::Callback<void(bool, const std::string&)> GenericDoneCallback;
   typedef base::Callback<void(bool, const std::string&, const std::string&)>
@@ -62,9 +65,6 @@
       void(bool, const std::string&, const std::string&)>
       StartEventLoggingCallback;
 
-  // Key used to attach the handler to the RenderProcessHost.
-  static const char kWebRtcLoggingHandlerHostKey[];
-
   // Upload failure reasons used for UMA stats. A failure reason can be one of
   // those listed here or a response code for the upload HTTP request. The
   // values in this list must be less than 100 and cannot be changed.
@@ -74,9 +74,10 @@
     kNetworkError = 2,
   };
 
-  WebRtcLoggingHandlerHost(int render_process_id,
-                           content::BrowserContext* browser_context,
-                           WebRtcLogUploader* log_uploader);
+  static void AttachToRenderProcessHost(content::RenderProcessHost* host,
+                                        WebRtcLogUploader* log_uploader);
+  static WebRtcLoggingHandlerHost* FromRenderProcessHost(
+      content::RenderProcessHost* host);
 
   // Sets meta data that will be uploaded along with the log and also written
   // in the beginning of the log. Must be called on the IO thread before calling
@@ -161,20 +162,22 @@
                         const LogsDirectoryErrorCallback& error_callback);
 #endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
 
- private:
-  friend class content::BrowserThread;
-  friend class base::DeleteHelper<WebRtcLoggingHandlerHost>;
+  // chrome::mojom::WebRtcLoggingClient methods:
+  void OnAddMessages(
+      std::vector<chrome::mojom::WebRtcLoggingMessagePtr> messages) override;
+  void OnStopped() override;
 
+  base::WeakPtr<WebRtcLoggingHandlerHost> GetWeakPtr() {
+    return weak_factory_.GetWeakPtr();
+  }
+
+ private:
+  WebRtcLoggingHandlerHost(int render_process_id,
+                           content::BrowserContext* browser_context,
+                           WebRtcLogUploader* log_uploader);
   ~WebRtcLoggingHandlerHost() override;
 
-  // BrowserMessageFilter implementation.
-  void OnChannelClosing() override;
-  void OnDestruct() const override;
-  bool OnMessageReceived(const IPC::Message& message) override;
-
-  // Handles log message requests from renderer process.
-  void OnAddLogMessages(const std::vector<WebRtcLoggingMessageData>& messages);
-  void OnLoggingStoppedInRenderer();
+  void OnAgentDisconnected();
 
   // Called after stopping RTP dumps.
   void StoreLogContinue(const std::string& log_id,
@@ -183,10 +186,6 @@
   // Writes a formatted log |message| to the |circular_buffer_|.
   void LogToCircularBuffer(const std::string& message);
 
-  // Gets the log directory path for |browser_context_| and ensure it exists.
-  // Must be called on the FILE thread.
-  base::FilePath GetLogDirectoryAndEnsureExists();
-
   void TriggerUpload(const UploadDoneCallback& callback,
                      const base::FilePath& log_directory);
 
@@ -195,10 +194,6 @@
                            const GenericDoneCallback& done_callback,
                            const base::FilePath& directory);
 
-  void UploadStoredLogOnFileThread(const std::string& log_id,
-                                   int web_app_id,
-                                   const UploadDoneCallback& callback);
-
   // A helper for TriggerUpload to do the real work.
   void DoUploadLogAndRtpDumps(const base::FilePath& log_directory,
                               const UploadDoneCallback& callback);
@@ -213,12 +208,6 @@
   // created.
   void DoStartRtpDump(RtpDumpType type, const GenericDoneCallback& callback);
 
-  // Adds the packet to the dump on IO thread.
-  void DumpRtpPacketOnIOThread(std::unique_ptr<uint8_t[]> packet_header,
-                               size_t header_length,
-                               size_t packet_length,
-                               bool incoming);
-
   bool ReleaseRtpDumps(WebRtcLogPaths* log_paths);
 
   void FireGenericDoneCallback(
@@ -237,18 +226,27 @@
       const base::FilePath& logs_path);
 #endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
 
+  static base::FilePath GetLogDirectoryAndEnsureExists(
+      const base::FilePath& browser_context_directory_path);
+
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  mojo::Receiver<chrome::mojom::WebRtcLoggingClient> receiver_;
+  mojo::Remote<chrome::mojom::WebRtcLoggingAgent> logging_agent_;
+
   // The render process ID this object belongs to.
   const int render_process_id_;
 
-  // The browser context directory path associated with our renderer process.
-  const base::FilePath browser_context_directory_path_;
+  // A callback that needs to be run from a blocking worker pool and returns
+  // the browser context directory path associated with our renderer process.
+  base::RepeatingCallback<base::FilePath(void)> log_directory_getter_;
 
   // Only accessed on the IO thread.
   bool upload_log_on_render_close_;
 
   // The text log handler owns the WebRtcLogBuffer object and keeps track of
   // the logging state. It is a scoped_refptr to allow posting tasks.
-  scoped_refptr<WebRtcTextLogHandler> text_log_handler_;
+  std::unique_ptr<WebRtcTextLogHandler> text_log_handler_;
 
   // The RTP dump handler responsible for creating the RTP header dump files.
   std::unique_ptr<WebRtcRtpDumpHandler> rtp_dump_handler_;
@@ -265,6 +263,8 @@
   // the empty string. Must only be accessed on the IO thread.
   int web_app_id_ = 0;
 
+  base::WeakPtrFactory<WebRtcLoggingHandlerHost> weak_factory_{this};
+
   DISALLOW_COPY_AND_ASSIGN(WebRtcLoggingHandlerHost);
 };
 
diff --git a/chrome/browser/media/webrtc/webrtc_rtp_dump_handler.cc b/chrome/browser/media/webrtc/webrtc_rtp_dump_handler.cc
index 070a81a..39bec05 100644
--- a/chrome/browser/media/webrtc/webrtc_rtp_dump_handler.cc
+++ b/chrome/browser/media/webrtc/webrtc_rtp_dump_handler.cc
@@ -12,12 +12,9 @@
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/task/post_task.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "base/time/time.h"
 #include "chrome/browser/media/webrtc/webrtc_rtp_dump_writer.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "content/public/browser/browser_thread.h"
-
-using content::BrowserThread;
 
 namespace {
 
@@ -33,11 +30,10 @@
     const WebRtcRtpDumpHandler::GenericDoneCallback& callback,
     bool success,
     const std::string& error_message) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(!callback.is_null());
 
-  base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI},
-                           base::BindOnce(callback, success, error_message));
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(callback, success, error_message));
 }
 
 bool DumpTypeContainsIncoming(RtpDumpType type) {
diff --git a/chrome/browser/media/webrtc/webrtc_rtp_dump_writer.cc b/chrome/browser/media/webrtc/webrtc_rtp_dump_writer.cc
index 417a4acd..330ad46 100644
--- a/chrome/browser/media/webrtc/webrtc_rtp_dump_writer.cc
+++ b/chrome/browser/media/webrtc/webrtc_rtp_dump_writer.cc
@@ -15,8 +15,6 @@
 #include "content/public/browser/browser_thread.h"
 #include "third_party/zlib/zlib.h"
 
-using content::BrowserThread;
-
 namespace {
 
 static const size_t kMinimumGzipOutputBufferSize = 256;  // In bytes.
diff --git a/chrome/browser/media/webrtc/webrtc_text_log_handler.cc b/chrome/browser/media/webrtc/webrtc_text_log_handler.cc
index 2a29f43..30a4f910 100644
--- a/chrome/browser/media/webrtc/webrtc_text_log_handler.cc
+++ b/chrome/browser/media/webrtc/webrtc_text_log_handler.cc
@@ -22,7 +22,7 @@
 #include "base/time/time.h"
 #include "chrome/browser/media/webrtc/webrtc_log_uploader.h"
 #include "chrome/common/channel_info.h"
-#include "chrome/common/media/webrtc_logging_messages.h"
+#include "chrome/common/media/webrtc_logging.mojom.h"
 #include "components/version_info/version_info.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
@@ -53,10 +53,26 @@
 #endif
 
 using base::NumberToString;
-using content::BrowserThread;
 
 namespace {
 
+void ForwardMessageViaTaskRunner(
+    scoped_refptr<base::SequencedTaskRunner> task_runner,
+    base::Callback<void(const std::string&)> callback,
+    const std::string& message) {
+  task_runner->PostTask(FROM_HERE,
+                        base::BindOnce(std::move(callback), message));
+}
+
+std::string Format(const std::string& message,
+                   base::Time timestamp,
+                   base::Time start_time) {
+  int32_t interval_ms =
+      static_cast<int32_t>((timestamp - start_time).InMilliseconds());
+  return base::StringPrintf("[%03d:%03d] %s", interval_ms / 1000,
+                            interval_ms % 1000, message.c_str());
+}
+
 std::string FormatMetaDataAsLogMessage(const MetaDataMap& meta_data) {
   std::string message;
   for (auto& kv : meta_data) {
@@ -110,11 +126,13 @@
       read_only_(false) {}
 
 WebRtcLogBuffer::~WebRtcLogBuffer() {
-  DCHECK(read_only_ || thread_checker_.CalledOnValidThread());
+#if DCHECK_IS_ON()
+  DCHECK(read_only_ || sequence_checker_.CalledOnValidSequence());
+#endif
 }
 
 void WebRtcLogBuffer::Log(const std::string& message) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!read_only_);
   circular_.Write(message.c_str(), message.length());
   const char eol = '\n';
@@ -122,18 +140,19 @@
 }
 
 webrtc_logging::PartialCircularBuffer WebRtcLogBuffer::Read() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(read_only_);
   return webrtc_logging::PartialCircularBuffer(&buffer_[0], sizeof(buffer_));
 }
 
 void WebRtcLogBuffer::SetComplete() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!read_only_) << "Already set? (programmer error)";
   read_only_ = true;
-  // Detach from the current thread so that we can check reads on a different
-  // thread.  This is to make sure that Read()s still happen on one thread only.
-  thread_checker_.DetachFromThread();
+  // Detach from the current sequence so that we can check reads on a different
+  // sequence. This is to make sure that Read()s still happen on one sequence
+  // only.
+  DETACH_FROM_SEQUENCE(sequence_checker_);
 }
 
 WebRtcTextLogHandler::WebRtcTextLogHandler(int render_process_id)
@@ -147,18 +166,18 @@
 }
 
 WebRtcTextLogHandler::LoggingState WebRtcTextLogHandler::GetState() const {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return logging_state_;
 }
 
 bool WebRtcTextLogHandler::GetChannelIsClosing() const {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return channel_is_closing_;
 }
 
 void WebRtcTextLogHandler::SetMetaData(std::unique_ptr<MetaDataMap> meta_data,
                                        const GenericDoneCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!callback.is_null());
 
   if (channel_is_closing_) {
@@ -192,7 +211,7 @@
 
 bool WebRtcTextLogHandler::StartLogging(WebRtcLogUploader* log_uploader,
                                         const GenericDoneCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!callback.is_null());
 
   if (channel_is_closing_) {
@@ -219,15 +238,15 @@
   if (!meta_data_)
     meta_data_.reset(new MetaDataMap());
 
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::UI},
-      base::BindOnce(&WebRtcTextLogHandler::GetNetworkInterfaceListOnUIThread,
-                     this, std::move(callback)));
+  content::GetNetworkService()->GetNetworkList(
+      net::EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES,
+      base::BindOnce(&WebRtcTextLogHandler::OnGetNetworkInterfaceList,
+                     weak_factory_.GetWeakPtr(), std::move(callback)));
   return true;
 }
 
 void WebRtcTextLogHandler::StartDone(const GenericDoneCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!callback.is_null());
 
   if (channel_is_closing_) {
@@ -246,7 +265,7 @@
 }
 
 bool WebRtcTextLogHandler::StopLogging(const GenericDoneCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!callback.is_null());
 
   if (channel_is_closing_) {
@@ -263,12 +282,15 @@
   stop_callback_ = callback;
   logging_state_ = STOPPING;
 
-  content::WebRtcLog::ClearLogMessageCallback(render_process_id_);
+  base::PostTaskWithTraits(
+      FROM_HERE, {content::BrowserThread::IO},
+      base::BindOnce(&content::WebRtcLog::ClearLogMessageCallback,
+                     render_process_id_));
   return true;
 }
 
 void WebRtcTextLogHandler::StopDone() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(stop_callback_);
 
   if (channel_is_closing_) {
@@ -291,15 +313,18 @@
 }
 
 void WebRtcTextLogHandler::ChannelClosing() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
-  if (logging_state_ == STARTING || logging_state_ == STARTED)
-    content::WebRtcLog::ClearLogMessageCallback(render_process_id_);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (logging_state_ == STARTING || logging_state_ == STARTED) {
+    base::PostTaskWithTraits(
+        FROM_HERE, {content::BrowserThread::IO},
+        base::BindOnce(&content::WebRtcLog::ClearLogMessageCallback,
+                       render_process_id_));
+  }
   channel_is_closing_ = true;
 }
 
 void WebRtcTextLogHandler::DiscardLog() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(logging_state_ == STOPPED ||
          (channel_is_closing_ && logging_state_ != CLOSED));
 
@@ -313,7 +338,7 @@
 void WebRtcTextLogHandler::ReleaseLog(
     std::unique_ptr<WebRtcLogBuffer>* log_buffer,
     std::unique_ptr<MetaDataMap>* meta_data) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(logging_state_ == STOPPED ||
          (channel_is_closing_ && logging_state_ != CLOSED));
   DCHECK(log_buffer_);
@@ -334,7 +359,7 @@
 }
 
 void WebRtcTextLogHandler::LogToCircularBuffer(const std::string& message) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK_NE(logging_state_, CLOSED);
   if (log_buffer_) {
     log_buffer_->Log(message);
@@ -342,22 +367,23 @@
 }
 
 void WebRtcTextLogHandler::LogMessage(const std::string& message) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (logging_state_ == STARTED && !channel_is_closing_) {
-    LogToCircularBuffer(WebRtcLoggingMessageData::Format(
-        message, base::Time::Now(), logging_started_time_));
+    LogToCircularBuffer(
+        Format(message, base::Time::Now(), logging_started_time_));
   }
 }
 
-void WebRtcTextLogHandler::LogWebRtcLoggingMessageData(
-    const WebRtcLoggingMessageData& message) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  LogToCircularBuffer(message.Format(logging_started_time_));
+void WebRtcTextLogHandler::LogWebRtcLoggingMessage(
+    const chrome::mojom::WebRtcLoggingMessage* message) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  LogToCircularBuffer(
+      Format(message->data, message->timestamp, logging_started_time_));
 }
 
 bool WebRtcTextLogHandler::ExpectLoggingStateStopped(
     const GenericDoneCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (logging_state_ != STOPPED) {
     FireGenericDoneCallback(callback, false,
                             "Logging not stopped or no log open.");
@@ -370,13 +396,13 @@
     const GenericDoneCallback& callback,
     bool success,
     const std::string& error_message) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!callback.is_null());
 
   if (error_message.empty()) {
     DCHECK(success);
-    base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI},
-                             base::BindOnce(callback, success, error_message));
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(callback, success, error_message));
     return;
   }
 
@@ -404,40 +430,19 @@
       base::StrCat({error_message, ". State=", state_string(), ". Channel is ",
                     channel_is_closing_ ? "" : "not ", "closing."});
 
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::UI},
-      base::BindOnce(callback, success, error_message_with_state));
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(callback, success, error_message_with_state));
 }
 
 void WebRtcTextLogHandler::SetWebAppId(int web_app_id) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   web_app_id_ = web_app_id;
 }
 
-void WebRtcTextLogHandler::GetNetworkInterfaceListOnUIThread(
-    const GenericDoneCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  content::GetNetworkService()->GetNetworkList(
-      net::EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES,
-      base::BindOnce(&WebRtcTextLogHandler::OnGetNetworkInterfaceList, this,
-                     std::move(callback)));
-}
-
 void WebRtcTextLogHandler::OnGetNetworkInterfaceList(
     const GenericDoneCallback& callback,
     const base::Optional<net::NetworkInterfaceList>& networks) {
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(
-          &WebRtcTextLogHandler::LogInitialInfoOnIOThread, this,
-          std::move(callback),
-          networks.has_value() ? *networks : net::NetworkInterfaceList()));
-}
-
-void WebRtcTextLogHandler::LogInitialInfoOnIOThread(
-    const GenericDoneCallback& callback,
-    const net::NetworkInterfaceList& network_list) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (logging_state_ != STARTING || channel_is_closing_) {
     FireGenericDoneCallback(callback, false, "Logging cancelled.");
@@ -531,6 +536,9 @@
       audio_manager ? audio_manager->GetName() : "Out of process"));
 
   // Network interfaces
+  const net::NetworkInterfaceList empty_network_list;
+  const net::NetworkInterfaceList& network_list =
+      networks.has_value() ? *networks : empty_network_list;
   LogToCircularBuffer("Discovered " +
                       base::NumberToString(network_list.size()) +
                       " network interfaces:");
@@ -548,6 +556,15 @@
   // renderer to start logging here, but for the time being
   // WebRtcLoggingHandlerHost::StartLogging will be responsible for sending
   // that IPC message.
-  content::WebRtcLog::SetLogMessageCallback(
-      render_process_id_, base::Bind(&WebRtcTextLogHandler::LogMessage, this));
+
+  // TODO(darin): Change SetLogMessageCallback to run on the UI thread.
+
+  auto log_message_callback = base::Bind(
+      &ForwardMessageViaTaskRunner, base::SequencedTaskRunnerHandle::Get(),
+      base::Bind(&WebRtcTextLogHandler::LogMessage,
+                 weak_factory_.GetWeakPtr()));
+  base::PostTaskWithTraits(
+      FROM_HERE, {content::BrowserThread::IO},
+      base::BindOnce(&content::WebRtcLog::SetLogMessageCallback,
+                     render_process_id_, std::move(log_message_callback)));
 }
diff --git a/chrome/browser/media/webrtc/webrtc_text_log_handler.h b/chrome/browser/media/webrtc/webrtc_text_log_handler.h
index 23d66812..0076aa2 100644
--- a/chrome/browser/media/webrtc/webrtc_text_log_handler.h
+++ b/chrome/browser/media/webrtc/webrtc_text_log_handler.h
@@ -10,11 +10,17 @@
 #include <string>
 
 #include "base/callback.h"
-#include "base/threading/thread_checker.h"
-#include "chrome/common/media/webrtc_logging_message_data.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
 #include "components/webrtc_logging/common/partial_circular_buffer.h"
 #include "net/base/network_interfaces.h"
 
+namespace chrome {
+namespace mojom {
+class WebRtcLoggingMessage;
+}  // namespace mojom
+}  // namespace chrome
+
 #if defined(OS_ANDROID)
 const size_t kWebRtcLogSize = 1 * 1024 * 1024;  // 1 MB
 #else
@@ -46,14 +52,13 @@
   void SetComplete();
 
  private:
-  base::ThreadChecker thread_checker_;
+  SEQUENCE_CHECKER(sequence_checker_);
   uint8_t buffer_[kWebRtcLogSize];
   webrtc_logging::PartialCircularBuffer circular_;
   bool read_only_;
 };
 
-class WebRtcTextLogHandler
-    : public base::RefCountedThreadSafe<WebRtcTextLogHandler> {
+class WebRtcTextLogHandler {
  public:
   // States used for protecting from function calls made at non-allowed points
   // in time. For example, StartLogging() is only allowed in CLOSED state.
@@ -77,6 +82,7 @@
   typedef base::Callback<void(bool, const std::string&)> GenericDoneCallback;
 
   explicit WebRtcTextLogHandler(int render_process_id);
+  ~WebRtcTextLogHandler();
 
   // Returns the current state of the log. Must be called on the IO thread.
   LoggingState GetState() const;
@@ -123,7 +129,8 @@
   void LogMessage(const std::string& message);
 
   // Adds a message to the log. Must be called on the IO thread.
-  void LogWebRtcLoggingMessageData(const WebRtcLoggingMessageData& message);
+  void LogWebRtcLoggingMessage(
+      const chrome::mojom::WebRtcLoggingMessage* message);
 
   // Returns true if the logging state is CLOSED and fires an the callback
   // with an error message otherwise. Must be called on the IO thread.
@@ -137,21 +144,15 @@
   void SetWebAppId(int web_app_id);
 
  private:
-  friend class base::RefCountedThreadSafe<WebRtcTextLogHandler>;
-  ~WebRtcTextLogHandler();
-
   void StartDone(const GenericDoneCallback& callback);
 
   void LogToCircularBuffer(const std::string& message);
 
-  void GetNetworkInterfaceListOnUIThread(const GenericDoneCallback& callback);
-
   void OnGetNetworkInterfaceList(
       const GenericDoneCallback& callback,
       const base::Optional<net::NetworkInterfaceList>& networks);
 
-  void LogInitialInfoOnIOThread(const GenericDoneCallback& callback,
-                                const net::NetworkInterfaceList& network_list);
+  SEQUENCE_CHECKER(sequence_checker_);
 
   // The render process ID this object belongs to.
   const int render_process_id_;
@@ -186,6 +187,8 @@
   // thread.
   int web_app_id_ = 0;
 
+  base::WeakPtrFactory<WebRtcTextLogHandler> weak_factory_{this};
+
   DISALLOW_COPY_AND_ASSIGN(WebRtcTextLogHandler);
 };
 
diff --git a/chrome/browser/notifications/scheduler/internal/background_task_coordinator.cc b/chrome/browser/notifications/scheduler/internal/background_task_coordinator.cc
index 06df21db..88d22a4 100644
--- a/chrome/browser/notifications/scheduler/internal/background_task_coordinator.cc
+++ b/chrome/browser/notifications/scheduler/internal/background_task_coordinator.cc
@@ -10,6 +10,7 @@
 #include "base/command_line.h"
 #include "base/numerics/ranges.h"
 #include "base/optional.h"
+#include "base/rand_util.h"
 #include "base/time/clock.h"
 #include "chrome/browser/notifications/scheduler/internal/impression_types.h"
 #include "chrome/browser/notifications/scheduler/internal/scheduler_config.h"
@@ -25,8 +26,12 @@
   BackgroundTaskCoordinatorHelper(
       NotificationBackgroundTaskScheduler* background_task,
       const SchedulerConfig* config,
+      BackgroundTaskCoordinator::TimeRandomizer time_randomizer,
       base::Clock* clock)
-      : background_task_(background_task), config_(config), clock_(clock) {}
+      : background_task_(background_task),
+        config_(config),
+        time_randomizer_(time_randomizer),
+        clock_(clock) {}
   ~BackgroundTaskCoordinatorHelper() = default;
 
   void ScheduleBackgroundTask(
@@ -153,13 +158,22 @@
       return;
     }
 
+    // Adds a randomized time delta to distribute the click loads.
+    // TODO(xingliu): Maybe show notifications one by one and spread into a time
+    // window.  See https://crbug.com/986614
+    base::TimeDelta random_interval;
+    if (task_start_time != SchedulerTaskTime::kUnknown)
+      random_interval = time_randomizer_.Run();
+
     background_task_->Schedule(
-        task_start_time, window_start_time,
-        window_start_time + config_->background_task_window_duration);
+        task_start_time, window_start_time + random_interval,
+        window_start_time + config_->background_task_window_duration +
+            random_interval);
   }
 
   NotificationBackgroundTaskScheduler* background_task_;
   const SchedulerConfig* config_;
+  BackgroundTaskCoordinator::TimeRandomizer time_randomizer_;
   base::Clock* clock_;
   base::Optional<base::Time> background_task_time_;
 
@@ -168,12 +182,20 @@
 
 }  // namespace
 
+// static
+base::TimeDelta BackgroundTaskCoordinator::DefaultTimeRandomizer(
+    const base::TimeDelta& time_window) {
+  return base::RandDouble() * time_window;
+}
+
 BackgroundTaskCoordinator::BackgroundTaskCoordinator(
     std::unique_ptr<NotificationBackgroundTaskScheduler> background_task,
     const SchedulerConfig* config,
+    TimeRandomizer time_randomizer,
     base::Clock* clock)
     : background_task_(std::move(background_task)),
       config_(config),
+      time_randomizer_(time_randomizer),
       clock_(clock) {}
 
 BackgroundTaskCoordinator::~BackgroundTaskCoordinator() = default;
@@ -183,7 +205,7 @@
     ClientStates client_states,
     SchedulerTaskTime task_start_time) {
   auto helper = std::make_unique<BackgroundTaskCoordinatorHelper>(
-      background_task_.get(), config_, clock_);
+      background_task_.get(), config_, time_randomizer_, clock_);
   helper->ScheduleBackgroundTask(std::move(notifications),
                                  std::move(client_states), task_start_time);
 }
diff --git a/chrome/browser/notifications/scheduler/internal/background_task_coordinator.h b/chrome/browser/notifications/scheduler/internal/background_task_coordinator.h
index f2001d2..ebf158a 100644
--- a/chrome/browser/notifications/scheduler/internal/background_task_coordinator.h
+++ b/chrome/browser/notifications/scheduler/internal/background_task_coordinator.h
@@ -9,6 +9,7 @@
 #include <memory>
 #include <vector>
 
+#include "base/callback.h"
 #include "base/macros.h"
 #include "chrome/browser/notifications/scheduler/public/notification_scheduler_types.h"
 
@@ -30,9 +31,13 @@
   using Notifications =
       std::map<SchedulerClientType, std::vector<const NotificationEntry*>>;
   using ClientStates = std::map<SchedulerClientType, const ClientState*>;
+  using TimeRandomizer = base::RepeatingCallback<base::TimeDelta()>;
+  static base::TimeDelta DefaultTimeRandomizer(
+      const base::TimeDelta& time_window);
   BackgroundTaskCoordinator(
       std::unique_ptr<NotificationBackgroundTaskScheduler> background_task,
       const SchedulerConfig* config,
+      TimeRandomizer time_randomizer,
       base::Clock* clock);
   virtual ~BackgroundTaskCoordinator();
 
@@ -48,6 +53,10 @@
   // System configuration.
   const SchedulerConfig* config_;
 
+  // Randomize the time to show the notification, to avoid large number of users
+  // to perform actions at the same time.
+  TimeRandomizer time_randomizer_;
+
   // Clock to query the current timestamp.
   base::Clock* clock_;
 
diff --git a/chrome/browser/notifications/scheduler/internal/background_task_coordinator_unittest.cc b/chrome/browser/notifications/scheduler/internal/background_task_coordinator_unittest.cc
index a4199ba9..79afb08 100644
--- a/chrome/browser/notifications/scheduler/internal/background_task_coordinator_unittest.cc
+++ b/chrome/browser/notifications/scheduler/internal/background_task_coordinator_unittest.cc
@@ -9,6 +9,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/bind.h"
 #include "base/test/scoped_task_environment.h"
 #include "chrome/browser/notifications/scheduler/internal/notification_entry.h"
 #include "chrome/browser/notifications/scheduler/internal/scheduler_config.h"
@@ -58,6 +59,10 @@
   DISALLOW_COPY_AND_ASSIGN(MockNotificationBackgroundTaskScheduler);
 };
 
+base::TimeDelta NoopTimeRandomizer(const base::TimeDelta& time_window) {
+  return base::TimeDelta();
+}
+
 struct TestData {
   // Impression data as the input.
   std::vector<test::ImpressionTestData> impression_test_data;
@@ -87,7 +92,8 @@
         std::make_unique<MockNotificationBackgroundTaskScheduler>();
     background_task_ = background_task.get();
     coordinator_ = std::make_unique<BackgroundTaskCoordinator>(
-        std::move(background_task), &config_, &clock_);
+        std::move(background_task), &config_,
+        base::BindRepeating(&NoopTimeRandomizer, base::TimeDelta()), &clock_);
   }
 
   MockNotificationBackgroundTaskScheduler* background_task() {
@@ -336,5 +342,15 @@
   TestScheduleNewNotification("04/25/20 18:30:00 PM", "04/26/20 06:00:00 AM");
 }
 
+// Test to verify the default time randomizer.
+TEST_F(BackgroundTaskCoordinatorTest, DefaultTimeRandomizer) {
+  EXPECT_EQ(BackgroundTaskCoordinator::DefaultTimeRandomizer(base::TimeDelta()),
+            base::TimeDelta());
+  auto time_window = base::TimeDelta::FromHours(1);
+  auto delta = BackgroundTaskCoordinator::DefaultTimeRandomizer(time_window);
+  EXPECT_LT(delta, time_window);
+  EXPECT_GE(delta, base::TimeDelta());
+}
+
 }  // namespace
 }  // namespace notifications
diff --git a/chrome/browser/notifications/scheduler/internal/notification_scheduler_context.cc b/chrome/browser/notifications/scheduler/internal/notification_scheduler_context.cc
index 196d864..91bfadf 100644
--- a/chrome/browser/notifications/scheduler/internal/notification_scheduler_context.cc
+++ b/chrome/browser/notifications/scheduler/internal/notification_scheduler_context.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <utility>
 
+#include "base/bind.h"
 #include "base/time/default_clock.h"
 #include "chrome/browser/notifications/scheduler/internal/background_task_coordinator.h"
 #include "chrome/browser/notifications/scheduler/internal/display_decider.h"
@@ -37,6 +38,8 @@
       background_task_coordinator_(std::make_unique<BackgroundTaskCoordinator>(
           std::move(background_task),
           config_.get(),
+          base::BindRepeating(&BackgroundTaskCoordinator::DefaultTimeRandomizer,
+                              config_->background_task_random_time_window),
           base::DefaultClock::GetInstance())) {}
 
 NotificationSchedulerContext::~NotificationSchedulerContext() = default;
diff --git a/chrome/browser/notifications/scheduler/internal/scheduler_config.cc b/chrome/browser/notifications/scheduler/internal/scheduler_config.cc
index 7af43bd..db76711 100644
--- a/chrome/browser/notifications/scheduler/internal/scheduler_config.cc
+++ b/chrome/browser/notifications/scheduler/internal/scheduler_config.cc
@@ -32,6 +32,10 @@
 constexpr base::TimeDelta kDefaultBackgroundTaskWindowDuration =
     base::TimeDelta::FromHours(1);
 
+// Default randomized time window to distribute load from user actions.
+constexpr base::TimeDelta kDefaultBackgroundTaskRandomTimeWindow =
+    base::TimeDelta::FromHours(1);
+
 // static
 std::unique_ptr<SchedulerConfig> SchedulerConfig::Create() {
   return std::make_unique<SchedulerConfig>();
@@ -48,7 +52,9 @@
       dismiss_duration(kDefaultDimissDuration),
       morning_task_hour(kDefaultMorningTaskHour),
       evening_task_hour(kDefaultEveningTaskHour),
-      background_task_window_duration(kDefaultBackgroundTaskWindowDuration) {
+      background_task_window_duration(kDefaultBackgroundTaskWindowDuration),
+      background_task_random_time_window(
+          kDefaultBackgroundTaskRandomTimeWindow) {
   // TODO(xingliu): Add constructor using finch data.
 }
 
diff --git a/chrome/browser/notifications/scheduler/internal/scheduler_config.h b/chrome/browser/notifications/scheduler/internal/scheduler_config.h
index 0c23b106..6683791 100644
--- a/chrome/browser/notifications/scheduler/internal/scheduler_config.h
+++ b/chrome/browser/notifications/scheduler/internal/scheduler_config.h
@@ -60,6 +60,9 @@
   // The time window to launch the background task.
   base::TimeDelta background_task_window_duration;
 
+  // A random time delta to distribute the user clicks to a time window.
+  base::TimeDelta background_task_random_time_window;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(SchedulerConfig);
 };
diff --git a/chrome/browser/page_load_metrics/observers/data_saver_site_breakdown_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/data_saver_site_breakdown_metrics_observer_browsertest.cc
index 58303c8f..effe3c36 100644
--- a/chrome/browser/page_load_metrics/observers/data_saver_site_breakdown_metrics_observer_browsertest.cc
+++ b/chrome/browser/page_load_metrics/observers/data_saver_site_breakdown_metrics_observer_browsertest.cc
@@ -63,7 +63,8 @@
   void SetUp() override {
     scoped_feature_list_.InitWithFeaturesAndParameters(
         {{features::kLazyImageLoading,
-          {{"automatic-lazy-load-images-enabled", "true"}}}},
+          {{"automatic-lazy-load-images-enabled", "true"},
+           {"enable-lazy-load-images-metadata-fetch", "true"}}}},
         {});
     InProcessBrowserTest::SetUp();
   }
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
index a13ebccf..15efbdb 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
@@ -438,8 +438,16 @@
                                      0);
 }
 
+// TODO(crbug.com/986642): Flaky on Win.
+#if defined(OS_WIN)
+#define MAYBE_NoPaintForEmptyDocumentInChildFrame \
+  DISABLED_NoPaintForEmptyDocumentInChildFrame
+#else
+#define MAYBE_NoPaintForEmptyDocumentInChildFrame \
+  NoPaintForEmptyDocumentInChildFrame
+#endif
 IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTest,
-                       NoPaintForEmptyDocumentInChildFrame) {
+                       MAYBE_NoPaintForEmptyDocumentInChildFrame) {
   ASSERT_TRUE(embedded_test_server()->Start());
 
   GURL a_url(
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.h b/chrome/browser/password_manager/chrome_password_manager_client.h
index a996deb..be105b61 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.h
+++ b/chrome/browser/password_manager/chrome_password_manager_client.h
@@ -14,7 +14,7 @@
 #include "base/macros.h"
 #include "base/optional.h"
 #include "build/build_config.h"
-#include "components/autofill/content/common/autofill_driver.mojom.h"
+#include "components/autofill/content/common/mojom/autofill_driver.mojom.h"
 #include "components/password_manager/content/browser/content_credential_manager.h"
 #include "components/password_manager/content/browser/content_password_manager_driver_factory.h"
 #include "components/password_manager/core/browser/http_auth_manager.h"
diff --git a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
index c223948..82088d5f 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
@@ -26,7 +26,7 @@
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
-#include "components/autofill/content/common/autofill_agent.mojom.h"
+#include "components/autofill/content/common/mojom/autofill_agent.mojom.h"
 #include "components/autofill/core/browser/logging/log_manager.h"
 #include "components/autofill/core/browser/logging/log_receiver.h"
 #include "components/autofill/core/browser/logging/log_router.h"
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_third_party.js b/chrome/browser/resources/chromeos/assistant_optin/assistant_third_party.js
index 494d4bb1..fb8de8ca 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/assistant_third_party.js
+++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_third_party.js
@@ -73,7 +73,7 @@
    * @param {MouseEvent} e click event.
    */
   urlClickHandler: function(e) {
-    if (!e.target.localName == 'a') {
+    if (e.target.localName !== 'a') {
       return;
     }
     e.preventDefault();
diff --git a/chrome/browser/resources/chromeos/guest_session_tab.html b/chrome/browser/resources/chromeos/guest_session_tab.html
index 3940a24a..790d6a7a 100644
--- a/chrome/browser/resources/chromeos/guest_session_tab.html
+++ b/chrome/browser/resources/chromeos/guest_session_tab.html
@@ -6,12 +6,6 @@
 <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
 <link rel="stylesheet" href="../ntp4/incognito_and_guest_tab.css">
 <link rel="stylesheet" href="guest_session_tab.css">
-<script>
-// Until themes can clear the cache, force-reload the theme stylesheet.
-document.write('<link id="incognitothemecss" rel="stylesheet" ' +
-               'href="chrome://theme/css/incognito_new_tab_theme.css?' +
-               Date.now() + '">');
-</script>
 </head>
 <body>
 <div id="enterprise-info" visible="$i18n{enterpriseInfoVisible}">
@@ -29,10 +23,4 @@
   </p>
 </div>
 </body>
-<script>
-function themeChanged() {
-  document.getElementById('incognitothemecss').href =
-      'chrome://theme/css/incognito_new_tab_theme.css?' + Date.now();
-}
-</script>
 </html>
diff --git a/chrome/browser/resources/local_ntp/customize.js b/chrome/browser/resources/local_ntp/customize.js
index 04c40d2..8076a8b 100644
--- a/chrome/browser/resources/local_ntp/customize.js
+++ b/chrome/browser/resources/local_ntp/customize.js
@@ -1194,8 +1194,11 @@
     }
   }
 
-
-  $(customize.IDS.TILES).focus();
+  if (configData.richerPicker) {
+    $(customize.IDS.BACKGROUNDS_IMAGE_MENU).focus();
+  } else {
+    $(customize.IDS.TILES).focus();
+  }
 };
 
 /**
@@ -1871,7 +1874,12 @@
   richerPicker.onkeydown = function(event) {
     richerPicker.classList.remove(customize.CLASSES.MOUSE_NAV);
 
-    if (event.keyCode === customize.KEYCODES.ESC ||
+    if (event.keyCode === customize.KEYCODES.BACKSPACE &&
+        customize.richerPicker_selectedSubmenu.menu.id ===
+            customize.IDS.BACKGROUNDS_IMAGE_MENU) {
+      backInteraction(event);
+    } else if (
+        event.keyCode === customize.KEYCODES.ESC ||
         event.keyCode === customize.KEYCODES.BACKSPACE) {
       customize.richerPicker_cancelCustomization();
     }
diff --git a/chrome/browser/resources/local_ntp/local_ntp.css b/chrome/browser/resources/local_ntp/local_ntp.css
index 8b54a376..cfad34e 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.css
+++ b/chrome/browser/resources/local_ntp/local_ntp.css
@@ -995,7 +995,8 @@
   }
 }
 
-#backgrounds-menu {
+#backgrounds-menu,
+#colors-menu {
   /* Remove extra spacing between inline-block elements. */
   font-size: 0;
 }
@@ -1662,6 +1663,7 @@
 
 #colors-theme.visible {
   display: flex;
+  font-size: small;
 }
 
 #colors-theme > * {
diff --git a/chrome/browser/resources/local_ntp/most_visited_single.js b/chrome/browser/resources/local_ntp/most_visited_single.js
index 0545c31e..9c760d9 100644
--- a/chrome/browser/resources/local_ntp/most_visited_single.js
+++ b/chrome/browser/resources/local_ntp/most_visited_single.js
@@ -80,8 +80,6 @@
 const LOG_TYPE = {
   // All NTP tiles have finished loading (successfully or failing).
   NTP_ALL_TILES_LOADED: 11,
-  // Shortcuts have been customized.
-  NTP_SHORTCUT_CUSTOMIZED: 39,
   // The 'Add shortcut' link was clicked.
   NTP_CUSTOMIZE_ADD_SHORTCUT_CLICKED: 44,
   // The 'Edit shortcut' link was clicked.
@@ -792,12 +790,6 @@
     logEvent(LOG_TYPE.NTP_ALL_TILES_LOADED);
     let tilesAreCustomLinks = isCustomLinksEnabled() &&
         chrome.embeddedSearch.newTabPage.isCustomLinks;
-    // Note that it's easiest to capture this when all custom links are loaded,
-    // rather than when the impression for each link is logged.
-    if (tilesAreCustomLinks) {
-      chrome.embeddedSearch.newTabPage.logEvent(
-          LOG_TYPE.NTP_SHORTCUT_CUSTOMIZED);
-    }
     // Tell the parent page whether to show the restore default shortcuts option
     // in the menu.
     window.parent.postMessage(
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.html b/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.html
index 5c4aea1..cddf333 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.html
+++ b/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.html
@@ -84,8 +84,8 @@
         --ink-color: var(--menu-text-color);
         align-items: center;
         background: none;
-        border-radius: initial;
         border: none;
+        border-radius: initial;
         box-shadow: none;
         color: var(--menu-text-color);
         display: flex;
@@ -230,10 +230,10 @@
               $i18n{osLanguagesPageTitle}
             </div>
           </a>
-          <a href="/downloads">
+          <a href="/files">
             <div class="item">
               <iron-icon icon="cr:file-download"></iron-icon>
-              $i18n{downloadsPageTitle}
+              $i18n{filesPageTitle}
             </div>
           </a>
           <a href="/printing">
diff --git a/chrome/browser/resources/settings/printing_page/cups_printers_entry_list.html b/chrome/browser/resources/settings/printing_page/cups_printers_entry_list.html
index 31ff8a3..fdb85be 100644
--- a/chrome/browser/resources/settings/printing_page/cups_printers_entry_list.html
+++ b/chrome/browser/resources/settings/printing_page/cups_printers_entry_list.html
@@ -2,6 +2,7 @@
 
 <link rel="import" href="chrome://resources/html/list_property_update_behavior.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html">
+<link rel="import" href="cups_printer_dialog_util.html">
 <link rel="import" href="cups_printer_types.html">
 <link rel="import" href="cups_printers_browser_proxy.html">
 <link rel="import" href="cups_printers_entry.html">
diff --git a/chrome/browser/resources/settings/printing_page/cups_printers_entry_list.js b/chrome/browser/resources/settings/printing_page/cups_printers_entry_list.js
index 33c8cc0..6037c31a 100644
--- a/chrome/browser/resources/settings/printing_page/cups_printers_entry_list.js
+++ b/chrome/browser/resources/settings/printing_page/cups_printers_entry_list.js
@@ -59,6 +59,11 @@
             item =>this.matchesSearchTerm_(item.printerInfo,this.searchTerm)) :
         this.printers.slice();
 
+    updatedPrinters.sort((first, second) => {
+      return settings.printing.alphabeticalSort(
+          first.printerInfo, second.printerInfo);
+    });
+
     this.updateList('filteredPrinters_', printer => printer.printerInfo,
         updatedPrinters);
   },
diff --git a/chrome/browser/resources/settings/route.js b/chrome/browser/resources/settings/route.js
index 3a08faf7..808fc77 100644
--- a/chrome/browser/resources/settings/route.js
+++ b/chrome/browser/resources/settings/route.js
@@ -43,6 +43,7 @@
  *   EDIT_DICTIONARY: (undefined|!settings.Route),
  *   EXTERNAL_STORAGE_PREFERENCES: (undefined|!settings.Route),
  *   FINGERPRINT: (undefined|!settings.Route),
+ *   FILES: (undefined|!settings.Route),
  *   FONTS: (undefined|!settings.Route),
  *   GOOGLE_ASSISTANT: (undefined|!settings.Route),
  *   IMPORT_DATA: (undefined|!settings.Route),
@@ -257,12 +258,6 @@
     r.SMART_LOCK =
         r.MULTIDEVICE_FEATURES.createChild('/multidevice/features/smartLock');
 
-    // TODO(hsuregan): Remove once this file is forked.
-    if (loadTimeData.getBoolean('isOSSettings')) {
-      r.PERSONALIZATION =
-          r.BASIC.createSection('/personalization', 'personalization');
-      r.CHANGE_PICTURE = r.PERSONALIZATION.createChild('/changePicture');
-    }
     // </if>
 
     if (pageVisibility.appearance !== false) {
@@ -333,7 +328,11 @@
       // </if>
       // <if expr="chromeos">
       // TODO(crbug.com/950007): Remove when SplitSettings is the default.
-      if (!loadTimeData.getBoolean('isOSSettings')) {
+      if (loadTimeData.getBoolean('isOSSettings')) {
+        r.PERSONALIZATION =
+            r.BASIC.createSection('/personalization', 'personalization');
+        r.CHANGE_PICTURE = r.PERSONALIZATION.createChild('/changePicture');
+      } else {
         r.CHANGE_PICTURE = r.PEOPLE.createChild('/changePicture');
       }
       r.ACCOUNTS = r.PEOPLE.createChild('/accounts');
@@ -449,7 +448,14 @@
       if (pageVisibility.downloads !== false) {
         r.DOWNLOADS = r.ADVANCED.createSection('/downloads', 'downloads');
         // <if expr="chromeos">
-        r.SMB_SHARES = r.DOWNLOADS.createChild('/smbShares');
+        // TODO(crbug.com/950007): Make unconditional and remove 'else' block
+        //     when SplitSettings is the default.
+        if (loadTimeData.getBoolean('isOSSettings')) {
+          r.FILES = r.ADVANCED.createSection('/files', 'files');
+          r.SMB_SHARES = r.FILES.createChild('/smbShares');
+        } else {
+          r.SMB_SHARES = r.DOWNLOADS.createChild('/smbShares');
+        }
         // </if>
       }
 
diff --git a/chrome/browser/resources/webapks/about_webapks.js b/chrome/browser/resources/webapks/about_webapks.js
index e1627629..2e427eb4 100644
--- a/chrome/browser/resources/webapks/about_webapks.js
+++ b/chrome/browser/resources/webapks/about_webapks.js
@@ -19,6 +19,7 @@
  *   themeColor: string,
  *   backgroundColor: string,
  *   lastUpdateCheckTimeMs: number,
+ *   lastUpdateCompletionTimeMs: number,
  *   relaxUpdates: boolean,
  *   updateStatus: string,
  * }}
@@ -33,6 +34,8 @@
  */
 let UpdateStatus;
 
+const UPDATE_TIMEOUT = 60 * 1000;  // milliseconds.
+
 /**
  * Creates and returns an element (with |text| as content) assigning it the
  * |className| class.
@@ -81,12 +84,14 @@
  * attributes.
  * @param {string} text For the button.
  * @param {function()} callback Invoked on click.
+ * @return {Element} The button that was created.
  */
 function addWebApkButton(webApkList, text, callback) {
   const divElement =
       createElementWithTextAndClass(text, 'button', 'update-button');
   divElement.onclick = callback;
   webApkList.appendChild(divElement);
+  return divElement;
 }
 
 /**
@@ -121,6 +126,9 @@
       webApkList, 'Last Update Check Time: ',
       new Date(webApkInfo.lastUpdateCheckTimeMs).toString());
   addWebApkField(
+      webApkList, 'Last Update Completion Time: ',
+      new Date(webApkInfo.lastUpdateCompletionTimeMs).toString());
+  addWebApkField(
       webApkList, 'Check for Updates Less Frequently: ',
       webApkInfo.relaxUpdates.toString());
   addWebApkField(webApkList, 'Update Status: ', webApkInfo.updateStatus);
@@ -130,14 +138,24 @@
     return;
   }
 
-  addWebApkButton(webApkList, 'Update ' + webApkInfo.name, () => {
-    alert(
-        'The WebAPK will check for an update the next time it launches. ' +
-        'If an update is available, the "Update Status" on this page ' +
-        'will switch to "Scheduled". The update will be installed once ' +
-        'the WebAPK is closed (this may take a few minutes).');
-    chrome.send('requestWebApkUpdate', [webApkInfo.id]);
-  });
+  const buttonElement =
+      addWebApkButton(webApkList, 'Update ' + webApkInfo.name, () => {
+        alert(
+            'The WebAPK will check for an update the next time it launches. ' +
+            'If an update is available, the "Update Status" on this page ' +
+            'will switch to "Scheduled". The update will be installed once ' +
+            'the WebAPK is closed (this may take a few minutes).');
+        chrome.send('requestWebApkUpdate', [webApkInfo.id]);
+      });
+
+  // Prevent updates in the WebAPK server caching window as they will fail.
+  const msSinceLastUpdate = Date.now() - webApkInfo.lastUpdateCompletionTimeMs;
+  if (msSinceLastUpdate < UPDATE_TIMEOUT) {
+    buttonElement.disabled = true;
+    window.setTimeout(() => {
+      buttonElement.disabled = false;
+    }, UPDATE_TIMEOUT - msSinceLastUpdate);
+  }
 }
 
 document.addEventListener('DOMContentLoaded', function() {
diff --git a/chrome/browser/search/instant_service.cc b/chrome/browser/search/instant_service.cc
index 3f4e3dc4..d34cd2b 100644
--- a/chrome/browser/search/instant_service.cc
+++ b/chrome/browser/search/instant_service.cc
@@ -811,6 +811,17 @@
   return true;
 }
 
+bool InstantService::AreShortcutsCustomized() {
+  return most_visited_info_->items_are_custom_links;
+}
+
+std::pair<bool, bool> InstantService::GetCurrentShortcutSettings() {
+  bool using_most_visited =
+      pref_service_->GetBoolean(prefs::kNtpUseMostVisitedTiles);
+  bool is_visible = pref_service_->GetBoolean(prefs::kNtpShortcutsVisible);
+  return std::make_pair(using_most_visited, is_visible);
+}
+
 void InstantService::ResetToDefault() {
   ResetCustomLinks();
   ResetCustomBackgroundThemeInfo();
diff --git a/chrome/browser/search/instant_service.h b/chrome/browser/search/instant_service.h
index dc51f7ca..9cf98e2 100644
--- a/chrome/browser/search/instant_service.h
+++ b/chrome/browser/search/instant_service.h
@@ -156,6 +156,16 @@
   // Check if a custom background has been set by the user.
   bool IsCustomBackgroundSet();
 
+  // Returns whether the user has customized their shortcuts. Will always be
+  // false if Most Visited shortcuts are enabled.
+  bool AreShortcutsCustomized();
+
+  // Returns the current shortcut settings as a pair consisting of shortcut type
+  // (i.e. true if Most Visited, false if custom links) and visibility. These
+  // correspond to values stored in |kNtpUseMostVisitedTiles| and
+  // |kNtpShortcutsVisible| respectively.
+  std::pair<bool, bool> GetCurrentShortcutSettings();
+
   // Reset all NTP customizations to default. Marked virtual for mocking in
   // tests.
   virtual void ResetToDefault();
diff --git a/chrome/browser/themes/browser_theme_pack.cc b/chrome/browser/themes/browser_theme_pack.cc
index 7c534e9..b310e92 100644
--- a/chrome/browser/themes/browser_theme_pack.cc
+++ b/chrome/browser/themes/browser_theme_pack.cc
@@ -14,6 +14,7 @@
 #include "base/containers/flat_set.h"
 #include "base/files/file.h"
 #include "base/memory/ref_counted_memory.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/no_destructor.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
@@ -760,6 +761,8 @@
 void BrowserThemePack::BuildFromColor(SkColor color, BrowserThemePack* pack) {
   DCHECK(!pack->is_valid());
 
+  SCOPED_UMA_HISTOGRAM_TIMER("AutogeneratedTheme.ColorGenerationTime");
+
   pack->InitEmptyPack();
 
   // Init |source_images_| only here as other code paths initialize it
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 4db6d86e..4296454 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -3400,6 +3400,8 @@
       "app_list/search/common/url_icon_source.h",
       "app_list/search/extension_app_result.cc",
       "app_list/search/extension_app_result.h",
+      "app_list/search/logging/search_ranking_event_logger.cc",
+      "app_list/search/logging/search_ranking_event_logger.h",
       "app_list/search/mixer.cc",
       "app_list/search/mixer.h",
       "app_list/search/omnibox_provider.cc",
diff --git a/chrome/browser/ui/app_list/app_list_client_impl.cc b/chrome/browser/ui/app_list/app_list_client_impl.cc
index 3216d4e..e234b828 100644
--- a/chrome/browser/ui/app_list/app_list_client_impl.cc
+++ b/chrome/browser/ui/app_list/app_list_client_impl.cc
@@ -517,6 +517,13 @@
     DismissView();
 }
 
+void AppListClientImpl::NotifySearchResultsForLogging(
+    const base::string16& trimmed_query,
+    const ash::SearchResultIdWithPositionIndices& results,
+    int position_index) {
+  search_ranking_event_logger_.Log(trimmed_query, results, position_index);
+}
+
 ash::ShelfLaunchSource AppListClientImpl::AppListSourceToLaunchSource(
     AppListSource source) {
   switch (source) {
diff --git a/chrome/browser/ui/app_list/app_list_client_impl.h b/chrome/browser/ui/app_list/app_list_client_impl.h
index b1725b3..cc463bd 100644
--- a/chrome/browser/ui/app_list/app_list_client_impl.h
+++ b/chrome/browser/ui/app_list/app_list_client_impl.h
@@ -7,8 +7,11 @@
 
 #include <stdint.h>
 
+#include <map>
 #include <memory>
 #include <string>
+#include <utility>
+#include <vector>
 
 #include "ash/public/cpp/app_list/app_list_client.h"
 #include "ash/public/cpp/shelf_types.h"
@@ -19,6 +22,7 @@
 #include "base/scoped_observer.h"
 #include "chrome/browser/ui/app_list/app_launch_event_logger.h"
 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
+#include "chrome/browser/ui/app_list/search/logging/search_ranking_event_logger.h"
 #include "components/search_engines/template_url_service.h"
 #include "components/search_engines/template_url_service_observer.h"
 #include "components/user_manager/user_manager.h"
@@ -84,6 +88,10 @@
       override;
   void OnSearchResultVisibilityChanged(const std::string& id,
                                        bool visible) override;
+  void NotifySearchResultsForLogging(
+      const base::string16& trimmed_query,
+      const ash::SearchResultIdWithPositionIndices& results,
+      int position_index) override;
 
   // user_manager::UserManager::UserSessionStateObserver:
   void ActiveUserChanged(const user_manager::User* active_user) override;
@@ -185,6 +193,7 @@
   bool app_list_visible_ = false;
 
   app_list::AppLaunchEventLogger app_launch_event_logger_;
+  app_list::SearchRankingEventLogger search_ranking_event_logger_;
 
   base::WeakPtrFactory<AppListClientImpl> weak_ptr_factory_{this};
 
diff --git a/chrome/browser/ui/app_list/search/logging/search_ranking_event_logger.cc b/chrome/browser/ui/app_list/search/logging/search_ranking_event_logger.cc
new file mode 100644
index 0000000..1475d34
--- /dev/null
+++ b/chrome/browser/ui/app_list/search/logging/search_ranking_event_logger.cc
@@ -0,0 +1,34 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/logging.h"
+#include "chrome/browser/ui/app_list/search/logging/search_ranking_event_logger.h"
+
+namespace app_list {
+
+SearchRankingEventLogger::SearchRankingEventLogger() {}
+SearchRankingEventLogger::~SearchRankingEventLogger() = default;
+
+void SearchRankingEventLogger::Log(
+    const base::string16& trimmed_query,
+    const ash::SearchResultIdWithPositionIndices& search_results,
+    int position_index) {
+  if (trimmed_query.empty()) {
+    LogSuggestedZeroStateItems(search_results, position_index);
+  } else {
+    // TODO(crbug.com/972817): Add the logics for query-based events.
+  }
+}
+
+void SearchRankingEventLogger::LogSuggestedZeroStateItems(
+    const ash::SearchResultIdWithPositionIndices& search_results,
+    int position_index) {
+  // TODO(crbug.com/972817): Add the logics to log the suggested items.
+}
+
+}  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/logging/search_ranking_event_logger.h b/chrome/browser/ui/app_list/search/logging/search_ranking_event_logger.h
new file mode 100644
index 0000000..c690681b
--- /dev/null
+++ b/chrome/browser/ui/app_list/search/logging/search_ranking_event_logger.h
@@ -0,0 +1,42 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_APP_LIST_SEARCH_LOGGING_SEARCH_RANKING_EVENT_LOGGER_H_
+#define CHROME_BROWSER_UI_APP_LIST_SEARCH_LOGGING_SEARCH_RANKING_EVENT_LOGGER_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "ash/public/cpp/app_list/app_list_types.h"
+#include "base/logging.h"
+#include "base/time/time.h"
+
+namespace app_list {
+
+class SearchRankingEventLogger {
+ public:
+  SearchRankingEventLogger();
+  ~SearchRankingEventLogger();
+  // Called if a search result item got clicked, or a list of search result has
+  // been shown to the user after a certain amount of time. |raw_query| is the
+  // raw query that produced the results, |results| is a list of items that were
+  // being shown to the users and their corresponding position indices of them
+  // (see |SearchResultIdWithPositionIndex| for more details),
+  // |position_index| is the position index of the clicked item (if no item got
+  // clicked, |position_index| will be -1).
+  void Log(const base::string16& trimmed_query,
+           const ash::SearchResultIdWithPositionIndices& search_results,
+           int position_index);
+
+ private:
+  // Logs suggested items either from impressions or from click events.
+  void LogSuggestedZeroStateItems(
+      const ash::SearchResultIdWithPositionIndices& search_results,
+      int position_index);
+};
+
+}  // namespace app_list
+
+#endif  // CHROME_BROWSER_UI_APP_LIST_SEARCH_LOGGING_SEARCH_RANKING_EVENT_LOGGER_H_
diff --git a/chrome/browser/ui/bookmarks/bookmark_drag_drop.h b/chrome/browser/ui/bookmarks/bookmark_drag_drop.h
index fcf9b05..28c92a7 100644
--- a/chrome/browser/ui/bookmarks/bookmark_drag_drop.h
+++ b/chrome/browser/ui/bookmarks/bookmark_drag_drop.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_DRAG_DROP_H_
 #define CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_DRAG_DROP_H_
 
+#include <memory>
 #include <vector>
 
 #include "build/build_config.h"
diff --git a/chrome/browser/ui/search/ntp_user_data_logger.cc b/chrome/browser/ui/search/ntp_user_data_logger.cc
index eaaa481..5c7104d 100644
--- a/chrome/browser/ui/search/ntp_user_data_logger.cc
+++ b/chrome/browser/ui/search/ntp_user_data_logger.cc
@@ -87,19 +87,38 @@
   VOICE_ERROR_MAX
 };
 
-// Logs BackgroundCustomization availability on the NTP,
+// Logs BackgroundCustomization availability on the NTP.
 void LogBackgroundCustomizationAvailability(
     BackgroundCustomization availability) {
   UMA_HISTOGRAM_ENUMERATION("NewTabPage.CustomizationAvailability.Backgrounds",
                             availability);
 }
 
-// Logs ShortcutCustomization availability on the NTP,
+// Logs ShortcutCustomization availability on the NTP.
 void LogShortcutCustomizationAvailability(ShortcutCustomization availability) {
   UMA_HISTOGRAM_ENUMERATION("NewTabPage.CustomizationAvailability.Shortcuts",
                             availability);
 }
 
+// Logs CustomizedShortcutSettings on the NTP.
+void LogCustomizedShortcutSettings(std::pair<bool, bool> settings) {
+  bool using_most_visited = settings.first;
+  bool is_visible = settings.second;
+
+  CustomizedShortcutSettings setting;
+  if (is_visible && using_most_visited) {
+    setting =
+        CustomizedShortcutSettings::CUSTOMIZED_SHORTCUT_SETTINGS_MOST_VISITED;
+  } else if (is_visible && !using_most_visited) {
+    setting =
+        CustomizedShortcutSettings::CUSTOMIZED_SHORTCUT_SETTINGS_CUSTOM_LINKS;
+  } else {
+    setting = CustomizedShortcutSettings::CUSTOMIZED_SHORTCUT_SETTINGS_HIDDEN;
+  }
+
+  UMA_HISTOGRAM_ENUMERATION("NewTabPage.CustomizedShortcuts", setting);
+}
+
 // Converts |NTPLoggingEventType| to a |CustomizedFeature|.
 CustomizedFeature LoggingEventToCustomizedFeature(NTPLoggingEventType event) {
   switch (event) {
@@ -202,6 +221,11 @@
       return CustomizeShortcutAction::CUSTOMIZE_SHORTCUT_ACTION_UNDO;
     case NTP_CUSTOMIZE_SHORTCUT_RESTORE_ALL:
       return CustomizeShortcutAction::CUSTOMIZE_SHORTCUT_ACTION_RESTORE_ALL;
+    case NTP_CUSTOMIZE_SHORTCUT_TOGGLE_TYPE:
+      return CustomizeShortcutAction::CUSTOMIZE_SHORTCUT_ACTION_TOGGLE_TYPE;
+    case NTP_CUSTOMIZE_SHORTCUT_TOGGLE_VISIBILITY:
+      return CustomizeShortcutAction::
+          CUSTOMIZE_SHORTCUT_ACTION_TOGGLE_VISIBILITY;
     default:
       break;
   }
@@ -422,6 +446,8 @@
     case NTP_CUSTOMIZE_SHORTCUT_DONE:
     case NTP_CUSTOMIZE_SHORTCUT_UNDO:
     case NTP_CUSTOMIZE_SHORTCUT_RESTORE_ALL:
+    case NTP_CUSTOMIZE_SHORTCUT_TOGGLE_TYPE:
+    case NTP_CUSTOMIZE_SHORTCUT_TOGGLE_VISIBILITY:
       UMA_HISTOGRAM_ENUMERATION("NewTabPage.CustomizeShortcutAction",
                                 LoggingEventToCustomizeShortcutAction(event));
       break;
@@ -507,6 +533,18 @@
   return instant_service->IsCustomBackgroundSet();
 }
 
+bool NTPUserDataLogger::AreShortcutsCustomized() const {
+  InstantService* instant_service =
+      InstantServiceFactory::GetForProfile(profile_);
+  return instant_service->AreShortcutsCustomized();
+}
+
+std::pair<bool, bool> NTPUserDataLogger::GetCurrentShortcutSettings() const {
+  InstantService* instant_service =
+      InstantServiceFactory::GetForProfile(profile_);
+  return instant_service->GetCurrentShortcutSettings();
+}
+
 void NTPUserDataLogger::EmitNtpStatistics(base::TimeDelta load_time) {
   // We only send statistics once per page.
   if (has_emitted_) {
@@ -575,26 +613,29 @@
     LogBackgroundCustomizationAvailability(
         BackgroundCustomization::
             BACKGROUND_CUSTOMIZATION_UNAVAILABLE_SEARCH_PROVIDER);
-  } else {
-    LogBackgroundCustomizationAvailability(
-        BackgroundCustomization::BACKGROUND_CUSTOMIZATION_AVAILABLE);
-  }
-
-  if (!is_google) {
-    // TODO(crbug.com/869931): This is only emitted upon search engine change.
     LogShortcutCustomizationAvailability(
         ShortcutCustomization::
             SHORTCUT_CUSTOMIZATION_UNAVAILABLE_SEARCH_PROVIDER);
   } else {
+    LogBackgroundCustomizationAvailability(
+        BackgroundCustomization::BACKGROUND_CUSTOMIZATION_AVAILABLE);
     LogShortcutCustomizationAvailability(
         ShortcutCustomization::SHORTCUT_CUSTOMIZATION_AVAILABLE);
+    LogCustomizedShortcutSettings(GetCurrentShortcutSettings());
+
+    if (AreShortcutsCustomized()) {
+      UMA_HISTOGRAM_ENUMERATION(
+          "NewTabPage.Customized",
+          LoggingEventToCustomizedFeature(NTP_SHORTCUT_CUSTOMIZED));
+    }
+
+    if (CustomBackgroundIsConfigured()) {
+      UMA_HISTOGRAM_ENUMERATION(
+          "NewTabPage.Customized",
+          LoggingEventToCustomizedFeature(NTP_BACKGROUND_CUSTOMIZED));
+    }
   }
 
-  if (CustomBackgroundIsConfigured()) {
-    UMA_HISTOGRAM_ENUMERATION(
-        "NewTabPage.Customized",
-        LoggingEventToCustomizedFeature(NTP_BACKGROUND_CUSTOMIZED));
-  }
   has_emitted_ = true;
   during_startup_ = false;
 }
diff --git a/chrome/browser/ui/search/ntp_user_data_logger.h b/chrome/browser/ui/search/ntp_user_data_logger.h
index 538e683..11c9a2e1 100644
--- a/chrome/browser/ui/search/ntp_user_data_logger.h
+++ b/chrome/browser/ui/search/ntp_user_data_logger.h
@@ -92,6 +92,13 @@
   // Returns whether a custom background is configured. Virtual for testing.
   virtual bool CustomBackgroundIsConfigured() const;
 
+  // Returns whether the user has customized their shortcuts. Will always be
+  // false if Most Visited shortcuts are enabled. Virtual for testing.
+  virtual bool AreShortcutsCustomized() const;
+
+  // Returns the current user shortcut settings. Virtual for testing.
+  virtual std::pair<bool, bool> GetCurrentShortcutSettings() const;
+
   // Logs a number of statistics regarding the NTP. Called when an NTP tab is
   // about to be deactivated (be it by switching tabs, losing focus or closing
   // the tab/shutting down Chrome), or when the user navigates to a URL.
diff --git a/chrome/browser/ui/search/ntp_user_data_logger_unittest.cc b/chrome/browser/ui/search/ntp_user_data_logger_unittest.cc
index fdaea20..47b276f 100644
--- a/chrome/browser/ui/search/ntp_user_data_logger_unittest.cc
+++ b/chrome/browser/ui/search/ntp_user_data_logger_unittest.cc
@@ -81,8 +81,19 @@
     return is_custom_background_configured_;
   }
 
-  bool is_google_ = true;
+  bool AreShortcutsCustomized() const override {
+    return are_shortcuts_customized_;
+  }
+
+  std::pair<bool, bool> GetCurrentShortcutSettings() const override {
+    return std::make_pair(using_most_visited_, is_visible_);
+  }
+
+  bool are_shortcuts_customized_ = false;
   bool is_custom_background_configured_ = false;
+  bool is_google_ = true;
+  bool is_visible_ = true;
+  bool using_most_visited_ = true;
 };
 
 using NTPUserDataLoggerTest = testing::Test;
@@ -812,7 +823,7 @@
                   /*count=*/1)));
 }
 
-TEST_F(NTPUserDataLoggerTest, ShouldRecordBackgroundCustomization) {
+TEST_F(NTPUserDataLoggerTest, ShouldRecordBackgroundIsCustomized) {
   base::HistogramTester histogram_tester;
 
   TestNTPUserDataLogger logger((GURL(chrome::kChromeSearchLocalNtpUrl)));
@@ -857,6 +868,78 @@
           1)));
 }
 
+TEST_F(NTPUserDataLoggerTest, ShouldRecordShortcutsAreCustomizedFromNTPGoogle) {
+  base::HistogramTester histogram_tester;
+
+  TestNTPUserDataLogger logger((GURL(chrome::kChromeSearchLocalNtpUrl)));
+  logger.is_google_ = true;
+  logger.are_shortcuts_customized_ = true;
+
+  base::TimeDelta delta_tiles_loaded = base::TimeDelta::FromMilliseconds(100);
+
+  // Send the ALL_TILES_LOADED event, this should trigger emitting histograms.
+  logger.LogEvent(NTP_ALL_TILES_LOADED, delta_tiles_loaded);
+
+  EXPECT_THAT(
+      histogram_tester.GetAllSamples("NewTabPage.Customized"),
+      ElementsAre(Bucket(
+          static_cast<int>(CustomizedFeature::CUSTOMIZED_FEATURE_SHORTCUT),
+          1)));
+}
+
+TEST_F(NTPUserDataLoggerTest,
+       ShouldNotRecordShortcutsAreCustomizedFromNTPOther) {
+  base::HistogramTester histogram_tester;
+
+  TestNTPUserDataLogger logger(GURL("https://www.notgoogle.com/newtab"));
+  logger.is_google_ = false;
+  logger.are_shortcuts_customized_ = true;
+
+  base::TimeDelta delta_tiles_loaded = base::TimeDelta::FromMilliseconds(100);
+
+  // Send the ALL_TILES_LOADED event, this should trigger emitting histograms.
+  logger.LogEvent(NTP_ALL_TILES_LOADED, delta_tiles_loaded);
+
+  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.Customized"),
+              IsEmpty());
+}
+
+TEST_F(NTPUserDataLoggerTest,
+       ShouldRecordCustomizedShortcutSettingsFromNTPGoogle) {
+  base::HistogramTester histogram_tester;
+
+  TestNTPUserDataLogger logger((GURL(chrome::kChromeSearchLocalNtpUrl)));
+  logger.is_google_ = true;
+
+  base::TimeDelta delta_tiles_loaded = base::TimeDelta::FromMilliseconds(100);
+
+  // Send the ALL_TILES_LOADED event, this should trigger emitting histograms.
+  logger.LogEvent(NTP_ALL_TILES_LOADED, delta_tiles_loaded);
+
+  EXPECT_THAT(
+      histogram_tester.GetAllSamples("NewTabPage.CustomizedShortcuts"),
+      ElementsAre(Bucket(
+          static_cast<int>(CustomizedShortcutSettings::
+                               CUSTOMIZED_SHORTCUT_SETTINGS_MOST_VISITED),
+          1)));
+}
+
+TEST_F(NTPUserDataLoggerTest,
+       ShouldNotRecordCustomizedShortcutSettingsFromNTPOther) {
+  base::HistogramTester histogram_tester;
+
+  TestNTPUserDataLogger logger(GURL("https://www.notgoogle.com/newtab"));
+  logger.is_google_ = false;
+
+  base::TimeDelta delta_tiles_loaded = base::TimeDelta::FromMilliseconds(100);
+
+  // Send the ALL_TILES_LOADED event, this should trigger emitting histograms.
+  logger.LogEvent(NTP_ALL_TILES_LOADED, delta_tiles_loaded);
+
+  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.CustomizedShortcuts"),
+              IsEmpty());
+}
+
 TEST_F(NTPUserDataLoggerTest, ShouldRecordCustomizationActionFromNTPGoogle) {
   base::HistogramTester histogram_tester;
 
diff --git a/chrome/browser/ui/search/ntp_user_data_types.h b/chrome/browser/ui/search/ntp_user_data_types.h
index 00a07fe..fe37d95e 100644
--- a/chrome/browser/ui/search/ntp_user_data_types.h
+++ b/chrome/browser/ui/search/ntp_user_data_types.h
@@ -38,6 +38,17 @@
   kMaxValue = CUSTOMIZED_FEATURE_SHORTCUT
 };
 
+// This enum must match the numbering for NTPCustomizedShortcutSettings in
+// enums.xml. Do not reorder or remove items, and update kMaxValue when new
+// items are added.
+enum class CustomizedShortcutSettings {
+  CUSTOMIZED_SHORTCUT_SETTINGS_MOST_VISITED = 0,
+  CUSTOMIZED_SHORTCUT_SETTINGS_CUSTOM_LINKS = 1,
+  CUSTOMIZED_SHORTCUT_SETTINGS_HIDDEN = 2,
+
+  kMaxValue = CUSTOMIZED_SHORTCUT_SETTINGS_HIDDEN
+};
+
 // This enum must match the numbering for NTPCustomizeAction in
 // enums.xml. Do not reorder or remove items, and update kMaxValue when new
 // items are added.
@@ -86,8 +97,10 @@
   CUSTOMIZE_SHORTCUT_ACTION_RESTORE_ALL = 4,
   CUSTOMIZE_SHORTCUT_ACTION_ADD = 5,
   CUSTOMIZE_SHORTCUT_ACTION_UPDATE = 6,
+  CUSTOMIZE_SHORTCUT_ACTION_TOGGLE_TYPE = 7,
+  CUSTOMIZE_SHORTCUT_ACTION_TOGGLE_VISIBILITY = 8,
 
-  kMaxValue = CUSTOMIZE_SHORTCUT_ACTION_UPDATE
+  kMaxValue = CUSTOMIZE_SHORTCUT_ACTION_TOGGLE_VISIBILITY
 };
 
 #endif  // CHROME_BROWSER_UI_SEARCH_NTP_USER_DATA_TYPES_H_
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.cc b/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.cc
index dbba7504..a97de83d 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.cc
@@ -257,22 +257,22 @@
   size_t index_to_drop_at = size_t{drop_parent->GetIndexOf(node)};
   BookmarkModel* model = GetBookmarkModel();
   switch (*position) {
-    case views::MenuDelegate::DROP_AFTER:
+    case views::MenuDelegate::DropPosition::kAfter:
       if (node == model->other_node() || node == model->mobile_node()) {
         // Dropping after these nodes makes no sense.
-        *position = views::MenuDelegate::DROP_NONE;
+        *position = views::MenuDelegate::DropPosition::kNone;
       }
       index_to_drop_at++;
       break;
 
-    case views::MenuDelegate::DROP_BEFORE:
+    case views::MenuDelegate::DropPosition::kBefore:
       if (node == model->mobile_node()) {
         // Dropping before this node makes no sense.
-        *position = views::MenuDelegate::DROP_NONE;
+        *position = views::MenuDelegate::DropPosition::kNone;
       }
       break;
 
-    case views::MenuDelegate::DROP_ON:
+    case views::MenuDelegate::DropPosition::kOn:
       drop_parent = node;
       index_to_drop_at = node->children().size();
       break;
@@ -297,17 +297,17 @@
   DCHECK(drop_parent);
   size_t index_to_drop_at = size_t{drop_parent->GetIndexOf(drop_node)};
   switch (position) {
-    case views::MenuDelegate::DROP_AFTER:
+    case views::MenuDelegate::DropPosition::kAfter:
       index_to_drop_at++;
       break;
 
-    case views::MenuDelegate::DROP_ON:
+    case views::MenuDelegate::DropPosition::kOn:
       DCHECK(drop_node->is_folder());
       drop_parent = drop_node;
       index_to_drop_at = drop_node->children().size();
       break;
 
-    case views::MenuDelegate::DROP_BEFORE:
+    case views::MenuDelegate::DropPosition::kBefore:
       if (drop_node == model->other_node() ||
           drop_node == model->mobile_node()) {
         // This can happen with SHOW_PERMANENT_FOLDERS.
diff --git a/chrome/browser/ui/views/find_bar_views_interactive_uitest.cc b/chrome/browser/ui/views/find_bar_views_interactive_uitest.cc
index 71bce1a..3b0cb5c 100644
--- a/chrome/browser/ui/views/find_bar_views_interactive_uitest.cc
+++ b/chrome/browser/ui/views/find_bar_views_interactive_uitest.cc
@@ -167,7 +167,13 @@
   EXPECT_TRUE(IsViewFocused(browser(), VIEW_ID_FIND_IN_PAGE_NEXT_BUTTON));
 }
 
-IN_PROC_BROWSER_TEST_F(FindInPageTest, ButtonsDoNotAlterFocus) {
+// Flaky on Mac. https://crbug.com/986571
+#if defined(OS_MACOSX)
+#define MAYBE_ButtonsDoNotAlterFocus DISABLED_ButtonsDoNotAlterFocus
+#else
+#define MAYBE_ButtonsDoNotAlterFocus ButtonsDoNotAlterFocus
+#endif
+IN_PROC_BROWSER_TEST_F(FindInPageTest, MAYBE_ButtonsDoNotAlterFocus) {
   ASSERT_TRUE(embedded_test_server()->Start());
   // Make sure Chrome is in the foreground, otherwise sending input
   // won't do anything and the test will hang.
diff --git a/chrome/browser/ui/webui/webapks_handler.cc b/chrome/browser/ui/webui/webapks_handler.cc
index 3e3156e..534163f 100644
--- a/chrome/browser/ui/webui/webapks_handler.cc
+++ b/chrome/browser/ui/webui/webapks_handler.cc
@@ -75,6 +75,8 @@
                       OptionalSkColorToString(webapk_info.background_color));
     result->SetDouble("lastUpdateCheckTimeMs",
                       webapk_info.last_update_check_time.ToJsTime());
+    result->SetDouble("lastUpdateCompletionTimeMs",
+                      webapk_info.last_update_completion_time.ToJsTime());
     result->SetBoolean("relaxUpdates", webapk_info.relax_updates);
     result->SetString("updateStatus", webapk_info.update_status);
     list.Append(std::move(result));
diff --git a/chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager.cc b/chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager.cc
index 7ec73fd8..c507b2ca 100644
--- a/chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager.cc
+++ b/chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager.cc
@@ -206,8 +206,9 @@
     return;
   }
 
-  WebappInstallSource metrics_install_source =
-      web_app::ConvertOptionsToMetricsInstallSource(install_options);
+  WebappInstallSource install_source =
+      web_app::ConvertExternalInstallSourceToInstallSource(
+          install_options.install_source);
 
   Profile* profile = Profile::FromBrowserContext(
       install_task->web_contents()->GetBrowserContext());
@@ -215,7 +216,7 @@
 
   auto bookmark_app_helper = install_manager->bookmark_app_helper_factory().Run(
       profile, std::move(web_app_info), install_task->web_contents(),
-      metrics_install_source);
+      install_source);
 
   BookmarkAppHelper* helper_ptr = bookmark_app_helper.get();
   SetBookmarkAppHelperOptions(install_options, bookmark_app_helper.get());
diff --git a/chrome/browser/web_applications/components/install_finalizer.h b/chrome/browser/web_applications/components/install_finalizer.h
index 79e7055..2724320 100644
--- a/chrome/browser/web_applications/components/install_finalizer.h
+++ b/chrome/browser/web_applications/components/install_finalizer.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/callback_forward.h"
+#include "chrome/browser/installable/installable_metrics.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 
@@ -33,18 +34,11 @@
   using CreateOsShortcutsCallback =
       base::OnceCallback<void(bool shortcuts_created)>;
 
-  enum class Source {
-    kUser,
-    kDefaultInstalled,
-    kPolicyInstalled,
-    kSystemInstalled,
-  };
-
   struct FinalizeOptions {
     // If |force_launch_container| defined as non-kDefault then the installed
     // app will launch in |force_launch_container|.
     LaunchContainer force_launch_container = LaunchContainer::kDefault;
-    Source source = Source::kUser;
+    WebappInstallSource install_source = WebappInstallSource::COUNT;
     bool locally_installed = true;
     bool no_network_install = false;
   };
diff --git a/chrome/browser/web_applications/components/web_app_install_utils.cc b/chrome/browser/web_applications/components/web_app_install_utils.cc
index 49eab6e..1f81d7bdc 100644
--- a/chrome/browser/web_applications/components/web_app_install_utils.cc
+++ b/chrome/browser/web_applications/components/web_app_install_utils.cc
@@ -14,7 +14,6 @@
 #include "chrome/browser/banners/app_banner_settings_helper.h"
 #include "chrome/browser/installable/installable_data.h"
 #include "chrome/browser/installable/installable_metrics.h"
-#include "chrome/browser/web_applications/components/external_install_options.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/components/web_app_icon_generator.h"
 #include "chrome/common/web_application_info.h"
@@ -204,28 +203,28 @@
       base::Time::Now());
 }
 
-WebappInstallSource ConvertOptionsToMetricsInstallSource(
-    const ExternalInstallOptions& options) {
-  auto metrics_install_source = WebappInstallSource::COUNT;
-  switch (options.install_source) {
+WebappInstallSource ConvertExternalInstallSourceToInstallSource(
+    ExternalInstallSource external_install_source) {
+  WebappInstallSource install_source;
+  switch (external_install_source) {
     case ExternalInstallSource::kInternalDefault:
-      metrics_install_source = WebappInstallSource::INTERNAL_DEFAULT;
+      install_source = WebappInstallSource::INTERNAL_DEFAULT;
       break;
     case ExternalInstallSource::kExternalDefault:
-      metrics_install_source = WebappInstallSource::EXTERNAL_DEFAULT;
+      install_source = WebappInstallSource::EXTERNAL_DEFAULT;
       break;
     case ExternalInstallSource::kExternalPolicy:
-      metrics_install_source = WebappInstallSource::EXTERNAL_POLICY;
+      install_source = WebappInstallSource::EXTERNAL_POLICY;
       break;
     case ExternalInstallSource::kSystemInstalled:
-      metrics_install_source = WebappInstallSource::SYSTEM_DEFAULT;
+      install_source = WebappInstallSource::SYSTEM_DEFAULT;
       break;
     case ExternalInstallSource::kArc:
-      metrics_install_source = WebappInstallSource::ARC;
+      install_source = WebappInstallSource::ARC;
       break;
   }
 
-  return metrics_install_source;
+  return install_source;
 }
 
 void RecordExternalAppInstallResultCode(
diff --git a/chrome/browser/web_applications/components/web_app_install_utils.h b/chrome/browser/web_applications/components/web_app_install_utils.h
index d781c2270..156a33d 100644
--- a/chrome/browser/web_applications/components/web_app_install_utils.h
+++ b/chrome/browser/web_applications/components/web_app_install_utils.h
@@ -26,10 +26,9 @@
 
 namespace web_app {
 
+enum class ExternalInstallSource;
 enum class InstallResultCode;
-
 struct BitmapAndSource;
-struct ExternalInstallOptions;
 
 enum class ForInstallableSite {
   kYes,
@@ -96,8 +95,8 @@
 // shown for this app.
 void RecordAppBanner(content::WebContents* contents, const GURL& app_url);
 
-WebappInstallSource ConvertOptionsToMetricsInstallSource(
-    const ExternalInstallOptions& options);
+WebappInstallSource ConvertExternalInstallSourceToInstallSource(
+    ExternalInstallSource external_install_source);
 
 void RecordExternalAppInstallResultCode(
     const char* histogram_name,
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_helper_installation_task_unittest.cc b/chrome/browser/web_applications/extensions/bookmark_app_helper_installation_task_unittest.cc
index 27fdcc6..9b67aca 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_helper_installation_task_unittest.cc
+++ b/chrome/browser/web_applications/extensions/bookmark_app_helper_installation_task_unittest.cc
@@ -665,8 +665,9 @@
 
             EXPECT_EQ(1u, install_finalizer()->num_create_os_shortcuts_calls());
             EXPECT_EQ(1u, install_finalizer()->finalize_options_list().size());
-            EXPECT_EQ(web_app::InstallFinalizer::Source::kPolicyInstalled,
-                      install_finalizer()->finalize_options_list()[0].source);
+            EXPECT_EQ(
+                WebappInstallSource::EXTERNAL_POLICY,
+                install_finalizer()->finalize_options_list()[0].install_source);
             const WebApplicationInfo& web_app_info =
                 install_finalizer()->web_app_info_list().at(0);
 
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.cc b/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.cc
index cb3371db11..ba2b273 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.cc
+++ b/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/logging.h"
 #include "base/optional.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/extensions/bookmark_app_extension_util.h"
@@ -115,17 +116,20 @@
       OnExtensionInstalled, web_app_info.app_url, launch_type,
       options.locally_installed, std::move(callback), crx_installer));
 
-  switch (options.source) {
-    case web_app::InstallFinalizer::Source::kDefaultInstalled:
+  switch (options.install_source) {
+      // TODO(nigeltao/ortuno): should these two cases lead to different
+      // Manifest::Location values: INTERNAL vs EXTERNAL_PREF_DOWNLOAD?
+    case WebappInstallSource::INTERNAL_DEFAULT:
+    case WebappInstallSource::EXTERNAL_DEFAULT:
       crx_installer->set_install_source(Manifest::EXTERNAL_PREF_DOWNLOAD);
       // CrxInstaller::InstallWebApp will OR the creation flags with
       // FROM_BOOKMARK.
       crx_installer->set_creation_flags(Extension::WAS_INSTALLED_BY_DEFAULT);
       break;
-    case web_app::InstallFinalizer::Source::kPolicyInstalled:
+    case WebappInstallSource::EXTERNAL_POLICY:
       crx_installer->set_install_source(Manifest::EXTERNAL_POLICY_DOWNLOAD);
       break;
-    case web_app::InstallFinalizer::Source::kSystemInstalled:
+    case WebappInstallSource::SYSTEM_DEFAULT:
       // System Apps are considered EXTERNAL_COMPONENT as they are downloaded
       // from the WebUI they point to. COMPONENT seems like the more correct
       // value, but usages (icon loading, filesystem cleanup), are tightly
@@ -134,7 +138,11 @@
       // InstallWebApp will OR the creation flags with FROM_BOOKMARK.
       crx_installer->set_creation_flags(Extension::WAS_INSTALLED_BY_DEFAULT);
       break;
-    case web_app::InstallFinalizer::Source::kUser:
+    case WebappInstallSource::COUNT:
+      NOTREACHED();
+      break;
+    default:
+      // All other install sources mean user-installed app. Do nothing.
       break;
   }
 
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer_unittest.cc b/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer_unittest.cc
index 63037fa..6a50128 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer_unittest.cc
+++ b/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer_unittest.cc
@@ -100,7 +100,7 @@
     info->title = base::ASCIIToUTF16(kWebAppTitle);
 
     web_app::InstallFinalizer::FinalizeOptions options;
-    options.source = web_app::InstallFinalizer::Source::kPolicyInstalled;
+    options.install_source = WebappInstallSource::EXTERNAL_POLICY;
 
     web_app::AppId app_id;
     base::RunLoop run_loop;
@@ -146,6 +146,7 @@
 
   base::RunLoop run_loop;
   web_app::InstallFinalizer::FinalizeOptions options;
+  options.install_source = WebappInstallSource::INTERNAL_DEFAULT;
   web_app::AppId app_id;
   bool callback_called = false;
 
@@ -182,6 +183,7 @@
 
   base::RunLoop run_loop;
   web_app::InstallFinalizer::FinalizeOptions options;
+  options.install_source = WebappInstallSource::INTERNAL_DEFAULT;
   bool callback_called = false;
 
   installer.FinalizeInstall(
@@ -211,7 +213,8 @@
 
   bool callback1_called = false;
   bool callback2_called = false;
-  const web_app::InstallFinalizer::FinalizeOptions options;
+  web_app::InstallFinalizer::FinalizeOptions options;
+  options.install_source = WebappInstallSource::INTERNAL_DEFAULT;
 
   // Start install finalization for the 1st app
   {
@@ -261,7 +264,7 @@
   info->title = base::ASCIIToUTF16(kWebAppTitle);
 
   web_app::InstallFinalizer::FinalizeOptions options;
-  options.source = web_app::InstallFinalizer::Source::kDefaultInstalled;
+  options.install_source = WebappInstallSource::EXTERNAL_DEFAULT;
 
   base::RunLoop run_loop;
   installer.FinalizeInstall(
@@ -290,7 +293,7 @@
   info->title = base::ASCIIToUTF16(kWebAppTitle);
 
   web_app::InstallFinalizer::FinalizeOptions options;
-  options.source = web_app::InstallFinalizer::Source::kPolicyInstalled;
+  options.install_source = WebappInstallSource::EXTERNAL_POLICY;
 
   base::RunLoop run_loop;
   installer.FinalizeInstall(
@@ -318,7 +321,7 @@
   info->title = base::ASCIIToUTF16(kWebAppTitle);
 
   web_app::InstallFinalizer::FinalizeOptions options;
-  options.source = web_app::InstallFinalizer::Source::kSystemInstalled;
+  options.install_source = WebappInstallSource::SYSTEM_DEFAULT;
 
   base::RunLoop run_loop;
   installer.FinalizeInstall(
@@ -346,6 +349,7 @@
   info->app_url = kWebAppUrl;
 
   web_app::InstallFinalizer::FinalizeOptions options;
+  options.install_source = WebappInstallSource::ARC;
   options.no_network_install = true;
 
   base::RunLoop run_loop;
@@ -375,6 +379,7 @@
   info->open_as_window = true;
 
   web_app::InstallFinalizer::FinalizeOptions options;
+  options.install_source = WebappInstallSource::INTERNAL_DEFAULT;
   // Force launch as a tab.
   options.force_launch_container = web_app::LaunchContainer::kTab;
 
@@ -413,6 +418,7 @@
 
   base::RunLoop run_loop;
   web_app::InstallFinalizer::FinalizeOptions options;
+  options.install_source = WebappInstallSource::SYNC;
 
   installer.FinalizeInstall(
       *info, options,
@@ -550,6 +556,7 @@
   info->app_url = kWebAppUrl;
 
   web_app::InstallFinalizer::FinalizeOptions options;
+  options.install_source = WebappInstallSource::INTERNAL_DEFAULT;
   options.locally_installed = false;
 
   base::RunLoop run_loop;
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_installation_task.cc b/chrome/browser/web_applications/extensions/bookmark_app_installation_task.cc
index ee0f660..e9b3d9b 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_installation_task.cc
+++ b/chrome/browser/web_applications/extensions/bookmark_app_installation_task.cc
@@ -170,7 +170,7 @@
   }
 
   web_app::InstallFinalizer::FinalizeOptions options;
-  options.source = web_app::InstallFinalizer::Source::kPolicyInstalled;
+  options.install_source = WebappInstallSource::EXTERNAL_POLICY;
 
   install_finalizer_->FinalizeInstall(
       web_app_info, options,
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_installation_task_unittest.cc b/chrome/browser/web_applications/extensions/bookmark_app_installation_task_unittest.cc
index b078f715..738d45d 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_installation_task_unittest.cc
+++ b/chrome/browser/web_applications/extensions/bookmark_app_installation_task_unittest.cc
@@ -377,8 +377,8 @@
 
             EXPECT_EQ(web_app::LaunchContainer::kDefault,
                       finalize_options().force_launch_container);
-            EXPECT_EQ(web_app::InstallFinalizer::Source::kDefaultInstalled,
-                      finalize_options().source);
+            EXPECT_EQ(WebappInstallSource::INTERNAL_DEFAULT,
+                      finalize_options().install_source);
 
             run_loop.Quit();
           }));
@@ -570,9 +570,8 @@
                                 result.code);
                       EXPECT_TRUE(result.app_id.has_value());
 
-                      EXPECT_EQ(
-                          web_app::InstallFinalizer::Source::kDefaultInstalled,
-                          finalize_options().source);
+                      EXPECT_EQ(WebappInstallSource::INTERNAL_DEFAULT,
+                                finalize_options().install_source);
                       run_loop.Quit();
                     }));
 
@@ -594,9 +593,8 @@
                                 result.code);
                       EXPECT_TRUE(result.app_id.has_value());
 
-                      EXPECT_EQ(
-                          web_app::InstallFinalizer::Source::kPolicyInstalled,
-                          finalize_options().source);
+                      EXPECT_EQ(WebappInstallSource::EXTERNAL_POLICY,
+                                finalize_options().install_source);
                       run_loop.Quit();
                     }));
 
@@ -622,8 +620,8 @@
 
         EXPECT_EQ(1u, finalizer()->num_create_os_shortcuts_calls());
         EXPECT_EQ(1u, finalizer()->finalize_options_list().size());
-        EXPECT_EQ(web_app::InstallFinalizer::Source::kPolicyInstalled,
-                  finalize_options().source);
+        EXPECT_EQ(WebappInstallSource::EXTERNAL_POLICY,
+                  finalize_options().install_source);
         const WebApplicationInfo& web_app_info =
             finalizer()->web_app_info_list().at(0);
 
diff --git a/chrome/browser/web_applications/web_app_install_task.cc b/chrome/browser/web_applications/web_app_install_task.cc
index 8aa8055..ab486bf 100644
--- a/chrome/browser/web_applications/web_app_install_task.cc
+++ b/chrome/browser/web_applications/web_app_install_task.cc
@@ -131,6 +131,7 @@
                                         : ForInstallableSite::kNo);
 
   InstallFinalizer::FinalizeOptions options;
+  options.install_source = install_source;
   if (no_network_install) {
     options.no_network_install = true;
     // We should only install windowed apps via this method.
@@ -149,7 +150,8 @@
 
   Observe(contents);
   install_callback_ = std::move(install_callback);
-  install_source_ = ConvertOptionsToMetricsInstallSource(install_options);
+  install_source_ = ConvertExternalInstallSourceToInstallSource(
+      install_options.install_source);
   install_options_ = install_options;
   background_installation_ = true;
 
@@ -417,6 +419,7 @@
   UpdateWebAppIconsWithoutChangingLinks(size_map, web_app_info.get());
 
   InstallFinalizer::FinalizeOptions options;
+  options.install_source = install_source_;
   options.locally_installed = is_locally_installed;
 
   install_finalizer_->FinalizeInstall(
@@ -471,27 +474,10 @@
   RecordInstallEvent(for_installable_site);
 
   InstallFinalizer::FinalizeOptions finalize_options;
+  finalize_options.install_source = install_source_;
   if (install_options_) {
     finalize_options.force_launch_container =
         install_options_->launch_container;
-
-    switch (install_options_->install_source) {
-      // TODO(nigeltao/ortuno): should these two cases lead to different
-      // Manifest::Location values: INTERNAL vs EXTERNAL_PREF_DOWNLOAD?
-      case ExternalInstallSource::kInternalDefault:
-      case ExternalInstallSource::kExternalDefault:
-        finalize_options.source = InstallFinalizer::Source::kDefaultInstalled;
-        break;
-      case ExternalInstallSource::kExternalPolicy:
-        finalize_options.source = InstallFinalizer::Source::kPolicyInstalled;
-        break;
-      case ExternalInstallSource::kSystemInstalled:
-        finalize_options.source = InstallFinalizer::Source::kSystemInstalled;
-        break;
-      case ExternalInstallSource::kArc:
-        NOTREACHED();
-        break;
-    }
   }
 
   install_finalizer_->FinalizeInstall(
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index d5fbe49..d856e29 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -151,9 +151,6 @@
     "mac/staging_watcher.mm",
     "media/media_resource_provider.cc",
     "media/media_resource_provider.h",
-    "media/webrtc_logging_message_data.cc",
-    "media/webrtc_logging_message_data.h",
-    "media/webrtc_logging_messages.h",
     "media_galleries/metadata_types.h",
     "multi_process_lock.h",
     "multi_process_lock_linux.cc",
@@ -720,6 +717,7 @@
     "chrome_render_frame.mojom",
     "constants.mojom",
     "content_settings_renderer.mojom",
+    "media/webrtc_logging.mojom",
     "navigation_corrector.mojom",
     "net_benchmarking.mojom",
     "network_diagnostics.mojom",
diff --git a/chrome/common/common_message_generator.h b/chrome/common/common_message_generator.h
index 8039857..d70b691 100644
--- a/chrome/common/common_message_generator.h
+++ b/chrome/common/common_message_generator.h
@@ -55,12 +55,6 @@
 #endif
 #endif
 
-#undef CHROME_COMMON_MEDIA_WEBRTC_LOGGING_MESSAGES_H_
-#include "chrome/common/media/webrtc_logging_messages.h"
-#ifndef CHROME_COMMON_MEDIA_WEBRTC_LOGGING_MESSAGES_H_
-#error "Failed to include header chrome/common/media/webrtc_logging_messages.h"
-#endif
-
 #if defined(FULL_SAFE_BROWSING)
 #include "chrome/services/file_util/public/mojom/safe_archive_analyzer_param_traits.h"
 #endif
diff --git a/chrome/common/media/OWNERS b/chrome/common/media/OWNERS
index 42444bc..d8469177 100644
--- a/chrome/common/media/OWNERS
+++ b/chrome/common/media/OWNERS
@@ -1,2 +1,5 @@
 per-file *_messages*.h=set noparent
 per-file *_messages*.h=file://ipc/SECURITY_OWNERS
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chrome/common/media/webrtc_logging.mojom b/chrome/common/media/webrtc_logging.mojom
new file mode 100644
index 0000000..782673d5
--- /dev/null
+++ b/chrome/common/media/webrtc_logging.mojom
@@ -0,0 +1,33 @@
+// 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.
+
+module chrome.mojom;
+
+import "mojo/public/mojom/base/time.mojom";
+
+// Represents a log message sent from the agent.
+struct WebRtcLoggingMessage {
+  mojo_base.mojom.Time timestamp;
+  string data;
+};
+
+// Used to listen for new log messages and events from the agent.
+interface WebRtcLoggingClient {
+  // New log messages are sent in batches to limit the frequency of calls.
+  OnAddMessages(array<WebRtcLoggingMessage> messages);
+
+  // Called in response to |Stop| being called on the agent. Any pending
+  // log messages will be sent via |OnAddMessages| first.
+  OnStopped();
+};
+
+// Used to control the renderer-side agent to start / stop logging.
+interface WebRtcLoggingAgent {
+  // Enables logging to the given |client|.
+  Start(pending_remote<WebRtcLoggingClient> client);
+
+  // Stops logging, resulting in any pending messages being sent via
+  // |OnAddMessages| and then |OnStopped| being called on the client.
+  Stop();
+};
diff --git a/chrome/common/media/webrtc_logging_message_data.cc b/chrome/common/media/webrtc_logging_message_data.cc
deleted file mode 100644
index 4d70eda7..0000000
--- a/chrome/common/media/webrtc_logging_message_data.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/common/media/webrtc_logging_message_data.h"
-
-#include <stdint.h>
-
-#include "base/strings/stringprintf.h"
-
-WebRtcLoggingMessageData::WebRtcLoggingMessageData() {}
-
-WebRtcLoggingMessageData::WebRtcLoggingMessageData(base::Time time,
-                                                   const std::string& message)
-    : timestamp(time), message(message) {}
-
-// static
-std::string WebRtcLoggingMessageData::Format(const std::string& message,
-                                             base::Time timestamp,
-                                             base::Time start_time) {
-  int32_t interval_ms =
-      static_cast<int32_t>((timestamp - start_time).InMilliseconds());
-  return base::StringPrintf("[%03d:%03d] %s", interval_ms / 1000,
-                            interval_ms % 1000, message.c_str());
-}
-
-std::string WebRtcLoggingMessageData::Format(base::Time start_time) const {
-  return Format(message, timestamp, start_time);
-}
diff --git a/chrome/common/media/webrtc_logging_message_data.h b/chrome/common/media/webrtc_logging_message_data.h
deleted file mode 100644
index 1376e7f..0000000
--- a/chrome/common/media/webrtc_logging_message_data.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_COMMON_MEDIA_WEBRTC_LOGGING_MESSAGE_DATA_H_
-#define CHROME_COMMON_MEDIA_WEBRTC_LOGGING_MESSAGE_DATA_H_
-
-#include <string>
-
-#include "base/time/time.h"
-
-// A struct representing a logging message with its creation time.
-struct WebRtcLoggingMessageData {
-  WebRtcLoggingMessageData();
-  WebRtcLoggingMessageData(base::Time time, const std::string& message);
-
-  // Returns a string formatted as "[XXX:YYY] $message", where "[XXX:YYY]" is
-  // the timestamp relative to |start_time| converted to seconds (XXX) plus
-  // milliseconds (YYY).
-  static std::string Format(const std::string& message, base::Time timestamp,
-                            base::Time start_time);
-  std::string Format(base::Time start_time) const;
-
-  base::Time timestamp;
-  std::string message;
-};
-
-#endif  // CHROME_COMMON_MEDIA_WEBRTC_LOGGING_MESSAGE_DATA_H_
diff --git a/chrome/common/media/webrtc_logging_messages.h b/chrome/common/media/webrtc_logging_messages.h
deleted file mode 100644
index b4a89a7..0000000
--- a/chrome/common/media/webrtc_logging_messages.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_COMMON_MEDIA_WEBRTC_LOGGING_MESSAGES_H_
-#define CHROME_COMMON_MEDIA_WEBRTC_LOGGING_MESSAGES_H_
-
-// IPC messages for WebRTC logging.
-
-#include "chrome/common/media/webrtc_logging_message_data.h"
-#include "ipc/ipc_message_macros.h"
-
-#define IPC_MESSAGE_START WebRtcLoggingMsgStart
-
-IPC_STRUCT_TRAITS_BEGIN(WebRtcLoggingMessageData)
-  IPC_STRUCT_TRAITS_MEMBER(timestamp)
-  IPC_STRUCT_TRAITS_MEMBER(message)
-IPC_STRUCT_TRAITS_END()
-
-// Messages sent from the renderer to the browser.
-
-// Send log message to add to log.
-IPC_MESSAGE_CONTROL1(WebRtcLoggingMsg_AddLogMessages,
-                     std::vector<WebRtcLoggingMessageData> /* messages */)
-
-// Notification that the renderer has stopped sending log messages to the
-// browser.
-IPC_MESSAGE_CONTROL0(WebRtcLoggingMsg_LoggingStopped)
-
-// Messages sent from the browser to the renderer.
-
-// Tells the renderer to start sending log messages to the browser.
-IPC_MESSAGE_CONTROL0(WebRtcLoggingMsg_StartLogging)
-
-// Tells the renderer to stop sending log messages to the browser.
-IPC_MESSAGE_CONTROL0(WebRtcLoggingMsg_StopLogging)
-
-#endif  // CHROME_COMMON_MEDIA_WEBRTC_LOGGING_MESSAGES_H_
diff --git a/chrome/common/search/ntp_logging_events.h b/chrome/common/search/ntp_logging_events.h
index e23dc4df..065c46a7 100644
--- a/chrome/common/search/ntp_logging_events.h
+++ b/chrome/common/search/ntp_logging_events.h
@@ -127,7 +127,13 @@
   // A promo link was clicked.
   NTP_MIDDLE_SLOT_PROMO_LINK_CLICKED = 61,
 
-  NTP_EVENT_TYPE_LAST = NTP_MIDDLE_SLOT_PROMO_LINK_CLICKED
+  // The shortcut type displayed (i.e. Most Visited or custom links) was
+  // changed.
+  NTP_CUSTOMIZE_SHORTCUT_TOGGLE_TYPE = 62,
+  // The visibility of shortcuts was changed.
+  NTP_CUSTOMIZE_SHORTCUT_TOGGLE_VISIBILITY = 63,
+
+  NTP_EVENT_TYPE_LAST = NTP_CUSTOMIZE_SHORTCUT_TOGGLE_VISIBILITY
 };
 
 // The different types of events that are logged for NTP search suggestions,
diff --git a/chrome/renderer/BUILD.gn b/chrome/renderer/BUILD.gn
index bdd17fb..a8adf787 100644
--- a/chrome/renderer/BUILD.gn
+++ b/chrome/renderer/BUILD.gn
@@ -61,12 +61,10 @@
     "media/chrome_key_systems.h",
     "media/chrome_key_systems_provider.cc",
     "media/chrome_key_systems_provider.h",
-    "media/chrome_webrtc_log_message_delegate.cc",
-    "media/chrome_webrtc_log_message_delegate.h",
     "media/flash_embed_rewrite.cc",
     "media/flash_embed_rewrite.h",
-    "media/webrtc_logging_message_filter.cc",
-    "media/webrtc_logging_message_filter.h",
+    "media/webrtc_logging_agent_impl.cc",
+    "media/webrtc_logging_agent_impl.h",
     "net/net_error_helper.cc",
     "net/net_error_helper.h",
     "net/net_error_helper_core.cc",
@@ -429,8 +427,6 @@
   sources = [
     "chrome_mock_render_thread.cc",
     "chrome_mock_render_thread.h",
-    "media/mock_webrtc_logging_message_filter.cc",
-    "media/mock_webrtc_logging_message_filter.h",
     "safe_browsing/mock_feature_extractor_clock.cc",
     "safe_browsing/mock_feature_extractor_clock.h",
     "safe_browsing/test_utils.cc",
diff --git a/chrome/renderer/autofill/autofill_renderer_browsertest.cc b/chrome/renderer/autofill/autofill_renderer_browsertest.cc
index c124faa..19a428f 100644
--- a/chrome/renderer/autofill/autofill_renderer_browsertest.cc
+++ b/chrome/renderer/autofill/autofill_renderer_browsertest.cc
@@ -13,7 +13,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "chrome/test/base/chrome_render_view_test.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "components/autofill/content/common/autofill_driver.mojom.h"
+#include "components/autofill/content/common/mojom/autofill_driver.mojom.h"
 #include "components/autofill/content/renderer/autofill_agent.h"
 #include "components/autofill/core/common/autofill_features.h"
 #include "components/autofill/core/common/form_data.h"
diff --git a/chrome/renderer/autofill/fake_mojo_password_manager_driver.h b/chrome/renderer/autofill/fake_mojo_password_manager_driver.h
index 223d4d9..8f32f50 100644
--- a/chrome/renderer/autofill/fake_mojo_password_manager_driver.h
+++ b/chrome/renderer/autofill/fake_mojo_password_manager_driver.h
@@ -10,7 +10,7 @@
 
 #include "base/optional.h"
 #include "base/strings/string16.h"
-#include "components/autofill/content/common/autofill_driver.mojom.h"
+#include "components/autofill/content/common/mojom/autofill_driver.mojom.h"
 #include "components/autofill/core/common/password_form.h"
 #include "mojo/public/cpp/bindings/associated_binding_set.h"
 
diff --git a/chrome/renderer/autofill/fake_password_generation_driver.h b/chrome/renderer/autofill/fake_password_generation_driver.h
index 0f88fb38..7fbf4c2 100644
--- a/chrome/renderer/autofill/fake_password_generation_driver.h
+++ b/chrome/renderer/autofill/fake_password_generation_driver.h
@@ -10,7 +10,7 @@
 
 #include "base/optional.h"
 #include "base/strings/string16.h"
-#include "components/autofill/content/common/autofill_driver.mojom.h"
+#include "components/autofill/content/common/mojom/autofill_driver.mojom.h"
 #include "components/autofill/core/common/password_form.h"
 #include "components/autofill/core/common/password_generation_util.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
index 42f2b341..ae7e073 100644
--- a/chrome/renderer/chrome_content_renderer_client.cc
+++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -50,7 +50,7 @@
 #include "chrome/renderer/content_settings_observer.h"
 #include "chrome/renderer/loadtimes_extension_bindings.h"
 #include "chrome/renderer/media/flash_embed_rewrite.h"
-#include "chrome/renderer/media/webrtc_logging_message_filter.h"
+#include "chrome/renderer/media/webrtc_logging_agent_impl.h"
 #include "chrome/renderer/net/net_error_helper.h"
 #include "chrome/renderer/net_benchmarking_extension.h"
 #include "chrome/renderer/page_load_metrics/metrics_render_frame_observer.h"
@@ -372,8 +372,10 @@
   prerender_dispatcher_.reset(new prerender::PrerenderDispatcher());
   subresource_filter_ruleset_dealer_.reset(
       new subresource_filter::UnverifiedRulesetDealer());
-  webrtc_logging_message_filter_ =
-      new WebRtcLoggingMessageFilter(thread->GetIOTaskRunner());
+
+  registry_.AddInterface(base::BindRepeating(
+      &ChromeContentRendererClient::OnWebRtcLoggingAgentRequest,
+      base::Unretained(this)));
 
   thread->AddObserver(chrome_observer_.get());
   thread->AddObserver(prerender_dispatcher_.get());
@@ -383,7 +385,6 @@
   thread->AddObserver(SearchBouncer::GetInstance());
 #endif
 
-  thread->AddFilter(webrtc_logging_message_filter_.get());
   thread->RegisterExtension(extensions_v8::LoadTimesExtension::Get());
 
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
@@ -1639,3 +1640,12 @@
 #endif
   return url.SchemeIs(content::kChromeUIScheme) && !can_use_polyfill;
 }
+
+void ChromeContentRendererClient::OnWebRtcLoggingAgentRequest(
+    mojo::InterfaceRequest<chrome::mojom::WebRtcLoggingAgent> request) {
+  if (!webrtc_logging_agent_impl_) {
+    webrtc_logging_agent_impl_ =
+        std::make_unique<chrome::WebRtcLoggingAgentImpl>();
+  }
+  webrtc_logging_agent_impl_->AddReceiver(std::move(request));
+}
diff --git a/chrome/renderer/chrome_content_renderer_client.h b/chrome/renderer/chrome_content_renderer_client.h
index c926cd33..d351fc3 100644
--- a/chrome/renderer/chrome_content_renderer_client.h
+++ b/chrome/renderer/chrome_content_renderer_client.h
@@ -54,6 +54,13 @@
 class WebServiceWorkerContextProxy;
 }
 
+namespace chrome {
+namespace mojom {
+class WebRtcLoggingAgent;
+}  // namespace mojom
+class WebRtcLoggingAgentImpl;
+}  // namespace chrome
+
 namespace content {
 class BrowserPluginDelegate;
 struct WebPluginInfo;
@@ -79,8 +86,6 @@
 class WebCacheImpl;
 }
 
-class WebRtcLoggingMessageFilter;
-
 class ChromeContentRendererClient
     : public content::ContentRendererClient,
       public service_manager::Service,
@@ -269,6 +274,9 @@
 
   service_manager::Connector* GetConnector();
 
+  void OnWebRtcLoggingAgentRequest(
+      mojo::InterfaceRequest<chrome::mojom::WebRtcLoggingAgent> request);
+
 #if defined(OS_WIN)
   // Observes module load events and notifies the ModuleDatabase in the browser
   // process. This instance is created on the main thread but then lives on the
@@ -283,6 +291,7 @@
 
   std::unique_ptr<ChromeRenderThreadObserver> chrome_observer_;
   std::unique_ptr<web_cache::WebCacheImpl> web_cache_impl_;
+  std::unique_ptr<chrome::WebRtcLoggingAgentImpl> webrtc_logging_agent_impl_;
 
   std::unique_ptr<network_hints::PrescientNetworkingDispatcher>
       prescient_networking_dispatcher_;
@@ -295,7 +304,6 @@
   std::unique_ptr<subresource_filter::UnverifiedRulesetDealer>
       subresource_filter_ruleset_dealer_;
   std::unique_ptr<prerender::PrerenderDispatcher> prerender_dispatcher_;
-  scoped_refptr<WebRtcLoggingMessageFilter> webrtc_logging_message_filter_;
 #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
   std::unique_ptr<ChromePDFPrintClient> pdf_print_client_;
 #endif
diff --git a/chrome/renderer/media/chrome_webrtc_log_message_delegate.cc b/chrome/renderer/media/chrome_webrtc_log_message_delegate.cc
deleted file mode 100644
index dd8db4a..0000000
--- a/chrome/renderer/media/chrome_webrtc_log_message_delegate.cc
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2013 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/renderer/media/chrome_webrtc_log_message_delegate.h"
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/single_thread_task_runner.h"
-#include "chrome/renderer/media/webrtc_logging_message_filter.h"
-#include "components/webrtc_logging/common/partial_circular_buffer.h"
-
-ChromeWebRtcLogMessageDelegate::ChromeWebRtcLogMessageDelegate(
-    const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
-    WebRtcLoggingMessageFilter* message_filter)
-    : io_task_runner_(io_task_runner),
-      logging_started_(false),
-      message_filter_(message_filter) {
-  blink::InitWebRtcLoggingDelegate(this);
-}
-
-ChromeWebRtcLogMessageDelegate::~ChromeWebRtcLogMessageDelegate() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-}
-
-void ChromeWebRtcLogMessageDelegate::LogMessage(const std::string& message) {
-  WebRtcLoggingMessageData data(base::Time::Now(), message);
-
-  io_task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&ChromeWebRtcLogMessageDelegate::LogMessageOnIOThread,
-                     base::Unretained(this), data));
-}
-
-void ChromeWebRtcLogMessageDelegate::LogMessageOnIOThread(
-    const WebRtcLoggingMessageData& message) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  if (logging_started_ && message_filter_) {
-    if (!log_buffer_.empty()) {
-      // A delayed task has already been posted for sending the buffer contents.
-      // Just add the message to the buffer.
-      log_buffer_.push_back(message);
-      return;
-    }
-
-    log_buffer_.push_back(message);
-
-    if (base::TimeTicks::Now() - last_log_buffer_send_ >
-        base::TimeDelta::FromMilliseconds(100)) {
-      SendLogBuffer();
-    } else {
-      io_task_runner_->PostDelayedTask(
-          FROM_HERE,
-          base::BindOnce(&ChromeWebRtcLogMessageDelegate::SendLogBuffer,
-                         base::Unretained(this)),
-          base::TimeDelta::FromMilliseconds(200));
-    }
-  }
-}
-
-void ChromeWebRtcLogMessageDelegate::OnFilterRemoved() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  message_filter_ = NULL;
-}
-
-void ChromeWebRtcLogMessageDelegate::OnStartLogging() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  logging_started_ = true;
-  blink::InitWebRtcLogging();
-}
-
-void ChromeWebRtcLogMessageDelegate::OnStopLogging() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  if (!log_buffer_.empty())
-    SendLogBuffer();
-  if (message_filter_)
-    message_filter_->LoggingStopped();
-  logging_started_ = false;
-}
-
-void ChromeWebRtcLogMessageDelegate::SendLogBuffer() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  if (logging_started_ && message_filter_) {
-    message_filter_->AddLogMessages(log_buffer_);
-    last_log_buffer_send_ = base::TimeTicks::Now();
-  }
-  log_buffer_.clear();
-}
diff --git a/chrome/renderer/media/chrome_webrtc_log_message_delegate.h b/chrome/renderer/media/chrome_webrtc_log_message_delegate.h
deleted file mode 100644
index faa363a..0000000
--- a/chrome/renderer/media/chrome_webrtc_log_message_delegate.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2013 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_RENDERER_MEDIA_CHROME_WEBRTC_LOG_MESSAGE_DELEGATE_H_
-#define CHROME_RENDERER_MEDIA_CHROME_WEBRTC_LOG_MESSAGE_DELEGATE_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "base/sequence_checker.h"
-#include "chrome/common/media/webrtc_logging_message_data.h"
-#include "ipc/ipc_channel_proxy.h"
-#include "third_party/blink/public/platform/modules/webrtc/webrtc_logging.h"
-
-namespace base {
-class SingleThreadTaskRunner;
-}
-
-class WebRtcLoggingMessageFilter;
-
-// ChromeWebRtcLogMessageDelegate handles WebRTC logging. There is one object
-// per render process, owned by WebRtcLoggingMessageFilter. It communicates with
-// WebRtcLoggingHandlerHost and receives logging messages from libjingle and
-// writes them to a shared memory buffer.
-class ChromeWebRtcLogMessageDelegate : public blink::WebRtcLogMessageDelegate {
- public:
-  ChromeWebRtcLogMessageDelegate(
-      const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
-      WebRtcLoggingMessageFilter* message_filter);
-
-  ~ChromeWebRtcLogMessageDelegate() override;
-
-  // blink::WebRtcLogMessageDelegate implementation.
-  void LogMessage(const std::string& message) override;
-
-  void OnFilterRemoved();
-
-  void OnStartLogging();
-  void OnStopLogging();
-
- private:
-  void LogMessageOnIOThread(const WebRtcLoggingMessageData& message);
-  void SendLogBuffer();
-
-  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
-  bool logging_started_;
-  std::vector<WebRtcLoggingMessageData> log_buffer_;
-
-  base::TimeTicks last_log_buffer_send_;
-
-  WebRtcLoggingMessageFilter* message_filter_;
-
-  SEQUENCE_CHECKER(sequence_checker_);
-
-  DISALLOW_COPY_AND_ASSIGN(ChromeWebRtcLogMessageDelegate);
-};
-
-#endif  // CHROME_RENDERER_MEDIA_CHROME_WEBRTC_LOG_MESSAGE_DELEGATE_H_
diff --git a/chrome/renderer/media/chrome_webrtc_log_message_delegate_unittest.cc b/chrome/renderer/media/chrome_webrtc_log_message_delegate_unittest.cc
deleted file mode 100644
index 711e45dc..0000000
--- a/chrome/renderer/media/chrome_webrtc_log_message_delegate_unittest.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2013 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 <stdint.h>
-
-#include <string>
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "chrome/renderer/media/chrome_webrtc_log_message_delegate.h"
-#include "chrome/renderer/media/mock_webrtc_logging_message_filter.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-TEST(ChromeWebRtcLogMessageDelegateTest, Basic) {
-  const char kTestString[] = "abcdefghijklmnopqrstuvwxyz";
-  base::MessageLoopForIO message_loop;
-  scoped_refptr<MockWebRtcLoggingMessageFilter> log_message_filter(
-      new MockWebRtcLoggingMessageFilter(message_loop.task_runner()));
-  // Run message loop to initialize delegate.
-  // TODO(vrk): Fix this so that we can construct a delegate without needing to
-  // construct a message filter.
-  base::RunLoop().RunUntilIdle();
-
-  ChromeWebRtcLogMessageDelegate* log_message_delegate =
-      log_message_filter->log_message_delegate();
-
-  // Start logging on the IO loop.
-  message_loop.task_runner()->PostTask(
-      FROM_HERE, base::BindOnce(&ChromeWebRtcLogMessageDelegate::OnStartLogging,
-                                base::Unretained(log_message_delegate)));
-
-  // These log messages should be added to the log buffer outside of the IO
-  // loop.
-  log_message_delegate->LogMessage(kTestString);
-  log_message_delegate->LogMessage(kTestString);
-
-  // Stop logging on IO loop.
-  message_loop.task_runner()->PostTask(
-      FROM_HERE, base::BindOnce(&ChromeWebRtcLogMessageDelegate::OnStopLogging,
-                                base::Unretained(log_message_delegate)));
-
-  // This log message should not be added to the log buffer.
-  log_message_delegate->LogMessage(kTestString);
-
-  base::RunLoop().RunUntilIdle();
-
-  // Size is calculated as (sizeof(kTestString) - 1 for terminating null
-  // + 1 for eol added for each log message in LogMessage) * 2.
-  const uint32_t kExpectedSize = sizeof(kTestString) * 2;
-  EXPECT_EQ(kExpectedSize, log_message_filter->log_buffer_.size());
-
-  std::string ref_output = kTestString;
-  ref_output.append("\n");
-  ref_output.append(kTestString);
-  ref_output.append("\n");
-  EXPECT_STREQ(ref_output.c_str(), log_message_filter->log_buffer_.c_str());
-}
diff --git a/chrome/renderer/media/mock_webrtc_logging_message_filter.cc b/chrome/renderer/media/mock_webrtc_logging_message_filter.cc
deleted file mode 100644
index a6f715a3..0000000
--- a/chrome/renderer/media/mock_webrtc_logging_message_filter.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/renderer/media/mock_webrtc_logging_message_filter.h"
-
-#include <stddef.h>
-
-#include "base/logging.h"
-#include "base/single_thread_task_runner.h"
-
-MockWebRtcLoggingMessageFilter::MockWebRtcLoggingMessageFilter(
-    const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
-    : WebRtcLoggingMessageFilter(io_task_runner),
-      logging_stopped_(false) {
-}
-
-MockWebRtcLoggingMessageFilter::~MockWebRtcLoggingMessageFilter() {
-}
-
-void MockWebRtcLoggingMessageFilter::AddLogMessages(
-    const std::vector<WebRtcLoggingMessageData>& messages) {
-  CHECK(io_task_runner_->BelongsToCurrentThread());
-  for (size_t i = 0; i < messages.size(); ++i)
-    log_buffer_ += messages[i].message + "\n";
-}
-
-void MockWebRtcLoggingMessageFilter::LoggingStopped() {
-  CHECK(io_task_runner_->BelongsToCurrentThread());
-  logging_stopped_ = true;
-}
diff --git a/chrome/renderer/media/mock_webrtc_logging_message_filter.h b/chrome/renderer/media/mock_webrtc_logging_message_filter.h
deleted file mode 100644
index ea640a7..0000000
--- a/chrome/renderer/media/mock_webrtc_logging_message_filter.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_RENDERER_MEDIA_MOCK_WEBRTC_LOGGING_MESSAGE_FILTER_H_
-#define CHROME_RENDERER_MEDIA_MOCK_WEBRTC_LOGGING_MESSAGE_FILTER_H_
-
-#include "base/macros.h"
-#include "base/single_thread_task_runner.h"
-#include "chrome/renderer/media/webrtc_logging_message_filter.h"
-
-class MockWebRtcLoggingMessageFilter
-    : public WebRtcLoggingMessageFilter {
- public:
-  explicit MockWebRtcLoggingMessageFilter(
-      const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner);
-
-  void AddLogMessages(
-      const std::vector<WebRtcLoggingMessageData>& messages) override;
-  void LoggingStopped() override;
-
-  ChromeWebRtcLogMessageDelegate* log_message_delegate() {
-    return log_message_delegate_;
-  }
-
-  std::string log_buffer_;
-  bool logging_stopped_;
-
- protected:
-  ~MockWebRtcLoggingMessageFilter() override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(MockWebRtcLoggingMessageFilter);
-};
-
-#endif  // CHROME_RENDERER_MEDIA_MOCK_WEBRTC_LOGGING_MESSAGE_FILTER_H_
diff --git a/chrome/renderer/media/webrtc_logging_agent_impl.cc b/chrome/renderer/media/webrtc_logging_agent_impl.cc
new file mode 100644
index 0000000..b8b24d4
--- /dev/null
+++ b/chrome/renderer/media/webrtc_logging_agent_impl.cc
@@ -0,0 +1,134 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/renderer/media/webrtc_logging_agent_impl.h"
+
+#include "base/no_destructor.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/time/time.h"
+#include "third_party/blink/public/platform/modules/webrtc/webrtc_logging.h"
+
+namespace chrome {
+namespace {
+
+constexpr base::TimeDelta kMinTimeSinceLastLogBufferSend =
+    base::TimeDelta::FromMilliseconds(100);
+constexpr base::TimeDelta kSendLogBufferDelay =
+    base::TimeDelta::FromMilliseconds(200);
+
+// There can be only one registered WebRtcLogMessageDelegate, and so this class
+// abstracts away that detail, so that we can set callbacks more than once. It
+// also abstracts away the detail of what thread the LogMessage call runs on.
+class WebRtcLogMessageDelegateImpl : public blink::WebRtcLogMessageDelegate {
+ public:
+  static WebRtcLogMessageDelegateImpl* GetInstance() {
+    static base::NoDestructor<WebRtcLogMessageDelegateImpl> instance;
+    return instance.get();
+  }
+
+  void Start(
+      base::RepeatingCallback<void(mojom::WebRtcLoggingMessagePtr)> callback) {
+    auto task_runner = base::SequencedTaskRunnerHandle::Get();
+    {
+      base::AutoLock locked(lock_);
+      task_runner_ = task_runner;
+      callback_ = std::move(callback);
+    }
+    blink::InitWebRtcLogging();
+  }
+
+  void Stop() {
+    {
+      base::AutoLock locked(lock_);
+      task_runner_ = nullptr;
+      callback_.Reset();
+    }
+  }
+
+  // blink::WebRtcLogMessageDelegate methods:
+  void LogMessage(const std::string& message) override {
+    // Called from a random thread.
+    auto data = mojom::WebRtcLoggingMessage::New(base::Time::Now(), message);
+    {
+      base::AutoLock locked(lock_);
+      if (callback_)
+        task_runner_->PostTask(FROM_HERE,
+                               base::BindOnce(callback_, std::move(data)));
+    }
+  }
+
+  WebRtcLogMessageDelegateImpl() { blink::InitWebRtcLoggingDelegate(this); }
+
+ private:
+  ~WebRtcLogMessageDelegateImpl() override = default;
+
+  base::Lock lock_;
+  base::RepeatingCallback<void(mojom::WebRtcLoggingMessagePtr)> callback_;
+  scoped_refptr<base::SequencedTaskRunner> task_runner_;
+};
+
+}  // namespace
+
+WebRtcLoggingAgentImpl::WebRtcLoggingAgentImpl() = default;
+WebRtcLoggingAgentImpl::~WebRtcLoggingAgentImpl() = default;
+
+void WebRtcLoggingAgentImpl::AddReceiver(
+    mojo::PendingReceiver<mojom::WebRtcLoggingAgent> receiver) {
+  self_receiver_set_.Add(this, std::move(receiver));
+}
+
+void WebRtcLoggingAgentImpl::Start(
+    mojo::PendingRemote<mojom::WebRtcLoggingClient> pending_client) {
+  // We only support one client at a time. OK to drop any existing client.
+  client_.Bind(std::move(pending_client));
+
+  WebRtcLogMessageDelegateImpl::GetInstance()->Start(base::BindRepeating(
+      &WebRtcLoggingAgentImpl::OnNewMessage, weak_factory_.GetWeakPtr()));
+}
+
+void WebRtcLoggingAgentImpl::Stop() {
+  if (!log_buffer_.empty())
+    SendLogBuffer();
+  WebRtcLogMessageDelegateImpl::GetInstance()->Stop();
+  if (client_) {
+    client_->OnStopped();
+    client_.reset();
+  }
+}
+
+void WebRtcLoggingAgentImpl::OnNewMessage(
+    mojom::WebRtcLoggingMessagePtr message) {
+  // We may have already been asked to stop.
+  if (!client_)
+    return;
+
+  log_buffer_.emplace_back(std::move(message));
+  if (log_buffer_.size() > 1) {
+    // A delayed task has already been posted for sending the buffer contents.
+    return;
+  }
+
+  if ((base::TimeTicks::Now() - last_log_buffer_send_) >
+      kMinTimeSinceLastLogBufferSend) {
+    SendLogBuffer();
+  } else {
+    base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE,
+        base::BindOnce(&WebRtcLoggingAgentImpl::SendLogBuffer,
+                       weak_factory_.GetWeakPtr()),
+        kSendLogBufferDelay);
+  }
+}
+
+void WebRtcLoggingAgentImpl::SendLogBuffer() {
+  last_log_buffer_send_ = base::TimeTicks::Now();
+  if (client_) {
+    client_->OnAddMessages(std::move(log_buffer_));
+  } else {
+    log_buffer_.clear();
+  }
+}
+
+}  // namespace chrome
diff --git a/chrome/renderer/media/webrtc_logging_agent_impl.h b/chrome/renderer/media/webrtc_logging_agent_impl.h
new file mode 100644
index 0000000..d5698c20
--- /dev/null
+++ b/chrome/renderer/media/webrtc_logging_agent_impl.h
@@ -0,0 +1,43 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_RENDERER_MEDIA_WEBRTC_LOGGING_AGENT_IMPL_H_
+#define CHROME_RENDERER_MEDIA_WEBRTC_LOGGING_AGENT_IMPL_H_
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/common/media/webrtc_logging.mojom.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+
+namespace chrome {
+
+class WebRtcLoggingAgentImpl : public mojom::WebRtcLoggingAgent {
+ public:
+  WebRtcLoggingAgentImpl();
+  ~WebRtcLoggingAgentImpl() override;
+
+  void AddReceiver(mojo::PendingReceiver<mojom::WebRtcLoggingAgent> receiver);
+
+  // mojom::WebRtcLoggingAgent methods:
+  void Start(
+      mojo::PendingRemote<mojom::WebRtcLoggingClient> pending_client) override;
+  void Stop() override;
+
+ private:
+  void OnNewMessage(mojom::WebRtcLoggingMessagePtr message);
+  void SendLogBuffer();
+
+  mojo::ReceiverSet<mojom::WebRtcLoggingAgent> self_receiver_set_;
+  mojo::Remote<mojom::WebRtcLoggingClient> client_;
+  std::vector<mojom::WebRtcLoggingMessagePtr> log_buffer_;
+  base::TimeTicks last_log_buffer_send_;
+
+  base::WeakPtrFactory<WebRtcLoggingAgentImpl> weak_factory_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(WebRtcLoggingAgentImpl);
+};
+
+}  // namespace chrome
+
+#endif  // CHROME_RENDERER_MEDIA_WEBRTC_LOGGING_AGENT_IMPL_H_
diff --git a/chrome/renderer/media/webrtc_logging_agent_impl_unittest.cc b/chrome/renderer/media/webrtc_logging_agent_impl_unittest.cc
new file mode 100644
index 0000000..d4a9e4d
--- /dev/null
+++ b/chrome/renderer/media/webrtc_logging_agent_impl_unittest.cc
@@ -0,0 +1,99 @@
+// Copyright 2013 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 <stdint.h>
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/test/scoped_task_environment.h"
+#include "chrome/renderer/media/webrtc_logging_agent_impl.h"
+#include "mojo/public/cpp/bindings/unique_receiver_set.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/platform/modules/webrtc/webrtc_logging.h"
+
+namespace chrome {
+namespace {
+
+class WebRtcLoggingClientRecorder : public mojom::WebRtcLoggingClient {
+ public:
+  struct Log {
+    std::string buffer;
+    int on_stopped_count = 0;
+  };
+
+  explicit WebRtcLoggingClientRecorder(Log* log) : log_(log) {}
+  ~WebRtcLoggingClientRecorder() override = default;
+
+  // mojom::WebRtcLoggingClient methods:
+  void OnAddMessages(
+      std::vector<mojom::WebRtcLoggingMessagePtr> messages) override {
+    for (auto& message : messages) {
+      log_->buffer.append(message->data);
+      log_->buffer.append("\n");
+    }
+  }
+  void OnStopped() override { log_->on_stopped_count++; }
+
+ private:
+  Log* const log_;
+};
+
+}  // namespace
+
+TEST(WebRtcLoggingAgentImplTest, Basic) {
+  constexpr char kTestString[] = "abcdefghijklmnopqrstuvwxyz";
+
+  base::test::ScopedTaskEnvironment task_environment;
+
+  mojo::UniqueReceiverSet<mojom::WebRtcLoggingClient> client_set;
+
+  WebRtcLoggingAgentImpl agent;
+  WebRtcLoggingClientRecorder::Log log;
+
+  // Start agent.
+  {
+    mojo::PendingRemote<mojom::WebRtcLoggingClient> client;
+    client_set.Add(std::make_unique<WebRtcLoggingClientRecorder>(&log),
+                   client.InitWithNewPipeAndPassReceiver());
+    agent.Start(std::move(client));
+  }
+
+  base::RunLoop().RunUntilIdle();
+
+  // These log messages should be added to the log buffer.
+  blink::WebRtcLogMessage(kTestString);
+  blink::WebRtcLogMessage(kTestString);
+
+  base::RunLoop().RunUntilIdle();
+
+  // Stop logging messages.
+  agent.Stop();
+
+  base::RunLoop().RunUntilIdle();
+
+  // This log message should not be added to the log buffer.
+  blink::WebRtcLogMessage(kTestString);
+
+  base::RunLoop().RunUntilIdle();
+
+  // Size is calculated as (sizeof(kTestString) - 1 for terminating null
+  // + 1 for eol added for each log message in LogMessage) * 2.
+  constexpr uint32_t kExpectedSize = sizeof(kTestString) * 2;
+  EXPECT_EQ(kExpectedSize, log.buffer.size());
+
+  std::string ref_output = kTestString;
+  ref_output.append("\n");
+  ref_output.append(kTestString);
+  ref_output.append("\n");
+  EXPECT_STREQ(ref_output.c_str(), log.buffer.c_str());
+
+  EXPECT_EQ(1, log.on_stopped_count);
+}
+
+}  // namespace chrome
diff --git a/chrome/renderer/media/webrtc_logging_message_filter.cc b/chrome/renderer/media/webrtc_logging_message_filter.cc
deleted file mode 100644
index 474c3fd..0000000
--- a/chrome/renderer/media/webrtc_logging_message_filter.cc
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2013 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/renderer/media/webrtc_logging_message_filter.h"
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/single_thread_task_runner.h"
-#include "chrome/common/media/webrtc_logging_messages.h"
-#include "chrome/renderer/media/chrome_webrtc_log_message_delegate.h"
-#include "ipc/ipc_logging.h"
-
-WebRtcLoggingMessageFilter::WebRtcLoggingMessageFilter(
-    const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
-    : io_task_runner_(io_task_runner),
-      log_message_delegate_(NULL),
-      sender_(NULL) {
-  // May be null in a browsertest using MockRenderThread.
-  if (io_task_runner_.get()) {
-    io_task_runner_->PostTask(
-        FROM_HERE,
-        base::BindOnce(&WebRtcLoggingMessageFilter::CreateLoggingHandler,
-                       base::Unretained(this)));
-  }
-}
-
-WebRtcLoggingMessageFilter::~WebRtcLoggingMessageFilter() {
-}
-
-bool WebRtcLoggingMessageFilter::OnMessageReceived(
-    const IPC::Message& message) {
-  DCHECK(io_task_runner_->BelongsToCurrentThread());
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(WebRtcLoggingMessageFilter, message)
-    IPC_MESSAGE_HANDLER(WebRtcLoggingMsg_StartLogging, OnStartLogging)
-    IPC_MESSAGE_HANDLER(WebRtcLoggingMsg_StopLogging, OnStopLogging)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  return handled;
-}
-
-void WebRtcLoggingMessageFilter::OnFilterAdded(IPC::Channel* channel) {
-  DCHECK(!io_task_runner_.get() || io_task_runner_->BelongsToCurrentThread());
-  sender_ = channel;
-}
-
-void WebRtcLoggingMessageFilter::OnFilterRemoved() {
-  DCHECK(!io_task_runner_.get() || io_task_runner_->BelongsToCurrentThread());
-  sender_ = NULL;
-  log_message_delegate_->OnFilterRemoved();
-}
-
-void WebRtcLoggingMessageFilter::OnChannelClosing() {
-  DCHECK(!io_task_runner_.get() || io_task_runner_->BelongsToCurrentThread());
-  sender_ = NULL;
-  log_message_delegate_->OnFilterRemoved();
-}
-
-void WebRtcLoggingMessageFilter::AddLogMessages(
-    const std::vector<WebRtcLoggingMessageData>& messages) {
-  DCHECK(io_task_runner_->BelongsToCurrentThread());
-  Send(new WebRtcLoggingMsg_AddLogMessages(messages));
-}
-
-void WebRtcLoggingMessageFilter::LoggingStopped() {
-  DCHECK(!io_task_runner_.get() || io_task_runner_->BelongsToCurrentThread());
-  Send(new WebRtcLoggingMsg_LoggingStopped());
-}
-
-void WebRtcLoggingMessageFilter::CreateLoggingHandler() {
-  DCHECK(!io_task_runner_.get() || io_task_runner_->BelongsToCurrentThread());
-  log_message_delegate_ =
-      new ChromeWebRtcLogMessageDelegate(io_task_runner_, this);
-}
-
-void WebRtcLoggingMessageFilter::OnStartLogging() {
-  DCHECK(!io_task_runner_.get() || io_task_runner_->BelongsToCurrentThread());
-  log_message_delegate_->OnStartLogging();
-}
-
-void WebRtcLoggingMessageFilter::OnStopLogging() {
-  DCHECK(!io_task_runner_.get() || io_task_runner_->BelongsToCurrentThread());
-  log_message_delegate_->OnStopLogging();
-}
-
-void WebRtcLoggingMessageFilter::Send(IPC::Message* message) {
-  DCHECK(!io_task_runner_.get() || io_task_runner_->BelongsToCurrentThread());
-  if (!sender_) {
-    DLOG(ERROR) << "IPC sender not available.";
-    delete message;
-  } else {
-    sender_->Send(message);
-  }
-}
diff --git a/chrome/renderer/media/webrtc_logging_message_filter.h b/chrome/renderer/media/webrtc_logging_message_filter.h
deleted file mode 100644
index e22880d..0000000
--- a/chrome/renderer/media/webrtc_logging_message_filter.h
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2013 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_RENDERER_MEDIA_WEBRTC_LOGGING_MESSAGE_FILTER_H_
-#define CHROME_RENDERER_MEDIA_WEBRTC_LOGGING_MESSAGE_FILTER_H_
-
-#include "base/macros.h"
-#include "base/single_thread_task_runner.h"
-#include "chrome/common/media/webrtc_logging_message_data.h"
-#include "ipc/message_filter.h"
-
-class ChromeWebRtcLogMessageDelegate;
-
-// Filter for WebRTC logging messages. Sits between
-// ChromeWebRtcLogMessageDelegate (renderer process) and
-// WebRtcLoggingHandlerHost (browser process). Must be called on the IO thread.
-class WebRtcLoggingMessageFilter : public IPC::MessageFilter {
- public:
-  explicit WebRtcLoggingMessageFilter(
-      const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner);
-
-  virtual void AddLogMessages(
-      const std::vector<WebRtcLoggingMessageData>& messages);
-  virtual void LoggingStopped();
-
-  const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner() {
-    return io_task_runner_;
-  }
-
- protected:
-  ~WebRtcLoggingMessageFilter() override;
-
-  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
-
-  // Owned by this class. The only other pointer to it is in libjingle's logging
-  // file. That's a global pointer used on different threads, so we will leak
-  // this object when we go away to ensure that it outlives any log messages
-  // coming from libjingle.
-  // This is protected for unit test purposes.
-  // TODO(vrk): Remove ChromeWebRtcLogMessageDelegate's pointer to
-  // WebRtcLoggingMessageFilter so that we can write a unit test that doesn't
-  // need this accessor.
-  ChromeWebRtcLogMessageDelegate* log_message_delegate_;
-
- private:
-  // IPC::MessageFilter implementation.
-  bool OnMessageReceived(const IPC::Message& message) override;
-  void OnFilterAdded(IPC::Channel* channel) override;
-  void OnFilterRemoved() override;
-  void OnChannelClosing() override;
-
-  void CreateLoggingHandler();
-
-  void OnStartLogging();
-  void OnStopLogging();
-  void Send(IPC::Message* message);
-
-  IPC::Sender* sender_;
-
-  DISALLOW_COPY_AND_ASSIGN(WebRtcLoggingMessageFilter);
-};
-
-#endif  // CHROME_RENDERER_MEDIA_WEBRTC_LOGGING_MESSAGE_FILTER_H_
diff --git a/chrome/renderer/searchbox/searchbox_extension.cc b/chrome/renderer/searchbox/searchbox_extension.cc
index c5e3aa72..55fdaaae2 100644
--- a/chrome/renderer/searchbox/searchbox_extension.cc
+++ b/chrome/renderer/searchbox/searchbox_extension.cc
@@ -1040,6 +1040,7 @@
   if (!search_box)
     return;
   search_box->ToggleMostVisitedOrCustomLinks();
+  search_box->LogEvent(NTPLoggingEventType::NTP_CUSTOMIZE_SHORTCUT_TOGGLE_TYPE);
 }
 
 // static
@@ -1048,6 +1049,8 @@
   if (!search_box)
     return;
   search_box->ToggleShortcutsVisibility(do_notify);
+  search_box->LogEvent(
+      NTPLoggingEventType::NTP_CUSTOMIZE_SHORTCUT_TOGGLE_VISIBILITY);
 }
 
 // static
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 8173ce6..a7953e84 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -641,7 +641,7 @@
       "//chrome/renderer",
       "//chrome/services/removable_storage_writer:lib",
       "//components/autofill/content/browser:risk_proto",
-      "//components/autofill/content/common:mojo_interfaces",
+      "//components/autofill/content/common/mojom",
       "//components/autofill/content/renderer:test_support",
       "//components/captive_portal:test_support",
       "//components/cbor",
@@ -3909,7 +3909,7 @@
       "../common/media_router/discovery/media_sink_service_base_unittest.cc",
       "../common/media_router/mojo/media_router_struct_traits_unittest.cc",
       "../common/media_router/providers/cast/cast_media_source_unittest.cc",
-      "../renderer/media/chrome_webrtc_log_message_delegate_unittest.cc",
+      "../renderer/media/webrtc_logging_agent_impl_unittest.cc",
     ]
 
     deps += [
diff --git a/chrome/test/android/BUILD.gn b/chrome/test/android/BUILD.gn
index c8db5a5..22eb2bf7 100644
--- a/chrome/test/android/BUILD.gn
+++ b/chrome/test/android/BUILD.gn
@@ -7,12 +7,18 @@
 android_library("chrome_java_test_pagecontroller") {
   testonly = true
   java_files = [
+    "javatests/src/org/chromium/chrome/test/pagecontroller/controllers/android/PermissionDialog.java",
     "javatests/src/org/chromium/chrome/test/pagecontroller/controllers/ElementController.java",
-    "javatests/src/org/chromium/chrome/test/pagecontroller/controllers/PageController.java",
     "javatests/src/org/chromium/chrome/test/pagecontroller/controllers/first_run/DataSaverController.java",
     "javatests/src/org/chromium/chrome/test/pagecontroller/controllers/first_run/SyncController.java",
     "javatests/src/org/chromium/chrome/test/pagecontroller/controllers/first_run/TOSController.java",
+    "javatests/src/org/chromium/chrome/test/pagecontroller/controllers/notifications/DownloadNotificationController.java",
+    "javatests/src/org/chromium/chrome/test/pagecontroller/controllers/ntp/ChromeMenu.java",
+    "javatests/src/org/chromium/chrome/test/pagecontroller/controllers/ntp/IncognitoNewTabPageController.java",
     "javatests/src/org/chromium/chrome/test/pagecontroller/controllers/ntp/NewTabPageController.java",
+    "javatests/src/org/chromium/chrome/test/pagecontroller/controllers/ntp/SuggestionTileController.java",
+    "javatests/src/org/chromium/chrome/test/pagecontroller/controllers/PageController.java",
+    "javatests/src/org/chromium/chrome/test/pagecontroller/controllers/urlpage/UrlPage.java",
     "javatests/src/org/chromium/chrome/test/pagecontroller/rules/ChromeUiApplicationTestRule.java",
     "javatests/src/org/chromium/chrome/test/pagecontroller/rules/ChromeUiAutomatorTestRule.java",
     "javatests/src/org/chromium/chrome/test/pagecontroller/utils/BySelectorIndexUi2Locator.java",
@@ -27,8 +33,10 @@
     "javatests/src/org/chromium/chrome/test/pagecontroller/utils/Utils.java",
   ]
   deps = [
+    ":chrome_java_test_support",
     "//base:base_java",
     "//base:base_java_test_support",
+    "//chrome/android:chrome_java",
     "//third_party/android_support_test_runner:runner_java",
     "//third_party/junit",
     "//third_party/ub-uiautomator:ub_uiautomator_java",
@@ -44,6 +52,7 @@
   java_files = [
     "javatests/src/org/chromium/chrome/test/pagecontroller/tests/ExampleTest.java",
     "javatests/src/org/chromium/chrome/test/pagecontroller/tests/FirstRunControllerTest.java",
+    "javatests/src/org/chromium/chrome/test/pagecontroller/tests/NewTabPageControllerTest.java",
   ]
   deps = [
     ":chrome_java_test_pagecontroller",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/PageController.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/PageController.java
index db4e676..a43545d 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/PageController.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/PageController.java
@@ -6,6 +6,8 @@
 
 import android.os.RemoteException;
 
+import org.junit.Assert;
+
 /**
  * Base class for page controllers.
  * A page controller allows tests to interact with a single page (think Android activity)
@@ -36,4 +38,12 @@
      * @return True if current page can be controlled by this controller, else false.
      */
     public abstract boolean isCurrentPageThis();
+
+    /**
+     * Verifies that the current page belongs to the controller.
+     * @throws           AssertionError if the current page does not belong the controller.
+     */
+    public void verify() {
+        Assert.assertTrue("Page expected to be " + getClass().getName(), isCurrentPageThis());
+    }
 }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/android/PermissionDialog.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/android/PermissionDialog.java
new file mode 100644
index 0000000..92b9114
--- /dev/null
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/android/PermissionDialog.java
@@ -0,0 +1,46 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.test.pagecontroller.controllers.android;
+
+import org.chromium.chrome.test.pagecontroller.controllers.PageController;
+import org.chromium.chrome.test.pagecontroller.utils.IUi2Locator;
+import org.chromium.chrome.test.pagecontroller.utils.Ui2Locators;
+
+/**
+ * Android Permissions Dialog Page Controller.
+ */
+public class PermissionDialog extends PageController {
+    private static final IUi2Locator LOCATOR_PERMISSION_DIALOG =
+            Ui2Locators.withResName("com.android.packageinstaller:id/perm_desc_root");
+    private static final IUi2Locator LOCATOR_ALLOW =
+            Ui2Locators.withResName("com.android.packageinstaller:id/permission_allow_button");
+    private static final IUi2Locator LOCATOR_DENY =
+            Ui2Locators.withResName("com.android.packageinstaller:id/permission_deny_button");
+    private static final IUi2Locator LOCATOR_MESSAGE =
+            Ui2Locators.withResName("com.android.packageinstaller:id/permission_message");
+
+    private static final PermissionDialog sInstance = new PermissionDialog();
+    private PermissionDialog() {}
+    public static PermissionDialog getInstance() {
+        return sInstance;
+    }
+
+    public void clickAllow() {
+        mUtils.click(LOCATOR_ALLOW);
+    }
+
+    public void clickDeny() {
+        mUtils.click(LOCATOR_DENY);
+    }
+
+    public String getMessage() {
+        return mLocatorHelper.getOneText(LOCATOR_MESSAGE);
+    }
+
+    @Override
+    public boolean isCurrentPageThis() {
+        return mLocatorHelper.isOnScreen(LOCATOR_PERMISSION_DIALOG);
+    }
+}
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/first_run/DataSaverController.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/first_run/DataSaverController.java
index 2fb8e1d2..2f5e21f8 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/first_run/DataSaverController.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/first_run/DataSaverController.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.test.pagecontroller.controllers.first_run;
 
+import org.chromium.chrome.R;
 import org.chromium.chrome.test.pagecontroller.controllers.PageController;
 import org.chromium.chrome.test.pagecontroller.utils.IUi2Locator;
 import org.chromium.chrome.test.pagecontroller.utils.Ui2Locators;
@@ -13,10 +14,10 @@
  */
 public class DataSaverController extends PageController {
     private static final IUi2Locator LOCATOR_DATA_SAVER =
-            Ui2Locators.withResIds("enable_data_saver_switch");
-    private static final IUi2Locator LOCATOR_NEXT = Ui2Locators.withResIds("next_button");
+            Ui2Locators.withResEntries(R.id.enable_data_saver_switch);
+    private static final IUi2Locator LOCATOR_NEXT = Ui2Locators.withResEntries(R.id.next_button);
 
-    private static DataSaverController sInstance = new DataSaverController();
+    private static final DataSaverController sInstance = new DataSaverController();
     private DataSaverController() {}
     public static DataSaverController getInstance() {
         return sInstance;
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/first_run/SyncController.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/first_run/SyncController.java
index f4b818b..4259c74 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/first_run/SyncController.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/first_run/SyncController.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.test.pagecontroller.controllers.first_run;
 
+import org.chromium.chrome.R;
 import org.chromium.chrome.test.pagecontroller.controllers.PageController;
 import org.chromium.chrome.test.pagecontroller.utils.IUi2Locator;
 import org.chromium.chrome.test.pagecontroller.utils.Ui2Locators;
@@ -13,10 +14,11 @@
  */
 public class SyncController extends PageController {
     private final static IUi2Locator LOCATOR_SYNC_CONTROLLER =
-            Ui2Locators.withResIds("signin_sync_title");
-    private final static IUi2Locator LOCATOR_NO_THANKS = Ui2Locators.withResIds("negative_button");
+            Ui2Locators.withResEntries(R.id.signin_sync_title);
+    private final static IUi2Locator LOCATOR_NO_THANKS =
+            Ui2Locators.withResEntries(R.id.negative_button);
 
-    private static SyncController sInstance = new SyncController();
+    private static final SyncController sInstance = new SyncController();
     private SyncController() {}
     public static SyncController getInstance() {
         return sInstance;
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/first_run/TOSController.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/first_run/TOSController.java
index f4965abf..349e8c8 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/first_run/TOSController.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/first_run/TOSController.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.test.pagecontroller.controllers.first_run;
 
+import org.chromium.chrome.R;
 import org.chromium.chrome.test.pagecontroller.controllers.PageController;
 import org.chromium.chrome.test.pagecontroller.utils.IUi2Locator;
 import org.chromium.chrome.test.pagecontroller.utils.Ui2Locators;
@@ -12,12 +13,12 @@
  * TOS Dialog (part of the First Run Experience) Page Controller.
  */
 public class TOSController extends PageController {
-    private static final IUi2Locator LOCATOR_TOS = Ui2Locators.withResIds("tos_and_privacy");
+    private static final IUi2Locator LOCATOR_TOS = Ui2Locators.withResEntries(R.id.tos_and_privacy);
     private static final IUi2Locator LOCATOR_SEND_REPORT_CHECKBOX =
-            Ui2Locators.withResIds("send_report_checkbox");
-    private static final IUi2Locator LOCATOR_ACCEPT = Ui2Locators.withResIds("terms_accept");
+            Ui2Locators.withResEntries(R.id.send_report_checkbox);
+    private static final IUi2Locator LOCATOR_ACCEPT = Ui2Locators.withResEntries(R.id.terms_accept);
 
-    private static TOSController sInstance = new TOSController();
+    private static final TOSController sInstance = new TOSController();
     private TOSController() {}
     public static TOSController getInstance() {
         return sInstance;
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/notifications/DownloadNotificationController.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/notifications/DownloadNotificationController.java
new file mode 100644
index 0000000..2affc1a
--- /dev/null
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/notifications/DownloadNotificationController.java
@@ -0,0 +1,35 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.test.pagecontroller.controllers.notifications;
+
+import org.chromium.chrome.test.pagecontroller.controllers.PageController;
+import org.chromium.chrome.test.pagecontroller.utils.IUi2Locator;
+import org.chromium.chrome.test.pagecontroller.utils.Ui2Locators;
+
+/**
+ * Download Permissions Dialog (download for offline viewing) Page Controller.
+ */
+public class DownloadNotificationController extends PageController {
+    private static final IUi2Locator LOCATOR_DOWNLOAD_NOTIFICATION =
+            Ui2Locators.withTextContaining("needs storage access to download files");
+    private static final IUi2Locator LOCATOR_CONTINUE =
+            Ui2Locators.withResEntries(android.R.id.button1);
+
+    private static final DownloadNotificationController sInstance =
+            new DownloadNotificationController();
+    private DownloadNotificationController() {}
+    public static DownloadNotificationController getInstance() {
+        return sInstance;
+    }
+
+    public void clickContinue() {
+        mUtils.click(LOCATOR_CONTINUE);
+    }
+
+    @Override
+    public boolean isCurrentPageThis() {
+        return mLocatorHelper.isOnScreen(LOCATOR_DOWNLOAD_NOTIFICATION);
+    }
+}
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/ntp/ChromeMenu.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/ntp/ChromeMenu.java
new file mode 100644
index 0000000..1fe67ab
--- /dev/null
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/ntp/ChromeMenu.java
@@ -0,0 +1,57 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.test.pagecontroller.controllers.ntp;
+
+import org.chromium.chrome.R;
+import org.chromium.chrome.test.pagecontroller.controllers.PageController;
+import org.chromium.chrome.test.pagecontroller.utils.IUi2Locator;
+import org.chromium.chrome.test.pagecontroller.utils.Ui2Locators;
+
+/**
+ * Chrome Menu (NTP 3-dot menu) Page Controller.
+ */
+public class ChromeMenu extends PageController {
+    private static final IUi2Locator LOCATOR_CHROME_MENU_BOX =
+            Ui2Locators.withResEntries(R.id.app_menu_list);
+    private static final IUi2Locator LOCATOR_CHROME_MENU = Ui2Locators.withPath(
+            LOCATOR_CHROME_MENU_BOX, Ui2Locators.withResEntries(R.id.button_five));
+
+    private static final IUi2Locator LOCATOR_NEW_TAB =
+            Ui2Locators.withResEntriesByIndex(0, R.id.menu_item_text);
+    private static final IUi2Locator LOCATOR_NEW_INCOGNITO_TAB =
+            Ui2Locators.withResEntriesByIndex(1, R.id.menu_item_text);
+
+    private static final ChromeMenu sInstance = new ChromeMenu();
+    private ChromeMenu() {}
+    static public ChromeMenu getInstance() {
+        return sInstance;
+    }
+
+    @Override
+    public boolean isCurrentPageThis() {
+        return mLocatorHelper.isOnScreen(LOCATOR_CHROME_MENU);
+    }
+
+    public NewTabPageController openNewTab() {
+        mUtils.click(LOCATOR_NEW_TAB);
+        NewTabPageController inst = NewTabPageController.getInstance();
+        inst.verify();
+        return inst;
+    }
+
+    public IncognitoNewTabPageController openNewIncognitoTab() {
+        mUtils.click(LOCATOR_NEW_INCOGNITO_TAB);
+        IncognitoNewTabPageController inst = IncognitoNewTabPageController.getInstance();
+        inst.verify();
+        return inst;
+    }
+
+    public NewTabPageController dismiss() {
+        mUtils.clickOutsideOf(LOCATOR_CHROME_MENU_BOX);
+        NewTabPageController inst = NewTabPageController.getInstance();
+        inst.verify();
+        return inst;
+    }
+}
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/ntp/IncognitoNewTabPageController.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/ntp/IncognitoNewTabPageController.java
new file mode 100644
index 0000000..8c032d4
--- /dev/null
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/ntp/IncognitoNewTabPageController.java
@@ -0,0 +1,30 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.test.pagecontroller.controllers.ntp;
+
+import org.chromium.chrome.R;
+import org.chromium.chrome.test.pagecontroller.controllers.PageController;
+import org.chromium.chrome.test.pagecontroller.utils.IUi2Locator;
+import org.chromium.chrome.test.pagecontroller.utils.Ui2Locators;
+
+/**
+ * Incognito NTP Page Controller.
+ */
+public class IncognitoNewTabPageController extends PageController {
+    private static final IUi2Locator LOCATOR_INCOGNITO_PAGE =
+            Ui2Locators.withResEntries(R.id.new_tab_incognito_container);
+
+    private static final IncognitoNewTabPageController sInstance =
+            new IncognitoNewTabPageController();
+    private IncognitoNewTabPageController() {}
+    public static IncognitoNewTabPageController getInstance() {
+        return sInstance;
+    }
+
+    @Override
+    public boolean isCurrentPageThis() {
+        return mLocatorHelper.isOnScreen(LOCATOR_INCOGNITO_PAGE);
+    }
+}
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/ntp/NewTabPageController.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/ntp/NewTabPageController.java
index 8d028b8..7375b3d 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/ntp/NewTabPageController.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/ntp/NewTabPageController.java
@@ -4,23 +4,212 @@
 
 package org.chromium.chrome.test.pagecontroller.controllers.ntp;
 
+import org.chromium.chrome.R;
 import org.chromium.chrome.test.pagecontroller.controllers.PageController;
+import org.chromium.chrome.test.pagecontroller.controllers.urlpage.UrlPage;
 import org.chromium.chrome.test.pagecontroller.utils.IUi2Locator;
 import org.chromium.chrome.test.pagecontroller.utils.Ui2Locators;
 
+import java.util.List;
+
 /**
  * New Tab Page Page Controller, handles either Feed or Zine implementations.
  */
 public class NewTabPageController extends PageController {
-    private static final IUi2Locator LOCATOR_NEW_TAB_PAGE =
-            Ui2Locators.withResIds("ntp_content", "feed_stream_recycler_view", "card_contents");
+    private static final float SCROLL_SWIPE_FRACTION = 0.6f;
+    private static final float MAX_LOAD_ARTICLES_WAIT = 5000f;
+    // The test will timeout for Small and Medium sizes before 50 swipes is
+    // reached.  This number is set so that it should not be hit if everything
+    // is working fine.  Please bump it up if test cases exceeding 50 swipes
+    // becomes common.
+    private static final int MAX_SCROLL_SWIPES = 50;
 
-    private static NewTabPageController sInstance = new NewTabPageController();
-    private NewTabPageController() {}
+    private static final String TEXT_HEADER_STATUS_HIDE = "Hide";
+    private static final String TEXT_HEADER_STATUS_SHOW = "Show";
+    private static final String REGEX_TEXT_HEADER_STATUS = "^Hide|Show$";
+
+    private static final IUi2Locator LOCATOR_SEARCH_BOX_TEXT =
+            Ui2Locators.withResEntries(R.id.search_box_text);
+    private static final IUi2Locator LOCATOR_URL_BAR = Ui2Locators.withResEntries(R.id.url_bar);
+    private static final IUi2Locator LOCATOR_SEARCH_PROVIDER_LOGO =
+            Ui2Locators.withResEntries(R.id.search_provider_logo);
+    private static final IUi2Locator LOCATOR_MORE_BUTTON =
+            Ui2Locators.withResEntries(R.id.action_button);
+    private static final IUi2Locator LOCATOR_MENU_BUTTON =
+            Ui2Locators.withResEntries(R.id.menu_button);
+    private static final IUi2Locator LOCATOR_BOTTOM_OF_PAGE =
+            Ui2Locators.withResEntries(R.id.progress_indicator, R.id.action_button);
+    private static final IUi2Locator LOCATOR_FEED_STREAM_RECYCLER_VIEW = Ui2Locators.withResEntries(
+            com.google.android.libraries.feed.basicstream.R.id.feed_stream_recycler_view);
+    private static final IUi2Locator LOCATOR_HEADER_STATUS =
+            Ui2Locators.withPath(Ui2Locators.withResEntries(R.id.header_status),
+                    Ui2Locators.withTextRegex(REGEX_TEXT_HEADER_STATUS));
+    private static final IUi2Locator LOCATOR_INFO_BAR_MESSAGE =
+            Ui2Locators.withResEntries(R.id.infobar_message, R.id.snackbar_message);
+    private static final IUi2Locator LOCATOR_INFO_BAR_CLOSE =
+            Ui2Locators.withResEntries(R.id.infobar_close_button);
+
+    private static final IUi2Locator LOCATOR_TAB_SWITCHER =
+            Ui2Locators.withResEntries(R.id.tab_switcher_button);
+
+    private static final IUi2Locator LOCATOR_NEW_TAB_PAGE =
+            Ui2Locators.withResEntries(R.id.ntp_content,
+                    com.google.android.libraries.feed.basicstream.R.id.feed_stream_recycler_view,
+                    R.id.card_contents);
+
+    private SuggestionTileController mSuggestionsTileController;
+
+    private static final NewTabPageController sInstance = new NewTabPageController();
+    private NewTabPageController() {
+        mSuggestionsTileController = SuggestionTileController.getInstance();
+    }
     public static NewTabPageController getInstance() {
         return sInstance;
     }
 
+    /**
+     * Hide articles if shown, and vice-versa.  This will cause page to scroll to where the
+     * show/hide articles button is visible.
+     */
+    public void toggleHideArticles() {
+        scrollToTop();
+        mUtils.swipeUpVerticallyUntilFound(LOCATOR_HEADER_STATUS, LOCATOR_MORE_BUTTON);
+        mUtils.click(LOCATOR_HEADER_STATUS);
+    }
+
+    /**
+     * This will cause page to scroll to where the show/hide articles button is visible.
+     * @return True if articles are currently hidden as indicated by the presence of the
+     *         show/hide articles button, else false.
+     */
+    public boolean areArticlesHidden() {
+        scrollToTop();
+
+        String status_text = mLocatorHelper.getOneText(LOCATOR_HEADER_STATUS);
+
+        // The ariticles are hidden if "Show" is displayed, appears to be reversed but makes UI
+        // sense since the user can click on "Show" to unhide them.
+        if (status_text.equals(TEXT_HEADER_STATUS_HIDE)) {
+            return false;
+        } else if (status_text.equals(TEXT_HEADER_STATUS_SHOW)) {
+            return true;
+        } else {
+            throw new IllegalStateException("Bad status text: " + status_text);
+        }
+    }
+
+    public void scrollTowardsTop(float screenHeightPercentage) {
+        mUtils.swipeDownVertically(screenHeightPercentage);
+    }
+
+    public void scrollTowardsBottom(float screenHeightPercentage) {
+        mUtils.swipeUpVertically(screenHeightPercentage);
+    }
+
+    public void clickInfoBarMessage() {
+        mUtils.click(LOCATOR_INFO_BAR_MESSAGE);
+    }
+
+    public String getInfoBarMessage() {
+        return mLocatorHelper.getOneText(LOCATOR_INFO_BAR_MESSAGE);
+    }
+
+    public NewTabPageController closeInfoBar() {
+        mUtils.click(LOCATOR_INFO_BAR_CLOSE);
+        return this;
+    }
+
+    public boolean hasScrolledToBottom() {
+        // If TEXT_HEADER_STATUS_SHOW is displayed, it means articles are hidden.
+        IUi2Locator locator = Ui2Locators.withPath(
+                LOCATOR_HEADER_STATUS, Ui2Locators.withTextRegex(TEXT_HEADER_STATUS_SHOW));
+        if (mLocatorHelper.isOnScreen(locator)) {
+            return true;
+        } else {
+            return mLocatorHelper.isOnScreen(LOCATOR_MORE_BUTTON);
+        }
+    }
+
+    public boolean hasScrolledToTop() {
+        return mLocatorHelper.isOnScreen(LOCATOR_SEARCH_PROVIDER_LOGO);
+    }
+
+    public void scrollToBottom() {
+        scrollToBottom(MAX_SCROLL_SWIPES);
+    }
+
+    public void scrollToBottom(int maxSwipes) {
+        int swipes = 0;
+        while (swipes++ < maxSwipes && !hasScrolledToBottom()) {
+            scrollTowardsBottom(SCROLL_SWIPE_FRACTION);
+        }
+    }
+
+    public void scrollToTop() {
+        scrollToTop(MAX_SCROLL_SWIPES);
+    }
+
+    public void scrollToTop(int maxSwipes) {
+        for (int swipes = 0; swipes < maxSwipes && !hasScrolledToTop(); swipes++) {
+            scrollTowardsTop(SCROLL_SWIPE_FRACTION);
+        }
+    }
+
+    /**
+     * Get all suggestion tiles.  This will cause the page to scroll to the top.
+     * @return List of suggestion infos, possibly empty.
+     */
+    public List<SuggestionTileController.Info> getAllSuggestionTiles() {
+        // Suggestion tiles are currently at the top of the NTP, so need to ensure page is
+        // scrolled to the top, otherwise they may be offscreen.
+        scrollToTop();
+        return mSuggestionsTileController.parseScreen();
+    }
+
+    /**
+     * The default action is the one that gets performed when the user taps on the tile icon
+     * (opens site in a new page).  If user long taps, then a menu is shown providing more choices
+     * (not yet implemented).  This will cause the page to scroll to the top.
+     */
+    public UrlPage performDefaultSuggestionTileAction(SuggestionTileController.Info tile) {
+        scrollToTop();
+        IUi2Locator locator = mSuggestionsTileController.getLocator(tile);
+        mUtils.swipeUpVerticallyUntilFound(locator, LOCATOR_BOTTOM_OF_PAGE);
+        mUtils.click(locator);
+        UrlPage inst = UrlPage.getInstance();
+        inst.verify();
+        return inst;
+    }
+
+    /**
+     * Click the load more aritcles button at the bottom of the page.  This will cause the page
+     * to scroll to the bottom.
+     */
+    public void clickLoadMoreArticles() {
+        scrollToBottom();
+        mUtils.click(LOCATOR_MORE_BUTTON);
+    }
+
+    /**
+     * Open the 3-dot menu at the top.  This will cause the page to scroll to the top.
+     * @return The ChromeMenu Page Controller.
+     */
+    public ChromeMenu openChromeMenu() {
+        scrollToTop();
+        mUtils.click(LOCATOR_MENU_BUTTON);
+        ChromeMenu inst = ChromeMenu.getInstance();
+        inst.verify();
+        return inst;
+    }
+
+    public UrlPage omniboxSearch(String url) {
+        mUtils.click(LOCATOR_SEARCH_BOX_TEXT);
+        mUtils.setTextAndEnter(LOCATOR_URL_BAR, url);
+        UrlPage inst = UrlPage.getInstance();
+        inst.verify();
+        return inst;
+    }
+
     @Override
     public boolean isCurrentPageThis() {
         return mLocatorHelper.isOnScreen(LOCATOR_NEW_TAB_PAGE);
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/ntp/SuggestionTileController.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/ntp/SuggestionTileController.java
new file mode 100644
index 0000000..f7df404
--- /dev/null
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/ntp/SuggestionTileController.java
@@ -0,0 +1,106 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.test.pagecontroller.controllers.ntp;
+
+import static org.chromium.chrome.test.pagecontroller.utils.Ui2Locators.withText;
+
+import android.support.test.uiautomator.UiObject2;
+
+import org.chromium.chrome.R;
+import org.chromium.chrome.test.pagecontroller.controllers.ElementController;
+import org.chromium.chrome.test.pagecontroller.utils.IUi2Locator;
+import org.chromium.chrome.test.pagecontroller.utils.Ui2Locators;
+import org.chromium.chrome.test.pagecontroller.utils.UiLocationException;
+import org.chromium.chrome.test.pagecontroller.utils.UiLocatorHelper;
+
+import java.util.List;
+
+/**
+ * Suggestions Tile (below the Omnibox) Element Controller.
+ */
+public class SuggestionTileController extends ElementController {
+    /**
+     * Represents a single tile, can be used by the NewTabPageController
+     * to perform actions.
+     */
+    public static class Info {
+        private String mTitle;
+
+        public Info(String title) {
+            mTitle = title;
+        }
+
+        public String getTitle() {
+            return mTitle;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (!(o instanceof Info)) return false;
+            Info info = (Info) o;
+            return mTitle.equals(info.mTitle);
+        }
+
+        @Override
+        public int hashCode() {
+            return mTitle.hashCode();
+        }
+
+        @Override
+        public String toString() {
+            return "Info{"
+                    + "mTitle='" + mTitle + '\'' + '}';
+        }
+    }
+
+    private static final IUi2Locator LOCATOR_TILE_TITLES =
+            Ui2Locators.withPath(Ui2Locators.withResEntries(R.id.tile_grid_layout),
+                    Ui2Locators.withResEntries(R.id.tile_view_title));
+    private static final IUi2Locator LOCATOR_TILE_TITLE_TEXT = Ui2Locators.withTextRegex(".+");
+
+    private static final SuggestionTileController sInstance = new SuggestionTileController();
+    private SuggestionTileController() {}
+    public static SuggestionTileController getInstance() {
+        return sInstance;
+    }
+
+    /**
+     * Get list of tiles.
+     * @return  List of Infos representing each tile on the screen, or empty list if non are found.
+     */
+    public List<Info> parseScreen() {
+        List<String> titles = mLocatorHelper.getAllTexts(LOCATOR_TILE_TITLES);
+        List<Info> infos = mLocatorHelper.getCustomElements(
+                LOCATOR_TILE_TITLES, new UiLocatorHelper.CustomElementMaker<Info>() {
+                    @Override
+                    public Info makeElement(UiObject2 root, boolean isLastAttempt) {
+                        String title =
+                                mLocatorHelper.getOneTextImmediate(LOCATOR_TILE_TITLE_TEXT, root);
+                        if (title != null) {
+                            return new Info(title);
+                        } else if (!isLastAttempt) {
+                            // Not the last attempt yet, so makeElement will be
+                            // called again if we throw an exception.  This
+                            // gives a chance for the title UI of the tile to
+                            // load.
+                            throw UiLocationException.newInstance(
+                                    "Title is null", LOCATOR_TILE_TITLES, root);
+                        } else {
+                            // This is the last attempt.  It is possible that
+                            // no complete tiles are found on the screen, just
+                            // return null to signal that no tile was found.
+                            return null;
+                        }
+                    }
+                });
+
+        return infos;
+    }
+
+    public IUi2Locator getLocator(Info tileInfo) {
+        return Ui2Locators.withPath(LOCATOR_TILE_TITLES, withText(tileInfo.getTitle()));
+    }
+}
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/urlpage/UrlPage.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/urlpage/UrlPage.java
new file mode 100644
index 0000000..977fc46
--- /dev/null
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/urlpage/UrlPage.java
@@ -0,0 +1,49 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.test.pagecontroller.controllers.urlpage;
+
+import org.chromium.chrome.R;
+import org.chromium.chrome.test.pagecontroller.controllers.PageController;
+import org.chromium.chrome.test.pagecontroller.utils.IUi2Locator;
+import org.chromium.chrome.test.pagecontroller.utils.Ui2Locators;
+import org.chromium.chrome.test.pagecontroller.utils.UiLocatorHelper;
+
+/**
+ * Url Page (showing a loaded URL) Page Controller.
+ */
+// TODO(aluo): merge incognito page into this.
+public class UrlPage extends PageController {
+    private static final long PAGE_LOAD_TIMEOUT = 10000L;
+    private static final IUi2Locator LOCATOR_WEB_VIEW =
+            Ui2Locators.withPath(Ui2Locators.withResEntries(R.id.content),
+                    Ui2Locators.withClassRegex("android\\.webkit\\.WebView"));
+    private static final IUi2Locator LOCATOR_URL_BAR = Ui2Locators.withResEntries(R.id.url_bar);
+    private static final IUi2Locator LOCATOR_TAB_SWITCHER =
+            Ui2Locators.withResEntries(R.id.tab_switcher_button);
+    private static final IUi2Locator LOCATOR_MENU = Ui2Locators.withResEntries(R.id.menu_button);
+
+    private static final UrlPage sInstance = new UrlPage();
+    private UrlPage() {}
+    public static UrlPage getInstance() {
+        return sInstance;
+    }
+
+    @Override
+    public boolean isCurrentPageThis() {
+        long savedTimeout = mUtils.getTimeout();
+        UiLocatorHelper helper = mUtils.getLocatorHelper(PAGE_LOAD_TIMEOUT);
+        return helper.isOnScreen(LOCATOR_WEB_VIEW);
+    }
+
+    public String getUrl() {
+        return mLocatorHelper.getOneText(LOCATOR_URL_BAR);
+    }
+
+    public boolean isTextFoundAtCurrentScroll(String text) {
+        IUi2Locator locator =
+                Ui2Locators.withPath(LOCATOR_WEB_VIEW, Ui2Locators.withTextContaining(text));
+        return mLocatorHelper.isOnScreen(locator);
+    }
+}
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/rules/ChromeUiApplicationTestRule.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/rules/ChromeUiApplicationTestRule.java
index 68b39b5..3d56ac86 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/rules/ChromeUiApplicationTestRule.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/rules/ChromeUiApplicationTestRule.java
@@ -8,7 +8,16 @@
 
 import org.junit.rules.ExternalResource;
 
+import org.chromium.base.Log;
 import org.chromium.chrome.test.pagecontroller.controllers.PageController;
+import org.chromium.chrome.test.pagecontroller.controllers.android.PermissionDialog;
+import org.chromium.chrome.test.pagecontroller.controllers.first_run.DataSaverController;
+import org.chromium.chrome.test.pagecontroller.controllers.first_run.SyncController;
+import org.chromium.chrome.test.pagecontroller.controllers.first_run.TOSController;
+import org.chromium.chrome.test.pagecontroller.controllers.notifications.DownloadNotificationController;
+import org.chromium.chrome.test.pagecontroller.controllers.ntp.ChromeMenu;
+import org.chromium.chrome.test.pagecontroller.controllers.ntp.IncognitoNewTabPageController;
+import org.chromium.chrome.test.pagecontroller.controllers.ntp.NewTabPageController;
 import org.chromium.chrome.test.pagecontroller.utils.UiAutomatorUtils;
 import org.chromium.chrome.test.pagecontroller.utils.UiLocationException;
 
@@ -17,7 +26,8 @@
  */
 public class ChromeUiApplicationTestRule extends ExternalResource {
     // TODO(aluo): Adjust according to https://crrev.com/c/1585142.
-    private static final String PACKAGE_NAME_ARG = "PackageUnderTest";
+    public static final String PACKAGE_NAME_ARG = "PackageUnderTest";
+    private static final String TAG = "ChromeUiAppTR";
 
     private String mPackageName;
 
@@ -29,19 +39,65 @@
      */
     public static PageController detectPageAmong(PageController... controllers) {
         for (PageController instance : controllers) {
-            if (instance.isCurrentPageThis()) return instance;
+            if (instance.isCurrentPageThis()) {
+                Log.d(TAG, "Detected " + instance.getClass().getName());
+                return instance;
+            }
         }
         throw UiLocationException.newInstance("Could not detect current Page");
     }
 
     /**
-     * Launch the Chrome application.
+     * Detect the page controller from among all page controllers.
+     * When a new page controller is implemented, add it to the list here.
+     * @return                 The detected page controller.
+     * @throws UiLocationError If page can't be determined.
      */
+    public static PageController detectCurrentPage() {
+        return detectPageAmong(NewTabPageController.getInstance(), SyncController.getInstance(),
+                DataSaverController.getInstance(), TOSController.getInstance(),
+                DownloadNotificationController.getInstance(), PermissionDialog.getInstance(),
+                IncognitoNewTabPageController.getInstance(), ChromeMenu.getInstance());
+    }
+
+    /** Launch the chrome application */
     public void launchApplication() {
         UiAutomatorUtils utils = UiAutomatorUtils.getInstance();
         utils.launchApplication(mPackageName);
     }
 
+    /** Navigate to the New Tab Page from somewhere in the application. */
+    public NewTabPageController navigateToNewTabPage() {
+        PageController controller = detectCurrentPage();
+        if (controller instanceof TOSController) {
+            ((TOSController) controller).acceptAndContinue();
+            controller = detectCurrentPage();
+        }
+        if (controller instanceof DataSaverController) {
+            ((DataSaverController) controller).clickNext();
+            controller = detectCurrentPage();
+        }
+        if (controller instanceof SyncController) {
+            ((SyncController) controller).clickNoThanks();
+            controller = detectCurrentPage();
+        }
+        if (controller instanceof ChromeMenu) {
+            controller = ((ChromeMenu) controller).dismiss();
+        }
+        if (controller instanceof NewTabPageController) {
+            return (NewTabPageController) controller;
+        } else {
+            throw UiLocationException.newInstance(
+                    "Could not navigate to new tab page from " + controller.getClass().getName());
+        }
+    }
+
+    /** Launch the application and navigate to the New Tab Page */
+    public NewTabPageController launchIntoNewTabPage() {
+        launchApplication();
+        return navigateToNewTabPage();
+    }
+
     public String getApplicationPackage() {
         return mPackageName;
     }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/tests/NewTabPageControllerTest.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/tests/NewTabPageControllerTest.java
new file mode 100644
index 0000000..bdbb2bd
--- /dev/null
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/tests/NewTabPageControllerTest.java
@@ -0,0 +1,78 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.test.pagecontroller.tests;
+
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.BaseJUnit4ClassRunner;
+import org.chromium.chrome.test.pagecontroller.controllers.ntp.ChromeMenu;
+import org.chromium.chrome.test.pagecontroller.controllers.ntp.NewTabPageController;
+import org.chromium.chrome.test.pagecontroller.controllers.urlpage.UrlPage;
+import org.chromium.chrome.test.pagecontroller.rules.ChromeUiApplicationTestRule;
+import org.chromium.chrome.test.pagecontroller.rules.ChromeUiAutomatorTestRule;
+
+/**
+ * Tests for the NewTabPageController.
+ */
+@SmallTest
+@RunWith(BaseJUnit4ClassRunner.class)
+public class NewTabPageControllerTest {
+    public ChromeUiAutomatorTestRule mRule = new ChromeUiAutomatorTestRule();
+
+    public ChromeUiApplicationTestRule mChromeUiRule = new ChromeUiApplicationTestRule();
+
+    @Rule
+    public final TestRule mChain = RuleChain.outerRule(mChromeUiRule).around(mRule);
+
+    private NewTabPageController mController;
+
+    @Before
+    public void setUp() {
+        mController = mChromeUiRule.launchIntoNewTabPage();
+    }
+
+    @Test
+    public void testIsCurrentPageThis() {
+        Assert.assertTrue(mController.isCurrentPageThis());
+    }
+
+    @Test
+    public void testHideArticles() {
+        boolean isHidden = mController.areArticlesHidden();
+        mController.toggleHideArticles();
+        assertNotEquals(isHidden, mController.areArticlesHidden());
+    }
+
+    @Test
+    public void testScrollPage() {
+        mController.scrollToTop();
+        assertTrue(mController.hasScrolledToTop());
+        mController.scrollToBottom();
+        assertTrue(mController.hasScrolledToBottom());
+    }
+
+    @Test
+    public void testOpenChromeMenu() {
+        ChromeMenu menu = mController.openChromeMenu();
+        Assert.assertTrue(menu.isCurrentPageThis());
+    }
+
+    @Test
+    public void testOmniboxSearch() {
+        UrlPage urlPage = mController.omniboxSearch("www.google.com");
+        Assert.assertTrue(urlPage.isCurrentPageThis());
+    }
+}
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/utils/Ui2Locators.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/utils/Ui2Locators.java
index 616237d1..0841e358 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/utils/Ui2Locators.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/utils/Ui2Locators.java
@@ -4,7 +4,9 @@
 
 package org.chromium.chrome.test.pagecontroller.utils;
 
+import android.support.annotation.IdRes;
 import android.support.annotation.NonNull;
+import android.support.test.InstrumentationRegistry;
 import android.support.test.uiautomator.By;
 
 import java.util.regex.Pattern;
@@ -69,6 +71,55 @@
         stringBuilder.append(")");
         return withResIdRegex(stringBuilder.toString());
     }
+
+    /**
+     * Locates the node(s) having a resource id name among a list of names (excluding the
+     * package:id/ part).
+     *
+     * @param index         The value of n.
+     * @param firstId       The first id to match against.
+     * @param additionalIds Optional ids to match against.
+     * @return       A locator that will find the nth node whose id matches.
+     */
+    public static IUi2Locator withResIdsByIndex(
+            int index, String firstId, String... additionalIds) {
+        StringBuilder stringBuilder = new StringBuilder();
+        stringBuilder.append("(");
+        stringBuilder.append(firstId);
+        for (int i = 0; i < additionalIds.length; i++) {
+            stringBuilder.append("|" + additionalIds[i]);
+        }
+        stringBuilder.append(")");
+        return withResNameRegexByIndex("^.*:id/" + stringBuilder.toString() + "$", index);
+    }
+
+    /**
+     * Returns a locator that find node(s) matching any one of R.id.* entry names (ignoring the
+     * package name).
+     *
+     * @param id             The layout resource id of the corresponding view node.
+     * @param additionalIds  Optional additional layout resource ids to match.
+     * @return               A locator that will match against the any of the ids.
+     */
+    public static IUi2Locator withResEntries(@IdRes int id, @IdRes int... additionalIds) {
+        return withResIds(getResourceEntryName(id), getResourceEntryNames(additionalIds));
+    }
+
+    /**
+     * Returns a locator that find the nth node matching any one of R.id.* entry names (ignoring
+     * the package name).
+     *
+     * @param index          The index into the list of matching nodes.
+     * @param id             The layout resource id of the corresponding view node.
+     * @param additionalIds  Optional additional layout resource ids to match.
+     * @return               A locator that will find the nth node whose id matches.
+     */
+    public static IUi2Locator withResEntriesByIndex(
+            int index, @IdRes int id, @IdRes int... additionalIds) {
+        return withResIdsByIndex(
+                index, getResourceEntryName(id), getResourceEntryNames(additionalIds));
+    }
+
     /**
      * Locates the node(s) having an exact resource name (including the package:id/ part).
      *
@@ -192,4 +243,30 @@
     public static IUi2Locator withPackageName(@NonNull String packageName) {
         return new BySelectorUi2Locator(By.pkg(packageName));
     }
+
+    /**
+     * This converts the integer resource ids to string resource entry names so
+     * that UIAutomator can be used to located them.
+     *
+     * @param id The layout resource id of the corresponding view node.
+     * @return   String resource entry name for id.
+     */
+    private static String getResourceEntryName(@IdRes int id) {
+        return InstrumentationRegistry.getTargetContext().getResources().getResourceEntryName(id);
+    }
+
+    /**
+     * This converts the integer resource ids to string resource entry names so
+     * that UIAutomator can be used to located them.
+     *
+     * @param ids The layout resource id of the corresponding view node.
+     * @return    Array of string resource entry names for ids.
+     */
+    private static String[] getResourceEntryNames(@IdRes int... ids) {
+        String[] names = new String[(ids.length)];
+        for (int i = 0; i < ids.length; i++) {
+            names[i] = getResourceEntryName(ids[i]);
+        }
+        return names;
+    }
 }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/utils/UiAutomatorUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/utils/UiAutomatorUtils.java
index 547dfb66..3f784f7 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/utils/UiAutomatorUtils.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/utils/UiAutomatorUtils.java
@@ -76,14 +76,6 @@
     }
 
     /**
-     * Set the timeout used for location operations.
-     * @param timeout Timeout in milliseconds.
-     */
-    public void setTimeout(long timeout) {
-        mLocatorHelper.setTimeout(timeout);
-    }
-
-    /**
      * Launch application.
      * @param packageName Package name of the application.
      */
@@ -144,11 +136,21 @@
         clickOutsideOfArea(bounds.left, bounds.top, bounds.right, bounds.bottom);
     }
 
+    /** Get the UiLocatorHelper. */
     public UiLocatorHelper getLocatorHelper() {
         return mLocatorHelper;
     }
 
     /**
+     * Get a copy of the UiLocatorHelper with a different timeout.
+     * @param timeout The timeout in milliseconds.
+     * @return UiLocatorHelper with the specified timeout.
+     */
+    public UiLocatorHelper getLocatorHelper(long timeout) {
+        return new UiLocatorHelper(timeout);
+    }
+
+    /**
      * Performs a long click on node.
      * @param locator Locator to use to find the node.
      */
@@ -328,13 +330,8 @@
         context.startActivity(intent);
 
         IUi2Locator packageLocator = Ui2Locators.withPackageName(packageName);
-        long oldTimeout = getTimeout();
-        try {
-            setTimeout(timeout);
-            mLocatorHelper.getOne(packageLocator);
-        } finally {
-            setTimeout(oldTimeout);
-        }
+        UiLocatorHelper helper = getLocatorHelper(timeout);
+        helper.getOne(packageLocator);
     }
 
     // positive fraction indicates swipe up
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/utils/UiLocatorHelper.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/utils/UiLocatorHelper.java
index 53d78b27..658221f 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/utils/UiLocatorHelper.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/utils/UiLocatorHelper.java
@@ -49,9 +49,18 @@
     private final UiDevice mDevice;
     private long mTimeout;
 
+    /** Create a UiLocatorHelper with default timeout. */
     UiLocatorHelper() {
+        this(DEFAULT_TIMEOUT_MS);
+    }
+
+    /**
+     * Create a UiLocatorHelper with specified timeout.
+     * @param timeout Timeout in milliseconds.
+     */
+    UiLocatorHelper(long timeout) {
         mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
-        mTimeout = DEFAULT_TIMEOUT_MS;
+        mTimeout = timeout;
     }
 
     /**
@@ -62,15 +71,6 @@
     }
 
     /**
-     * Set the timeout used for location operations.
-     * This is immutable outside package to reduce errors.
-     * @param timeout Timeout in milliseconds.
-     */
-    void setTimeout(long timeout) {
-        mTimeout = timeout;
-    }
-
-    /**
      * Checks and waits if a node is found on the screen.
      * @param locator Locator used to find the node.
      * @return        true if node is found, false otherwise.
diff --git a/chrome/test/data/local_ntp/customize_menu_browsertest.js b/chrome/test/data/local_ntp/customize_menu_browsertest.js
index 589a9d0..3e446973 100644
--- a/chrome/test/data/local_ntp/customize_menu_browsertest.js
+++ b/chrome/test/data/local_ntp/customize_menu_browsertest.js
@@ -782,7 +782,8 @@
 };
 
 /**
- * Tests the back arrow for custom backgrounds.
+ * Tests pressing the back arrow in the background image submenu will return to
+ * the collections menu.
  */
 test.customizeMenu.testBackgrounds_BackArrowCustomBackground = function() {
   init();
@@ -825,20 +826,7 @@
   // Reopen the images menu, the selection should still be present.
   $('coll_tile_0').click();
 
-  assertFalse(elementIsVisible(backgroundSubmenu));
-  assertTrue(elementIsVisible(backgroundImageSubmenu));
-  assertTrue(
-      $(test.customizeMenu.IDS.BACKGROUNDS_IMAGE_MENU)
-          .getElementsByClassName('bg-sel-tile')
-          .length === 4);
-  assertTrue(
-      $(test.customizeMenu.IDS.BACKGROUNDS_IMAGE_MENU)
-          .getElementsByClassName('selected')
-          .length === 1);
-  assertTrue(
-      $(test.customizeMenu.IDS.BACKGROUNDS_IMAGE_MENU)
-          .getElementsByClassName('selected')[0]
-          .firstChild.id === 'coll_0_img_tile_0');
+  assertImageSubmenuOpenWithFirstTileSelected();
 
   // Clicking the image again should deselect it.
   $('coll_0_img_tile_0').click();
@@ -854,16 +842,73 @@
   assertEquals(0, test.customizeMenu.timesCustomBackgroundWasSet);
   $('coll_tile_0').click();
 
+  assertImageSubmenuOpenWithNoTileSelected();
+};
+
+/**
+ * Tests pressing backspace in the background image submenu will return to the
+ * collections menu.
+ */
+test.customizeMenu.testBackgrounds_BackspaceCustomBackground = function() {
+  init();
+
+  setupFakeAsyncCollectionLoad();
+
+  // Open the Shortcuts submenu.
+  $(test.customizeMenu.IDS.EDIT_BG).click();
+
+  const backgroundSubmenu = $(test.customizeMenu.IDS.BACKGROUNDS_MENU);
+  const backgroundImageSubmenu =
+      $(test.customizeMenu.IDS.BACKGROUNDS_IMAGE_MENU);
+  assertTrue(elementIsVisible(backgroundSubmenu));
+
+  // 5 total tiles: upload, default, and the 3 collection tiles.
+  assertTrue(
+      $(test.customizeMenu.IDS.BACKGROUNDS_MENU)
+          .getElementsByClassName('bg-sel-tile')
+          .length === 5);
+
+  setupFakeAsyncImageLoad('coll_tile_0');
+  $('coll_tile_0').click();
+
+  // The open menu is now the images menu with 4 tiles.
   assertFalse(elementIsVisible(backgroundSubmenu));
   assertTrue(elementIsVisible(backgroundImageSubmenu));
   assertTrue(
       $(test.customizeMenu.IDS.BACKGROUNDS_IMAGE_MENU)
           .getElementsByClassName('bg-sel-tile')
           .length === 4);
+
+  $('coll_0_img_tile_0').click();
+  const keyDown = new Event('keydown');
+  keyDown.keyCode = 8;
+  $(test.customizeMenu.IDS.CUSTOMIZATION_MENU).dispatchEvent(keyDown);
+
+  // The main backgrounds menu should be open, and no custom background set.
+  assertTrue(elementIsVisible(backgroundSubmenu));
+  assertFalse(elementIsVisible(backgroundImageSubmenu));
+  assertEquals(0, test.customizeMenu.timesCustomBackgroundWasSet);
+
+  // Reopen the images menu, the selection should still be present.
+  $('coll_tile_0').click();
+
+  assertImageSubmenuOpenWithFirstTileSelected();
+
+  // Clicking the image again should deselect it.
+  $('coll_0_img_tile_0').click();
   assertTrue(
       $(test.customizeMenu.IDS.BACKGROUNDS_IMAGE_MENU)
           .getElementsByClassName('selected')
           .length === 0);
+
+  // Close and reopen the submenu and ensure nothing is selected.
+  $(test.customizeMenu.IDS.MENU_BACK).click();
+  assertTrue(elementIsVisible(backgroundSubmenu));
+  assertFalse(elementIsVisible(backgroundImageSubmenu));
+  assertEquals(0, test.customizeMenu.timesCustomBackgroundWasSet);
+  $('coll_tile_0').click();
+
+  assertImageSubmenuOpenWithNoTileSelected();
 };
 
 // ******************************* HELPERS *******************************
@@ -949,6 +994,52 @@
 };
 
 /**
+ * Assert that the background images submenu is open and the first image tile is
+ * selected.
+ */
+assertImageSubmenuOpenWithFirstTileSelected = function() {
+  const backgroundSubmenu = $(test.customizeMenu.IDS.BACKGROUNDS_MENU);
+  const backgroundImageSubmenu =
+      $(test.customizeMenu.IDS.BACKGROUNDS_IMAGE_MENU);
+
+  assertFalse(elementIsVisible(backgroundSubmenu));
+  assertTrue(elementIsVisible(backgroundImageSubmenu));
+  assertTrue(
+      $(test.customizeMenu.IDS.BACKGROUNDS_IMAGE_MENU)
+          .getElementsByClassName('bg-sel-tile')
+          .length === 4);
+  assertTrue(
+      $(test.customizeMenu.IDS.BACKGROUNDS_IMAGE_MENU)
+          .getElementsByClassName('selected')
+          .length === 1);
+  assertTrue(
+      $(test.customizeMenu.IDS.BACKGROUNDS_IMAGE_MENU)
+          .getElementsByClassName('selected')[0]
+          .firstChild.id === 'coll_0_img_tile_0');
+};
+
+/**
+ * Assert that the background images submenu is open and no image tile is
+ * selected.
+ */
+assertImageSubmenuOpenWithNoTileSelected = function() {
+  const backgroundSubmenu = $(test.customizeMenu.IDS.BACKGROUNDS_MENU);
+  const backgroundImageSubmenu =
+      $(test.customizeMenu.IDS.BACKGROUNDS_IMAGE_MENU);
+
+  assertFalse(elementIsVisible(backgroundSubmenu));
+  assertTrue(elementIsVisible(backgroundImageSubmenu));
+  assertTrue(
+      $(test.customizeMenu.IDS.BACKGROUNDS_IMAGE_MENU)
+          .getElementsByClassName('bg-sel-tile')
+          .length === 4);
+  assertTrue(
+      $(test.customizeMenu.IDS.BACKGROUNDS_IMAGE_MENU)
+          .getElementsByClassName('selected')
+          .length === 0);
+};
+
+/**
  * Fake the loading of the Chrome Backgrounds collections so it happens
  * synchronously.
  */
diff --git a/chrome/test/data/webui/settings/chromeos/cups_printer_landing_page_tests.js b/chrome/test/data/webui/settings/chromeos/cups_printer_landing_page_tests.js
index b82245a..b954084a 100644
--- a/chrome/test/data/webui/settings/chromeos/cups_printer_landing_page_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/cups_printer_landing_page_tests.js
@@ -190,10 +190,10 @@
 
   setup(function() {
     printerList = [
+      createCupsPrinterInfo('google', '4', 'id4'),
       createCupsPrinterInfo('test1', '1', 'id1'),
       createCupsPrinterInfo('test2', '2', 'id2'),
       createCupsPrinterInfo('test3', '3', 'id3'),
-      createCupsPrinterInfo('google', '4', 'id4'),
     ];
 
     cupsPrintersBrowserProxy =
@@ -410,7 +410,7 @@
     ];
     const discoveredPrinterList = [
       createCupsPrinterInfo('test3', '3', 'id3'),
-      createCupsPrinterInfo('google', '4', 'id4'),
+      createCupsPrinterInfo('test4', '4', 'id4'),
     ];
 
     return cupsPrintersBrowserProxy.whenCalled('startDiscoveringPrinters')
diff --git a/chromeos/disks/disk_mount_manager.cc b/chromeos/disks/disk_mount_manager.cc
index ec19b3dd..a4caa57 100644
--- a/chromeos/disks/disk_mount_manager.cc
+++ b/chromeos/disks/disk_mount_manager.cc
@@ -19,6 +19,7 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/weak_ptr.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/observer_list.h"
 #include "base/strings/string_util.h"
 #include "chromeos/constants/chromeos_features.h"
@@ -555,6 +556,9 @@
     DiskMap::const_iterator disk = disks_.find(device_path);
     DCHECK(disk != disks_.end() && disk->second->mount_path().empty());
 
+    base::UmaHistogramEnumeration("FileBrowser.FormatFileSystemType",
+                                  filesystem);
+
     const std::string filesystem_str = FormatFileSystemTypeToString(filesystem);
     pending_format_changes_[device_path] = {filesystem_str, label};
 
diff --git a/chromeos/disks/disk_mount_manager.h b/chromeos/disks/disk_mount_manager.h
index 8e6d50b..44dbde4 100644
--- a/chromeos/disks/disk_mount_manager.h
+++ b/chromeos/disks/disk_mount_manager.h
@@ -28,11 +28,14 @@
 };
 
 // Possible filesystem types that can be passed to FormatMountedDevice.
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
 enum class FormatFileSystemType {
   kUnknown = 0,
   kVfat = 1,
   kExfat = 2,
   kNtfs = 3,
+  kMaxValue = kNtfs,
 };
 
 // This class handles the interaction with cros-disks.
diff --git a/chromeos/services/device_sync/cryptauth_device_syncer.cc b/chromeos/services/device_sync/cryptauth_device_syncer.cc
index a8ca2f3c..feb2684 100644
--- a/chromeos/services/device_sync/cryptauth_device_syncer.cc
+++ b/chromeos/services/device_sync/cryptauth_device_syncer.cc
@@ -15,7 +15,8 @@
 CryptAuthDeviceSyncer::~CryptAuthDeviceSyncer() = default;
 
 void CryptAuthDeviceSyncer::Sync(
-    const cryptauthv2::RequestContext& request_context,
+    const cryptauthv2::ClientMetadata& client_metadata,
+    const cryptauthv2::ClientAppMetadata& client_app_metadata,
     DeviceSyncAttemptFinishedCallback callback) {
   // Enforce that Sync() can only be called once.
   DCHECK(!was_sync_called_);
@@ -23,7 +24,7 @@
 
   callback_ = std::move(callback);
 
-  OnAttemptStarted(request_context);
+  OnAttemptStarted(client_metadata, client_app_metadata);
 }
 
 void CryptAuthDeviceSyncer::OnAttemptFinished(
diff --git a/chromeos/services/device_sync/cryptauth_device_syncer.h b/chromeos/services/device_sync/cryptauth_device_syncer.h
index 6c9b05c9..5a8d8e9 100644
--- a/chromeos/services/device_sync/cryptauth_device_syncer.h
+++ b/chromeos/services/device_sync/cryptauth_device_syncer.h
@@ -7,10 +7,10 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
-#include "base/optional.h"
 
 namespace cryptauthv2 {
-class RequestContext;
+class ClientMetadata;
+class ClientAppMetadata;
 }  // namespace cryptauthv2
 
 namespace chromeos {
@@ -36,28 +36,30 @@
 //     public key in the response differs from the one sent in the request,
 //     another SyncMetadataRequest is made. Otherwise, the second
 //     SyncMetadataRequest is skipped and the encrypted remote device metadata
-//     is decrypted using the group private key.
+//     is decrypted using the group private key if available. Note: The remote
+//     devices are only those registered in the DeviceSync:BetterTogether group,
+//     in other words, those using v2 DeviceSync.
 //
 // 2a) (Possible) Second SyncMetadataRequest: Not invoked if the group public
-//     key from the first SyncMetadataResponse (1b) matches that sent in the
-//     first SyncMetadataRequest (1a). Now that the correct group key pair has
-//     been established, another request is made.
+//     key from the first SyncMetadataResponse (1b) agrees with the one sent in
+//     the first SyncMetadataRequest (1a). The client has the correct group
+//     public key at this point.
 //
 // 2b) (Possible) Second SyncMetadataResponse: The included remote device
-//     metadata can now be decrypted. The remote devices are only those
-//     registered in the DeviceSync:BetterTogether group, in other words, those
-//     using v2 DeviceSync.
+//     metadata can be decrypted if a group private key is sent. If no group
+//     private key is returned, the client must wait for a GCM message
+//     requesting another DeviceSync when the key becomes available.
 //
 // 3)  BatchGetFeatureStatusesRequest/Response: Gets the supported and enabled
 //     states of all multidevice (BetterTogether) features for all devices.
 //
-// 4a) ShareGroupPrivateKeyRequest: Sends CryptAuth the device's group private
+// 4a) ShareGroupPrivateKeyRequest: Sends CryptAuth this device's group private
 //     key encrypted with each remote device's
 //     CryptAuthKeyBundle::kDeviceSyncBetterTogether public key. This ensures
 //     end-to-end encryption of the group private key and consequently the
 //     device metadata.
 //
-// 4b) ShareGroupPrivateKeyResponse: We view this response as an indication that
+// 4b) ShareGroupPrivateKeyResponse: This response is only an indication that
 //     the ShareGroupPrivateKeyRequest was successful.
 //
 // A CryptAuthDeviceSyncer object is designed to be used for only one Sync()
@@ -69,24 +71,29 @@
   using DeviceSyncAttemptFinishedCallback =
       base::OnceCallback<void(const CryptAuthDeviceSyncResult&)>;
 
-  // Starts the v2 DeviceSync flow.
-  // |request_context|: Information about the DeviceSync attempt--such as
-  //     invocation reason and device identifiers--that is sent to CryptAuth in
+  // Starts the CryptAuth v2 DeviceSync flow.
+  // |client_metadata|: Information about the DeviceSync attempt--such as
+  //     invocation reason, retry count, etc.--that is sent to CryptAuth in
   //     each request.
+  // |client_app_metadata|: Information about the local device such as the
+  //     Instance ID and hardware information.
   // |callback|: Invoked when the DeviceSync attempt concludes, successfully or
   //     not. The CryptAuthDeviceSyncResult provides information about the
   //     outcome of the DeviceSync attempt and possibly a new ClientDirective.
-  void Sync(const cryptauthv2::RequestContext& request_context,
+  void Sync(const cryptauthv2::ClientMetadata& client_metadata,
+            const cryptauthv2::ClientAppMetadata& client_app_metadata,
             DeviceSyncAttemptFinishedCallback callback);
 
  protected:
   CryptAuthDeviceSyncer();
 
   virtual void OnAttemptStarted(
-      const cryptauthv2::RequestContext& request_context) = 0;
+      const cryptauthv2::ClientMetadata& client_metadata,
+      const cryptauthv2::ClientAppMetadata& client_app_metadata) = 0;
 
   void OnAttemptFinished(const CryptAuthDeviceSyncResult& device_sync_result);
 
+ private:
   DeviceSyncAttemptFinishedCallback callback_;
   bool was_sync_called_ = false;
 
diff --git a/components/autofill/content/browser/BUILD.gn b/components/autofill/content/browser/BUILD.gn
index a9cea4c..19732d4f 100644
--- a/components/autofill/content/browser/BUILD.gn
+++ b/components/autofill/content/browser/BUILD.gn
@@ -21,7 +21,7 @@
 
   public_deps = [
     ":risk_proto",
-    "//components/autofill/content/common:mojo_interfaces",
+    "//components/autofill/content/common/mojom",
     "//components/autofill/core/browser",
     "//components/autofill/core/common",
     "//components/keyed_service/content",
@@ -76,7 +76,7 @@
   deps = [
     ":browser",
     "//base",
-    "//components/autofill/content/common:mojo_interfaces",
+    "//components/autofill/content/common/mojom",
     "//components/autofill/core/browser",
     "//components/autofill/core/browser:test_support",
     "//components/autofill/core/common",
diff --git a/components/autofill/content/browser/content_autofill_driver.h b/components/autofill/content/browser/content_autofill_driver.h
index 658cb4c2..5de70a3f 100644
--- a/components/autofill/content/browser/content_autofill_driver.h
+++ b/components/autofill/content/browser/content_autofill_driver.h
@@ -12,8 +12,8 @@
 #include "build/build_config.h"
 #include "components/autofill/content/browser/key_press_handler_manager.h"
 #include "components/autofill/content/browser/webauthn/internal_authenticator_impl.h"
-#include "components/autofill/content/common/autofill_agent.mojom.h"
-#include "components/autofill/content/common/autofill_driver.mojom.h"
+#include "components/autofill/content/common/mojom/autofill_agent.mojom.h"
+#include "components/autofill/content/common/mojom/autofill_driver.mojom.h"
 #include "components/autofill/core/browser/autofill_driver.h"
 #include "components/autofill/core/browser/autofill_external_delegate.h"
 #include "components/autofill/core/browser/autofill_manager.h"
diff --git a/components/autofill/content/browser/content_autofill_driver_factory.h b/components/autofill/content/browser/content_autofill_driver_factory.h
index 6863377..a530737 100644
--- a/components/autofill/content/browser/content_autofill_driver_factory.h
+++ b/components/autofill/content/browser/content_autofill_driver_factory.h
@@ -8,7 +8,7 @@
 #include <string>
 
 #include "base/supports_user_data.h"
-#include "components/autofill/content/common/autofill_driver.mojom.h"
+#include "components/autofill/content/common/mojom/autofill_driver.mojom.h"
 #include "components/autofill/core/browser/autofill_driver_factory.h"
 #include "components/autofill/core/browser/autofill_manager.h"
 #include "content/public/browser/web_contents_observer.h"
diff --git a/components/autofill/content/common/BUILD.gn b/components/autofill/content/common/mojom/BUILD.gn
similarity index 94%
rename from components/autofill/content/common/BUILD.gn
rename to components/autofill/content/common/mojom/BUILD.gn
index c4ad7b9..312d062 100644
--- a/components/autofill/content/common/BUILD.gn
+++ b/components/autofill/content/common/mojom/BUILD.gn
@@ -4,7 +4,7 @@
 
 import("//mojo/public/tools/bindings/mojom.gni")
 
-mojom("mojo_interfaces") {
+mojom("mojom") {
   sources = [
     "autofill_agent.mojom",
     "autofill_driver.mojom",
diff --git a/components/autofill/content/common/DEPS b/components/autofill/content/common/mojom/DEPS
similarity index 100%
rename from components/autofill/content/common/DEPS
rename to components/autofill/content/common/mojom/DEPS
diff --git a/components/autofill/content/common/OWNERS b/components/autofill/content/common/mojom/OWNERS
similarity index 81%
rename from components/autofill/content/common/OWNERS
rename to components/autofill/content/common/mojom/OWNERS
index 92c6ef9..c6d9ce4c 100644
--- a/components/autofill/content/common/OWNERS
+++ b/components/autofill/content/common/mojom/OWNERS
@@ -4,8 +4,8 @@
 per-file *.mojom=file://ipc/SECURITY_OWNERS
 per-file *.typemap=set noparent
 per-file *.typemap=file://ipc/SECURITY_OWNERS
-per-file *_struct_traits*.*=set noparent
-per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
 per-file *_message*.*=set noparent
 per-file *_message*.*=file://ipc/SECURITY_OWNERS
 per-file *_param_traits*.*=set noparent
diff --git a/components/autofill/content/common/autofill_agent.mojom b/components/autofill/content/common/mojom/autofill_agent.mojom
similarity index 100%
rename from components/autofill/content/common/autofill_agent.mojom
rename to components/autofill/content/common/mojom/autofill_agent.mojom
diff --git a/components/autofill/content/common/autofill_driver.mojom b/components/autofill/content/common/mojom/autofill_driver.mojom
similarity index 100%
rename from components/autofill/content/common/autofill_driver.mojom
rename to components/autofill/content/common/mojom/autofill_driver.mojom
diff --git a/components/autofill/content/renderer/BUILD.gn b/components/autofill/content/renderer/BUILD.gn
index 5031108..7afe41f5 100644
--- a/components/autofill/content/renderer/BUILD.gn
+++ b/components/autofill/content/renderer/BUILD.gn
@@ -41,7 +41,7 @@
   deps = [
     "//base",
     "//base:i18n",
-    "//components/autofill/content/common:mojo_interfaces",
+    "//components/autofill/content/common/mojom",
     "//components/autofill/core/common",
     "//components/strings",
     "//content/public/common",
@@ -91,7 +91,7 @@
   deps = [
     ":test_support",
     "//base/test:test_support",
-    "//components/autofill/content/common:mojo_interfaces",
+    "//components/autofill/content/common/mojom",
     "//components/autofill/core/common",
     "//testing/gtest",
   ]
diff --git a/components/autofill/content/renderer/autofill_agent.h b/components/autofill/content/renderer/autofill_agent.h
index 0acf9d1..c1c2b5d 100644
--- a/components/autofill/content/renderer/autofill_agent.h
+++ b/components/autofill/content/renderer/autofill_agent.h
@@ -14,8 +14,8 @@
 #include "base/strings/string16.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
-#include "components/autofill/content/common/autofill_agent.mojom.h"
-#include "components/autofill/content/common/autofill_driver.mojom.h"
+#include "components/autofill/content/common/mojom/autofill_agent.mojom.h"
+#include "components/autofill/content/common/mojom/autofill_driver.mojom.h"
 #include "components/autofill/content/renderer/form_cache.h"
 #include "components/autofill/content/renderer/form_tracker.h"
 #include "content/public/renderer/render_frame_observer.h"
diff --git a/components/autofill/content/renderer/password_autofill_agent.h b/components/autofill/content/renderer/password_autofill_agent.h
index 6b223ea4..183f210 100644
--- a/components/autofill/content/renderer/password_autofill_agent.h
+++ b/components/autofill/content/renderer/password_autofill_agent.h
@@ -13,8 +13,8 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "build/build_config.h"
-#include "components/autofill/content/common/autofill_agent.mojom.h"
-#include "components/autofill/content/common/autofill_driver.mojom.h"
+#include "components/autofill/content/common/mojom/autofill_agent.mojom.h"
+#include "components/autofill/content/common/mojom/autofill_driver.mojom.h"
 #include "components/autofill/content/renderer/autofill_agent.h"
 #include "components/autofill/content/renderer/field_data_manager.h"
 #include "components/autofill/content/renderer/form_tracker.h"
diff --git a/components/autofill/content/renderer/password_generation_agent.h b/components/autofill/content/renderer/password_generation_agent.h
index d9e514b..460bbce 100644
--- a/components/autofill/content/renderer/password_generation_agent.h
+++ b/components/autofill/content/renderer/password_generation_agent.h
@@ -13,8 +13,8 @@
 #include <vector>
 
 #include "base/macros.h"
-#include "components/autofill/content/common/autofill_agent.mojom.h"
-#include "components/autofill/content/common/autofill_driver.mojom.h"
+#include "components/autofill/content/common/mojom/autofill_agent.mojom.h"
+#include "components/autofill/content/common/mojom/autofill_driver.mojom.h"
 #include "components/autofill/content/renderer/renderer_save_password_progress_logger.h"
 #include "content/public/renderer/render_frame_observer.h"
 #include "mojo/public/cpp/bindings/associated_receiver.h"
diff --git a/components/autofill/content/renderer/renderer_save_password_progress_logger.h b/components/autofill/content/renderer/renderer_save_password_progress_logger.h
index 43416aa..af0cd80 100644
--- a/components/autofill/content/renderer/renderer_save_password_progress_logger.h
+++ b/components/autofill/content/renderer/renderer_save_password_progress_logger.h
@@ -8,7 +8,7 @@
 #include <string>
 
 #include "base/macros.h"
-#include "components/autofill/content/common/autofill_driver.mojom.h"
+#include "components/autofill/content/common/mojom/autofill_driver.mojom.h"
 #include "components/autofill/core/common/save_password_progress_logger.h"
 
 namespace blink {
diff --git a/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc b/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc
index 71c6a7a..bf66816 100644
--- a/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc
+++ b/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc
@@ -7,7 +7,7 @@
 #include "base/optional.h"
 #include "base/run_loop.h"
 #include "base/test/scoped_task_environment.h"
-#include "components/autofill/content/common/autofill_driver.mojom.h"
+#include "components/autofill/content/common/mojom/autofill_driver.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/components/autofill/core/browser/ui/suggestion_selection.cc b/components/autofill/core/browser/ui/suggestion_selection.cc
index 9a8723eb..2311917 100644
--- a/components/autofill/core/browser/ui/suggestion_selection.cc
+++ b/components/autofill/core/browser/ui/suggestion_selection.cc
@@ -282,7 +282,15 @@
       // The given |suggestions| are already sorted from highest to lowest
       // ranking. Suggestions with lower indices have a higher ranking and
       // should be kept.
-      (*suggestions)[index_to_add_suggestion].label = labels[i];
+      //
+      // We check whether the value and label are the same because in certain
+      // cases, e.g. when a credit card form contains a zip code field and the
+      // user clicks on the zip code, a suggestion's value and the label
+      // produced for it may both be a zip code.
+      if (!comparator.Compare((*suggestions)[index_to_add_suggestion].value,
+                              labels[i])) {
+        (*suggestions)[index_to_add_suggestion].label = labels[i];
+      }
       ++index_to_add_suggestion;
     }
   }
diff --git a/components/autofill/core/browser/ui/suggestion_selection_unittest.cc b/components/autofill/core/browser/ui/suggestion_selection_unittest.cc
index 5f73b6cc..2bb414b 100644
--- a/components/autofill/core/browser/ui/suggestion_selection_unittest.cc
+++ b/components/autofill/core/browser/ui/suggestion_selection_unittest.cc
@@ -574,5 +574,18 @@
                       base::ASCIIToUTF16("1 Winterfell Ln")))));
 }
 
+TEST_F(SuggestionSelectionTest, PrepareSuggestions_SameStringInValueAndLabel) {
+  std::vector<Suggestion> suggestions{
+      Suggestion(base::UTF8ToUTF16("4 Mañana Road"))};
+
+  const std::vector<base::string16> labels{base::ASCIIToUTF16("4 manana road")};
+
+  PrepareSuggestions(labels, &suggestions, comparator_);
+  EXPECT_THAT(suggestions,
+              ElementsAre(AllOf(
+                  Field(&Suggestion::value, base::UTF8ToUTF16("4 Mañana Road")),
+                  Field(&Suggestion::label, base::string16()))));
+}
+
 }  // namespace suggestion_selection
 }  // namespace autofill
diff --git a/components/autofill/core/common/mojom/BUILD.gn b/components/autofill/core/common/mojom/BUILD.gn
index 98e1ed0..118d4d5 100644
--- a/components/autofill/core/common/mojom/BUILD.gn
+++ b/components/autofill/core/common/mojom/BUILD.gn
@@ -30,7 +30,7 @@
 source_set("unit_tests") {
   testonly = true
   sources = [
-    "autofill_types_struct_traits_unittest.cc",
+    "autofill_types_mojom_traits_unittest.cc",
   ]
 
   public_deps = [
diff --git a/components/autofill/core/common/mojom/OWNERS b/components/autofill/core/common/mojom/OWNERS
index 2c44a46..ae29a36aa 100644
--- a/components/autofill/core/common/mojom/OWNERS
+++ b/components/autofill/core/common/mojom/OWNERS
@@ -1,6 +1,6 @@
 per-file *.mojom=set noparent
 per-file *.mojom=file://ipc/SECURITY_OWNERS
-per-file *_struct_traits*.*=set noparent
-per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
 per-file *.typemap=set noparent
 per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/components/autofill/core/common/mojom/autofill_types.typemap b/components/autofill/core/common/mojom/autofill_types.typemap
index cf6bd4d7..99febf4 100644
--- a/components/autofill/core/common/mojom/autofill_types.typemap
+++ b/components/autofill/core/common/mojom/autofill_types.typemap
@@ -15,9 +15,9 @@
   "//components/autofill/core/common/password_generation_util.h",
 ]
 traits_headers =
-    [ "//components/autofill/core/common/mojom/autofill_types_struct_traits.h" ]
+    [ "//components/autofill/core/common/mojom/autofill_types_mojom_traits.h" ]
 sources = [
-  "//components/autofill/core/common/mojom/autofill_types_struct_traits.cc",
+  "//components/autofill/core/common/mojom/autofill_types_mojom_traits.cc",
 ]
 deps = [
   "//base",
diff --git a/components/autofill/core/common/mojom/autofill_types_struct_traits.cc b/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc
similarity index 99%
rename from components/autofill/core/common/mojom/autofill_types_struct_traits.cc
rename to components/autofill/core/common/mojom/autofill_types_mojom_traits.cc
index 657ce2e..f7ba57f 100644
--- a/components/autofill/core/common/mojom/autofill_types_struct_traits.cc
+++ b/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/autofill/core/common/mojom/autofill_types_struct_traits.h"
+#include "components/autofill/core/common/mojom/autofill_types_mojom_traits.h"
 
 #include "base/i18n/rtl.h"
 #include "mojo/public/cpp/base/string16_mojom_traits.h"
diff --git a/components/autofill/core/common/mojom/autofill_types_struct_traits.h b/components/autofill/core/common/mojom/autofill_types_mojom_traits.h
similarity index 98%
rename from components/autofill/core/common/mojom/autofill_types_struct_traits.h
rename to components/autofill/core/common/mojom/autofill_types_mojom_traits.h
index 68a96f8aa..6a1ca29d 100644
--- a/components/autofill/core/common/mojom/autofill_types_struct_traits.h
+++ b/components/autofill/core/common/mojom/autofill_types_mojom_traits.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_AUTOFILL_CORE_COMMON_MOJOM_AUTOFILL_TYPES_STRUCT_TRAITS_H_
-#define COMPONENTS_AUTOFILL_CORE_COMMON_MOJOM_AUTOFILL_TYPES_STRUCT_TRAITS_H_
+#ifndef COMPONENTS_AUTOFILL_CORE_COMMON_MOJOM_AUTOFILL_TYPES_MOJOM_TRAITS_H_
+#define COMPONENTS_AUTOFILL_CORE_COMMON_MOJOM_AUTOFILL_TYPES_MOJOM_TRAITS_H_
 
 #include <map>
 #include <string>
@@ -620,4 +620,4 @@
 
 }  // namespace mojo
 
-#endif  // COMPONENTS_AUTOFILL_CORE_COMMON_MOJOM_AUTOFILL_TYPES_STRUCT_TRAITS_H_
+#endif  // COMPONENTS_AUTOFILL_CORE_COMMON_MOJOM_AUTOFILL_TYPES_MOJOM_TRAITS_H_
diff --git a/components/autofill/core/common/mojom/autofill_types_struct_traits_unittest.cc b/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc
similarity index 100%
rename from components/autofill/core/common/mojom/autofill_types_struct_traits_unittest.cc
rename to components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc
diff --git a/components/autofill/ios/browser/autofill_agent.mm b/components/autofill/ios/browser/autofill_agent.mm
index ad390756..720d00a 100644
--- a/components/autofill/ios/browser/autofill_agent.mm
+++ b/components/autofill/ios/browser/autofill_agent.mm
@@ -50,8 +50,8 @@
 #include "ios/web/public/js_messaging/web_frame.h"
 #include "ios/web/public/js_messaging/web_frame_util.h"
 #import "ios/web/public/js_messaging/web_frames_manager.h"
+#import "ios/web/public/navigation/navigation_context.h"
 #include "ios/web/public/url_scheme_util.h"
-#import "ios/web/public/web_state/navigation_context.h"
 #import "ios/web/public/web_state/web_state.h"
 #import "ios/web/public/web_state/web_state_observer_bridge.h"
 #include "ui/gfx/geometry/rect.h"
diff --git a/components/autofill/ios/browser/autofill_util.mm b/components/autofill/ios/browser/autofill_util.mm
index 8a8e7713..a17223e 100644
--- a/components/autofill/ios/browser/autofill_util.mm
+++ b/components/autofill/ios/browser/autofill_util.mm
@@ -19,8 +19,8 @@
 #include "components/autofill/core/common/form_data.h"
 #include "components/autofill/core/common/form_field_data.h"
 #import "ios/web/public/deprecated/crw_js_injection_receiver.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #include "ios/web/public/security/ssl_status.h"
 #include "url/gurl.h"
 #include "url/origin.h"
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUma.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUma.java
index c360726..11024d9 100644
--- a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUma.java
+++ b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUma.java
@@ -215,6 +215,10 @@
      * @param startupMode Chrome's startup mode.
      */
     public void reportStartupMode(int startupMode) {
+        // We don't record full browser's warm startup since most of the full browser warm startup
+        // don't even reach here.
+        if (startupMode < 0) return;
+
         cacheEvent("Servicification.Startup3", startupMode);
     }
 
diff --git a/components/dom_distiller/ios/distiller_page_ios.mm b/components/dom_distiller/ios/distiller_page_ios.mm
index b81c423..109b93d 100644
--- a/components/dom_distiller/ios/distiller_page_ios.mm
+++ b/components/dom_distiller/ios/distiller_page_ios.mm
@@ -19,10 +19,10 @@
 #include "ios/web/public/browser_state.h"
 #import "ios/web/public/deprecated/crw_js_injection_manager.h"
 #import "ios/web/public/deprecated/crw_js_injection_receiver.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_manager.h"
+#import "ios/web/public/navigation/web_state_policy_decider.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "ios/web/public/web_state/web_state_observer.h"
-#import "ios/web/public/web_state/web_state_policy_decider.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/components/exo/wm_helper.h b/components/exo/wm_helper.h
index 83f0b24e..9c9de973 100644
--- a/components/exo/wm_helper.h
+++ b/components/exo/wm_helper.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_EXO_WM_HELPER_H_
 #define COMPONENTS_EXO_WM_HELPER_H_
 
+#include <memory>
 #include <vector>
 
 #include "base/macros.h"
diff --git a/components/favicon/ios/web_favicon_driver.mm b/components/favicon/ios/web_favicon_driver.mm
index 44e08bc..024d66a8 100644
--- a/components/favicon/ios/web_favicon_driver.mm
+++ b/components/favicon/ios/web_favicon_driver.mm
@@ -10,9 +10,9 @@
 #include "components/favicon/ios/favicon_url_util.h"
 #include "ios/web/public/browser_state.h"
 #include "ios/web/public/favicon/favicon_status.h"
-#include "ios/web/public/navigation_item.h"
-#include "ios/web/public/navigation_manager.h"
-#include "ios/web/public/web_state/navigation_context.h"
+#include "ios/web/public/navigation/navigation_context.h"
+#include "ios/web/public/navigation/navigation_item.h"
+#include "ios/web/public/navigation/navigation_manager.h"
 #include "ios/web/public/web_state/web_state.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "skia/ext/skia_utils_ios.h"
diff --git a/components/flags_ui/resources/flags.js b/components/flags_ui/resources/flags.js
index 56e69f2..d2dbc2d 100644
--- a/components/flags_ui/resources/flags.js
+++ b/components/flags_ui/resources/flags.js
@@ -82,13 +82,13 @@
 
   var smallScreenCheck = window.matchMedia('(max-width: 480px)');
   // Toggling of experiment description overflow content on smaller screens.
-  elements = document.querySelectorAll('.experiment .flex:first-child');
-  for (var i = 0; i < elements.length; ++i) {
-    elements[i].onclick = function(e) {
-      if (smallScreenCheck.matches) {
+  if(smallScreenCheck.matches){
+    elements = document.querySelectorAll('.experiment .flex:first-child');
+    for (var i = 0; i < elements.length; ++i) {
+      elements[i].onclick = function(e) {
         this.classList.toggle('expand');
-      }
-    };
+      };
+    }
   }
 
   $('experiment-reset-all').onclick = resetAllFlags;
diff --git a/components/history/ios/browser/web_state_top_sites_observer.mm b/components/history/ios/browser/web_state_top_sites_observer.mm
index 7f44e62..414365a 100644
--- a/components/history/ios/browser/web_state_top_sites_observer.mm
+++ b/components/history/ios/browser/web_state_top_sites_observer.mm
@@ -7,9 +7,9 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "components/history/core/browser/top_sites.h"
-#include "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
-#import "ios/web/public/web_state/navigation_context.h"
+#import "ios/web/public/navigation/navigation_context.h"
+#include "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/components/password_manager/content/browser/BUILD.gn b/components/password_manager/content/browser/BUILD.gn
index 0f8227b..aa5749de 100644
--- a/components/password_manager/content/browser/BUILD.gn
+++ b/components/password_manager/content/browser/BUILD.gn
@@ -25,7 +25,7 @@
   public_deps = [
     "//base",
     "//components/autofill/content/browser",
-    "//components/autofill/content/common:mojo_interfaces",
+    "//components/autofill/content/common/mojom",
     "//components/autofill/core/common",
     "//components/keyed_service/content",
     "//components/password_manager/core/browser",
diff --git a/components/password_manager/content/browser/content_password_manager_driver.h b/components/password_manager/content/browser/content_password_manager_driver.h
index a049fa8..8e81de31 100644
--- a/components/password_manager/content/browser/content_password_manager_driver.h
+++ b/components/password_manager/content/browser/content_password_manager_driver.h
@@ -11,8 +11,8 @@
 
 #include "base/compiler_specific.h"
 #include "base/macros.h"
-#include "components/autofill/content/common/autofill_agent.mojom.h"
-#include "components/autofill/content/common/autofill_driver.mojom.h"
+#include "components/autofill/content/common/mojom/autofill_agent.mojom.h"
+#include "components/autofill/content/common/mojom/autofill_driver.mojom.h"
 #include "components/autofill/core/common/password_form_field_prediction_map.h"
 #include "components/autofill/core/common/password_form_generation_data.h"
 #include "components/password_manager/core/browser/password_autofill_manager.h"
diff --git a/components/password_manager/content/browser/content_password_manager_driver_factory.h b/components/password_manager/content/browser/content_password_manager_driver_factory.h
index c0672d06..39616d1 100644
--- a/components/password_manager/content/browser/content_password_manager_driver_factory.h
+++ b/components/password_manager/content/browser/content_password_manager_driver_factory.h
@@ -11,7 +11,7 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/supports_user_data.h"
-#include "components/autofill/content/common/autofill_driver.mojom.h"
+#include "components/autofill/content/common/mojom/autofill_driver.mojom.h"
 #include "components/password_manager/core/browser/password_autofill_manager.h"
 #include "components/password_manager/core/browser/password_generation_frame_helper.h"
 #include "components/password_manager/core/browser/password_manager.h"
diff --git a/components/password_manager/content/browser/content_password_manager_driver_unittest.cc b/components/password_manager/content/browser/content_password_manager_driver_unittest.cc
index 5c26f69..21088bd2 100644
--- a/components/password_manager/content/browser/content_password_manager_driver_unittest.cc
+++ b/components/password_manager/content/browser/content_password_manager_driver_unittest.cc
@@ -11,7 +11,7 @@
 #include "base/macros.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
-#include "components/autofill/content/common/autofill_agent.mojom.h"
+#include "components/autofill/content/common/mojom/autofill_agent.mojom.h"
 #include "components/autofill/core/browser/logging/stub_log_manager.h"
 #include "components/autofill/core/browser/test_autofill_client.h"
 #include "components/password_manager/core/browser/stub_password_manager_client.h"
diff --git a/components/sessions/ios/ios_live_tab.mm b/components/sessions/ios/ios_live_tab.mm
index 1b7fbba9a..d3bdbc6f 100644
--- a/components/sessions/ios/ios_live_tab.mm
+++ b/components/sessions/ios/ios_live_tab.mm
@@ -4,7 +4,7 @@
 
 #include "components/sessions/ios/ios_live_tab.h"
 #include "base/memory/ptr_util.h"
-#include "ios/web/public/navigation_manager.h"
+#include "ios/web/public/navigation/navigation_manager.h"
 
 namespace {
 const char kIOSLiveTabWebStateUserDataKey[] = "ios_live_tab";
diff --git a/components/sessions/ios/ios_serialized_navigation_builder.mm b/components/sessions/ios/ios_serialized_navigation_builder.mm
index 9f0cd7a..8224e75 100644
--- a/components/sessions/ios/ios_serialized_navigation_builder.mm
+++ b/components/sessions/ios/ios_serialized_navigation_builder.mm
@@ -6,8 +6,8 @@
 
 #include "components/sessions/core/serialized_navigation_entry.h"
 #include "ios/web/public/favicon/favicon_status.h"
-#include "ios/web/public/navigation_item.h"
-#include "ios/web/public/referrer.h"
+#include "ios/web/public/navigation/navigation_item.h"
+#include "ios/web/public/navigation/referrer.h"
 
 namespace sessions {
 
diff --git a/components/sessions/ios/ios_serialized_navigation_builder_unittest.mm b/components/sessions/ios/ios_serialized_navigation_builder_unittest.mm
index ab998e5..4dafcb9 100644
--- a/components/sessions/ios/ios_serialized_navigation_builder_unittest.mm
+++ b/components/sessions/ios/ios_serialized_navigation_builder_unittest.mm
@@ -7,8 +7,8 @@
 #include "components/sessions/core/serialized_navigation_entry.h"
 #include "components/sessions/core/serialized_navigation_entry_test_helper.h"
 #include "ios/web/public/favicon/favicon_status.h"
-#include "ios/web/public/navigation_item.h"
-#include "ios/web/public/referrer.h"
+#include "ios/web/public/navigation/navigation_item.h"
+#include "ios/web/public/navigation/referrer.h"
 #include "ios/web/public/test/web_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/components/sessions/ios/ios_serialized_navigation_driver.cc b/components/sessions/ios/ios_serialized_navigation_driver.cc
index e9740dcd6..c24ea5c 100644
--- a/components/sessions/ios/ios_serialized_navigation_driver.cc
+++ b/components/sessions/ios/ios_serialized_navigation_driver.cc
@@ -7,7 +7,7 @@
 #include "base/memory/singleton.h"
 #include "components/sessions/core/serialized_navigation_entry.h"
 #include "ios/web/common/referrer_util.h"
-#include "ios/web/public/referrer.h"
+#include "ios/web/public/navigation/referrer.h"
 
 namespace sessions {
 
diff --git a/components/sessions/ios/ios_serialized_navigation_driver_unittest.cc b/components/sessions/ios/ios_serialized_navigation_driver_unittest.cc
index e0050df..4ece98824 100644
--- a/components/sessions/ios/ios_serialized_navigation_driver_unittest.cc
+++ b/components/sessions/ios/ios_serialized_navigation_driver_unittest.cc
@@ -6,7 +6,7 @@
 
 #include "components/sessions/core/serialized_navigation_entry.h"
 #include "components/sessions/core/serialized_navigation_entry_test_helper.h"
-#include "ios/web/public/referrer.h"
+#include "ios/web/public/navigation/referrer.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/page_transition_types.h"
 
diff --git a/components/signin/ios/browser/account_consistency_service.mm b/components/signin/ios/browser/account_consistency_service.mm
index 74f7268ec..5b1ef2e 100644
--- a/components/signin/ios/browser/account_consistency_service.mm
+++ b/components/signin/ios/browser/account_consistency_service.mm
@@ -21,7 +21,7 @@
 #include "components/signin/public/base/account_consistency_method.h"
 #include "ios/web/common/web_view_creation_util.h"
 #include "ios/web/public/browser_state.h"
-#include "ios/web/public/web_state/web_state_policy_decider.h"
+#import "ios/web/public/navigation/web_state_policy_decider.h"
 #include "net/base/mac/url_conversions.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "url/gurl.h"
diff --git a/components/signin/ios/browser/account_consistency_service_unittest.mm b/components/signin/ios/browser/account_consistency_service_unittest.mm
index 2a1b5fb23..17305e6 100644
--- a/components/signin/ios/browser/account_consistency_service_unittest.mm
+++ b/components/signin/ios/browser/account_consistency_service_unittest.mm
@@ -22,10 +22,10 @@
 #include "components/signin/public/identity_manager/identity_test_environment.h"
 #include "components/signin/public/identity_manager/test_identity_manager_observer.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
+#include "ios/web/public/navigation/web_state_policy_decider.h"
 #include "ios/web/public/test/fakes/test_browser_state.h"
 #import "ios/web/public/test/fakes/test_web_state.h"
 #include "ios/web/public/test/test_web_thread_bundle.h"
-#include "ios/web/public/web_state/web_state_policy_decider.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
diff --git a/components/translate/ios/browser/ios_translate_driver.mm b/components/translate/ios/browser/ios_translate_driver.mm
index 40aa13a1e..d92d6737 100644
--- a/components/translate/ios/browser/ios_translate_driver.mm
+++ b/components/translate/ios/browser/ios_translate_driver.mm
@@ -21,10 +21,10 @@
 #include "ios/chrome/browser/metrics/ukm_url_recorder.h"
 #include "ios/web/public/browser_state.h"
 #include "ios/web/public/deprecated/crw_js_injection_receiver.h"
-#include "ios/web/public/navigation_item.h"
-#include "ios/web/public/navigation_manager.h"
-#include "ios/web/public/referrer.h"
-#include "ios/web/public/web_state/navigation_context.h"
+#include "ios/web/public/navigation/navigation_context.h"
+#include "ios/web/public/navigation/navigation_item.h"
+#include "ios/web/public/navigation/navigation_manager.h"
+#include "ios/web/public/navigation/referrer.h"
 #include "ios/web/public/web_state/web_state.h"
 #include "ui/base/page_transition_types.h"
 #include "ui/base/window_open_disposition.h"
diff --git a/components/translate/ios/browser/language_detection_controller.mm b/components/translate/ios/browser/language_detection_controller.mm
index 0cb795b..eb76d507 100644
--- a/components/translate/ios/browser/language_detection_controller.mm
+++ b/components/translate/ios/browser/language_detection_controller.mm
@@ -18,8 +18,8 @@
 #import "components/translate/ios/browser/js_language_detection_manager.h"
 #include "components/translate/ios/browser/string_clipping_util.h"
 #include "ios/web/public/js_messaging/web_frame.h"
+#import "ios/web/public/navigation/navigation_context.h"
 #import "ios/web/public/url_scheme_util.h"
-#import "ios/web/public/web_state/navigation_context.h"
 #include "ios/web/public/web_state/web_state.h"
 #include "net/http/http_response_headers.h"
 
diff --git a/components/translate/ios/browser/translate_controller.mm b/components/translate/ios/browser/translate_controller.mm
index 68bab1f..8348084 100644
--- a/components/translate/ios/browser/translate_controller.mm
+++ b/components/translate/ios/browser/translate_controller.mm
@@ -19,7 +19,7 @@
 #import "components/translate/ios/browser/js_translate_manager.h"
 #include "ios/web/public/browser_state.h"
 #include "ios/web/public/js_messaging/web_frame.h"
-#include "ios/web/public/web_state/navigation_context.h"
+#include "ios/web/public/navigation/navigation_context.h"
 #include "ios/web/public/web_state/web_state.h"
 #include "net/base/load_flags.h"
 #include "net/base/net_errors.h"
diff --git a/components/viz/service/display/gl_renderer.cc b/components/viz/service/display/gl_renderer.cc
index bd87811..5c173202 100644
--- a/components/viz/service/display/gl_renderer.cc
+++ b/components/viz/service/display/gl_renderer.cc
@@ -295,6 +295,8 @@
   float backdrop_filter_quality = 1.0;
   // Whether the original background texture is needed for the mask.
   bool mask_for_background = false;
+
+  bool apply_shader_based_rounded_corner = true;
 };
 
 class GLRenderer::ScopedUseGrContext {
@@ -1406,7 +1408,8 @@
           tex_coord_precision, sampler_type, shader_blend_mode,
           params->use_aa ? USE_AA : NO_AA, mask_mode, mask_for_background,
           params->use_color_matrix, tint_gl_composited_content_,
-          ShouldApplyRoundedCorner(params->quad)),
+          params->apply_shader_based_rounded_corner &&
+              ShouldApplyRoundedCorner(params->quad)),
       params->contents_and_bypass_color_space, target_color_space);
 }
 
@@ -3570,6 +3573,12 @@
 
   UpdateRPDQTexturesForSampling(&params);
   UpdateRPDQBlendMode(&params);
+  // The code in this method (CopyRenderPassDrawQuadToOverlayResource) is
+  // only called when we are drawing for the purpose of copying to
+  // a CALayerOverlay. In such cases, the CALayerOverlay applies rounded
+  // corners via CALayer parameters, so the shader-based rounded corners
+  // should be disabled here.
+  params.apply_shader_based_rounded_corner = false;
   ChooseRPDQProgram(&params, (*overlay_texture)->texture.color_space());
   UpdateRPDQUniforms(&params);
 
diff --git a/components/viz/service/display/gl_renderer_unittest.cc b/components/viz/service/display/gl_renderer_unittest.cc
index 5e38126d..e5da1ca 100644
--- a/components/viz/service/display/gl_renderer_unittest.cc
+++ b/components/viz/service/display/gl_renderer_unittest.cc
@@ -3148,6 +3148,9 @@
                     GLuint filter));
   MOCK_METHOD2(ScheduleCALayerInUseQueryCHROMIUM,
                void(GLsizei count, const GLuint* textures));
+  MOCK_METHOD5(
+      Uniform4f,
+      void(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w));
 };
 
 class CALayerGLRendererTest : public GLRendererTest {
@@ -3295,11 +3298,15 @@
   gfx::Size viewport_size(10, 10);
 
   for (size_t subtest = 0; subtest < 3; ++subtest) {
+    RenderPass* child_pass =
+        cc::AddRenderPass(&render_passes_in_draw_order_, 1, gfx::Rect(250, 250),
+                          gfx::Transform(), cc::FilterOperations());
+
     RenderPassId root_pass_id = 1;
     RenderPass* root_pass = cc::AddRenderPass(
         &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
         gfx::Transform(), cc::FilterOperations());
-    auto* quad = cc::AddQuad(root_pass, gfx::Rect(viewport_size), SK_ColorRED);
+    auto* quad = cc::AddRenderPassQuad(root_pass, child_pass);
     SharedQuadState* sqs =
         const_cast<SharedQuadState*>(quad->shared_quad_state);
 
@@ -3313,6 +3320,7 @@
       case 0:
         // Subtest 0 is a simple round rect that matches the clip rect, and
         // should be handled by CALayers.
+        EXPECT_CALL(gl(), Uniform4f(_, _, _, _, _)).Times(1);
         EXPECT_CALL(gl(), ScheduleCALayerSharedStateCHROMIUM(_, _, _, _, _, _))
             .Times(1);
         EXPECT_CALL(gl(), ScheduleCALayerCHROMIUM(_, _, _, _, _, _)).Times(1);
@@ -3321,12 +3329,17 @@
         // Subtest 1 doesn't match clip and rounded rect, but we can still
         // use CALayers.
         sqs->clip_rect = gfx::Rect(3, 3, 4, 4);
+        EXPECT_CALL(gl(), Uniform4f(_, _, _, _, _)).Times(1);
         EXPECT_CALL(gl(), ScheduleCALayerCHROMIUM(_, _, _, _, _, _)).Times(1);
         break;
       case 2:
         // Subtest 2 has a non-simple rounded rect.
         sqs->rounded_corner_bounds.SetCornerRadii(
             gfx::RRectF::Corner::kUpperLeft, 1, 1);
+        // Called 2 extra times in order to set up the rounded corner
+        // parameters in the shader, because the CALayer is not handling
+        // the rounded corners.
+        EXPECT_CALL(gl(), Uniform4f(_, _, _, _, _)).Times(3);
         EXPECT_CALL(gl(), ScheduleCALayerCHROMIUM(_, _, _, _, _, _)).Times(0);
         break;
     }
diff --git a/components/viz/service/display/surface_aggregator.cc b/components/viz/service/display/surface_aggregator.cc
index 932ec04..fe10c91 100644
--- a/components/viz/service/display/surface_aggregator.cc
+++ b/components/viz/service/display/surface_aggregator.cc
@@ -74,75 +74,9 @@
 
 }  // namespace
 
-struct SurfaceAggregator::ClipData {
-  std::string ToString() const {
-    return is_clipped ? "clip " + rect.ToString() : "no clip";
-  }
-
-  bool is_clipped = false;
-  gfx::Rect rect;
-};
-
-struct SurfaceAggregator::PrewalkResult {
-  // This is the set of Surfaces that were referenced by another Surface, but
-  // not included in a SurfaceDrawQuad.
-  base::flat_set<SurfaceId> undrawn_surfaces;
-  bool may_contain_video = false;
-};
-
-struct SurfaceAggregator::RoundedCornerInfo {
-  RoundedCornerInfo() = default;
-
-  // |target_transform| is the transform that maps |bounds| from its current
-  // space into the desired target space. It must be a scale+translation
-  // matrix.
-  RoundedCornerInfo(const gfx::RRectF& bounds_arg,
-                    bool is_fast_rounded_corner,
-                    const gfx::Transform target_transform)
-      : bounds(bounds_arg), is_fast_rounded_corner(is_fast_rounded_corner) {
-    if (bounds_arg.IsEmpty())
-      return;
-    DCHECK(target_transform.Preserves2dAxisAlignment());
-    SkMatrix matrix = target_transform.matrix();
-    bounds.Scale(matrix.getScaleX(), matrix.getScaleY());
-    bounds.Offset(target_transform.To2dTranslation());
-  }
-
-  gfx::RRectF bounds;
-  bool is_fast_rounded_corner = false;
-};
-
-struct SurfaceAggregator::ChildSurfaceInfo {
-  ChildSurfaceInfo(RenderPassId parent_pass_id,
-                   const gfx::Transform& quad_to_target_transform,
-                   const gfx::Rect& quad_rect,
-                   bool stretch_content_to_fill_bounds,
-                   bool is_clipped,
-                   const gfx::Rect& clip_rect)
-      : parent_pass_id(parent_pass_id),
-        quad_to_target_transform(quad_to_target_transform),
-        quad_rect(quad_rect),
-        stretch_content_to_fill_bounds(stretch_content_to_fill_bounds),
-        is_clipped(is_clipped),
-        clip_rect(clip_rect) {}
-
-  RenderPassId parent_pass_id;
-  gfx::Transform quad_to_target_transform;
-  gfx::Rect quad_rect;
-  bool stretch_content_to_fill_bounds;
-  bool is_clipped;
-  gfx::Rect clip_rect;
-  bool has_moved_pixels = false;
-  std::vector<gfx::Transform> transforms_to_root_target;
-};
-
-struct SurfaceAggregator::RenderPassMapEntry {
-  explicit RenderPassMapEntry(RenderPass* render_pass)
-      : render_pass(render_pass) {}
-
-  RenderPass* render_pass;
-  bool is_visited = false;
-};
+std::string SurfaceAggregator::ClipData::ToString() const {
+  return is_clipped ? "clip " + rect.ToString() : "no clip";
+}
 
 SurfaceAggregator::SurfaceAggregator(SurfaceManager* manager,
                                      DisplayResourceProvider* provider,
@@ -164,6 +98,10 @@
   ProcessAddedAndRemovedSurfaces();
 }
 
+SurfaceAggregator::PrewalkResult::PrewalkResult() {}
+
+SurfaceAggregator::PrewalkResult::~PrewalkResult() {}
+
 // Create a clip rect for an aggregated quad from the original clip rect and
 // the clip rect from the surface it's on.
 SurfaceAggregator::ClipData SurfaceAggregator::CalculateClipRect(
@@ -548,9 +486,9 @@
 
     CopyQuadsToPass(source.quad_list, source.shared_quad_state_list,
                     surface->GetActiveFrame().device_scale_factor(),
-                    child_to_parent_map, gfx::Transform(), {}, copy_pass.get(),
-                    surface_id, RoundedCornerInfo(), occluding_damage_rect,
-                    occluding_damage_rect_valid);
+                    child_to_parent_map, gfx::Transform(), ClipData(),
+                    copy_pass.get(), surface_id, RoundedCornerInfo(),
+                    occluding_damage_rect, occluding_damage_rect_valid);
 
     // If the render pass has copy requests, or should be cached, or has
     // moving-pixel filters, or in a moving-pixel surface, we should damage the
@@ -589,9 +527,9 @@
 
     // Intersect the transformed visible rect and the clip rect to create a
     // smaller cliprect for the quad.
-    ClipData surface_quad_clip_rect = {
+    ClipData surface_quad_clip_rect(
         true, cc::MathUtil::MapEnclosingClippedRect(
-                  source_sqs->quad_to_target_transform, source_visible_rect)};
+                  source_sqs->quad_to_target_transform, source_visible_rect));
     if (source_sqs->is_clipped) {
       surface_quad_clip_rect.rect.Intersect(source_sqs->clip_rect);
     }
@@ -633,7 +571,8 @@
                  /* backdrop_filter_quality*/ 1.0f);
   }
 
-  referenced_surfaces_.erase(surface_id);
+  // Need to re-query since referenced_surfaces_ iterators are not stable.
+  referenced_surfaces_.erase(referenced_surfaces_.find(surface_id));
 }
 
 void SurfaceAggregator::EmitDefaultBackgroundColorQuad(
@@ -832,6 +771,20 @@
       occluding_damage_rect_valid);
 }
 
+SurfaceAggregator::RoundedCornerInfo::RoundedCornerInfo(
+    const gfx::RRectF& bounds_arg,
+    bool is_fast_rounded_corner_arg,
+    const gfx::Transform target_transform) {
+  is_fast_rounded_corner = is_fast_rounded_corner_arg;
+  if (bounds_arg.IsEmpty())
+    return;
+  DCHECK(target_transform.Preserves2dAxisAlignment());
+  bounds = bounds_arg;
+  SkMatrix matrix = target_transform.matrix();
+  bounds.Scale(matrix.getScaleX(), matrix.getScaleY());
+  bounds.Offset(target_transform.To2dTranslation());
+}
+
 SharedQuadState* SurfaceAggregator::CopyAndScaleSharedQuadState(
     const SharedQuadState* source_sqs,
     const gfx::Transform& scaled_quad_to_target_transform,
@@ -845,7 +798,7 @@
     bool occluding_damage_rect_valid) {
   auto* shared_quad_state = dest_render_pass->CreateAndAppendSharedQuadState();
   ClipData new_clip_rect = CalculateClipRect(
-      clip_rect, {source_sqs->is_clipped, source_sqs->clip_rect},
+      clip_rect, ClipData(source_sqs->is_clipped, source_sqs->clip_rect),
       target_transform);
 
   // target_transform contains any transformation that may exist
@@ -914,7 +867,7 @@
     // Both cannot be set at once. If this happens then a surface is being
     // merged when it should not.
     DCHECK(quad->shared_quad_state->rounded_corner_bounds.IsEmpty() ||
-           parent_rounded_corner_info.bounds.IsEmpty());
+           parent_rounded_corner_info.IsEmpty());
 
     if (quad->material == DrawQuad::Material::kSurfaceContent) {
       const auto* surface_quad = SurfaceDrawQuad::MaterialCast(quad);
@@ -925,7 +878,7 @@
       if (!surface_quad->surface_range.end().is_valid())
         continue;
 
-      if (parent_rounded_corner_info.bounds.IsEmpty()) {
+      if (parent_rounded_corner_info.IsEmpty()) {
         new_rounded_corner_info = RoundedCornerInfo(
             quad->shared_quad_state->rounded_corner_bounds,
             quad->shared_quad_state->is_fast_rounded_corner, target_transform);
@@ -937,7 +890,7 @@
           &damage_rect_in_quad_space_valid, new_rounded_corner_info);
     } else {
       if (quad->shared_quad_state != last_copied_source_shared_quad_state) {
-        if (parent_rounded_corner_info.bounds.IsEmpty()) {
+        if (parent_rounded_corner_info.IsEmpty()) {
           new_rounded_corner_info =
               RoundedCornerInfo(quad->shared_quad_state->rounded_corner_bounds,
                                 quad->shared_quad_state->is_fast_rounded_corner,
@@ -1086,7 +1039,7 @@
                     frame.device_scale_factor(), child_to_parent_map,
                     apply_surface_transform_to_root_pass ? surface_transform
                                                          : gfx::Transform(),
-                    {}, copy_pass.get(), surface->surface_id(),
+                    ClipData(), copy_pass.get(), surface->surface_id(),
                     RoundedCornerInfo(), occluding_damage_rect,
                     occluding_damage_rect_valid);
 
@@ -1122,96 +1075,6 @@
   }
 }
 
-// Helper function that uses backtracking on the render pass tree of a surface
-// to find all surfaces embedded in it. If a surface is embedded multiple times
-// (due to use of a MirrorLayer), it will be reachable via multiple paths from
-// root render pass. For each such a path the appropriate transform is
-// calculated.
-void SurfaceAggregator::FindChildSurfaces(
-    SurfaceId surface_id,
-    base::flat_map<RenderPassId, RenderPassMapEntry>* render_pass_map,
-    const base::flat_set<RenderPassId>& pixel_moving_background_filter_passes,
-    const gfx::Transform& parent_transform,
-    RenderPassId render_pass_id,
-    base::flat_map<SurfaceRange, ChildSurfaceInfo>* child_surfaces,
-    gfx::Rect* pixel_moving_backdrop_filters_rect) {
-  auto render_pass_it = render_pass_map->find(render_pass_id);
-  DCHECK(render_pass_it != render_pass_map->end());
-  if (render_pass_it->second.is_visited) {
-    // This means that this render pass is an ancestor of itself. This is not
-    // allowed. Stop processing the render pass again.
-    return;
-  }
-  base::AutoReset<bool> reset_is_visited(&render_pass_it->second.is_visited,
-                                         true);
-  RenderPass* render_pass = render_pass_it->second.render_pass;
-
-  gfx::Transform transform_to_root_target(
-      parent_transform, render_pass->transform_to_root_target);
-  RenderPassId remapped_pass_id = RemapPassId(render_pass->id, surface_id);
-  if (pixel_moving_background_filter_passes.contains(remapped_pass_id)) {
-    pixel_moving_backdrop_filters_rect->Union(
-        cc::MathUtil::MapEnclosingClippedRect(transform_to_root_target,
-                                              render_pass->output_rect));
-  }
-  bool has_pixel_moving_filter =
-      render_pass->filters.HasFilterThatMovesPixels();
-  if (has_pixel_moving_filter)
-    moved_pixel_passes_.insert(remapped_pass_id);
-  bool in_moved_pixel_pass =
-      has_pixel_moving_filter ||
-      base::Contains(moved_pixel_passes_, remapped_pass_id);
-  for (auto* quad : render_pass->quad_list) {
-    if (quad->material == DrawQuad::Material::kSurfaceContent) {
-      // A child surface has been found. Add necessary info from this surface to
-      // the set of child surfaces that can be used to update damage rect for
-      // the parent surface. If this child surface has been visited previously,
-      // we only need to update |has_moved_pixels| and add the transform
-      // corresponding to this visit; rest of the info would remain the same.
-      const auto* surface_quad = SurfaceDrawQuad::MaterialCast(quad);
-      auto it = child_surfaces->find(surface_quad->surface_range);
-      if (it == child_surfaces->end()) {
-        auto insert_pair = child_surfaces->emplace(
-            std::piecewise_construct,
-            std::forward_as_tuple(surface_quad->surface_range),
-            std::forward_as_tuple(
-                remapped_pass_id,
-                surface_quad->shared_quad_state->quad_to_target_transform,
-                surface_quad->rect,
-                surface_quad->stretch_content_to_fill_bounds,
-                surface_quad->shared_quad_state->is_clipped,
-                surface_quad->shared_quad_state->clip_rect));
-        DCHECK(insert_pair.second);
-        it = insert_pair.first;
-      }
-      auto& surface_info = it->second;
-      if (in_moved_pixel_pass)
-        surface_info.has_moved_pixels = true;
-      surface_info.transforms_to_root_target.push_back(
-          transform_to_root_target);
-    } else if (quad->material == DrawQuad::Material::kRenderPass) {
-      // A child render pass has been found. Find its child surfaces
-      // recursively.
-      const auto* render_pass_quad = RenderPassDrawQuad::MaterialCast(quad);
-      RenderPassId child_pass_id = render_pass_quad->render_pass_id;
-      RenderPassId remapped_child_pass_id =
-          RemapPassId(child_pass_id, surface_id);
-      if (in_moved_pixel_pass)
-        moved_pixel_passes_.insert(remapped_child_pass_id);
-      if (pixel_moving_background_filter_passes.contains(child_pass_id))
-        in_moved_pixel_pass = true;
-      render_pass_dependencies_[remapped_pass_id].insert(
-          remapped_child_pass_id);
-      FindChildSurfaces(
-          surface_id, render_pass_map, pixel_moving_background_filter_passes,
-          gfx::Transform(
-              transform_to_root_target,
-              render_pass_quad->shared_quad_state->quad_to_target_transform),
-          child_pass_id, child_surfaces, pixel_moving_backdrop_filters_rect);
-    }
-  }
-}
-
 // Walk the Surface tree from surface_id. Validate the resources of the current
 // surface and its descendants, check if there are any copy requests, and
 // return the combined damage rect.
@@ -1241,6 +1104,15 @@
     provider_->ReceiveFromChild(child_id, frame.resource_list);
   }
 
+  std::vector<ResourceId> referenced_resources;
+  size_t reserve_size = frame.resource_list.size();
+  referenced_resources.reserve(reserve_size);
+
+  bool invalid_frame = false;
+  std::unordered_map<ResourceId, ResourceId> empty_map;
+  const auto& child_to_parent_map =
+      provider_ ? provider_->GetChildToParentMap(child_id) : empty_map;
+
   RenderPassId remapped_pass_id =
       RemapPassId(frame.render_pass_list.back()->id, surface->surface_id());
   if (in_moved_pixel_surface)
@@ -1250,13 +1122,40 @@
 
   const gfx::Transform& root_pass_transform =
       IsRootSurface(surface) ? root_surface_transform_ : gfx::Transform();
+  struct SurfaceInfo {
+    SurfaceInfo(const SurfaceRange& surface_range,
+                bool has_moved_pixels,
+                RenderPassId parent_pass_id,
+                const gfx::Transform& target_to_surface_transform,
+                const gfx::Rect& quad_rect,
+                bool stretch_content_to_fill_bounds,
+                bool is_clipped,
+                const gfx::Rect& clip_rect_in_root_target_space)
+        : surface_range(surface_range),
+          has_moved_pixels(has_moved_pixels),
+          parent_pass_id(parent_pass_id),
+          target_to_surface_transform(target_to_surface_transform),
+          quad_rect(quad_rect),
+          stretch_content_to_fill_bounds(stretch_content_to_fill_bounds),
+          is_clipped(is_clipped),
+          clip_rect_in_root_target_space(clip_rect_in_root_target_space) {}
+    SurfaceRange surface_range;
+    bool has_moved_pixels;
+    RenderPassId parent_pass_id;
+    gfx::Transform target_to_surface_transform;
+    gfx::Rect quad_rect;
+    bool stretch_content_to_fill_bounds;
+    bool is_clipped;
+    gfx::Rect clip_rect_in_root_target_space;
+  };
+  std::vector<SurfaceInfo> child_surfaces;
 
+  gfx::Rect pixel_moving_backdrop_filters_rect;
+  // This data is created once and typically small or empty. Collect all items
+  // and pass to a flat_vector to sort once.
+  std::vector<RenderPassId> pixel_moving_background_filter_passes_data;
   const auto* root_pass_in_root_surface =
       IsRootSurface(surface) ? frame.render_pass_list.back().get() : nullptr;
-  // This data is created once and typically small or empty. Collect all items
-  // and pass to a flat_set/flat_map to sort once.
-  std::vector<RenderPassId> pixel_moving_background_filter_passes_data;
-  std::vector<std::pair<RenderPassId, RenderPassMapEntry>> render_pass_list;
   for (const auto& render_pass : frame.render_pass_list) {
     if (render_pass->backdrop_filters.HasFilterThatMovesPixels()) {
       DCHECK_NE(render_pass.get(), root_pass_in_root_surface)
@@ -1265,36 +1164,75 @@
 
       pixel_moving_background_filter_passes_data.push_back(
           RemapPassId(render_pass->id, surface->surface_id()));
+
+      gfx::Transform transform_to_root_target(
+          root_pass_transform, render_pass->transform_to_root_target);
+      pixel_moving_backdrop_filters_rect.Union(
+          cc::MathUtil::MapEnclosingClippedRect(transform_to_root_target,
+                                                render_pass->output_rect));
     }
-    render_pass_list.emplace_back(render_pass->id, render_pass.get());
   }
   base::flat_set<RenderPassId> pixel_moving_background_filter_passes(
-      std::move(pixel_moving_background_filter_passes_data));
-  base::flat_map<RenderPassId, RenderPassMapEntry> render_pass_map(
-      std::move(render_pass_list));
+      std::move(pixel_moving_background_filter_passes_data),
+      base::KEEP_FIRST_OF_DUPES);
 
-  base::flat_map<SurfaceRange, ChildSurfaceInfo> child_surfaces;
-  gfx::Rect pixel_moving_backdrop_filters_rect;
-  FindChildSurfaces(surface->surface_id(), &render_pass_map,
-                    pixel_moving_background_filter_passes, root_pass_transform,
-                    frame.render_pass_list.back()->id, &child_surfaces,
-                    &pixel_moving_backdrop_filters_rect);
+  for (const auto& render_pass : base::Reversed(frame.render_pass_list)) {
+    RenderPassId remapped_pass_id =
+        RemapPassId(render_pass->id, surface->surface_id());
+    bool has_pixel_moving_filter =
+        render_pass->filters.HasFilterThatMovesPixels();
+    if (has_pixel_moving_filter)
+      moved_pixel_passes_.insert(remapped_pass_id);
+    bool in_moved_pixel_pass =
+        has_pixel_moving_filter ||
+        base::Contains(moved_pixel_passes_, remapped_pass_id);
 
-  std::vector<ResourceId> referenced_resources;
-  referenced_resources.reserve(frame.resource_list.size());
+    for (auto* quad : render_pass->quad_list) {
+      if (quad->material == DrawQuad::Material::kSurfaceContent) {
+        const auto* surface_quad = SurfaceDrawQuad::MaterialCast(quad);
+        gfx::Transform transform_to_root_target(
+            root_pass_transform, render_pass->transform_to_root_target);
+        gfx::Transform target_to_surface_transform(
+            transform_to_root_target,
+            surface_quad->shared_quad_state->quad_to_target_transform);
 
-  bool invalid_frame = false;
-  if (provider_) {
-    const auto& child_to_parent_map = provider_->GetChildToParentMap(child_id);
-    for (const auto& render_pass : base::Reversed(frame.render_pass_list)) {
-      for (auto* quad : render_pass->quad_list) {
-        for (ResourceId resource_id : quad->resources) {
-          if (!child_to_parent_map.count(resource_id)) {
-            invalid_frame = true;
-            break;
-          }
-          referenced_resources.push_back(resource_id);
+        gfx::Rect clip_rect_in_root_target_space;
+        if (surface_quad->shared_quad_state->is_clipped) {
+          // clip_rect is already in quad target space so only
+          // transform_to_root_target needs to be applied
+          clip_rect_in_root_target_space =
+              cc::MathUtil::MapEnclosingClippedRect(
+                  transform_to_root_target,
+                  surface_quad->shared_quad_state->clip_rect);
         }
+        child_surfaces.emplace_back(
+            surface_quad->surface_range, in_moved_pixel_pass, remapped_pass_id,
+            target_to_surface_transform, surface_quad->rect,
+            surface_quad->stretch_content_to_fill_bounds,
+            surface_quad->shared_quad_state->is_clipped,
+            clip_rect_in_root_target_space);
+      } else if (quad->material == DrawQuad::Material::kRenderPass) {
+        const auto* render_pass_quad = RenderPassDrawQuad::MaterialCast(quad);
+        if (in_moved_pixel_pass) {
+          moved_pixel_passes_.insert(RemapPassId(
+              render_pass_quad->render_pass_id, surface->surface_id()));
+        }
+        if (pixel_moving_background_filter_passes.count(
+                render_pass_quad->render_pass_id)) {
+          in_moved_pixel_pass = true;
+        }
+        render_pass_dependencies_[remapped_pass_id].insert(RemapPassId(
+            render_pass_quad->render_pass_id, surface->surface_id()));
+      }
+
+      if (!provider_)
+        continue;
+      for (ResourceId resource_id : quad->resources) {
+        if (!child_to_parent_map.count(resource_id)) {
+          invalid_frame = true;
+          break;
+        }
+        referenced_resources.push_back(resource_id);
       }
     }
   }
@@ -1320,19 +1258,20 @@
   // Avoid infinite recursion by adding current surface to
   // referenced_surfaces_.
   referenced_surfaces_.insert(surface->surface_id());
-  for (const auto& surface_info_pair : child_surfaces) {
-    const auto& surface_range = surface_info_pair.first;
-    const auto& surface_info = surface_info_pair.second;
+  for (const auto& surface_info : child_surfaces) {
     // TODO(fsamuel): Consider caching this value somewhere so that
     // HandleSurfaceQuad doesn't need to call it again.
-    Surface* child_surface = manager_->GetLatestInFlightSurface(surface_range);
+    Surface* child_surface =
+        manager_->GetLatestInFlightSurface(surface_info.surface_range);
 
     // If the primary surface is not available then we assume the damage is
     // the full size of the SurfaceDrawQuad because we might need to introduce
     // gutter.
     gfx::Rect surface_damage;
-    if (!child_surface || child_surface->surface_id() != surface_range.end())
+    if (!child_surface ||
+        child_surface->surface_id() != surface_info.surface_range.end()) {
       surface_damage = surface_info.quad_rect;
+    }
 
     if (child_surface) {
       if (surface_info.stretch_content_to_fill_bounds) {
@@ -1367,22 +1306,14 @@
       continue;
     }
 
-    for (const auto& transform_to_root_target :
-         surface_info.transforms_to_root_target) {
-      gfx::Transform target_to_surface_transform(
-          transform_to_root_target, surface_info.quad_to_target_transform);
-      gfx::Rect surface_damage_in_root_target_space =
-          cc::MathUtil::MapEnclosingClippedRect(target_to_surface_transform,
-                                                surface_damage);
-      if (surface_info.is_clipped) {
-        gfx::Rect clip_rect_in_root_target_space =
-            cc::MathUtil::MapEnclosingClippedRect(transform_to_root_target,
-                                                  surface_info.clip_rect);
-        surface_damage_in_root_target_space.Intersect(
-            clip_rect_in_root_target_space);
-      }
-      damage_rect.Union(surface_damage_in_root_target_space);
+    gfx::Rect surface_damage_in_root_target_space =
+        cc::MathUtil::MapEnclosingClippedRect(
+            surface_info.target_to_surface_transform, surface_damage);
+    if (surface_info.is_clipped) {
+      surface_damage_in_root_target_space.Intersect(
+          surface_info.clip_rect_in_root_target_space);
     }
+    damage_rect.Union(surface_damage_in_root_target_space);
   }
 
   if (!damage_rect.IsEmpty()) {
@@ -1436,7 +1367,8 @@
       has_cached_render_passes_ = true;
   }
 
-  referenced_surfaces_.erase(surface->surface_id());
+  auto it = referenced_surfaces_.find(surface->surface_id());
+  referenced_surfaces_.erase(it);
   if (!damage_rect.IsEmpty() && frame.metadata.may_contain_video)
     result->may_contain_video = true;
 
@@ -1480,7 +1412,8 @@
       prewalk_result->undrawn_surfaces.erase(surface_id);
       referenced_surfaces_.insert(surface_id);
       CopyPasses(surface->GetActiveFrame(), surface);
-      referenced_surfaces_.erase(surface_id);
+      // CopyPasses may have mutated container, need to re-query to erase.
+      referenced_surfaces_.erase(referenced_surfaces_.find(surface_id));
     }
   }
 }
@@ -1506,7 +1439,7 @@
     const RoundedCornerInfo& rounded_corner_info,
     const RenderPass& root_render_pass) {
   // If the quad has no rounded corner, then we do not have to block merging.
-  if (rounded_corner_info.bounds.IsEmpty())
+  if (rounded_corner_info.IsEmpty())
     return true;
 
   // If the quad has rounded corner and it is not a fast rounded corner, we
@@ -1580,7 +1513,8 @@
   CopyUndrawnSurfaces(&prewalk_result);
   referenced_surfaces_.insert(surface_id);
   CopyPasses(root_surface_frame, surface);
-  referenced_surfaces_.erase(surface_id);
+  // CopyPasses may have mutated container, need to re-query to erase.
+  referenced_surfaces_.erase(referenced_surfaces_.find(surface_id));
   AddColorConversionPass();
 
   moved_pixel_passes_.clear();
diff --git a/components/viz/service/display/surface_aggregator.h b/components/viz/service/display/surface_aggregator.h
index eed9a794..d16f763 100644
--- a/components/viz/service/display/surface_aggregator.h
+++ b/components/viz/service/display/surface_aggregator.h
@@ -64,11 +64,25 @@
   bool NotifySurfaceDamageAndCheckForDisplayDamage(const SurfaceId& surface_id);
 
  private:
-  struct ClipData;
-  struct PrewalkResult;
-  struct RoundedCornerInfo;
-  struct ChildSurfaceInfo;
-  struct RenderPassMapEntry;
+  struct ClipData {
+    ClipData() : is_clipped(false) {}
+    ClipData(bool is_clipped, const gfx::Rect& rect)
+        : is_clipped(is_clipped), rect(rect) {}
+
+    std::string ToString() const;
+
+    bool is_clipped;
+    gfx::Rect rect;
+  };
+
+  struct PrewalkResult {
+    PrewalkResult();
+    ~PrewalkResult();
+    // This is the set of Surfaces that were referenced by another Surface, but
+    // not included in a SurfaceDrawQuad.
+    base::flat_set<SurfaceId> undrawn_surfaces;
+    bool may_contain_video = false;
+  };
 
   struct RenderPassInfo {
     // This is the id the pass is mapped to.
@@ -77,6 +91,20 @@
     bool in_use = true;
   };
 
+  struct RoundedCornerInfo {
+    RoundedCornerInfo() : is_fast_rounded_corner(false) {}
+    // |target_transform| is the transform that maps |bounds| from its current
+    // space into the desired target space. It must be a scale+translation
+    // matrix.
+    RoundedCornerInfo(const gfx::RRectF& bounds,
+                      bool is_fast_rounded_corner,
+                      const gfx::Transform target_transform);
+
+    bool IsEmpty() const { return bounds.IsEmpty(); }
+    gfx::RRectF bounds;
+    bool is_fast_rounded_corner;
+  };
+
   ClipData CalculateClipRect(const ClipData& surface_clip,
                              const ClipData& quad_clip,
                              const gfx::Transform& target_transform);
@@ -160,14 +188,6 @@
       const gfx::Rect& occluding_damage_rect,
       bool occluding_damage_rect_valid);
 
-  void FindChildSurfaces(
-      SurfaceId surface_id,
-      base::flat_map<RenderPassId, RenderPassMapEntry>* render_pass_map,
-      const base::flat_set<RenderPassId>& pixel_moving_background_filter_passes,
-      const gfx::Transform& parent_transform,
-      RenderPassId render_pass_id,
-      base::flat_map<SurfaceRange, ChildSurfaceInfo>* child_surfaces,
-      gfx::Rect* pixel_moving_backdrop_filters_rect);
   gfx::Rect PrewalkTree(Surface* surface,
                         bool in_moved_pixel_surface,
                         int parent_pass,
diff --git a/components/viz/service/display/surface_aggregator_unittest.cc b/components/viz/service/display/surface_aggregator_unittest.cc
index 03260bf..7a813bb 100644
--- a/components/viz/service/display/surface_aggregator_unittest.cc
+++ b/components/viz/service/display/surface_aggregator_unittest.cc
@@ -204,7 +204,6 @@
     }
 
     DrawQuad::Material material;
-
     // Set when material==DrawQuad::Material::kSurfaceContent.
     SurfaceRange surface_range;
     SkColor default_background_color;
@@ -213,15 +212,13 @@
     gfx::Rect primary_surface_rect;
     float opacity;
     gfx::Transform to_target_transform;
-    gfx::RRectF rounded_corner_bounds;
-    bool is_fast_rounded_corner;
-
     // Set when material==DrawQuad::Material::kSolidColor.
     SkColor color;
     gfx::Rect rect;
-
     // Set when material==DrawQuad::Material::kRenderPass.
     RenderPassId render_pass_id;
+    gfx::RRectF rounded_corner_bounds;
+    bool is_fast_rounded_corner;
 
    private:
     Quad()
@@ -2921,8 +2918,7 @@
   auto parent_support = std::make_unique<CompositorFrameSinkSupport>(
       nullptr, &manager_, kArbitraryMiddleFrameSinkId, kChildIsRoot,
       kNeedsSyncPoints);
-  std::vector<Quad> child_quads = {
-      Quad::SolidColorQuad(SK_ColorGREEN, gfx::Rect(5, 5))};
+  std::vector<Quad> child_quads = {Quad::RenderPassQuad(1)};
   std::vector<Pass> child_passes = {Pass(child_quads, 1, SurfaceSize())};
 
   CompositorFrame child_frame = MakeEmptyCompositorFrame();
@@ -3110,8 +3106,7 @@
   auto parent_support = std::make_unique<CompositorFrameSinkSupport>(
       nullptr, &manager_, kArbitraryMiddleFrameSinkId, kChildIsRoot,
       kNeedsSyncPoints);
-  std::vector<Quad> child_quads = {
-      Quad::SolidColorQuad(SK_ColorGREEN, gfx::Rect(5, 5))};
+  std::vector<Quad> child_quads = {Quad::RenderPassQuad(1)};
   std::vector<Pass> child_passes = {Pass(child_quads, 1, gfx::Size(100, 100))};
 
   CompositorFrame child_frame = MakeEmptyCompositorFrame();
@@ -3220,8 +3215,7 @@
   auto parent_support = std::make_unique<CompositorFrameSinkSupport>(
       nullptr, &manager_, kArbitraryMiddleFrameSinkId, kChildIsRoot,
       kNeedsSyncPoints);
-  std::vector<Quad> child_quads = {
-      Quad::SolidColorQuad(SK_ColorGREEN, gfx::Rect(5, 5))};
+  std::vector<Quad> child_quads = {Quad::RenderPassQuad(1)};
   std::vector<Pass> child_passes = {Pass(child_quads, 1, gfx::Size(100, 100))};
 
   CompositorFrame child_frame = MakeEmptyCompositorFrame();
@@ -3644,17 +3638,14 @@
   // the other other with a visible rect of 10,10 2x2 (relative to root target
   // space), and one with a non-invertible transform.
   {
-    int child_pass_ids[] = {1, 2, 3};
-    std::vector<Quad> child_quads1 = {
-        Quad::SolidColorQuad(SK_ColorGREEN, gfx::Rect(5, 5))};
-    std::vector<Quad> child_quads2 = {
-        Quad::SolidColorQuad(SK_ColorGREEN, gfx::Rect(5, 5))};
-    std::vector<Quad> child_quads3 = {
-        Quad::SolidColorQuad(SK_ColorGREEN, gfx::Rect(5, 5))};
+    int child_pass_id = 1;
+    std::vector<Quad> child_quads1 = {Quad::RenderPassQuad(child_pass_id)};
+    std::vector<Quad> child_quads2 = {Quad::RenderPassQuad(child_pass_id)};
+    std::vector<Quad> child_quads3 = {Quad::RenderPassQuad(child_pass_id)};
     std::vector<Pass> child_passes = {
-        Pass(child_quads1, child_pass_ids[0], SurfaceSize()),
-        Pass(child_quads2, child_pass_ids[1], SurfaceSize()),
-        Pass(child_quads3, child_pass_ids[2], SurfaceSize())};
+        Pass(child_quads1, child_pass_id, SurfaceSize()),
+        Pass(child_quads2, child_pass_id, SurfaceSize()),
+        Pass(child_quads3, child_pass_id, SurfaceSize())};
 
     RenderPassList child_pass_list;
     std::vector<SurfaceRange> referenced_surfaces;
@@ -4422,8 +4413,7 @@
 // Tests that has_damage_from_contributing_content is aggregated correctly from
 // child surface quads.
 TEST_F(SurfaceAggregatorValidSurfaceTest, HasDamageByChangingChildSurface) {
-  std::vector<Quad> child_surface_quads = {
-      Quad::SolidColorQuad(SK_ColorGREEN, gfx::Rect(5, 5))};
+  std::vector<Quad> child_surface_quads = {Quad::RenderPassQuad(1)};
   std::vector<Pass> child_surface_passes = {
       Pass(child_surface_quads, 1, SurfaceSize())};
 
@@ -4504,8 +4494,7 @@
       nullptr, &manager_, kArbitraryMiddleFrameSinkId, kChildIsRoot,
       kNeedsSyncPoints);
 
-  std::vector<Quad> child_surface_quads = {
-      Quad::SolidColorQuad(SK_ColorGREEN, gfx::Rect(5, 5))};
+  std::vector<Quad> child_surface_quads = {Quad::RenderPassQuad(1)};
   std::vector<Pass> child_surface_passes = {
       Pass(child_surface_quads, 1, SurfaceSize())};
 
@@ -4549,8 +4538,7 @@
   }
 
   // Add a grand_child_frame should cause damage.
-  std::vector<Quad> grand_child_quads = {
-      Quad::SolidColorQuad(SK_ColorGREEN, gfx::Rect(5, 5))};
+  std::vector<Quad> grand_child_quads = {Quad::RenderPassQuad(1)};
   std::vector<Pass> grand_child_passes = {
       Pass(grand_child_quads, 1, SurfaceSize())};
   ParentLocalSurfaceIdAllocator grandchild_allocator;
@@ -4628,8 +4616,7 @@
 // Tests that has_damage_from_contributing_content is aggregated correctly from
 // render pass quads.
 TEST_F(SurfaceAggregatorValidSurfaceTest, HasDamageFromRenderPassQuads) {
-  std::vector<Quad> child_quads = {
-      Quad::SolidColorQuad(SK_ColorGREEN, gfx::Rect(5, 5))};
+  std::vector<Quad> child_quads = {Quad::RenderPassQuad(1)};
   std::vector<Pass> child_passes = {Pass(child_quads, 1, SurfaceSize())};
 
   CompositorFrame child_frame = MakeEmptyCompositorFrame();
@@ -5650,198 +5637,5 @@
             aggregated_first_pass_sqs->rounded_corner_bounds);
 }
 
-// Verifies that if a child surface is embedded twice in the root surface,
-// SurfaceAggregator considers both occurrences in damage rect calculation.
-TEST_F(SurfaceAggregatorValidSurfaceTest,
-       AggregateDamageRectWithMutiplyEmbeddedSurface) {
-  // Add a callback for when the surface is damaged.
-  MockAggregatedDamageCallback aggregated_damage_callback;
-  root_sink_->SetAggregatedDamageCallbackForTesting(
-      aggregated_damage_callback.GetCallback());
-
-  // The child surface consists of a single render pass containing a single
-  // solid color draw quad.
-  std::vector<Quad> child_quads = {
-      Quad::SolidColorQuad(SK_ColorGREEN, gfx::Rect(5, 5))};
-  std::vector<Pass> child_passes = {Pass(child_quads, SurfaceSize())};
-
-  CompositorFrame child_frame = MakeEmptyCompositorFrame();
-  AddPasses(&child_frame.render_pass_list, child_passes,
-            &child_frame.metadata.referenced_surfaces);
-
-  ParentLocalSurfaceIdAllocator child_allocator;
-  child_allocator.GenerateId();
-  LocalSurfaceId child_local_surface_id =
-      child_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
-  SurfaceId child_surface_id(child_sink_->frame_sink_id(),
-                             child_local_surface_id);
-  child_sink_->SubmitCompositorFrame(child_local_surface_id,
-                                     std::move(child_frame));
-
-  // The root surface consists of two render passes:
-  //  1) The first one contains a surface draw quad referencing the child
-  //     surface.
-  //  2) The Second one consists of two render pass draw quads both referencing
-  //     the first render pass. However, the second draw quad has a transform
-  //     applied.
-  std::vector<Quad> root_quads_1 = {Quad::SurfaceQuad(
-      SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
-      gfx::Rect(5, 5), /*stretch_content_to_fill_bounds=*/false,
-      /*ignores_input_event=*/false)};
-  std::vector<Quad> root_quads_2 = {Quad::RenderPassQuad(1),
-                                    Quad::RenderPassQuad(1)};
-  std::vector<Pass> root_passes = {Pass(root_quads_1, 1, SurfaceSize()),
-                                   Pass(root_quads_2, 2, SurfaceSize())};
-
-  CompositorFrame root_frame = MakeEmptyCompositorFrame();
-  AddPasses(&root_frame.render_pass_list, root_passes,
-            &root_frame.metadata.referenced_surfaces);
-
-  auto& rpdq_2_transform = root_frame.render_pass_list.back()
-                               ->shared_quad_state_list.back()
-                               ->quad_to_target_transform;
-  rpdq_2_transform.Translate(30.f, 50.f);
-  rpdq_2_transform.Scale(2.f, 2.f);
-
-  root_sink_->SubmitCompositorFrame(root_local_surface_id_,
-                                    std::move(root_frame));
-
-  SurfaceId root_surface_id(root_sink_->frame_sink_id(),
-                            root_local_surface_id_);
-
-  // Damage rect for the first aggregation would contain entire root surface
-  // which is union of (0,0 100x100) and (30,50 200x200); i.e. (0,0 230x250).
-  EXPECT_CALL(
-      aggregated_damage_callback,
-      OnAggregatedDamage(root_local_surface_id_, SurfaceSize(),
-                         gfx::Rect(0, 0, 230, 250), next_display_time()));
-  CompositorFrame aggregated_frame = AggregateFrame(root_surface_id);
-  testing::Mock::VerifyAndClearExpectations(&aggregated_damage_callback);
-
-  // For the second aggregation we only damage the child surface at
-  // (10,10 10x10). The aggregated damage rect should reflect that.
-  CompositorFrame child_frame_2 = MakeEmptyCompositorFrame();
-  AddPasses(&child_frame_2.render_pass_list, child_passes,
-            &child_frame_2.metadata.referenced_surfaces);
-
-  child_frame_2.render_pass_list.back()->damage_rect =
-      gfx::Rect(10, 10, 10, 10);
-
-  child_sink_->SubmitCompositorFrame(child_local_surface_id,
-                                     std::move(child_frame_2));
-
-  // The child surface is embedded twice in the root surface, so its damage rect
-  // would appear in two locations in the root surface:
-  //  1) The first embedding has no transform, so its damage rect would simply
-  //     be (10,10 10x10).
-  //  2) The second embedding is scaled by a factor of 2 and translated by
-  //     (30,50). So, its damage rect would be (10*2+30,10*2+50 10*2x10*2) =
-  //     (50,70 20x20).
-  // The aggregated damage rect would be union of the above damage rects which
-  // is (10,10 60x80).
-  gfx::Rect expected_damage_rect(10, 10, 60, 80);
-  EXPECT_CALL(aggregated_damage_callback,
-              OnAggregatedDamage(root_local_surface_id_, SurfaceSize(),
-                                 expected_damage_rect, next_display_time()));
-  CompositorFrame aggregated_frame_2 = AggregateFrame(root_surface_id);
-  testing::Mock::VerifyAndClearExpectations(&aggregated_damage_callback);
-}
-
-// Verifies that if a child surface is embedded in the root surface inside a
-// render pass cycle, only the first embedding of the child surface is
-// considered in the damage rect and its repeated embeddings are ignored.
-TEST_F(SurfaceAggregatorValidSurfaceTest,
-       AggregateDamageRectWithRenderPassCycle) {
-  // Add a callback for when the surface is damaged.
-  MockAggregatedDamageCallback aggregated_damage_callback;
-  root_sink_->SetAggregatedDamageCallbackForTesting(
-      aggregated_damage_callback.GetCallback());
-
-  // The child surface consists of a single render pass containing a single
-  // solid color draw quad.
-  std::vector<Quad> child_quads = {
-      Quad::SolidColorQuad(SK_ColorGREEN, gfx::Rect(5, 5))};
-  std::vector<Pass> child_passes = {Pass(child_quads, SurfaceSize())};
-
-  CompositorFrame child_frame = MakeEmptyCompositorFrame();
-  AddPasses(&child_frame.render_pass_list, child_passes,
-            &child_frame.metadata.referenced_surfaces);
-
-  ParentLocalSurfaceIdAllocator child_allocator;
-  child_allocator.GenerateId();
-  LocalSurfaceId child_local_surface_id =
-      child_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
-  SurfaceId child_surface_id(child_sink_->frame_sink_id(),
-                             child_local_surface_id);
-  child_sink_->SubmitCompositorFrame(child_local_surface_id,
-                                     std::move(child_frame));
-
-  // The root surface consists of two render passes:
-  //  1) The first render pass contains a surface draw quad referencing the
-  //     child surface and a render pass draw quad referencing the second render
-  //     pass.
-  //  2) The second render pass contains a render pass draw quad with a
-  //     transform applied that is referencing the first render pass, creating a
-  //     cycle.
-  RenderPassId root_pass_ids[] = {1, 2};
-  std::vector<Quad> root_quads_1 = {
-      Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_surface_id),
-                        SK_ColorWHITE, gfx::Rect(5, 5),
-                        /*stretch_content_to_fill_bounds=*/false,
-                        /*ignores_input_event=*/false),
-      Quad::RenderPassQuad(root_pass_ids[1])};
-  std::vector<Quad> root_quads_2 = {Quad::RenderPassQuad(root_pass_ids[0])};
-  std::vector<Pass> root_passes = {
-      Pass(root_quads_2, root_pass_ids[1], SurfaceSize()),
-      Pass(root_quads_1, root_pass_ids[0], SurfaceSize())};
-
-  CompositorFrame root_frame = MakeEmptyCompositorFrame();
-  AddPasses(&root_frame.render_pass_list, root_passes,
-            &root_frame.metadata.referenced_surfaces);
-
-  auto& rpdq_2_transform = root_frame.render_pass_list.front()
-                               ->shared_quad_state_list.back()
-                               ->quad_to_target_transform;
-  rpdq_2_transform.Translate(30.f, 50.f);
-  rpdq_2_transform.Scale(2.f, 2.f);
-
-  root_sink_->SubmitCompositorFrame(root_local_surface_id_,
-                                    std::move(root_frame));
-
-  SurfaceId root_surface_id(root_sink_->frame_sink_id(),
-                            root_local_surface_id_);
-
-  // Damage rect for the first aggregation would contain entire root surface
-  // which is just (0,0 100x100). The child surface is only embedded once and
-  // without any transform, since repeated embeddings caused by the render pass
-  // cycle are ignored.
-  EXPECT_CALL(
-      aggregated_damage_callback,
-      OnAggregatedDamage(root_local_surface_id_, SurfaceSize(),
-                         gfx::Rect(0, 0, 100, 100), next_display_time()));
-  CompositorFrame aggregated_frame = AggregateFrame(root_surface_id);
-  testing::Mock::VerifyAndClearExpectations(&aggregated_damage_callback);
-
-  // For the second aggregation we only damage the child surface at
-  // (10,10 10x10). The aggregated damage rect should reflect that only for the
-  // first embedding.
-  CompositorFrame child_frame_2 = MakeEmptyCompositorFrame();
-  AddPasses(&child_frame_2.render_pass_list, child_passes,
-            &child_frame_2.metadata.referenced_surfaces);
-
-  child_frame_2.render_pass_list.back()->damage_rect =
-      gfx::Rect(10, 10, 10, 10);
-
-  child_sink_->SubmitCompositorFrame(child_local_surface_id,
-                                     std::move(child_frame_2));
-
-  gfx::Rect expected_damage_rect(10, 10, 10, 10);
-  EXPECT_CALL(aggregated_damage_callback,
-              OnAggregatedDamage(root_local_surface_id_, SurfaceSize(),
-                                 expected_damage_rect, next_display_time()));
-  CompositorFrame aggregated_frame_2 = AggregateFrame(root_surface_id);
-  testing::Mock::VerifyAndClearExpectations(&aggregated_damage_callback);
-}
-
 }  // namespace
 }  // namespace viz
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
index 90c04ef8..c8244fa 100644
--- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -413,12 +413,29 @@
   RunAriaTest(FILE_PATH_LITERAL("aria-columnheader.html"));
 }
 
-IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AccessibilityAriaCombobox) {
+#if defined(OS_ANDROID)
+// TODO(crbug.com/986673): test is flaky on android.
+#define MAYBE_AccessibilityAriaCombobox DISABLED_AccessibilityAriaCombobox
+#else
+#define MAYBE_AccessibilityAriaCombobox AccessibilityAriaCombobox
+#endif
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest,
+                       MAYBE_AccessibilityAriaCombobox) {
   RunAriaTest(FILE_PATH_LITERAL("aria-combobox.html"));
 }
 
+#if defined(OS_ANDROID)
+// TODO(crbug.com/986673): test is flaky on android.
+#define MAYBE_AccessibilityAriaOnePointOneCombobox \
+  DISABLED_AccessibilityAriaOnePointOneCombobox
+#else
+#define MAYBE_AccessibilityAriaOnePointOneCombobox \
+  AccessibilityAriaOnePointOneCombobox
+#endif
+
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest,
-                       AccessibilityAriaOnePointOneCombobox) {
+                       MAYBE_AccessibilityAriaOnePointOneCombobox) {
   RunAriaTest(FILE_PATH_LITERAL("aria1.1-combobox.html"));
 }
 
@@ -1537,8 +1554,16 @@
   RunHtmlTest(FILE_PATH_LITERAL("input-text.html"));
 }
 
+#if defined(OS_ANDROID)
+// TODO(crbug.com/986673): test is flaky on android.
+#define MAYBE_AccessibilityInputTextReadOnly \
+  DISABLED_AccessibilityInputTextReadOnly
+#else
+#define MAYBE_AccessibilityInputTextReadOnly AccessibilityInputTextReadOnly
+#endif
+
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest,
-                       AccessibilityInputTextReadOnly) {
+                       MAYBE_AccessibilityInputTextReadOnly) {
   RunHtmlTest(FILE_PATH_LITERAL("input-text-read-only.html"));
 }
 
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 783925a..e0d5b840 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -5144,15 +5144,23 @@
       auto* storage_partition = static_cast<StoragePartitionImpl*>(
           BrowserContext::GetStoragePartition(
               GetSiteInstance()->GetBrowserContext(), GetSiteInstance()));
-      base::PostTaskWithTraits(
-          FROM_HERE, {BrowserThread::IO},
-          base::BindOnce(
-              &PrefetchURLLoaderService::GetFactory,
-              storage_partition->GetPrefetchURLLoaderService(),
-              prefetch_loader_factory.InitWithNewPipeAndPassReceiver(),
-              frame_tree_node_->frame_tree_node_id(),
-              std::move(factory_bundle_for_prefetch),
-              EnsurePrefetchedSignedExchangeCache()));
+      if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
+        storage_partition->GetPrefetchURLLoaderService()->GetFactory(
+            prefetch_loader_factory.InitWithNewPipeAndPassReceiver(),
+            frame_tree_node_->frame_tree_node_id(),
+            std::move(factory_bundle_for_prefetch),
+            EnsurePrefetchedSignedExchangeCache());
+      } else {
+        base::PostTaskWithTraits(
+            FROM_HERE, {BrowserThread::IO},
+            base::BindOnce(
+                &PrefetchURLLoaderService::GetFactory,
+                storage_partition->GetPrefetchURLLoaderService(),
+                prefetch_loader_factory.InitWithNewPipeAndPassReceiver(),
+                frame_tree_node_->frame_tree_node_id(),
+                std::move(factory_bundle_for_prefetch),
+                EnsurePrefetchedSignedExchangeCache()));
+      }
     }
 
     mojom::NavigationClient* navigation_client = nullptr;
diff --git a/content/browser/loader/cross_origin_read_blocking_checker.cc b/content/browser/loader/cross_origin_read_blocking_checker.cc
index 22b9e7a..e98febff 100644
--- a/content/browser/loader/cross_origin_read_blocking_checker.cc
+++ b/content/browser/loader/cross_origin_read_blocking_checker.cc
@@ -5,6 +5,9 @@
 #include "content/browser/loader/cross_origin_read_blocking_checker.h"
 
 #include "base/callback.h"
+#include "base/task/post_task.h"
+#include "content/browser/loader/navigation_url_loader_impl.h"
+#include "content/public/browser/browser_task_traits.h"
 #include "net/base/io_buffer.h"
 #include "net/base/mime_sniffer.h"
 #include "services/network/cross_origin_read_blocking.h"
@@ -16,6 +19,81 @@
 
 namespace content {
 
+// When NavigationLoaderOnUI is enabled, the CrossOriginReadBlockingChecker
+// lives on the UI thread, but blobs must be read on IO. This class handles all
+// blob access for CrossOriginReadBlockingChecker.
+class CrossOriginReadBlockingChecker::BlobIOState {
+ public:
+  BlobIOState(base::WeakPtr<CrossOriginReadBlockingChecker> checker,
+              std::unique_ptr<storage::BlobDataHandle> blob_data_handle)
+      : checker_(std::move(checker)),
+        blob_data_handle_(std::move(blob_data_handle)) {}
+
+  ~BlobIOState() { DCHECK_CURRENTLY_ON(BrowserThread::IO); }
+
+  void StartSniffing() {
+    DCHECK_CURRENTLY_ON(BrowserThread::IO);
+    blob_reader_ = blob_data_handle_->CreateReader();
+    const storage::BlobReader::Status size_status = blob_reader_->CalculateSize(
+        base::BindOnce(&BlobIOState::DidCalculateSize, base::Unretained(this)));
+    switch (size_status) {
+      case storage::BlobReader::Status::NET_ERROR:
+        OnNetError();
+        return;
+      case storage::BlobReader::Status::IO_PENDING:
+        return;
+      case storage::BlobReader::Status::DONE:
+        DidCalculateSize(net::OK);
+        return;
+    }
+  }
+
+ private:
+  void DidCalculateSize(int result) {
+    DCHECK_CURRENTLY_ON(BrowserThread::IO);
+    size_t buf_size = net::kMaxBytesToSniff;
+    if (buf_size > blob_reader_->total_size())
+      buf_size = blob_reader_->total_size();
+    buffer_ = base::MakeRefCounted<net::IOBufferWithSize>(buf_size);
+    int bytes_read;
+    const storage::BlobReader::Status status = blob_reader_->Read(
+        buffer_.get(), buf_size, &bytes_read,
+        base::BindOnce(&BlobIOState::OnReadComplete, base::Unretained(this)));
+    switch (status) {
+      case storage::BlobReader::Status::NET_ERROR:
+        OnNetError();
+        return;
+      case storage::BlobReader::Status::IO_PENDING:
+        return;
+      case storage::BlobReader::Status::DONE:
+        OnReadComplete(bytes_read);
+        return;
+    }
+  }
+
+  void OnNetError() {
+    NavigationURLLoaderImpl::RunOrPostTaskOnLoaderThread(
+        FROM_HERE, base::BindOnce(&CrossOriginReadBlockingChecker::OnNetError,
+                                  checker_, blob_reader_->net_error()));
+  }
+
+  void OnReadComplete(int bytes_read) {
+    NavigationURLLoaderImpl::RunOrPostTaskOnLoaderThread(
+        FROM_HERE,
+        base::BindOnce(&CrossOriginReadBlockingChecker::OnReadComplete,
+                       checker_, bytes_read, buffer_,
+                       blob_reader_->net_error()));
+  }
+
+  // |checker_| should only be accessed on the thread the navigation loader is
+  // running on.
+  base::WeakPtr<CrossOriginReadBlockingChecker> checker_;
+
+  scoped_refptr<net::IOBufferWithSize> buffer_;
+  std::unique_ptr<storage::BlobDataHandle> blob_data_handle_;
+  std::unique_ptr<storage::BlobReader> blob_reader_;
+};
+
 CrossOriginReadBlockingChecker::CrossOriginReadBlockingChecker(
     const network::ResourceRequest& request,
     const network::ResourceResponseHead& response,
@@ -35,18 +113,34 @@
     return;
   }
   if (corb_analyzer_->needs_sniffing()) {
-    StartSniffing(blob_data_handle);
+    blob_io_state_ = std::make_unique<BlobIOState>(
+        weak_factory_.GetWeakPtr(),
+        std::make_unique<storage::BlobDataHandle>(blob_data_handle));
+    if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
+      // base::Unretained is safe because |blob_io_state_| will be deleted on
+      // the IO thread.
+      base::PostTaskWithTraits(
+          FROM_HERE, {BrowserThread::IO},
+          base::BindOnce(&BlobIOState::StartSniffing,
+                         base::Unretained(blob_io_state_.get())));
+    } else {
+      blob_io_state_->StartSniffing();
+    }
     return;
   }
   DCHECK(corb_analyzer_->ShouldAllow());
   OnAllowed();
 }
 
-CrossOriginReadBlockingChecker::~CrossOriginReadBlockingChecker() = default;
+CrossOriginReadBlockingChecker::~CrossOriginReadBlockingChecker() {
+  if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
+    BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE,
+                              std::move(blob_io_state_));
+  }
+}
 
 int CrossOriginReadBlockingChecker::GetNetError() {
-  DCHECK(blob_reader_);
-  return blob_reader_->net_error();
+  return net_error_;
 }
 
 void CrossOriginReadBlockingChecker::OnAllowed() {
@@ -61,56 +155,20 @@
                                : Result::kBlocked_ShouldNotReport);
 }
 
-void CrossOriginReadBlockingChecker::OnNetError() {
+void CrossOriginReadBlockingChecker::OnNetError(int net_error) {
+  net_error_ = net_error;
   std::move(callback_).Run(Result::kNetError);
 }
 
-void CrossOriginReadBlockingChecker::StartSniffing(
-    const storage::BlobDataHandle& blob_data_handle) {
-  blob_reader_ = blob_data_handle.CreateReader();
-  const storage::BlobReader::Status size_status = blob_reader_->CalculateSize(
-      base::BindOnce(&CrossOriginReadBlockingChecker::DidCalculateSize,
-                     base::Unretained(this)));
-  switch (size_status) {
-    case storage::BlobReader::Status::NET_ERROR:
-      OnNetError();
-      return;
-    case storage::BlobReader::Status::IO_PENDING:
-      return;
-    case storage::BlobReader::Status::DONE:
-      DidCalculateSize(net::OK);
-      return;
-  }
-}
-
-void CrossOriginReadBlockingChecker::DidCalculateSize(int result) {
-  size_t buf_size = net::kMaxBytesToSniff;
-  if (buf_size > blob_reader_->total_size())
-    buf_size = blob_reader_->total_size();
-  buffer_ = base::MakeRefCounted<net::IOBufferWithSize>(buf_size);
-  int bytes_read;
-  const storage::BlobReader::Status status = blob_reader_->Read(
-      buffer_.get(), buf_size, &bytes_read,
-      base::BindOnce(&CrossOriginReadBlockingChecker::OnReadComplete,
-                     base::Unretained(this)));
-  switch (status) {
-    case storage::BlobReader::Status::NET_ERROR:
-      OnNetError();
-      return;
-    case storage::BlobReader::Status::IO_PENDING:
-      return;
-    case storage::BlobReader::Status::DONE:
-      OnReadComplete(bytes_read);
-      return;
-  }
-}
-
-void CrossOriginReadBlockingChecker::OnReadComplete(int bytes_read) {
-  if (bytes_read != buffer_->size()) {
-    OnNetError();
+void CrossOriginReadBlockingChecker::OnReadComplete(
+    int bytes_read,
+    scoped_refptr<net::IOBufferWithSize> buffer,
+    int net_error) {
+  if (bytes_read != buffer->size()) {
+    OnNetError(net_error);
     return;
   }
-  base::StringPiece data(buffer_->data(), bytes_read);
+  base::StringPiece data(buffer->data(), bytes_read);
   corb_analyzer_->SniffResponseBody(data, 0);
   if (corb_analyzer_->ShouldBlock()) {
     OnBlocked();
diff --git a/content/browser/loader/cross_origin_read_blocking_checker.h b/content/browser/loader/cross_origin_read_blocking_checker.h
index f72a8cb..b8bda3d 100644
--- a/content/browser/loader/cross_origin_read_blocking_checker.h
+++ b/content/browser/loader/cross_origin_read_blocking_checker.h
@@ -7,6 +7,8 @@
 
 #include "base/callback_forward.h"
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "net/base/net_errors.h"
 #include "services/network/cross_origin_read_blocking.h"
 
 namespace net {
@@ -20,7 +22,6 @@
 
 namespace storage {
 class BlobDataHandle;
-class BlobReader;
 }  // namespace storage
 
 namespace url {
@@ -50,21 +51,23 @@
   int GetNetError();
 
  private:
+  class BlobIOState;
+
   void OnAllowed();
   void OnBlocked();
-  void OnNetError();
+  void OnNetError(int net_error);
 
-  void StartSniffing(const storage::BlobDataHandle& blob_data_handle);
-
-  void DidCalculateSize(int result);
-
-  void OnReadComplete(int bytes_read);
+  void OnReadComplete(int bytes_read,
+                      scoped_refptr<net::IOBufferWithSize> buffer,
+                      int net_error);
 
   base::OnceCallback<void(Result)> callback_;
   std::unique_ptr<network::CrossOriginReadBlocking::ResponseAnalyzer>
       corb_analyzer_;
-  std::unique_ptr<storage::BlobReader> blob_reader_;
-  scoped_refptr<net::IOBufferWithSize> buffer_;
+  std::unique_ptr<BlobIOState> blob_io_state_;
+  int net_error_ = net::OK;
+
+  base::WeakPtrFactory<CrossOriginReadBlockingChecker> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(CrossOriginReadBlockingChecker);
 };
diff --git a/content/browser/loader/cross_site_document_resource_handler.cc b/content/browser/loader/cross_site_document_resource_handler.cc
index 8bc3ce2..b74bbef 100644
--- a/content/browser/loader/cross_site_document_resource_handler.cc
+++ b/content/browser/loader/cross_site_document_resource_handler.cc
@@ -35,6 +35,7 @@
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "services/metrics/public/cpp/ukm_recorder.h"
 #include "services/network/cross_origin_resource_policy.h"
+#include "services/network/public/mojom/network_context.mojom.h"
 
 using MimeType = network::CrossOriginReadBlocking::MimeType;
 
@@ -148,10 +149,12 @@
     network::ResourceResponse* response,
     std::unique_ptr<ResourceController> controller) {
   // Enforce the Cross-Origin-Resource-Policy (CORP) header.
+  // COEP is not supported when the network service is disabled.
   if (network::CrossOriginResourcePolicy::kBlock ==
       network::CrossOriginResourcePolicy::Verify(
           request()->url(), request()->initiator(), response->head,
-          request_mode_, kNonNetworkServiceInitiatorLock)) {
+          request_mode_, kNonNetworkServiceInitiatorLock,
+          network::mojom::CrossOriginEmbedderPolicy::kNone)) {
     blocked_read_completed_ = true;
     blocked_by_cross_origin_resource_policy_ = true;
     controller->Cancel();
@@ -168,10 +171,12 @@
   has_response_started_ = true;
 
   // Enforce the Cross-Origin-Resource-Policy (CORP) header.
+  // COEP is not supported when the network service is disabled.
   if (network::CrossOriginResourcePolicy::kBlock ==
       network::CrossOriginResourcePolicy::Verify(
           request()->url(), request()->initiator(), response->head,
-          request_mode_, kNonNetworkServiceInitiatorLock)) {
+          request_mode_, kNonNetworkServiceInitiatorLock,
+          network::mojom::CrossOriginEmbedderPolicy::kNone)) {
     blocked_read_completed_ = true;
     blocked_by_cross_origin_resource_policy_ = true;
     controller->Cancel();
diff --git a/content/browser/loader/mime_sniffing_resource_handler.cc b/content/browser/loader/mime_sniffing_resource_handler.cc
index 660ae5b..b0458c1 100644
--- a/content/browser/loader/mime_sniffing_resource_handler.cc
+++ b/content/browser/loader/mime_sniffing_resource_handler.cc
@@ -467,7 +467,7 @@
   if (!must_download) {
     if (blink::IsSupportedMimeType(mime_type))
       return true;
-    if (signed_exchange_utils::IsSignedExchangeHandlingEnabled(
+    if (signed_exchange_utils::IsSignedExchangeHandlingEnabledOnIO(
             info->GetContext()) &&
         signed_exchange_utils::ShouldHandleAsSignedHTTPExchange(
             request()->url(), response_->head)) {
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index 43e29e1..fea66c7 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -518,7 +518,6 @@
         base::Unretained(appcache_handle_core));
 
     StartInternal(request_info_.get(),
-                  /*service_worker_navigation_handle=*/nullptr,
                   service_worker_navigation_handle_core,
                   /*appcache_handle_core=*/nullptr,
                   std::move(prefetched_signed_exchange_cache),
@@ -555,6 +554,7 @@
     web_contents_getter_ = base::BindRepeating(
         &WebContents::FromFrameTreeNodeId, frame_tree_node_id_);
     navigation_ui_data_ = std::move(navigation_ui_data);
+    service_worker_navigation_handle_ = service_worker_navigation_handle;
 
     base::PostTaskWithTraits(
         FROM_HERE, {BrowserThread::UI},
@@ -586,13 +586,12 @@
       CHECK(result && blob_handles_.empty());
     }
 
-    StartInternal(request_info.get(), service_worker_navigation_handle,
-                  service_worker_navigation_handle_core, appcache_handle_core,
-                  std::move(prefetched_signed_exchange_cache),
-                  std::move(signed_exchange_prefetch_metric_recorder),
-                  std::move(factory_for_webui),
-                  nullptr /* url_request_context_getter */,
-                  std::move(accept_langs));
+    StartInternal(
+        request_info.get(), service_worker_navigation_handle_core,
+        appcache_handle_core, std::move(prefetched_signed_exchange_cache),
+        std::move(signed_exchange_prefetch_metric_recorder),
+        std::move(factory_for_webui), nullptr /* url_request_context_getter */,
+        std::move(accept_langs));
   }
 
   // Common setup routines, called by both StartWithoutNetworkService() and
@@ -608,8 +607,6 @@
   // shipped.
   void StartInternal(
       NavigationRequestInfo* request_info,
-      ServiceWorkerNavigationHandle*
-          service_worker_navigation_handle /* ui thread only */,
       ServiceWorkerNavigationHandleCore*
           service_worker_navigation_handle_core /* io thread only */,
       AppCacheNavigationHandleCore* appcache_handle_core,
@@ -623,9 +620,13 @@
     DCHECK_CURRENTLY_ON(GetLoaderRequestControllerThreadID());
 
     std::string accept_value = network::kFrameAcceptHeader;
-    // TODO(http://crbug.com/824840): Make this work on UI thread.
-    if (!IsNavigationLoaderOnUIEnabled()) {
+    if (IsNavigationLoaderOnUIEnabled()) {
       if (signed_exchange_utils::IsSignedExchangeHandlingEnabled(
+              browser_context_)) {
+        accept_value.append(kAcceptHeaderSignedExchangeSuffix);
+      }
+    } else {
+      if (signed_exchange_utils::IsSignedExchangeHandlingEnabledOnIO(
               resource_context_)) {
         accept_value.append(kAcceptHeaderSignedExchangeSuffix);
       }
@@ -662,8 +663,9 @@
     }
 
     if (IsNavigationLoaderOnUIEnabled()) {
-      CreateInterceptorsForUI(request_info, service_worker_navigation_handle,
-                              appcache_handle_core);
+      CreateInterceptorsForUI(
+          request_info, appcache_handle_core, prefetched_signed_exchange_cache,
+          signed_exchange_prefetch_metric_recorder, accept_langs);
     } else {
       CreateInterceptorsForIO(
           request_info, service_worker_navigation_handle_core,
@@ -694,13 +696,28 @@
 
   void CreateInterceptorsForUI(
       NavigationRequestInfo* request_info,
-      ServiceWorkerNavigationHandle* service_worker_navigation_handle,
-      AppCacheNavigationHandleCore* appcache_handle_core) {
+      AppCacheNavigationHandleCore* appcache_handle_core,
+      scoped_refptr<PrefetchedSignedExchangeCache>
+          prefetched_signed_exchange_cache,
+      scoped_refptr<SignedExchangePrefetchMetricRecorder>
+          signed_exchange_prefetch_metric_recorder,
+      const std::string& accept_langs) {
+    if (prefetched_signed_exchange_cache) {
+      std::unique_ptr<NavigationLoaderInterceptor>
+          prefetched_signed_exchange_interceptor =
+              prefetched_signed_exchange_cache->MaybeCreateInterceptor(
+                  request_info->common_params.url);
+      if (prefetched_signed_exchange_interceptor) {
+        interceptors_.push_back(
+            std::move(prefetched_signed_exchange_interceptor));
+      }
+    }
+
     // Set up an interceptor for service workers.
-    if (service_worker_navigation_handle) {
+    if (service_worker_navigation_handle_) {
       std::unique_ptr<NavigationLoaderInterceptor> service_worker_interceptor =
           ServiceWorkerRequestHandler::CreateForNavigationUI(
-              resource_request_->url, service_worker_navigation_handle,
+              resource_request_->url, service_worker_navigation_handle_,
               *request_info);
       // The interceptor may not be created in certain cases (e.g., the origin
       // is not secure).
@@ -719,6 +736,15 @@
         interceptors_.push_back(std::move(appcache_interceptor));
     }
 
+    // Set-up an interceptor for SignedExchange handling if it is enabled.
+    if (signed_exchange_utils::IsSignedExchangeHandlingEnabled(
+            browser_context_)) {
+      interceptors_.push_back(CreateSignedExchangeRequestHandler(
+          *request_info, network_loader_factory_,
+          std::move(signed_exchange_prefetch_metric_recorder),
+          std::move(accept_langs)));
+    }
+
     // See if embedders want to add interceptors.
     std::vector<std::unique_ptr<URLLoaderRequestInterceptor>>
         browser_interceptors =
@@ -745,7 +771,7 @@
       scoped_refptr<SignedExchangePrefetchMetricRecorder>
           signed_exchange_prefetch_metric_recorder,
       net::URLRequestContextGetter* url_request_context_getter,
-      std::string accept_langs) {
+      const std::string& accept_langs) {
     DCHECK(!IsNavigationLoaderOnUIEnabled());
     if (prefetched_signed_exchange_cache) {
       std::unique_ptr<NavigationLoaderInterceptor>
@@ -783,7 +809,7 @@
     }
 
     // Set-up an interceptor for SignedExchange handling if it is enabled.
-    if (signed_exchange_utils::IsSignedExchangeHandlingEnabled(
+    if (signed_exchange_utils::IsSignedExchangeHandlingEnabledOnIO(
             resource_context_)) {
       auto network_loader_factory = network_loader_factory_;
       if (!network_loader_factory) {
@@ -1449,16 +1475,31 @@
               new_interceptors;
           new_interceptors.push_back(std::move(interceptors_[i]));
           new_interceptors.swap(interceptors_);
+          // Reset the state of ServiceWorkerProviderHost.
+          // Currently we don't support Service Worker in Signed Exchange
+          // pages. The page will not be controlled by service workers. And
+          // Service Worker related APIs will fail with NoDocumentURL error.
+          // TODO(crbug/898733): Support SignedExchange loading and Service
+          // Worker integration.
           if (service_worker_provider_host_) {
-            // Reset the state of ServiceWorkerProviderHost.
-            // Currently we don't support Service Worker in Signed Exchange
-            // pages. The page will not be controlled by service workers. And
-            // Service Worker related APIs will fail with NoDocumentURL error.
-            // TODO(crbug/898733): Support SignedExchange loading and Service
-            // Worker integration.
+            DCHECK(!NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled());
             service_worker_provider_host_->SetControllerRegistration(
                 nullptr, false /* notify_controllerchange */);
             service_worker_provider_host_->UpdateUrls(GURL(), GURL());
+          } else if (service_worker_navigation_handle_) {
+            DCHECK(NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled());
+            base::PostTaskWithTraits(
+                FROM_HERE, {BrowserThread::IO},
+                base::BindOnce(
+                    [](base::WeakPtr<ServiceWorkerProviderHost> host) {
+                      if (host) {
+                        host->SetControllerRegistration(
+                            nullptr, false /* notify_controllerchange */);
+                        host->UpdateUrls(GURL(), GURL());
+                      }
+                    },
+                    service_worker_navigation_handle_->core()
+                        ->provider_host()));
           }
         }
         return true;
@@ -1597,6 +1638,7 @@
   // Used to reset the state of ServiceWorkerProviderHost when
   // SignedExchangeRequestHandler will handle the response.
   base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host_;
+  ServiceWorkerNavigationHandle* service_worker_navigation_handle_ = nullptr;
 
   // Counts the time overhead of all the hops from the UI to the IO threads.
   base::TimeDelta ui_to_io_time_;
@@ -1938,6 +1980,14 @@
                                          : BrowserThread::IO;
 }
 
+// static
+void NavigationURLLoaderImpl::RunOrPostTaskOnLoaderThread(
+    const base::Location& from_here,
+    base::OnceClosure task) {
+  RunOrPostTaskIfNecessary(from_here, GetLoaderRequestControllerThreadID(),
+                           std::move(task));
+}
+
 void NavigationURLLoaderImpl::OnRequestStarted(base::TimeTicks timestamp) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   delegate_->OnRequestStarted(timestamp);
diff --git a/content/browser/loader/navigation_url_loader_impl.h b/content/browser/loader/navigation_url_loader_impl.h
index c5685dc4..013502c 100644
--- a/content/browser/loader/navigation_url_loader_impl.h
+++ b/content/browser/loader/navigation_url_loader_impl.h
@@ -114,6 +114,24 @@
   // running on.
   static BrowserThread::ID GetLoaderRequestControllerThreadID();
 
+  // Runs |task| on the the loader thread if already on that thread, otherwise
+  // posts a task to the loader thread.
+  static void RunOrPostTaskOnLoaderThread(const base::Location& from_here,
+                                          base::OnceClosure task);
+
+  // Deleter to use for objects that should be deleted on the loader thread.
+  struct DeleteOnLoaderThread {
+    template <typename T>
+    static void Destruct(const T* x) {
+      if (BrowserThread::CurrentlyOn(GetLoaderRequestControllerThreadID())) {
+        delete x;
+      } else {
+        BrowserThread::DeleteSoon(GetLoaderRequestControllerThreadID(),
+                                  FROM_HERE, x);
+      }
+    }
+  };
+
  private:
   class URLLoaderRequestController;
   void OnRequestStarted(base::TimeTicks timestamp);
diff --git a/content/browser/loader/prefetch_browsertest_base.cc b/content/browser/loader/prefetch_browsertest_base.cc
index c43b5c4a..43b8c54 100644
--- a/content/browser/loader/prefetch_browsertest_base.cc
+++ b/content/browser/loader/prefetch_browsertest_base.cc
@@ -8,6 +8,7 @@
 #include "base/callback.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
+#include "content/browser/loader/navigation_url_loader_impl.h"
 #include "content/browser/loader/prefetch_url_loader_service.h"
 #include "content/browser/storage_partition_impl.h"
 #include "content/browser/web_package/signed_exchange_handler.h"
@@ -56,14 +57,21 @@
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       BrowserContext::GetDefaultStoragePartition(
           shell()->web_contents()->GetBrowserContext()));
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(
-          &PrefetchURLLoaderService::RegisterPrefetchLoaderCallbackForTest,
-          base::RetainedRef(partition->GetPrefetchURLLoaderService()),
-          base::BindRepeating(
-              &PrefetchBrowserTestBase::OnPrefetchURLLoaderCalled,
-              base::Unretained(this))));
+  if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
+    partition->GetPrefetchURLLoaderService()
+        ->RegisterPrefetchLoaderCallbackForTest(base::BindRepeating(
+            &PrefetchBrowserTestBase::OnPrefetchURLLoaderCalled,
+            base::Unretained(this)));
+  } else {
+    base::PostTaskWithTraits(
+        FROM_HERE, {BrowserThread::IO},
+        base::BindOnce(
+            &PrefetchURLLoaderService::RegisterPrefetchLoaderCallbackForTest,
+            base::RetainedRef(partition->GetPrefetchURLLoaderService()),
+            base::BindRepeating(
+                &PrefetchBrowserTestBase::OnPrefetchURLLoaderCalled,
+                base::Unretained(this))));
+  }
 }
 
 void PrefetchBrowserTestBase::RegisterResponse(const std::string& url,
@@ -89,7 +97,8 @@
 }
 
 void PrefetchBrowserTestBase::OnPrefetchURLLoaderCalled() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(
+      NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID());
   base::AutoLock lock(lock_);
   prefetch_url_loader_called_++;
 }
diff --git a/content/browser/loader/prefetch_url_loader.cc b/content/browser/loader/prefetch_url_loader.cc
index 7ef617bc..1346aa7 100644
--- a/content/browser/loader/prefetch_url_loader.cc
+++ b/content/browser/loader/prefetch_url_loader.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/feature_list.h"
+#include "content/browser/loader/navigation_url_loader_impl.h"
 #include "content/browser/web_package/prefetched_signed_exchange_cache.h"
 #include "content/browser/web_package/prefetched_signed_exchange_cache_adapter.h"
 #include "content/browser/web_package/signed_exchange_prefetch_handler.h"
@@ -36,6 +37,7 @@
     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
     scoped_refptr<network::SharedURLLoaderFactory> network_loader_factory,
     URLLoaderThrottlesGetter url_loader_throttles_getter,
+    BrowserContext* browser_context,
     ResourceContext* resource_context,
     scoped_refptr<net::URLRequestContextGetter> request_context_getter,
     scoped_refptr<SignedExchangePrefetchMetricRecorder>
@@ -50,6 +52,7 @@
       client_binding_(this),
       forwarding_client_(std::move(client)),
       url_loader_throttles_getter_(url_loader_throttles_getter),
+      browser_context_(browser_context),
       resource_context_(resource_context),
       request_context_getter_(std::move(request_context_getter)),
       signed_exchange_prefetch_metric_recorder_(
@@ -57,18 +60,27 @@
       accept_langs_(accept_langs) {
   DCHECK(network_loader_factory_);
 
-  if (signed_exchange_utils::IsSignedExchangeHandlingEnabled(
-          resource_context_)) {
+  if (IsSignedExchangeHandlingEnabled()) {
     // Set the SignedExchange accept header.
     // (https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#internet-media-type-applicationsigned-exchange).
     resource_request_.headers.SetHeader(
         network::kAcceptHeader, kSignedExchangeEnabledAcceptHeaderForPrefetch);
     if (prefetched_signed_exchange_cache &&
         resource_request.is_signed_exchange_prefetch_cache_enabled) {
+      BrowserContext::BlobContextGetter getter;
+      if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
+        getter = BrowserContext::GetBlobStorageContext(browser_context_);
+      } else {
+        getter = base::BindRepeating(
+            [](base::WeakPtr<storage::BlobStorageContext> context) {
+              return context;
+            },
+            std::move(blob_storage_context));
+      }
       prefetched_signed_exchange_cache_adapter_ =
           std::make_unique<PrefetchedSignedExchangeCacheAdapter>(
-              std::move(prefetched_signed_exchange_cache),
-              std::move(blob_storage_context), resource_request.url, this);
+              std::move(prefetched_signed_exchange_cache), std::move(getter),
+              resource_request.url, this);
     }
   }
 
@@ -132,8 +144,7 @@
 
 void PrefetchURLLoader::OnReceiveResponse(
     const network::ResourceResponseHead& response) {
-  if (signed_exchange_utils::IsSignedExchangeHandlingEnabled(
-          resource_context_) &&
+  if (IsSignedExchangeHandlingEnabled() &&
       signed_exchange_utils::ShouldHandleAsSignedHTTPExchange(
           resource_request_.url, response)) {
     DCHECK(!signed_exchange_prefetch_handler_);
@@ -252,4 +263,13 @@
   forwarding_client_.reset();
 }
 
+bool PrefetchURLLoader::IsSignedExchangeHandlingEnabled() {
+  if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
+    return signed_exchange_utils::IsSignedExchangeHandlingEnabled(
+        browser_context_);
+  }
+  return signed_exchange_utils::IsSignedExchangeHandlingEnabledOnIO(
+      resource_context_);
+}
+
 }  // namespace content
diff --git a/content/browser/loader/prefetch_url_loader.h b/content/browser/loader/prefetch_url_loader.h
index b5552cc..6cd426c 100644
--- a/content/browser/loader/prefetch_url_loader.h
+++ b/content/browser/loader/prefetch_url_loader.h
@@ -36,6 +36,7 @@
 
 namespace content {
 
+class BrowserContext;
 class ResourceContext;
 class URLLoaderThrottle;
 class PrefetchedSignedExchangeCacheAdapter;
@@ -66,6 +67,7 @@
       const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
       scoped_refptr<network::SharedURLLoaderFactory> network_loader_factory,
       URLLoaderThrottlesGetter url_loader_throttles_getter,
+      BrowserContext* browser_context,
       ResourceContext* resource_context,
       scoped_refptr<net::URLRequestContextGetter> request_context_getter,
       scoped_refptr<SignedExchangePrefetchMetricRecorder>
@@ -115,6 +117,8 @@
 
   void OnNetworkConnectionError();
 
+  bool IsSignedExchangeHandlingEnabled();
+
   const base::RepeatingCallback<int(void)> frame_tree_node_id_getter_;
 
   // Set in the constructor and updated when redirected.
@@ -132,6 +136,7 @@
   // |url_loader_throttles_getter_| and |resource_context_| should be
   // valid as far as |request_context_getter_| returns non-null value.
   URLLoaderThrottlesGetter url_loader_throttles_getter_;
+  BrowserContext* browser_context_;
   ResourceContext* resource_context_;
   scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
 
diff --git a/content/browser/loader/prefetch_url_loader_service.cc b/content/browser/loader/prefetch_url_loader_service.cc
index 22ff2922..2aa397b 100644
--- a/content/browser/loader/prefetch_url_loader_service.cc
+++ b/content/browser/loader/prefetch_url_loader_service.cc
@@ -51,7 +51,8 @@
 
 PrefetchURLLoaderService::PrefetchURLLoaderService(
     BrowserContext* browser_context)
-    : preference_watcher_binding_(this),
+    : browser_context_(browser_context),
+      preference_watcher_binding_(this),
       signed_exchange_prefetch_metric_recorder_(
           base::MakeRefCounted<SignedExchangePrefetchMetricRecorder>(
               base::DefaultTickClock::GetInstance())) {
@@ -62,6 +63,8 @@
   // Create a RendererPreferenceWatcher to observe updates in the preferences.
   blink::mojom::RendererPreferenceWatcherPtr watcher_ptr;
   preference_watcher_request_ = mojo::MakeRequest(&watcher_ptr);
+  if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled())
+    preference_watcher_binding_.Bind(std::move(preference_watcher_request_));
   GetContentClient()->browser()->RegisterRendererPreferenceWatcher(
       browser_context, std::move(watcher_ptr));
 }
@@ -71,6 +74,7 @@
     scoped_refptr<net::URLRequestContextGetter> request_context_getter,
     ChromeBlobStorageContext* blob_storage_context) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK(!NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled());
   DCHECK(!resource_context_);
   DCHECK(!request_context_getter_);
   resource_context_ = resource_context;
@@ -85,7 +89,8 @@
     std::unique_ptr<network::SharedURLLoaderFactoryInfo> factories,
     scoped_refptr<PrefetchedSignedExchangeCache>
         prefetched_signed_exchange_cache) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(
+      NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID());
   auto factory_bundle =
       network::SharedURLLoaderFactory::Create(std::move(factories));
   loader_factory_receivers_.Add(
@@ -105,10 +110,12 @@
     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
     scoped_refptr<network::SharedURLLoaderFactory> network_loader_factory,
     base::RepeatingCallback<int(void)> frame_tree_node_id_getter) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(
+      NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID());
   DCHECK_EQ(static_cast<int>(ResourceType::kPrefetch),
             resource_request.resource_type);
-  DCHECK(resource_context_);
+  DCHECK(NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled() ||
+         resource_context_);
 
   if (prefetch_load_callback_for_testing_)
     prefetch_load_callback_for_testing_.Run();
@@ -132,7 +139,7 @@
           base::BindRepeating(
               &PrefetchURLLoaderService::CreateURLLoaderThrottles, this,
               resource_request, frame_tree_node_id_getter),
-          resource_context_, request_context_getter_,
+          browser_context_, resource_context_, request_context_getter_,
           signed_exchange_prefetch_metric_recorder_,
           std::move(prefetched_signed_exchange_cache), blob_storage_context_,
           accept_langs_),
@@ -149,7 +156,8 @@
     const network::ResourceRequest& resource_request,
     network::mojom::URLLoaderClientPtr client,
     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(
+      NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID());
   const auto& current_context = *loader_factory_receivers_.current_context();
   int frame_tree_node_id = current_context.frame_tree_node_id;
   CreateLoaderAndStart(
@@ -160,7 +168,8 @@
 
 void PrefetchURLLoaderService::Clone(
     network::mojom::URLLoaderFactoryRequest request) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(
+      NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID());
   loader_factory_receivers_.Add(
       this, std::move(request),
       std::make_unique<BindContext>(
@@ -181,6 +190,13 @@
       !request_context_getter_->GetURLRequestContext())
     return std::vector<std::unique_ptr<content::URLLoaderThrottle>>();
   int frame_tree_node_id = frame_tree_node_id_getter.Run();
+  if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
+    return GetContentClient()->browser()->CreateURLLoaderThrottles(
+        request, browser_context_,
+        base::BindRepeating(&WebContents::FromFrameTreeNodeId,
+                            frame_tree_node_id),
+        nullptr /* navigation_ui_data */, frame_tree_node_id);
+  }
   return GetContentClient()->browser()->CreateURLLoaderThrottlesOnIO(
       request, resource_context_,
       base::BindRepeating(&WebContents::FromFrameTreeNodeId,
diff --git a/content/browser/loader/prefetch_url_loader_service.h b/content/browser/loader/prefetch_url_loader_service.h
index 04b6df452..40bf637 100644
--- a/content/browser/loader/prefetch_url_loader_service.h
+++ b/content/browser/loader/prefetch_url_loader_service.h
@@ -10,6 +10,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "content/browser/loader/navigation_url_loader_impl.h"
 #include "content/browser/web_package/signed_exchange_prefetch_metric_recorder.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/browser_thread.h"
@@ -41,8 +42,9 @@
 class URLLoaderThrottle;
 
 class CONTENT_EXPORT PrefetchURLLoaderService final
-    : public base::RefCountedThreadSafe<PrefetchURLLoaderService,
-                                        BrowserThread::DeleteOnIOThread>,
+    : public base::RefCountedThreadSafe<
+          PrefetchURLLoaderService,
+          NavigationURLLoaderImpl::DeleteOnLoaderThread>,
       public blink::mojom::RendererPreferenceWatcher,
       public network::mojom::URLLoaderFactory {
  public:
@@ -96,7 +98,7 @@
 
  private:
   friend class base::DeleteHelper<content::PrefetchURLLoaderService>;
-  friend struct BrowserThread::DeleteOnThread<BrowserThread::IO>;
+  friend struct NavigationURLLoaderImpl::DeleteOnLoaderThread;
   struct BindContext;
 
   ~PrefetchURLLoaderService() override;
@@ -122,6 +124,8 @@
       base::RepeatingCallback<int(void)> frame_tree_node_id_getter);
 
   scoped_refptr<URLLoaderFactoryGetter> loader_factory_getter_;
+  BrowserContext* browser_context_ = nullptr;
+  // Not used when NavigationLoaderOnUI is enabled.
   ResourceContext* resource_context_ = nullptr;
   scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
 
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc
index d2f737c..76bcf34 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -359,8 +359,7 @@
     CreateDownloadHandlerIntercept download_handler_intercept,
     const scoped_refptr<base::SingleThreadTaskRunner>& io_thread_runner,
     bool enable_resource_scheduler)
-    : request_id_(-1),
-      is_shutdown_(false),
+    : is_shutdown_(false),
       enable_resource_scheduler_(enable_resource_scheduler),
       num_in_flight_requests_(0),
       max_num_in_flight_requests_(base::GetHandleLimit()),
@@ -1766,7 +1765,6 @@
 }
 
 int ResourceDispatcherHostImpl::MakeRequestID() {
-  DCHECK(io_thread_task_runner_->BelongsToCurrentThread());
   return --request_id_;
 }
 
diff --git a/content/browser/loader/resource_dispatcher_host_impl.h b/content/browser/loader/resource_dispatcher_host_impl.h
index 936d45f..c002964 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.h
+++ b/content/browser/loader/resource_dispatcher_host_impl.h
@@ -270,7 +270,7 @@
   bool is_shutdown() const { return is_shutdown_; }
 
   // Creates a new request ID for browser initiated requests. See the comments
-  // of |request_id_| for the details. Must be called on the IO thread.
+  // of |request_id_| for the details. Can be called on any thread.
   int MakeRequestID();
 
   // Creates a new global request ID for browser initiated requests. The ID
@@ -638,7 +638,7 @@
   // uninitialized variables.) This way, we no longer have the unlikely (but
   // observed in the real world!) event where we have two requests with the same
   // request_id_.
-  int request_id_;
+  std::atomic_int request_id_{-1};
 
   // True if the resource dispatcher host has been shut down.
   bool is_shutdown_;
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc
index 61536301..46b07e5 100644
--- a/content/browser/service_worker/service_worker_browsertest.cc
+++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -3813,11 +3813,9 @@
   ASSERT_TRUE(dict);
 
   // Default headers are present.
-  std::string expect_accept(network::kFrameAcceptHeader);
-  // See http://crbug.com/824854.
-  if (!NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled())
-    expect_accept += std::string(kAcceptHeaderSignedExchangeSuffix);
-  EXPECT_TRUE(CheckHeader(*dict, "accept", expect_accept));
+  EXPECT_TRUE(CheckHeader(*dict, "accept",
+                          std::string(network::kFrameAcceptHeader) +
+                              std::string(kAcceptHeaderSignedExchangeSuffix)));
 
   // Injected headers are present.
   EXPECT_TRUE(CheckHeader(*dict, "x-injected", "injected value"));
diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc
index eea2106..a932cd5 100644
--- a/content/browser/service_worker/service_worker_context_wrapper.cc
+++ b/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -23,7 +23,9 @@
 #include "base/task/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
+#include "content/browser/loader/navigation_url_loader_impl.h"
 #include "content/browser/service_worker/embedded_worker_status.h"
+#include "content/browser/service_worker/service_worker_context_watcher.h"
 #include "content/browser/service_worker/service_worker_process_manager.h"
 #include "content/browser/service_worker/service_worker_quota_client.h"
 #include "content/browser/service_worker/service_worker_version.h"
@@ -206,6 +208,15 @@
   // Add this object as an observer of the wrapped |context_core_|. This lets us
   // forward observer methods to observers outside of content.
   core_observer_list_->AddObserver(this);
+
+  if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
+    watcher_ = base::MakeRefCounted<ServiceWorkerContextWatcher>(
+        this,
+        base::BindRepeating(&ServiceWorkerContextWrapper::OnRegistrationUpdated,
+                            base::Unretained(this)),
+        base::DoNothing(), base::DoNothing());
+    watcher_->Start();
+  }
 }
 
 void ServiceWorkerContextWrapper::Init(
@@ -240,6 +251,10 @@
 
   storage_partition_ = nullptr;
   process_manager_->Shutdown();
+  if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
+    watcher_->Stop();
+    watcher_ = nullptr;
+  }
   base::PostTaskWithTraits(
       FROM_HERE, {BrowserThread::IO},
       base::BindOnce(&ServiceWorkerContextWrapper::ShutdownOnIO, this));
@@ -1527,4 +1542,33 @@
   return factory_bundle;
 }
 
+bool ServiceWorkerContextWrapper::HasRegistrationForOrigin(
+    const GURL& origin) const {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled());
+  return !registrations_initialized_ ||
+         registrations_for_origin_.find(origin) !=
+             registrations_for_origin_.end();
+}
+
+void ServiceWorkerContextWrapper::OnRegistrationUpdated(
+    const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  // The first call will initialize stored registrations.
+  registrations_initialized_ = true;
+
+  for (const auto& registration : registrations) {
+    GURL origin = registration.scope.GetOrigin();
+    int64_t registration_id = registration.registration_id;
+    if (registration.delete_flag == ServiceWorkerRegistrationInfo::IS_DELETED) {
+      auto& registration_ids = registrations_for_origin_[origin];
+      registration_ids.erase(registration_id);
+      if (registration_ids.empty())
+        registrations_for_origin_.erase(origin);
+    } else {
+      registrations_for_origin_[origin].insert(registration_id);
+    }
+  }
+}
+
 }  // namespace content
diff --git a/content/browser/service_worker/service_worker_context_wrapper.h b/content/browser/service_worker/service_worker_context_wrapper.h
index 276b570b..f636d99 100644
--- a/content/browser/service_worker/service_worker_context_wrapper.h
+++ b/content/browser/service_worker/service_worker_context_wrapper.h
@@ -43,6 +43,7 @@
 class ChromeBlobStorageContext;
 class ResourceContext;
 class ServiceWorkerContextObserver;
+class ServiceWorkerContextWatcher;
 class StoragePartitionImpl;
 class URLLoaderFactoryGetter;
 
@@ -314,6 +315,9 @@
   // DeleteAndStartOver fails.
   ServiceWorkerContextCore* context();
 
+  // Whether |origin| has any registrations. Must be called on UI thread.
+  bool HasRegistrationForOrigin(const GURL& origin) const;
+
  private:
   friend class BackgroundSyncManagerTest;
   friend class base::RefCountedThreadSafe<ServiceWorkerContextWrapper>;
@@ -442,6 +446,11 @@
   CreateNonNetworkURLLoaderFactoryBundleInfoForUpdateCheck(
       BrowserContext* browser_context);
 
+  // Called when the stored registrations are loaded, and each time a new
+  // service worker is registered.
+  void OnRegistrationUpdated(
+      const std::vector<ServiceWorkerRegistrationInfo>& registrations);
+
   // Observers of |context_core_| which live within content's implementation
   // boundary. Shared with |context_core_|.
   using ServiceWorkerContextObserverList =
@@ -469,6 +478,15 @@
   // OnVersionRunningStatusChanged events.
   base::flat_set<int64_t /* version_id */> running_service_workers_;
 
+  // Maps the origin to a set of registration ids for that origin. Must be
+  // accessed on UI thread.
+  // TODO(http://crbug.com/824858): This can be removed when service workers are
+  // fully converted to running on the UI thread.
+  base::flat_map<GURL, base::flat_set<int64_t>> registrations_for_origin_;
+  bool registrations_initialized_ = false;
+
+  scoped_refptr<ServiceWorkerContextWatcher> watcher_;
+
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerContextWrapper);
 };
 
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler.cc b/content/browser/service_worker/service_worker_controllee_request_handler.cc
index 8af604e..94a1d2e 100644
--- a/content/browser/service_worker/service_worker_controllee_request_handler.cc
+++ b/content/browser/service_worker/service_worker_controllee_request_handler.cc
@@ -106,24 +106,15 @@
     ResourceContext* resource_context,
     LoaderCallback callback,
     FallbackCallback fallback_callback) {
-  ClearJob();
-
-  if (!provider_host_) {
+  // InitializeProvider() will update the host. This is important to do before
+  // falling back to network below, so service worker APIs still work even if
+  // the service worker is bypassed for request interception.
+  if (!InitializeProvider(tentative_resource_request)) {
     // We can't do anything other than to fall back to network.
     std::move(callback).Run({});
     return;
   }
 
-  // Update the provider host with this request, clearing old controller state
-  // if this is a redirect. It's important to update the host before falling
-  // back to network below, so service worker APIs still work even if the
-  // service worker is bypassed for request interception.
-  provider_host_->SetControllerRegistration(nullptr,
-                                            /*notify_controllerchange=*/false);
-  stripped_url_ = net::SimplifyUrlForRequest(tentative_resource_request.url);
-  provider_host_->UpdateUrls(stripped_url_,
-                             tentative_resource_request.site_for_cookies);
-
   // Fall back to network if we were instructed to bypass the service worker for
   // request interception, or if the context is gone so we have to bypass
   // anyway.
@@ -204,6 +195,24 @@
   return base::Optional<SubresourceLoaderParams>(std::move(params));
 }
 
+bool ServiceWorkerControlleeRequestHandler::InitializeProvider(
+    const network::ResourceRequest& tentative_resource_request) {
+  ClearJob();
+
+  if (!provider_host_) {
+    return false;
+  }
+
+  // Update the provider host with this request, clearing old controller state
+  // if this is a redirect.
+  provider_host_->SetControllerRegistration(nullptr,
+                                            /*notify_controllerchange=*/false);
+  stripped_url_ = net::SimplifyUrlForRequest(tentative_resource_request.url);
+  provider_host_->UpdateUrls(stripped_url_,
+                             tentative_resource_request.site_for_cookies);
+  return true;
+}
+
 void ServiceWorkerControlleeRequestHandler::ContinueWithRegistration(
     blink::ServiceWorkerStatusCode status,
     scoped_refptr<ServiceWorkerRegistration> registration) {
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler.h b/content/browser/service_worker/service_worker_controllee_request_handler.h
index fd6f124..c6917ee 100644
--- a/content/browser/service_worker/service_worker_controllee_request_handler.h
+++ b/content/browser/service_worker/service_worker_controllee_request_handler.h
@@ -60,6 +60,9 @@
   base::Optional<SubresourceLoaderParams> MaybeCreateSubresourceLoaderParams()
       override;
 
+  // Does all initialization of |provider_host_| for a request.
+  bool InitializeProvider(const network::ResourceRequest& tentative_request);
+
   // Exposed for testing.
   ServiceWorkerNavigationLoader* loader() {
     return loader_wrapper_ ? loader_wrapper_->get() : nullptr;
diff --git a/content/browser/service_worker/service_worker_navigation_handle.cc b/content/browser/service_worker/service_worker_navigation_handle.cc
index efeada5e..ca3a020 100644
--- a/content/browser/service_worker/service_worker_navigation_handle.cc
+++ b/content/browser/service_worker/service_worker_navigation_handle.cc
@@ -8,6 +8,7 @@
 
 #include "base/bind.h"
 #include "base/task/post_task.h"
+#include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/browser/service_worker/service_worker_navigation_handle_core.h"
 #include "content/common/service_worker/service_worker_utils.h"
 #include "content/public/browser/browser_task_traits.h"
@@ -16,7 +17,8 @@
 namespace content {
 
 ServiceWorkerNavigationHandle::ServiceWorkerNavigationHandle(
-    ServiceWorkerContextWrapper* context_wrapper) {
+    ServiceWorkerContextWrapper* context_wrapper)
+    : context_wrapper_(context_wrapper) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   core_ = new ServiceWorkerNavigationHandleCore(weak_factory_.GetWeakPtr(),
                                                 context_wrapper);
diff --git a/content/browser/service_worker/service_worker_navigation_handle.h b/content/browser/service_worker/service_worker_navigation_handle.h
index 246ade4f..d2e0708 100644
--- a/content/browser/service_worker/service_worker_navigation_handle.h
+++ b/content/browser/service_worker/service_worker_navigation_handle.h
@@ -69,11 +69,16 @@
 
   ServiceWorkerNavigationHandleCore* core() const { return core_; }
 
+  const ServiceWorkerContextWrapper* context_wrapper() const {
+    return context_wrapper_.get();
+  }
+
  private:
   blink::mojom::ServiceWorkerProviderInfoForClientPtr provider_info_;
   // TODO(leonhsl): Use std::unique_ptr<ServiceWorkerNavigationHandleCore,
   // BrowserThread::DeleteOnIOThread> instead.
   ServiceWorkerNavigationHandleCore* core_;
+  scoped_refptr<ServiceWorkerContextWrapper> context_wrapper_;
   base::WeakPtrFactory<ServiceWorkerNavigationHandle> weak_factory_{this};
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerNavigationHandle);
 };
diff --git a/content/browser/service_worker/service_worker_navigation_handle_core.h b/content/browser/service_worker/service_worker_navigation_handle_core.h
index 02d963b..2e4d0b47 100644
--- a/content/browser/service_worker/service_worker_navigation_handle_core.h
+++ b/content/browser/service_worker/service_worker_navigation_handle_core.h
@@ -53,7 +53,9 @@
     provider_host_ = std::move(provider_host);
   }
 
-  ServiceWorkerProviderHost* provider_host() { return provider_host_.get(); }
+  base::WeakPtr<ServiceWorkerProviderHost> provider_host() {
+    return provider_host_;
+  }
 
   void set_interceptor(
       std::unique_ptr<ServiceWorkerControlleeRequestHandler> interceptor) {
diff --git a/content/browser/service_worker/service_worker_navigation_loader_interceptor.cc b/content/browser/service_worker/service_worker_navigation_loader_interceptor.cc
index 907fdaf..7c3d34b 100644
--- a/content/browser/service_worker/service_worker_navigation_loader_interceptor.cc
+++ b/content/browser/service_worker/service_worker_navigation_loader_interceptor.cc
@@ -31,6 +31,7 @@
     ServiceWorkerNavigationHandleCore* handle_core,
     base::WeakPtr<ServiceWorkerNavigationLoaderInterceptor> interceptor_on_ui,
     blink::mojom::ServiceWorkerProviderInfoForClientPtr provider_info,
+    NavigationLoaderInterceptor::LoaderCallback loader_callback,
     SingleRequestURLLoaderFactory::RequestHandler handler) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
@@ -45,18 +46,21 @@
       base::BindOnce(
           &ServiceWorkerNavigationLoaderInterceptor::LoaderCallbackWrapper,
           interceptor_on_ui, std::move(provider_info),
-          std::move(subresource_loader_params), std::move(handler)));
+          std::move(subresource_loader_params), std::move(loader_callback),
+          std::move(handler)));
 }
 
 void FallbackCallbackWrapperOnIO(
     base::WeakPtr<ServiceWorkerNavigationLoaderInterceptor> interceptor_on_ui,
+    NavigationLoaderInterceptor::FallbackCallback fallback_callback,
     bool reset_subresource_loader_params) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   PostTaskWithTraits(
       FROM_HERE, {BrowserThread::UI},
       base::BindOnce(
           &ServiceWorkerNavigationLoaderInterceptor::FallbackCallbackWrapper,
-          interceptor_on_ui, reset_subresource_loader_params));
+          interceptor_on_ui, std::move(fallback_callback),
+          reset_subresource_loader_params));
 }
 
 void InvokeRequestHandlerOnIO(
@@ -79,7 +83,10 @@
     ResourceType resource_type,
     bool skip_service_worker,
     const network::ResourceRequest& tentative_resource_request,
-    BrowserContext* browser_context) {
+    BrowserContext* browser_context,
+    NavigationLoaderInterceptor::LoaderCallback loader_callback,
+    NavigationLoaderInterceptor::FallbackCallback fallback_callback,
+    bool initialize_provider_only) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   ServiceWorkerContextCore* context_core =
@@ -89,6 +96,7 @@
   if (!context_core || !resource_context) {
     LoaderCallbackWrapperOnIO(handle_core, std::move(interceptor_on_ui),
                               /*provider_info=*/nullptr,
+                              std::move(loader_callback),
                               /*handler=*/{});
     return;
   }
@@ -115,6 +123,18 @@
             skip_service_worker));
   }
 
+  // If |initialize_provider_only| is true, we have already determined there is
+  // no registered service worker on the UI thread, so just initialize the
+  // provider for this request.
+  if (initialize_provider_only) {
+    handle_core->interceptor()->InitializeProvider(tentative_resource_request);
+    LoaderCallbackWrapperOnIO(handle_core, interceptor_on_ui,
+                              std::move(provider_info),
+                              std::move(loader_callback),
+                              /*handler=*/{});
+    return;
+  }
+
   // Start the inner interceptor. We continue in LoaderCallbackWrapperOnIO().
   //
   // It's safe to bind the raw |handle_core| to the callback because it owns the
@@ -122,8 +142,9 @@
   handle_core->interceptor()->MaybeCreateLoader(
       tentative_resource_request, browser_context, resource_context,
       base::BindOnce(&LoaderCallbackWrapperOnIO, handle_core, interceptor_on_ui,
-                     std::move(provider_info)),
-      base::BindOnce(&FallbackCallbackWrapperOnIO, interceptor_on_ui));
+                     std::move(provider_info), std::move(loader_callback)),
+      base::BindOnce(&FallbackCallbackWrapperOnIO, interceptor_on_ui,
+                     std::move(fallback_callback)));
 }
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -157,16 +178,26 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(!resource_context);
 
+  bool initialize_provider_only = false;
+  if (!handle_->context_wrapper()->HasRegistrationForOrigin(
+          tentative_resource_request.url.GetOrigin())) {
+    // We have no registrations, so it's safe to continue the request now
+    // without hopping to IO.
+    std::move(loader_callback).Run({});
+    loader_callback =
+        base::BindOnce([](SingleRequestURLLoaderFactory::RequestHandler) {});
+    initialize_provider_only = true;
+  }
+
   // Start the inner interceptor on the IO thread. It will call back to
   // LoaderCallbackWrapper() on the UI thread.
-  loader_callback_ = std::move(loader_callback);
-  fallback_callback_ = std::move(fallback_callback);
   base::PostTaskWithTraits(
       FROM_HERE, {BrowserThread::IO},
       base::BindOnce(&MaybeCreateLoaderOnIO, GetWeakPtr(), handle_->core(),
                      are_ancestors_secure_, frame_tree_node_id_, resource_type_,
                      skip_service_worker_, tentative_resource_request,
-                     browser_context));
+                     browser_context, std::move(loader_callback),
+                     std::move(fallback_callback), initialize_provider_only));
 }
 
 base::Optional<SubresourceLoaderParams>
@@ -178,6 +209,7 @@
 void ServiceWorkerNavigationLoaderInterceptor::LoaderCallbackWrapper(
     blink::mojom::ServiceWorkerProviderInfoForClientPtr provider_info,
     base::Optional<SubresourceLoaderParams> subresource_loader_params,
+    LoaderCallback loader_callback,
     SingleRequestURLLoaderFactory::RequestHandler handler_on_io) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
@@ -189,23 +221,24 @@
   subresource_loader_params_ = std::move(subresource_loader_params);
 
   if (!handler_on_io) {
-    std::move(loader_callback_).Run({});
+    std::move(loader_callback).Run({});
     return;
   }
 
   // The inner IO thread interceptor wants to handle the request. However,
   // |handler_on_io| expects to run on the IO thread. Give our own wrapper to
   // the loader callback.
-  std::move(loader_callback_)
+  std::move(loader_callback)
       .Run(base::BindOnce(
           &ServiceWorkerNavigationLoaderInterceptor::RequestHandlerWrapper,
           GetWeakPtr(), std::move(handler_on_io)));
 }
 
 void ServiceWorkerNavigationLoaderInterceptor::FallbackCallbackWrapper(
+    FallbackCallback fallback_callback,
     bool reset_subresource_loader_params) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  std::move(fallback_callback_).Run(reset_subresource_loader_params);
+  std::move(fallback_callback).Run(reset_subresource_loader_params);
 }
 
 base::WeakPtr<ServiceWorkerNavigationLoaderInterceptor>
diff --git a/content/browser/service_worker/service_worker_navigation_loader_interceptor.h b/content/browser/service_worker/service_worker_navigation_loader_interceptor.h
index 0f97476b..302af35 100644
--- a/content/browser/service_worker/service_worker_navigation_loader_interceptor.h
+++ b/content/browser/service_worker/service_worker_navigation_loader_interceptor.h
@@ -56,8 +56,10 @@
   void LoaderCallbackWrapper(
       blink::mojom::ServiceWorkerProviderInfoForClientPtr provider_info,
       base::Optional<SubresourceLoaderParams> subresource_loader_params,
+      LoaderCallback loader_callback,
       SingleRequestURLLoaderFactory::RequestHandler handler_on_io);
-  void FallbackCallbackWrapper(bool reset_subresource_loader_params);
+  void FallbackCallbackWrapper(FallbackCallback fallback_callback,
+                               bool reset_subresource_loader_params);
 
   base::WeakPtr<ServiceWorkerNavigationLoaderInterceptor> GetWeakPtr();
 
@@ -77,9 +79,6 @@
   const ResourceType resource_type_;
   const bool skip_service_worker_;
 
-  LoaderCallback loader_callback_;
-  FallbackCallback fallback_callback_;
-
   base::Optional<SubresourceLoaderParams> subresource_loader_params_;
 
   base::WeakPtrFactory<ServiceWorkerNavigationLoaderInterceptor> weak_factory_{
diff --git a/content/browser/storage_partition_impl_map.cc b/content/browser/storage_partition_impl_map.cc
index bd832fe..cddf1af 100644
--- a/content/browser/storage_partition_impl_map.cc
+++ b/content/browser/storage_partition_impl_map.cc
@@ -568,14 +568,16 @@
                        partition->GetServiceWorkerContext(),
                        browser_context_->GetResourceContext()));
 
-    base::PostTaskWithTraits(
-        FROM_HERE, {BrowserThread::IO},
-        base::BindOnce(
-            &PrefetchURLLoaderService::InitializeResourceContext,
-            partition->GetPrefetchURLLoaderService(),
-            browser_context_->GetResourceContext(), request_context_getter,
-            base::RetainedRef(
-                ChromeBlobStorageContext::GetFor(browser_context_))));
+    if (!NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
+      base::PostTaskWithTraits(
+          FROM_HERE, {BrowserThread::IO},
+          base::BindOnce(
+              &PrefetchURLLoaderService::InitializeResourceContext,
+              partition->GetPrefetchURLLoaderService(),
+              browser_context_->GetResourceContext(), request_context_getter,
+              base::RetainedRef(
+                  ChromeBlobStorageContext::GetFor(browser_context_))));
+    }
 
     base::PostTaskWithTraits(
         FROM_HERE, {BrowserThread::IO},
diff --git a/content/browser/utility_process_host_browsertest.cc b/content/browser/utility_process_host_browsertest.cc
index 862c4e5..0c9fd30 100644
--- a/content/browser/utility_process_host_browsertest.cc
+++ b/content/browser/utility_process_host_browsertest.cc
@@ -125,11 +125,8 @@
       const ChildProcessTerminationInfo& info) override {
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
 #if defined(OS_WIN)
-    EXPECT_EQ(EXCEPTION_ILLEGAL_INSTRUCTION, DWORD{info.exit_code});
-#elif defined(OS_MACOSX)
-    EXPECT_TRUE(WIFSIGNALED(info.exit_code));
-    EXPECT_EQ(SIGILL, WTERMSIG(info.exit_code));
-#elif defined(OS_LINUX)
+    EXPECT_EQ(EXCEPTION_BREAKPOINT, DWORD{info.exit_code});
+#elif defined(OS_MACOSX) || defined(OS_LINUX)
     EXPECT_TRUE(WIFSIGNALED(info.exit_code));
     EXPECT_EQ(SIGTRAP, WTERMSIG(info.exit_code));
 #endif
diff --git a/content/browser/web_package/prefetched_signed_exchange_cache.cc b/content/browser/web_package/prefetched_signed_exchange_cache.cc
index 4bd5f3e1..3486a587 100644
--- a/content/browser/web_package/prefetched_signed_exchange_cache.cc
+++ b/content/browser/web_package/prefetched_signed_exchange_cache.cc
@@ -12,6 +12,7 @@
 #include "components/link_header_util/link_header_util.h"
 #include "content/browser/loader/cross_origin_read_blocking_checker.h"
 #include "content/browser/loader/navigation_loader_interceptor.h"
+#include "content/browser/loader/navigation_url_loader_impl.h"
 #include "content/browser/navigation_subresource_loader_params.h"
 #include "content/browser/web_package/signed_exchange_utils.h"
 #include "content/public/browser/browser_task_traits.h"
@@ -280,12 +281,18 @@
       return;
     }
 
-    storage::MojoBlobReader::Create(
-        blob_data_handle_.get(), net::HttpByteRange(),
-        std::make_unique<MojoBlobReaderDelegate>(
-            base::BindOnce(&InnerResponseURLLoader::BlobReaderComplete,
-                           weak_factory_.GetWeakPtr())),
-        std::move(pipe_producer_handle));
+    if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
+      base::PostTaskWithTraits(
+          FROM_HERE, {BrowserThread::IO},
+          base::BindOnce(
+              &InnerResponseURLLoader::CreateMojoBlobReader,
+              weak_factory_.GetWeakPtr(), std::move(pipe_producer_handle),
+              std::make_unique<storage::BlobDataHandle>(*blob_data_handle_)));
+    } else {
+      CreateMojoBlobReader(
+          weak_factory_.GetWeakPtr(), std::move(pipe_producer_handle),
+          std::make_unique<storage::BlobDataHandle>(*blob_data_handle_));
+    }
 
     client_->OnStartLoadingResponseBody(std::move(pipe_consumer_handle));
   }
@@ -303,6 +310,26 @@
     client_->OnComplete(status);
   }
 
+  static void CreateMojoBlobReader(
+      base::WeakPtr<InnerResponseURLLoader> loader,
+      mojo::ScopedDataPipeProducerHandle pipe_producer_handle,
+      std::unique_ptr<storage::BlobDataHandle> blob_data_handle) {
+    storage::MojoBlobReader::Create(
+        blob_data_handle.get(), net::HttpByteRange(),
+        std::make_unique<MojoBlobReaderDelegate>(
+            base::BindOnce(&InnerResponseURLLoader::BlobReaderCompleteOnIO,
+                           std::move(loader))),
+        std::move(pipe_producer_handle));
+  }
+
+  static void BlobReaderCompleteOnIO(
+      base::WeakPtr<InnerResponseURLLoader> loader,
+      net::Error result) {
+    NavigationURLLoaderImpl::RunOrPostTaskOnLoaderThread(
+        FROM_HERE, base::BindOnce(&InnerResponseURLLoader::BlobReaderComplete,
+                                  std::move(loader), result));
+  }
+
   network::ResourceResponseHead response_;
   std::unique_ptr<const storage::BlobDataHandle> blob_data_handle_;
   const network::URLLoaderCompletionStatus completion_status_;
@@ -626,7 +653,8 @@
 
 void PrefetchedSignedExchangeCache::Store(
     std::unique_ptr<const Entry> cached_exchange) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(
+      NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID());
   if (exchanges_.size() > kMaxEntrySize)
     return;
   DCHECK(cached_exchange->outer_url().is_valid());
@@ -646,7 +674,8 @@
 
 std::unique_ptr<NavigationLoaderInterceptor>
 PrefetchedSignedExchangeCache::MaybeCreateInterceptor(const GURL& outer_url) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(
+      NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID());
   const auto it = exchanges_.find(outer_url);
   if (it == exchanges_.end())
     return nullptr;
@@ -662,18 +691,21 @@
 
 const PrefetchedSignedExchangeCache::EntryMap&
 PrefetchedSignedExchangeCache::GetExchanges() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(
+      NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID());
   return exchanges_;
 }
 
 void PrefetchedSignedExchangeCache::RecordHistograms() {
-  if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+  BrowserThread::ID thread_id =
+      NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID();
+  if (!BrowserThread::CurrentlyOn(thread_id)) {
     base::PostTaskWithTraits(
-        FROM_HERE, {BrowserThread::IO},
+        FROM_HERE, {thread_id},
         base::BindOnce(&PrefetchedSignedExchangeCache::RecordHistograms, this));
     return;
   }
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(thread_id);
   if (exchanges_.empty())
     return;
   UMA_HISTOGRAM_COUNTS_100("PrefetchedSignedExchangeCache.Count",
@@ -702,7 +734,8 @@
 PrefetchedSignedExchangeCache::GetInfoListForNavigation(
     const Entry& main_exchange,
     const base::Time& now) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(
+      NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID());
 
   const url::Origin outer_url_origin =
       url::Origin::Create(main_exchange.outer_url());
diff --git a/content/browser/web_package/prefetched_signed_exchange_cache_adapter.cc b/content/browser/web_package/prefetched_signed_exchange_cache_adapter.cc
index 49628333..c7c171b 100644
--- a/content/browser/web_package/prefetched_signed_exchange_cache_adapter.cc
+++ b/content/browser/web_package/prefetched_signed_exchange_cache_adapter.cc
@@ -4,21 +4,40 @@
 
 #include "content/browser/web_package/prefetched_signed_exchange_cache_adapter.h"
 
+#include "base/task/post_task.h"
+#include "content/browser/loader/navigation_url_loader_impl.h"
 #include "content/browser/loader/prefetch_url_loader.h"
+#include "content/public/browser/browser_task_traits.h"
 #include "storage/browser/blob/blob_builder_from_stream.h"
 #include "storage/browser/blob/blob_data_handle.h"
 
 namespace content {
+namespace {
+
+void AbortAndDeleteBlobBuilder(
+    std::unique_ptr<storage::BlobBuilderFromStream> blob_builder) {
+  if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+    blob_builder->Abort();
+    return;
+  }
+
+  base::PostTaskWithTraits(
+      FROM_HERE, {BrowserThread::IO},
+      base::BindOnce(&storage::BlobBuilderFromStream::Abort,
+                     std::move(blob_builder)));
+}
+
+}  // namespace
 
 PrefetchedSignedExchangeCacheAdapter::PrefetchedSignedExchangeCacheAdapter(
     scoped_refptr<PrefetchedSignedExchangeCache>
         prefetched_signed_exchange_cache,
-    base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
+    BrowserContext::BlobContextGetter blob_context_getter,
     const GURL& request_url,
     PrefetchURLLoader* prefetch_url_loader)
     : prefetched_signed_exchange_cache_(
           std::move(prefetched_signed_exchange_cache)),
-      blob_storage_context_(std::move(blob_storage_context)),
+      blob_context_getter_(std::move(blob_context_getter)),
       cached_exchange_(
           std::make_unique<PrefetchedSignedExchangeCache::Entry>()),
       prefetch_url_loader_(prefetch_url_loader) {
@@ -27,7 +46,7 @@
 
 PrefetchedSignedExchangeCacheAdapter::~PrefetchedSignedExchangeCacheAdapter() {
   if (blob_builder_from_stream_)
-    blob_builder_from_stream_->Abort();
+    AbortAndDeleteBlobBuilder(std::move(blob_builder_from_stream_));
 }
 
 void PrefetchedSignedExchangeCacheAdapter::OnReceiveOuterResponse(
@@ -61,18 +80,26 @@
     mojo::ScopedDataPipeConsumerHandle body) {
   DCHECK(cached_exchange_->inner_response());
   DCHECK(!cached_exchange_->completion_status());
-  DCHECK(blob_storage_context_);
   uint64_t length_hint = 0;
   if (cached_exchange_->inner_response()->content_length > 0) {
     length_hint = cached_exchange_->inner_response()->content_length;
   }
-  blob_builder_from_stream_ = std::make_unique<storage::BlobBuilderFromStream>(
-      blob_storage_context_, "" /* content_type */,
-      "" /* content_disposition */,
-      base::BindOnce(&PrefetchedSignedExchangeCacheAdapter::StreamingBlobDone,
-                     base::Unretained(this)));
-  blob_builder_from_stream_->Start(length_hint, std::move(body),
-                                   nullptr /*  progress_client */);
+  blob_is_streaming_ = true;
+  if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
+    base::PostTaskWithTraitsAndReplyWithResult(
+        FROM_HERE, {BrowserThread::IO},
+        base::BindOnce(
+            &PrefetchedSignedExchangeCacheAdapter::CreateBlobBuilderFromStream,
+            weak_factory_.GetWeakPtr(), std::move(body), length_hint,
+            blob_context_getter_),
+        base::BindOnce(
+            &PrefetchedSignedExchangeCacheAdapter::SetBlobBuilderFromStream,
+            weak_factory_.GetWeakPtr()));
+  } else {
+    blob_builder_from_stream_ =
+        CreateBlobBuilderFromStream(weak_factory_.GetWeakPtr(), std::move(body),
+                                    length_hint, blob_context_getter_);
+  }
 }
 
 void PrefetchedSignedExchangeCacheAdapter::OnComplete(
@@ -85,13 +112,19 @@
 void PrefetchedSignedExchangeCacheAdapter::StreamingBlobDone(
     storage::BlobBuilderFromStream* builder,
     std::unique_ptr<storage::BlobDataHandle> result) {
-  blob_builder_from_stream_.reset();
+  blob_is_streaming_ = false;
+  if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
+    BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE,
+                              std::move(blob_builder_from_stream_));
+  } else {
+    blob_builder_from_stream_.reset();
+  }
   cached_exchange_->SetBlobDataHandle(std::move(result));
   MaybeCallOnSignedExchangeStored();
 }
 
 void PrefetchedSignedExchangeCacheAdapter::MaybeCallOnSignedExchangeStored() {
-  if (!cached_exchange_->completion_status() || blob_builder_from_stream_) {
+  if (!cached_exchange_->completion_status() || blob_is_streaming_) {
     return;
   }
 
@@ -117,4 +150,50 @@
   prefetch_url_loader_->SendOnComplete(completion_status);
 }
 
+// static
+std::unique_ptr<storage::BlobBuilderFromStream>
+PrefetchedSignedExchangeCacheAdapter::CreateBlobBuilderFromStream(
+    base::WeakPtr<PrefetchedSignedExchangeCacheAdapter> adapter,
+    mojo::ScopedDataPipeConsumerHandle body,
+    uint64_t length_hint,
+    BrowserContext::BlobContextGetter blob_context_getter) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  auto blob_builder_from_stream =
+      std::make_unique<storage::BlobBuilderFromStream>(
+          blob_context_getter.Run(), "" /* content_type */,
+          "" /* content_disposition */,
+          base::BindOnce(
+              &PrefetchedSignedExchangeCacheAdapter::StreamingBlobDoneOnIO,
+              std::move(adapter)));
+
+  blob_builder_from_stream->Start(length_hint, std::move(body),
+                                  nullptr /*  progress_client */);
+  return blob_builder_from_stream;
+}
+
+// static
+void PrefetchedSignedExchangeCacheAdapter::SetBlobBuilderFromStream(
+    base::WeakPtr<PrefetchedSignedExchangeCacheAdapter> adapter,
+    std::unique_ptr<storage::BlobBuilderFromStream> blob_builder_from_stream) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  if (!adapter) {
+    AbortAndDeleteBlobBuilder(std::move(blob_builder_from_stream));
+    return;
+  }
+
+  adapter->blob_builder_from_stream_ = std::move(blob_builder_from_stream);
+}
+
+// static
+void PrefetchedSignedExchangeCacheAdapter::StreamingBlobDoneOnIO(
+    base::WeakPtr<PrefetchedSignedExchangeCacheAdapter> adapter,
+    storage::BlobBuilderFromStream* builder,
+    std::unique_ptr<storage::BlobDataHandle> result) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  NavigationURLLoaderImpl::RunOrPostTaskOnLoaderThread(
+      FROM_HERE,
+      base::BindOnce(&PrefetchedSignedExchangeCacheAdapter::StreamingBlobDone,
+                     adapter, builder, std::move(result)));
+}
+
 }  // namespace content
diff --git a/content/browser/web_package/prefetched_signed_exchange_cache_adapter.h b/content/browser/web_package/prefetched_signed_exchange_cache_adapter.h
index 82e271f2..0a7f863a 100644
--- a/content/browser/web_package/prefetched_signed_exchange_cache_adapter.h
+++ b/content/browser/web_package/prefetched_signed_exchange_cache_adapter.h
@@ -7,6 +7,7 @@
 
 #include "base/optional.h"
 #include "content/browser/web_package/prefetched_signed_exchange_cache.h"
+#include "content/public/browser/browser_context.h"
 #include "mojo/public/cpp/system/data_pipe.h"
 
 class GURL;
@@ -34,7 +35,7 @@
   PrefetchedSignedExchangeCacheAdapter(
       scoped_refptr<PrefetchedSignedExchangeCache>
           prefetched_signed_exchange_cache,
-      base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
+      BrowserContext::BlobContextGetter blob_context_getter,
       const GURL& request_url,
       PrefetchURLLoader* prefetch_url_loader);
   ~PrefetchedSignedExchangeCacheAdapter();
@@ -54,6 +55,26 @@
 
   void MaybeCallOnSignedExchangeStored();
 
+  // Creates and starts the blob builder.
+  static std::unique_ptr<storage::BlobBuilderFromStream>
+  CreateBlobBuilderFromStream(
+      base::WeakPtr<PrefetchedSignedExchangeCacheAdapter> adapter,
+      mojo::ScopedDataPipeConsumerHandle body,
+      uint64_t length_hint,
+      BrowserContext::BlobContextGetter blob_context_getter);
+
+  // Sets |blob_builder_from_stream| on |adapter|. If |adapter| is no longer
+  // valid, aborts the blob builder.
+  static void SetBlobBuilderFromStream(
+      base::WeakPtr<PrefetchedSignedExchangeCacheAdapter> adapter,
+      std::unique_ptr<storage::BlobBuilderFromStream> blob_builder_from_stream);
+
+  // Calls StreamingBlobDone() on the correct thread.
+  static void StreamingBlobDoneOnIO(
+      base::WeakPtr<PrefetchedSignedExchangeCacheAdapter> adapter,
+      storage::BlobBuilderFromStream* builder,
+      std::unique_ptr<storage::BlobDataHandle> result);
+
   // Holds the prefetched signed exchanges which will be used in the next
   // navigation. This is shared with RenderFrameHostImpl that created this.
   const scoped_refptr<PrefetchedSignedExchangeCache>
@@ -61,19 +82,23 @@
 
   // Used to create a BlobDataHandle from a DataPipe of signed exchange's inner
   // response body to store to |prefetched_signed_exchange_cache_|.
-  base::WeakPtr<storage::BlobStorageContext> blob_storage_context_;
+  BrowserContext::BlobContextGetter blob_context_getter_;
 
   // A temporary entry of PrefetchedSignedExchangeCache, which will be stored
   // to |prefetched_signed_exchange_cache_|.
   std::unique_ptr<PrefetchedSignedExchangeCache::Entry> cached_exchange_;
 
   // Used to create a BlobDataHandle from a DataPipe of signed exchange's inner
-  // response body.
+  // response body. This should only be accessed on the IO thread.
   std::unique_ptr<storage::BlobBuilderFromStream> blob_builder_from_stream_;
+  bool blob_is_streaming_ = false;
 
   // |prefetch_url_loader_| owns |this|.
   PrefetchURLLoader* prefetch_url_loader_;
 
+  base::WeakPtrFactory<PrefetchedSignedExchangeCacheAdapter> weak_factory_{
+      this};
+
   DISALLOW_COPY_AND_ASSIGN(PrefetchedSignedExchangeCacheAdapter);
 };
 
diff --git a/content/browser/web_package/signed_exchange_devtools_proxy.cc b/content/browser/web_package/signed_exchange_devtools_proxy.cc
index 2b71146..2a24b5c 100644
--- a/content/browser/web_package/signed_exchange_devtools_proxy.cc
+++ b/content/browser/web_package/signed_exchange_devtools_proxy.cc
@@ -9,6 +9,7 @@
 #include "base/trace_event/trace_event.h"
 #include "content/browser/devtools/devtools_instrumentation.h"
 #include "content/browser/frame_host/frame_tree_node.h"
+#include "content/browser/loader/navigation_url_loader_impl.h"
 #include "content/browser/web_package/signed_exchange_envelope.h"
 #include "content/browser/web_package/signed_exchange_error.h"
 #include "content/public/browser/browser_task_traits.h"
@@ -20,6 +21,19 @@
 
 namespace {
 
+// Runs |task| on the thread specified by |thread_id| if already on that thread,
+// otherwise posts a task to that thread.
+void RunOrPostTaskIfNecessary(const base::Location& from_here,
+                              BrowserThread::ID thread_id,
+                              base::OnceClosure task) {
+  if (BrowserThread::CurrentlyOn(thread_id)) {
+    std::move(task).Run();
+    return;
+  }
+
+  base::PostTaskWithTraits(from_here, {thread_id}, std::move(task));
+}
+
 void AddErrorMessageToConsoleOnUI(
     base::RepeatingCallback<int(void)> frame_tree_node_id_getter,
     std::string error_message) {
@@ -103,20 +117,23 @@
       frame_tree_node_id_getter_(frame_tree_node_id_getter),
       devtools_navigation_token_(devtools_navigation_token),
       devtools_enabled_(report_raw_headers) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(
+      NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID());
 }
 
 SignedExchangeDevToolsProxy::~SignedExchangeDevToolsProxy() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(
+      NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID());
 }
 
 void SignedExchangeDevToolsProxy::ReportError(
     const std::string& message,
     base::Optional<SignedExchangeError::FieldIndexPair> error_field) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(
+      NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID());
   errors_.push_back(SignedExchangeError(message, std::move(error_field)));
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::UI},
+  RunOrPostTaskIfNecessary(
+      FROM_HERE, BrowserThread::UI,
       base::BindOnce(&AddErrorMessageToConsoleOnUI, frame_tree_node_id_getter_,
                      std::move(message)));
 }
@@ -127,8 +144,8 @@
   if (!devtools_enabled_)
     return;
 
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::UI},
+  RunOrPostTaskIfNecessary(
+      FROM_HERE, BrowserThread::UI,
       base::BindOnce(
           &CertificateRequestSentOnUI, frame_tree_node_id_getter_, request_id,
           devtools_navigation_token_ ? *devtools_navigation_token_ : request_id,
@@ -146,8 +163,8 @@
   auto resource_response = base::MakeRefCounted<network::ResourceResponse>();
   resource_response->head = head;
 
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::UI},
+  RunOrPostTaskIfNecessary(
+      FROM_HERE, BrowserThread::UI,
       base::BindOnce(
           &CertificateResponseReceivedOnUI, frame_tree_node_id_getter_,
           request_id,
@@ -160,8 +177,8 @@
     const network::URLLoaderCompletionStatus& status) {
   if (!devtools_enabled_)
     return;
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::UI},
+  RunOrPostTaskIfNecessary(
+      FROM_HERE, BrowserThread::UI,
       base::BindOnce(&CertificateRequestCompletedOnUI,
                      frame_tree_node_id_getter_, request_id, status));
 }
@@ -170,7 +187,8 @@
     const base::Optional<SignedExchangeEnvelope>& envelope,
     const scoped_refptr<net::X509Certificate>& certificate,
     const net::SSLInfo* ssl_info) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(
+      NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID());
   if (!devtools_enabled_)
     return;
   base::Optional<net::SSLInfo> ssl_info_opt;
@@ -181,8 +199,8 @@
   auto resource_response = base::MakeRefCounted<network::ResourceResponse>();
   resource_response->head = outer_response_;
 
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::UI},
+  RunOrPostTaskIfNecessary(
+      FROM_HERE, BrowserThread::UI,
       base::BindOnce(&OnSignedExchangeReceivedOnUI, frame_tree_node_id_getter_,
                      outer_request_url_, resource_response->DeepCopy(),
                      devtools_navigation_token_, envelope, certificate,
diff --git a/content/browser/web_package/signed_exchange_handler.cc b/content/browser/web_package/signed_exchange_handler.cc
index b77bb7a..d9ebe52 100644
--- a/content/browser/web_package/signed_exchange_handler.cc
+++ b/content/browser/web_package/signed_exchange_handler.cc
@@ -17,6 +17,7 @@
 #include "content/browser/frame_host/frame_tree_node.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/loader/merkle_integrity_source_stream.h"
+#include "content/browser/loader/navigation_url_loader_impl.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
 #include "content/browser/web_package/signed_exchange_cert_fetcher_factory.h"
 #include "content/browser/web_package/signed_exchange_certificate_chain.h"
@@ -95,8 +96,8 @@
                     int32_t error_code,
                     const net::CertVerifyResult& cv_result,
                     const net::ct::CTVerifyResult& ct_result) {
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::IO},
+  NavigationURLLoaderImpl::RunOrPostTaskOnLoaderThread(
+      FROM_HERE,
       base::BindOnce(std::move(callback), error_code, cv_result, ct_result));
 }
 
diff --git a/content/browser/web_package/signed_exchange_subresource_prefetch_browsertest.cc b/content/browser/web_package/signed_exchange_subresource_prefetch_browsertest.cc
index eb720f9..d4d65538a 100644
--- a/content/browser/web_package/signed_exchange_subresource_prefetch_browsertest.cc
+++ b/content/browser/web_package/signed_exchange_subresource_prefetch_browsertest.cc
@@ -23,6 +23,7 @@
 #include "base/time/time_override.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/loader/navigation_url_loader_impl.h"
 #include "content/browser/loader/prefetch_browsertest_base.h"
 #include "content/browser/web_package/mock_signed_exchange_handler.h"
 #include "content/browser/web_package/prefetched_signed_exchange_cache.h"
@@ -63,19 +64,25 @@
   scoped_refptr<PrefetchedSignedExchangeCache> cache =
       rfh->EnsurePrefetchedSignedExchangeCache();
   PrefetchedSignedExchangeCache::EntryMap results;
-  base::RunLoop run_loop;
-  base::PostTaskWithTraitsAndReply(
-      FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(
-          [](scoped_refptr<PrefetchedSignedExchangeCache> cache,
-             PrefetchedSignedExchangeCache::EntryMap* results) {
-            for (const auto& exchanges_it : cache->GetExchanges()) {
-              (*results)[exchanges_it.first] = exchanges_it.second->Clone();
-            }
-          },
-          cache, &results),
-      run_loop.QuitClosure());
-  run_loop.Run();
+  if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
+    for (const auto& exchanges_it : cache->GetExchanges()) {
+      results[exchanges_it.first] = exchanges_it.second->Clone();
+    }
+  } else {
+    base::RunLoop run_loop;
+    base::PostTaskWithTraitsAndReply(
+        FROM_HERE, {BrowserThread::IO},
+        base::BindOnce(
+            [](scoped_refptr<PrefetchedSignedExchangeCache> cache,
+               PrefetchedSignedExchangeCache::EntryMap* results) {
+              for (const auto& exchanges_it : cache->GetExchanges()) {
+                (*results)[exchanges_it.first] = exchanges_it.second->Clone();
+              }
+            },
+            cache, &results),
+        run_loop.QuitClosure());
+    run_loop.Run();
+  }
   return results;
 }
 
diff --git a/content/browser/web_package/signed_exchange_url_loader_factory_for_non_network_service.cc b/content/browser/web_package/signed_exchange_url_loader_factory_for_non_network_service.cc
index b32b39e..3f6d894 100644
--- a/content/browser/web_package/signed_exchange_url_loader_factory_for_non_network_service.cc
+++ b/content/browser/web_package/signed_exchange_url_loader_factory_for_non_network_service.cc
@@ -23,8 +23,8 @@
     : resource_context_(resource_context),
       url_request_context_getter_(url_request_context_getter) {
   DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
-  DCHECK(
-      signed_exchange_utils::IsSignedExchangeHandlingEnabled(resource_context));
+  DCHECK(signed_exchange_utils::IsSignedExchangeHandlingEnabledOnIO(
+      resource_context));
 }
 
 SignedExchangeURLLoaderFactoryForNonNetworkService::
diff --git a/content/browser/web_package/signed_exchange_utils.cc b/content/browser/web_package/signed_exchange_utils.cc
index f0b23a54..67923bc 100644
--- a/content/browser/web_package/signed_exchange_utils.cc
+++ b/content/browser/web_package/signed_exchange_utils.cc
@@ -36,7 +36,16 @@
     devtools_proxy->ReportError(error_message, std::move(error_field));
 }
 
-bool IsSignedExchangeHandlingEnabled(ResourceContext* context) {
+bool IsSignedExchangeHandlingEnabledOnIO(ResourceContext* context) {
+  if (!GetContentClient()->browser()->AllowSignedExchangeOnIO(context))
+    return false;
+
+  return base::FeatureList::IsEnabled(features::kSignedHTTPExchange) ||
+         base::CommandLine::ForCurrentProcess()->HasSwitch(
+             switches::kEnableExperimentalWebPlatformFeatures);
+}
+
+bool IsSignedExchangeHandlingEnabled(BrowserContext* context) {
   if (!GetContentClient()->browser()->AllowSignedExchange(context))
     return false;
 
diff --git a/content/browser/web_package/signed_exchange_utils.h b/content/browser/web_package/signed_exchange_utils.h
index 1500b0f..d520f92c 100644
--- a/content/browser/web_package/signed_exchange_utils.h
+++ b/content/browser/web_package/signed_exchange_utils.h
@@ -23,6 +23,7 @@
 
 namespace content {
 
+class BrowserContext;
 class ResourceContext;
 class SignedExchangeDevToolsProxy;
 
@@ -48,7 +49,10 @@
 
 // Returns true when SignedHTTPExchange feature is enabled. This must be called
 // on the IO thread.
-CONTENT_EXPORT bool IsSignedExchangeHandlingEnabled(ResourceContext* context);
+CONTENT_EXPORT bool IsSignedExchangeHandlingEnabledOnIO(
+    ResourceContext* context);
+// Same as above but called on UI thread.
+CONTENT_EXPORT bool IsSignedExchangeHandlingEnabled(BrowserContext* context);
 
 // Returns true when SignedExchangeReportingForDistributors feature is enabled.
 bool IsSignedExchangeReportingForDistributorsEnabled();
diff --git a/content/browser/webrtc/webrtc_image_capture_browsertest.cc b/content/browser/webrtc/webrtc_image_capture_browsertest.cc
index ca2a8dc..29edb07 100644
--- a/content/browser/webrtc/webrtc_image_capture_browsertest.cc
+++ b/content/browser/webrtc/webrtc_image_capture_browsertest.cc
@@ -39,6 +39,15 @@
 #define MAYBE_ManipulateExposureTime ManipulateExposureTime
 #endif
 
+#if defined(OS_LINUX)
+// See crbug/986470
+#define MAYBE_GetPhotoSettings DISABLED_GetPhotoSettings
+#define MAYBE_GetTrackSettings DISABLED_GetTrackSettings
+#else
+#define MAYBE_GetPhotoSettings GetPhotoSettings
+#define MAYBE_GetTrackSettings GetTrackSettings
+#endif
+
 namespace {
 
 static const char kImageCaptureHtmlFile[] = "/media/image_capture_test.html";
@@ -177,7 +186,7 @@
 }
 
 IN_PROC_BROWSER_TEST_P(WebRtcImageCaptureSucceedsBrowserTest,
-                       GetPhotoSettings) {
+                       MAYBE_GetPhotoSettings) {
   embedded_test_server()->StartAcceptingConnections();
   ASSERT_TRUE(
       RunImageCaptureTestCase("testCreateAndGetPhotoSettingsSucceeds()"));
@@ -200,7 +209,7 @@
 }
 
 IN_PROC_BROWSER_TEST_P(WebRtcImageCaptureSucceedsBrowserTest,
-                       GetTrackSettings) {
+                       MAYBE_GetTrackSettings) {
   embedded_test_server()->StartAcceptingConnections();
   ASSERT_TRUE(RunImageCaptureTestCase("testCreateAndGetTrackSettings()"));
 }
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index d34c185a..7b5da90 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -405,7 +405,7 @@
   WebRuntimeFeatures::EnableLazyImageLoadingMetadataFetch(
       base::GetFieldTrialParamByFeatureAsBool(
           features::kLazyImageLoading, "enable-lazy-load-images-metadata-fetch",
-          true));
+          false));
 
   WebRuntimeFeatures::EnablePictureInPicture(
       base::FeatureList::IsEnabled(media::kPictureInPicture));
@@ -522,7 +522,8 @@
     WebRuntimeFeatures::EnableSmsReceiver(false);
 
   WebRuntimeFeatures::EnableDisplayLocking(
-      base::FeatureList::IsEnabled(blink::features::kDisplayLocking));
+      base::FeatureList::IsEnabled(blink::features::kDisplayLocking) ||
+      enable_experimental_web_platform_features);
 
   WebRuntimeFeatures::EnableFormControlsRefresh(
       features::IsFormControlsRefreshEnabled());
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index 72ca266..546ad19 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -322,7 +322,11 @@
   return true;
 }
 
-bool ContentBrowserClient::AllowSignedExchange(ResourceContext* context) {
+bool ContentBrowserClient::AllowSignedExchangeOnIO(ResourceContext* context) {
+  return true;
+}
+
+bool ContentBrowserClient::AllowSignedExchange(BrowserContext* context) {
   return true;
 }
 
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index aecf782..cc45848d 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -575,7 +575,9 @@
   // loaded. This is called on the IO thread.
   // Relying on ResourceContext to access preferences on IO thread until we move
   // the call sites out of the IO thread. See crbug.com/908955 for more context.
-  virtual bool AllowSignedExchange(ResourceContext* context);
+  virtual bool AllowSignedExchangeOnIO(ResourceContext* context);
+  // Same as above but called on UI thread.
+  virtual bool AllowSignedExchange(BrowserContext* context);
 
   virtual bool IsDataSaverEnabled(BrowserContext* context);
 
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 64430295..d1ca3ab5 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -34,8 +34,12 @@
   sources = [
     "accessibility/aom_content_ax_tree.cc",
     "accessibility/aom_content_ax_tree.h",
+    "accessibility/ax_action_target_factory.cc",
+    "accessibility/ax_action_target_factory.h",
     "accessibility/ax_image_annotator.cc",
     "accessibility/ax_image_annotator.h",
+    "accessibility/blink_ax_action_target.cc",
+    "accessibility/blink_ax_action_target.h",
     "accessibility/blink_ax_enum_conversion.cc",
     "accessibility/blink_ax_enum_conversion.h",
     "accessibility/blink_ax_tree_source.cc",
diff --git a/content/renderer/accessibility/ax_action_target_factory.cc b/content/renderer/accessibility/ax_action_target_factory.cc
new file mode 100644
index 0000000..04f0cb2
--- /dev/null
+++ b/content/renderer/accessibility/ax_action_target_factory.cc
@@ -0,0 +1,26 @@
+// 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 "content/renderer/accessibility/ax_action_target_factory.h"
+
+#include "content/renderer/accessibility/blink_ax_action_target.h"
+#include "third_party/blink/public/web/web_ax_object.h"
+#include "third_party/blink/public/web/web_document.h"
+#include "ui/accessibility/null_ax_action_target.h"
+
+namespace content {
+
+// static
+std::unique_ptr<ui::AXActionTarget> AXActionTargetFactory::CreateFromNodeId(
+    const blink::WebDocument& document,
+    int node_id) {
+  blink::WebAXObject blink_target =
+      blink::WebAXObject::FromWebDocumentByID(document, node_id);
+  if (!blink_target.IsNull())
+    return std::make_unique<BlinkAXActionTarget>(blink_target);
+
+  return std::make_unique<ui::NullAXActionTarget>();
+}
+
+}  // namespace content
diff --git a/content/renderer/accessibility/ax_action_target_factory.h b/content/renderer/accessibility/ax_action_target_factory.h
new file mode 100644
index 0000000..c4b83079
--- /dev/null
+++ b/content/renderer/accessibility/ax_action_target_factory.h
@@ -0,0 +1,33 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_ACCESSIBILITY_AX_ACTION_TARGET_FACTORY_H_
+#define CONTENT_RENDERER_ACCESSIBILITY_AX_ACTION_TARGET_FACTORY_H_
+
+#include "content/common/content_export.h"
+
+#include <memory>
+
+namespace blink {
+class WebDocument;
+}
+
+namespace ui {
+class AXActionTarget;
+}
+
+namespace content {
+
+class CONTENT_EXPORT AXActionTargetFactory {
+ public:
+  // Given a node id, obtain a node from the appropriate tree source and wrap
+  // it in an abstraction for dispatching accessibility actions.
+  static std::unique_ptr<ui::AXActionTarget> CreateFromNodeId(
+      const blink::WebDocument& document,
+      int node_id);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_ACCESSIBILITY_AX_ACTION_TARGET_FACTORY_H_
diff --git a/content/renderer/accessibility/blink_ax_action_target.cc b/content/renderer/accessibility/blink_ax_action_target.cc
new file mode 100644
index 0000000..4f9bfeb
--- /dev/null
+++ b/content/renderer/accessibility/blink_ax_action_target.cc
@@ -0,0 +1,144 @@
+// 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 "content/renderer/accessibility/blink_ax_action_target.h"
+#include "third_party/blink/public/platform/web_float_rect.h"
+#include "third_party/blink/public/platform/web_rect.h"
+#include "third_party/blink/public/platform/web_string.h"
+#include "third_party/skia/include/core/SkMatrix44.h"
+
+using blink::WebAXObject;
+using blink::WebFloatRect;
+using blink::WebPoint;
+using blink::WebRect;
+
+namespace content {
+
+BlinkAXActionTarget::BlinkAXActionTarget(
+    const blink::WebAXObject& web_ax_object)
+    : web_ax_object_(web_ax_object) {
+  DCHECK(!web_ax_object.IsNull());
+}
+
+BlinkAXActionTarget::~BlinkAXActionTarget() {}
+
+const WebAXObject& BlinkAXActionTarget::WebAXObject() const {
+  return web_ax_object_;
+}
+
+// static
+const BlinkAXActionTarget* BlinkAXActionTarget::FromAXActionTarget(
+    const ui::AXActionTarget* ax_action_target) {
+  if (ax_action_target->GetType() == ui::AXActionTarget::Type::kBlink)
+    return static_cast<const BlinkAXActionTarget*>(ax_action_target);
+
+  return nullptr;
+}
+
+ui::AXActionTarget::Type BlinkAXActionTarget::GetType() const {
+  return ui::AXActionTarget::Type::kBlink;
+}
+
+bool BlinkAXActionTarget::ClearAccessibilityFocus() const {
+  return web_ax_object_.ClearAccessibilityFocus();
+}
+
+bool BlinkAXActionTarget::Click() const {
+  return web_ax_object_.Click();
+}
+
+bool BlinkAXActionTarget::Decrement() const {
+  return web_ax_object_.Decrement();
+}
+
+bool BlinkAXActionTarget::Increment() const {
+  return web_ax_object_.Increment();
+}
+
+bool BlinkAXActionTarget::Focus() const {
+  return web_ax_object_.Focus();
+}
+
+gfx::Rect BlinkAXActionTarget::GetRelativeBounds() const {
+  blink::WebAXObject offset_container;
+  WebFloatRect bounds;
+  SkMatrix44 container_transform;
+  web_ax_object_.GetRelativeBounds(offset_container, bounds,
+                                   container_transform);
+  return gfx::Rect(bounds.x, bounds.y, bounds.width, bounds.height);
+}
+
+gfx::Point BlinkAXActionTarget::GetScrollOffset() const {
+  WebPoint offset = web_ax_object_.GetScrollOffset();
+  return gfx::Point(offset.x, offset.y);
+}
+
+gfx::Point BlinkAXActionTarget::MinimumScrollOffset() const {
+  WebPoint offset = web_ax_object_.MinimumScrollOffset();
+  return gfx::Point(offset.x, offset.y);
+}
+
+gfx::Point BlinkAXActionTarget::MaximumScrollOffset() const {
+  WebPoint offset = web_ax_object_.MaximumScrollOffset();
+  return gfx::Point(offset.x, offset.y);
+}
+
+bool BlinkAXActionTarget::SetAccessibilityFocus() const {
+  return web_ax_object_.SetAccessibilityFocus();
+}
+
+void BlinkAXActionTarget::SetScrollOffset(const gfx::Point& point) const {
+  web_ax_object_.SetScrollOffset(WebPoint(point.x(), point.y()));
+}
+
+bool BlinkAXActionTarget::SetSelected(bool selected) const {
+  return web_ax_object_.SetSelected(selected);
+}
+
+bool BlinkAXActionTarget::SetSelection(const ui::AXActionTarget* anchor_object,
+                                       int anchor_offset,
+                                       const ui::AXActionTarget* focus_object,
+                                       int focus_offset) const {
+  const BlinkAXActionTarget* blink_anchor_object =
+      BlinkAXActionTarget::FromAXActionTarget(anchor_object);
+  const BlinkAXActionTarget* blink_focus_object =
+      BlinkAXActionTarget::FromAXActionTarget(focus_object);
+  if (!blink_anchor_object || !blink_focus_object)
+    return false;
+
+  return web_ax_object_.SetSelection(
+      blink_anchor_object->WebAXObject(), anchor_offset,
+      blink_focus_object->WebAXObject(), focus_offset);
+}
+
+bool BlinkAXActionTarget::SetSequentialFocusNavigationStartingPoint() const {
+  return web_ax_object_.SetSequentialFocusNavigationStartingPoint();
+}
+
+bool BlinkAXActionTarget::SetValue(const std::string& value) const {
+  return web_ax_object_.SetValue(blink::WebString::FromUTF8(value));
+}
+
+bool BlinkAXActionTarget::ShowContextMenu() const {
+  return web_ax_object_.ShowContextMenu();
+}
+
+bool BlinkAXActionTarget::ScrollToMakeVisible() const {
+  return web_ax_object_.ScrollToMakeVisible();
+}
+
+bool BlinkAXActionTarget::ScrollToMakeVisibleWithSubFocus(
+    const gfx::Rect& rect,
+    ax::mojom::ScrollAlignment horizontal_scroll_alignment,
+    ax::mojom::ScrollAlignment vertical_scroll_alignment) const {
+  return web_ax_object_.ScrollToMakeVisibleWithSubFocus(
+      WebRect(rect.x(), rect.y(), rect.width(), rect.height()),
+      horizontal_scroll_alignment, vertical_scroll_alignment);
+}
+
+bool BlinkAXActionTarget::ScrollToGlobalPoint(const gfx::Point& point) const {
+  return web_ax_object_.ScrollToGlobalPoint(WebPoint(point.x(), point.y()));
+}
+
+}  // namespace content
diff --git a/content/renderer/accessibility/blink_ax_action_target.h b/content/renderer/accessibility/blink_ax_action_target.h
new file mode 100644
index 0000000..3f9f37a
--- /dev/null
+++ b/content/renderer/accessibility/blink_ax_action_target.h
@@ -0,0 +1,58 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_ACCESSIBILITY_BLINK_AX_ACTION_TARGET_H_
+#define CONTENT_RENDERER_ACCESSIBILITY_BLINK_AX_ACTION_TARGET_H_
+
+#include "third_party/blink/public/web/web_ax_object.h"
+#include "ui/accessibility/ax_action_target.h"
+
+namespace content {
+
+// Wraps a WebAXObject for dispatching accessibility actions.
+class BlinkAXActionTarget : public ui::AXActionTarget {
+ public:
+  BlinkAXActionTarget(const blink::WebAXObject& web_ax_object);
+  ~BlinkAXActionTarget() override;
+
+  const blink::WebAXObject& WebAXObject() const;
+  static const BlinkAXActionTarget* FromAXActionTarget(
+      const ui::AXActionTarget* ax_action_target);
+
+ protected:
+  // AXActionTarget overrides.
+  Type GetType() const override;
+  bool ClearAccessibilityFocus() const override;
+  bool Click() const override;
+  bool Decrement() const override;
+  bool Increment() const override;
+  bool Focus() const override;
+  gfx::Rect GetRelativeBounds() const override;
+  gfx::Point GetScrollOffset() const override;
+  gfx::Point MinimumScrollOffset() const override;
+  gfx::Point MaximumScrollOffset() const override;
+  bool SetAccessibilityFocus() const override;
+  void SetScrollOffset(const gfx::Point& point) const override;
+  bool SetSelected(bool selected) const override;
+  bool SetSelection(const ui::AXActionTarget* anchor_object,
+                    int anchor_offset,
+                    const ui::AXActionTarget* focus_object,
+                    int focus_offset) const override;
+  bool SetSequentialFocusNavigationStartingPoint() const override;
+  bool SetValue(const std::string& value) const override;
+  bool ShowContextMenu() const override;
+  bool ScrollToMakeVisible() const override;
+  bool ScrollToMakeVisibleWithSubFocus(
+      const gfx::Rect& rect,
+      ax::mojom::ScrollAlignment horizontal_scroll_alignment,
+      ax::mojom::ScrollAlignment vertical_scroll_alignment) const override;
+  bool ScrollToGlobalPoint(const gfx::Point& point) const override;
+
+ private:
+  blink::WebAXObject web_ax_object_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_ACCESSIBILITY_BLINK_AX_ACTION_TARGET_H_
diff --git a/content/renderer/accessibility/render_accessibility_impl.cc b/content/renderer/accessibility/render_accessibility_impl.cc
index 1d2e7b8..96ac02c 100644
--- a/content/renderer/accessibility/render_accessibility_impl.cc
+++ b/content/renderer/accessibility/render_accessibility_impl.cc
@@ -22,7 +22,9 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "content/common/accessibility_messages.h"
+#include "content/renderer/accessibility/ax_action_target_factory.h"
 #include "content/renderer/accessibility/ax_image_annotator.h"
+#include "content/renderer/accessibility/blink_ax_action_target.h"
 #include "content/renderer/accessibility/blink_ax_enum_conversion.h"
 #include "content/renderer/render_frame_impl.h"
 #include "content/renderer/render_frame_proxy.h"
@@ -741,25 +743,28 @@
   if (!root.UpdateLayoutAndCheckValidity())
     return;
 
-  auto target = WebAXObject::FromWebDocumentByID(document, data.target_node_id);
-  auto anchor = WebAXObject::FromWebDocumentByID(document, data.anchor_node_id);
-  auto focus = WebAXObject::FromWebDocumentByID(document, data.focus_node_id);
+  std::unique_ptr<ui::AXActionTarget> target =
+      AXActionTargetFactory::CreateFromNodeId(document, data.target_node_id);
+  std::unique_ptr<ui::AXActionTarget> anchor =
+      AXActionTargetFactory::CreateFromNodeId(document, data.anchor_node_id);
+  std::unique_ptr<ui::AXActionTarget> focus =
+      AXActionTargetFactory::CreateFromNodeId(document, data.focus_node_id);
 
   switch (data.action) {
     case ax::mojom::Action::kBlur:
       root.Focus();
       break;
     case ax::mojom::Action::kClearAccessibilityFocus:
-      target.ClearAccessibilityFocus();
+      target->ClearAccessibilityFocus();
       break;
     case ax::mojom::Action::kDecrement:
-      target.Decrement();
+      target->Decrement();
       break;
     case ax::mojom::Action::kDoDefault:
-      target.Click();
+      target->Click();
       break;
     case ax::mojom::Action::kGetImageData:
-      OnGetImageData(target, data.target_rect.size());
+      OnGetImageData(target.get(), data.target_rect.size());
       break;
     case ax::mojom::Action::kHitTest:
       DCHECK(data.hit_test_event_to_fire != ax::mojom::Event::kNone);
@@ -767,44 +772,42 @@
                 data.request_id);
       break;
     case ax::mojom::Action::kIncrement:
-      target.Increment();
+      target->Increment();
       break;
     case ax::mojom::Action::kScrollToMakeVisible:
-      target.ScrollToMakeVisibleWithSubFocus(
-          WebRect(data.target_rect.x(), data.target_rect.y(),
-                  data.target_rect.width(), data.target_rect.height()),
-          data.horizontal_scroll_alignment, data.vertical_scroll_alignment);
+      target->ScrollToMakeVisibleWithSubFocus(data.target_rect,
+                                              data.horizontal_scroll_alignment,
+                                              data.vertical_scroll_alignment);
       break;
     case ax::mojom::Action::kScrollToPoint:
-      target.ScrollToGlobalPoint(
-          WebPoint(data.target_point.x(), data.target_point.y()));
+      target->ScrollToGlobalPoint(data.target_point);
       break;
     case ax::mojom::Action::kLoadInlineTextBoxes:
-      OnLoadInlineTextBoxes(target);
+      OnLoadInlineTextBoxes(target.get());
       break;
     case ax::mojom::Action::kFocus:
-      target.Focus();
+      target->Focus();
       break;
     case ax::mojom::Action::kSetAccessibilityFocus:
-      target.SetAccessibilityFocus();
+      target->SetAccessibilityFocus();
       break;
     case ax::mojom::Action::kSetScrollOffset:
-      target.SetScrollOffset(
+      target->SetScrollOffset(
           WebPoint(data.target_point.x(), data.target_point.y()));
       break;
     case ax::mojom::Action::kSetSelection:
-        anchor.SetSelection(anchor, data.anchor_offset, focus,
-                            data.focus_offset);
+      anchor->SetSelection(anchor.get(), data.anchor_offset, focus.get(),
+                           data.focus_offset);
       HandleAXEvent(root, ax::mojom::Event::kLayoutComplete);
       break;
     case ax::mojom::Action::kSetSequentialFocusNavigationStartingPoint:
-      target.SetSequentialFocusNavigationStartingPoint();
+      target->SetSequentialFocusNavigationStartingPoint();
       break;
     case ax::mojom::Action::kSetValue:
-      target.SetValue(blink::WebString::FromUTF8(data.value));
+      target->SetValue(data.value);
       break;
     case ax::mojom::Action::kShowContextMenu:
-      target.ShowContextMenu();
+      target->ShowContextMenu();
       break;
     case ax::mojom::Action::kScrollBackward:
     case ax::mojom::Action::kScrollForward:
@@ -812,7 +815,7 @@
     case ax::mojom::Action::kScrollDown:
     case ax::mojom::Action::kScrollLeft:
     case ax::mojom::Action::kScrollRight:
-      Scroll(target, data.action);
+      Scroll(target.get(), data.action);
       break;
     case ax::mojom::Action::kCustomAction:
     case ax::mojom::Action::kReplaceSelectedText:
@@ -911,7 +914,14 @@
                 action_request_id);
 }
 
-void RenderAccessibilityImpl::OnLoadInlineTextBoxes(const WebAXObject& obj) {
+void RenderAccessibilityImpl::OnLoadInlineTextBoxes(
+    const ui::AXActionTarget* target) {
+  const BlinkAXActionTarget* blink_target =
+      BlinkAXActionTarget::FromAXActionTarget(target);
+  if (!blink_target)
+    return;
+  const WebAXObject& obj = blink_target->WebAXObject();
+
   ScopedFreezeBlinkAXTreeSource freeze(&tree_source_);
   if (tree_source_.ShouldLoadInlineTextBoxes(obj))
     return;
@@ -930,8 +940,14 @@
   HandleAXEvent(obj, ax::mojom::Event::kTreeChanged);
 }
 
-void RenderAccessibilityImpl::OnGetImageData(const WebAXObject& obj,
+void RenderAccessibilityImpl::OnGetImageData(const ui::AXActionTarget* target,
                                              const gfx::Size& max_size) {
+  const BlinkAXActionTarget* blink_target =
+      BlinkAXActionTarget::FromAXActionTarget(target);
+  if (!blink_target)
+    return;
+  const WebAXObject& obj = blink_target->WebAXObject();
+
   ScopedFreezeBlinkAXTreeSource freeze(&tree_source_);
   if (tree_source_.image_data_node_id() == obj.AxID())
     return;
@@ -1055,63 +1071,59 @@
   }
 }
 
-void RenderAccessibilityImpl::Scroll(const WebAXObject& target,
+void RenderAccessibilityImpl::Scroll(const ui::AXActionTarget* target,
                                      ax::mojom::Action scroll_action) {
-  WebAXObject offset_container;
-  WebFloatRect bounds;
-  SkMatrix44 container_transform;
-  target.GetRelativeBounds(offset_container, bounds, container_transform);
-
+  gfx::Rect bounds = target->GetRelativeBounds();
   if (bounds.IsEmpty())
     return;
 
-  WebPoint initial = target.GetScrollOffset();
-  WebPoint min = target.MinimumScrollOffset();
-  WebPoint max = target.MaximumScrollOffset();
+  gfx::Point initial = target->GetScrollOffset();
+  gfx::Point min = target->MinimumScrollOffset();
+  gfx::Point max = target->MaximumScrollOffset();
 
   // TODO(anastasi): This 4/5ths came from the Android implementation, revisit
   // to find the appropriate modifier to keep enough context onscreen after
   // scrolling.
-  int page_x = std::max((int)(bounds.width * 4 / 5), 1);
-  int page_y = std::max((int)(bounds.height * 4 / 5), 1);
+  int page_x = std::max((int)(bounds.width() * 4 / 5), 1);
+  int page_y = std::max((int)(bounds.height() * 4 / 5), 1);
 
   // Forward/backward defaults to down/up unless it can only be scrolled
   // horizontally.
   if (scroll_action == ax::mojom::Action::kScrollForward)
-    scroll_action = max.y > min.y ? ax::mojom::Action::kScrollDown
-                                  : ax::mojom::Action::kScrollRight;
+    scroll_action = max.y() > min.y() ? ax::mojom::Action::kScrollDown
+                                      : ax::mojom::Action::kScrollRight;
   if (scroll_action == ax::mojom::Action::kScrollBackward)
-    scroll_action = max.y > min.y ? ax::mojom::Action::kScrollUp
-                                  : ax::mojom::Action::kScrollLeft;
+    scroll_action = max.y() > min.y() ? ax::mojom::Action::kScrollUp
+                                      : ax::mojom::Action::kScrollLeft;
 
-  int x = initial.x;
-  int y = initial.y;
+  int x = initial.x();
+  int y = initial.y();
   switch (scroll_action) {
     case ax::mojom::Action::kScrollUp:
-      if (initial.y == min.y)
+      if (initial.y() == min.y())
         return;
-      y = std::max(initial.y - page_y, min.y);
+      y = std::max(initial.y() - page_y, min.y());
       break;
     case ax::mojom::Action::kScrollDown:
-      if (initial.y == max.y)
+      if (initial.y() == max.y())
         return;
-      y = std::min(initial.y + page_y, max.y);
+      y = std::min(initial.y() + page_y, max.y());
       break;
     case ax::mojom::Action::kScrollLeft:
-      if (initial.x == min.x)
+      if (initial.x() == min.x())
         return;
-      x = std::max(initial.x - page_x, min.x);
+      x = std::max(initial.x() - page_x, min.x());
       break;
     case ax::mojom::Action::kScrollRight:
-      if (initial.x == max.x)
+      if (initial.x() == max.x())
         return;
-      x = std::min(initial.x + page_x, max.x);
+      x = std::min(initial.x() + page_x, max.x());
       break;
     default:
       NOTREACHED();
   }
 
-  target.SetScrollOffset(WebPoint(x, y));
+  target->SetScrollOffset(gfx::Point(x, y));
 }
 
 void RenderAccessibilityImpl::ScrollPlugin(int id_to_make_visible) {
diff --git a/content/renderer/accessibility/render_accessibility_impl.h b/content/renderer/accessibility/render_accessibility_impl.h
index 84764ac..e5e6325 100644
--- a/content/renderer/accessibility/render_accessibility_impl.h
+++ b/content/renderer/accessibility/render_accessibility_impl.h
@@ -30,6 +30,7 @@
 
 namespace ui {
 struct AXActionData;
+class AXActionTarget;
 struct AXEvent;
 }
 
@@ -144,8 +145,9 @@
   void OnHitTest(const gfx::Point& point,
                  ax::mojom::Event event_to_fire,
                  int action_request_id);
-  void OnLoadInlineTextBoxes(const blink::WebAXObject& obj);
-  void OnGetImageData(const blink::WebAXObject& obj, const gfx::Size& max_size);
+  void OnLoadInlineTextBoxes(const ui::AXActionTarget* target);
+  void OnGetImageData(const ui::AXActionTarget* target,
+                      const gfx::Size& max_size);
   void AddPluginTreeToUpdate(AXContentTreeUpdate* update,
                              bool invalidate_plugin_subtree);
 
@@ -161,7 +163,7 @@
   // Marks all AXObjects with the given role in the current tree dirty.
   void MarkAllAXObjectsDirty(ax::mojom::Role role);
 
-  void Scroll(const blink::WebAXObject& target,
+  void Scroll(const ui::AXActionTarget* target,
               ax::mojom::Action scroll_action);
   void ScrollPlugin(int id_to_make_visible);
   void ScheduleSendAccessibilityEventsIfNeeded();
diff --git a/content/renderer/accessibility/render_accessibility_impl_browsertest.cc b/content/renderer/accessibility/render_accessibility_impl_browsertest.cc
index 08bacee..e6f6ef8 100644
--- a/content/renderer/accessibility/render_accessibility_impl_browsertest.cc
+++ b/content/renderer/accessibility/render_accessibility_impl_browsertest.cc
@@ -21,6 +21,7 @@
 #include "content/common/frame_messages.h"
 #include "content/public/common/content_features.h"
 #include "content/public/test/render_view_test.h"
+#include "content/renderer/accessibility/ax_action_target_factory.h"
 #include "content/renderer/accessibility/ax_image_annotator.h"
 #include "content/renderer/render_frame_impl.h"
 #include "content/renderer/render_view_impl.h"
@@ -35,8 +36,10 @@
 #include "third_party/blink/public/web/web_local_frame.h"
 #include "third_party/blink/public/web/web_node.h"
 #include "third_party/blink/public/web/web_view.h"
+#include "ui/accessibility/ax_action_target.h"
 #include "ui/accessibility/ax_mode.h"
 #include "ui/accessibility/ax_node_data.h"
+#include "ui/native_theme/native_theme_features.h"
 
 namespace content {
 
@@ -364,6 +367,201 @@
   EXPECT_EQ(2, CountAccessibilityNodesSentToBrowser());
 }
 
+TEST_F(RenderAccessibilityImplTest, TestAXActionTargetFromNodeId) {
+  // Validate that we create the correct type of AXActionTarget for a given
+  // node id.
+  constexpr char html[] = R"HTML(
+      <body>
+      </body>
+      )HTML";
+  LoadHTMLAndRefreshAccessibilityTree(html);
+
+  WebDocument document = GetMainFrame()->GetDocument();
+  WebAXObject root_obj = WebAXObject::FromWebDocument(document);
+  WebAXObject body = root_obj.ChildAt(0);
+
+  // An AxID for an HTML node should produce a Blink action target.
+  std::unique_ptr<ui::AXActionTarget> body_action_target =
+      AXActionTargetFactory::CreateFromNodeId(document, body.AxID());
+  EXPECT_EQ(ui::AXActionTarget::Type::kBlink, body_action_target->GetType());
+
+  // An invalid AxID should produce a null action target.
+  std::unique_ptr<ui::AXActionTarget> null_action_target =
+      AXActionTargetFactory::CreateFromNodeId(document, -1);
+  EXPECT_EQ(ui::AXActionTarget::Type::kNull, null_action_target->GetType());
+}
+
+class BlinkAXActionTargetTest : public RenderAccessibilityImplTest {
+ protected:
+  void SetUp() override {
+    // Disable overlay scrollbars to avoid DCHECK on ChromeOS.
+    feature_list_.InitAndDisableFeature(features::kOverlayScrollbar);
+
+    RenderAccessibilityImplTest::SetUp();
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+TEST_F(BlinkAXActionTargetTest, TestMethods) {
+  // Exercise the methods on BlinkAXActionTarget to ensure they have the
+  // expected effects.
+  constexpr char html[] = R"HTML(
+      <body>
+        <input type=checkbox>
+        <input type=range min=1 value=2 max=3 step=1>
+        <input type=text>
+        <select size=2>
+          <option>One</option>
+          <option>Two</option>
+        </select>
+        <div style='width:100px; height: 100px; overflow:scroll'>
+          <div style='width:1000px; height:900px'></div>
+          <div style='width:1000px; height:100px'></div>
+        </div>
+        <div>Text Node One</div>
+        <div>Text Node Two</div>
+      </body>
+      )HTML";
+  LoadHTMLAndRefreshAccessibilityTree(html);
+
+  WebDocument document = GetMainFrame()->GetDocument();
+  WebAXObject root_obj = WebAXObject::FromWebDocument(document);
+  WebAXObject body = root_obj.ChildAt(0);
+  WebAXObject input_checkbox = body.ChildAt(0);
+  WebAXObject input_range = body.ChildAt(1);
+  WebAXObject input_text = body.ChildAt(2);
+  WebAXObject option = body.ChildAt(3).ChildAt(0);
+  WebAXObject scroller = body.ChildAt(4);
+  WebAXObject scroller_child = body.ChildAt(4).ChildAt(1);
+  WebAXObject text_one = body.ChildAt(5).ChildAt(0);
+  WebAXObject text_two = body.ChildAt(6).ChildAt(0);
+
+  std::unique_ptr<ui::AXActionTarget> input_checkbox_action_target =
+      AXActionTargetFactory::CreateFromNodeId(document, input_checkbox.AxID());
+  EXPECT_EQ(ui::AXActionTarget::Type::kBlink,
+            input_checkbox_action_target->GetType());
+
+  std::unique_ptr<ui::AXActionTarget> input_range_action_target =
+      AXActionTargetFactory::CreateFromNodeId(document, input_range.AxID());
+  EXPECT_EQ(ui::AXActionTarget::Type::kBlink,
+            input_range_action_target->GetType());
+
+  std::unique_ptr<ui::AXActionTarget> input_text_action_target =
+      AXActionTargetFactory::CreateFromNodeId(document, input_text.AxID());
+  EXPECT_EQ(ui::AXActionTarget::Type::kBlink,
+            input_text_action_target->GetType());
+
+  std::unique_ptr<ui::AXActionTarget> option_action_target =
+      AXActionTargetFactory::CreateFromNodeId(document, option.AxID());
+  EXPECT_EQ(ui::AXActionTarget::Type::kBlink, option_action_target->GetType());
+
+  std::unique_ptr<ui::AXActionTarget> scroller_action_target =
+      AXActionTargetFactory::CreateFromNodeId(document, scroller.AxID());
+  EXPECT_EQ(ui::AXActionTarget::Type::kBlink,
+            scroller_action_target->GetType());
+
+  std::unique_ptr<ui::AXActionTarget> scroller_child_action_target =
+      AXActionTargetFactory::CreateFromNodeId(document, scroller_child.AxID());
+  EXPECT_EQ(ui::AXActionTarget::Type::kBlink,
+            scroller_child_action_target->GetType());
+
+  std::unique_ptr<ui::AXActionTarget> text_one_action_target =
+      AXActionTargetFactory::CreateFromNodeId(document, text_one.AxID());
+  EXPECT_EQ(ui::AXActionTarget::Type::kBlink,
+            text_one_action_target->GetType());
+
+  std::unique_ptr<ui::AXActionTarget> text_two_action_target =
+      AXActionTargetFactory::CreateFromNodeId(document, text_two.AxID());
+  EXPECT_EQ(ui::AXActionTarget::Type::kBlink,
+            text_two_action_target->GetType());
+
+  EXPECT_EQ(ax::mojom::CheckedState::kFalse, input_checkbox.CheckedState());
+  EXPECT_TRUE(input_checkbox_action_target->Click());
+  EXPECT_EQ(ax::mojom::CheckedState::kTrue, input_checkbox.CheckedState());
+
+  float value = 0.0f;
+  EXPECT_TRUE(input_range.ValueForRange(&value));
+  EXPECT_EQ(2.0f, value);
+  EXPECT_TRUE(input_range_action_target->Decrement());
+  EXPECT_TRUE(input_range.ValueForRange(&value));
+  EXPECT_EQ(1.0f, value);
+  EXPECT_TRUE(input_range_action_target->Increment());
+  EXPECT_TRUE(input_range.ValueForRange(&value));
+  EXPECT_EQ(2.0f, value);
+
+  EXPECT_FALSE(input_range.IsFocused());
+  EXPECT_TRUE(input_range_action_target->Focus());
+  EXPECT_TRUE(input_range.IsFocused());
+
+  blink::WebFloatRect expected_bounds;
+  blink::WebAXObject offset_container;
+  SkMatrix44 container_transform;
+  input_checkbox.GetRelativeBounds(offset_container, expected_bounds,
+                                   container_transform);
+  gfx::Rect actual_bounds = input_checkbox_action_target->GetRelativeBounds();
+  EXPECT_EQ(static_cast<int>(expected_bounds.x), actual_bounds.x());
+  EXPECT_EQ(static_cast<int>(expected_bounds.y), actual_bounds.y());
+  EXPECT_EQ(static_cast<int>(expected_bounds.width), actual_bounds.width());
+  EXPECT_EQ(static_cast<int>(expected_bounds.height), actual_bounds.height());
+
+  gfx::Point offset_to_set(500, 500);
+  scroller_action_target->SetScrollOffset(gfx::Point(500, 500));
+  EXPECT_EQ(offset_to_set, scroller_action_target->GetScrollOffset());
+  EXPECT_EQ(gfx::Point(0, 0), scroller_action_target->MinimumScrollOffset());
+  EXPECT_GE(scroller_action_target->MaximumScrollOffset().y(), 900);
+
+  // Android does not produce accessible items for option elements.
+#if !defined(OS_ANDROID)
+  EXPECT_EQ(blink::kWebAXSelectedStateFalse, option.IsSelected());
+  EXPECT_TRUE(option_action_target->SetSelected(true));
+  EXPECT_EQ(blink::kWebAXSelectedStateTrue, option.IsSelected());
+#endif
+
+  std::string value_to_set("test-value");
+  input_text_action_target->SetValue(value_to_set);
+  EXPECT_EQ(value_to_set, input_text.StringValue().Utf8());
+
+  // Setting selection requires layout to be clean.
+  ASSERT_TRUE(root_obj.UpdateLayoutAndCheckValidity());
+
+  EXPECT_TRUE(text_one_action_target->SetSelection(
+      text_one_action_target.get(), 3, text_two_action_target.get(), 4));
+  bool is_selection_backward;
+  blink::WebAXObject anchor_object;
+  int anchor_offset;
+  ax::mojom::TextAffinity anchor_affinity;
+  blink::WebAXObject focus_object;
+  int focus_offset;
+  ax::mojom::TextAffinity focus_affinity;
+  root_obj.Selection(is_selection_backward, anchor_object, anchor_offset,
+                     anchor_affinity, focus_object, focus_offset,
+                     focus_affinity);
+  EXPECT_EQ(text_one, anchor_object);
+  EXPECT_EQ(3, anchor_offset);
+  EXPECT_EQ(text_two, focus_object);
+  EXPECT_EQ(4, focus_offset);
+
+  scroller_action_target->SetScrollOffset(gfx::Point(0, 0));
+  EXPECT_EQ(gfx::Point(0, 0), scroller_action_target->GetScrollOffset());
+  EXPECT_TRUE(scroller_child_action_target->ScrollToMakeVisible());
+  EXPECT_GE(scroller_action_target->GetScrollOffset().y(), 900);
+
+  scroller_action_target->SetScrollOffset(gfx::Point(0, 0));
+  EXPECT_EQ(gfx::Point(0, 0), scroller_action_target->GetScrollOffset());
+  EXPECT_TRUE(scroller_child_action_target->ScrollToMakeVisibleWithSubFocus(
+      gfx::Rect(0, 0, 50, 50), ax::mojom::ScrollAlignment::kScrollAlignmentLeft,
+      ax::mojom::ScrollAlignment::kScrollAlignmentTop));
+  EXPECT_GE(scroller_action_target->GetScrollOffset().y(), 900);
+
+  scroller_action_target->SetScrollOffset(gfx::Point(0, 0));
+  EXPECT_EQ(gfx::Point(0, 0), scroller_action_target->GetScrollOffset());
+  EXPECT_TRUE(
+      scroller_child_action_target->ScrollToGlobalPoint(gfx::Point(0, 0)));
+  EXPECT_GE(scroller_action_target->GetScrollOffset().y(), 900);
+}
+
 //
 // AXImageAnnotatorTest
 //
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index d0a02e6..3818e4c 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -53,7 +53,6 @@
 #include "third_party/blink/public/mojom/service_worker/service_worker_client.mojom.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
-#include "third_party/blink/public/platform/interface_provider.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_error.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/url_conversion.h"
diff --git a/content/test/gpu/gpu_tests/cloud_storage_integration_test_base.py b/content/test/gpu/gpu_tests/cloud_storage_integration_test_base.py
index 979e5f3..b9b48e744 100644
--- a/content/test/gpu/gpu_tests/cloud_storage_integration_test_base.py
+++ b/content/test/gpu/gpu_tests/cloud_storage_integration_test_base.py
@@ -403,8 +403,8 @@
            'view_test_results.html?%s for this run\'s test results') % (
       error_image_cloud_storage_bucket, upload_dir)
 
-  # TODO(https://crbug.com/983600): Remove this once the truncated images are
-  # determined to be legitimate or due to upload issues.
+  # Not used consistently, but potentially useful for debugging issues on the
+  # bots, so kept around for future use.
   @classmethod
   def _UploadGoldErrorImageToCloudStorage(cls, image_name, screenshot):
     machine_name = re.sub(r'\W+', '_',
@@ -505,10 +505,6 @@
       if self.GetParsedCommandLineOptions().local_run:
         logging.error(
             'Image produced by %s: file://%s', image_name, png_temp_file)
-      else:
-        # TODO(https://crbug.com/983600): Remove this once the truncated images
-        # are determined to be legitimate or due to upload issues.
-        self._UploadGoldErrorImageToCloudStorage(image_name, screenshot)
       if not self.GetParsedCommandLineOptions().no_skia_gold_failure:
         raise Exception('goldctl command failed')
 
diff --git a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
index 2e49289..5ab0027 100644
--- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -169,11 +169,8 @@
 # investigate later. Filed a bug to track the debug.
 crbug.com/984734 [ android-webview-instrumentation qualcomm-adreno-(tm)-418 ] Pixel_Video_Context_Loss_VP9 [ Failure ]
 
-# Producing black images on Nexus 5Xs in Android Webview.
-crbug.com/984352 [ android android-webview-instrumentation qualcomm-adreno-(tm)-418 ] Pixel_CanvasLowLatency2D [ Failure ]
-
 # Failing on Pixel 2 FYI.
-crbug.com/966069 [ android qualcomm-adreno-(tm)-540 ] Pixel_CanvasLowLatency2D [ Failure ]
+crbug.com/966069 [ android-chromium qualcomm-adreno-(tm)-540 ] Pixel_CanvasLowLatency2D [ Failure ]
 
 # Failing on Linux and Windows, both Intel HD 630 and NVIDIA Quadro P400
 crbug.com/974380 [ linux ] Pixel_OffscreenCanvasUnaccelerated2DGPUCompositing [ Skip ]
diff --git a/docs/accessibility/autoclick.md b/docs/accessibility/autoclick.md
new file mode 100644
index 0000000..28de750
--- /dev/null
+++ b/docs/accessibility/autoclick.md
@@ -0,0 +1,211 @@
+# Automatic clicks (for developers)
+
+Automatic clicks is a Chrome OS feature to automatically generate mouse events
+when the cursor dwells in one location.
+
+
+Dwell control supports users with motor impairments. A user who is unable to
+use a mouse or unable to click with a mouse, but who is able to control the
+cursor position (often using an alternative input method) will need to use
+dwell control to perform mouse or trackpad actions, including left-click,
+right-click, double-click, click-and-drag and scroll.
+
+## Using automatic clicks
+
+Go to Chrome settings, Accessibility settings, “Manage accessibility Features”,
+and in the “mouse and input” section enable “Automatically click when the
+cursor stops”. You can adjust timing, radius, stabilization, and whether to
+revert to a left-click after another type of action has been taken from the
+settings page.
+
+
+A on-screen menu bubble will appear in the corner. Dwell over this menu to
+change the action taken, or pause the feature. There is also a button to
+re-position the menu to another corner of the screen.
+
+## Reporting bugs
+
+Use bugs.chromium.org, filing bugs under the component UI>Accessibility with
+the label “autoclick” (or, use
+[this template](https://bugs.chromium.org/p/chromium/issues/entry?summary=Autoclick%20-%20&status=Available&cc=katie%40chromium.org%2C%20qqwangxin%40google.com&labels=Pri-3%2C%20autoclick%2C&components=UI>Accessibility)).
+
+
+Open bugs have the label 
+“[autoclick](https://bugs.chromium.org/p/chromium/issues/list?can=2&q=label%3Aautoclick)”.
+
+## Developing
+
+### Code location
+
+Automatic clicks code lives mainly in three places:
+
+- A controller, event-rewriter, and widgets to draw around click locations, in
+ash/autoclick/
+
+- UI through menu bubbles and their controllers, in
+ash/system/accessibility/autoclick*
+
+- A component extension to provide Accessibility tree information, in
+chrome/browser/resources/chromeos/autoclick/
+
+In addition, there are settings for automatic clicks in
+chrome/browser/resources/settings/a11y_page/manage_a11y_page.*
+
+
+### Tests
+
+Tests are in ash_unittests and in browser_tests:
+
+```
+out/Release/ash_unittests --gtest_filter=”Autoclick*”
+out/Release/browser_tests --gtest_filter=”Autoclick*”
+```
+
+### Debugging
+
+Developers can add log lines to any of the autoclick C++ files and see output
+in the console. To debug the Autoclick extension, the easiest way is from an
+external browser. Start Chrome OS on Linux with this command-line flag:
+
+```
+out/Release/chrome --remote-debugging-port=9222
+```
+
+Now open http://localhost:9222 in a separate instance of the browser, and debug
+the Autoclick extension background page from there.
+
+## How it works
+
+AutoclickController is a pre-target EventHandler with very high priority,
+which means it can receive and act on mouse events before other parts of
+Chrome OS get them.
+
+
+AutoclickController::OnMouseEvent receives mouse events and checks whether
+the event is close to the current dwell target (in which case dwell count-down
+should continue), or far enough away to clear the target and set a new one.
+
+
+There is a small delay before the user sees the count-down timer ring UI appear
+(AutoclickRingHandler) show up, which is controlled by the start_gesture_timer_.
+Performing the click is controlled by the autoclick_timer_.
+
+
+When the autoclick_timer_ completes it calls
+AutoclickController::DoAutoclickAction. This function first checks if the
+target point is over either of the autoclick bubbles, the menu or the scroll
+bubble. If it is over a bubble the gesture will not be handled with a synthetic
+event, but instead sent directly to that menu. This keeps focus from shifting
+and things like dialogs or context menus from closing when the user interacts
+with an autoclick bubble. But, if the target was not over the bubble, a
+synthetic event is generated as follows:
+
+### Left-click, right-click and double-click
+
+Synthetic mouse events for ui::ET_MOUSE_PRESSED and ui::ET_MOUSE_RELEASED are
+created with the appropriate mouse button flags, and sent to the WindowTreeHost
+under the target point for processing. For double-click, a second press and
+release pair are also sent.
+
+### Click-and-drag
+
+A synthetic mouse event for ui::ET_MOUSE_PRESSED is created at the first dwell.
+An AutoclickDragEventRewriter is enabled and begins re-writing all MOUSE_MOVED
+events to MOUSE_DRAGGED events to create the illusion of a drag. This occurs
+in AutoclickDragEventRewriter::RewriteEvent.
+
+A final synthetic mouse event for ui::ET_MOUSE_RELEASED is created at the
+second dwell, and the AutoclickDragEventRewriter is disabled.
+
+### Scroll
+
+On a dwell during scroll, the scroll target point is changed. No scroll events
+are generated from AutoclickController until the user hovers over the scroll
+pad buttons (AutoclickScrollButton class). The AutoclickScrollButtons track
+whether they are currently hovered, and while hovered they fire a repeating
+timer to ask the AutoclickController to do a scroll event.
+
+#### Scroll location
+
+By default, the scroll position is at the center of the active screen. Users
+may dwell anywhere on the screen to change the scroll location.
+
+
+When the scroll location is changed, the AutoclickController will request the
+bounds of the nearest scrollable view from the Autoclick component extension
+via the AccessibilityPrivate API. The Autoclick component extension has access
+to accessibility tree information, and using a HitTest is able to find the view
+at the scroll location, then walks up the tree to find the first view which can
+scroll, or stops at the nearest window or dialog bounds. This logic takes place
+in autoclick.js, onAutomationHitTestResult_. When the scrolling location is
+found, the bounds of the scrollable area are highlighted with a focus ring. 
+In addition, the bounds are sent back through the AccessibilityPrivate API,
+routed to the AutoclickController, which passes it via the
+AutoclickMenuBubbleController to the AutoclickScrollBubbleController, which
+does layout accordingly.
+
+### Bubble Menus: interface and positioning
+
+The AutoclickController owns the AutoclickMenuBubbleController, which controls
+the widget and AutoclickMenuView view for the autoclick bubble menu.
+AutoclickMenuView inherits from TrayBubbleView for styling, and contains all
+the buttons to change click types, pause, and update the menu position.
+
+
+Similarly, AutoclickMenuBubbleController also owns
+AutoclickScrollBubbleController so that it can pass on messages about
+positioning and activation from AutoclickController.
+AutoclickScrollBubbleController owns the widgets and AutoclickScrollView for
+the autoclick scroll bubble. AutoclickScrollView inherits from TrayBubbleView
+for styling, and contains the scroll pad buttons, including all the logic to
+draw the custom shape buttons for left/right/up/down scrolling.
+
+#### Menu positioning
+
+The autoclick bubble menu can be positioned in the four corners of the screen
+and defaults to the same location as the volume widget (which depends on
+LTR/RTL language). AutoclickMenuBubbleController takes a preferred
+AutoclickMenuPosition enum and uses that to determine the best position for
+the menu in AutoclickMenuBubbleController::SetPosition. This function finds
+the ideal corner of the screen, then uses CollisionDetectionUtils (also used 
+by Picture-in-Picture) to refine the position to avoid collisions with system
+UI.
+
+#### Scroll bubble positioning
+
+The scroll bubble starts out anchored to the automatic clicks bubble menu, but
+if the user selects a new scroll point it will move. When a scroll point is
+selected, if the scrollable region found by the Autoclick component extension
+is large enough, the scroll bubble will be anchored near the scroll point
+itself, similarly to the way the context menu is anchored near the cursor on
+a right click. When the scrollable region is small, the scroll bubble will be 
+anchored to the closest side of the scrollable region to the scroll point, as
+long as there is space for it on that side.
+
+#### Clicking on the bubble menus
+
+The AutomaticController cannot generate synthetic click events over the
+bubbles, because that would cause context and focus changes. For example, if
+the user has a drop-down menu open, clicking the autoclick menu bubble will
+cause the drop-down to close. Instead, the AutoclickController must check to
+see if an event will take place over a bubble menu, and if so, request that 
+AutoclickMenuBubbleController forward the event to the bubble via 
+AutoclickMenuBubbleController::ClickOnBubble. This generates a synthetic mouse
+event which does not propagate through the system, so there is no focus or 
+context change, allowing users to continue to interact with whatever was on
+screen.
+
+## For Googlers
+
+Googlers could check out the automatic clicks feature design docs for more
+details on design as well as autoclick’s UMA.
+
+- Overall product design, [go/chromeos-dwell-design](go/chromeos-dwell-design)
+
+- On-screen menu design,
+[go/chromeos-dwell-menu-design](go/chromeos-dwell-menu-design)
+
+- Scrolling design,
+[go/chromeos-dwell-scroll-design](go/chromeos-dwell-scroll-design)
+
+- UX mocks, [go/cros-dwell-ux](go/cros-dwell-ux)
diff --git a/docs/gpu/gpu_pixel_testing_with_gold.md b/docs/gpu/gpu_pixel_testing_with_gold.md
index 36fe0f02..82196f4 100644
--- a/docs/gpu/gpu_pixel_testing_with_gold.md
+++ b/docs/gpu/gpu_pixel_testing_with_gold.md
@@ -224,6 +224,14 @@
 pass the `--no-skia-gold-failure` flag to not fail the test on a failed image
 comparison.
 
+Example usage:
+`run_gpu_integration_test.py pixel --download-refimg-from-cloud-storage
+--use-skia-gold --no-skia-gold-failure --build-revision aabbccdd
+--test-machine-name local`
+
+The `--download-refimg-from-cloud-storage` is a temporary hold-over from the
+legacy pixel tests, and will be removed in the near future.
+
 ## Working On Gold
 
 ### Modifying Gold And goldctl
diff --git a/infra/config/luci-milo.cfg b/infra/config/luci-milo.cfg
index cae4f32..3ae0d19 100644
--- a/infra/config/luci-milo.cfg
+++ b/infra/config/luci-milo.cfg
@@ -3474,12 +3474,12 @@
   }
   builders {
     name: "buildbucket/luci.chromium.ci/Android FYI 32 Vk Release (Pixel 2)"
-    category: "Android|vk|P32"
+    category: "Android|vk|Q32"
     short_name: "P2"
   }
   builders {
     name: "buildbucket/luci.chromium.ci/Android FYI 64 Vk Release (Pixel 2)"
-    category: "Android|vk|P64"
+    category: "Android|vk|Q64"
     short_name: "P2"
   }
   builders {
@@ -3489,12 +3489,12 @@
   }
   builders {
     name: "buildbucket/luci.chromium.ci/Android FYI 32 dEQP Vk Release (Pixel 2)"
-    category: "Android|dqp|vk|P32"
+    category: "Android|dqp|vk|Q32"
     short_name: "P2"
   }
   builders {
     name: "buildbucket/luci.chromium.ci/Android FYI 64 dEQP Vk Release (Pixel 2)"
-    category: "Android|dqp|vk|P64"
+    category: "Android|dqp|vk|Q64"
     short_name: "P2"
   }
   builders {
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index 991da3d2..1faa653c 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -158,8 +158,8 @@
 #import "ios/third_party/material_roboto_font_loader_ios/src/src/MDCTypographyAdditions/MDFRobotoFontLoader+MDCTypographyAdditions.h"
 #import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
 #import "ios/web/common/web_view_creation_util.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #include "ios/web/public/thread/web_task_traits.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "ios/web/public/webui/web_ui_ios_controller_factory.h"
diff --git a/ios/chrome/browser/app_launcher/app_launcher_tab_helper.h b/ios/chrome/browser/app_launcher/app_launcher_tab_helper.h
index ccc2c70..667e67b 100644
--- a/ios/chrome/browser/app_launcher/app_launcher_tab_helper.h
+++ b/ios/chrome/browser/app_launcher/app_launcher_tab_helper.h
@@ -6,7 +6,7 @@
 #define IOS_CHROME_BROWSER_APP_LAUNCHER_APP_LAUNCHER_TAB_HELPER_H_
 
 #include "base/macros.h"
-#import "ios/web/public/web_state/web_state_policy_decider.h"
+#import "ios/web/public/navigation/web_state_policy_decider.h"
 #import "ios/web/public/web_state/web_state_user_data.h"
 
 @protocol AppLauncherTabHelperDelegate;
diff --git a/ios/chrome/browser/app_launcher/app_launcher_tab_helper.mm b/ios/chrome/browser/app_launcher/app_launcher_tab_helper.mm
index 745582f6..a9923dfe 100644
--- a/ios/chrome/browser/app_launcher/app_launcher_tab_helper.mm
+++ b/ios/chrome/browser/app_launcher/app_launcher_tab_helper.mm
@@ -17,8 +17,8 @@
 #import "ios/chrome/browser/chrome_url_util.h"
 #include "ios/chrome/browser/reading_list/reading_list_model_factory.h"
 #import "ios/chrome/browser/u2f/u2f_tab_helper.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/url_scheme_util.h"
 #import "ios/web/public/web_client.h"
 #import "net/base/mac/url_conversions.h"
diff --git a/ios/chrome/browser/autofill/autofill_controller_unittest.mm b/ios/chrome/browser/autofill/autofill_controller_unittest.mm
index 85e5bb9cf..51cc3bd 100644
--- a/ios/chrome/browser/autofill/autofill_controller_unittest.mm
+++ b/ios/chrome/browser/autofill/autofill_controller_unittest.mm
@@ -44,8 +44,8 @@
 #include "ios/web/public/js_messaging/web_frame.h"
 #include "ios/web/public/js_messaging/web_frame_util.h"
 #import "ios/web/public/js_messaging/web_frames_manager.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/web_state/web_state.h"
 #import "testing/gtest_mac.h"
 
diff --git a/ios/chrome/browser/autofill/form_suggestion_controller_unittest.mm b/ios/chrome/browser/autofill/form_suggestion_controller_unittest.mm
index 9396b3b..31ab038 100644
--- a/ios/chrome/browser/autofill/form_suggestion_controller_unittest.mm
+++ b/ios/chrome/browser/autofill/form_suggestion_controller_unittest.mm
@@ -19,7 +19,7 @@
 #import "ios/chrome/browser/autofill/form_suggestion_view.h"
 #import "ios/chrome/browser/ui/autofill/form_input_accessory_mediator.h"
 #include "ios/chrome/browser/ui/util/ui_util.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #include "ios/web/public/test/fakes/fake_web_frame.h"
 #import "ios/web/public/test/fakes/test_web_state.h"
 #include "ios/web/public/test/test_web_thread_bundle.h"
diff --git a/ios/chrome/browser/complex_tasks/ios_task_tab_helper.mm b/ios/chrome/browser/complex_tasks/ios_task_tab_helper.mm
index 9879160..482d9e2 100644
--- a/ios/chrome/browser/complex_tasks/ios_task_tab_helper.mm
+++ b/ios/chrome/browser/complex_tasks/ios_task_tab_helper.mm
@@ -6,9 +6,9 @@
 
 #include <string>
 
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
-#import "ios/web/public/web_state/navigation_context.h"
+#import "ios/web/public/navigation/navigation_context.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/crash_report/crash_report_helper.mm b/ios/chrome/browser/crash_report/crash_report_helper.mm
index b0b52ee..1e71d24b 100644
--- a/ios/chrome/browser/crash_report/crash_report_helper.mm
+++ b/ios/chrome/browser/crash_report/crash_report_helper.mm
@@ -24,10 +24,10 @@
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h"
 #include "ios/web/public/browser_state.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_context.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #include "ios/web/public/thread/web_thread.h"
-#import "ios/web/public/web_state/navigation_context.h"
 #import "ios/web/public/web_state/web_state.h"
 #import "ios/web/public/web_state/web_state_observer_bridge.h"
 #import "net/base/mac/url_conversions.h"
diff --git a/ios/chrome/browser/external_files/external_file_remover_impl.mm b/ios/chrome/browser/external_files/external_file_remover_impl.mm
index 0d64f51..7860350 100644
--- a/ios/chrome/browser/external_files/external_file_remover_impl.mm
+++ b/ios/chrome/browser/external_files/external_file_remover_impl.mm
@@ -20,7 +20,7 @@
 #import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/tabs/tab_model_list.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
-#include "ios/web/public/navigation_item.h"
+#include "ios/web/public/navigation/navigation_item.h"
 #include "ios/web/public/thread/web_thread.h"
 #import "ios/web/public/web_state/web_state.h"
 
diff --git a/ios/chrome/browser/geolocation/omnibox_geolocation_controller.mm b/ios/chrome/browser/geolocation/omnibox_geolocation_controller.mm
index 1fffe2de..0aa97783 100644
--- a/ios/chrome/browser/geolocation/omnibox_geolocation_controller.mm
+++ b/ios/chrome/browser/geolocation/omnibox_geolocation_controller.mm
@@ -23,8 +23,8 @@
 #import "ios/chrome/browser/geolocation/omnibox_geolocation_controller+Testing.h"
 #import "ios/chrome/browser/geolocation/omnibox_geolocation_local_state.h"
 #import "ios/web/public/browser_state.h"
-#include "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#include "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/web_state/web_state.h"
 #import "ios/web/public/web_state/web_state_observer_bridge.h"
 #include "url/gurl.h"
diff --git a/ios/chrome/browser/history/history_tab_helper.mm b/ios/chrome/browser/history/history_tab_helper.mm
index 96e258f..8b4f82d4 100644
--- a/ios/chrome/browser/history/history_tab_helper.mm
+++ b/ios/chrome/browser/history/history_tab_helper.mm
@@ -13,9 +13,9 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
 #include "ios/chrome/browser/history/history_service_factory.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
-#import "ios/web/public/web_state/navigation_context.h"
+#import "ios/web/public/navigation/navigation_context.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "net/http/http_response_headers.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/ios/chrome/browser/history/history_tab_helper_unittest.mm b/ios/chrome/browser/history/history_tab_helper_unittest.mm
index 2a4107a..e242e90 100644
--- a/ios/chrome/browser/history/history_tab_helper_unittest.mm
+++ b/ios/chrome/browser/history/history_tab_helper_unittest.mm
@@ -15,7 +15,7 @@
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
 #include "ios/chrome/browser/history/history_service_factory.h"
-#include "ios/web/public/navigation_item.h"
+#include "ios/web/public/navigation/navigation_item.h"
 #include "ios/web/public/test/fakes/test_web_state.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
diff --git a/ios/chrome/browser/infobars/infobar_manager_impl.mm b/ios/chrome/browser/infobars/infobar_manager_impl.mm
index 08bcccb..faeaa49d 100644
--- a/ios/chrome/browser/infobars/infobar_manager_impl.mm
+++ b/ios/chrome/browser/infobars/infobar_manager_impl.mm
@@ -8,9 +8,9 @@
 #include "components/infobars/core/confirm_infobar_delegate.h"
 #include "components/infobars/core/infobar.h"
 #include "ios/chrome/browser/infobars/infobar_utils.h"
-#include "ios/web/public/navigation_item.h"
-#include "ios/web/public/navigation_manager.h"
-#import "ios/web/public/web_state/navigation_context.h"
+#import "ios/web/public/navigation/navigation_context.h"
+#include "ios/web/public/navigation/navigation_item.h"
+#include "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/web_state/web_state.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/interstitials/ios_chrome_controller_client.mm b/ios/chrome/browser/interstitials/ios_chrome_controller_client.mm
index 34c318e..ec6b36c 100644
--- a/ios/chrome/browser/interstitials/ios_chrome_controller_client.mm
+++ b/ios/chrome/browser/interstitials/ios_chrome_controller_client.mm
@@ -9,8 +9,8 @@
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/pref_names.h"
-#import "ios/web/public/navigation_manager.h"
-#include "ios/web/public/reload_type.h"
+#import "ios/web/public/navigation/navigation_manager.h"
+#include "ios/web/public/navigation/reload_type.h"
 #include "ios/web/public/security/web_interstitial.h"
 #import "ios/web/public/web_state/web_state.h"
 
diff --git a/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.h b/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.h
index d0f2947..ab69771 100644
--- a/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.h
+++ b/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.h
@@ -6,7 +6,7 @@
 #define IOS_CHROME_BROWSER_ITUNES_URLS_ITUNES_URLS_HANDLER_TAB_HELPER_H_
 
 #include "base/macros.h"
-#import "ios/web/public/web_state/web_state_policy_decider.h"
+#import "ios/web/public/navigation/web_state_policy_decider.h"
 #import "ios/web/public/web_state/web_state_user_data.h"
 
 // Enum for the IOS.StoreKit.ITunesURLsHandlingResult UMA histogram to report
diff --git a/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.mm b/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.mm
index 45b247ef..8031ade 100644
--- a/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.mm
+++ b/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.mm
@@ -16,9 +16,9 @@
 #include "base/strings/sys_string_conversions.h"
 #import "ios/chrome/browser/store_kit/store_kit_tab_helper.h"
 #include "ios/web/public/browser_state.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
-#import "ios/web/public/web_state/web_state_policy_decider.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
+#import "ios/web/public/navigation/web_state_policy_decider.h"
 #include "net/base/filename_util.h"
 #import "net/base/mac/url_conversions.h"
 #include "net/base/url_util.h"
diff --git a/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper_unittest.mm b/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper_unittest.mm
index 43c272a6..bc11d70 100644
--- a/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper_unittest.mm
+++ b/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper_unittest.mm
@@ -10,9 +10,9 @@
 #import "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #import "ios/chrome/browser/store_kit/store_kit_tab_helper.h"
 #import "ios/chrome/test/fakes/fake_store_kit_launcher.h"
+#import "ios/web/public/navigation/web_state_policy_decider.h"
 #import "ios/web/public/test/fakes/test_web_state.h"
 #include "ios/web/public/test/test_web_thread_bundle.h"
-#import "ios/web/public/web_state/web_state_policy_decider.h"
 #include "testing/gtest_mac.h"
 #include "testing/platform_test.h"
 
diff --git a/ios/chrome/browser/metrics/ios_chrome_stability_metrics_provider.mm b/ios/chrome/browser/metrics/ios_chrome_stability_metrics_provider.mm
index d0852a4..64124c3 100644
--- a/ios/chrome/browser/metrics/ios_chrome_stability_metrics_provider.mm
+++ b/ios/chrome/browser/metrics/ios_chrome_stability_metrics_provider.mm
@@ -8,7 +8,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
 #include "ios/chrome/browser/metrics/features.h"
-#import "ios/web/public/web_state/navigation_context.h"
+#import "ios/web/public/navigation/navigation_context.h"
 #import "ios/web/public/web_state/web_state.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/metrics/tab_usage_recorder.mm b/ios/chrome/browser/metrics/tab_usage_recorder.mm
index fbbdaee..e46e129 100644
--- a/ios/chrome/browser/metrics/tab_usage_recorder.mm
+++ b/ios/chrome/browser/metrics/tab_usage_recorder.mm
@@ -12,9 +12,9 @@
 #include "ios/chrome/browser/metrics/ukm_url_recorder.h"
 #import "ios/chrome/browser/prerender/prerender_service.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
-#import "ios/web/public/web_state/navigation_context.h"
+#import "ios/web/public/navigation/navigation_context.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "ui/base/page_transition_types.h"
diff --git a/ios/chrome/browser/metrics/ukm_url_recorder.mm b/ios/chrome/browser/metrics/ukm_url_recorder.mm
index a336d336..704885d 100644
--- a/ios/chrome/browser/metrics/ukm_url_recorder.mm
+++ b/ios/chrome/browser/metrics/ukm_url_recorder.mm
@@ -8,7 +8,7 @@
 
 #include "base/containers/flat_map.h"
 #include "base/macros.h"
-#import "ios/web/public/web_state/navigation_context.h"
+#import "ios/web/public/navigation/navigation_context.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "ios/web/public/web_state/web_state_observer.h"
 #import "ios/web/public/web_state/web_state_user_data.h"
diff --git a/ios/chrome/browser/metrics/ukm_url_recorder_unittest.mm b/ios/chrome/browser/metrics/ukm_url_recorder_unittest.mm
index da85bd8..dddbff4 100644
--- a/ios/chrome/browser/metrics/ukm_url_recorder_unittest.mm
+++ b/ios/chrome/browser/metrics/ukm_url_recorder_unittest.mm
@@ -9,7 +9,7 @@
 #import "base/test/ios/wait_util.h"
 #include "components/ukm/test_ukm_recorder.h"
 #import "ios/chrome/browser/web/chrome_web_test.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_request.h"
diff --git a/ios/chrome/browser/ntp/new_tab_page_tab_helper.mm b/ios/chrome/browser/ntp/new_tab_page_tab_helper.mm
index bc9aa4b..735b44a 100644
--- a/ios/chrome/browser/ntp/new_tab_page_tab_helper.mm
+++ b/ios/chrome/browser/ntp/new_tab_page_tab_helper.mm
@@ -14,9 +14,9 @@
 #include "ios/chrome/browser/chrome_url_constants.h"
 #include "ios/chrome/browser/ntp/features.h"
 #include "ios/chrome/browser/ntp/new_tab_page_tab_helper_delegate.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
-#import "ios/web/public/web_state/navigation_context.h"
+#import "ios/web/public/navigation/navigation_context.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "ui/base/l10n/l10n_util.h"
 
diff --git a/ios/chrome/browser/open_in/open_in_tab_helper.mm b/ios/chrome/browser/open_in/open_in_tab_helper.mm
index fdd9ed3..8ba20f546 100644
--- a/ios/chrome/browser/open_in/open_in_tab_helper.mm
+++ b/ios/chrome/browser/open_in/open_in_tab_helper.mm
@@ -6,9 +6,9 @@
 
 #include "base/strings/sys_string_conversions.h"
 #include "ios/chrome/grit/ios_strings.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
-#import "ios/web/public/web_state/navigation_context.h"
+#import "ios/web/public/navigation/navigation_context.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "net/base/filename_util.h"
 #include "net/http/http_response_headers.h"
diff --git a/ios/chrome/browser/open_in/open_in_tab_helper_unittest.mm b/ios/chrome/browser/open_in/open_in_tab_helper_unittest.mm
index 39f3f38..1d15d8e 100644
--- a/ios/chrome/browser/open_in/open_in_tab_helper_unittest.mm
+++ b/ios/chrome/browser/open_in/open_in_tab_helper_unittest.mm
@@ -11,8 +11,8 @@
 #include "base/strings/sys_string_conversions.h"
 #import "ios/chrome/browser/open_in/open_in_tab_helper_delegate.h"
 #include "ios/chrome/grit/ios_strings.h"
-#include "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#include "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/test/fakes/fake_navigation_context.h"
 #import "ios/web/public/test/fakes/test_navigation_manager.h"
 #import "ios/web/public/test/fakes/test_web_state.h"
diff --git a/ios/chrome/browser/overlays/overlay_request_queue_impl.mm b/ios/chrome/browser/overlays/overlay_request_queue_impl.mm
index 52fee22..4e893fa 100644
--- a/ios/chrome/browser/overlays/overlay_request_queue_impl.mm
+++ b/ios/chrome/browser/overlays/overlay_request_queue_impl.mm
@@ -9,7 +9,7 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "ios/chrome/browser/overlays/public/overlay_request.h"
-#import "ios/web/public/web_state/navigation_context.h"
+#import "ios/web/public/navigation/navigation_context.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/passwords/credential_manager_unittest.mm b/ios/chrome/browser/passwords/credential_manager_unittest.mm
index d7dda1b2..4327f26 100644
--- a/ios/chrome/browser/passwords/credential_manager_unittest.mm
+++ b/ios/chrome/browser/passwords/credential_manager_unittest.mm
@@ -13,8 +13,8 @@
 #include "ios/chrome/browser/passwords/credential_manager_util.h"
 #import "ios/chrome/browser/passwords/test/test_password_manager_client.h"
 #include "ios/chrome/browser/ssl/ios_security_state_tab_helper.h"
-#include "ios/web/public/navigation_item.h"
-#include "ios/web/public/navigation_manager.h"
+#include "ios/web/public/navigation/navigation_item.h"
+#include "ios/web/public/navigation/navigation_manager.h"
 #include "ios/web/public/security/ssl_status.h"
 #import "ios/web/public/test/web_js_test.h"
 #include "ios/web/public/test/web_test_with_web_state.h"
diff --git a/ios/chrome/browser/passwords/password_controller_unittest.mm b/ios/chrome/browser/passwords/password_controller_unittest.mm
index 69866e43..756b5af 100644
--- a/ios/chrome/browser/passwords/password_controller_unittest.mm
+++ b/ios/chrome/browser/passwords/password_controller_unittest.mm
@@ -41,8 +41,8 @@
 #include "ios/web/public/js_messaging/web_frame.h"
 #include "ios/web/public/js_messaging/web_frame_util.h"
 #import "ios/web/public/js_messaging/web_frames_manager.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/test/fakes/test_web_state.h"
 #import "ios/web/public/test/web_js_test.h"
 #import "ios/web/public/web_state/web_state.h"
diff --git a/ios/chrome/browser/payments/ios_payment_instrument_launcher.mm b/ios/chrome/browser/payments/ios_payment_instrument_launcher.mm
index 2b5855d0..20a3e49 100644
--- a/ios/chrome/browser/payments/ios_payment_instrument_launcher.mm
+++ b/ios/chrome/browser/payments/ios_payment_instrument_launcher.mm
@@ -17,8 +17,8 @@
 #include "components/payments/core/payment_details.h"
 #include "components/payments/core/payment_instrument.h"
 #import "ios/chrome/browser/payments/payment_request_constants.h"
-#include "ios/web/public/navigation_item.h"
-#include "ios/web/public/navigation_manager.h"
+#include "ios/web/public/navigation/navigation_item.h"
+#include "ios/web/public/navigation/navigation_manager.h"
 #include "ios/web/public/security/ssl_status.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "net/base/mac/url_conversions.h"
diff --git a/ios/chrome/browser/prerender/preload_controller.h b/ios/chrome/browser/prerender/preload_controller.h
index 8689e376..24d8edf 100644
--- a/ios/chrome/browser/prerender/preload_controller.h
+++ b/ios/chrome/browser/prerender/preload_controller.h
@@ -12,7 +12,7 @@
 #include "components/prefs/pref_change_registrar.h"
 #import "ios/chrome/browser/net/connection_type_observer_bridge.h"
 #import "ios/web/public/deprecated/crw_native_content_provider.h"
-#include "ios/web/public/referrer.h"
+#include "ios/web/public/navigation/referrer.h"
 #import "ios/web/public/web_state/web_state_delegate_bridge.h"
 #import "net/url_request/url_fetcher.h"
 #include "ui/base/page_transition_types.h"
diff --git a/ios/chrome/browser/prerender/preload_controller.mm b/ios/chrome/browser/prerender/preload_controller.mm
index 7febc8d9..8868c24 100644
--- a/ios/chrome/browser/prerender/preload_controller.mm
+++ b/ios/chrome/browser/prerender/preload_controller.mm
@@ -27,12 +27,12 @@
 #import "ios/web/public/deprecated/crw_native_content.h"
 #import "ios/web/public/deprecated/crw_native_content_holder.h"
 #import "ios/web/public/deprecated/crw_web_controller_util.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
+#import "ios/web/public/navigation/web_state_policy_decider_bridge.h"
 #include "ios/web/public/thread/web_thread.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "ios/web/public/web_state/web_state_observer_bridge.h"
-#import "ios/web/public/web_state/web_state_policy_decider_bridge.h"
 #import "ios/web/web_state/ui/crw_web_controller.h"
 #import "net/base/mac/url_conversions.h"
 #include "ui/base/page_transition_types.h"
diff --git a/ios/chrome/browser/prerender/prerender_service.h b/ios/chrome/browser/prerender/prerender_service.h
index 561a8466..f857835 100644
--- a/ios/chrome/browser/prerender/prerender_service.h
+++ b/ios/chrome/browser/prerender/prerender_service.h
@@ -7,7 +7,7 @@
 
 #include "base/macros.h"
 #include "components/keyed_service/core/keyed_service.h"
-#include "ios/web/public/referrer.h"
+#include "ios/web/public/navigation/referrer.h"
 #include "ui/base/page_transition_types.h"
 #include "url/gurl.h"
 
diff --git a/ios/chrome/browser/prerender/prerender_service.mm b/ios/chrome/browser/prerender/prerender_service.mm
index 13bfcff..2e6319b0 100644
--- a/ios/chrome/browser/prerender/prerender_service.mm
+++ b/ios/chrome/browser/prerender/prerender_service.mm
@@ -10,7 +10,7 @@
 #import "ios/chrome/browser/ui/ntp/ntp_util.h"
 #import "ios/chrome/browser/web/load_timing_tab_helper.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #include "ios/web/public/web_client.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "ui/base/page_transition_types.h"
diff --git a/ios/chrome/browser/reading_list/offline_page_tab_helper.mm b/ios/chrome/browser/reading_list/offline_page_tab_helper.mm
index 3726d020..66944d48 100644
--- a/ios/chrome/browser/reading_list/offline_page_tab_helper.mm
+++ b/ios/chrome/browser/reading_list/offline_page_tab_helper.mm
@@ -21,10 +21,10 @@
 #include "ios/chrome/browser/reading_list/offline_url_utils.h"
 #include "ios/chrome/browser/reading_list/reading_list_download_service.h"
 #include "ios/chrome/browser/reading_list/reading_list_download_service_factory.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_context.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #include "ios/web/public/thread/web_task_traits.h"
 #include "ios/web/public/thread/web_thread.h"
-#import "ios/web/public/web_state/navigation_context.h"
 #include "ui/base/page_transition_types.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/reading_list/reading_list_distiller_page.mm b/ios/chrome/browser/reading_list/reading_list_distiller_page.mm
index 563e1a3f..cc2906e 100644
--- a/ios/chrome/browser/reading_list/reading_list_distiller_page.mm
+++ b/ios/chrome/browser/reading_list/reading_list_distiller_page.mm
@@ -13,8 +13,8 @@
 #include "components/google/core/common/google_util.h"
 #include "ios/chrome/browser/reading_list/favicon_web_state_dispatcher_impl.h"
 #import "ios/web/public/deprecated/crw_js_injection_receiver.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #include "ios/web/public/security/ssl_status.h"
 #import "ios/web/public/web_state/web_state.h"
 #import "net/base/mac/url_conversions.h"
diff --git a/ios/chrome/browser/reading_list/reading_list_web_state_observer.mm b/ios/chrome/browser/reading_list/reading_list_web_state_observer.mm
index 8619fc0b..d831227 100644
--- a/ios/chrome/browser/reading_list/reading_list_web_state_observer.mm
+++ b/ios/chrome/browser/reading_list/reading_list_web_state_observer.mm
@@ -14,9 +14,9 @@
 #include "ios/chrome/browser/chrome_url_constants.h"
 #include "ios/chrome/browser/reading_list/offline_url_utils.h"
 #include "ios/chrome/browser/reading_list/reading_list_model_factory.h"
-#include "ios/web/public/navigation_item.h"
-#include "ios/web/public/navigation_manager.h"
-#include "ios/web/public/reload_type.h"
+#include "ios/web/public/navigation/navigation_item.h"
+#include "ios/web/public/navigation/navigation_manager.h"
+#include "ios/web/public/navigation/reload_type.h"
 #import "ios/web/public/web_state/web_state_user_data.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/reading_list/reading_list_web_state_observer_unittest.mm b/ios/chrome/browser/reading_list/reading_list_web_state_observer_unittest.mm
index 175b178..da013a42 100644
--- a/ios/chrome/browser/reading_list/reading_list_web_state_observer_unittest.mm
+++ b/ios/chrome/browser/reading_list/reading_list_web_state_observer_unittest.mm
@@ -9,8 +9,8 @@
 #include "base/time/default_clock.h"
 #include "components/reading_list/core/reading_list_model_impl.h"
 #include "ios/chrome/browser/reading_list/offline_url_utils.h"
-#import "ios/web/public/navigation_item.h"
-#include "ios/web/public/reload_type.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#include "ios/web/public/navigation/reload_type.h"
 #import "ios/web/public/test/fakes/test_navigation_manager.h"
 #import "ios/web/public/test/fakes/test_web_state.h"
 #include "ios/web/public/test/web_test.h"
diff --git a/ios/chrome/browser/search_engines/search_engine_tab_helper.mm b/ios/chrome/browser/search_engines/search_engine_tab_helper.mm
index 329da5cf..2b5d19bf 100644
--- a/ios/chrome/browser/search_engines/search_engine_tab_helper.mm
+++ b/ios/chrome/browser/search_engines/search_engine_tab_helper.mm
@@ -13,9 +13,9 @@
 #include "ios/chrome/browser/search_engines/template_url_fetcher_factory.h"
 #include "ios/chrome/browser/search_engines/template_url_service_factory.h"
 #include "ios/web/public/favicon/favicon_status.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
-#import "ios/web/public/web_state/navigation_context.h"
+#import "ios/web/public/navigation/navigation_context.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #include "ui/base/page_transition_types.h"
 #include "url/gurl.h"
 
diff --git a/ios/chrome/browser/send_tab_to_self/send_tab_to_self_util.mm b/ios/chrome/browser/send_tab_to_self/send_tab_to_self_util.mm
index 96f3d9f54..5fa84c6d 100644
--- a/ios/chrome/browser/send_tab_to_self/send_tab_to_self_util.mm
+++ b/ios/chrome/browser/send_tab_to_self/send_tab_to_self_util.mm
@@ -25,7 +25,7 @@
 #import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/tabs/tab_model_list.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
-#import "ios/web/public/navigation_item.h"
+#import "ios/web/public/navigation/navigation_item.h"
 #import "ios/web/public/web_state/web_state.h"
 
 #include "url/gurl.h"
diff --git a/ios/chrome/browser/sessions/session_util.mm b/ios/chrome/browser/sessions/session_util.mm
index 10c8bb70..bfd0fa4 100644
--- a/ios/chrome/browser/sessions/session_util.mm
+++ b/ios/chrome/browser/sessions/session_util.mm
@@ -11,8 +11,8 @@
 #include "components/sessions/ios/ios_serialized_navigation_builder.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/sessions/session_service_ios.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/web_state/web_state.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ssl/captive_portal_metrics_tab_helper.mm b/ios/chrome/browser/ssl/captive_portal_metrics_tab_helper.mm
index d8fb5ca..1a096a0 100644
--- a/ios/chrome/browser/ssl/captive_portal_metrics_tab_helper.mm
+++ b/ios/chrome/browser/ssl/captive_portal_metrics_tab_helper.mm
@@ -8,7 +8,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "components/captive_portal/captive_portal_detector.h"
 #import "ios/chrome/browser/ssl/captive_portal_detector_tab_helper.h"
-#import "ios/web/public/web_state/navigation_context.h"
+#import "ios/web/public/navigation/navigation_context.h"
 #import "ios/web/public/web_state/web_state.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ssl/insecure_input_tab_helper.mm b/ios/chrome/browser/ssl/insecure_input_tab_helper.mm
index c20f36f8..4309479 100644
--- a/ios/chrome/browser/ssl/insecure_input_tab_helper.mm
+++ b/ios/chrome/browser/ssl/insecure_input_tab_helper.mm
@@ -13,9 +13,9 @@
 #include "components/autofill/ios/form_util/form_activity_tab_helper.h"
 #include "components/security_state/ios/ssl_status_input_event_data.h"
 #import "ios/web/common/origin_util.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
-#import "ios/web/public/web_state/navigation_context.h"
+#import "ios/web/public/navigation/navigation_context.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/web_state/web_state.h"
 #import "ios/web/public/web_state/web_state_user_data.h"
 #include "ui/base/page_transition_types.h"
diff --git a/ios/chrome/browser/ssl/ios_security_state_tab_helper.mm b/ios/chrome/browser/ssl/ios_security_state_tab_helper.mm
index 0c50b9c..622e1c9 100644
--- a/ios/chrome/browser/ssl/ios_security_state_tab_helper.mm
+++ b/ios/chrome/browser/ssl/ios_security_state_tab_helper.mm
@@ -12,8 +12,8 @@
 #include "components/security_state/ios/ssl_status_input_event_data.h"
 #import "ios/web/common/origin_util.h"
 #include "ios/web/public/browser_state.h"
-#include "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#include "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #include "ios/web/public/security/security_style.h"
 #include "ios/web/public/security/ssl_status.h"
 #import "ios/web/public/web_state/web_state.h"
diff --git a/ios/chrome/browser/ssl/ios_security_state_tab_helper_unittest.mm b/ios/chrome/browser/ssl/ios_security_state_tab_helper_unittest.mm
index 85447f0..5f8e91f 100644
--- a/ios/chrome/browser/ssl/ios_security_state_tab_helper_unittest.mm
+++ b/ios/chrome/browser/ssl/ios_security_state_tab_helper_unittest.mm
@@ -6,8 +6,8 @@
 
 #include "components/security_state/core/security_state.h"
 #import "ios/chrome/browser/ssl/insecure_input_tab_helper.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #include "ios/web/public/security/ssl_status.h"
 #import "ios/web/public/test/web_test_with_web_state.h"
 
diff --git a/ios/chrome/browser/ssl/ios_ssl_blocking_page.mm b/ios/chrome/browser/ssl/ios_ssl_blocking_page.mm
index f93523af..ef44e12 100644
--- a/ios/chrome/browser/ssl/ios_ssl_blocking_page.mm
+++ b/ios/chrome/browser/ssl/ios_ssl_blocking_page.mm
@@ -16,7 +16,7 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/interstitials/ios_chrome_controller_client.h"
 #include "ios/chrome/browser/interstitials/ios_chrome_metrics_helper.h"
-#import "ios/web/public/navigation_item.h"
+#import "ios/web/public/navigation/navigation_item.h"
 #include "ios/web/public/security/ssl_status.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "net/base/net_errors.h"
diff --git a/ios/chrome/browser/sync/ios_chrome_synced_tab_delegate.mm b/ios/chrome/browser/sync/ios_chrome_synced_tab_delegate.mm
index eb59d222..6dd0b238c 100644
--- a/ios/chrome/browser/sync/ios_chrome_synced_tab_delegate.mm
+++ b/ios/chrome/browser/sync/ios_chrome_synced_tab_delegate.mm
@@ -13,8 +13,8 @@
 #import "ios/chrome/browser/complex_tasks/ios_task_tab_helper.h"
 #include "ios/chrome/browser/sessions/ios_chrome_session_tab_helper.h"
 #include "ios/web/public/favicon/favicon_status.h"
-#include "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#include "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "ui/base/page_transition_types.h"
 
diff --git a/ios/chrome/browser/tabs/tab_model.h b/ios/chrome/browser/tabs/tab_model.h
index 9689f46d..157e8ef 100644
--- a/ios/chrome/browser/tabs/tab_model.h
+++ b/ios/chrome/browser/tabs/tab_model.h
@@ -11,7 +11,7 @@
 #include <memory>
 
 #import "ios/chrome/browser/sessions/session_window_restoring.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 
 #include "ui/base/page_transition_types.h"
 
diff --git a/ios/chrome/browser/tabs/tab_model.mm b/ios/chrome/browser/tabs/tab_model.mm
index 861fff198..86a9904 100644
--- a/ios/chrome/browser/tabs/tab_model.mm
+++ b/ios/chrome/browser/tabs/tab_model.mm
@@ -55,14 +55,14 @@
 #import "ios/chrome/browser/web_state_list/web_usage_enabler/web_state_list_web_usage_enabler.h"
 #import "ios/chrome/browser/web_state_list/web_usage_enabler/web_state_list_web_usage_enabler_factory.h"
 #include "ios/web/public/browser_state.h"
-#include "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_context.h"
+#include "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #include "ios/web/public/security/certificate_policy_cache.h"
 #import "ios/web/public/session/serializable_user_data_manager.h"
 #include "ios/web/public/session/session_certificate_policy_cache.h"
 #include "ios/web/public/thread/web_task_traits.h"
 #include "ios/web/public/thread/web_thread.h"
-#import "ios/web/public/web_state/navigation_context.h"
 #import "ios/web/public/web_state/web_state_observer_bridge.h"
 #include "url/gurl.h"
 
diff --git a/ios/chrome/browser/tabs/tab_model_closing_web_state_observer.mm b/ios/chrome/browser/tabs/tab_model_closing_web_state_observer.mm
index 453f00d..f062324 100644
--- a/ios/chrome/browser/tabs/tab_model_closing_web_state_observer.mm
+++ b/ios/chrome/browser/tabs/tab_model_closing_web_state_observer.mm
@@ -12,8 +12,8 @@
 #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h"
 #import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "url/gurl.h"
 
diff --git a/ios/chrome/browser/tabs/tab_model_synced_window_delegate.mm b/ios/chrome/browser/tabs/tab_model_synced_window_delegate.mm
index 673288da..ce6d124f 100644
--- a/ios/chrome/browser/tabs/tab_model_synced_window_delegate.mm
+++ b/ios/chrome/browser/tabs/tab_model_synced_window_delegate.mm
@@ -9,7 +9,7 @@
 #include "ios/chrome/browser/sessions/ios_chrome_session_tab_helper.h"
 #include "ios/chrome/browser/sync/ios_chrome_synced_tab_delegate.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/web_state/web_state.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/tabs/tab_model_unittest.mm b/ios/chrome/browser/tabs/tab_model_unittest.mm
index 35debdb..fabb343d 100644
--- a/ios/chrome/browser/tabs/tab_model_unittest.mm
+++ b/ios/chrome/browser/tabs/tab_model_unittest.mm
@@ -30,8 +30,8 @@
 #include "ios/chrome/test/ios_chrome_scoped_testing_chrome_browser_state_manager.h"
 #include "ios/web/common/features.h"
 #import "ios/web/navigation/navigation_manager_impl.h"
-#import "ios/web/public/navigation_manager.h"
-#include "ios/web/public/referrer.h"
+#import "ios/web/public/navigation/navigation_manager.h"
+#include "ios/web/public/navigation/referrer.h"
 #import "ios/web/public/session/crw_session_storage.h"
 #import "ios/web/public/session/serializable_user_data_manager.h"
 #include "ios/web/public/test/scoped_testing_web_client.h"
diff --git a/ios/chrome/browser/tabs/tab_title_util.mm b/ios/chrome/browser/tabs/tab_title_util.mm
index deaea0f..7fa96ee0 100644
--- a/ios/chrome/browser/tabs/tab_title_util.mm
+++ b/ios/chrome/browser/tabs/tab_title_util.mm
@@ -9,8 +9,8 @@
 #include "base/strings/sys_string_conversions.h"
 #include "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/download/download_manager_tab_helper.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "ui/base/l10n/l10n_util.h"
 
diff --git a/ios/chrome/browser/tabs/tab_title_util_unittest.mm b/ios/chrome/browser/tabs/tab_title_util_unittest.mm
index 9b1b9ff..98aba26 100644
--- a/ios/chrome/browser/tabs/tab_title_util_unittest.mm
+++ b/ios/chrome/browser/tabs/tab_title_util_unittest.mm
@@ -10,7 +10,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/download/download_manager_tab_helper.h"
-#import "ios/web/public/navigation_item.h"
+#import "ios/web/public/navigation/navigation_item.h"
 #import "ios/web/public/test/fakes/fake_download_task.h"
 #import "ios/web/public/test/fakes/test_navigation_manager.h"
 #import "ios/web/public/test/fakes/test_web_state.h"
diff --git a/ios/chrome/browser/translate/chrome_ios_translate_client.mm b/ios/chrome/browser/translate/chrome_ios_translate_client.mm
index adc1c35..354ae1ba 100644
--- a/ios/chrome/browser/translate/chrome_ios_translate_client.mm
+++ b/ios/chrome/browser/translate/chrome_ios_translate_client.mm
@@ -34,8 +34,8 @@
 #import "ios/chrome/browser/ui/translate/translate_notification_handler.h"
 #include "ios/chrome/grit/ios_theme_resources.h"
 #include "ios/web/public/browser_state.h"
-#include "ios/web/public/navigation_item.h"
-#include "ios/web/public/navigation_manager.h"
+#include "ios/web/public/navigation/navigation_item.h"
+#include "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "third_party/metrics_proto/translate_event.pb.h"
 #include "url/gurl.h"
diff --git a/ios/chrome/browser/ui/activity_services/share_to_data_builder.mm b/ios/chrome/browser/ui/activity_services/share_to_data_builder.mm
index 93569f57..7ffd1fc4 100644
--- a/ios/chrome/browser/ui/activity_services/share_to_data_builder.mm
+++ b/ios/chrome/browser/ui/activity_services/share_to_data_builder.mm
@@ -10,8 +10,8 @@
 #import "ios/chrome/browser/tabs/tab_title_util.h"
 #include "ios/chrome/browser/ui/activity_services/chrome_activity_item_thumbnail_generator.h"
 #include "ios/chrome/browser/ui/activity_services/share_to_data.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "url/gurl.h"
 
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
index cc08c1597..d482144 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
@@ -55,8 +55,8 @@
 #import "ios/chrome/common/favicon/favicon_view.h"
 #import "ios/chrome/common/ui_util/constraints_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
-#import "ios/web/public/navigation_manager.h"
-#include "ios/web/public/referrer.h"
+#import "ios/web/public/navigation/navigation_manager.h"
+#include "ios/web/public/navigation/referrer.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm
index f5165eac5..0bfdfed 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm
@@ -41,8 +41,8 @@
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/third_party/material_components_ios/src/components/Snackbar/src/MaterialSnackbar.h"
-#import "ios/web/public/navigation_manager.h"
-#include "ios/web/public/referrer.h"
+#import "ios/web/public/navigation/navigation_manager.h"
+#include "ios/web/public/navigation/referrer.h"
 #import "ios/web/public/web_state/web_state.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
index 0e380144..a48d433 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -186,7 +186,7 @@
 #import "ios/web/public/deprecated/crw_native_content_holder.h"
 #import "ios/web/public/deprecated/crw_native_content_provider.h"
 #import "ios/web/public/deprecated/crw_web_controller_util.h"
-#include "ios/web/public/navigation_item.h"
+#include "ios/web/public/navigation/navigation_item.h"
 #include "ios/web/public/thread/web_thread.h"
 #include "ios/web/public/url_scheme_util.h"
 #include "ios/web/public/web_client.h"
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller_unittest.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller_unittest.mm
index da9ec5c..a3e2b007f 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller_unittest.mm
@@ -58,7 +58,7 @@
 #import "ios/testing/ocmock_complex_type_helper.h"
 #import "ios/web/public/deprecated/crw_js_injection_receiver.h"
 #import "ios/web/public/deprecated/crw_native_content_provider.h"
-#include "ios/web/public/referrer.h"
+#include "ios/web/public/navigation/referrer.h"
 #import "ios/web/public/test/fakes/fake_navigation_context.h"
 #import "ios/web/public/test/fakes/test_navigation_manager.h"
 #import "ios/web/public/test/fakes/test_web_state.h"
diff --git a/ios/chrome/browser/ui/commands/open_new_tab_command.mm b/ios/chrome/browser/ui/commands/open_new_tab_command.mm
index 62ad2b7..0ce2021 100644
--- a/ios/chrome/browser/ui/commands/open_new_tab_command.mm
+++ b/ios/chrome/browser/ui/commands/open_new_tab_command.mm
@@ -5,7 +5,7 @@
 #import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
 
 #include "base/logging.h"
-#include "ios/web/public/referrer.h"
+#include "ios/web/public/navigation/referrer.h"
 #include "url/gurl.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.mm b/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.mm
index 3ee96983..5abc37c 100644
--- a/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.mm
+++ b/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.mm
@@ -53,9 +53,9 @@
 #import "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #import "ios/public/provider/chrome/browser/signin/signin_resources_provider.h"
 #import "ios/third_party/material_components_ios/src/components/Snackbar/src/MaterialSnackbar.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
-#include "ios/web/public/referrer.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
+#include "ios/web/public/navigation/referrer.h"
 #import "ios/web/public/web_state/web_state.h"
 #import "ios/web/public/web_state/web_state_observer_bridge.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/ios/chrome/browser/ui/dialogs/dialog_presenter.mm b/ios/chrome/browser/ui/dialogs/dialog_presenter.mm
index 679a5dc..445987cd 100644
--- a/ios/chrome/browser/ui/dialogs/dialog_presenter.mm
+++ b/ios/chrome/browser/ui/dialogs/dialog_presenter.mm
@@ -19,7 +19,7 @@
 #import "ios/chrome/browser/ui/dialogs/nsurl_protection_space_util.h"
 #include "ios/chrome/browser/ui/util/ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
-#import "ios/web/public/web_state/navigation_context.h"
+#import "ios/web/public/navigation/navigation_context.h"
 #import "ios/web/public/web_state/web_state.h"
 #import "ios/web/public/web_state/web_state_observer_bridge.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/ios/chrome/browser/ui/dialogs/dialog_presenter_unittest.mm b/ios/chrome/browser/ui/dialogs/dialog_presenter_unittest.mm
index 1eeb8b9c..58b9492 100644
--- a/ios/chrome/browser/ui/dialogs/dialog_presenter_unittest.mm
+++ b/ios/chrome/browser/ui/dialogs/dialog_presenter_unittest.mm
@@ -10,7 +10,7 @@
 #include "base/time/time.h"
 #include "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h"
-#import "ios/web/public/navigation_item.h"
+#import "ios/web/public/navigation/navigation_item.h"
 #import "ios/web/public/test/fakes/fake_navigation_context.h"
 #import "ios/web/public/test/fakes/test_navigation_manager.h"
 #import "ios/web/public/test/fakes/test_web_state.h"
diff --git a/ios/chrome/browser/ui/dialogs/java_script_dialog_blocking_state.mm b/ios/chrome/browser/ui/dialogs/java_script_dialog_blocking_state.mm
index db7c851..93ac82e 100644
--- a/ios/chrome/browser/ui/dialogs/java_script_dialog_blocking_state.mm
+++ b/ios/chrome/browser/ui/dialogs/java_script_dialog_blocking_state.mm
@@ -5,9 +5,9 @@
 #import "ios/chrome/browser/ui/dialogs/java_script_dialog_blocking_state.h"
 
 #include "base/logging.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
-#import "ios/web/public/web_state/navigation_context.h"
+#import "ios/web/public/navigation/navigation_context.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/dialogs/java_script_dialog_blocking_state_unittest.mm b/ios/chrome/browser/ui/dialogs/java_script_dialog_blocking_state_unittest.mm
index f6febc8..93d86bc9 100644
--- a/ios/chrome/browser/ui/dialogs/java_script_dialog_blocking_state_unittest.mm
+++ b/ios/chrome/browser/ui/dialogs/java_script_dialog_blocking_state_unittest.mm
@@ -6,7 +6,7 @@
 
 #include <memory>
 
-#import "ios/web/public/navigation_item.h"
+#import "ios/web/public/navigation/navigation_item.h"
 #import "ios/web/public/test/fakes/fake_navigation_context.h"
 #import "ios/web/public/test/fakes/test_navigation_manager.h"
 #import "ios/web/public/test/fakes/test_web_state.h"
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer_unittest.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer_unittest.mm
index 1e0978b..8f97dc03 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer_unittest.mm
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer_unittest.mm
@@ -13,7 +13,7 @@
 #import "ios/chrome/browser/web_state_list/fake_web_state_list_delegate.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/web_state_list/web_state_opener.h"
-#import "ios/web/public/navigation_item.h"
+#import "ios/web/public/navigation/navigation_item.h"
 #include "ios/web/public/security/ssl_status.h"
 #import "ios/web/public/test/fakes/fake_navigation_context.h"
 #import "ios/web/public/test/fakes/test_navigation_manager.h"
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.mm
index 9dd1de7..a2b340a 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.mm
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.mm
@@ -16,10 +16,10 @@
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #import "ios/public/provider/chrome/browser/ui/fullscreen_provider.h"
 #include "ios/web/common/url_util.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_context.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #include "ios/web/public/security/ssl_status.h"
-#import "ios/web/public/web_state/navigation_context.h"
 #import "ios/web/public/web_state/page_display_state.h"
 #import "ios/web/public/web_state/ui/crw_web_view_proxy.h"
 #import "ios/web/public/web_state/web_state.h"
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer_unittest.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer_unittest.mm
index d11daff..b0ba929 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer_unittest.mm
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer_unittest.mm
@@ -8,7 +8,7 @@
 #import "ios/chrome/browser/ui/fullscreen/test/fullscreen_model_test_util.h"
 #import "ios/chrome/browser/ui/fullscreen/test/test_fullscreen_controller.h"
 #import "ios/chrome/browser/ui/fullscreen/test/test_fullscreen_mediator.h"
-#import "ios/web/public/navigation_item.h"
+#import "ios/web/public/navigation/navigation_item.h"
 #include "ios/web/public/security/ssl_status.h"
 #import "ios/web/public/test/fakes/fake_navigation_context.h"
 #import "ios/web/public/test/fakes/test_navigation_manager.h"
diff --git a/ios/chrome/browser/ui/history/history_clear_browsing_data_coordinator.mm b/ios/chrome/browser/ui/history/history_clear_browsing_data_coordinator.mm
index f55e251..b16e811 100644
--- a/ios/chrome/browser/ui/history/history_clear_browsing_data_coordinator.mm
+++ b/ios/chrome/browser/ui/history/history_clear_browsing_data_coordinator.mm
@@ -17,7 +17,7 @@
 #import "ios/chrome/browser/url_loading/url_loading_params.h"
 #import "ios/chrome/browser/url_loading/url_loading_service.h"
 #import "ios/chrome/browser/url_loading/url_loading_service_factory.h"
-#import "ios/web/public/referrer.h"
+#import "ios/web/public/navigation/referrer.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/history/history_table_view_controller.mm b/ios/chrome/browser/ui/history/history_table_view_controller.mm
index 8a14f9d3..94c87b0 100644
--- a/ios/chrome/browser/ui/history/history_table_view_controller.mm
+++ b/ios/chrome/browser/ui/history/history_table_view_controller.mm
@@ -42,8 +42,8 @@
 #import "ios/chrome/common/favicon/favicon_view.h"
 #import "ios/chrome/common/ui_util/constraints_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
-#import "ios/web/public/navigation_manager.h"
-#import "ios/web/public/referrer.h"
+#import "ios/web/public/navigation/navigation_manager.h"
+#import "ios/web/public/navigation/referrer.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm b/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
index 501afa1..b5bbac2 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
+++ b/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
@@ -49,8 +49,8 @@
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #include "ios/public/provider/chrome/browser/voice/voice_search_provider.h"
-#import "ios/web/public/navigation_manager.h"
-#import "ios/web/public/referrer.h"
+#import "ios/web/public/navigation/navigation_manager.h"
+#import "ios/web/public/navigation/referrer.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "url/gurl.h"
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_mediator.mm b/ios/chrome/browser/ui/location_bar/location_bar_mediator.mm
index b2ce1f9..0785948 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_mediator.mm
+++ b/ios/chrome/browser/ui/location_bar/location_bar_mediator.mm
@@ -18,8 +18,8 @@
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h"
 #include "ios/chrome/grit/ios_theme_resources.h"
-#include "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#include "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #include "ios/web/public/security/ssl_status.h"
 #import "ios/web/public/web_client.h"
 #import "ios/web/public/web_state/web_state.h"
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_model_delegate_ios.mm b/ios/chrome/browser/ui/location_bar/location_bar_model_delegate_ios.mm
index 38e62d3b..31a2eec4 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_model_delegate_ios.mm
+++ b/ios/chrome/browser/ui/location_bar/location_bar_model_delegate_ios.mm
@@ -17,8 +17,8 @@
 #import "ios/chrome/browser/reading_list/offline_page_tab_helper.h"
 #include "ios/chrome/browser/ssl/ios_security_state_tab_helper.h"
 #include "ios/chrome/browser/web_state_list/web_state_list.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/security/ssl_status.h"
 #import "ios/web/public/web_state/web_state.h"
 
diff --git a/ios/chrome/browser/ui/main_content/web_scroll_view_main_content_ui_forwarder.mm b/ios/chrome/browser/ui/main_content/web_scroll_view_main_content_ui_forwarder.mm
index 1f2b35e..eb83d05 100644
--- a/ios/chrome/browser/ui/main_content/web_scroll_view_main_content_ui_forwarder.mm
+++ b/ios/chrome/browser/ui/main_content/web_scroll_view_main_content_ui_forwarder.mm
@@ -10,7 +10,7 @@
 #import "ios/chrome/browser/ui/main_content/main_content_ui_state.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h"
-#import "ios/web/public/web_state/navigation_context.h"
+#import "ios/web/public/navigation/navigation_context.h"
 #import "ios/web/public/web_state/ui/crw_web_view_proxy.h"
 #import "ios/web/public/web_state/ui/crw_web_view_scroll_view_proxy.h"
 #import "ios/web/public/web_state/web_state.h"
diff --git a/ios/chrome/browser/ui/ntp/incognito_view.mm b/ios/chrome/browser/ui/ntp/incognito_view.mm
index 5647265..e1286a6 100644
--- a/ios/chrome/browser/ui/ntp/incognito_view.mm
+++ b/ios/chrome/browser/ui/ntp/incognito_view.mm
@@ -19,8 +19,8 @@
 #import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
 #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
-#import "ios/web/public/navigation_manager.h"
-#include "ios/web/public/referrer.h"
+#import "ios/web/public/navigation/navigation_manager.h"
+#include "ios/web/public/navigation/referrer.h"
 #import "net/base/mac/url_conversions.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "url/gurl.h"
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
index 81c5dc01..c1fa360 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
@@ -12,9 +12,9 @@
 #import "ios/chrome/browser/ui/ntp/incognito_view_controller.h"
 #import "ios/chrome/browser/url_loading/url_loading_service_factory.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
-#import "ios/web/public/web_state/navigation_context.h"
+#import "ios/web/public/navigation/navigation_context.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/web_state/web_state.h"
 #import "ios/web/public/web_state/web_state_observer_bridge.h"
 
diff --git a/ios/chrome/browser/ui/ntp/ntp_util.mm b/ios/chrome/browser/ui/ntp/ntp_util.mm
index fa6a941d8..4adc951 100644
--- a/ios/chrome/browser/ui/ntp/ntp_util.mm
+++ b/ios/chrome/browser/ui/ntp/ntp_util.mm
@@ -5,8 +5,8 @@
 #import "ios/chrome/browser/ui/ntp/ntp_util.h"
 
 #include "ios/chrome/browser/chrome_url_constants.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.mm b/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.mm
index 7eeafc52..284811d 100644
--- a/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.mm
+++ b/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.mm
@@ -23,7 +23,7 @@
 #include "ios/chrome/browser/sessions/ios_chrome_session_tab_helper.h"
 #include "ios/chrome/browser/ui/omnibox/web_omnibox_edit_controller.h"
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "url/gurl.h"
 
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm b/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm
index 68f560ef..ed9616ad 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm
@@ -32,7 +32,7 @@
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ios/chrome/grit/ios_theme_resources.h"
-#include "ios/web/public/referrer.h"
+#include "ios/web/public/navigation/referrer.h"
 #import "net/base/mac/url_conversions.h"
 #include "skia/ext/skia_utils_ios.h"
 #include "ui/base/page_transition_types.h"
diff --git a/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_mediator.mm b/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_mediator.mm
index 492cfda..80388709 100644
--- a/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_mediator.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_mediator.mm
@@ -16,8 +16,8 @@
 #import "ios/chrome/browser/ui/toolbar/public/omnibox_focuser.h"
 #import "ios/chrome/browser/url_loading/url_loading_params.h"
 #import "ios/chrome/browser/url_loading/url_loading_service.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/page_info/page_info_legacy_coordinator.mm b/ios/chrome/browser/ui/page_info/page_info_legacy_coordinator.mm
index 96b603e..b151cad 100644
--- a/ios/chrome/browser/ui/page_info/page_info_legacy_coordinator.mm
+++ b/ios/chrome/browser/ui/page_info/page_info_legacy_coordinator.mm
@@ -26,9 +26,9 @@
 #import "ios/chrome/browser/url_loading/url_loading_service.h"
 #import "ios/chrome/browser/url_loading/url_loading_service_factory.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
-#include "ios/web/public/navigation_item.h"
-#include "ios/web/public/navigation_manager.h"
-#include "ios/web/public/reload_type.h"
+#include "ios/web/public/navigation/navigation_item.h"
+#include "ios/web/public/navigation/navigation_manager.h"
+#include "ios/web/public/navigation/reload_type.h"
 #include "ios/web/public/web_client.h"
 #import "ios/web/public/web_state/web_state.h"
 
diff --git a/ios/chrome/browser/ui/payments/payment_request_manager.mm b/ios/chrome/browser/ui/payments/payment_request_manager.mm
index d168c10..5087bddf 100644
--- a/ios/chrome/browser/ui/payments/payment_request_manager.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_manager.mm
@@ -63,11 +63,11 @@
 #include "ios/web/public/js_messaging/web_frame.h"
 #include "ios/web/public/js_messaging/web_frame_util.h"
 #import "ios/web/public/js_messaging/web_frames_manager.h"
-#include "ios/web/public/navigation_item.h"
-#include "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_context.h"
+#include "ios/web/public/navigation/navigation_item.h"
+#include "ios/web/public/navigation/navigation_manager.h"
 #include "ios/web/public/security/ssl_status.h"
 #import "ios/web/public/url_scheme_util.h"
-#import "ios/web/public/web_state/navigation_context.h"
 #import "ios/web/public/web_state/ui/crw_web_view_proxy.h"
 #import "ios/web/public/web_state/web_state.h"
 #import "ios/web/public/web_state/web_state_observer_bridge.h"
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm
index 23d01ad..dc89c59 100644
--- a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm
+++ b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm
@@ -43,9 +43,9 @@
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #import "ios/public/provider/chrome/browser/user_feedback/user_feedback_provider.h"
 #include "ios/web/public/favicon/favicon_status.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
-#include "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
+#include "ios/web/public/navigation/navigation_manager.h"
 #include "ios/web/public/user_agent.h"
 #include "ios/web/public/web_client.h"
 #import "ios/web/public/web_state/web_state.h"
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator_unittest.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator_unittest.mm
index 6c33cd8..34ed01d 100644
--- a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator_unittest.mm
@@ -21,7 +21,7 @@
 #import "ios/chrome/browser/web_state_list/web_state_opener.h"
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #import "ios/public/provider/chrome/browser/user_feedback/user_feedback_provider.h"
-#import "ios/web/public/navigation_item.h"
+#import "ios/web/public/navigation/navigation_item.h"
 #import "ios/web/public/test/fakes/fake_navigation_context.h"
 #import "ios/web/public/test/fakes/test_navigation_manager.h"
 #import "ios/web/public/test/fakes/test_web_state.h"
diff --git a/ios/chrome/browser/ui/reading_list/offline_page_native_content.mm b/ios/chrome/browser/ui/reading_list/offline_page_native_content.mm
index 604e57d..6c4c5ebd 100644
--- a/ios/chrome/browser/ui/reading_list/offline_page_native_content.mm
+++ b/ios/chrome/browser/ui/reading_list/offline_page_native_content.mm
@@ -12,9 +12,9 @@
 #include "ios/chrome/browser/reading_list/reading_list_download_service_factory.h"
 #import "ios/chrome/browser/ui/static_content/static_html_view_controller.h"
 #include "ios/web/public/browser_state.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
-#include "ios/web/public/reload_type.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
+#include "ios/web/public/navigation/reload_type.h"
 #import "ios/web/public/web_state/web_state.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ui/reading_list/offline_page_native_content_unittest.mm b/ios/chrome/browser/ui/reading_list/offline_page_native_content_unittest.mm
index 151e2a2..55e872b 100644
--- a/ios/chrome/browser/ui/reading_list/offline_page_native_content_unittest.mm
+++ b/ios/chrome/browser/ui/reading_list/offline_page_native_content_unittest.mm
@@ -10,8 +10,8 @@
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #include "ios/chrome/browser/reading_list/offline_url_utils.h"
 #import "ios/chrome/browser/ui/static_content/static_html_view_controller.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/test/web_test_with_web_state.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_coordinator.mm b/ios/chrome/browser/ui/reading_list/reading_list_coordinator.mm
index 4ebdac2..a21aa30 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_coordinator.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_coordinator.mm
@@ -37,7 +37,7 @@
 #import "ios/chrome/browser/url_loading/url_loading_service.h"
 #import "ios/chrome/browser/url_loading/url_loading_service_factory.h"
 #include "ios/chrome/grit/ios_strings.h"
-#include "ios/web/public/referrer.h"
+#include "ios/web/public/navigation/referrer.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/strings/grit/ui_strings.h"
 #include "url/gurl.h"
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm b/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm
index 8035ce85..52e94e5 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm
@@ -35,8 +35,8 @@
 #import "ios/chrome/test/earl_grey/chrome_matchers.h"
 #import "ios/chrome/test/earl_grey/chrome_test_case.h"
 #import "ios/third_party/material_components_ios/src/components/Snackbar/src/MaterialSnackbar.h"
-#import "ios/web/public/navigation_manager.h"
-#import "ios/web/public/reload_type.h"
+#import "ios/web/public/navigation/navigation_manager.h"
+#import "ios/web/public/navigation/reload_type.h"
 #import "ios/web/public/test/web_view_content_test_util.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "net/base/network_change_notifier.h"
diff --git a/ios/chrome/browser/ui/sad_tab/sad_tab_view.h b/ios/chrome/browser/ui/sad_tab/sad_tab_view.h
index 2590155..66bfef7 100644
--- a/ios/chrome/browser/ui/sad_tab/sad_tab_view.h
+++ b/ios/chrome/browser/ui/sad_tab/sad_tab_view.h
@@ -8,7 +8,7 @@
 #import <UIKit/UIKit.h>
 
 #include "base/ios/block_types.h"
-#include "ios/web/public/navigation_manager.h"
+#include "ios/web/public/navigation/navigation_manager.h"
 
 @protocol ApplicationCommands;
 @class SadTabView;
diff --git a/ios/chrome/browser/ui/sad_tab/sad_tab_view.mm b/ios/chrome/browser/ui/sad_tab/sad_tab_view.mm
index 215b403..eee58fad 100644
--- a/ios/chrome/browser/ui/sad_tab/sad_tab_view.mm
+++ b/ios/chrome/browser/ui/sad_tab/sad_tab_view.mm
@@ -18,7 +18,7 @@
 #import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h"
 #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ios/web/public/browser_state.h"
-#include "ios/web/public/navigation_manager.h"
+#include "ios/web/public/navigation/navigation_manager.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "url/gurl.h"
 
diff --git a/ios/chrome/browser/ui/settings/google_services/google_services_settings_egtest.mm b/ios/chrome/browser/ui/settings/google_services/google_services_settings_egtest.mm
index 64c5f98..8e0742e 100644
--- a/ios/chrome/browser/ui/settings/google_services/google_services_settings_egtest.mm
+++ b/ios/chrome/browser/ui/settings/google_services/google_services_settings_egtest.mm
@@ -21,7 +21,7 @@
 #import "ios/chrome/test/earl_grey/chrome_matchers.h"
 #import "ios/chrome/test/earl_grey/chrome_test_case.h"
 #import "ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.h"
-#import "ios/web/public/web_state/web_state_policy_decider.h"
+#import "ios/web/public/navigation/web_state_policy_decider.h"
 #import "ui/base/l10n/l10n_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ui/side_swipe/side_swipe_controller.mm b/ios/chrome/browser/ui/side_swipe/side_swipe_controller.mm
index 1baa1e9..7c70044 100644
--- a/ios/chrome/browser/ui/side_swipe/side_swipe_controller.mm
+++ b/ios/chrome/browser/ui/side_swipe/side_swipe_controller.mm
@@ -29,7 +29,7 @@
 #import "ios/chrome/browser/web/web_navigation_util.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h"
-#import "ios/web/public/navigation_item.h"
+#import "ios/web/public/navigation/navigation_item.h"
 #import "ios/web/public/web_client.h"
 #import "ios/web/public/web_state/web_state.h"
 #import "ios/web/public/web_state/web_state_observer_bridge.h"
diff --git a/ios/chrome/browser/ui/side_swipe/side_swipe_controller_unittest.mm b/ios/chrome/browser/ui/side_swipe/side_swipe_controller_unittest.mm
index e46ade9..6b469036 100644
--- a/ios/chrome/browser/ui/side_swipe/side_swipe_controller_unittest.mm
+++ b/ios/chrome/browser/ui/side_swipe/side_swipe_controller_unittest.mm
@@ -10,7 +10,7 @@
 #import "ios/chrome/browser/web_state_list/web_state_list_delegate.h"
 #import "ios/chrome/browser/web_state_list/web_state_opener.h"
 #include "ios/web/common/features.h"
-#import "ios/web/public/navigation_item.h"
+#import "ios/web/public/navigation/navigation_item.h"
 #import "ios/web/public/test/fakes/fake_navigation_context.h"
 #import "ios/web/public/test/fakes/test_navigation_manager.h"
 #import "ios/web/public/test/fakes/test_web_state.h"
diff --git a/ios/chrome/browser/ui/side_swipe/side_swipe_util.mm b/ios/chrome/browser/ui/side_swipe/side_swipe_util.mm
index ecbc1a0..f032e40b 100644
--- a/ios/chrome/browser/ui/side_swipe/side_swipe_util.mm
+++ b/ios/chrome/browser/ui/side_swipe/side_swipe_util.mm
@@ -10,7 +10,7 @@
 #import "ios/chrome/browser/chrome_url_util.h"
 #import "ios/chrome/browser/ui/ntp/ntp_util.h"
 #include "ios/chrome/browser/ui/util/rtl_geometry.h"
-#import "ios/web/public/navigation_item.h"
+#import "ios/web/public/navigation/navigation_item.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/static_content/static_html_native_content.h b/ios/chrome/browser/ui/static_content/static_html_native_content.h
index fe2eea1..0a4e07bc 100644
--- a/ios/chrome/browser/ui/static_content/static_html_native_content.h
+++ b/ios/chrome/browser/ui/static_content/static_html_native_content.h
@@ -8,7 +8,7 @@
 #import <UIKit/UIKit.h>
 
 #import "ios/web/public/deprecated/crw_native_content.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #include "ui/base/page_transition_types.h"
 
 class GURL;
diff --git a/ios/chrome/browser/ui/static_content/static_html_native_content.mm b/ios/chrome/browser/ui/static_content/static_html_native_content.mm
index d0fbe0c..a5439824 100644
--- a/ios/chrome/browser/ui/static_content/static_html_native_content.mm
+++ b/ios/chrome/browser/ui/static_content/static_html_native_content.mm
@@ -7,7 +7,7 @@
 #include "base/logging.h"
 #import "ios/chrome/browser/ui/overscroll_actions/overscroll_actions_controller.h"
 #include "ios/chrome/browser/ui/static_content/static_html_view_controller.h"
-#include "ios/web/public/referrer.h"
+#include "ios/web/public/navigation/referrer.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/static_content/static_html_view_controller.mm b/ios/chrome/browser/ui/static_content/static_html_view_controller.mm
index 5a85a12..6b04b57 100644
--- a/ios/chrome/browser/ui/static_content/static_html_view_controller.mm
+++ b/ios/chrome/browser/ui/static_content/static_html_view_controller.mm
@@ -18,7 +18,7 @@
 #import "ios/web/common/web_view_creation_util.h"
 #import "ios/web/public/deprecated/crw_context_menu_delegate.h"
 #import "ios/web/public/deprecated/crw_native_content.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "net/base/mac/url_conversions.h"
 #include "ui/base/page_transition_types.h"
 #include "ui/base/resource/resource_bundle.h"
diff --git a/ios/chrome/browser/ui/static_content/static_html_view_controller_unittest.mm b/ios/chrome/browser/ui/static_content/static_html_view_controller_unittest.mm
index 8699694..fb2fc4b 100644
--- a/ios/chrome/browser/ui/static_content/static_html_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/static_content/static_html_view_controller_unittest.mm
@@ -15,7 +15,7 @@
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/testing/ocmock_complex_type_helper.h"
 #import "ios/web/public/deprecated/crw_native_content.h"
-#include "ios/web/public/referrer.h"
+#include "ios/web/public/navigation/referrer.h"
 #import "ios/web/public/test/fakes/test_web_client.h"
 #import "ios/web/public/test/js_test_util.h"
 #include "ios/web/public/test/scoped_testing_web_client.h"
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_adaptor.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_adaptor.mm
index 24f4943..7acf214 100644
--- a/ios/chrome/browser/ui/tab_grid/tab_grid_adaptor.mm
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_adaptor.mm
@@ -9,7 +9,7 @@
 #import "ios/chrome/browser/ui/tab_grid/tab_grid_paging.h"
 #import "ios/chrome/browser/ui/tab_grid/view_controller_swapping.h"
 #import "ios/chrome/browser/url_loading/url_loading_params.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_mediator.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_mediator.mm
index 435b2f37f..281f83d 100644
--- a/ios/chrome/browser/ui/tab_grid/tab_grid_mediator.mm
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_mediator.mm
@@ -30,7 +30,7 @@
 #include "ios/chrome/browser/web_state_list/web_state_opener.h"
 #import "ios/chrome/browser/web_state_list/web_usage_enabler/web_state_list_web_usage_enabler.h"
 #import "ios/chrome/browser/web_state_list/web_usage_enabler/web_state_list_web_usage_enabler_factory.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/web_state/web_state.h"
 #import "ios/web/public/web_state/web_state_observer_bridge.h"
 #include "ui/gfx/image/image.h"
diff --git a/ios/chrome/browser/ui/tabs/tab_strip_controller_unittest.mm b/ios/chrome/browser/ui/tabs/tab_strip_controller_unittest.mm
index 8e1484d..445c3a0 100644
--- a/ios/chrome/browser/ui/tabs/tab_strip_controller_unittest.mm
+++ b/ios/chrome/browser/ui/tabs/tab_strip_controller_unittest.mm
@@ -17,7 +17,7 @@
 #import "ios/chrome/browser/web_state_list/fake_web_state_list_delegate.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/web_state_list/web_state_opener.h"
-#import "ios/web/public/navigation_item.h"
+#import "ios/web/public/navigation/navigation_item.h"
 #import "ios/web/public/test/fakes/test_navigation_manager.h"
 #import "ios/web/public/test/fakes/test_web_state.h"
 #include "ios/web/public/test/test_web_thread_bundle.h"
diff --git a/ios/chrome/browser/ui/toolbar/fullscreen/legacy_toolbar_ui_updater.mm b/ios/chrome/browser/ui/toolbar/fullscreen/legacy_toolbar_ui_updater.mm
index 6417662..287b39f 100644
--- a/ios/chrome/browser/ui/toolbar/fullscreen/legacy_toolbar_ui_updater.mm
+++ b/ios/chrome/browser/ui/toolbar/fullscreen/legacy_toolbar_ui_updater.mm
@@ -10,7 +10,7 @@
 #import "ios/chrome/browser/ui/toolbar/fullscreen/toolbar_ui.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h"
-#import "ios/web/public/web_state/navigation_context.h"
+#import "ios/web/public/navigation/navigation_context.h"
 #import "ios/web/public/web_state/web_state.h"
 #import "ios/web/public/web_state/web_state_observer_bridge.h"
 
diff --git a/ios/chrome/browser/ui/toolbar/primary_toolbar_coordinator.mm b/ios/chrome/browser/ui/toolbar/primary_toolbar_coordinator.mm
index cc88c196..bf25391 100644
--- a/ios/chrome/browser/ui/toolbar/primary_toolbar_coordinator.mm
+++ b/ios/chrome/browser/ui/toolbar/primary_toolbar_coordinator.mm
@@ -26,7 +26,7 @@
 #import "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
-#include "ios/web/public/referrer.h"
+#include "ios/web/public/navigation/referrer.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_mediator.mm b/ios/chrome/browser/ui/toolbar/toolbar_mediator.mm
index d4b7149..592c91f 100644
--- a/ios/chrome/browser/ui/toolbar/toolbar_mediator.mm
+++ b/ios/chrome/browser/ui/toolbar/toolbar_mediator.mm
@@ -18,7 +18,7 @@
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #import "ios/public/provider/chrome/browser/images/branded_image_provider.h"
 #import "ios/public/provider/chrome/browser/voice/voice_search_provider.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/web_client.h"
 #import "ios/web/public/web_state/web_state.h"
 #import "ios/web/public/web_state/web_state_observer_bridge.h"
diff --git a/ios/chrome/browser/url_loading/url_loading_params.h b/ios/chrome/browser/url_loading/url_loading_params.h
index 1f61f06..da663e4 100644
--- a/ios/chrome/browser/url_loading/url_loading_params.h
+++ b/ios/chrome/browser/url_loading/url_loading_params.h
@@ -6,7 +6,7 @@
 #define IOS_CHROME_BROWSER_URL_LOADING_URL_LOADING_PARAMS_H_
 
 #import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #include "ui/base/window_open_disposition.h"
 
 // Enum of ways of changing loading behavior, that can be passed around
diff --git a/ios/chrome/browser/url_loading/url_loading_service.h b/ios/chrome/browser/url_loading/url_loading_service.h
index 831e1b6d..2c02441 100644
--- a/ios/chrome/browser/url_loading/url_loading_service.h
+++ b/ios/chrome/browser/url_loading/url_loading_service.h
@@ -9,7 +9,7 @@
 #import <UIKit/UIKit.h>
 
 #include "components/keyed_service/core/keyed_service.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #include "ui/base/page_transition_types.h"
 #include "url/gurl.h"
 
diff --git a/ios/chrome/browser/voice/text_to_speech_listener.mm b/ios/chrome/browser/voice/text_to_speech_listener.mm
index 00f64e1..33ba104 100644
--- a/ios/chrome/browser/voice/text_to_speech_listener.mm
+++ b/ios/chrome/browser/voice/text_to_speech_listener.mm
@@ -9,7 +9,7 @@
 #include "base/logging.h"
 #import "ios/chrome/browser/voice/text_to_speech_parser.h"
 #import "ios/chrome/browser/voice/voice_search_url_rewriter.h"
-#include "ios/web/public/navigation_manager.h"
+#include "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "ios/web/public/web_state/web_state_observer.h"
 #import "ios/web/public/web_state/web_state_observer_bridge.h"
diff --git a/ios/chrome/browser/voice/voice_search_navigations_tab_helper.mm b/ios/chrome/browser/voice/voice_search_navigations_tab_helper.mm
index 384d35a..41f25aa 100644
--- a/ios/chrome/browser/voice/voice_search_navigations_tab_helper.mm
+++ b/ios/chrome/browser/voice/voice_search_navigations_tab_helper.mm
@@ -7,7 +7,7 @@
 #include <memory>
 
 #include "base/logging.h"
-#import "ios/web/public/web_state/navigation_context.h"
+#import "ios/web/public/navigation/navigation_context.h"
 #import "ios/web/public/web_state/web_state.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/voice/voice_search_navigations_tab_helper_unittest.mm b/ios/chrome/browser/voice/voice_search_navigations_tab_helper_unittest.mm
index dd516bf..8ef0bbe9 100644
--- a/ios/chrome/browser/voice/voice_search_navigations_tab_helper_unittest.mm
+++ b/ios/chrome/browser/voice/voice_search_navigations_tab_helper_unittest.mm
@@ -6,7 +6,7 @@
 
 #include "base/test/scoped_feature_list.h"
 #include "ios/web/common/features.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/test/web_test_with_web_state.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/ios/chrome/browser/web/blocked_popup_tab_helper.h b/ios/chrome/browser/web/blocked_popup_tab_helper.h
index 1de30b62..0782e5f 100644
--- a/ios/chrome/browser/web/blocked_popup_tab_helper.h
+++ b/ios/chrome/browser/web/blocked_popup_tab_helper.h
@@ -10,7 +10,7 @@
 #include "base/macros.h"
 #include "base/scoped_observer.h"
 #include "components/infobars/core/infobar_manager.h"
-#include "ios/web/public/referrer.h"
+#include "ios/web/public/navigation/referrer.h"
 #import "ios/web/public/web_state/web_state_user_data.h"
 #include "url/gurl.h"
 
diff --git a/ios/chrome/browser/web/blocked_popup_tab_helper.mm b/ios/chrome/browser/web/blocked_popup_tab_helper.mm
index 7ee9916..3762c3c 100644
--- a/ios/chrome/browser/web/blocked_popup_tab_helper.mm
+++ b/ios/chrome/browser/web/blocked_popup_tab_helper.mm
@@ -21,7 +21,7 @@
 #include "ios/chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "ios/chrome/browser/infobars/infobar_manager_impl.h"
 #include "ios/chrome/grit/ios_strings.h"
-#include "ios/web/public/referrer.h"
+#include "ios/web/public/navigation/referrer.h"
 #include "net/base/mac/url_conversions.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/image/image.h"
diff --git a/ios/chrome/browser/web/chrome_web_client.mm b/ios/chrome/browser/web/chrome_web_client.mm
index 3a7dc37e..8b080be 100644
--- a/ios/chrome/browser/web/chrome_web_client.mm
+++ b/ios/chrome/browser/web/chrome_web_client.mm
@@ -33,7 +33,7 @@
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #include "ios/public/provider/chrome/browser/voice/audio_session_controller.h"
 #include "ios/public/provider/chrome/browser/voice/voice_search_provider.h"
-#include "ios/web/public/browser_url_rewriter.h"
+#include "ios/web/public/navigation/browser_url_rewriter.h"
 #include "ios/web/public/service_names.mojom.h"
 #include "ios/web/public/user_agent.h"
 #include "net/http/http_util.h"
diff --git a/ios/chrome/browser/web/image_fetch_tab_helper.mm b/ios/chrome/browser/web/image_fetch_tab_helper.mm
index e20f78e5..6d4e849 100644
--- a/ios/chrome/browser/web/image_fetch_tab_helper.mm
+++ b/ios/chrome/browser/web/image_fetch_tab_helper.mm
@@ -14,9 +14,9 @@
 #include "components/image_fetcher/ios/ios_image_data_fetcher_wrapper.h"
 #include "ios/web/common/referrer_util.h"
 #include "ios/web/public/browser_state.h"
+#import "ios/web/public/navigation/navigation_context.h"
 #include "ios/web/public/thread/web_task_traits.h"
 #include "ios/web/public/thread/web_thread.h"
-#import "ios/web/public/web_state/navigation_context.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/web/sad_tab_tab_helper.mm b/ios/chrome/browser/web/sad_tab_tab_helper.mm
index 015c9250..e72a3cc 100644
--- a/ios/chrome/browser/web/sad_tab_tab_helper.mm
+++ b/ios/chrome/browser/web/sad_tab_tab_helper.mm
@@ -19,8 +19,8 @@
 #include "ios/chrome/browser/ui/fullscreen/scoped_fullscreen_disabler.h"
 #import "ios/chrome/browser/web/page_placeholder_tab_helper.h"
 #import "ios/chrome/browser/web/sad_tab_tab_helper_delegate.h"
-#import "ios/web/public/navigation_manager.h"
-#include "ios/web/public/web_state/navigation_context.h"
+#include "ios/web/public/navigation/navigation_context.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/web_state/web_state.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/web/visible_url_egtest.mm b/ios/chrome/browser/web/visible_url_egtest.mm
index f571c5d..4c8dffc 100644
--- a/ios/chrome/browser/web/visible_url_egtest.mm
+++ b/ios/chrome/browser/web/visible_url_egtest.mm
@@ -18,7 +18,7 @@
 #import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
 #import "ios/chrome/test/earl_grey/chrome_matchers.h"
 #import "ios/chrome/test/earl_grey/chrome_test_case.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #include "ios/web/public/test/http_server/html_response_provider.h"
 #import "ios/web/public/test/http_server/http_server.h"
 #include "ios/web/public/test/http_server/http_server_util.h"
diff --git a/ios/chrome/browser/web/web_navigation_util.h b/ios/chrome/browser/web/web_navigation_util.h
index 09755c2b..2dac993 100644
--- a/ios/chrome/browser/web/web_navigation_util.h
+++ b/ios/chrome/browser/web/web_navigation_util.h
@@ -6,7 +6,7 @@
 #define IOS_CHROME_BROWSER_WEB_WEB_NAVIGATION_UTIL_H_
 
 #include "components/search_engines/template_url.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #include "ui/base/page_transition_types.h"
 
 namespace web {
diff --git a/ios/chrome/browser/web/web_navigation_util.mm b/ios/chrome/browser/web/web_navigation_util.mm
index a20a4d5..0fa2f5d6 100644
--- a/ios/chrome/browser/web/web_navigation_util.mm
+++ b/ios/chrome/browser/web/web_navigation_util.mm
@@ -9,7 +9,7 @@
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
 #include "base/strings/sys_string_conversions.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "url/gurl.h"
 
diff --git a/ios/chrome/browser/web/web_navigation_util_unittest.mm b/ios/chrome/browser/web/web_navigation_util_unittest.mm
index 41102a3..ac744c5 100644
--- a/ios/chrome/browser/web/web_navigation_util_unittest.mm
+++ b/ios/chrome/browser/web/web_navigation_util_unittest.mm
@@ -6,7 +6,7 @@
 
 #include "base/test/metrics/user_action_tester.h"
 #include "components/search_engines/template_url.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/test/fakes/test_navigation_manager.h"
 #import "ios/web/public/test/fakes/test_web_state.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/ios/chrome/browser/web_state_list/web_state_list.mm b/ios/chrome/browser/web_state_list/web_state_list.mm
index a8160c97..9b46970 100644
--- a/ios/chrome/browser/web_state_list/web_state_list.mm
+++ b/ios/chrome/browser/web_state_list/web_state_list.mm
@@ -13,7 +13,7 @@
 #import "ios/chrome/browser/web_state_list/web_state_list_observer.h"
 #import "ios/chrome/browser/web_state_list/web_state_list_order_controller.h"
 #import "ios/chrome/browser/web_state_list/web_state_opener.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/web_state/web_state.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/web_state_list/web_state_opener.mm b/ios/chrome/browser/web_state_list/web_state_opener.mm
index 5f7abd46..f32ecc9 100644
--- a/ios/chrome/browser/web_state_list/web_state_opener.mm
+++ b/ios/chrome/browser/web_state_list/web_state_opener.mm
@@ -5,7 +5,7 @@
 #import "ios/chrome/browser/web_state_list/web_state_opener.h"
 
 #include "base/logging.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/web_state/web_state.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/web_state_list/web_usage_enabler/web_state_list_web_usage_enabler_impl.mm b/ios/chrome/browser/web_state_list/web_usage_enabler/web_state_list_web_usage_enabler_impl.mm
index f801a2ac..e5abdd8 100644
--- a/ios/chrome/browser/web_state_list/web_usage_enabler/web_state_list_web_usage_enabler_impl.mm
+++ b/ios/chrome/browser/web_state_list/web_usage_enabler/web_state_list_web_usage_enabler_impl.mm
@@ -5,7 +5,7 @@
 #import "ios/chrome/browser/web_state_list/web_usage_enabler/web_state_list_web_usage_enabler_impl.h"
 
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/web_state/web_state.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/test/app/chrome_test_util.mm b/ios/chrome/test/app/chrome_test_util.mm
index a8c1a4b..3525c2dc 100644
--- a/ios/chrome/test/app/chrome_test_util.mm
+++ b/ios/chrome/test/app/chrome_test_util.mm
@@ -26,10 +26,10 @@
 #import "ios/chrome/browser/ui/tab_grid/view_controller_swapping.h"
 #include "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/test/app/tab_test_util.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_context.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #include "ios/web/public/test/fakes/test_web_state_observer.h"
 #import "ios/web/public/test/native_controller_test_util.h"
-#import "ios/web/public/web_state/navigation_context.h"
 #import "third_party/breakpad/breakpad/src/client/ios/BreakpadController.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/public/provider/chrome/browser/browser_url_rewriter_provider.h b/ios/public/provider/chrome/browser/browser_url_rewriter_provider.h
index 8db7c204..de6eaad 100644
--- a/ios/public/provider/chrome/browser/browser_url_rewriter_provider.h
+++ b/ios/public/provider/chrome/browser/browser_url_rewriter_provider.h
@@ -5,7 +5,7 @@
 #ifndef IOS_PUBLIC_PROVIDER_CHROME_BROWSER_BROWSER_URL_REWRITER_PROVIDER_H_
 #define IOS_PUBLIC_PROVIDER_CHROME_BROWSER_BROWSER_URL_REWRITER_PROVIDER_H_
 
-#include "ios/web/public/browser_url_rewriter.h"
+#include "ios/web/public/navigation/browser_url_rewriter.h"
 
 #include "base/macros.h"
 
diff --git a/ios/web/browser_url_rewriter_impl.h b/ios/web/browser_url_rewriter_impl.h
index faa956cf..98a7addf 100644
--- a/ios/web/browser_url_rewriter_impl.h
+++ b/ios/web/browser_url_rewriter_impl.h
@@ -9,7 +9,7 @@
 
 #include "base/macros.h"
 #include "base/no_destructor.h"
-#include "ios/web/public/browser_url_rewriter.h"
+#include "ios/web/public/navigation/browser_url_rewriter.h"
 
 class GURL;
 
diff --git a/ios/web/common/BUILD.gn b/ios/web/common/BUILD.gn
index afb2969..9103251 100644
--- a/ios/web/common/BUILD.gn
+++ b/ios/web/common/BUILD.gn
@@ -21,7 +21,7 @@
 
   deps = [
     "//base",
-    "//ios/web/public:referrer",
+    "//ios/web/public/navigation",
     "//net",
     "//url",
   ]
@@ -55,7 +55,7 @@
   deps = [
     ":common",
     "//base",
-    "//ios/web/public:referrer",
+    "//ios/web/public/navigation",
     "//net",
     "//testing/gtest",
     "//url",
diff --git a/ios/web/common/referrer_util.cc b/ios/web/common/referrer_util.cc
index 01bf0dc..49bd735 100644
--- a/ios/web/common/referrer_util.cc
+++ b/ios/web/common/referrer_util.cc
@@ -5,7 +5,7 @@
 #include "ios/web/common/referrer_util.h"
 
 #include "base/logging.h"
-#include "ios/web/public/referrer.h"
+#include "ios/web/public/navigation/referrer.h"
 #include "url/gurl.h"
 
 namespace web {
diff --git a/ios/web/common/referrer_util.h b/ios/web/common/referrer_util.h
index 49ef082..bc53bd9 100644
--- a/ios/web/common/referrer_util.h
+++ b/ios/web/common/referrer_util.h
@@ -7,7 +7,7 @@
 
 #include <string>
 
-#include "ios/web/public/referrer.h"
+#include "ios/web/public/navigation/referrer.h"
 #include "net/url_request/url_request.h"
 
 class GURL;
diff --git a/ios/web/common/referrer_util_unittest.cc b/ios/web/common/referrer_util_unittest.cc
index a8cca5a0..0875d0d 100644
--- a/ios/web/common/referrer_util_unittest.cc
+++ b/ios/web/common/referrer_util_unittest.cc
@@ -5,7 +5,7 @@
 #include "ios/web/common/referrer_util.h"
 
 #include "base/stl_util.h"
-#include "ios/web/public/referrer.h"
+#include "ios/web/public/navigation/referrer.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 #include "url/gurl.h"
diff --git a/ios/web/init/web_main_runner.mm b/ios/web/init/web_main_runner.mm
index b8eed971..4139b69 100644
--- a/ios/web/init/web_main_runner.mm
+++ b/ios/web/init/web_main_runner.mm
@@ -9,7 +9,7 @@
 #include "base/macros.h"
 #include "ios/web/init/web_main_loop.h"
 #include "ios/web/public/init/ios_global_state.h"
-#include "ios/web/public/url_schemes.h"
+#include "ios/web/public/navigation/url_schemes.h"
 #import "ios/web/public/web_client.h"
 #include "ios/web/web_thread_impl.h"
 #include "mojo/core/embedder/embedder.h"
diff --git a/ios/web/js_messaging/web_frames_manager_inttest.mm b/ios/web/js_messaging/web_frames_manager_inttest.mm
index 39bd557dd..7de1ea5 100644
--- a/ios/web/js_messaging/web_frames_manager_inttest.mm
+++ b/ios/web/js_messaging/web_frames_manager_inttest.mm
@@ -7,7 +7,7 @@
 #include "ios/web/common/features.h"
 #include "ios/web/js_messaging/web_frames_manager_impl.h"
 #include "ios/web/public/js_messaging/web_frame.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/test/web_view_content_test_util.h"
 #import "ios/web/public/test/web_view_interaction_test_util.h"
 #import "ios/web/test/web_int_test.h"
diff --git a/ios/web/navigation/BUILD.gn b/ios/web/navigation/BUILD.gn
index 5cb90844..ecdcc11 100644
--- a/ios/web/navigation/BUILD.gn
+++ b/ios/web/navigation/BUILD.gn
@@ -23,7 +23,7 @@
     "//ios/web/js_messaging",
     "//ios/web/navigation:wk_navigation_util",
     "//ios/web/public",
-    "//ios/web/public/deprecated",
+    "//ios/web/public/deprecated:deprecated_navigation_util",
     "//ios/web/public/download",
     "//ios/web/public/js_messaging",
     "//ios/web/public/security",
@@ -91,7 +91,7 @@
     "//components/url_formatter:url_formatter",
     "//ios/web/navigation:wk_navigation_util",
     "//ios/web/public",
-    "//ios/web/public/deprecated",
+    "//ios/web/public/deprecated:deprecated_navigation_util",
     "//ios/web/public/security",
     "//ui/base",
   ]
diff --git a/ios/web/navigation/crw_navigation_item_storage_unittest.mm b/ios/web/navigation/crw_navigation_item_storage_unittest.mm
index 9f97cfd5..c8abd95 100644
--- a/ios/web/navigation/crw_navigation_item_storage_unittest.mm
+++ b/ios/web/navigation/crw_navigation_item_storage_unittest.mm
@@ -12,7 +12,7 @@
 #include "base/strings/sys_string_conversions.h"
 #import "ios/web/navigation/navigation_item_impl.h"
 #import "ios/web/navigation/navigation_item_storage_test_util.h"
-#include "ios/web/public/referrer.h"
+#include "ios/web/public/navigation/referrer.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
 #include "testing/platform_test.h"
diff --git a/ios/web/navigation/crw_session_controller.h b/ios/web/navigation/crw_session_controller.h
index 594b3e16..bff12a35 100644
--- a/ios/web/navigation/crw_session_controller.h
+++ b/ios/web/navigation/crw_session_controller.h
@@ -11,7 +11,7 @@
 #include <vector>
 
 #import "ios/web/navigation/navigation_item_impl_list.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #include "ui/base/page_transition_types.h"
 #include "url/gurl.h"
 
diff --git a/ios/web/navigation/crw_session_controller.mm b/ios/web/navigation/crw_session_controller.mm
index 8467ea81..4cb85944 100644
--- a/ios/web/navigation/crw_session_controller.mm
+++ b/ios/web/navigation/crw_session_controller.mm
@@ -22,8 +22,8 @@
 #import "ios/web/navigation/navigation_manager_impl.h"
 #include "ios/web/navigation/time_smoother.h"
 #include "ios/web/public/browser_state.h"
-#include "ios/web/public/browser_url_rewriter.h"
-#include "ios/web/public/referrer.h"
+#include "ios/web/public/navigation/browser_url_rewriter.h"
+#include "ios/web/public/navigation/referrer.h"
 #include "ios/web/public/security/ssl_status.h"
 #import "ios/web/public/web_client.h"
 
diff --git a/ios/web/navigation/crw_session_controller_unittest.mm b/ios/web/navigation/crw_session_controller_unittest.mm
index 277e5f88..0380687 100644
--- a/ios/web/navigation/crw_session_controller_unittest.mm
+++ b/ios/web/navigation/crw_session_controller_unittest.mm
@@ -17,7 +17,7 @@
 #import "ios/web/navigation/legacy_navigation_manager_impl.h"
 #import "ios/web/navigation/navigation_item_impl.h"
 #import "ios/web/navigation/navigation_manager_impl.h"
-#include "ios/web/public/referrer.h"
+#include "ios/web/public/navigation/referrer.h"
 #include "ios/web/public/test/fakes/test_browser_state.h"
 #include "ios/web/public/test/test_web_thread_bundle.h"
 #import "ios/web/test/fakes/crw_fake_session_controller_delegate.h"
diff --git a/ios/web/navigation/crw_session_storage_unittest.mm b/ios/web/navigation/crw_session_storage_unittest.mm
index e1f4065..6bd283c 100644
--- a/ios/web/navigation/crw_session_storage_unittest.mm
+++ b/ios/web/navigation/crw_session_storage_unittest.mm
@@ -8,7 +8,7 @@
 #import "ios/web/navigation/navigation_item_impl.h"
 #import "ios/web/navigation/navigation_item_storage_test_util.h"
 #import "ios/web/navigation/serializable_user_data_manager_impl.h"
-#include "ios/web/public/referrer.h"
+#include "ios/web/public/navigation/referrer.h"
 #import "ios/web/public/session/crw_navigation_item_storage.h"
 #import "net/base/mac/url_conversions.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/ios/web/navigation/history_state_operations_inttest.mm b/ios/web/navigation/history_state_operations_inttest.mm
index 5bab0888..4f70d16 100644
--- a/ios/web/navigation/history_state_operations_inttest.mm
+++ b/ios/web/navigation/history_state_operations_inttest.mm
@@ -11,8 +11,8 @@
 #include "base/test/scoped_feature_list.h"
 #include "ios/web/common/features.h"
 #import "ios/web/navigation/navigation_item_impl.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/test/http_server/http_server.h"
 #include "ios/web/public/test/http_server/http_server_util.h"
 #import "ios/web/public/test/web_view_interaction_test_util.h"
diff --git a/ios/web/navigation/legacy_navigation_manager_impl.h b/ios/web/navigation/legacy_navigation_manager_impl.h
index 584fe97..3f42d5e 100644
--- a/ios/web/navigation/legacy_navigation_manager_impl.h
+++ b/ios/web/navigation/legacy_navigation_manager_impl.h
@@ -13,7 +13,7 @@
 #include "base/macros.h"
 #import "ios/web/navigation/navigation_manager_impl.h"
 #import "ios/web/public/deprecated/navigation_item_list.h"
-#include "ios/web/public/reload_type.h"
+#include "ios/web/public/navigation/reload_type.h"
 #include "ui/base/page_transition_types.h"
 #include "url/gurl.h"
 
diff --git a/ios/web/navigation/legacy_navigation_manager_impl.mm b/ios/web/navigation/legacy_navigation_manager_impl.mm
index 04283181..4c28603a 100644
--- a/ios/web/navigation/legacy_navigation_manager_impl.mm
+++ b/ios/web/navigation/legacy_navigation_manager_impl.mm
@@ -15,8 +15,8 @@
 #import "ios/web/navigation/navigation_item_impl.h"
 #import "ios/web/navigation/navigation_item_impl_list.h"
 #import "ios/web/navigation/navigation_manager_delegate.h"
-#import "ios/web/public/navigation_item.h"
-#include "ios/web/public/reload_type.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#include "ios/web/public/navigation/reload_type.h"
 #import "ios/web/public/web_client.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "ui/base/page_transition_types.h"
diff --git a/ios/web/navigation/navigation_context_impl.h b/ios/web/navigation/navigation_context_impl.h
index 059b443..a59d5b2 100644
--- a/ios/web/navigation/navigation_context_impl.h
+++ b/ios/web/navigation/navigation_context_impl.h
@@ -11,7 +11,7 @@
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#import "ios/web/public/web_state/navigation_context.h"
+#import "ios/web/public/navigation/navigation_context.h"
 #include "url/gurl.h"
 
 namespace web {
diff --git a/ios/web/navigation/navigation_item_impl.h b/ios/web/navigation/navigation_item_impl.h
index 5565a94b..87e7103 100644
--- a/ios/web/navigation/navigation_item_impl.h
+++ b/ios/web/navigation/navigation_item_impl.h
@@ -12,8 +12,8 @@
 #include "base/strings/string16.h"
 #include "ios/web/navigation/error_retry_state_machine.h"
 #include "ios/web/public/favicon/favicon_status.h"
-#import "ios/web/public/navigation_item.h"
-#include "ios/web/public/referrer.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#include "ios/web/public/navigation/referrer.h"
 #include "ios/web/public/security/ssl_status.h"
 #include "url/gurl.h"
 
diff --git a/ios/web/navigation/navigation_manager_impl.h b/ios/web/navigation/navigation_manager_impl.h
index 55fd847..2e95d36c 100644
--- a/ios/web/navigation/navigation_manager_impl.h
+++ b/ios/web/navigation/navigation_manager_impl.h
@@ -14,8 +14,8 @@
 #include "base/macros.h"
 #import "ios/web/navigation/navigation_item_impl.h"
 #import "ios/web/public/deprecated/navigation_item_list.h"
-#import "ios/web/public/navigation_manager.h"
-#include "ios/web/public/reload_type.h"
+#import "ios/web/public/navigation/navigation_manager.h"
+#include "ios/web/public/navigation/reload_type.h"
 #include "ui/base/page_transition_types.h"
 #include "url/gurl.h"
 
diff --git a/ios/web/navigation/navigation_manager_impl_unittest.mm b/ios/web/navigation/navigation_manager_impl_unittest.mm
index c2126f8..e5b0dce 100644
--- a/ios/web/navigation/navigation_manager_impl_unittest.mm
+++ b/ios/web/navigation/navigation_manager_impl_unittest.mm
@@ -19,7 +19,7 @@
 #import "ios/web/navigation/navigation_manager_delegate.h"
 #import "ios/web/navigation/wk_based_navigation_manager_impl.h"
 #import "ios/web/navigation/wk_navigation_util.h"
-#include "ios/web/public/navigation_item.h"
+#include "ios/web/public/navigation/navigation_item.h"
 #include "ios/web/public/test/fakes/test_browser_state.h"
 #import "ios/web/public/test/fakes/test_navigation_manager.h"
 #import "ios/web/public/web_client.h"
diff --git a/ios/web/navigation/navigation_manager_util_unittest.mm b/ios/web/navigation/navigation_manager_util_unittest.mm
index 88c9004..78c866b 100644
--- a/ios/web/navigation/navigation_manager_util_unittest.mm
+++ b/ios/web/navigation/navigation_manager_util_unittest.mm
@@ -12,7 +12,7 @@
 #import "ios/web/navigation/legacy_navigation_manager_impl.h"
 #import "ios/web/navigation/navigation_context_impl.h"
 #import "ios/web/navigation/wk_based_navigation_manager_impl.h"
-#import "ios/web/public/navigation_item.h"
+#import "ios/web/public/navigation/navigation_item.h"
 #include "ios/web/public/test/fakes/test_browser_state.h"
 #import "ios/web/test/fakes/crw_fake_back_forward_list.h"
 #import "ios/web/test/fakes/fake_navigation_manager_delegate.h"
diff --git a/ios/web/navigation/window_location_inttest.mm b/ios/web/navigation/window_location_inttest.mm
index 0ff409a0d..713133f 100644
--- a/ios/web/navigation/window_location_inttest.mm
+++ b/ios/web/navigation/window_location_inttest.mm
@@ -6,8 +6,8 @@
 #include "base/memory/ptr_util.h"
 #import "base/strings/sys_string_conversions.h"
 #import "base/test/ios/wait_util.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/test/http_server/http_server.h"
 #include "ios/web/public/test/http_server/http_server_util.h"
 #import "ios/web/public/test/web_view_interaction_test_util.h"
diff --git a/ios/web/navigation/wk_back_forward_list_item_holder.mm b/ios/web/navigation/wk_back_forward_list_item_holder.mm
index b072b665..73fe21e6 100644
--- a/ios/web/navigation/wk_back_forward_list_item_holder.mm
+++ b/ios/web/navigation/wk_back_forward_list_item_holder.mm
@@ -5,7 +5,7 @@
 #import "ios/web/navigation/wk_back_forward_list_item_holder.h"
 
 #include "base/memory/ptr_util.h"
-#import "ios/web/public/navigation_item.h"
+#import "ios/web/public/navigation/navigation_item.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/web/navigation/wk_back_forward_list_item_holder_unittest.mm b/ios/web/navigation/wk_back_forward_list_item_holder_unittest.mm
index 848b0884..7f33548d 100644
--- a/ios/web/navigation/wk_back_forward_list_item_holder_unittest.mm
+++ b/ios/web/navigation/wk_back_forward_list_item_holder_unittest.mm
@@ -7,7 +7,7 @@
 #import <WebKit/WebKit.h>
 
 #import "ios/web/navigation/navigation_item_impl.h"
-#import "ios/web/public/navigation_item.h"
+#import "ios/web/public/navigation/navigation_item.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
 #include "testing/platform_test.h"
diff --git a/ios/web/navigation/wk_based_navigation_manager_impl.h b/ios/web/navigation/wk_based_navigation_manager_impl.h
index 31631ad..3340cb61 100644
--- a/ios/web/navigation/wk_based_navigation_manager_impl.h
+++ b/ios/web/navigation/wk_based_navigation_manager_impl.h
@@ -15,7 +15,7 @@
 #import "ios/web/navigation/navigation_item_impl.h"
 #import "ios/web/navigation/navigation_manager_impl.h"
 #include "ios/web/navigation/time_smoother.h"
-#include "ios/web/public/reload_type.h"
+#include "ios/web/public/navigation/reload_type.h"
 #include "ui/base/page_transition_types.h"
 #include "url/gurl.h"
 
diff --git a/ios/web/navigation/wk_based_navigation_manager_impl.mm b/ios/web/navigation/wk_based_navigation_manager_impl.mm
index e413044..8e2281b 100644
--- a/ios/web/navigation/wk_based_navigation_manager_impl.mm
+++ b/ios/web/navigation/wk_based_navigation_manager_impl.mm
@@ -23,7 +23,7 @@
 #include "ios/web/navigation/navigation_item_impl_list.h"
 #import "ios/web/navigation/navigation_manager_delegate.h"
 #import "ios/web/navigation/wk_navigation_util.h"
-#import "ios/web/public/navigation_item.h"
+#import "ios/web/public/navigation/navigation_item.h"
 #import "ios/web/public/web_client.h"
 #import "ios/web/public/web_state/web_state.h"
 #import "ios/web/web_state/ui/crw_web_view_navigation_proxy.h"
diff --git a/ios/web/navigation/wk_based_navigation_manager_impl_unittest.mm b/ios/web/navigation/wk_based_navigation_manager_impl_unittest.mm
index 88bd281..f7032e4 100644
--- a/ios/web/navigation/wk_based_navigation_manager_impl_unittest.mm
+++ b/ios/web/navigation/wk_based_navigation_manager_impl_unittest.mm
@@ -15,8 +15,8 @@
 #import "ios/web/navigation/navigation_manager_delegate.h"
 #import "ios/web/navigation/navigation_manager_impl.h"
 #import "ios/web/navigation/wk_navigation_util.h"
-#include "ios/web/public/navigation_item.h"
-#include "ios/web/public/reload_type.h"
+#include "ios/web/public/navigation/navigation_item.h"
+#include "ios/web/public/navigation/reload_type.h"
 #include "ios/web/public/test/fakes/test_browser_state.h"
 #import "ios/web/public/web_client.h"
 #import "ios/web/test/fakes/crw_fake_back_forward_list.h"
diff --git a/ios/web/navigation/wk_navigation_util.mm b/ios/web/navigation/wk_navigation_util.mm
index 56a03d1a..7ed21f320 100644
--- a/ios/web/navigation/wk_navigation_util.mm
+++ b/ios/web/navigation/wk_navigation_util.mm
@@ -10,7 +10,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/values.h"
 #include "ios/web/common/features.h"
-#import "ios/web/public/navigation_item.h"
+#import "ios/web/public/navigation/navigation_item.h"
 #import "ios/web/public/web_client.h"
 #include "net/base/escape.h"
 #include "net/base/url_util.h"
diff --git a/ios/web/public/BUILD.gn b/ios/web/public/BUILD.gn
index d007125..d5f228e8 100644
--- a/ios/web/public/BUILD.gn
+++ b/ios/web/public/BUILD.gn
@@ -6,10 +6,11 @@
 
 source_set("public") {
   public_deps = [
-    ":referrer",
+    ":ui",
     ":user_agent",
     ":web_state_types",
     "//ios/web/public/favicon",
+    "//ios/web/public/navigation",
     "//ios/web/public/thread",
     "//net",
     "//services/network/public/cpp",
@@ -25,20 +26,13 @@
 
   sources = [
     "browser_state.h",
-    "browser_url_rewriter.h",
     "java_script_dialog_callback.h",
     "java_script_dialog_presenter.h",
     "java_script_dialog_type.h",
-    "navigation_item.h",
-    "navigation_manager.h",
-    "reload_type.h",
     "service_manager_connection.h",
     "url_scheme_util.h",
-    "url_schemes.h",
     "url_schemes.mm",
     "web_client.h",
-    "web_state/navigation_context.h",
-    "web_state/page_display_state.h",
     "web_state/page_display_state.mm",
     "web_state/ui/crw_web_view_proxy.h",
     "web_state/ui/crw_web_view_scroll_view_proxy.h",
@@ -48,8 +42,6 @@
     "web_state/web_state_interface_provider.cc",
     "web_state/web_state_interface_provider.h",
     "web_state/web_state_observer_bridge.h",
-    "web_state/web_state_policy_decider.h",
-    "web_state/web_state_policy_decider_bridge.h",
     "web_state/web_state_user_data.h",
   ]
 
@@ -62,8 +54,8 @@
 # deprecated.
 source_set("web_state_types") {
   deps = [
-    ":referrer",
     "//base",
+    "//ios/web/public/navigation",
     "//url",
   ]
   sources = [
@@ -88,14 +80,9 @@
   configs += [ "//build/config/compiler:enable_arc" ]
 }
 
-source_set("referrer") {
-  deps = [
-    "//base",
-    "//url",
-  ]
-
+source_set("ui") {
   sources = [
-    "referrer.h",
+    "web_state/page_display_state.h",
   ]
 
   configs += [ "//build/config/compiler:enable_arc" ]
diff --git a/ios/web/public/deprecated/BUILD.gn b/ios/web/public/deprecated/BUILD.gn
index 331ccfc..92c1e362 100644
--- a/ios/web/public/deprecated/BUILD.gn
+++ b/ios/web/public/deprecated/BUILD.gn
@@ -21,8 +21,6 @@
     "crw_native_content_holder.h",
     "crw_native_content_provider.h",
     "global_web_state_observer.h",
-    "navigation_item_list.h",
-    "navigation_item_list.mm",
     "url_verification_constants.h",
   ]
 }
@@ -44,6 +42,15 @@
   ]
 }
 
+source_set("deprecated_navigation_util") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+
+  sources = [
+    "navigation_item_list.h",
+    "navigation_item_list.mm",
+  ]
+}
+
 source_set("test_doubles") {
   configs += [ "//build/config/compiler:enable_arc" ]
 
diff --git a/ios/web/public/navigation/BUILD.gn b/ios/web/public/navigation/BUILD.gn
new file mode 100644
index 0000000..573e931
--- /dev/null
+++ b/ios/web/public/navigation/BUILD.gn
@@ -0,0 +1,27 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("navigation") {
+  deps = [
+    "//ios/web/public:ui",
+    "//ios/web/public:user_agent",
+    "//ios/web/public/deprecated:deprecated_navigation_util",
+    "//ui/base",
+    "//url",
+  ]
+
+  sources = [
+    "browser_url_rewriter.h",
+    "navigation_context.h",
+    "navigation_item.h",
+    "navigation_manager.h",
+    "referrer.h",
+    "reload_type.h",
+    "url_schemes.h",
+    "web_state_policy_decider.h",
+    "web_state_policy_decider_bridge.h",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+}
diff --git a/ios/web/public/navigation/README.md b/ios/web/public/navigation/README.md
new file mode 100644
index 0000000..7a247d9f
--- /dev/null
+++ b/ios/web/public/navigation/README.md
@@ -0,0 +1 @@
+This directory contains API to perform web content navigation (load URLs, go back/forward) and inspect navigation state.
diff --git a/ios/web/public/browser_url_rewriter.h b/ios/web/public/navigation/browser_url_rewriter.h
similarity index 90%
rename from ios/web/public/browser_url_rewriter.h
rename to ios/web/public/navigation/browser_url_rewriter.h
index dd90d1d1..755f418 100644
--- a/ios/web/public/browser_url_rewriter.h
+++ b/ios/web/public/navigation/browser_url_rewriter.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_WEB_PUBLIC_BROWSER_URL_REWRITER_H_
-#define IOS_WEB_PUBLIC_BROWSER_URL_REWRITER_H_
+#ifndef IOS_WEB_PUBLIC_NAVIGATION_BROWSER_URL_REWRITER_H_
+#define IOS_WEB_PUBLIC_NAVIGATION_BROWSER_URL_REWRITER_H_
 
 #include <vector>
 
@@ -49,4 +49,4 @@
 
 }  // namespace web
 
-#endif  // IOS_WEB_PUBLIC_BROWSER_URL_REWRITER_H_
+#endif  // IOS_WEB_PUBLIC_NAVIGATION_BROWSER_URL_REWRITER_H_
diff --git a/ios/web/public/web_state/navigation_context.h b/ios/web/public/navigation/navigation_context.h
similarity index 95%
rename from ios/web/public/web_state/navigation_context.h
rename to ios/web/public/navigation/navigation_context.h
index 29c3455..b935513 100644
--- a/ios/web/public/web_state/navigation_context.h
+++ b/ios/web/public/navigation/navigation_context.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_WEB_PUBLIC_WEB_STATE_NAVIGATION_CONTEXT_H_
-#define IOS_WEB_PUBLIC_WEB_STATE_NAVIGATION_CONTEXT_H_
+#ifndef IOS_WEB_PUBLIC_NAVIGATION_NAVIGATION_CONTEXT_H_
+#define IOS_WEB_PUBLIC_NAVIGATION_NAVIGATION_CONTEXT_H_
 
 #import <Foundation/Foundation.h>
 
@@ -97,4 +97,4 @@
 
 }  // namespace web
 
-#endif  // IOS_WEB_PUBLIC_WEB_STATE_NAVIGATION_CONTEXT_H_
+#endif  // IOS_WEB_PUBLIC_NAVIGATION_NAVIGATION_CONTEXT_H_
diff --git a/ios/web/public/navigation_item.h b/ios/web/public/navigation/navigation_item.h
similarity index 96%
rename from ios/web/public/navigation_item.h
rename to ios/web/public/navigation/navigation_item.h
index 76c1c20..682ed3b1 100644
--- a/ios/web/public/navigation_item.h
+++ b/ios/web/public/navigation/navigation_item.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_WEB_PUBLIC_NAVIGATION_ITEM_H_
-#define IOS_WEB_PUBLIC_NAVIGATION_ITEM_H_
+#ifndef IOS_WEB_PUBLIC_NAVIGATION_NAVIGATION_ITEM_H_
+#define IOS_WEB_PUBLIC_NAVIGATION_NAVIGATION_ITEM_H_
 
 #include <memory>
 
@@ -127,4 +127,4 @@
 
 }  // namespace web
 
-#endif  // IOS_WEB_PUBLIC_NAVIGATION_ITEM_H_
+#endif  // IOS_WEB_PUBLIC_NAVIGATION_NAVIGATION_ITEM_H_
diff --git a/ios/web/public/navigation_manager.h b/ios/web/public/navigation/navigation_manager.h
similarity index 96%
rename from ios/web/public/navigation_manager.h
rename to ios/web/public/navigation/navigation_manager.h
index c43ab9b..f04bba6b 100644
--- a/ios/web/public/navigation_manager.h
+++ b/ios/web/public/navigation/navigation_manager.h
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_WEB_PUBLIC_NAVIGATION_MANAGER_H_
-#define IOS_WEB_PUBLIC_NAVIGATION_MANAGER_H_
+#ifndef IOS_WEB_PUBLIC_NAVIGATION_NAVIGATION_MANAGER_H_
+#define IOS_WEB_PUBLIC_NAVIGATION_NAVIGATION_MANAGER_H_
 
 #include <stddef.h>
 
 #include "base/callback.h"
-#include "ios/web/public/browser_url_rewriter.h"
 #include "ios/web/public/deprecated/navigation_item_list.h"
-#include "ios/web/public/referrer.h"
-#include "ios/web/public/reload_type.h"
+#include "ios/web/public/navigation/browser_url_rewriter.h"
+#include "ios/web/public/navigation/referrer.h"
+#include "ios/web/public/navigation/reload_type.h"
 #include "ios/web/public/user_agent.h"
 #include "ui/base/page_transition_types.h"
 
@@ -230,4 +230,4 @@
 
 }  // namespace web
 
-#endif  // IOS_WEB_PUBLIC_NAVIGATION_MANAGER_H_
+#endif  // IOS_WEB_PUBLIC_NAVIGATION_NAVIGATION_MANAGER_H_
diff --git a/ios/web/public/referrer.h b/ios/web/public/navigation/referrer.h
similarity index 87%
rename from ios/web/public/referrer.h
rename to ios/web/public/navigation/referrer.h
index 93833a4..63904ba 100644
--- a/ios/web/public/referrer.h
+++ b/ios/web/public/navigation/referrer.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_WEB_PUBLIC_REFERRER_H_
-#define IOS_WEB_PUBLIC_REFERRER_H_
+#ifndef IOS_WEB_PUBLIC_NAVIGATION_REFERRER_H_
+#define IOS_WEB_PUBLIC_NAVIGATION_REFERRER_H_
 
 #include "base/logging.h"
 #include "url/gurl.h"
@@ -36,4 +36,4 @@
 
 }  // namespace web
 
-#endif  // IOS_WEB_PUBLIC_REFERRER_H_
+#endif  // IOS_WEB_PUBLIC_NAVIGATION_REFERRER_H_
diff --git a/ios/web/public/reload_type.h b/ios/web/public/navigation/reload_type.h
similarity index 81%
rename from ios/web/public/reload_type.h
rename to ios/web/public/navigation/reload_type.h
index 0158c07..242df9d 100644
--- a/ios/web/public/reload_type.h
+++ b/ios/web/public/navigation/reload_type.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_WEB_PUBLIC_RELOAD_TYPE_H_
-#define IOS_WEB_PUBLIC_RELOAD_TYPE_H_
+#ifndef IOS_WEB_PUBLIC_NAVIGATION_RELOAD_TYPE_H_
+#define IOS_WEB_PUBLIC_NAVIGATION_RELOAD_TYPE_H_
 
 namespace web {
 
@@ -21,4 +21,4 @@
 
 }  // namespace web
 
-#endif  // IOS_WEB_PUBLIC_RELOAD_TYPE_H_
+#endif  // IOS_WEB_PUBLIC_NAVIGATION_RELOAD_TYPE_H_
diff --git a/ios/web/public/url_schemes.h b/ios/web/public/navigation/url_schemes.h
similarity index 84%
rename from ios/web/public/url_schemes.h
rename to ios/web/public/navigation/url_schemes.h
index 0253069..1c09251a 100644
--- a/ios/web/public/url_schemes.h
+++ b/ios/web/public/navigation/url_schemes.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_WEB_PUBLIC_URL_SCHEMES_H_
-#define IOS_WEB_PUBLIC_URL_SCHEMES_H_
+#ifndef IOS_WEB_PUBLIC_NAVIGATION_URL_SCHEMES_H_
+#define IOS_WEB_PUBLIC_NAVIGATION_URL_SCHEMES_H_
 
 namespace web {
 
@@ -22,4 +22,4 @@
 
 }  // namespace web
 
-#endif  // IOS_WEB_PUBLIC_URL_SCHEMES_H_
+#endif  // IOS_WEB_PUBLIC_NAVIGATION_URL_SCHEMES_H_
diff --git a/ios/web/public/web_state/web_state_policy_decider.h b/ios/web/public/navigation/web_state_policy_decider.h
similarity index 93%
rename from ios/web/public/web_state/web_state_policy_decider.h
rename to ios/web/public/navigation/web_state_policy_decider.h
index e560327..4cbac694 100644
--- a/ios/web/public/web_state/web_state_policy_decider.h
+++ b/ios/web/public/navigation/web_state_policy_decider.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_WEB_PUBLIC_WEB_STATE_WEB_STATE_POLICY_DECIDER_H_
-#define IOS_WEB_PUBLIC_WEB_STATE_WEB_STATE_POLICY_DECIDER_H_
+#ifndef IOS_WEB_PUBLIC_NAVIGATION_WEB_STATE_POLICY_DECIDER_H_
+#define IOS_WEB_PUBLIC_NAVIGATION_WEB_STATE_POLICY_DECIDER_H_
 
 #import <Foundation/Foundation.h>
 
@@ -85,6 +85,6 @@
 
   DISALLOW_COPY_AND_ASSIGN(WebStatePolicyDecider);
 };
-}
+}  // namespace web
 
-#endif  // IOS_WEB_PUBLIC_WEB_STATE_WEB_STATE_POLICY_DECIDER_H_
+#endif  // IOS_WEB_PUBLIC_NAVIGATION_WEB_STATE_POLICY_DECIDER_H_
diff --git a/ios/web/public/web_state/web_state_policy_decider_bridge.h b/ios/web/public/navigation/web_state_policy_decider_bridge.h
similarity index 82%
rename from ios/web/public/web_state/web_state_policy_decider_bridge.h
rename to ios/web/public/navigation/web_state_policy_decider_bridge.h
index c61d5d4..bb1e042 100644
--- a/ios/web/public/web_state/web_state_policy_decider_bridge.h
+++ b/ios/web/public/navigation/web_state_policy_decider_bridge.h
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_WEB_PUBLIC_WEB_STATE_WEB_STATE_POLICY_DECIDER_BRIDGE_H_
-#define IOS_WEB_PUBLIC_WEB_STATE_WEB_STATE_POLICY_DECIDER_BRIDGE_H_
+#ifndef IOS_WEB_PUBLIC_NAVIGATION_WEB_STATE_POLICY_DECIDER_BRIDGE_H_
+#define IOS_WEB_PUBLIC_NAVIGATION_WEB_STATE_POLICY_DECIDER_BRIDGE_H_
 
 #import <Foundation/Foundation.h>
 
-#import "ios/web/public/web_state/web_state_policy_decider.h"
+#import "ios/web/public/navigation/web_state_policy_decider.h"
 
 // Objective-C interface for web::WebStatePolicyDecider.
-@protocol CRWWebStatePolicyDecider<NSObject>
+@protocol CRWWebStatePolicyDecider <NSObject>
 @optional
 
 // Invoked by |WebStatePolicyDeciderBridge::ShouldAllowRequest|.
@@ -49,4 +49,4 @@
 
 }  // web
 
-#endif  // IOS_WEB_PUBLIC_WEB_STATE_WEB_STATE_POLICY_DECIDER_BRIDGE_H_
+#endif  // IOS_WEB_PUBLIC_NAVIGATION_WEB_STATE_POLICY_DECIDER_BRIDGE_H_
diff --git a/ios/web/public/session/BUILD.gn b/ios/web/public/session/BUILD.gn
index 83d5b47..3b6e050 100644
--- a/ios/web/public/session/BUILD.gn
+++ b/ios/web/public/session/BUILD.gn
@@ -7,8 +7,8 @@
   deps = [
     "//base",
     "//ios/web/public",
-    "//ios/web/public:referrer",
     "//ios/web/public:user_agent",
+    "//ios/web/public/navigation",
     "//net",
     "//url",
   ]
diff --git a/ios/web/public/session/crw_navigation_item_storage.h b/ios/web/public/session/crw_navigation_item_storage.h
index a004354..4a11a08 100644
--- a/ios/web/public/session/crw_navigation_item_storage.h
+++ b/ios/web/public/session/crw_navigation_item_storage.h
@@ -10,7 +10,7 @@
 
 #include "base/strings/string16.h"
 #include "base/time/time.h"
-#include "ios/web/public/referrer.h"
+#include "ios/web/public/navigation/referrer.h"
 #include "ios/web/public/user_agent.h"
 #import "ios/web/public/web_state/page_display_state.h"
 #include "url/gurl.h"
diff --git a/ios/web/public/test/fakes/BUILD.gn b/ios/web/public/test/fakes/BUILD.gn
index d7a52cfb..56538eba 100644
--- a/ios/web/public/test/fakes/BUILD.gn
+++ b/ios/web/public/test/fakes/BUILD.gn
@@ -12,6 +12,7 @@
     "//ios/web/js_messaging",
     "//ios/web/navigation:core",
     "//ios/web/public/deprecated",
+    "//ios/web/public/deprecated:deprecated_navigation_util",
     "//ios/web/public/download",
     "//ios/web/public/find_in_page",
     "//ios/web/public/js_messaging",
diff --git a/ios/web/public/test/fakes/crw_fake_web_state_policy_decider.h b/ios/web/public/test/fakes/crw_fake_web_state_policy_decider.h
index 603da85..5fdcb32 100644
--- a/ios/web/public/test/fakes/crw_fake_web_state_policy_decider.h
+++ b/ios/web/public/test/fakes/crw_fake_web_state_policy_decider.h
@@ -5,7 +5,7 @@
 #ifndef IOS_WEB_PUBLIC_TEST_FAKES_CRW_FAKE_WEB_STATE_POLICY_DECIDER_H_
 #define IOS_WEB_PUBLIC_TEST_FAKES_CRW_FAKE_WEB_STATE_POLICY_DECIDER_H_
 
-#import "ios/web/public/web_state/web_state_policy_decider_bridge.h"
+#import "ios/web/public/navigation/web_state_policy_decider_bridge.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/web/public/test/fakes/crw_test_web_state_observer.mm b/ios/web/public/test/fakes/crw_test_web_state_observer.mm
index c753a591..12cc8dd 100644
--- a/ios/web/public/test/fakes/crw_test_web_state_observer.mm
+++ b/ios/web/public/test/fakes/crw_test_web_state_observer.mm
@@ -7,7 +7,7 @@
 #include <memory>
 
 #import "ios/web/navigation/navigation_context_impl.h"
-#import "ios/web/public/web_state/navigation_context.h"
+#import "ios/web/public/navigation/navigation_context.h"
 #include "net/http/http_response_headers.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/ios/web/public/test/fakes/fake_navigation_context.h b/ios/web/public/test/fakes/fake_navigation_context.h
index bdf183ed..4786b46 100644
--- a/ios/web/public/test/fakes/fake_navigation_context.h
+++ b/ios/web/public/test/fakes/fake_navigation_context.h
@@ -9,7 +9,7 @@
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#import "ios/web/public/web_state/navigation_context.h"
+#import "ios/web/public/navigation/navigation_context.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "url/gurl.h"
 
diff --git a/ios/web/public/test/fakes/fake_web_state_policy_decider.h b/ios/web/public/test/fakes/fake_web_state_policy_decider.h
index 33f55186..25c4125d 100644
--- a/ios/web/public/test/fakes/fake_web_state_policy_decider.h
+++ b/ios/web/public/test/fakes/fake_web_state_policy_decider.h
@@ -5,8 +5,8 @@
 #ifndef IOS_WEB_PUBLIC_TEST_FAKES_FAKE_WEB_STATE_POLICY_DECIDER_H_
 #define IOS_WEB_PUBLIC_TEST_FAKES_FAKE_WEB_STATE_POLICY_DECIDER_H_
 
+#import "ios/web/public/navigation/web_state_policy_decider.h"
 #import "ios/web/public/web_state/web_state.h"
-#import "ios/web/public/web_state/web_state_policy_decider.h"
 
 @class NSURLRequest;
 @class NSURLResponse;
diff --git a/ios/web/public/test/fakes/test_navigation_manager.h b/ios/web/public/test/fakes/test_navigation_manager.h
index 050bfaad..347fa507 100644
--- a/ios/web/public/test/fakes/test_navigation_manager.h
+++ b/ios/web/public/test/fakes/test_navigation_manager.h
@@ -7,8 +7,8 @@
 
 #include "base/callback.h"
 #include "ios/web/public/deprecated/navigation_item_list.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #include "ui/base/page_transition_types.h"
 
 namespace web {
diff --git a/ios/web/public/test/fakes/test_web_state.h b/ios/web/public/test/fakes/test_web_state.h
index 06bc74b..7c1fdc5 100644
--- a/ios/web/public/test/fakes/test_web_state.h
+++ b/ios/web/public/test/fakes/test_web_state.h
@@ -13,10 +13,10 @@
 #include "base/observer_list.h"
 #include "base/strings/string16.h"
 #include "ios/web/public/deprecated/url_verification_constants.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_manager.h"
+#import "ios/web/public/navigation/web_state_policy_decider.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "ios/web/public/web_state/web_state_observer.h"
-#import "ios/web/public/web_state/web_state_policy_decider.h"
 #include "url/gurl.h"
 
 @class NSURLRequest;
diff --git a/ios/web/public/test/fakes/test_web_state.mm b/ios/web/public/test/fakes/test_web_state.mm
index 349452d..3cf86a8 100644
--- a/ios/web/public/test/fakes/test_web_state.mm
+++ b/ios/web/public/test/fakes/test_web_state.mm
@@ -14,10 +14,10 @@
 #import "ios/web/common/crw_content_view.h"
 #include "ios/web/js_messaging/web_frames_manager_impl.h"
 #include "ios/web/public/js_messaging/web_frame.h"
+#import "ios/web/public/navigation/web_state_policy_decider.h"
 #import "ios/web/public/session/crw_navigation_item_storage.h"
 #import "ios/web/public/session/crw_session_storage.h"
 #import "ios/web/public/session/serializable_user_data_manager.h"
-#import "ios/web/public/web_state/web_state_policy_decider.h"
 #include "ui/gfx/image/image.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/web/public/test/fakes/test_web_state_observer.mm b/ios/web/public/test/fakes/test_web_state_observer.mm
index 6fd8479..4402c57 100644
--- a/ios/web/public/test/fakes/test_web_state_observer.mm
+++ b/ios/web/public/test/fakes/test_web_state_observer.mm
@@ -7,10 +7,10 @@
 #include <memory>
 
 #include "ios/web/navigation/navigation_context_impl.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_context.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #include "ios/web/public/security/ssl_status.h"
-#import "ios/web/public/web_state/navigation_context.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "net/http/http_response_headers.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/ios/web/public/test/fakes/test_web_state_observer_util.mm b/ios/web/public/test/fakes/test_web_state_observer_util.mm
index 9942694..857b7b7 100644
--- a/ios/web/public/test/fakes/test_web_state_observer_util.mm
+++ b/ios/web/public/test/fakes/test_web_state_observer_util.mm
@@ -4,8 +4,8 @@
 
 #import "ios/web/public/test/fakes/test_web_state_observer_util.h"
 
+#import "ios/web/public/navigation/navigation_context.h"
 #include "ios/web/public/security/ssl_status.h"
-#import "ios/web/public/web_state/navigation_context.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/web/public/test/navigation_test_util.mm b/ios/web/public/test/navigation_test_util.mm
index 13944fc..953672b4 100644
--- a/ios/web/public/test/navigation_test_util.mm
+++ b/ios/web/public/test/navigation_test_util.mm
@@ -5,7 +5,7 @@
 #import "ios/web/public/test/navigation_test_util.h"
 
 #import "base/test/ios/wait_util.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/web_state/web_state.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/web/public/test/test_redirect_observer.mm b/ios/web/public/test/test_redirect_observer.mm
index be770e7..71a0707 100644
--- a/ios/web/public/test/test_redirect_observer.mm
+++ b/ios/web/public/test/test_redirect_observer.mm
@@ -4,9 +4,9 @@
 
 #include "ios/web/public/test/test_redirect_observer.h"
 
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
-#include "ios/web/public/web_state/navigation_context.h"
+#include "ios/web/public/navigation/navigation_context.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/web_state/web_state.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/web/public/url_schemes.mm b/ios/web/public/url_schemes.mm
index 163ec48..e2dbcf0 100644
--- a/ios/web/public/url_schemes.mm
+++ b/ios/web/public/url_schemes.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ios/web/public/url_schemes.h"
+#include "ios/web/public/navigation/url_schemes.h"
 
 #include <algorithm>
 #include <vector>
diff --git a/ios/web/public/web_state/context_menu_params.h b/ios/web/public/web_state/context_menu_params.h
index 79e6e59..48c40ef 100644
--- a/ios/web/public/web_state/context_menu_params.h
+++ b/ios/web/public/web_state/context_menu_params.h
@@ -7,7 +7,7 @@
 #import <UIKit/UIKit.h>
 
 #include "base/strings/string16.h"
-#include "ios/web/public/referrer.h"
+#include "ios/web/public/navigation/referrer.h"
 #include "url/gurl.h"
 
 namespace web {
diff --git a/ios/web/public/web_state/web_state.h b/ios/web/public/web_state/web_state.h
index 7af6554..f6641ea 100644
--- a/ios/web/public/web_state/web_state.h
+++ b/ios/web/public/web_state/web_state.h
@@ -16,7 +16,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/supports_user_data.h"
 #include "ios/web/public/deprecated/url_verification_constants.h"
-#include "ios/web/public/referrer.h"
+#include "ios/web/public/navigation/referrer.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
 #include "mojo/public/cpp/system/message_pipe.h"
 #include "ui/base/page_transition_types.h"
diff --git a/ios/web/security/crw_ssl_status_updater_unittest.mm b/ios/web/security/crw_ssl_status_updater_unittest.mm
index 825e87c..3c5528c 100644
--- a/ios/web/security/crw_ssl_status_updater_unittest.mm
+++ b/ios/web/security/crw_ssl_status_updater_unittest.mm
@@ -11,7 +11,7 @@
 #import "ios/web/navigation/crw_session_controller.h"
 #import "ios/web/navigation/legacy_navigation_manager_impl.h"
 #import "ios/web/navigation/navigation_manager_impl.h"
-#import "ios/web/public/navigation_item.h"
+#import "ios/web/public/navigation/navigation_item.h"
 #include "ios/web/public/security/ssl_status.h"
 #include "ios/web/public/test/web_test.h"
 #import "ios/web/security/wk_web_view_security_util.h"
diff --git a/ios/web/security/web_interstitial_impl.mm b/ios/web/security/web_interstitial_impl.mm
index e8ad3ce9..2f517f6 100644
--- a/ios/web/security/web_interstitial_impl.mm
+++ b/ios/web/security/web_interstitial_impl.mm
@@ -11,8 +11,8 @@
 #import "ios/web/common/crw_web_view_content_view.h"
 #import "ios/web/common/web_view_creation_util.h"
 #import "ios/web/navigation/navigation_manager_impl.h"
-#import "ios/web/public/navigation_manager.h"
-#include "ios/web/public/reload_type.h"
+#import "ios/web/public/navigation/navigation_manager.h"
+#include "ios/web/public/navigation/reload_type.h"
 #import "ios/web/public/security/web_interstitial_delegate.h"
 #import "ios/web/web_state/web_state_impl.h"
 #import "net/base/mac/url_conversions.h"
diff --git a/ios/web/shell/view_controller.mm b/ios/web/shell/view_controller.mm
index 199128f..58828f1 100644
--- a/ios/web/shell/view_controller.mm
+++ b/ios/web/shell/view_controller.mm
@@ -12,8 +12,8 @@
 #include <utility>
 
 #include "base/strings/sys_string_conversions.h"
-#import "ios/web/public/navigation_manager.h"
-#include "ios/web/public/referrer.h"
+#import "ios/web/public/navigation/navigation_manager.h"
+#include "ios/web/public/navigation/referrer.h"
 #import "ios/web/public/web_state/context_menu_params.h"
 #import "ios/web/public/web_state/web_state.h"
 #import "ios/web/public/web_state/web_state_delegate_bridge.h"
diff --git a/ios/web/test/web_int_test.h b/ios/web/test/web_int_test.h
index c85bf668..1112ab7 100644
--- a/ios/web/test/web_int_test.h
+++ b/ios/web/test/web_int_test.h
@@ -10,7 +10,7 @@
 #include "base/compiler_specific.h"
 #import "base/ios/block_types.h"
 #include "base/macros.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/test/fakes/test_web_state_delegate.h"
 #include "ios/web/public/test/web_test.h"
 #import "ios/web/public/web_state/web_state.h"
diff --git a/ios/web/test/web_test_suite.mm b/ios/web/test/web_test_suite.mm
index f27819e..74a51d6 100644
--- a/ios/web/test/web_test_suite.mm
+++ b/ios/web/test/web_test_suite.mm
@@ -6,8 +6,8 @@
 
 #include "base/memory/ptr_util.h"
 #include "base/path_service.h"
+#include "ios/web/public/navigation/url_schemes.h"
 #import "ios/web/public/test/fakes/test_web_client.h"
-#include "ios/web/public/url_schemes.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/resource/resource_bundle.h"
 
diff --git a/ios/web/web_state/bad_ssl_response_inttest.mm b/ios/web/web_state/bad_ssl_response_inttest.mm
index 44ed69c44..78cd015 100644
--- a/ios/web/web_state/bad_ssl_response_inttest.mm
+++ b/ios/web/web_state/bad_ssl_response_inttest.mm
@@ -6,7 +6,7 @@
 #import "base/test/ios/wait_util.h"
 #include "base/test/scoped_feature_list.h"
 #include "ios/web/common/features.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #include "ios/web/public/security/certificate_policy_cache.h"
 #import "ios/web/public/session/crw_session_certificate_policy_cache_storage.h"
 #import "ios/web/public/session/crw_session_storage.h"
diff --git a/ios/web/web_state/error_page_inttest.mm b/ios/web/web_state/error_page_inttest.mm
index b174c0e..3391663 100644
--- a/ios/web/web_state/error_page_inttest.mm
+++ b/ios/web/web_state/error_page_inttest.mm
@@ -11,9 +11,9 @@
 #include "base/test/scoped_feature_list.h"
 #include "ios/testing/embedded_test_server_handlers.h"
 #include "ios/web/common/features.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
-#include "ios/web/public/reload_type.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
+#include "ios/web/public/navigation/reload_type.h"
 #include "ios/web/public/security/security_style.h"
 #include "ios/web/public/security/ssl_status.h"
 #include "ios/web/public/test/element_selector.h"
diff --git a/ios/web/web_state/ui/controller/crw_legacy_native_content_controller.mm b/ios/web/web_state/ui/controller/crw_legacy_native_content_controller.mm
index bec50847..ea64074 100644
--- a/ios/web/web_state/ui/controller/crw_legacy_native_content_controller.mm
+++ b/ios/web/web_state/ui/controller/crw_legacy_native_content_controller.mm
@@ -10,7 +10,7 @@
 #import "ios/web/navigation/navigation_item_impl.h"
 #import "ios/web/public/deprecated/crw_native_content.h"
 #import "ios/web/public/deprecated/crw_native_content_provider.h"
-#import "ios/web/public/navigation_item.h"
+#import "ios/web/public/navigation/navigation_item.h"
 #import "ios/web/public/web_client.h"
 #import "ios/web/web_state/ui/controller/crw_legacy_native_content_controller_delegate.h"
 #import "ios/web/web_state/web_state_impl.h"
diff --git a/ios/web/web_state/ui/controller/crw_legacy_native_content_controller_delegate.h b/ios/web/web_state/ui/controller/crw_legacy_native_content_controller_delegate.h
index 30a54a2d..5456a8e 100644
--- a/ios/web/web_state/ui/controller/crw_legacy_native_content_controller_delegate.h
+++ b/ios/web/web_state/ui/controller/crw_legacy_native_content_controller_delegate.h
@@ -5,7 +5,7 @@
 #ifndef IOS_WEB_WEB_STATE_UI_CONTROLLER_CRW_LEGACY_NATIVE_CONTENT_CONTROLLER_DELEGATE_H_
 #define IOS_WEB_WEB_STATE_UI_CONTROLLER_CRW_LEGACY_NATIVE_CONTENT_CONTROLLER_DELEGATE_H_
 
-#include "ios/web/public/referrer.h"
+#include "ios/web/public/navigation/referrer.h"
 #include "ui/base/page_transition_types.h"
 
 namespace web {
diff --git a/ios/web/web_state/ui/crw_context_menu_controller.mm b/ios/web/web_state/ui/crw_context_menu_controller.mm
index e4b0abb..370752d 100644
--- a/ios/web/web_state/ui/crw_context_menu_controller.mm
+++ b/ios/web/web_state/ui/crw_context_menu_controller.mm
@@ -15,8 +15,8 @@
 #include "base/unguessable_token.h"
 #import "ios/web/js_messaging/crw_wk_script_message_router.h"
 #import "ios/web/public/deprecated/crw_context_menu_delegate.h"
+#import "ios/web/public/navigation/navigation_context.h"
 #import "ios/web/public/web_state/context_menu_params.h"
-#import "ios/web/public/web_state/navigation_context.h"
 #import "ios/web/public/web_state/web_state.h"
 #import "ios/web/public/web_state/web_state_observer_bridge.h"
 #import "ios/web/web_state/context_menu_constants.h"
diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm
index ba168f50..15cc5187 100644
--- a/ios/web/web_state/ui/crw_web_controller_unittest.mm
+++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm
@@ -35,7 +35,7 @@
 #include "ios/web/public/deprecated/url_verification_constants.h"
 #import "ios/web/public/download/download_controller.h"
 #import "ios/web/public/download/download_task.h"
-#include "ios/web/public/referrer.h"
+#include "ios/web/public/navigation/referrer.h"
 #import "ios/web/public/session/crw_navigation_item_storage.h"
 #import "ios/web/public/session/crw_session_storage.h"
 #include "ios/web/public/test/fakes/fake_download_controller_delegate.h"
diff --git a/ios/web/web_state/ui/crw_web_request_controller.h b/ios/web/web_state/ui/crw_web_request_controller.h
index 48c1b9b..8d09224 100644
--- a/ios/web/web_state/ui/crw_web_request_controller.h
+++ b/ios/web/web_state/ui/crw_web_request_controller.h
@@ -7,7 +7,7 @@
 
 #import <WebKit/WebKit.h>
 
-#include "ios/web/public/referrer.h"
+#include "ios/web/public/navigation/referrer.h"
 #include "ui/base/page_transition_types.h"
 #include "url/gurl.h"
 
diff --git a/ios/web/web_state/web_state_impl.h b/ios/web/web_state/web_state_impl.h
index b4967efd..38cdbddc 100644
--- a/ios/web/web_state/web_state_impl.h
+++ b/ios/web/web_state/web_state_impl.h
@@ -24,9 +24,9 @@
 #import "ios/web/public/java_script_dialog_callback.h"
 #include "ios/web/public/java_script_dialog_type.h"
 #include "ios/web/public/js_messaging/web_frame.h"
+#import "ios/web/public/navigation/web_state_policy_decider.h"
 #import "ios/web/public/web_state/web_state.h"
 #import "ios/web/public/web_state/web_state_delegate.h"
-#import "ios/web/public/web_state/web_state_policy_decider.h"
 #include "url/gurl.h"
 
 @class CRWSessionStorage;
diff --git a/ios/web/web_state/web_state_impl.mm b/ios/web/web_state/web_state_impl.mm
index 4b76ca53..4829b7b 100644
--- a/ios/web/web_state/web_state_impl.mm
+++ b/ios/web/web_state/web_state_impl.mm
@@ -28,7 +28,8 @@
 #import "ios/web/public/deprecated/crw_native_content_holder.h"
 #include "ios/web/public/favicon/favicon_url.h"
 #import "ios/web/public/java_script_dialog_presenter.h"
-#import "ios/web/public/navigation_item.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/web_state_policy_decider.h"
 #import "ios/web/public/session/crw_navigation_item_storage.h"
 #import "ios/web/public/session/crw_session_storage.h"
 #import "ios/web/public/session/serializable_user_data_manager.h"
@@ -38,7 +39,6 @@
 #import "ios/web/public/web_state/web_state_delegate.h"
 #include "ios/web/public/web_state/web_state_interface_provider.h"
 #include "ios/web/public/web_state/web_state_observer.h"
-#import "ios/web/public/web_state/web_state_policy_decider.h"
 #include "ios/web/public/webui/web_ui_ios_controller.h"
 #import "ios/web/security/web_interstitial_impl.h"
 #import "ios/web/session/session_certificate_policy_cache_impl.h"
diff --git a/ios/web/web_state/web_state_impl_unittest.mm b/ios/web/web_state/web_state_impl_unittest.mm
index 5573b35e..fd2e04d 100644
--- a/ios/web/web_state/web_state_impl_unittest.mm
+++ b/ios/web/web_state/web_state_impl_unittest.mm
@@ -24,6 +24,7 @@
 #import "ios/web/navigation/wk_navigation_util.h"
 #include "ios/web/public/deprecated/global_web_state_observer.h"
 #import "ios/web/public/java_script_dialog_presenter.h"
+#import "ios/web/public/navigation/web_state_policy_decider.h"
 #import "ios/web/public/session/crw_navigation_item_storage.h"
 #import "ios/web/public/session/crw_session_storage.h"
 #import "ios/web/public/session/serializable_user_data_manager.h"
@@ -37,7 +38,6 @@
 #import "ios/web/public/web_state/context_menu_params.h"
 #import "ios/web/public/web_state/web_state_delegate.h"
 #include "ios/web/public/web_state/web_state_observer.h"
-#import "ios/web/public/web_state/web_state_policy_decider.h"
 #import "ios/web/security/web_interstitial_impl.h"
 #import "ios/web/test/fakes/mock_interstitial_delegate.h"
 #include "ios/web/web_state/global_web_state_event_tracker.h"
diff --git a/ios/web/web_state/web_state_observer_inttest.mm b/ios/web/web_state/web_state_observer_inttest.mm
index 5c04b95..4c5ce18 100644
--- a/ios/web/web_state/web_state_observer_inttest.mm
+++ b/ios/web/web_state/web_state_observer_inttest.mm
@@ -22,8 +22,10 @@
 #import "ios/web/public/deprecated/crw_native_content_holder.h"
 #import "ios/web/public/deprecated/test_native_content.h"
 #import "ios/web/public/deprecated/test_native_content_provider.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_context.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
+#import "ios/web/public/navigation/web_state_policy_decider.h"
 #import "ios/web/public/session/crw_navigation_item_storage.h"
 #import "ios/web/public/session/crw_session_storage.h"
 #include "ios/web/public/test/fakes/test_web_state_observer.h"
@@ -31,9 +33,7 @@
 #import "ios/web/public/test/web_view_content_test_util.h"
 #import "ios/web/public/test/web_view_interaction_test_util.h"
 #import "ios/web/public/web_client.h"
-#import "ios/web/public/web_state/navigation_context.h"
 #include "ios/web/public/web_state/web_state_observer.h"
-#import "ios/web/public/web_state/web_state_policy_decider.h"
 #include "ios/web/test/test_url_constants.h"
 #import "ios/web/test/web_int_test.h"
 #import "ios/web/web_state/ui/crw_web_controller.h"
diff --git a/ios/web/web_state/web_state_policy_decider.mm b/ios/web/web_state/web_state_policy_decider.mm
index 412bac05..3c84c0c2 100644
--- a/ios/web/web_state/web_state_policy_decider.mm
+++ b/ios/web/web_state/web_state_policy_decider.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ios/web/public/web_state/web_state_policy_decider.h"
+#import "ios/web/public/navigation/web_state_policy_decider.h"
 
 #import "ios/web/public/web_state/web_state.h"
 #import "ios/web/web_state/web_state_impl.h"
diff --git a/ios/web/web_state/web_state_policy_decider_bridge.mm b/ios/web/web_state/web_state_policy_decider_bridge.mm
index 25605993..4ac1e33 100644
--- a/ios/web/web_state/web_state_policy_decider_bridge.mm
+++ b/ios/web/web_state/web_state_policy_decider_bridge.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ios/web/public/web_state/web_state_policy_decider_bridge.h"
+#import "ios/web/public/navigation/web_state_policy_decider_bridge.h"
 
 #import "ios/web/public/web_state/web_state.h"
 
diff --git a/ios/web/web_state/web_state_policy_decider_bridge_unittest.mm b/ios/web/web_state/web_state_policy_decider_bridge_unittest.mm
index 4a00fa3..faaa88b 100644
--- a/ios/web/web_state/web_state_policy_decider_bridge_unittest.mm
+++ b/ios/web/web_state/web_state_policy_decider_bridge_unittest.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ios/web/public/web_state/web_state_policy_decider_bridge.h"
+#import "ios/web/public/navigation/web_state_policy_decider_bridge.h"
 
 #import "ios/web/public/test/fakes/crw_fake_web_state_policy_decider.h"
 #import "ios/web/public/test/fakes/test_web_state.h"
diff --git a/ios/web/web_state/web_state_unittest.mm b/ios/web/web_state/web_state_unittest.mm
index 042ba1a..ff61f6b 100644
--- a/ios/web/web_state/web_state_unittest.mm
+++ b/ios/web/web_state/web_state_unittest.mm
@@ -19,8 +19,8 @@
 #import "ios/web/navigation/wk_based_navigation_manager_impl.h"
 #import "ios/web/navigation/wk_navigation_util.h"
 #include "ios/web/public/js_messaging/web_frame.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/session/crw_navigation_item_storage.h"
 #import "ios/web/public/session/crw_session_storage.h"
 #import "ios/web/public/test/fakes/test_web_client.h"
diff --git a/ios/web/webui/web_ui_mojo_inttest.mm b/ios/web/webui/web_ui_mojo_inttest.mm
index f2c9f15..e64ae51 100644
--- a/ios/web/webui/web_ui_mojo_inttest.mm
+++ b/ios/web/webui/web_ui_mojo_inttest.mm
@@ -9,7 +9,7 @@
 #import "base/test/ios/wait_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "ios/web/grit/ios_web_resources.h"
-#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/test/navigation_test_util.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "ios/web/public/web_state/web_state_interface_provider.h"
diff --git a/ios/web_view/internal/cwv_web_view.mm b/ios/web_view/internal/cwv_web_view.mm
index 6c4e9b2..55426b18 100644
--- a/ios/web_view/internal/cwv_web_view.mm
+++ b/ios/web_view/internal/cwv_web_view.mm
@@ -21,13 +21,13 @@
 #include "ios/web/public/favicon/favicon_url.h"
 #include "ios/web/public/js_messaging/web_frame.h"
 #import "ios/web/public/js_messaging/web_frames_manager.h"
-#import "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
-#include "ios/web/public/referrer.h"
-#include "ios/web/public/reload_type.h"
+#import "ios/web/public/navigation/navigation_context.h"
+#import "ios/web/public/navigation/navigation_item.h"
+#import "ios/web/public/navigation/navigation_manager.h"
+#include "ios/web/public/navigation/referrer.h"
+#include "ios/web/public/navigation/reload_type.h"
 #import "ios/web/public/web_client.h"
 #import "ios/web/public/web_state/context_menu_params.h"
-#import "ios/web/public/web_state/navigation_context.h"
 #import "ios/web/public/web_state/ui/crw_web_view_proxy.h"
 #import "ios/web/public/web_state/ui/crw_web_view_scroll_view_proxy.h"
 #import "ios/web/public/web_state/web_state.h"
diff --git a/ios/web_view/internal/web_view_web_state_policy_decider.h b/ios/web_view/internal/web_view_web_state_policy_decider.h
index 3b8e9b5..8ba60a4 100644
--- a/ios/web_view/internal/web_view_web_state_policy_decider.h
+++ b/ios/web_view/internal/web_view_web_state_policy_decider.h
@@ -7,7 +7,7 @@
 
 #import <Foundation/Foundation.h>
 
-#import "ios/web/public/web_state/web_state_policy_decider.h"
+#import "ios/web/public/navigation/web_state_policy_decider.h"
 
 namespace web {
 class WebState;
diff --git a/media/gpu/v4l2/v4l2_device.cc b/media/gpu/v4l2/v4l2_device.cc
index cd5d5e1..8269030 100644
--- a/media/gpu/v4l2/v4l2_device.cc
+++ b/media/gpu/v4l2/v4l2_device.cc
@@ -1177,9 +1177,6 @@
     case V4L2_PIX_FMT_RGB32:
       return DRM_FORMAT_ARGB8888;
 
-    case V4L2_PIX_FMT_MT21C:
-      return DRM_FORMAT_MT21;
-
     default:
       DVLOGF(1) << "Unrecognized format " << FourccToString(format);
       return 0;
diff --git a/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc b/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
index fc233e5..070a5dc3 100644
--- a/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
@@ -262,6 +262,29 @@
     return false;
   }
 
+  struct v4l2_requestbuffers reqbufs;
+  memset(&reqbufs, 0, sizeof(reqbufs));
+  reqbufs.count = 0;
+  reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+  reqbufs.memory = V4L2_MEMORY_MMAP;
+  IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs);
+  if (reqbufs.capabilities & V4L2_BUF_CAP_SUPPORTS_REQUESTS) {
+    supports_requests_ = true;
+    VLOGF(1) << "Using request API";
+    DCHECK(!media_fd_.is_valid());
+    // Let's try to open the media device
+    // TODO(crbug.com/985230): remove this hardcoding, replace with V4L2Device
+    // integration.
+    int media_fd = open("/dev/media-dec0", O_RDWR, 0);
+    if (media_fd < 0) {
+      VPLOGF(1) << "Failed to open media device: ";
+      NOTIFY_ERROR(PLATFORM_FAILURE);
+    }
+    media_fd_ = base::ScopedFD(media_fd);
+  } else {
+    VLOGF(1) << "Using config store";
+  }
+
   if (video_profile_ >= H264PROFILE_MIN && video_profile_ <= H264PROFILE_MAX) {
     decoder_.reset(new H264Decoder(
         std::make_unique<V4L2H264Accelerator>(this, device_.get())));
@@ -370,6 +393,8 @@
   DestroyInputBuffers();
   DestroyOutputs(false);
 
+  media_fd_.reset();
+
   base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
       this);
 
@@ -465,26 +490,6 @@
     return false;
   }
 
-  // Open media device if we are discovering that we support requests.
-  supports_requests_ =
-      static_cast<bool>(reqbufs.capabilities & V4L2_BUF_CAP_SUPPORTS_REQUESTS);
-  if (supports_requests_) {
-    VLOGF(2) << "Using request API";
-    DCHECK(!media_fd_.is_valid());
-    // Let's try to open the media device
-    // TODO(crbug.com/985230): remove this hardcoding, replace with V4L2Device
-    // integration.
-    int media_fd = open("/dev/media-dec0", O_RDWR, 0);
-    if (media_fd < 0) {
-      VPLOGF(1) << "Failed to open media device: ";
-      NOTIFY_ERROR(PLATFORM_FAILURE);
-    }
-    media_fd_ = base::ScopedFD(media_fd);
-
-  } else {
-    VLOGF(2) << "Using config store";
-  }
-
   input_buffer_map_.resize(reqbufs.count);
   for (size_t i = 0; i < input_buffer_map_.size(); ++i) {
     free_input_buffers_.push_back(i);
@@ -617,8 +622,6 @@
 
   input_buffer_map_.clear();
   free_input_buffers_.clear();
-
-  media_fd_.reset();
 }
 
 void V4L2SliceVideoDecodeAccelerator::DismissPictures(
diff --git a/media/renderers/paint_canvas_video_renderer.cc b/media/renderers/paint_canvas_video_renderer.cc
index 2a290b9..9ca3c31f 100644
--- a/media/renderers/paint_canvas_video_renderer.cc
+++ b/media/renderers/paint_canvas_video_renderer.cc
@@ -159,22 +159,6 @@
                           &yuv_textures_info[i].minFilter);
     gl->GetTexParameteriv(mailbox_holder.texture_target, GL_TEXTURE_MAG_FILTER,
                           &yuv_textures_info[i].magFilter);
-    // TODO(dcastagna): avoid this copy once Skia supports native textures
-    // with a GL_TEXTURE_RECTANGLE_ARB texture target.
-    // crbug.com/505026
-    if (mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB) {
-      unsigned texture_copy = 0;
-      gl->GenTextures(1, &texture_copy);
-      DCHECK(texture_copy);
-      gl->BindTexture(GL_TEXTURE_2D, texture_copy);
-      gl->CopyTextureCHROMIUM(yuv_textures_info[i].texture.fID, 0,
-                              GL_TEXTURE_2D, texture_copy, 0, GL_RGB,
-                              GL_UNSIGNED_BYTE, false, true, false);
-
-      gl->DeleteTextures(1, &yuv_textures_info[i].texture.fID);
-      yuv_textures_info[i].texture.fID = texture_copy;
-      yuv_textures_info[i].texture.fTarget = GL_TEXTURE_2D;
-    }
   }
 
   return yuv_textures_info;
@@ -288,8 +272,7 @@
 sk_sp<SkImage> NewSkImageFromVideoFrameNative(
     VideoFrame* video_frame,
     viz::ContextProvider* context_provider,
-    bool allow_wrap_texture,
-    bool* wrapped_video_frame_texture) {
+    bool wrap_texture) {
   DCHECK(PIXEL_FORMAT_ARGB == video_frame->format() ||
          PIXEL_FORMAT_XRGB == video_frame->format() ||
          PIXEL_FORMAT_RGB24 == video_frame->format() ||
@@ -311,18 +294,12 @@
       gl->CreateAndConsumeTextureCHROMIUM(mailbox_holder.mailbox.name);
   unsigned source_texture = 0;
   gfx::ColorSpace color_space_for_skia;
-  *wrapped_video_frame_texture =
-      mailbox_holder.texture_target == GL_TEXTURE_2D && allow_wrap_texture;
-  if (*wrapped_video_frame_texture) {
+  if (wrap_texture) {
     // Fast path where we can avoid a copy, by having last_image_ directly wrap
     // the VideoFrame texture.
     source_texture = frame_texture;
     color_space_for_skia = video_frame->ColorSpace();
   } else {
-    // TODO(dcastagna): At the moment Skia doesn't support targets different
-    // than GL_TEXTURE_2D.  Avoid this copy once
-    // https://code.google.com/p/skia/issues/detail?id=3868 is addressed, when
-    // we allow wrapping.
     gl->GenTextures(1, &source_texture);
     DCHECK(source_texture);
     gl->BindTexture(GL_TEXTURE_2D, source_texture);
@@ -1526,8 +1503,8 @@
             video_frame.get(), context_provider);
       } else {
         cache_->source_image = NewSkImageFromVideoFrameNative(
-            video_frame.get(), context_provider, allow_wrap_texture,
-            &cache_->wraps_video_frame_texture);
+            video_frame.get(), context_provider, allow_wrap_texture);
+        cache_->wraps_video_frame_texture = allow_wrap_texture;
       }
       if (!cache_->source_image) {
         // Couldn't create the SkImage.
diff --git a/pdf/draw_utils/coordinates.cc b/pdf/draw_utils/coordinates.cc
index e9673b75..f18bb56 100644
--- a/pdf/draw_utils/coordinates.cc
+++ b/pdf/draw_utils/coordinates.cc
@@ -22,7 +22,6 @@
     size_t num_of_pages,
     const PageInsetSizes& single_view_insets,
     int horizontal_separator) {
-  DCHECK_GE(page_index, 0u);
   DCHECK_LT(page_index, num_of_pages);
 
   // Don't change |two_up_insets| if the page is on the left side and is the
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index 1225d9e..b636d6b 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -87,6 +87,8 @@
     kPageShadowLeft, kPageShadowTop, kPageShadowRight, kPageShadowBottom};
 
 constexpr int32_t kBottomSeparator = 4;
+constexpr int32_t kHorizontalSeparator = 1;
+
 constexpr int32_t kHighlightColorR = 153;
 constexpr int32_t kHighlightColorG = 193;
 constexpr int32_t kHighlightColorB = 218;
@@ -2332,8 +2334,7 @@
 
 pp::Rect PDFiumEngine::GetPageRect(int index) {
   pp::Rect rc(pages_[index]->rect());
-  rc.Inset(-kPageShadowLeft, -kPageShadowTop, -kPageShadowRight,
-           -kPageShadowBottom);
+  InsetPage(index, pages_.size(), /*multiplier=*/-1, &rc);
   return rc;
 }
 
@@ -2637,8 +2638,7 @@
     }
 
     pp::Size size = page_available ? GetPageSize(i) : default_page_size_;
-    size.Enlarge(kPageShadowLeft + kPageShadowRight,
-                 kPageShadowTop + kPageShadowBottom);
+    EnlargePage(i, new_page_count, &size);
     pp::Rect rect(pp::Point(0, document_size_.height()), size);
     page_rects.push_back(rect);
 
@@ -2648,8 +2648,7 @@
   for (size_t i = 0; i < new_page_count; ++i) {
     // Center pages relative to the entire document.
     page_rects[i].set_x((document_size_.width() - page_rects[i].width()) / 2);
-    page_rects[i].Inset(kPageShadowLeft, kPageShadowTop, kPageShadowRight,
-                        kPageShadowBottom);
+    InsetPage(i, new_page_count, /*multiplier=*/1, &page_rects[i]);
     AppendPageRectToPages(page_rects[i], i, reload);
   }
 
@@ -2834,6 +2833,39 @@
   return size;
 }
 
+void PDFiumEngine::EnlargePage(size_t page_index,
+                               size_t num_of_pages,
+                               pp::Size* page_size) {
+  DCHECK_LT(page_index, num_of_pages);
+
+  draw_utils::PageInsetSizes inset_sizes = kSingleViewInsets;
+  if (two_up_view_) {
+    inset_sizes = draw_utils::GetPageInsetsForTwoUpView(
+        page_index, num_of_pages, kSingleViewInsets, kHorizontalSeparator);
+  }
+
+  page_size->Enlarge(inset_sizes.left + inset_sizes.right,
+                     inset_sizes.top + inset_sizes.bottom);
+}
+
+void PDFiumEngine::InsetPage(size_t page_index,
+                             size_t num_of_pages,
+                             double multiplier,
+                             pp::Rect* rect) {
+  DCHECK_LT(page_index, num_of_pages);
+
+  draw_utils::PageInsetSizes inset_sizes = kSingleViewInsets;
+  if (two_up_view_) {
+    inset_sizes = draw_utils::GetPageInsetsForTwoUpView(
+        page_index, num_of_pages, kSingleViewInsets, kHorizontalSeparator);
+  }
+
+  rect->Inset(static_cast<int>(ceil(inset_sizes.left * multiplier)),
+              static_cast<int>(ceil(inset_sizes.top * multiplier)),
+              static_cast<int>(ceil(inset_sizes.right * multiplier)),
+              static_cast<int>(ceil(inset_sizes.bottom * multiplier)));
+}
+
 int PDFiumEngine::StartPaint(int page_index, const pp::Rect& dirty) {
   // For the first time we hit paint, do nothing and just record the paint for
   // the next callback.  This keeps the UI responsive in case the user is doing
@@ -2972,8 +3004,7 @@
       progressive_paints_[progressive_index].rect();
   pp::Rect page_rect = pages_[page_index]->rect();
   pp::Rect shadow_rect(page_rect);
-  shadow_rect.Inset(-kPageShadowLeft, -kPageShadowTop, -kPageShadowRight,
-                    -kPageShadowBottom);
+  InsetPage(page_index, pages_.size(), /*multiplier=*/-1, &shadow_rect);
 
   // Due to the rounding errors of the GetScreenRect it is possible to get
   // different size shadows on the left and right sides even they are defined
@@ -2981,11 +3012,8 @@
   // it by the size of the shadows.
   shadow_rect = GetScreenRect(shadow_rect);
   page_rect = shadow_rect;
-
-  page_rect.Inset(static_cast<int>(ceil(kPageShadowLeft * current_zoom_)),
-                  static_cast<int>(ceil(kPageShadowTop * current_zoom_)),
-                  static_cast<int>(ceil(kPageShadowRight * current_zoom_)),
-                  static_cast<int>(ceil(kPageShadowBottom * current_zoom_)));
+  InsetPage(page_index, pages_.size(), /*multiplier=*/current_zoom_,
+            &page_rect);
 
   DrawPageShadow(page_rect, shadow_rect, dirty_in_screen, image_data);
 }
diff --git a/pdf/pdfium/pdfium_engine.h b/pdf/pdfium/pdfium_engine.h
index acfdcacf..e1b7ac9 100644
--- a/pdf/pdfium/pdfium_engine.h
+++ b/pdf/pdfium/pdfium_engine.h
@@ -267,6 +267,19 @@
   // PDFiumPage because we might not have that structure when we need this.
   pp::Size GetPageSize(int index);
 
+  // If |two_up_view_| is false, enlarges |page_size| with inset sizes for
+  // single-view. If |two_up_view_| is true, gets the appropriate two-up view
+  // inset sizes for the position of the page (dependent on |page_index| and
+  // |num_of_pages|) and then enlarges |page_size|.
+  void EnlargePage(size_t page_index, size_t num_of_pages, pp::Size* page_size);
+
+  // Similar to EnlargePage(), but insets a |rect|. Also multiplies the inset
+  // sizes by |multiplier|, using the ceiling of the result.
+  void InsetPage(size_t page_index,
+                 size_t num_of_pages,
+                 double multiplier,
+                 pp::Rect* rect);
+
   void GetAllScreenRectsUnion(const std::vector<PDFiumRange>& rect_range,
                               const pp::Point& offset_point,
                               std::vector<pp::Rect>* rect_vector) const;
@@ -523,6 +536,10 @@
   // The indexes of the pages pending download.
   std::vector<int> pending_pages_;
 
+  // True if loading pages in two-up view layout. False if loading pages in
+  // single view layout.
+  bool two_up_view_ = false;
+
   // During handling of input events we don't want to unload any pages in
   // callbacks to us from PDFium, since the current page can change while PDFium
   // code still has a pointer to it.
diff --git a/remoting/protocol/ice_config.h b/remoting/protocol/ice_config.h
index f2b4169..b2a3037 100644
--- a/remoting/protocol/ice_config.h
+++ b/remoting/protocol/ice_config.h
@@ -44,10 +44,6 @@
 
   std::vector<rtc::SocketAddress> stun_servers;
 
-  // Legacy GTURN relay servers.
-  std::vector<std::string> relay_servers;
-  std::string relay_token;
-
   // Standard TURN servers
   std::vector<cricket::RelayServerConfig> turn_servers;
 
diff --git a/remoting/protocol/port_allocator.cc b/remoting/protocol/port_allocator.cc
index b4d818e8..0243e6f 100644
--- a/remoting/protocol/port_allocator.cc
+++ b/remoting/protocol/port_allocator.cc
@@ -10,35 +10,9 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/logging.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
-#include "net/base/escape.h"
-#include "net/http/http_status_code.h"
-#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "remoting/protocol/network_settings.h"
 #include "remoting/protocol/transport_context.h"
 
-namespace {
-
-typedef std::map<std::string, std::string> StringMap;
-
-// Parses the lines in the result of the HTTP request that are of the form
-// 'a=b' and returns them in a map.
-StringMap ParseMap(const std::string& string) {
-  StringMap map;
-  base::StringPairs pairs;
-  base::SplitStringIntoKeyValuePairs(string, '=', '\n', &pairs);
-
-  for (auto& pair : pairs) {
-    map[pair.first] = pair.second;
-  }
-  return map;
-}
-
-const int kNumRetries = 5;
-
-}  // namespace
-
 namespace remoting {
 namespace protocol {
 
@@ -110,11 +84,6 @@
 void PortAllocatorSession::OnIceConfig(const IceConfig& ice_config) {
   ice_config_ = ice_config;
   ConfigReady(GetPortConfiguration().release());
-
-  if (relay_enabled() && !ice_config_.relay_servers.empty() &&
-      !ice_config_.relay_token.empty()) {
-    TryCreateRelaySession();
-  }
 }
 
 std::unique_ptr<cricket::PortConfiguration>
@@ -136,109 +105,5 @@
   return config;
 }
 
-void PortAllocatorSession::TryCreateRelaySession() {
-  DCHECK(!ice_config_.relay_servers.empty());
-  DCHECK(!ice_config_.relay_token.empty());
-
-  if (attempts_ == kNumRetries) {
-    LOG(ERROR) << "PortAllocator: maximum number of requests reached; "
-               << "giving up on relay.";
-    return;
-  }
-
-  // Choose the next host to try.
-  std::string host =
-      ice_config_.relay_servers[attempts_ % ice_config_.relay_servers.size()];
-  attempts_++;
-
-  DCHECK(!username().empty());
-  DCHECK(!password().empty());
-  std::string url = "https://" + host + "/create_session?username=" +
-                    net::EscapeUrlEncodedData(username(), false) +
-                    "&password=" +
-                    net::EscapeUrlEncodedData(password(), false) + "&sn=1";
-  net::NetworkTrafficAnnotationTag traffic_annotation =
-      net::DefineNetworkTrafficAnnotation("CRD_relay_session_request", R"(
-        semantics {
-          sender: "Chrome Remote Desktop"
-          description:
-            "Request is sent by Chrome Remote Desktop to allocate relay "
-            "session. Returned relay session credentials are used over UDP to "
-            "connect to Google-owned relay servers, which is required for NAT "
-            "traversal."
-          trigger:
-            "Start of each Chrome Remote Desktop and during connection when "
-            "peer-to-peer transport needs to be reconnected."
-          data:
-            "A temporary authentication token issued by Google services (over "
-            "XMPP connection)."
-          destination: GOOGLE_OWNED_SERVICE
-        }
-        policy {
-          cookies_allowed: NO
-          setting:
-            "This feature cannot be disabled by settings. You can block Chrome "
-            "Remote Desktop as specified here: "
-            "https://support.google.com/chrome/?p=remote_desktop"
-          chrome_policy {
-            RemoteAccessHostFirewallTraversal {
-              policy_options {mode: MANDATORY}
-              RemoteAccessHostFirewallTraversal: false
-            }
-          }
-        }
-        comments:
-          "Above specified policy is only applicable on the host side and "
-          "doesn't have effect in Android and iOS client apps. The product "
-          "is shipped separately from Chromium, except on Chrome OS."
-        )");
-  std::unique_ptr<UrlRequest> url_request =
-      transport_context_->url_request_factory()->CreateUrlRequest(
-          UrlRequest::Type::GET, url, traffic_annotation);
-  url_request->AddHeader("X-Talk-Google-Relay-Auth: " +
-                         ice_config_.relay_token);
-  url_request->AddHeader("X-Google-Relay-Auth: " + ice_config_.relay_token);
-  url_request->AddHeader("X-Stream-Type: chromoting");
-  url_request->Start(base::Bind(&PortAllocatorSession::OnSessionRequestResult,
-                                base::Unretained(this)));
-  url_requests_.insert(std::move(url_request));
-}
-
-void PortAllocatorSession::OnSessionRequestResult(
-    const UrlRequest::Result& result) {
-  if (!result.success || result.status != net::HTTP_OK) {
-    LOG(WARNING) << "Received error when allocating relay session: "
-                 << result.status;
-    TryCreateRelaySession();
-    return;
-  }
-
-  StringMap map = ParseMap(result.response_body);
-
-  if (!username().empty() && map["username"] != username()) {
-    LOG(WARNING) << "Received unexpected username value from relay server.";
-  }
-  if (!password().empty() && map["password"] != password()) {
-    LOG(WARNING) << "Received unexpected password value from relay server.";
-  }
-
-  std::unique_ptr<cricket::PortConfiguration> config = GetPortConfiguration();
-
-  std::string relay_ip = map["relay.ip"];
-  std::string relay_port = map["relay.udp_port"];
-  unsigned relay_port_int;
-
-  if (!relay_ip.empty() && !relay_port.empty() &&
-      base::StringToUint(relay_port, &relay_port_int)) {
-    cricket::RelayServerConfig relay_config(cricket::RELAY_GTURN);
-    rtc::SocketAddress address(relay_ip, relay_port_int);
-    relay_config.ports.push_back(
-        cricket::ProtocolAddress(address, cricket::PROTO_UDP));
-    config->AddRelay(relay_config);
-  }
-
-  ConfigReady(config.release());
-}
-
 }  // namespace protocol
 }  // namespace remoting
diff --git a/remoting/protocol/port_allocator.h b/remoting/protocol/port_allocator.h
index ca4b9ea..7059ebb2 100644
--- a/remoting/protocol/port_allocator.h
+++ b/remoting/protocol/port_allocator.h
@@ -9,7 +9,6 @@
 #include <vector>
 
 #include "base/memory/weak_ptr.h"
-#include "remoting/base/url_request.h"
 #include "remoting/protocol/ice_config.h"
 #include "remoting/protocol/transport_context.h"
 #include "third_party/webrtc/p2p/client/basic_port_allocator.h"
@@ -60,24 +59,14 @@
   // Callback for TransportContext::GetIceConfig().
   void OnIceConfig(const IceConfig& ice_config);
 
-  // Creates PortConfiguration that inclues STUN and TURN servers from
+  // Creates PortConfiguration that includes STUN and TURN servers from
   // |ice_config_|.
   std::unique_ptr<cricket::PortConfiguration> GetPortConfiguration();
 
-  // Attempts to allocate relay session.
-  void TryCreateRelaySession();
-
-  // Result handler for UrlRequest objects in |url_requests_|.
-  void OnSessionRequestResult(const UrlRequest::Result& result);
-
   scoped_refptr<TransportContext> transport_context_;
 
   IceConfig ice_config_;
 
-  int attempts_ = 0;
-
-  std::set<std::unique_ptr<UrlRequest>> url_requests_;
-
   base::WeakPtrFactory<PortAllocatorSession> weak_factory_;
 };
 
diff --git a/sandbox/win/BUILD.gn b/sandbox/win/BUILD.gn
index 2acc1c9a..63864dc 100644
--- a/sandbox/win/BUILD.gn
+++ b/sandbox/win/BUILD.gn
@@ -118,6 +118,12 @@
     "src/sharedmem_ipc_server.h",
     "src/sid.cc",
     "src/sid.h",
+    "src/signed_dispatcher.cc",
+    "src/signed_dispatcher.h",
+    "src/signed_interception.cc",
+    "src/signed_interception.h",
+    "src/signed_policy.cc",
+    "src/signed_policy.h",
     "src/sync_dispatcher.cc",
     "src/sync_dispatcher.h",
     "src/sync_interception.cc",
diff --git a/sandbox/win/fuzzer/fuzzer_types.h b/sandbox/win/fuzzer/fuzzer_types.h
index 8ff06d0d..a3d56fa45 100644
--- a/sandbox/win/fuzzer/fuzzer_types.h
+++ b/sandbox/win/fuzzer/fuzzer_types.h
@@ -6,6 +6,7 @@
 #define SANDBOX_FUZZER_TYPES_H_
 
 #include <stdint.h>
+#include <string.h>
 
 // This file defines Windows types for the sandbox_ipc_fuzzer target when
 // compiled on Linux.
@@ -35,4 +36,12 @@
 // __stdcall is used in one place. TODO(wfh): replace with WINAPI.
 #define __stdcall
 
+namespace sandbox {
+
+struct NtExports {
+  using memcpyFunction = decltype(&memcpy);
+  memcpyFunction memcpy;
+};
+
+}  // namespace sandbox
 #endif  // SANDBOX_FUZZER_TYPES_H_
diff --git a/sandbox/win/src/crosscall_client.h b/sandbox/win/src/crosscall_client.h
index 7bcfb3c..98cd65d 100644
--- a/sandbox/win/src/crosscall_client.h
+++ b/sandbox/win/src/crosscall_client.h
@@ -224,7 +224,7 @@
     // We are touching user memory, this has to be done from inside a try
     // except.
     __try {
-      memcpy(t_.Buffer(), buffer, t_.Size());
+      memcpy_wrapper(t_.Buffer(), buffer, t_.Size());
     } __except (EXCEPTION_EXECUTE_HANDLER) {
       return false;
     }
diff --git a/sandbox/win/src/crosscall_params.h b/sandbox/win/src/crosscall_params.h
index 4dccd2b..60a1bb6 100644
--- a/sandbox/win/src/crosscall_params.h
+++ b/sandbox/win/src/crosscall_params.h
@@ -20,15 +20,11 @@
 
 #include "base/macros.h"
 #include "sandbox/win/src/internal_types.h"
+#if !defined(SANDBOX_FUZZ_TARGET)
+#include "sandbox/win/src/sandbox_nt_types.h"
+#endif
 #include "sandbox/win/src/sandbox_types.h"
 
-// Increases |value| until there is no need for padding given an int64_t
-// alignment. Returns the increased value.
-inline uint32_t Align(uint32_t value) {
-  uint32_t alignment = sizeof(int64_t);
-  return ((value + alignment - 1) / alignment) * alignment;
-}
-
 // This header is part of CrossCall: the sandbox inter-process communication.
 // This header defines the basic types used both in the client IPC and in the
 // server IPC code. CrossCallParams and ActualCallParams model the input
@@ -49,6 +45,26 @@
 
 namespace sandbox {
 
+// This is the list of all imported symbols from ntdll.dll.
+SANDBOX_INTERCEPT NtExports g_nt;
+
+namespace {
+
+// Increases |value| until there is no need for padding given an int64_t
+// alignment. Returns the increased value.
+inline uint32_t Align(uint32_t value) {
+  uint32_t alignment = sizeof(int64_t);
+  return ((value + alignment - 1) / alignment) * alignment;
+}
+
+inline void* memcpy_wrapper(void* dest, const void* src, size_t count) {
+  if (g_nt.memcpy)
+    return g_nt.memcpy(dest, src, count);
+  return memcpy(dest, src, count);
+}
+
+}  // namespace
+
 // max number of extended return parameters. See CrossCallReturn
 const size_t kExtendedReturnCount = 8;
 
@@ -243,7 +259,7 @@
     // We might be touching user memory, this has to be done from inside a try
     // except.
     __try {
-      memcpy(dest, parameter_address, size);
+      memcpy_wrapper(dest, parameter_address, size);
     } __except (EXCEPTION_EXECUTE_HANDLER) {
       return false;
     }
diff --git a/sandbox/win/src/interceptors.h b/sandbox/win/src/interceptors.h
index 44b34e37..5788614 100644
--- a/sandbox/win/src/interceptors.h
+++ b/sandbox/win/src/interceptors.h
@@ -61,6 +61,8 @@
   GETOPMRANDOMNUMBER_ID,
   GETSUGGESTEDOPMPROTECTEDOUTPUTARRAYSIZE_ID,
   SETOPMSIGNINGKEYANDSEQUENCENUMBERS_ID,
+  // Signed dispatcher:
+  CREATE_SECTION_ID,
   INTERCEPTOR_MAX_ID
 };
 
diff --git a/sandbox/win/src/interceptors_64.cc b/sandbox/win/src/interceptors_64.cc
index 669d68b..0ac2671 100644
--- a/sandbox/win/src/interceptors_64.cc
+++ b/sandbox/win/src/interceptors_64.cc
@@ -13,6 +13,7 @@
 #include "sandbox/win/src/registry_interception.h"
 #include "sandbox/win/src/sandbox_nt_types.h"
 #include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/signed_interception.h"
 #include "sandbox/win/src/sync_interception.h"
 #include "sandbox/win/src/target_interceptions.h"
 
@@ -512,4 +513,19 @@
       additional_parameters);
 }
 
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtCreateSection64(PHANDLE section_handle,
+                        ACCESS_MASK desired_access,
+                        POBJECT_ATTRIBUTES object_attributes,
+                        PLARGE_INTEGER maximum_size,
+                        ULONG section_page_protection,
+                        ULONG allocation_attributes,
+                        HANDLE file_handle) {
+  NtCreateSectionFunction orig_fn =
+      reinterpret_cast<NtCreateSectionFunction>(g_originals[CREATE_SECTION_ID]);
+  return TargetNtCreateSection(
+      orig_fn, section_handle, desired_access, object_attributes, maximum_size,
+      section_page_protection, allocation_attributes, file_handle);
+}
+
 }  // namespace sandbox
diff --git a/sandbox/win/src/interceptors_64.h b/sandbox/win/src/interceptors_64.h
index 1016b7cf..f34627d 100644
--- a/sandbox/win/src/interceptors_64.h
+++ b/sandbox/win/src/interceptors_64.h
@@ -310,6 +310,19 @@
     ULONG additional_parameters_size,
     const BYTE* additional_parameters);
 
+// -----------------------------------------------------------------------
+// Interceptors handled by the signed process code.
+
+// Interception of NtCreateSection on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtCreateSection64(PHANDLE section_handle,
+                        ACCESS_MASK desired_access,
+                        POBJECT_ATTRIBUTES object_attributes,
+                        PLARGE_INTEGER maximum_size,
+                        ULONG section_page_protection,
+                        ULONG allocation_attributes,
+                        HANDLE file_handle);
+
 }  // extern "C"
 
 }  // namespace sandbox
diff --git a/sandbox/win/src/ipc_tags.h b/sandbox/win/src/ipc_tags.h
index 1c754cd..2d38cdf 100644
--- a/sandbox/win/src/ipc_tags.h
+++ b/sandbox/win/src/ipc_tags.h
@@ -44,6 +44,7 @@
   IPC_GDI_GETOPMRANDOMNUMBER_TAG,
   IPC_GDI_GETSUGGESTEDOPMPROTECTEDOUTPUTARRAYSIZE_TAG,
   IPC_GDI_SETOPMSIGNINGKEYANDSEQUENCENUMBERS_TAG,
+  IPC_NTCREATESECTION_TAG,
   IPC_LAST_TAG
 };
 
diff --git a/sandbox/win/src/nt_internals.h b/sandbox/win/src/nt_internals.h
index a786ddd..6041566 100644
--- a/sandbox/win/src/nt_internals.h
+++ b/sandbox/win/src/nt_internals.h
@@ -35,6 +35,7 @@
 #define STATUS_INVALID_IMAGE_FORMAT   ((NTSTATUS)0xC000007BL)
 #define STATUS_NO_TOKEN               ((NTSTATUS)0xC000007CL)
 #define STATUS_NOT_SUPPORTED          ((NTSTATUS)0xC00000BBL)
+#define STATUS_INVALID_IMAGE_HASH     ((NTSTATUS)0xC0000428L)
 // clang-format on
 
 #define CURRENT_PROCESS ((HANDLE)-1)
diff --git a/sandbox/win/src/process_mitigations_unittest.cc b/sandbox/win/src/process_mitigations_unittest.cc
index 270cfa1d..244068c 100644
--- a/sandbox/win/src/process_mitigations_unittest.cc
+++ b/sandbox/win/src/process_mitigations_unittest.cc
@@ -82,15 +82,24 @@
 //------------------------------------------------------------------------------
 void TestWin10MsSigned(bool expect_success,
                        bool enable_mitigation,
-                       bool use_ms_signed_binary) {
+                       bool delayed,
+                       bool use_ms_signed_binary,
+                       bool add_dll_permission,
+                       bool add_directory_permission) {
   sandbox::TestRunner runner;
   sandbox::TargetPolicy* policy = runner.GetPolicy();
 
   if (enable_mitigation) {
     // Enable the ForceMsSigned mitigation.
-    EXPECT_EQ(policy->SetDelayedProcessMitigations(
-                  sandbox::MITIGATION_FORCE_MS_SIGNED_BINS),
-              sandbox::SBOX_ALL_OK);
+    if (delayed) {
+      EXPECT_EQ(policy->SetDelayedProcessMitigations(
+                    sandbox::MITIGATION_FORCE_MS_SIGNED_BINS),
+                sandbox::SBOX_ALL_OK);
+    } else {
+      EXPECT_EQ(policy->SetProcessMitigations(
+                    sandbox::MITIGATION_FORCE_MS_SIGNED_BINS),
+                sandbox::SBOX_ALL_OK);
+    }
   }
 
   // Choose the appropriate DLL and make sure the sandbox allows access to it.
@@ -101,10 +110,25 @@
   } else {
     EXPECT_TRUE(base::PathService::Get(base::DIR_EXE, &dll_path));
     dll_path = dll_path.Append(hooking_dll::g_hook_dll_file);
+
+    if (add_dll_permission) {
+      EXPECT_EQ(sandbox::SBOX_ALL_OK,
+                policy->AddRule(sandbox::TargetPolicy::SUBSYS_SIGNED_BINARY,
+                                sandbox::TargetPolicy::SIGNED_ALLOW_LOAD,
+                                dll_path.value().c_str()));
+    }
+    if (add_directory_permission) {
+      base::FilePath exe_path;
+      EXPECT_TRUE(base::PathService::Get(base::DIR_EXE, &exe_path));
+      EXPECT_EQ(sandbox::SBOX_ALL_OK,
+                policy->AddRule(
+                    sandbox::TargetPolicy::SUBSYS_SIGNED_BINARY,
+                    sandbox::TargetPolicy::SIGNED_ALLOW_LOAD,
+                    exe_path.DirName().AppendASCII("*.dll").value().c_str()));
+    }
   }
   EXPECT_TRUE(runner.AddFsRule(sandbox::TargetPolicy::FILES_ALLOW_READONLY,
                                dll_path.value().c_str()));
-
   // Set up test string.
   base::string16 test = L"TestDllLoad \"";
   test += dll_path.value().c_str();
@@ -711,7 +735,7 @@
 
 // This test validates that setting the MITIGATION_FORCE_MS_SIGNED_BINS
 // mitigation enables the setting on a process.
-TEST(ProcessMitigationsTest, CheckWin10MsSignedPolicySuccess) {
+TEST(ProcessMitigationsTest, CheckWin10MsSignedPolicySuccessDelayed) {
   if (base::win::GetVersion() < base::win::Version::WIN10_TH2)
     return;
 
@@ -736,6 +760,41 @@
 #endif  // !defined(COMPONENT_BUILD)
 }
 
+// This test validates that setting the MITIGATION_FORCE_MS_SIGNED_BINS
+// mitigation enables the setting on a process when non-delayed.
+TEST(ProcessMitigationsTest, CheckWin10MsSignedPolicySuccess) {
+  if (base::win::GetVersion() < base::win::Version::WIN10_TH2)
+    return;
+
+  base::string16 test_command = L"CheckPolicy ";
+  test_command += std::to_wstring(TESTPOLICY_MSSIGNED);
+
+  //---------------------------------
+  // 1) Test setting post-startup.
+  // **Only test if NOT component build, otherwise component DLLs are not signed
+  //   by MS and prevent process setup.
+  // **Only test post-startup, otherwise this test executable has dependencies
+  //   on DLLs that are not signed by MS and they prevent process startup.
+  //---------------------------------
+  TestRunner runner2;
+  sandbox::TargetPolicy* policy = runner2.GetPolicy();
+
+  EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_FORCE_MS_SIGNED_BINS),
+            SBOX_ALL_OK);
+  // In a component build, the DLLs must be allowed to load.
+#if defined(COMPONENT_BUILD)
+  base::FilePath exe_path;
+  EXPECT_TRUE(base::PathService::Get(base::DIR_EXE, &exe_path));
+  // Allow all *.dll in current directory to load.
+  EXPECT_EQ(
+      sandbox::SBOX_ALL_OK,
+      policy->AddRule(sandbox::TargetPolicy::SUBSYS_SIGNED_BINARY,
+                      sandbox::TargetPolicy::SIGNED_ALLOW_LOAD,
+                      exe_path.DirName().AppendASCII("*.dll").value().c_str()));
+#endif  // defined(COMPONENT_BUILD)
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner2.RunTest(test_command.c_str()));
+}
 // This test validates that we can load an unsigned DLL if the
 // MITIGATION_FORCE_MS_SIGNED_BINS mitigation is NOT set.
 TEST(ProcessMitigationsTest, CheckWin10MsSigned_Success) {
@@ -746,7 +805,10 @@
 
   TestWin10MsSigned(true /* expect_success */,
                     false /* enable_mitigation */,
-                    false /* use_ms_signed_binary */);
+                    false /* delayed */,
+                    false /* use_ms_signed_binary */,
+                    false /* add_dll_permission */,
+                    false /* add_directory_permission */);
 }
 
 // This test validates that setting the MITIGATION_FORCE_MS_SIGNED_BINS
@@ -759,7 +821,37 @@
 
   TestWin10MsSigned(false /* expect_success */,
                     true /* enable_mitigation */,
-                    false /* use_ms_signed_binary */);
+                    true /* delayed */,
+                    false /* use_ms_signed_binary */,
+                    false /* add_dll_permission */,
+                    false /* add_directory_permission */);
+}
+
+// This test validates that setting the MITIGATION_FORCE_MS_SIGNED_BINS
+// mitigation allows the loading of an unsigned DLL if intercept in place.
+TEST(ProcessMitigationsTest, CheckWin10MsSignedWithIntercept_Success) {
+  if (base::win::GetVersion() < base::win::Version::WIN10_TH2)
+    return;
+
+  ScopedTestMutex mutex(hooking_dll::g_hooking_dll_mutex);
+
+  // Expect success; Enable mitigation; Use non MS-signed binary.
+#if defined(COMPONENT_BUILD)
+  // In a component build, add the directory to the allowed list.
+  TestWin10MsSigned(true /* expect_success */,
+                    true /* enable_mitigation */,
+                    false /* delayed */,
+                    false /* use_ms_signed_binary */,
+                    true /* add_dll_permission */,
+                    true /* add_directory_permission */);
+#else
+  TestWin10MsSigned(true /* expect_success */,
+                    true /* enable_mitigation */,
+                    false /* delayed */,
+                    false /* use_ms_signed_binary */,
+                    true /* add_dll_permission */,
+                    false /* add_directory_permission */);
+#endif  // defined(COMPONENT_BUILD)
 }
 
 // This test validates that we can load a signed Microsoft DLL if the
@@ -773,7 +865,10 @@
 
   TestWin10MsSigned(true /* expect_success */,
                     false /* enable_mitigation */,
-                    true /* use_ms_signed_binary */);
+                    false /* delayed */,
+                    true /* use_ms_signed_binary */,
+                    false /* add_dll_permission */,
+                    false /* add_directory_permission */);
 }
 
 // This test validates that setting the MITIGATION_FORCE_MS_SIGNED_BINS
@@ -786,7 +881,10 @@
 
   TestWin10MsSigned(true /* expect_success */,
                     true /* enable_mitigation */,
-                    true /* use_ms_signed_binary */);
+                    true /* delayed */,
+                    true /* use_ms_signed_binary */,
+                    false /* add_dll_permission */,
+                    false /* add_directory_permission */);
 }
 
 //------------------------------------------------------------------------------
diff --git a/sandbox/win/src/sandbox_policy.h b/sandbox/win/src/sandbox_policy.h
index 52c0db1..205e9ba 100644
--- a/sandbox/win/src/sandbox_policy.h
+++ b/sandbox/win/src/sandbox_policy.h
@@ -24,12 +24,13 @@
   // exactly like the CreateProcess API does. See the comment at the top of
   // process_thread_dispatcher.cc for more details.
   enum SubSystem {
-    SUBSYS_FILES,           // Creation and opening of files and pipes.
-    SUBSYS_NAMED_PIPES,     // Creation of named pipes.
-    SUBSYS_PROCESS,         // Creation of child processes.
-    SUBSYS_REGISTRY,        // Creation and opening of registry keys.
-    SUBSYS_SYNC,            // Creation of named sync objects.
-    SUBSYS_WIN32K_LOCKDOWN  // Win32K Lockdown related policy.
+    SUBSYS_FILES,            // Creation and opening of files and pipes.
+    SUBSYS_NAMED_PIPES,      // Creation of named pipes.
+    SUBSYS_PROCESS,          // Creation of child processes.
+    SUBSYS_REGISTRY,         // Creation and opening of registry keys.
+    SUBSYS_SYNC,             // Creation of named sync objects.
+    SUBSYS_WIN32K_LOCKDOWN,  // Win32K Lockdown related policy.
+    SUBSYS_SIGNED_BINARY     // Signed binary policy.
   };
 
   // Allowable semantics when a rule is matched.
@@ -56,9 +57,10 @@
     FAKE_USER_GDI_INIT,     // Fakes user32 and gdi32 initialization. This can
                             // be used to allow the DLLs to load and initialize
                             // even if the process cannot access that subsystem.
-    IMPLEMENT_OPM_APIS      // Implements FAKE_USER_GDI_INIT and also exposes
+    IMPLEMENT_OPM_APIS,     // Implements FAKE_USER_GDI_INIT and also exposes
                             // IPC calls to handle Output Protection Manager
                             // APIs.
+    SIGNED_ALLOW_LOAD       // Allows loading the module when CIG is enabled.
   };
 
   // Increments the reference count of this object. The reference count must
diff --git a/sandbox/win/src/sandbox_policy_base.cc b/sandbox/win/src/sandbox_policy_base.cc
index 9f2d265c..a47151d 100644
--- a/sandbox/win/src/sandbox_policy_base.cc
+++ b/sandbox/win/src/sandbox_policy_base.cc
@@ -30,6 +30,7 @@
 #include "sandbox/win/src/sandbox_policy.h"
 #include "sandbox/win/src/sandbox_utils.h"
 #include "sandbox/win/src/security_capabilities.h"
+#include "sandbox/win/src/signed_policy.h"
 #include "sandbox/win/src/sync_policy.h"
 #include "sandbox/win/src/target_process.h"
 #include "sandbox/win/src/top_level_dispatcher.h"
@@ -745,6 +746,17 @@
       }
       break;
     }
+    case SUBSYS_SIGNED_BINARY: {
+      // These rules only need to be added if the
+      // MITIGATION_FORCE_MS_SIGNED_BINS pre-startup mitigation is set.
+      if (mitigations_ & MITIGATION_FORCE_MS_SIGNED_BINS) {
+        if (!SignedPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
+          NOTREACHED();
+          return SBOX_ERROR_BAD_PARAMS;
+        }
+      }
+      break;
+    }
 
     default: { return SBOX_ERROR_UNSUPPORTED; }
   }
diff --git a/sandbox/win/src/signed_dispatcher.cc b/sandbox/win/src/signed_dispatcher.cc
new file mode 100644
index 0000000..325a81e
--- /dev/null
+++ b/sandbox/win/src/signed_dispatcher.cc
@@ -0,0 +1,66 @@
+// 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 "sandbox/win/src/signed_dispatcher.h"
+
+#include <stdint.h>
+
+#include "base/strings/string16.h"
+#include "base/strings/string_util.h"
+#include "base/win/scoped_handle.h"
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/interception.h"
+#include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/signed_interception.h"
+#include "sandbox/win/src/signed_policy.h"
+
+namespace sandbox {
+
+SignedDispatcher::SignedDispatcher(PolicyBase* policy_base)
+    : policy_base_(policy_base) {
+  static const IPCCall create_params = {
+      {IPC_NTCREATESECTION_TAG, {VOIDPTR_TYPE}},
+      reinterpret_cast<CallbackGeneric>(&SignedDispatcher::CreateSection)};
+
+  ipc_calls_.push_back(create_params);
+}
+
+bool SignedDispatcher::SetupService(InterceptionManager* manager, int service) {
+  if (service == IPC_NTCREATESECTION_TAG)
+    return INTERCEPT_NT(manager, NtCreateSection, CREATE_SECTION_ID, 32);
+  return false;
+}
+
+bool SignedDispatcher::CreateSection(IPCInfo* ipc, HANDLE file_handle) {
+  // Duplicate input handle from target to broker.
+  HANDLE local_file_handle = nullptr;
+  if (!::DuplicateHandle((*ipc->client_info).process, file_handle,
+                         ::GetCurrentProcess(), &local_file_handle,
+                         FILE_MAP_EXECUTE, false, 0)) {
+    return false;
+  }
+
+  base::win::ScopedHandle local_handle(local_file_handle);
+  base::string16 path;
+  if (!GetPathFromHandle(local_handle.Get(), &path))
+    return false;
+  const wchar_t* module_name = path.c_str();
+  CountedParameterSet<NameBased> params;
+  params[NameBased::NAME] = ParamPickerMake(module_name);
+
+  EvalResult result =
+      policy_base_->EvalPolicy(IPC_NTCREATESECTION_TAG, params.GetBase());
+
+  // Return operation status on the IPC.
+  HANDLE section_handle = nullptr;
+  ipc->return_info.nt_status = SignedPolicy::CreateSectionAction(
+      result, *ipc->client_info, local_handle, &section_handle);
+  ipc->return_info.handle = section_handle;
+  return true;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/signed_dispatcher.h b/sandbox/win/src/signed_dispatcher.h
new file mode 100644
index 0000000..7abff80
--- /dev/null
+++ b/sandbox/win/src/signed_dispatcher.h
@@ -0,0 +1,36 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_SIGNED_DISPATCHER_H_
+#define SANDBOX_WIN_SRC_SIGNED_DISPATCHER_H_
+
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/interception.h"
+#include "sandbox/win/src/sandbox_policy_base.h"
+
+namespace sandbox {
+
+// This class handles signed-binary related IPC calls.
+class SignedDispatcher : public Dispatcher {
+ public:
+  explicit SignedDispatcher(PolicyBase* policy_base);
+  ~SignedDispatcher() override {}
+
+  // Dispatcher interface.
+  bool SetupService(InterceptionManager* manager, int service) override;
+
+ private:
+  // Processes IPC requests coming from calls to CreateSection in the target.
+  bool CreateSection(IPCInfo* ipc, HANDLE file_handle);
+
+  PolicyBase* policy_base_;
+  DISALLOW_COPY_AND_ASSIGN(SignedDispatcher);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_WIN_SRC_SIGNED_DISPATCHER_H_
diff --git a/sandbox/win/src/signed_interception.cc b/sandbox/win/src/signed_interception.cc
new file mode 100644
index 0000000..c071521
--- /dev/null
+++ b/sandbox/win/src/signed_interception.cc
@@ -0,0 +1,90 @@
+// 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 "sandbox/win/src/signed_interception.h"
+
+#include <stdint.h>
+
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/policy_target.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/sharedmem_ipc_client.h"
+#include "sandbox/win/src/target_services.h"
+
+namespace sandbox {
+
+NTSTATUS WINAPI
+TargetNtCreateSection(NtCreateSectionFunction orig_CreateSection,
+                      PHANDLE section_handle,
+                      ACCESS_MASK desired_access,
+                      POBJECT_ATTRIBUTES object_attributes,
+                      PLARGE_INTEGER maximum_size,
+                      ULONG section_page_protection,
+                      ULONG allocation_attributes,
+                      HANDLE file_handle) {
+  NTSTATUS status = orig_CreateSection(
+      section_handle, desired_access, object_attributes, maximum_size,
+      section_page_protection, allocation_attributes, file_handle);
+
+  // Only intercept calls that match a particular signature.
+  if (status != STATUS_INVALID_IMAGE_HASH)
+    return status;
+  if (desired_access != (SECTION_QUERY | SECTION_MAP_WRITE | SECTION_MAP_READ |
+                         SECTION_MAP_EXECUTE))
+    return status;
+  if (object_attributes)
+    return status;
+  if (maximum_size)
+    return status;
+  if (section_page_protection != PAGE_EXECUTE)
+    return status;
+  if (allocation_attributes != SEC_IMAGE)
+    return status;
+
+  do {
+    if (!ValidParameter(section_handle, sizeof(HANDLE), WRITE))
+      break;
+
+    void* memory = GetGlobalIPCMemory();
+    if (!memory)
+      break;
+    std::unique_ptr<wchar_t, NtAllocDeleter> path;
+    if (!NtGetPathFromHandle(file_handle, &path))
+      break;
+    const wchar_t* const_name = path.get();
+
+    CountedParameterSet<NameBased> params;
+    params[NameBased::NAME] = ParamPickerMake(const_name);
+
+    if (!QueryBroker(IPC_NTCREATESECTION_TAG, params.GetBase()))
+      break;
+
+    CrossCallReturn answer = {0};
+    answer.nt_status = status;
+    SharedMemIPCClient ipc(memory);
+    ResultCode code =
+        CrossCall(ipc, IPC_NTCREATESECTION_TAG, file_handle, &answer);
+
+    if (code != SBOX_ALL_OK)
+      break;
+
+    status = answer.nt_status;
+
+    if (!NT_SUCCESS(answer.nt_status))
+      break;
+
+    __try {
+      *section_handle = answer.handle;
+    } __except (EXCEPTION_EXECUTE_HANDLER) {
+      break;
+    }
+  } while (false);
+
+  return status;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/signed_interception.h b/sandbox/win/src/signed_interception.h
new file mode 100644
index 0000000..a50ec382
--- /dev/null
+++ b/sandbox/win/src/signed_interception.h
@@ -0,0 +1,30 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_SIGNED_INTERCEPTION_H_
+#define SANDBOX_WIN_SRC_SIGNED_INTERCEPTION_H_
+
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace sandbox {
+
+extern "C" {
+
+// Interceptor for NtCreateSection
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtCreateSection(NtCreateSectionFunction orig_CreateSection,
+                      PHANDLE section_handle,
+                      ACCESS_MASK desired_access,
+                      POBJECT_ATTRIBUTES object_attributes,
+                      PLARGE_INTEGER maximum_size,
+                      ULONG section_page_protection,
+                      ULONG allocation_attributes,
+                      HANDLE file_handle);
+
+}  // extern "C"
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_WIN_SRC_SIGNED_INTERCEPTION_H_
diff --git a/sandbox/win/src/signed_policy.cc b/sandbox/win/src/signed_policy.cc
new file mode 100644
index 0000000..6b7b11f
--- /dev/null
+++ b/sandbox/win/src/signed_policy.cc
@@ -0,0 +1,78 @@
+// 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 "sandbox/win/src/signed_policy.h"
+
+#include <stdint.h>
+
+#include <string>
+
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_engine_opcodes.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/sandbox_policy.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace sandbox {
+
+bool SignedPolicy::GenerateRules(const wchar_t* name,
+                                 TargetPolicy::Semantics semantics,
+                                 LowLevelPolicy* policy) {
+  // Only support one semantic.
+  if (TargetPolicy::SIGNED_ALLOW_LOAD != semantics) {
+    return false;
+  }
+
+  base::FilePath file_path(name);
+  base::string16 nt_path_name;
+  if (!GetNtPathFromWin32Path(file_path.DirName().value().c_str(),
+                              &nt_path_name))
+    return false;
+  base::FilePath nt_path(nt_path_name);
+  base::string16 nt_filename = nt_path.Append(file_path.BaseName()).value();
+  // Create a rule to ASK_BROKER if name matches.
+  PolicyRule signed_policy(ASK_BROKER);
+  if (!signed_policy.AddStringMatch(IF, NameBased::NAME, nt_filename.c_str(),
+                                    CASE_INSENSITIVE)) {
+    return false;
+  }
+  if (!policy->AddRule(IPC_NTCREATESECTION_TAG, &signed_policy)) {
+    return false;
+  }
+
+  return true;
+}
+
+NTSTATUS SignedPolicy::CreateSectionAction(
+    EvalResult eval_result,
+    const ClientInfo& client_info,
+    const base::win::ScopedHandle& local_file_handle,
+    HANDLE* target_section_handle) {
+  NtCreateSectionFunction NtCreateSection = nullptr;
+  ResolveNTFunctionPtr("NtCreateSection", &NtCreateSection);
+
+  // The only action supported is ASK_BROKER which means create the requested
+  // section as specified.
+  if (ASK_BROKER != eval_result)
+    return false;
+
+  HANDLE local_section_handle = nullptr;
+  NTSTATUS status = NtCreateSection(&local_section_handle,
+                                    SECTION_QUERY | SECTION_MAP_WRITE |
+                                        SECTION_MAP_READ | SECTION_MAP_EXECUTE,
+                                    nullptr, 0, PAGE_EXECUTE, SEC_IMAGE,
+                                    local_file_handle.Get());
+  if (!local_section_handle)
+    return status;
+
+  // Duplicate section handle back to the target.
+  if (!::DuplicateHandle(::GetCurrentProcess(), local_section_handle,
+                         client_info.process, target_section_handle, 0, false,
+                         DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+    return STATUS_ACCESS_DENIED;
+  }
+  return status;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/signed_policy.h b/sandbox/win/src/signed_policy.h
new file mode 100644
index 0000000..d22af4d
--- /dev/null
+++ b/sandbox/win/src/signed_policy.h
@@ -0,0 +1,39 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_SIGNED_POLICY_H_
+#define SANDBOX_WIN_SRC_SIGNED_POLICY_H_
+
+#include <stdint.h>
+
+#include "base/win/scoped_handle.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/policy_engine_opcodes.h"
+#include "sandbox/win/src/policy_low_level.h"
+#include "sandbox/win/src/sandbox_policy.h"
+
+namespace sandbox {
+
+// This class centralizes most of the knowledge related to signed policy
+class SignedPolicy {
+ public:
+  // Creates the required low-level policy rules to evaluate a high-level
+  // policy rule.
+  static bool GenerateRules(const wchar_t* name,
+                            TargetPolicy::Semantics semantics,
+                            LowLevelPolicy* policy);
+
+  // Performs the desired policy action on a request.
+  // client_info is the target process that is making the request and
+  // eval_result is the desired policy action to accomplish.
+  static NTSTATUS CreateSectionAction(
+      EvalResult eval_result,
+      const ClientInfo& client_info,
+      const base::win::ScopedHandle& local_file_handle,
+      HANDLE* section_handle);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_WIN_SRC_SIGNED_POLICY_H_
diff --git a/sandbox/win/src/top_level_dispatcher.cc b/sandbox/win/src/top_level_dispatcher.cc
index 9cbbdc20..f245802 100644
--- a/sandbox/win/src/top_level_dispatcher.cc
+++ b/sandbox/win/src/top_level_dispatcher.cc
@@ -18,6 +18,7 @@
 #include "sandbox/win/src/process_thread_dispatcher.h"
 #include "sandbox/win/src/registry_dispatcher.h"
 #include "sandbox/win/src/sandbox_policy_base.h"
+#include "sandbox/win/src/signed_dispatcher.h"
 #include "sandbox/win/src/sync_dispatcher.h"
 
 namespace sandbox {
@@ -76,6 +77,10 @@
       dispatcher;
   ipc_targets_[IPC_GDI_SETOPMSIGNINGKEYANDSEQUENCENUMBERS_TAG] = dispatcher;
   process_mitigations_win32k_dispatcher_.reset(dispatcher);
+
+  dispatcher = new SignedDispatcher(policy_);
+  ipc_targets_[IPC_NTCREATESECTION_TAG] = dispatcher;
+  signed_dispatcher_.reset(dispatcher);
 }
 
 TopLevelDispatcher::~TopLevelDispatcher() {}
diff --git a/sandbox/win/src/top_level_dispatcher.h b/sandbox/win/src/top_level_dispatcher.h
index c1cf8f6..36f71ae 100644
--- a/sandbox/win/src/top_level_dispatcher.h
+++ b/sandbox/win/src/top_level_dispatcher.h
@@ -42,6 +42,7 @@
   std::unique_ptr<Dispatcher> registry_dispatcher_;
   std::unique_ptr<Dispatcher> handle_dispatcher_;
   std::unique_ptr<Dispatcher> process_mitigations_win32k_dispatcher_;
+  std::unique_ptr<Dispatcher> signed_dispatcher_;
   Dispatcher* ipc_targets_[IPC_LAST_TAG];
 
   DISALLOW_COPY_AND_ASSIGN(TopLevelDispatcher);
diff --git a/services/network/cross_origin_read_blocking.cc b/services/network/cross_origin_read_blocking.cc
index f0319b5..4c244aa4 100644
--- a/services/network/cross_origin_read_blocking.cc
+++ b/services/network/cross_origin_read_blocking.cc
@@ -28,6 +28,7 @@
 #include "services/network/cross_origin_resource_policy.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/resource_response_info.h"
+#include "services/network/public/mojom/network_context.mojom.h"
 
 using base::StringPiece;
 using MimeType = network::CrossOriginReadBlocking::MimeType;
@@ -787,10 +788,12 @@
   // |request_initiator| (i.e. vetted against |request_initiator|site_lock|).
   constexpr mojom::RequestMode kOverreachingRequestMode =
       mojom::RequestMode::kNoCors;
+  // COEP is not supported when OOR-CORS is disabled.
   if (CrossOriginResourcePolicy::kBlock ==
-      CrossOriginResourcePolicy::Verify(request_url, request_initiator,
-                                        response, kOverreachingRequestMode,
-                                        request_initiator_site_lock)) {
+      CrossOriginResourcePolicy::Verify(
+          request_url, request_initiator, response, kOverreachingRequestMode,
+          request_initiator_site_lock,
+          mojom::CrossOriginEmbedderPolicy::kNone)) {
     // Ignore mime types and/or sniffing and have CORB block all responses with
     // COR*P* header.
     return kBlock;
diff --git a/services/network/cross_origin_resource_policy.cc b/services/network/cross_origin_resource_policy.cc
index fc1befa..02e62e4 100644
--- a/services/network/cross_origin_resource_policy.cc
+++ b/services/network/cross_origin_resource_policy.cc
@@ -6,9 +6,11 @@
 
 #include <string>
 
+#include "base/feature_list.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "net/http/http_response_headers.h"
 #include "services/network/initiator_lock_compatibility.h"
+#include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/resource_response_info.h"
 #include "url/gurl.h"
 #include "url/origin.h"
@@ -41,6 +43,11 @@
   if (header_value == "same-site")
     return CrossOriginResourcePolicy::kSameSite;
 
+  if (base::FeatureList::IsEnabled(features::kCrossOriginEmbedderPolicy) &&
+      header_value == "cross-origin") {
+    return CrossOriginResourcePolicy::kCrossOrigin;
+  }
+
   // TODO(lukasza): Once https://github.com/whatwg/fetch/issues/760 gets
   // resolved, add support for parsing specific origins.
   return CrossOriginResourcePolicy::kParsingError;
@@ -100,7 +107,8 @@
     const base::Optional<url::Origin>& request_initiator,
     const ResourceResponseInfo& response,
     mojom::RequestMode request_mode,
-    base::Optional<url::Origin> request_initiator_site_lock) {
+    base::Optional<url::Origin> request_initiator_site_lock,
+    mojom::CrossOriginEmbedderPolicy embedder_policy) {
   // From https://fetch.spec.whatwg.org/#cross-origin-resource-policy-header:
   // > 1. If request’s mode is not "no-cors", then return allowed.
   if (request_mode != mojom::RequestMode::kNoCors)
@@ -114,7 +122,16 @@
   // 2 and 3 from the spec), to return early if there was no header (before
   // slightly more expensive steps needed to extract the origins below).
   ParsedHeader policy = ParseHeader(response.headers.get());
-  if (policy == kNoHeader || policy == kParsingError) {
+
+  // COEP https://mikewest.github.io/corpp/#corp-check
+  if ((policy == kNoHeader || policy == kParsingError) &&
+      embedder_policy == mojom::CrossOriginEmbedderPolicy::kRequireCorp) {
+    DCHECK(base::FeatureList::IsEnabled(features::kCrossOriginEmbedderPolicy));
+    policy = kSameOrigin;
+  }
+
+  if (policy == kNoHeader || policy == kParsingError ||
+      policy == kCrossOrigin) {
     // The algorithm only returns kBlock from steps 4 and 6, when policy is
     // either kSameOrigin or kSameSite.  For other policy values we can
     // immediately execute step 7 and return kAllow.
diff --git a/services/network/cross_origin_resource_policy.h b/services/network/cross_origin_resource_policy.h
index fb3ae9e..1bc3f7b 100644
--- a/services/network/cross_origin_resource_policy.h
+++ b/services/network/cross_origin_resource_policy.h
@@ -9,6 +9,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/optional.h"
 #include "services/network/public/mojom/fetch_api.mojom-shared.h"
+#include "services/network/public/mojom/network_context.mojom.h"
 #include "url/origin.h"
 
 class GURL;
@@ -41,13 +42,15 @@
       const base::Optional<url::Origin>& request_initiator,
       const ResourceResponseInfo& response,
       mojom::RequestMode request_mode,
-      base::Optional<url::Origin> request_initiator_site_lock);
+      base::Optional<url::Origin> request_initiator_site_lock,
+      mojom::CrossOriginEmbedderPolicy embedder_policy);
 
   // Parsing of the Cross-Origin-Resource-Policy http response header.
   enum ParsedHeader {
     kNoHeader,
     kSameOrigin,
     kSameSite,
+    kCrossOrigin,
     kParsingError,
   };
   static ParsedHeader ParseHeaderForTesting(
diff --git a/services/network/cross_origin_resource_policy_unittest.cc b/services/network/cross_origin_resource_policy_unittest.cc
index a19f3f4..afaeb5a 100644
--- a/services/network/cross_origin_resource_policy_unittest.cc
+++ b/services/network/cross_origin_resource_policy_unittest.cc
@@ -5,9 +5,11 @@
 #include <string>
 
 #include "base/memory/ref_counted.h"
+#include "base/test/scoped_feature_list.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_util.h"
 #include "services/network/cross_origin_resource_policy.h"
+#include "services/network/public/cpp/features.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace network {
@@ -65,6 +67,20 @@
                         "Cross-Origin-Resource-Policy: same-origin"));
 }
 
+TEST(CrossOriginResourcePolicyTest, CrossSiteHeaderWithCOEP) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(features::kCrossOriginEmbedderPolicy);
+  EXPECT_EQ(CrossOriginResourcePolicy::kCrossOrigin,
+            ParseHeader("Cross-Origin-Resource-Policy: cross-origin"));
+}
+
+TEST(CrossOriginResourcePolicyTest, CrossSiteHeaderWithoutCOEP) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndDisableFeature(features::kCrossOriginEmbedderPolicy);
+  EXPECT_EQ(CrossOriginResourcePolicy::kParsingError,
+            ParseHeader("Cross-Origin-Resource-Policy: cross-origin"));
+}
+
 bool ShouldAllowSameSite(const std::string& initiator,
                          const std::string& target) {
   return CrossOriginResourcePolicy::ShouldAllowSameSiteForTesting(
@@ -106,4 +122,74 @@
   EXPECT_FALSE(ShouldAllowSameSite("http://127.0.0.1", "http://127.0.0.1"));
 }
 
+TEST(CrossOriginResourcePolicyTest, WithCOEP) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(features::kCrossOriginEmbedderPolicy);
+
+  ResourceResponseInfo corp_none;
+  ResourceResponseInfo corp_same_origin;
+  ResourceResponseInfo corp_cross_origin;
+
+  corp_same_origin.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+      net::HttpUtil::AssembleRawHeaders(
+          "HTTP/1.1 200 OK\n"
+          "cross-origin-resource-policy: same-origin\n"));
+
+  corp_cross_origin.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+      net::HttpUtil::AssembleRawHeaders(
+          "HTTP/1.1 200 OK\n"
+          "cross-origin-resource-policy: cross-origin\n"));
+
+  GURL destination("https://www.example.com/");
+
+  url::Origin destination_origin =
+      url::Origin::Create(GURL("https://www.example.com"));
+  url::Origin another_origin =
+      url::Origin::Create(GURL("https://www2.example.com"));
+
+  constexpr auto kAllow = CrossOriginResourcePolicy::kAllow;
+  constexpr auto kBlock = CrossOriginResourcePolicy::kBlock;
+  using mojom::RequestMode;
+
+  struct TestCase {
+    const RequestMode request_mode;
+    const url::Origin origin;
+    const ResourceResponseInfo response_info;
+    const CrossOriginResourcePolicy::VerificationResult
+        expectation_with_coep_none;
+    const CrossOriginResourcePolicy::VerificationResult
+        expectation_with_coep_require_corp;
+  } test_cases[] = {
+      // We don't have a cross-origin-resource-policy header on a response. That
+      // leads to kBlock when COEP: kRequireCorp is used.
+      {RequestMode::kNoCors, another_origin, corp_none, kAllow, kBlock},
+      // We have "cross-origin-resource-policy: same-origin", so regardless of
+      // COEP the response is blocked.
+      {RequestMode::kNoCors, another_origin, corp_same_origin, kBlock, kBlock},
+      // We have "cross-origin-resource-policy: cross-origin", so regardless of
+      // COEP the response is allowed.
+      {RequestMode::kNoCors, another_origin, corp_cross_origin, kAllow, kAllow},
+      // The origin of the request URL and request's origin match, so regardless
+      // of COEP the response is allowed.
+      {RequestMode::kNoCors, destination_origin, corp_same_origin, kAllow,
+       kAllow},
+      // The request mode is "cors", so so regardless of COEP the response is
+      // allowed.
+      {RequestMode::kCors, another_origin, corp_same_origin, kAllow, kAllow},
+  };
+
+  for (const auto& test_case : test_cases) {
+    EXPECT_EQ(test_case.expectation_with_coep_none,
+              CrossOriginResourcePolicy::Verify(
+                  destination, test_case.origin, test_case.response_info,
+                  test_case.request_mode, test_case.origin,
+                  mojom::CrossOriginEmbedderPolicy::kNone));
+
+    EXPECT_EQ(test_case.expectation_with_coep_require_corp,
+              CrossOriginResourcePolicy::Verify(
+                  destination, test_case.origin, test_case.response_info,
+                  test_case.request_mode, test_case.origin,
+                  mojom::CrossOriginEmbedderPolicy::kRequireCorp));
+  }
+}
 }  // namespace network
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom
index 70229c7..75dc07c 100644
--- a/services/network/public/mojom/network_context.mojom
+++ b/services/network/public/mojom/network_context.mojom
@@ -455,6 +455,12 @@
 const uint32 kBrowserProcessId = 0;
 const uint32 kInvalidProcessId = 0xffffffff;
 
+// https://mikewest.github.io/corpp/#integration-html
+enum CrossOriginEmbedderPolicy {
+  kNone,
+  kRequireCorp,
+};
+
 struct URLLoaderFactoryParams {
   // Process requesting the URLLoaderFactory.
   // Set to kBrowserProcessId to indicate the browser process.
@@ -474,6 +480,11 @@
   // mainly used by people testing their sites, via a command line switch.
   bool disable_web_security = false;
 
+  // https://mikewest.github.io/corpp/#integration-html
+  // https://mikewest.github.io/corpp/#initialize-embedder-policy-for-global
+  CrossOriginEmbedderPolicy cross_origin_embedder_policy =
+      CrossOriginEmbedderPolicy.kNone;
+
   // If this is set, requests with the kURLLoadOptionUseHeaderClient option will
   // callback to the |header_client|, allowing the Cookie/Referrer request
   // headers and Cookie response headers to be modified. This has a performance
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index 4e86726..423fcb0 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -798,7 +798,8 @@
   if (CrossOriginResourcePolicy::kBlock ==
       CrossOriginResourcePolicy::Verify(
           url_request_->url(), url_request_->initiator(), response->head,
-          request_mode_, factory_params_->request_initiator_site_lock)) {
+          request_mode_, factory_params_->request_initiator_site_lock,
+          factory_params_->cross_origin_embedder_policy)) {
     CompleteBlockedResponse(net::ERR_BLOCKED_BY_RESPONSE, false);
     DeleteSelf();
     return;
@@ -957,7 +958,8 @@
   if (CrossOriginResourcePolicy::kBlock ==
       CrossOriginResourcePolicy::Verify(
           url_request_->url(), url_request_->initiator(), response_->head,
-          request_mode_, factory_params_->request_initiator_site_lock)) {
+          request_mode_, factory_params_->request_initiator_site_lock,
+          factory_params_->cross_origin_embedder_policy)) {
     CompleteBlockedResponse(net::ERR_BLOCKED_BY_RESPONSE, false);
     DeleteSelf();
     return;
diff --git a/testing/buildbot/filters/navigation_loader_on_ui_browser_tests.filter b/testing/buildbot/filters/navigation_loader_on_ui_browser_tests.filter
index dabc7c5a..5d006fa 100644
--- a/testing/buildbot/filters/navigation_loader_on_ui_browser_tests.filter
+++ b/testing/buildbot/filters/navigation_loader_on_ui_browser_tests.filter
@@ -1,7 +1 @@
 # These tests currently fail when run with --enable-features=NavigationLoaderOnUI
-
-# http://crbug.com/824854
--ChromeAcceptHeaderTest.Check
--SignedExchangePageLoadMetricsBrowserTest.UkmSignedExchangeMetric
--SignedExchangePolicyBrowserTest.BlackList
--SignedExchangePolicyTest.SignedExchangeEnabled
diff --git a/testing/buildbot/filters/navigation_loader_on_ui_content_browsertests.filter b/testing/buildbot/filters/navigation_loader_on_ui_content_browsertests.filter
index bd16211b..5d006fa 100644
--- a/testing/buildbot/filters/navigation_loader_on_ui_content_browsertests.filter
+++ b/testing/buildbot/filters/navigation_loader_on_ui_content_browsertests.filter
@@ -1,139 +1 @@
 # These tests currently fail when run with --enable-features=NavigationLoaderOnUI
-
-# http://crbug.com/824854
--AcceptHeaderTest.Check
--PrefetchBrowserTest/PrefetchBrowserTest.CrossOriginSignedExchangeWithPreload/3
--PrefetchBrowserTest/PrefetchBrowserTest.SignedExchangeWithPreload/3
--SignedExchangeAcceptHeaderBrowserTest/SignedExchangeAcceptHeaderBrowserTest.FallbackRedirect/1
--SignedExchangeAcceptHeaderBrowserTest/SignedExchangeAcceptHeaderBrowserTest.Redirect/1
--SignedExchangeAcceptHeaderBrowserTest/SignedExchangeAcceptHeaderBrowserTest.ServiceWorker/0
--SignedExchangeAcceptHeaderBrowserTest/SignedExchangeAcceptHeaderBrowserTest.ServiceWorker/1
--SignedExchangeAcceptHeaderBrowserTest/SignedExchangeAcceptHeaderBrowserTest.ServiceWorkerPrefetch/0
--SignedExchangeAcceptHeaderBrowserTest/SignedExchangeAcceptHeaderBrowserTest.ServiceWorkerPrefetch/1
--SignedExchangeAcceptHeaderBrowserTest/SignedExchangeAcceptHeaderBrowserTest.Simple/1
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchAlternativeSubresourceSXG/2
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchAlternativeSubresourceSXG/3
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchAlternativeSubresourceSXG/4
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchAlternativeSubresourceSXG/5
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchAlternativeSubresourceSXG/6
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchAlternativeSubresourceSXG/7
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_CacheControlPublic/2
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_CacheControlPublic/3
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_CacheControlPublic/4
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_CacheControlPublic/5
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_CacheControlPublic/6
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_CacheControlPublic/7
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_CacheControlPublicExpire/2
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_CacheControlPublicExpire/3
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_CacheControlPublicExpire/4
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_CacheControlPublicExpire/5
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_CacheControlPublicExpire/6
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_CacheControlPublicExpire/7
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_CrossOrigin/2
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_CrossOrigin/3
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_CrossOrigin/4
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_CrossOrigin/5
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_CrossOrigin/6
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_CrossOrigin/7
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_ExceedPrefetchReuseMins/2
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_ExceedPrefetchReuseMins/3
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_ExceedPrefetchReuseMins/4
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_ExceedPrefetchReuseMins/5
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_ExceedPrefetchReuseMins/6
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_ExceedPrefetchReuseMins/7
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_SameOrigin/2
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_SameOrigin/3
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_SameOrigin/4
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_SameOrigin/5
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_SameOrigin/6
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_SameOrigin/7
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_SameURL/2
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_SameURL/3
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_SameURL/4
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_SameURL/5
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_SameURL/6
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_SameURL/7
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_SignatureExpire/2
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_SignatureExpire/3
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_SignatureExpire/4
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_SignatureExpire/5
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_SignatureExpire/6
--SignedExchangePrefetchBrowserTest/SignedExchangePrefetchBrowserTest.PrefetchMainResourceSXG_SignatureExpire/7
--SignedExchangeRequestHandlerBrowserTest.BadMICE/2
--SignedExchangeRequestHandlerBrowserTest.BadMICE/3
--SignedExchangeRequestHandlerBrowserTest.BadMICE/6
--SignedExchangeRequestHandlerBrowserTest.BadMICE/7
--SignedExchangeRequestHandlerBrowserTest.BadMICESmall/2
--SignedExchangeRequestHandlerBrowserTest.BadMICESmall/3
--SignedExchangeRequestHandlerBrowserTest.BadMICESmall/6
--SignedExchangeRequestHandlerBrowserTest.BadMICESmall/7
--SignedExchangeRequestHandlerBrowserTest.CertNotFound/2
--SignedExchangeRequestHandlerBrowserTest.CertNotFound/3
--SignedExchangeRequestHandlerBrowserTest.CertNotFound/6
--SignedExchangeRequestHandlerBrowserTest.CertNotFound/7
--SignedExchangeRequestHandlerBrowserTest.Expired/2
--SignedExchangeRequestHandlerBrowserTest.Expired/3
--SignedExchangeRequestHandlerBrowserTest.Expired/6
--SignedExchangeRequestHandlerBrowserTest.Expired/7
--SignedExchangeRequestHandlerBrowserTest.InvalidContentType/2
--SignedExchangeRequestHandlerBrowserTest.InvalidContentType/3
--SignedExchangeRequestHandlerBrowserTest.InvalidContentType/6
--SignedExchangeRequestHandlerBrowserTest.InvalidContentType/7
--SignedExchangeRequestHandlerBrowserTest.LogicalUrlInServiceWorkerScope/2
--SignedExchangeRequestHandlerBrowserTest.LogicalUrlInServiceWorkerScope/3
--SignedExchangeRequestHandlerBrowserTest.LogicalUrlInServiceWorkerScope/6
--SignedExchangeRequestHandlerBrowserTest.LogicalUrlInServiceWorkerScope/7
--SignedExchangeRequestHandlerBrowserTest.MissingNosniff/2
--SignedExchangeRequestHandlerBrowserTest.MissingNosniff/3
--SignedExchangeRequestHandlerBrowserTest.MissingNosniff/6
--SignedExchangeRequestHandlerBrowserTest.MissingNosniff/7
--SignedExchangeRequestHandlerBrowserTest.NotControlledByDistributorsSW/2
--SignedExchangeRequestHandlerBrowserTest.NotControlledByDistributorsSW/3
--SignedExchangeRequestHandlerBrowserTest.NotControlledByDistributorsSW/6
--SignedExchangeRequestHandlerBrowserTest.NotControlledByDistributorsSW/7
--SignedExchangeRequestHandlerBrowserTest.NotControlledBySameOriginDistributorsSW/2
--SignedExchangeRequestHandlerBrowserTest.NotControlledBySameOriginDistributorsSW/3
--SignedExchangeRequestHandlerBrowserTest.NotControlledBySameOriginDistributorsSW/6
--SignedExchangeRequestHandlerBrowserTest.NotControlledBySameOriginDistributorsSW/7
--SignedExchangeRequestHandlerBrowserTest.RedirectBrokenSignedExchanges/2
--SignedExchangeRequestHandlerBrowserTest.RedirectBrokenSignedExchanges/3
--SignedExchangeRequestHandlerBrowserTest.RedirectBrokenSignedExchanges/6
--SignedExchangeRequestHandlerBrowserTest.RedirectBrokenSignedExchanges/7
--SignedExchangeRequestHandlerBrowserTest.RegisterServiceWorkerFromSignedExchange/2
--SignedExchangeRequestHandlerBrowserTest.RegisterServiceWorkerFromSignedExchange/3
--SignedExchangeRequestHandlerBrowserTest.RegisterServiceWorkerFromSignedExchange/6
--SignedExchangeRequestHandlerBrowserTest.RegisterServiceWorkerFromSignedExchange/7
--SignedExchangeRequestHandlerBrowserTest.Simple/2
--SignedExchangeRequestHandlerBrowserTest.Simple/3
--SignedExchangeRequestHandlerBrowserTest.Simple/6
--SignedExchangeRequestHandlerBrowserTest.Simple/7
--SignedExchangeRequestHandlerBrowserTest.VariantMatch/2
--SignedExchangeRequestHandlerBrowserTest.VariantMatch/3
--SignedExchangeRequestHandlerBrowserTest.VariantMatch/6
--SignedExchangeRequestHandlerBrowserTest.VariantMatch/7
--SignedExchangeRequestHandlerBrowserTest.VariantMismatch/2
--SignedExchangeRequestHandlerBrowserTest.VariantMismatch/3
--SignedExchangeRequestHandlerBrowserTest.VariantMismatch/6
--SignedExchangeRequestHandlerBrowserTest.VariantMismatch/7
--SignedExchangeRequestHandlerRealCertVerifierBrowserTest.Basic
--SignedExchangeSubresourcePrefetchBrowserTest/SignedExchangeSubresourcePrefetchBrowserTest.CORS/1
--SignedExchangeSubresourcePrefetchBrowserTest/SignedExchangeSubresourcePrefetchBrowserTest.CrossOriginReadBlocking_AllowedAfterSniffing/1
--SignedExchangeSubresourcePrefetchBrowserTest/SignedExchangeSubresourcePrefetchBrowserTest.CrossOriginReadBlocking_AllowedWithoutSniffing/1
--SignedExchangeSubresourcePrefetchBrowserTest/SignedExchangeSubresourcePrefetchBrowserTest.CrossOriginReadBlocking_BlockedAfterSniffing/1
--SignedExchangeSubresourcePrefetchBrowserTest/SignedExchangeSubresourcePrefetchBrowserTest.CrossOriginReadBlocking_BlockedWithoutSniffing/1
--SignedExchangeSubresourcePrefetchBrowserTest/SignedExchangeSubresourcePrefetchBrowserTest.DoNotSendUnrelatedSXG/1
--SignedExchangeSubresourcePrefetchBrowserTest/SignedExchangeSubresourcePrefetchBrowserTest.ImageSrcsetAndSizes/1
--SignedExchangeSubresourcePrefetchBrowserTest/SignedExchangeSubresourcePrefetchBrowserTest.IntegrityMismatch/1
--SignedExchangeSubresourcePrefetchBrowserTest/SignedExchangeSubresourcePrefetchBrowserTest.MainResourceSXGAndScriptSXG_CacheControlNoStore/1
--SignedExchangeSubresourcePrefetchBrowserTest/SignedExchangeSubresourcePrefetchBrowserTest.MainResourceSXGAndScriptSXG_CacheControlPublic/1
--SignedExchangeSubresourcePrefetchBrowserTest/SignedExchangeSubresourcePrefetchBrowserTest.MainResourceSXGAndScriptSXG_CacheControlPublicExpire/1
--SignedExchangeSubresourcePrefetchBrowserTest/SignedExchangeSubresourcePrefetchBrowserTest.MainResourceSXGAndScriptSXG_CrossOrigin/1
--SignedExchangeSubresourcePrefetchBrowserTest/SignedExchangeSubresourcePrefetchBrowserTest.MainResourceSXGAndScriptSXG_DifferentOriginScriptSXG/1
--SignedExchangeSubresourcePrefetchBrowserTest/SignedExchangeSubresourcePrefetchBrowserTest.MainResourceSXGAndScriptSXG_ExceedPrefetchReuseMins/1
--SignedExchangeSubresourcePrefetchBrowserTest/SignedExchangeSubresourcePrefetchBrowserTest.MainResourceSXGAndScriptSXG_SameOrigin/1
--SignedExchangeSubresourcePrefetchBrowserTest/SignedExchangeSubresourcePrefetchBrowserTest.MainResourceSXGAndScriptSXG_SameUrl/1
--SignedExchangeSubresourcePrefetchBrowserTest/SignedExchangeSubresourcePrefetchBrowserTest.MainResourceSXGAndScriptSXG_VaryAcceptEncodingHeader/1
--SignedExchangeSubresourcePrefetchBrowserTest/SignedExchangeSubresourcePrefetchBrowserTest.MainResourceSXGAndScriptSXG_VaryAsteriskHeader/1
--SignedExchangeSubresourcePrefetchBrowserTest/SignedExchangeSubresourcePrefetchBrowserTest.MultipleResources/1
--SignedExchangeSubresourcePrefetchBrowserTest/SignedExchangeSubresourcePrefetchBrowserTest.MultipleResources_IntegrityMismatch/1
--SignedExchangeSubresourcePrefetchBrowserTest/SignedExchangeSubresourcePrefetchBrowserTest.ScriptSXGNotGCed/1
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 6c26af2..b1339f5 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1803,6 +1803,21 @@
             ]
         }
     ],
+    "DistinctModuleDatabaseSequence": [
+        {
+            "platforms": [
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "DistinctModuleDatabaseSequence"
+                    ]
+                }
+            ]
+        }
+    ],
     "DownloadHomeMoreButton": [
         {
             "platforms": [
@@ -2818,6 +2833,7 @@
                     "params": {
                         "automatic-lazy-load-frames-enabled": "true",
                         "automatic-lazy-load-images-enabled": "true",
+                        "enable-lazy-load-images-metadata-fetch": "false",
                         "restrict-lazy-load-frames-to-data-saver-only": "true",
                         "restrict-lazy-load-images-to-data-saver-only": "true"
                     },
diff --git a/third_party/blink/public/platform/modules/webrtc/webrtc_logging.h b/third_party/blink/public/platform/modules/webrtc/webrtc_logging.h
index b1761ba..9f4c162 100644
--- a/third_party/blink/public/platform/modules/webrtc/webrtc_logging.h
+++ b/third_party/blink/public/platform/modules/webrtc/webrtc_logging.h
@@ -24,11 +24,11 @@
   virtual ~WebRtcLogMessageDelegate() {}
 };
 
-// Must be called on IO thread.
+// Must only be called once, and |delegate| must be non-null.
 BLINK_PLATFORM_EXPORT void InitWebRtcLoggingDelegate(
     WebRtcLogMessageDelegate* delegate);
 
-// Must be called on IO thread.
+// Called to start the diagnostic WebRTC log.
 BLINK_PLATFORM_EXPORT void InitWebRtcLogging();
 
 // This function will add |message| to the diagnostic WebRTC log, if started.
diff --git a/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc b/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc
index d33ce94..15e5f7b 100644
--- a/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc
+++ b/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc
@@ -299,49 +299,51 @@
         document_parameters.lazyload_policy_enforced) {
       effective_loading_attr_value = LoadingAttrValue::kAuto;
     }
-    bool is_lazy_load_image_enabled = false;
-    switch (effective_loading_attr_value) {
-      case LoadingAttrValue::kEager:
-        is_lazy_load_image_enabled = false;
-        break;
-      case LoadingAttrValue::kLazy:
-        is_lazy_load_image_enabled =
-            document_parameters.lazy_load_image_setting !=
-            LocalFrame::LazyLoadImageSetting::kDisabled;
-        break;
-      case LoadingAttrValue::kAuto:
-        if ((width_attr_dimension_type_ ==
-                 HTMLImageElement::LazyLoadDimensionType::kAbsoluteSmall &&
-             height_attr_dimension_type_ ==
-                 HTMLImageElement::LazyLoadDimensionType::kAbsoluteSmall) ||
-            inline_style_dimensions_type_ ==
-                HTMLImageElement::LazyLoadDimensionType::kAbsoluteSmall) {
+    if (type == ResourceType::kImage) {
+      bool is_lazy_load_image_enabled = false;
+      switch (effective_loading_attr_value) {
+        case LoadingAttrValue::kEager:
           is_lazy_load_image_enabled = false;
-        } else {
+          break;
+        case LoadingAttrValue::kLazy:
           is_lazy_load_image_enabled =
-              document_parameters.lazy_load_image_setting ==
-              LocalFrame::LazyLoadImageSetting::kEnabledAutomatic;
-        }
-        break;
+              document_parameters.lazy_load_image_setting !=
+              LocalFrame::LazyLoadImageSetting::kDisabled;
+          break;
+        case LoadingAttrValue::kAuto:
+          if ((width_attr_dimension_type_ ==
+                   HTMLImageElement::LazyLoadDimensionType::kAbsoluteSmall &&
+               height_attr_dimension_type_ ==
+                   HTMLImageElement::LazyLoadDimensionType::kAbsoluteSmall) ||
+              inline_style_dimensions_type_ ==
+                  HTMLImageElement::LazyLoadDimensionType::kAbsoluteSmall) {
+            is_lazy_load_image_enabled = false;
+          } else {
+            is_lazy_load_image_enabled =
+                document_parameters.lazy_load_image_setting ==
+                LocalFrame::LazyLoadImageSetting::kEnabledAutomatic;
+          }
+          break;
+      }
+      // Do not preload if lazyload is possible but metadata fetch is disabled.
+      if (is_lazy_load_image_enabled &&
+          !RuntimeEnabledFeatures::LazyImageLoadingMetadataFetchEnabled()) {
+        return nullptr;
+      }
+      // LazyLoad: Do not preload if absolute dimensions are mentioned in width
+      // and height attributes or in the inline style, and the dimensions are
+      // not small enough.
+      if (is_lazy_load_image_enabled &&
+          ((width_attr_dimension_type_ ==
+                HTMLImageElement::LazyLoadDimensionType::kAbsoluteNotSmall &&
+            height_attr_dimension_type_ ==
+                HTMLImageElement::LazyLoadDimensionType::kAbsoluteNotSmall) ||
+           inline_style_dimensions_type_ ==
+               HTMLImageElement::LazyLoadDimensionType::kAbsoluteNotSmall)) {
+        return nullptr;
+      }
+      request->SetIsLazyLoadImageEnabled(is_lazy_load_image_enabled);
     }
-    // Do not preload if lazyload is possible but metadata fetch is disabled.
-    if (is_lazy_load_image_enabled &&
-        !RuntimeEnabledFeatures::LazyImageLoadingMetadataFetchEnabled()) {
-      return nullptr;
-    }
-    // LazyLoad: Do not preload if absolute dimensions are mentioned in width
-    // and height attributes or in the inline style, and the dimensions are not
-    // small enough.
-    if (is_lazy_load_image_enabled &&
-        ((width_attr_dimension_type_ ==
-              HTMLImageElement::LazyLoadDimensionType::kAbsoluteNotSmall &&
-          height_attr_dimension_type_ ==
-              HTMLImageElement::LazyLoadDimensionType::kAbsoluteNotSmall) ||
-         inline_style_dimensions_type_ ==
-             HTMLImageElement::LazyLoadDimensionType::kAbsoluteNotSmall)) {
-      return nullptr;
-    }
-    request->SetIsLazyLoadImageEnabled(is_lazy_load_image_enabled);
 
     request->SetIntegrityMetadata(integrity_metadata_);
 
diff --git a/third_party/blink/renderer/core/layout/BUILD.gn b/third_party/blink/renderer/core/layout/BUILD.gn
index 9f2f4c09..b3cfd30 100644
--- a/third_party/blink/renderer/core/layout/BUILD.gn
+++ b/third_party/blink/renderer/core/layout/BUILD.gn
@@ -384,6 +384,8 @@
     "ng/layout_box_utils.h",
     "ng/layout_ng_block_flow.cc",
     "ng/layout_ng_block_flow.h",
+    "ng/layout_ng_block_flow_mixin.cc",
+    "ng/layout_ng_block_flow_mixin.h",
     "ng/layout_ng_fieldset.cc",
     "ng/layout_ng_fieldset.h",
     "ng/layout_ng_flexible_box.cc",
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc
index e335a8c..12123bb9 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc
@@ -5,24 +5,17 @@
 #include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
 
 #include "third_party/blink/renderer/core/layout/layout_analyzer.h"
-#include "third_party/blink/renderer/core/layout/layout_view.h"
-#include "third_party/blink/renderer/core/layout/min_max_size.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h"
-#include "third_party/blink/renderer/core/layout/ng/layout_box_utils.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
 #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_out_of_flow_positioned_node.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
-#include "third_party/blink/renderer/core/paint/paint_layer.h"
-#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
 
 namespace blink {
 
 LayoutNGBlockFlow::LayoutNGBlockFlow(Element* element)
-    : LayoutNGMixin<LayoutBlockFlow>(element) {}
+    : LayoutNGBlockFlowMixin<LayoutBlockFlow>(element) {}
 
 LayoutNGBlockFlow::~LayoutNGBlockFlow() = default;
 
@@ -52,122 +45,6 @@
   UpdateMargins(constraint_space);
 }
 
-void LayoutNGBlockFlow::UpdateOutOfFlowBlockLayout() {
-  LayoutBoxModelObject* css_container = ToLayoutBoxModelObject(Container());
-  LayoutBox* container =
-      css_container->IsBox() ? ToLayoutBox(css_container) : ContainingBlock();
-  const ComputedStyle* container_style = container->Style();
-  NGConstraintSpace constraint_space =
-      NGConstraintSpace::CreateFromLayoutObject(*this);
-
-  // As this is part of the Legacy->NG bridge, the container_builder is used
-  // for indicating the resolved size of the OOF-positioned containing-block
-  // and not used for caching purposes.
-  // When we produce a layout result from it, we access its child fragments
-  // which must contain *at least* this node. We use the child fragments for
-  // copying back position information.
-  NGBlockNode container_node(container);
-  NGBoxFragmentBuilder container_builder(
-      container_node, scoped_refptr<const ComputedStyle>(container_style),
-      /* space */ nullptr, container_style->GetWritingMode(),
-      container_style->Direction());
-  container_builder.SetIsNewFormattingContext(
-      container_node.CreatesNewFormattingContext());
-
-  NGFragmentGeometry fragment_geometry;
-  fragment_geometry.border = ComputeBorders(constraint_space, container_node);
-  fragment_geometry.scrollbar =
-      ComputeScrollbars(constraint_space, container_node);
-  fragment_geometry.padding =
-      ComputePadding(constraint_space, *container_style);
-
-  NGBoxStrut border_scrollbar =
-      fragment_geometry.border + fragment_geometry.scrollbar;
-
-  // Calculate the border-box size of the object that's the containing block of
-  // this out-of-flow positioned descendant. Note that this is not to be used as
-  // the containing block size to resolve sizes and positions for the
-  // descendant, since we're dealing with the border box here (not the padding
-  // box, which is where the containing block is established). These sizes are
-  // just used to do a fake/partial NG layout pass of the containing block (that
-  // object is really managed by legacy layout).
-  LayoutUnit container_border_box_logical_width;
-  LayoutUnit container_border_box_logical_height;
-  if (HasOverrideContainingBlockContentLogicalWidth()) {
-    container_border_box_logical_width =
-        OverrideContainingBlockContentLogicalWidth() +
-        border_scrollbar.InlineSum();
-  } else {
-    container_border_box_logical_width = container->LogicalWidth();
-  }
-  if (HasOverrideContainingBlockContentLogicalHeight()) {
-    container_border_box_logical_height =
-        OverrideContainingBlockContentLogicalHeight() +
-        border_scrollbar.BlockSum();
-  } else {
-    container_border_box_logical_height = container->LogicalHeight();
-  }
-
-  fragment_geometry.border_box_size = {container_border_box_logical_width,
-                                       container_border_box_logical_height};
-  container_builder.SetInitialFragmentGeometry(fragment_geometry);
-
-  NGLogicalStaticPosition static_position =
-      LayoutBoxUtils::ComputeStaticPositionFromLegacy(*this, border_scrollbar);
-  // Set correct container for inline containing blocks.
-  container_builder.AddOutOfFlowLegacyCandidate(
-      NGBlockNode(this), static_position, ToLayoutInlineOrNull(css_container));
-
-  base::Optional<LogicalSize> initial_containing_block_fixed_size;
-  if (container->IsLayoutView() && !GetDocument().Printing()) {
-    if (LocalFrameView* frame_view = ToLayoutView(container)->GetFrameView()) {
-      IntSize size =
-          frame_view->LayoutViewport()->ExcludeScrollbars(frame_view->Size());
-      PhysicalSize physical_size(size);
-      initial_containing_block_fixed_size =
-          physical_size.ConvertToLogical(container->Style()->GetWritingMode());
-    }
-  }
-  // We really only want to lay out ourselves here, so we pass |this| to
-  // Run(). Otherwise, NGOutOfFlowLayoutPart may also lay out other objects
-  // it discovers that are part of the same containing block, but those
-  // should get laid out by the actual containing block.
-  NGOutOfFlowLayoutPart(css_container->CanContainAbsolutePositionObjects(),
-                        css_container->CanContainFixedPositionObjects(),
-                        *container_style, constraint_space, border_scrollbar,
-                        &container_builder, initial_containing_block_fixed_size)
-      .Run(/* only_layout */ this);
-  scoped_refptr<const NGLayoutResult> result =
-      container_builder.ToBoxFragment();
-  // These are the unpositioned OOF descendants of the current OOF block.
-  for (const auto& descendant :
-       result->PhysicalFragment().OutOfFlowPositionedDescendants())
-    descendant.node.UseLegacyOutOfFlowPositioning();
-
-  const auto& fragment = result->PhysicalFragment();
-  DCHECK_GT(fragment.Children().size(), 0u);
-  // Copy sizes of all child fragments to Legacy.
-  // There could be multiple fragments, when this node has descendants whose
-  // container is this node's container.
-  // Example: fixed descendant of fixed element.
-  for (auto& child : fragment.Children()) {
-    const NGPhysicalFragment* child_fragment = child.get();
-    DCHECK(child_fragment->GetLayoutObject()->IsBox());
-    LayoutBox* child_legacy_box =
-        ToLayoutBox(child_fragment->GetMutableLayoutObject());
-    PhysicalOffset child_offset = child.Offset();
-    if (container_style->IsFlippedBlocksWritingMode()) {
-      child_legacy_box->SetX(container_border_box_logical_height -
-                             child_offset.left - child_fragment->Size().width);
-    } else {
-      child_legacy_box->SetX(child_offset.left);
-    }
-    child_legacy_box->SetY(child_offset.top);
-  }
-  DCHECK_EQ(fragment.Children()[0]->GetLayoutObject(), this);
-  SetIsLegacyInitiatedOutOfFlowLayout(true);
-}
-
 void LayoutNGBlockFlow::UpdateMargins(const NGConstraintSpace& space) {
   const LayoutBlock* containing_block = ContainingBlock();
   if (!containing_block || !containing_block->IsLayoutBlockFlow())
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h
index 07792ae7..ae132bb 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h
@@ -7,12 +7,13 @@
 
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/layout/layout_block_flow.h"
-#include "third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h"
+#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.h"
 
 namespace blink {
 
 // This overrides the default layout block algorithm to use Layout NG.
-class CORE_EXPORT LayoutNGBlockFlow : public LayoutNGMixin<LayoutBlockFlow> {
+class CORE_EXPORT LayoutNGBlockFlow
+    : public LayoutNGBlockFlowMixin<LayoutBlockFlow> {
  public:
   explicit LayoutNGBlockFlow(Element*);
   ~LayoutNGBlockFlow() override;
@@ -25,7 +26,6 @@
   bool IsOfType(LayoutObjectType) const override;
 
  private:
-  void UpdateOutOfFlowBlockLayout();
   void UpdateMargins(const NGConstraintSpace&);
 };
 
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc
new file mode 100644
index 0000000..a8ca5a8
--- /dev/null
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc
@@ -0,0 +1,331 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.h"
+
+#include <memory>
+#include <utility>
+
+#include "third_party/blink/renderer/core/editing/position_with_affinity.h"
+#include "third_party/blink/renderer/core/layout/hit_test_location.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
+#include "third_party/blink/renderer/core/layout/ng/layout_box_utils.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.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/layout/ng/ng_layout_utils.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/layout/ng/ng_relative_utils.h"
+#include "third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h"
+#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
+#include "third_party/blink/renderer/core/paint/paint_layer.h"
+
+namespace blink {
+
+template <typename Base>
+LayoutNGBlockFlowMixin<Base>::LayoutNGBlockFlowMixin(Element* element)
+    : LayoutNGMixin<Base>(element) {
+  static_assert(std::is_base_of<LayoutBlockFlow, Base>::value,
+                "Base class of LayoutNGBlockFlowMixin must be LayoutBlockFlow "
+                "or derived class.");
+  DCHECK(!element || !element->ShouldForceLegacyLayout());
+}
+
+template <typename Base>
+LayoutNGBlockFlowMixin<Base>::~LayoutNGBlockFlowMixin() = default;
+
+template <typename Base>
+void LayoutNGBlockFlowMixin<Base>::StyleDidChange(
+    StyleDifference diff,
+    const ComputedStyle* old_style) {
+  Base::StyleDidChange(diff, old_style);
+
+  if (diff.NeedsCollectInlines()) {
+    Base::SetNeedsCollectInlines();
+  }
+}
+
+template <typename Base>
+NGInlineNodeData* LayoutNGBlockFlowMixin<Base>::TakeNGInlineNodeData() {
+  return ng_inline_node_data_.release();
+}
+
+template <typename Base>
+NGInlineNodeData* LayoutNGBlockFlowMixin<Base>::GetNGInlineNodeData() const {
+  DCHECK(ng_inline_node_data_);
+  return ng_inline_node_data_.get();
+}
+
+template <typename Base>
+void LayoutNGBlockFlowMixin<Base>::ResetNGInlineNodeData() {
+  ng_inline_node_data_ = std::make_unique<NGInlineNodeData>();
+}
+
+template <typename Base>
+void LayoutNGBlockFlowMixin<Base>::ClearNGInlineNodeData() {
+  ng_inline_node_data_.reset();
+}
+
+// The current fragment from the last layout cycle for this box.
+// When pre-NG layout calls functions of this block flow, fragment and/or
+// LayoutResult are required to compute the result.
+// TODO(kojii): Use the cached result for now, we may need to reconsider as the
+// cache evolves.
+template <typename Base>
+const NGPhysicalBoxFragment* LayoutNGBlockFlowMixin<Base>::CurrentFragment()
+    const {
+  const NGLayoutResult* cached_layout_result = Base::GetCachedLayoutResult();
+  if (!cached_layout_result)
+    return nullptr;
+
+  return &To<NGPhysicalBoxFragment>(cached_layout_result->PhysicalFragment());
+}
+
+template <typename Base>
+void LayoutNGBlockFlowMixin<Base>::AddLayoutOverflowFromChildren() {
+  // |ComputeOverflow()| calls this, which is called from
+  // |CopyFragmentDataToLayoutBox()| and |RecalcOverflow()|.
+  // Add overflow from the last layout cycle.
+  // TODO(chrishtr): do we need to condition on CurrentFragment()? Why?
+  if (CurrentFragment()) {
+    AddScrollingOverflowFromChildren();
+  }
+  Base::AddLayoutOverflowFromChildren();
+}
+
+template <typename Base>
+void LayoutNGBlockFlowMixin<Base>::AddScrollingOverflowFromChildren() {
+  bool children_inline = Base::ChildrenInline();
+
+  const NGPhysicalBoxFragment* physical_fragment = CurrentFragment();
+  DCHECK(physical_fragment);
+  // inline-end LayoutOverflow padding spec is still undecided:
+  // https://github.com/w3c/csswg-drafts/issues/129
+  // For backwards compatibility, if container clips overflow,
+  // padding is added to the inline-end for inline children.
+  base::Optional<NGPhysicalBoxStrut> padding_strut;
+  if (Base::HasOverflowClip()) {
+    padding_strut =
+        NGBoxStrut(LayoutUnit(), Base::PaddingEnd(), LayoutUnit(), LayoutUnit())
+            .ConvertToPhysical(Base::StyleRef().GetWritingMode(),
+                               Base::StyleRef().Direction());
+  }
+
+  PhysicalRect children_overflow;
+
+  // Only add overflow for fragments NG has not reflected into Legacy.
+  // These fragments are:
+  // - inline fragments,
+  // - out of flow fragments whose css container is inline box.
+  // TODO(layout-dev) Transforms also need to be applied to compute overflow
+  // correctly. NG is not yet transform-aware. crbug.com/855965
+  if (!physical_fragment->Children().empty()) {
+    LayoutUnit border_inline_start =
+        LayoutUnit(Base::StyleRef().BorderStartWidth());
+    LayoutUnit border_block_start =
+        LayoutUnit(Base::StyleRef().BorderBeforeWidth());
+    for (const auto& child : physical_fragment->Children()) {
+      PhysicalRect child_scrollable_overflow;
+      if (child->IsFloatingOrOutOfFlowPositioned()) {
+        child_scrollable_overflow =
+            child->ScrollableOverflowForPropagation(this);
+      } else if (children_inline && child->IsLineBox()) {
+        DCHECK(child->IsLineBox());
+        child_scrollable_overflow =
+            To<NGPhysicalLineBoxFragment>(*child).ScrollableOverflow(
+                this, Base::Style(), physical_fragment->Size());
+        if (padding_strut)
+          child_scrollable_overflow.Expand(*padding_strut);
+      } else {
+        continue;
+      }
+      child_scrollable_overflow.offset += child.Offset();
+
+      // Do not add overflow if fragment is not reachable by scrolling.
+      WritingMode writing_mode = Base::StyleRef().GetWritingMode();
+      LogicalOffset child_logical_end =
+          child_scrollable_overflow.offset.ConvertToLogical(
+              writing_mode, Base::StyleRef().Direction(),
+              physical_fragment->Size(), child_scrollable_overflow.size) +
+          child_scrollable_overflow.size.ConvertToLogical(writing_mode);
+
+      if (child_logical_end.inline_offset > border_inline_start &&
+          child_logical_end.block_offset > border_block_start)
+        children_overflow.Unite(child_scrollable_overflow);
+    }
+  }
+
+  // LayoutOverflow takes flipped blocks coordinates, adjust as needed.
+  LayoutRect children_flipped_overflow = children_overflow.ToLayoutFlippedRect(
+      physical_fragment->Style(), physical_fragment->Size());
+  Base::AddLayoutOverflow(children_flipped_overflow);
+}
+
+template <typename Base>
+void LayoutNGBlockFlowMixin<Base>::AddOutlineRects(
+    Vector<PhysicalRect>& rects,
+    const PhysicalOffset& additional_offset,
+    NGOutlineType include_block_overflows) const {
+  if (PaintFragment()) {
+    PaintFragment()->AddSelfOutlineRects(&rects, additional_offset,
+                                         include_block_overflows);
+  } else {
+    Base::AddOutlineRects(rects, additional_offset, include_block_overflows);
+  }
+}
+
+template <typename Base>
+bool LayoutNGBlockFlowMixin<
+    Base>::PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const {
+  // LayoutNGBlockFlowMixin is in charge of paint invalidation of the first
+  // line.
+  if (PaintFragment())
+    return false;
+
+  return Base::PaintedOutputOfObjectHasNoEffectRegardlessOfSize();
+}
+
+// Retrieve NGBaseline from the current fragment.
+template <typename Base>
+base::Optional<LayoutUnit> LayoutNGBlockFlowMixin<Base>::FragmentBaseline(
+    NGBaselineAlgorithmType type) const {
+  if (Base::ShouldApplyLayoutContainment())
+    return base::nullopt;
+
+  if (const NGPhysicalFragment* physical_fragment = CurrentFragment()) {
+    FontBaseline baseline_type = Base::StyleRef().GetFontBaseline();
+    return To<NGPhysicalBoxFragment>(physical_fragment)
+        ->Baseline({type, baseline_type});
+  }
+  return base::nullopt;
+}
+
+template <typename Base>
+LayoutUnit LayoutNGBlockFlowMixin<Base>::FirstLineBoxBaseline() const {
+  if (Base::ChildrenInline()) {
+    if (base::Optional<LayoutUnit> offset =
+            FragmentBaseline(NGBaselineAlgorithmType::kFirstLine)) {
+      return *offset;
+    }
+  }
+  return Base::FirstLineBoxBaseline();
+}
+
+template <typename Base>
+LayoutUnit LayoutNGBlockFlowMixin<Base>::InlineBlockBaseline(
+    LineDirectionMode line_direction) const {
+  if (Base::ChildrenInline()) {
+    if (base::Optional<LayoutUnit> offset =
+            FragmentBaseline(NGBaselineAlgorithmType::kAtomicInline)) {
+      return *offset;
+    }
+  }
+  return Base::InlineBlockBaseline(line_direction);
+}
+
+template <typename Base>
+void LayoutNGBlockFlowMixin<Base>::SetPaintFragment(
+    const NGBlockBreakToken* break_token,
+    scoped_refptr<const NGPhysicalFragment> fragment) {
+  DCHECK(!break_token || break_token->InputNode().GetLayoutBox() == this);
+
+  scoped_refptr<NGPaintFragment>* current =
+      NGPaintFragment::Find(&paint_fragment_, break_token);
+  DCHECK(current);
+  if (fragment) {
+    *current = NGPaintFragment::Create(std::move(fragment), break_token,
+                                       std::move(*current));
+    // |NGPaintFragment::Create()| calls |SlowSetPaintingLayerNeedsRepaint()|.
+  } else if (*current) {
+    DCHECK_EQ(this, (*current)->GetLayoutObject());
+    // TODO(kojii): Pass break_token for LayoutObject that spans across block
+    // fragmentation boundaries.
+    (*current)->ClearAssociationWithLayoutObject();
+    *current = nullptr;
+    ObjectPaintInvalidator(*this).SlowSetPaintingLayerNeedsRepaint();
+  }
+}
+
+template <typename Base>
+void LayoutNGBlockFlowMixin<Base>::Paint(const PaintInfo& paint_info) const {
+  if (const NGPaintFragment* paint_fragment = PaintFragment())
+    NGBoxFragmentPainter(*paint_fragment).Paint(paint_info);
+  else
+    LayoutBlockFlow::Paint(paint_info);
+}
+
+template <typename Base>
+bool LayoutNGBlockFlowMixin<Base>::NodeAtPoint(
+    HitTestResult& result,
+    const HitTestLocation& hit_test_location,
+    const PhysicalOffset& accumulated_offset,
+    HitTestAction action) {
+  const NGPaintFragment* paint_fragment = PaintFragment();
+  if (!paint_fragment) {
+    return LayoutBlockFlow::NodeAtPoint(result, hit_test_location,
+                                        accumulated_offset, action);
+  }
+
+  if (!this->IsEffectiveRootScroller()) {
+    // Check if we need to do anything at all.
+    // If we have clipping, then we can't have any spillout.
+    PhysicalRect overflow_box = Base::HasOverflowClip()
+                                    ? Base::PhysicalBorderBoxRect()
+                                    : Base::PhysicalVisualOverflowRect();
+    overflow_box.Move(accumulated_offset);
+    if (!hit_test_location.Intersects(overflow_box))
+      return false;
+  }
+  if (Base::IsInSelfHitTestingPhase(action) && Base::HasOverflowClip() &&
+      Base::HitTestOverflowControl(result, hit_test_location,
+                                   accumulated_offset))
+    return true;
+
+  return NGBoxFragmentPainter(*paint_fragment)
+      .NodeAtPoint(result, hit_test_location, accumulated_offset, action);
+}
+
+template <typename Base>
+PositionWithAffinity LayoutNGBlockFlowMixin<Base>::PositionForPoint(
+    const PhysicalOffset& point) const {
+  if (Base::IsAtomicInlineLevel()) {
+    const PositionWithAffinity atomic_inline_position =
+        Base::PositionForPointIfOutsideAtomicInlineLevel(point);
+    if (atomic_inline_position.IsNotNull())
+      return atomic_inline_position;
+  }
+
+  if (!Base::ChildrenInline())
+    return LayoutBlock::PositionForPoint(point);
+
+  if (!PaintFragment())
+    return Base::CreatePositionWithAffinity(0);
+
+  const PositionWithAffinity ng_position =
+      PaintFragment()->PositionForPoint(point);
+  if (ng_position.IsNotNull())
+    return ng_position;
+  return Base::CreatePositionWithAffinity(0);
+}
+
+template <typename Base>
+void LayoutNGBlockFlowMixin<Base>::DirtyLinesFromChangedChild(
+    LayoutObject* child,
+    MarkingBehavior marking_behavior) {
+  DCHECK_EQ(marking_behavior, kMarkContainerChain);
+
+  // We need to dirty line box fragments only if the child is once laid out in
+  // LayoutNG inline formatting context. New objects are handled in
+  // NGInlineNode::MarkLineBoxesDirty().
+  if (child->IsInLayoutNGInlineFormattingContext())
+    NGPaintFragment::DirtyLinesFromChangedChild(child);
+}
+
+template class CORE_TEMPLATE_EXPORT LayoutNGBlockFlowMixin<LayoutTableCaption>;
+template class CORE_TEMPLATE_EXPORT LayoutNGBlockFlowMixin<LayoutTableCell>;
+template class CORE_TEMPLATE_EXPORT LayoutNGBlockFlowMixin<LayoutBlockFlow>;
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.h b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.h
new file mode 100644
index 0000000..926c3395
--- /dev/null
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.h
@@ -0,0 +1,100 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LAYOUT_NG_BLOCK_FLOW_MIXIN_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LAYOUT_NG_BLOCK_FLOW_MIXIN_H_
+
+#include <type_traits>
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
+#include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
+#include "third_party/blink/renderer/core/layout/layout_table_caption.h"
+#include "third_party/blink/renderer/core/layout/layout_table_cell.h"
+#include "third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
+
+namespace blink {
+
+enum class NGBaselineAlgorithmType;
+class NGPaintFragment;
+class NGPhysicalFragment;
+struct NGInlineNodeData;
+
+// This mixin holds code shared between LayoutNG subclasses of LayoutBlockFlow.
+template <typename Base>
+class LayoutNGBlockFlowMixin : public LayoutNGMixin<Base> {
+ public:
+  explicit LayoutNGBlockFlowMixin(Element* element);
+  ~LayoutNGBlockFlowMixin() override;
+
+  NGInlineNodeData* TakeNGInlineNodeData() final;
+  NGInlineNodeData* GetNGInlineNodeData() const final;
+  void ResetNGInlineNodeData() final;
+  void ClearNGInlineNodeData() final;
+  bool HasNGInlineNodeData() const final { return ng_inline_node_data_.get(); }
+
+  LayoutUnit FirstLineBoxBaseline() const final;
+  LayoutUnit InlineBlockBaseline(LineDirectionMode) const final;
+
+  void Paint(const PaintInfo&) const final;
+
+  bool NodeAtPoint(HitTestResult&,
+                   const HitTestLocation&,
+                   const PhysicalOffset& accumulated_offset,
+                   HitTestAction) final;
+
+  PositionWithAffinity PositionForPoint(const PhysicalOffset&) const override;
+
+  const NGPaintFragment* PaintFragment() const final {
+    // TODO(layout-dev) crbug.com/963103
+    // Safer option here is to return nullptr only if
+    // Lifecycle > DocumentLifecycle::kAfterPerformLayout, but this breaks
+    // some layout tests.
+    if (Base::NeedsLayout())
+      return nullptr;
+    return paint_fragment_.get();
+  }
+  void SetPaintFragment(const NGBlockBreakToken*,
+                        scoped_refptr<const NGPhysicalFragment>) final;
+
+ protected:
+  void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
+
+  const NGPhysicalBoxFragment* CurrentFragment() const final;
+
+  void AddLayoutOverflowFromChildren() final;
+
+  void AddOutlineRects(Vector<PhysicalRect>&,
+                       const PhysicalOffset& additional_offset,
+                       NGOutlineType) const final;
+
+  bool PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const final;
+
+  base::Optional<LayoutUnit> FragmentBaseline(NGBaselineAlgorithmType) const;
+
+  void DirtyLinesFromChangedChild(LayoutObject* child,
+                                  MarkingBehavior marking_behavior) final;
+
+  std::unique_ptr<NGInlineNodeData> ng_inline_node_data_;
+  scoped_refptr<NGPaintFragment> paint_fragment_;
+
+  friend class NGBaseLayoutAlgorithmTest;
+
+ private:
+  void AddScrollingOverflowFromChildren();
+};
+
+// If you edit these export templates, also update templates in
+// layout_ng_mixin.h.
+extern template class CORE_EXTERN_TEMPLATE_EXPORT
+    LayoutNGBlockFlowMixin<LayoutBlockFlow>;
+extern template class CORE_EXTERN_TEMPLATE_EXPORT
+    LayoutNGBlockFlowMixin<LayoutTableCaption>;
+extern template class CORE_EXTERN_TEMPLATE_EXPORT
+    LayoutNGBlockFlowMixin<LayoutTableCell>;
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LAYOUT_NG_BLOCK_FLOW_MIXIN_H_
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.cc
index 6ca0936..51594e30 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.cc
@@ -14,13 +14,15 @@
 namespace blink {
 
 LayoutNGFlexibleBox::LayoutNGFlexibleBox(Element* element)
-    : LayoutBlock(element) {}
+    : LayoutNGMixin<LayoutBlock>(element) {}
 
 void LayoutNGFlexibleBox::UpdateBlockLayout(bool relayout_children) {
   LayoutAnalyzer::BlockScope analyzer(*this);
 
-  // TODO(dgrogan): Reuse logic from LayoutNGBlockFlow's
-  // UpdateOutOfFlowBlockLayout when this flexbox is out of flow.
+  if (IsOutOfFlowPositioned()) {
+    UpdateOutOfFlowBlockLayout();
+    return;
+  }
 
   NGConstraintSpace constraint_space =
       NGConstraintSpace::CreateFromLayoutObject(*this);
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.h b/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.h
index 091d5f6..c4c0fcf 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.h
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.h
@@ -7,10 +7,11 @@
 
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/layout/layout_block.h"
+#include "third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h"
 
 namespace blink {
 
-class CORE_EXPORT LayoutNGFlexibleBox : public LayoutBlock {
+class CORE_EXPORT LayoutNGFlexibleBox : public LayoutNGMixin<LayoutBlock> {
  public:
   explicit LayoutNGFlexibleBox(Element*);
 
@@ -18,12 +19,12 @@
 
   bool IsFlexibleBoxIncludingDeprecatedAndNG() const final { return true; }
   bool IsFlexibleBoxIncludingNG() const final { return true; }
-  bool IsLayoutNGObject() const override { return true; }
   const char* GetName() const override { return "LayoutNGFlexibleBox"; }
 
  protected:
   bool IsOfType(LayoutObjectType type) const override {
-    return type == kLayoutObjectNGFlexibleBox || LayoutBlock::IsOfType(type);
+    return type == kLayoutObjectNGFlexibleBox ||
+           LayoutNGMixin<LayoutBlock>::IsOfType(type);
   }
 };
 
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
index 65fa098..329b58b1 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
@@ -7,29 +7,22 @@
 #include <memory>
 #include <utility>
 
-#include "third_party/blink/renderer/core/editing/position_with_affinity.h"
-#include "third_party/blink/renderer/core/layout/hit_test_location.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
+#include "third_party/blink/renderer/core/layout/layout_view.h"
 #include "third_party/blink/renderer/core/layout/ng/layout_box_utils.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_layout_utils.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/layout/ng/ng_relative_utils.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
-#include "third_party/blink/renderer/core/paint/paint_layer.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h"
+#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
 
 namespace blink {
 
 template <typename Base>
 LayoutNGMixin<Base>::LayoutNGMixin(Element* element) : Base(element) {
   static_assert(
-      std::is_base_of<LayoutBlockFlow, Base>::value,
-      "Base class of LayoutNGMixin must be LayoutBlockFlow or derived class.");
+      std::is_base_of<LayoutBlock, Base>::value,
+      "Base class of LayoutNGMixin must be LayoutBlock or derived class.");
   DCHECK(!element || !element->ShouldForceLegacyLayout());
 }
 
@@ -42,51 +35,6 @@
 }
 
 template <typename Base>
-void LayoutNGMixin<Base>::StyleDidChange(StyleDifference diff,
-                                         const ComputedStyle* old_style) {
-  Base::StyleDidChange(diff, old_style);
-
-  if (diff.NeedsCollectInlines()) {
-    Base::SetNeedsCollectInlines();
-  }
-}
-
-template <typename Base>
-NGInlineNodeData* LayoutNGMixin<Base>::TakeNGInlineNodeData() {
-  return ng_inline_node_data_.release();
-}
-
-template <typename Base>
-NGInlineNodeData* LayoutNGMixin<Base>::GetNGInlineNodeData() const {
-  DCHECK(ng_inline_node_data_);
-  return ng_inline_node_data_.get();
-}
-
-template <typename Base>
-void LayoutNGMixin<Base>::ResetNGInlineNodeData() {
-  ng_inline_node_data_ = std::make_unique<NGInlineNodeData>();
-}
-
-template <typename Base>
-void LayoutNGMixin<Base>::ClearNGInlineNodeData() {
-  ng_inline_node_data_.reset();
-}
-
-// The current fragment from the last layout cycle for this box.
-// When pre-NG layout calls functions of this block flow, fragment and/or
-// LayoutResult are required to compute the result.
-// TODO(kojii): Use the cached result for now, we may need to reconsider as the
-// cache evolves.
-template <typename Base>
-const NGPhysicalBoxFragment* LayoutNGMixin<Base>::CurrentFragment() const {
-  const NGLayoutResult* cached_layout_result = Base::GetCachedLayoutResult();
-  if (!cached_layout_result)
-    return nullptr;
-
-  return &To<NGPhysicalBoxFragment>(cached_layout_result->PhysicalFragment());
-}
-
-template <typename Base>
 void LayoutNGMixin<Base>::ComputeIntrinsicLogicalWidths(
     LayoutUnit& min_logical_width,
     LayoutUnit& max_logical_width) const {
@@ -123,245 +71,126 @@
 }
 
 template <typename Base>
-void LayoutNGMixin<Base>::AddLayoutOverflowFromChildren() {
-  // |ComputeOverflow()| calls this, which is called from
-  // |CopyFragmentDataToLayoutBox()| and |RecalcOverflow()|.
-  // Add overflow from the last layout cycle.
-  // TODO(chrishtr): do we need to condition on CurrentFragment()? Why?
-  if (CurrentFragment()) {
-    AddScrollingOverflowFromChildren();
-  }
-  Base::AddLayoutOverflowFromChildren();
-}
+void LayoutNGMixin<Base>::UpdateOutOfFlowBlockLayout() {
+  LayoutBoxModelObject* css_container =
+      ToLayoutBoxModelObject(Base::Container());
+  LayoutBox* container = css_container->IsBox() ? ToLayoutBox(css_container)
+                                                : Base::ContainingBlock();
+  const ComputedStyle* container_style = container->Style();
+  NGConstraintSpace constraint_space =
+      NGConstraintSpace::CreateFromLayoutObject(*this);
 
-template <typename Base>
-void LayoutNGMixin<Base>::AddScrollingOverflowFromChildren() {
-  bool children_inline = Base::ChildrenInline();
+  // As this is part of the Legacy->NG bridge, the container_builder is used
+  // for indicating the resolved size of the OOF-positioned containing-block
+  // and not used for caching purposes.
+  // When we produce a layout result from it, we access its child fragments
+  // which must contain *at least* this node. We use the child fragments for
+  // copying back position information.
+  NGBlockNode container_node(container);
+  NGBoxFragmentBuilder container_builder(
+      container_node, scoped_refptr<const ComputedStyle>(container_style),
+      /* space */ nullptr, container_style->GetWritingMode(),
+      container_style->Direction());
+  container_builder.SetIsNewFormattingContext(
+      container_node.CreatesNewFormattingContext());
 
-  const NGPhysicalBoxFragment* physical_fragment = CurrentFragment();
-  DCHECK(physical_fragment);
-  // inline-end LayoutOverflow padding spec is still undecided:
-  // https://github.com/w3c/csswg-drafts/issues/129
-  // For backwards compatibility, if container clips overflow,
-  // padding is added to the inline-end for inline children.
-  base::Optional<NGPhysicalBoxStrut> padding_strut;
-  if (Base::HasOverflowClip()) {
-    padding_strut =
-        NGBoxStrut(LayoutUnit(), Base::PaddingEnd(), LayoutUnit(), LayoutUnit())
-            .ConvertToPhysical(Base::StyleRef().GetWritingMode(),
-                               Base::StyleRef().Direction());
-  }
+  NGFragmentGeometry fragment_geometry;
+  fragment_geometry.border = ComputeBorders(constraint_space, container_node);
+  fragment_geometry.scrollbar =
+      ComputeScrollbars(constraint_space, container_node);
+  fragment_geometry.padding =
+      ComputePadding(constraint_space, *container_style);
 
-  PhysicalRect children_overflow;
+  NGBoxStrut border_scrollbar =
+      fragment_geometry.border + fragment_geometry.scrollbar;
 
-  // Only add overflow for fragments NG has not reflected into Legacy.
-  // These fragments are:
-  // - inline fragments,
-  // - out of flow fragments whose css container is inline box.
-  // TODO(layout-dev) Transfroms also need to be applied to compute overflow
-  // correctly. NG is not yet transform-aware. crbug.com/855965
-  if (!physical_fragment->Children().empty()) {
-    LayoutUnit border_inline_start =
-        LayoutUnit(Base::StyleRef().BorderStartWidth());
-    LayoutUnit border_block_start =
-        LayoutUnit(Base::StyleRef().BorderBeforeWidth());
-    for (const auto& child : physical_fragment->Children()) {
-      PhysicalRect child_scrollable_overflow;
-      if (child->IsFloatingOrOutOfFlowPositioned()) {
-        child_scrollable_overflow =
-            child->ScrollableOverflowForPropagation(this);
-      } else if (children_inline && child->IsLineBox()) {
-        DCHECK(child->IsLineBox());
-        child_scrollable_overflow =
-            To<NGPhysicalLineBoxFragment>(*child).ScrollableOverflow(
-                this, Base::Style(), physical_fragment->Size());
-        if (padding_strut)
-          child_scrollable_overflow.Expand(*padding_strut);
-      } else {
-        continue;
-      }
-      child_scrollable_overflow.offset += child.Offset();
-
-      // Do not add overflow if fragment is not reachable by scrolling.
-      WritingMode writing_mode = Base::StyleRef().GetWritingMode();
-      LogicalOffset child_logical_end =
-          child_scrollable_overflow.offset.ConvertToLogical(
-              writing_mode, Base::StyleRef().Direction(),
-              physical_fragment->Size(), child_scrollable_overflow.size) +
-          child_scrollable_overflow.size.ConvertToLogical(writing_mode);
-
-      if (child_logical_end.inline_offset > border_inline_start &&
-          child_logical_end.block_offset > border_block_start)
-        children_overflow.Unite(child_scrollable_overflow);
-    }
-  }
-
-  // LayoutOverflow takes flipped blocks coordinates, adjust as needed.
-  LayoutRect children_flipped_overflow = children_overflow.ToLayoutFlippedRect(
-      physical_fragment->Style(), physical_fragment->Size());
-  Base::AddLayoutOverflow(children_flipped_overflow);
-}
-
-template <typename Base>
-void LayoutNGMixin<Base>::AddOutlineRects(
-    Vector<PhysicalRect>& rects,
-    const PhysicalOffset& additional_offset,
-    NGOutlineType include_block_overflows) const {
-  if (PaintFragment()) {
-    PaintFragment()->AddSelfOutlineRects(&rects, additional_offset,
-                                         include_block_overflows);
+  // Calculate the border-box size of the object that's the containing block of
+  // this out-of-flow positioned descendant. Note that this is not to be used as
+  // the containing block size to resolve sizes and positions for the
+  // descendant, since we're dealing with the border box here (not the padding
+  // box, which is where the containing block is established). These sizes are
+  // just used to do a fake/partial NG layout pass of the containing block (that
+  // object is really managed by legacy layout).
+  LayoutUnit container_border_box_logical_width;
+  LayoutUnit container_border_box_logical_height;
+  if (Base::HasOverrideContainingBlockContentLogicalWidth()) {
+    container_border_box_logical_width =
+        Base::OverrideContainingBlockContentLogicalWidth() +
+        border_scrollbar.InlineSum();
   } else {
-    Base::AddOutlineRects(rects, additional_offset, include_block_overflows);
+    container_border_box_logical_width = container->LogicalWidth();
   }
-}
-
-template <typename Base>
-bool LayoutNGMixin<Base>::PaintedOutputOfObjectHasNoEffectRegardlessOfSize()
-    const {
-  // LayoutNGMixin is in charge of paint invalidation of the first line.
-  if (PaintFragment())
-    return false;
-
-  return Base::PaintedOutputOfObjectHasNoEffectRegardlessOfSize();
-}
-
-// Retrieve NGBaseline from the current fragment.
-template <typename Base>
-base::Optional<LayoutUnit> LayoutNGMixin<Base>::FragmentBaseline(
-    NGBaselineAlgorithmType type) const {
-  if (Base::ShouldApplyLayoutContainment())
-    return base::nullopt;
-
-  if (const NGPhysicalFragment* physical_fragment = CurrentFragment()) {
-    FontBaseline baseline_type = Base::StyleRef().GetFontBaseline();
-    return To<NGPhysicalBoxFragment>(physical_fragment)
-        ->Baseline({type, baseline_type});
+  if (Base::HasOverrideContainingBlockContentLogicalHeight()) {
+    container_border_box_logical_height =
+        Base::OverrideContainingBlockContentLogicalHeight() +
+        border_scrollbar.BlockSum();
+  } else {
+    container_border_box_logical_height = container->LogicalHeight();
   }
-  return base::nullopt;
-}
 
-template <typename Base>
-LayoutUnit LayoutNGMixin<Base>::FirstLineBoxBaseline() const {
-  if (Base::ChildrenInline()) {
-    if (base::Optional<LayoutUnit> offset =
-            FragmentBaseline(NGBaselineAlgorithmType::kFirstLine)) {
-      return *offset;
+  fragment_geometry.border_box_size = {container_border_box_logical_width,
+                                       container_border_box_logical_height};
+  container_builder.SetInitialFragmentGeometry(fragment_geometry);
+
+  NGLogicalStaticPosition static_position =
+      LayoutBoxUtils::ComputeStaticPositionFromLegacy(*this, border_scrollbar);
+  // Set correct container for inline containing blocks.
+  container_builder.AddOutOfFlowLegacyCandidate(
+      NGBlockNode(this), static_position, ToLayoutInlineOrNull(css_container));
+
+  base::Optional<LogicalSize> initial_containing_block_fixed_size;
+  if (container->IsLayoutView() && !Base::GetDocument().Printing()) {
+    if (LocalFrameView* frame_view = ToLayoutView(container)->GetFrameView()) {
+      IntSize size =
+          frame_view->LayoutViewport()->ExcludeScrollbars(frame_view->Size());
+      PhysicalSize physical_size(size);
+      initial_containing_block_fixed_size =
+          physical_size.ConvertToLogical(container->Style()->GetWritingMode());
     }
   }
-  return Base::FirstLineBoxBaseline();
-}
+  // We really only want to lay out ourselves here, so we pass |this| to
+  // Run(). Otherwise, NGOutOfFlowLayoutPart may also lay out other objects
+  // it discovers that are part of the same containing block, but those
+  // should get laid out by the actual containing block.
+  NGOutOfFlowLayoutPart(css_container->CanContainAbsolutePositionObjects(),
+                        css_container->CanContainFixedPositionObjects(),
+                        *container_style, constraint_space, border_scrollbar,
+                        &container_builder, initial_containing_block_fixed_size)
+      .Run(/* only_layout */ this);
+  scoped_refptr<const NGLayoutResult> result =
+      container_builder.ToBoxFragment();
+  // These are the unpositioned OOF descendants of the current OOF block.
+  for (const auto& descendant :
+       result->PhysicalFragment().OutOfFlowPositionedDescendants())
+    descendant.node.UseLegacyOutOfFlowPositioning();
 
-template <typename Base>
-LayoutUnit LayoutNGMixin<Base>::InlineBlockBaseline(
-    LineDirectionMode line_direction) const {
-  if (Base::ChildrenInline()) {
-    if (base::Optional<LayoutUnit> offset =
-            FragmentBaseline(NGBaselineAlgorithmType::kAtomicInline)) {
-      return *offset;
+  const auto& fragment = result->PhysicalFragment();
+  DCHECK_GT(fragment.Children().size(), 0u);
+  // Copy sizes of all child fragments to Legacy.
+  // There could be multiple fragments, when this node has descendants whose
+  // container is this node's container.
+  // Example: fixed descendant of fixed element.
+  for (auto& child : fragment.Children()) {
+    const NGPhysicalFragment* child_fragment = child.get();
+    DCHECK(child_fragment->GetLayoutObject()->IsBox());
+    LayoutBox* child_legacy_box =
+        ToLayoutBox(child_fragment->GetMutableLayoutObject());
+    PhysicalOffset child_offset = child.Offset();
+    if (container_style->IsFlippedBlocksWritingMode()) {
+      child_legacy_box->SetX(container_border_box_logical_height -
+                             child_offset.left - child_fragment->Size().width);
+    } else {
+      child_legacy_box->SetX(child_offset.left);
     }
+    child_legacy_box->SetY(child_offset.top);
   }
-  return Base::InlineBlockBaseline(line_direction);
+  DCHECK_EQ(fragment.Children()[0]->GetLayoutObject(), this);
+  Base::SetIsLegacyInitiatedOutOfFlowLayout(true);
 }
 
-template <typename Base>
-void LayoutNGMixin<Base>::SetPaintFragment(
-    const NGBlockBreakToken* break_token,
-    scoped_refptr<const NGPhysicalFragment> fragment) {
-  DCHECK(!break_token || break_token->InputNode().GetLayoutBox() == this);
-
-  scoped_refptr<NGPaintFragment>* current =
-      NGPaintFragment::Find(&paint_fragment_, break_token);
-  DCHECK(current);
-  if (fragment) {
-    *current = NGPaintFragment::Create(std::move(fragment), break_token,
-                                       std::move(*current));
-    // |NGPaintFragment::Create()| calls |SlowSetPaintingLayerNeedsRepaint()|.
-  } else if (*current) {
-    DCHECK_EQ(this, (*current)->GetLayoutObject());
-    // TODO(kojii): Pass break_token for LayoutObject that spans across block
-    // fragmentation boundaries.
-    (*current)->ClearAssociationWithLayoutObject();
-    *current = nullptr;
-    ObjectPaintInvalidator(*this).SlowSetPaintingLayerNeedsRepaint();
-  }
-}
-
-template <typename Base>
-void LayoutNGMixin<Base>::Paint(const PaintInfo& paint_info) const {
-  if (const NGPaintFragment* paint_fragment = PaintFragment())
-    NGBoxFragmentPainter(*paint_fragment).Paint(paint_info);
-  else
-    LayoutBlockFlow::Paint(paint_info);
-}
-
-template <typename Base>
-bool LayoutNGMixin<Base>::NodeAtPoint(HitTestResult& result,
-                                      const HitTestLocation& hit_test_location,
-                                      const PhysicalOffset& accumulated_offset,
-                                      HitTestAction action) {
-  const NGPaintFragment* paint_fragment = PaintFragment();
-  if (!paint_fragment) {
-    return LayoutBlockFlow::NodeAtPoint(result, hit_test_location,
-                                        accumulated_offset, action);
-  }
-
-  if (!this->IsEffectiveRootScroller()) {
-    // Check if we need to do anything at all.
-    // If we have clipping, then we can't have any spillout.
-    PhysicalRect overflow_box = Base::HasOverflowClip()
-                                    ? Base::PhysicalBorderBoxRect()
-                                    : Base::PhysicalVisualOverflowRect();
-    overflow_box.Move(accumulated_offset);
-    if (!hit_test_location.Intersects(overflow_box))
-      return false;
-  }
-  if (Base::IsInSelfHitTestingPhase(action) && Base::HasOverflowClip() &&
-      Base::HitTestOverflowControl(result, hit_test_location,
-                                   accumulated_offset))
-    return true;
-
-  return NGBoxFragmentPainter(*paint_fragment)
-      .NodeAtPoint(result, hit_test_location, accumulated_offset, action);
-}
-
-template <typename Base>
-PositionWithAffinity LayoutNGMixin<Base>::PositionForPoint(
-    const PhysicalOffset& point) const {
-  if (Base::IsAtomicInlineLevel()) {
-    const PositionWithAffinity atomic_inline_position =
-        Base::PositionForPointIfOutsideAtomicInlineLevel(point);
-    if (atomic_inline_position.IsNotNull())
-      return atomic_inline_position;
-  }
-
-  if (!Base::ChildrenInline())
-    return LayoutBlock::PositionForPoint(point);
-
-  if (!PaintFragment())
-    return Base::CreatePositionWithAffinity(0);
-
-  const PositionWithAffinity ng_position =
-      PaintFragment()->PositionForPoint(point);
-  if (ng_position.IsNotNull())
-    return ng_position;
-  return Base::CreatePositionWithAffinity(0);
-}
-
-template <typename Base>
-void LayoutNGMixin<Base>::DirtyLinesFromChangedChild(
-    LayoutObject* child,
-    MarkingBehavior marking_behavior) {
-  DCHECK_EQ(marking_behavior, kMarkContainerChain);
-
-  // We need to dirty line box fragments only if the child is once laid out in
-  // LayoutNG inline formatting context. New objects are handled in
-  // NGInlineNode::MarkLineBoxesDirty().
-  if (child->IsInLayoutNGInlineFormattingContext())
-    NGPaintFragment::DirtyLinesFromChangedChild(child);
-}
-
+template class CORE_TEMPLATE_EXPORT LayoutNGMixin<LayoutBlock>;
+template class CORE_TEMPLATE_EXPORT LayoutNGMixin<LayoutBlockFlow>;
 template class CORE_TEMPLATE_EXPORT LayoutNGMixin<LayoutTableCaption>;
 template class CORE_TEMPLATE_EXPORT LayoutNGMixin<LayoutTableCell>;
-template class CORE_TEMPLATE_EXPORT LayoutNGMixin<LayoutBlockFlow>;
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h
index 53d3b9b..57eea64 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h
@@ -9,21 +9,13 @@
 
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/layout/layout_block_flow.h"
-#include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
 #include "third_party/blink/renderer/core/layout/layout_table_caption.h"
 #include "third_party/blink/renderer/core/layout/layout_table_cell.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
 
 namespace blink {
 
-enum class NGBaselineAlgorithmType;
-class NGPaintFragment;
-class NGPhysicalFragment;
-struct NGInlineNodeData;
-
 // This mixin holds code shared between LayoutNG subclasses of
-// LayoutBlockFlow.
-
+// LayoutBlock.
 template <typename Base>
 class LayoutNGMixin : public Base {
  public:
@@ -32,69 +24,17 @@
 
   bool IsLayoutNGObject() const final { return true; }
 
-  NGInlineNodeData* TakeNGInlineNodeData() final;
-  NGInlineNodeData* GetNGInlineNodeData() const final;
-  void ResetNGInlineNodeData() final;
-  void ClearNGInlineNodeData() final;
-  bool HasNGInlineNodeData() const final { return ng_inline_node_data_.get(); }
-
-  LayoutUnit FirstLineBoxBaseline() const final;
-  LayoutUnit InlineBlockBaseline(LineDirectionMode) const final;
-
-  void Paint(const PaintInfo&) const final;
-
-  bool NodeAtPoint(HitTestResult&,
-                   const HitTestLocation&,
-                   const PhysicalOffset& accumulated_offset,
-                   HitTestAction) final;
-
-  PositionWithAffinity PositionForPoint(const PhysicalOffset&) const override;
-
-  const NGPaintFragment* PaintFragment() const final {
-    // TODO(layout-dev) crbug.com/963103
-    // Safer option here is to return nullptr only if
-    // Lifecycle > DocumentLifecycle::kAfterPerformLayout, but this breaks
-    // some layout tests.
-    if (Base::NeedsLayout())
-      return nullptr;
-    return paint_fragment_.get();
-  }
-  void SetPaintFragment(const NGBlockBreakToken*,
-                        scoped_refptr<const NGPhysicalFragment>) final;
-
  protected:
   bool IsOfType(LayoutObject::LayoutObjectType) const override;
 
-  void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
-
   void ComputeIntrinsicLogicalWidths(
       LayoutUnit& min_logical_width,
       LayoutUnit& max_logical_width) const override;
 
-  void AddLayoutOverflowFromChildren() final;
-
-  void AddOutlineRects(Vector<PhysicalRect>&,
-                       const PhysicalOffset& additional_offset,
-                       NGOutlineType) const final;
-
-  bool PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const final;
-
-  const NGPhysicalBoxFragment* CurrentFragment() const final;
-
-  base::Optional<LayoutUnit> FragmentBaseline(NGBaselineAlgorithmType) const;
-
-  void DirtyLinesFromChangedChild(LayoutObject* child,
-                                  MarkingBehavior marking_behavior) final;
-
-  std::unique_ptr<NGInlineNodeData> ng_inline_node_data_;
-  scoped_refptr<NGPaintFragment> paint_fragment_;
-
-  friend class NGBaseLayoutAlgorithmTest;
-
- private:
-  void AddScrollingOverflowFromChildren();
+  void UpdateOutOfFlowBlockLayout();
 };
 
+extern template class CORE_EXTERN_TEMPLATE_EXPORT LayoutNGMixin<LayoutBlock>;
 extern template class CORE_EXTERN_TEMPLATE_EXPORT
     LayoutNGMixin<LayoutBlockFlow>;
 extern template class CORE_EXTERN_TEMPLATE_EXPORT
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.cc
index 7976107..e1fbe037 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.cc
@@ -16,7 +16,7 @@
 namespace blink {
 
 LayoutNGTableCaption::LayoutNGTableCaption(Element* element)
-    : LayoutNGMixin<LayoutTableCaption>(element) {}
+    : LayoutNGBlockFlowMixin<LayoutTableCaption>(element) {}
 
 void LayoutNGTableCaption::CalculateAndSetMargins(
     const NGConstraintSpace& constraint_space,
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.h b/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.h
index 1ea6e59..35ee8e2d7 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.h
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.h
@@ -7,12 +7,12 @@
 
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/layout/layout_table_caption.h"
-#include "third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h"
+#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.h"
 
 namespace blink {
 
 class CORE_EXPORT LayoutNGTableCaption final
-    : public LayoutNGMixin<LayoutTableCaption> {
+    : public LayoutNGBlockFlowMixin<LayoutTableCaption> {
  public:
   explicit LayoutNGTableCaption(Element*);
 
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_table_cell.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_table_cell.cc
index 04411a9a..6b8c2da 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_table_cell.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_table_cell.cc
@@ -15,7 +15,7 @@
 namespace blink {
 
 LayoutNGTableCell::LayoutNGTableCell(Element* element)
-    : LayoutNGMixin<LayoutTableCell>(element) {}
+    : LayoutNGBlockFlowMixin<LayoutTableCell>(element) {}
 
 void LayoutNGTableCell::UpdateBlockLayout(bool relayout_children) {
   LayoutAnalyzer::BlockScope analyzer(*this);
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_table_cell.h b/third_party/blink/renderer/core/layout/ng/layout_ng_table_cell.h
index eb8c2cc..d51ed5338 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_table_cell.h
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_table_cell.h
@@ -7,12 +7,12 @@
 
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/layout/layout_table_cell.h"
-#include "third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h"
+#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.h"
 
 namespace blink {
 
 class CORE_EXPORT LayoutNGTableCell final
-    : public LayoutNGMixin<LayoutTableCell> {
+    : public LayoutNGBlockFlowMixin<LayoutTableCell> {
  public:
   explicit LayoutNGTableCell(Element*);
 
diff --git a/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h b/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h
index 7d8327a..82ea95e 100644
--- a/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h
+++ b/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h
@@ -90,14 +90,13 @@
 inline bool IsLayoutNGContainingBlock(const LayoutBlock* containing_block) {
   if (UNLIKELY(containing_block->IsLayoutFlowThread()))
     containing_block = containing_block->ContainingBlock();
-  return containing_block && (containing_block->IsLayoutNGMixin() ||
-                              containing_block->IsLayoutNGFlexibleBox());
+  return containing_block && containing_block->IsLayoutNGMixin();
 }
 
 // Return true if the layout object is a LayoutNG object that is managed by the
 // LayoutNG engine (i.e. its containing block is a LayoutNG object as well).
 inline bool IsManagedByLayoutNG(const LayoutObject& object) {
-  if (!object.IsLayoutNGMixin() && !object.IsLayoutNGFlexibleBox())
+  if (!object.IsLayoutNGMixin())
     return false;
   const auto* containing_block = object.ContainingBlock();
   if (UNLIKELY(!containing_block))
diff --git a/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker.cc b/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker.cc
index 71e648a4c6..06b7732 100644
--- a/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker.cc
+++ b/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker.cc
@@ -10,7 +10,7 @@
 namespace blink {
 
 LayoutNGListMarker::LayoutNGListMarker(Element* element)
-    : LayoutNGMixin<LayoutBlockFlow>(element) {}
+    : LayoutNGBlockFlowMixin<LayoutBlockFlow>(element) {}
 
 LayoutNGListMarker* LayoutNGListMarker::CreateAnonymous(Document* document) {
   LayoutNGListMarker* object = new LayoutNGListMarker(nullptr);
diff --git a/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker.h b/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker.h
index 6b9ac9777..d317122 100644
--- a/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker.h
+++ b/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker.h
@@ -7,7 +7,7 @@
 
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/layout/layout_block_flow.h"
-#include "third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h"
+#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.h"
 
 namespace blink {
 
@@ -15,7 +15,7 @@
 
 // A LayoutObject subclass for outside-positioned list markers in LayoutNG.
 class CORE_EXPORT LayoutNGListMarker final
-    : public LayoutNGMixin<LayoutBlockFlow> {
+    : public LayoutNGBlockFlowMixin<LayoutBlockFlow> {
  public:
   explicit LayoutNGListMarker(Element*);
   static LayoutNGListMarker* CreateAnonymous(Document*);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
index 200a46e0..a6d98d5 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
@@ -669,7 +669,7 @@
   DCHECK(RuntimeEnabledFeatures::LayoutNGEnabled());
   if (box.ForceLegacyLayout())
     return false;
-  return box.IsLayoutNGMixin() || box.IsLayoutNGFlexibleBox();
+  return box.IsLayoutNGMixin();
 }
 
 bool NGBlockNode::CanUseNewLayout() 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 51867b3..4d88bbcf1 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
@@ -342,7 +342,7 @@
   const LayoutBlock* container = layout_object_.ContainingBlock();
   if (!container)
     return false;
-  return container->IsLayoutNGMixin() || container->IsLayoutNGFlexibleBox();
+  return container->IsLayoutNGMixin();
 }
 
 const NGPhysicalFragment* NGPhysicalFragment::PostLayout() const {
diff --git a/third_party/blink/renderer/devtools/front_end/sources/WatchExpressionsSidebarPane.js b/third_party/blink/renderer/devtools/front_end/sources/WatchExpressionsSidebarPane.js
index f709857..7373762 100644
--- a/third_party/blink/renderer/devtools/front_end/sources/WatchExpressionsSidebarPane.js
+++ b/third_party/blink/renderer/devtools/front_end/sources/WatchExpressionsSidebarPane.js
@@ -43,9 +43,9 @@
     this._watchExpressions = [];
     this._watchExpressionsSetting = Common.settings.createLocalSetting('watchExpressions', []);
 
-    this._addButton = new UI.ToolbarButton(Common.UIString('Add expression'), 'largeicon-add');
+    this._addButton = new UI.ToolbarButton(ls`Add watch expression`, 'largeicon-add');
     this._addButton.addEventListener(UI.ToolbarButton.Events.Click, this._addButtonClicked.bind(this));
-    this._refreshButton = new UI.ToolbarButton(Common.UIString('Refresh'), 'largeicon-refresh');
+    this._refreshButton = new UI.ToolbarButton(ls`Refresh watch expressions`, 'largeicon-refresh');
     this._refreshButton.addEventListener(UI.ToolbarButton.Events.Click, this.update, this);
 
     this.contentElement.classList.add('watch-expressions');
diff --git a/third_party/blink/renderer/devtools/front_end/sources/sources_strings.grdp b/third_party/blink/renderer/devtools/front_end/sources/sources_strings.grdp
index 2ea41cf..d3ff40b 100644
--- a/third_party/blink/renderer/devtools/front_end/sources/sources_strings.grdp
+++ b/third_party/blink/renderer/devtools/front_end/sources/sources_strings.grdp
@@ -114,9 +114,6 @@
   <message name="IDS_DEVTOOLS_3831f64f248899a06a6bbc8b82fccfdf" desc="Text in Breakpoint Edit Dialog of the Sources panel">
     Log message, e.g. &apos;x is&apos;, x
   </message>
-  <message name="IDS_DEVTOOLS_38b6dddcf45b3d2c9fc86ce4dd2592ba" desc="Tooltip text that appears when hovering over the largeicon add button in the Watch Expressions Sidebar Pane of the Sources panel">
-    Add expression
-  </message>
   <message name="IDS_DEVTOOLS_3a4c2017c43ba6b63be4576d17893645" desc="Text in Debugger Plugin of the Sources panel">
     Source map found, but ignored for blackboxed file.
   </message>
@@ -477,6 +474,9 @@
   <message name="IDS_DEVTOOLS_f0a47f037ca7a988466a647277ef1134" desc="Text in Debugger Paused Message of the Sources panel">
     Paused on assertion
   </message>
+  <message name="IDS_DEVTOOLS_f156b89abea73d4db0bf1b212d198c41" desc="Tooltip/screen reader label of a button in the Sources panel that refreshes all watch expressions.">
+    Refresh watch expressions
+  </message>
   <message name="IDS_DEVTOOLS_f20658650d987d31063b593c05980397" desc="Title of the sources watch">
     Watch
   </message>
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 2518c0f1..cb70c28 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -485,6 +485,7 @@
     },
     {
       name: "DisplayLocking",
+      status: "experimental",
     },
     {
       name: "DocumentCookie",
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-features=NavigationLoaderOnUI b/third_party/blink/web_tests/FlagExpectations/enable-features=NavigationLoaderOnUI
index dc1cb837..edc53d75 100644
--- a/third_party/blink/web_tests/FlagExpectations/enable-features=NavigationLoaderOnUI
+++ b/third_party/blink/web_tests/FlagExpectations/enable-features=NavigationLoaderOnUI
@@ -6,11 +6,4 @@
 Bug(none) virtual/not-omt-sw-fetch/external/wpt/html/browsers/offline/appcache/workers/appcache-worker.https.html [ Skip ]
 Bug(none) virtual/omt-worker-fetch/external/wpt/html/browsers/offline/appcache/workers/appcache-worker.https.html [ Skip ]
 
-# signed exchange
-Bug(none) external/wpt/signed-exchange [ Skip ]
-Bug(none) virtual/sxg-subresource [ Skip ]
-Bug(none) virtual/sxg-with-network-service [ Skip ]
-Bug(none) http/tests/devtools/sxg [ Skip ]
-Bug(none) http/tests/loading/sxg [ Skip ]
-
 Bug(none) http/tests/misc/xhtml.php [ Failure ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 166d30a..8553810b 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -234,21 +234,19 @@
 
 crbug.com/980969 [ Mac ] http/tests/input/discard-events-to-unstable-iframe.html [ Pass Failure ]
 
-# Display locking, currently only available via a virtual test.
-crbug.com/882663 wpt_internal/display-lock [ Skip ]
-
 # Display locking, run highlight-display-locked.js only with display locking.
 crbug.com/882663 http/tests/devtools/elements/highlight/highlight-display-locked.js [ Skip ]
-crbug.com/882663 virtual/display-lock/http/tests/devtools/elements/highlight [ Skip ]
-Bug(none) virtual/display-lock/http/tests/devtools/elements/highlight/highlight-display-locked.js [ Pass ]
+crbug.com/882663 http/tests/devtools/elements/highlight [ Skip ]
 
 # Display locking, run css-get-platform-fonts-display-locked.js only with display locking.
 crbug.com/882663 inspector-protocol/css/css-get-platform-fonts-display-locked.js [ Skip ]
-crbug.com/882663 virtual/display-lock/inspector-protocol/css [ Skip ]
-Bug(none) virtual/display-lock/inspector-protocol/css/css-get-platform-fonts-display-locked.js [ Pass ]
+crbug.com/882663 inspector-protocol/css [ Skip ]
 
 # Display locking failures
-crbug.com/955533 virtual/display-lock/wpt_internal/display-lock/sizing/overflow-auto-with-overflow.html [ Failure ]
+crbug.com/955533 wpt_internal/display-lock/sizing/overflow-auto-with-overflow.html [ Failure ]
+
+# virtual-scroller failures
+crbug.com/986574 wpt_internal/virtual-scroller/ [ Failure ]
 
 # Sheriff 2018/05/25
 crbug.com/846747 http/tests/navigation/navigation-interrupted-by-fragment.html  [ Pass Timeout ]
@@ -593,9 +591,11 @@
 crbug.com/880802 virtual/layout_ng_experimental/external/wpt/css/css-contain/contain-paint-021.html [ Failure ]
 crbug.com/882367 virtual/layout_ng_experimental/external/wpt/css/css-contain/contain-paint-clip-015.html [ Failure ]
 crbug.com/882367 virtual/layout_ng_experimental/external/wpt/css/css-contain/contain-paint-clip-016.html [ Failure ]
+crbug.com/845235 virtual/layout_ng_experimental/external/wpt/css/css-contain/contain-size-flexbox-001.html [ Failure ]
 crbug.com/955170 virtual/layout_ng_experimental/external/wpt/css/css-contain/contain-size-replaced-003a.html [ Failure ]
 crbug.com/955163 virtual/layout_ng_experimental/external/wpt/css/css-contain/contain-size-replaced-003b.html [ Failure ]
 crbug.com/955163 virtual/layout_ng_experimental/external/wpt/css/css-contain/contain-size-replaced-003c.html [ Failure ]
+crbug.com/845235 virtual/layout_ng_experimental/external/wpt/css/css-contain/contain-size-scrollbars-002.html [ Failure ]
 crbug.com/882383 virtual/layout_ng_experimental/external/wpt/css/css-contain/counter-scoping-001.html [ Failure ]
 crbug.com/882383 virtual/layout_ng_experimental/external/wpt/css/css-contain/counter-scoping-002.html [ Failure ]
 crbug.com/882383 virtual/layout_ng_experimental/external/wpt/css/css-contain/counter-scoping-003.html [ Failure ]
@@ -609,6 +609,8 @@
 crbug.com/880802 virtual/layout_ng_experimental/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-paint-ignored-cases-ruby-stacking-and-clipping-001.html [ Failure ]
 crbug.com/881057 virtual/layout_ng_experimental/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-paint-stacking-context-001b.html [ Failure ]
 crbug.com/965491 virtual/layout_ng_experimental/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-fieldset-002.html [ Failure ]
+crbug.com/845235 virtual/layout_ng_experimental/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-flex-001.html [ Failure ]
+crbug.com/845235 virtual/layout_ng_experimental/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-flex-001.html [ Failure ]
 
 # [css-align]
 
@@ -2032,7 +2034,6 @@
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_flow-column-wrap-reverse.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_flow-column-wrap.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_flow-row-wrap-reverse.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_inline-abspos.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_inline.html [ Failure ]
 crbug.com/467127 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_justifycontent-center-overflow.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_margin-collapse.html [ Failure ]
@@ -3236,6 +3237,15 @@
 crbug.com/968164 external/wpt/css/css-ui/webkit-appearance-menulist-button-001.html [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 external/wpt/css/css-text-decor/text-decoration-thickness-overline-001.html [ Failure ]
+crbug.com/626703 external/wpt/webxr/xrWebGLLayer_viewports.https.html [ Timeout ]
+crbug.com/626703 external/wpt/css/css-text-decor/text-decoration-thickness-vertical-001.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-text-decor/text-decoration-thickness-scroll-001.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-text-decor/text-decoration-thickness-linethrough-001.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-text/white-space/break-spaces-tab-004.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-text-decor/text-decoration-thickness-underline-001.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-text-decor/text-decoration-thickness-vertical-002.html [ Failure ]
+crbug.com/626703 external/wpt/webxr/xrWebGLLayer_framebuffer.https.html [ Timeout ]
 crbug.com/626703 external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success.https.html [ Timeout ]
 crbug.com/626703 [ Win10 ] virtual/omt-worker-fetch/external/wpt/fetch/api/request/destination/fetch-destination-worker.https.html [ Crash ]
 crbug.com/626703 external/wpt/webauthn/idlharness-manual.https.window.js [ Skip ]
@@ -4645,12 +4655,6 @@
 crbug.com/626703 external/wpt/html/browsers/history/the-location-interface/location-protocol-setter-non-broken.html [ Failure Pass ]
 
 # Underline offset and thickness are not implemented yet.
-crbug.com/626703 external/wpt/css/css-text-decor/text-decoration-width-linethrough-001.html [ Skip ]
-crbug.com/626703 external/wpt/css/css-text-decor/text-decoration-width-overline-001.html [ Skip ]
-crbug.com/626703 external/wpt/css/css-text-decor/text-decoration-width-scroll-001.html [ Skip ]
-crbug.com/785230 external/wpt/css/css-text-decor/text-decoration-width-underline-001.html [ Skip ]
-crbug.com/626703 external/wpt/css/css-text-decor/text-decoration-width-vertical-001.html [ Skip ]
-crbug.com/785230 external/wpt/css/css-text-decor/text-decoration-width-vertical-002.html [ Skip ]
 crbug.com/785230 external/wpt/css/css-text-decor/text-underline-offset-001.html [ Skip ]
 crbug.com/785230 external/wpt/css/css-text-decor/text-underline-offset-scroll-001.html [ Skip ]
 crbug.com/785230 external/wpt/css/css-text-decor/text-underline-offset-vertical-001.html [ Skip ]
@@ -6299,16 +6303,15 @@
 crbug.com/985232 [ Win7 ] virtual/streaming-preload/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-credentials.sub.html [ Pass Failure ]
 
 # Sheriff 2019-07-19
-crbug.com/985811 [ Win7 ] http/tests/devtools/elements/edit/edit-dom-actions-2.js [ Pass Timeout ]
+crbug.com/985811 [ Win ] http/tests/devtools/elements/edit/edit-dom-actions-1.js [ Pass Timeout ]
+crbug.com/985811 [ Win ] http/tests/devtools/elements/edit/edit-dom-actions-2.js [ Pass Timeout ]
 crbug.com/985869 [ Linux Win7 ] http/tests/security/contentSecurityPolicy/object-src-no-url-allowed.html [ Pass Failure ]
 crbug.com/985869 [ Linux Win7 ] virtual/blink-cors/http/tests/security/contentSecurityPolicy/object-src-no-url-allowed.html [ Pass Failure ]
 
 # Sheriff 2019-07-20
-crbug.com/986019 [ Linux Win ] animations/web-animations/animation-state-changes-positive-playback-rate.html [ Pass Failure ]
 crbug.com/986018 fast/scroll-snap/snaps-after-keyboard-scrolling-rtl.html [ Pass Failure ]
 
 # Sheriff 2019-07-22
-crbug.com/986019 [ Linux Win ] virtual/threaded/animations/web-animations/animation-state-changes-positive-playback-rate.html [ Pass Failure ]
 crbug.com/986282 [ Linux Win ] external/wpt/client-hints/accept-ch-lifetime.tentative.https.html [ Pass Failure ]
 crbug.com/986019 [ Linux ] virtual/threaded/animations/play-state.html [ Pass Timeout ]
 crbug.com/986019 [ Linux ] virtual/disable-blink-gen-property-trees/animations/play-state.html [ Pass Timeout ]
@@ -6322,3 +6325,11 @@
 crbug.com/986477 [ Win ] external/wpt/cookies/path/match.html [ Pass Timeout ]
 crbug.com/986477 [ Win ] virtual/samesite-by-default-cookies/external/wpt/cookies/path/match.html [ Pass Timeout ]
 
+# Sheriff 2019-07-23
+crbug.com/986019 animations/web-animations/animation-state-changes-positive-playback-rate.html [ Pass Failure ]
+crbug.com/986019 virtual/threaded/animations/web-animations/animation-state-changes-positive-playback-rate.html [ Pass Failure ]
+crbug.com/986019 virtual/disable-blink-gen-property-trees/animations/web-animations/animation-state-changes-positive-playback-rate.html [ Pass Failure ]
+crbug.com/986666 animations/web-animations/animation-state-changes-negative-playback-rate.html [ Pass Failure ]
+crbug.com/986666 virtual/threaded/animations/web-animations/animation-state-changes-negative-playback-rate.html [ Pass Failure ]
+crbug.com/986666 virtual/disable-blink-gen-property-trees/animations/web-animations/animation-state-changes-negative-playback-rate.html [ Pass Failure ]
+
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index cba98f13..1c19790 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -775,21 +775,6 @@
              "--disable-blink-features=RestrictAutomaticLazyFrameLoadingToDataSaver,RestrictAutomaticLazyImageLoadingToDataSaver"]
   },
   {
-    "prefix": "display-lock",
-    "base": "wpt_internal/display-lock",
-    "args": ["--enable-blink-features=DisplayLocking"]
-  },
-  {
-    "prefix": "display-lock",
-    "base": "http/tests/devtools/elements/highlight",
-    "args": ["--enable-blink-features=DisplayLocking"]
-  },
-  {
-    "prefix": "display-lock",
-    "base": "inspector-protocol/css",
-    "args": ["--enable-blink-features=DisplayLocking"]
-  },
-  {
     "prefix" : "autoupgrade-optionally-blockable-mixed-content",
     "base": "http/tests/mixed-autoupgrade/optionally",
     "args": ["--enable-features=AutoupgradeMixedContent<AU",
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
index 045f753..e9ae4a0a 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
@@ -56003,6 +56003,18 @@
      {}
     ]
    ],
+   "css/css-multicol/multicol-dynamic-add-001.html": [
+    [
+     "css/css-multicol/multicol-dynamic-add-001.html",
+     [
+      [
+       "/css/css-multicol/multicol-dynamic-add-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-multicol/multicol-fill-000.xht": [
     [
      "css/css-multicol/multicol-fill-000.xht",
@@ -64451,6 +64463,90 @@
      {}
     ]
    ],
+   "css/css-text-decor/text-decoration-thickness-001.html": [
+    [
+     "css/css-text-decor/text-decoration-thickness-001.html",
+     [
+      [
+       "/css/css-text-decor/reference/text-decoration-thickness-001-notref.html",
+       "!="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-text-decor/text-decoration-thickness-linethrough-001.html": [
+    [
+     "css/css-text-decor/text-decoration-thickness-linethrough-001.html",
+     [
+      [
+       "/css/css-text-decor/reference/text-decoration-thickness-green-rect-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-text-decor/text-decoration-thickness-overline-001.html": [
+    [
+     "css/css-text-decor/text-decoration-thickness-overline-001.html",
+     [
+      [
+       "/css/css-text-decor/reference/text-decoration-thickness-green-rect-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-text-decor/text-decoration-thickness-scroll-001.html": [
+    [
+     "css/css-text-decor/text-decoration-thickness-scroll-001.html",
+     [
+      [
+       "/css/css-text-decor/reference/text-decoration-thickness-scroll-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-text-decor/text-decoration-thickness-underline-001.html": [
+    [
+     "css/css-text-decor/text-decoration-thickness-underline-001.html",
+     [
+      [
+       "/css/css-text-decor/reference/text-decoration-thickness-green-rect-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-text-decor/text-decoration-thickness-vertical-001.html": [
+    [
+     "css/css-text-decor/text-decoration-thickness-vertical-001.html",
+     [
+      [
+       "/css/css-text-decor/reference/text-decoration-thickness-vertical-green-rect-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-text-decor/text-decoration-thickness-vertical-002.html": [
+    [
+     "css/css-text-decor/text-decoration-thickness-vertical-002.html",
+     [
+      [
+       "/css/css-text-decor/reference/text-decoration-thickness-vertical-green-rect-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-text-decor/text-decoration-underline-position-horizontal.html": [
     [
      "css/css-text-decor/text-decoration-underline-position-horizontal.html",
@@ -64487,90 +64583,6 @@
      {}
     ]
    ],
-   "css/css-text-decor/text-decoration-width-001.html": [
-    [
-     "css/css-text-decor/text-decoration-width-001.html",
-     [
-      [
-       "/css/css-text-decor/reference/text-decoration-width-001-notref.html",
-       "!="
-      ]
-     ],
-     {}
-    ]
-   ],
-   "css/css-text-decor/text-decoration-width-linethrough-001.html": [
-    [
-     "css/css-text-decor/text-decoration-width-linethrough-001.html",
-     [
-      [
-       "/css/css-text-decor/reference/text-decoration-width-green-rect-ref.html",
-       "=="
-      ]
-     ],
-     {}
-    ]
-   ],
-   "css/css-text-decor/text-decoration-width-overline-001.html": [
-    [
-     "css/css-text-decor/text-decoration-width-overline-001.html",
-     [
-      [
-       "/css/css-text-decor/reference/text-decoration-width-green-rect-ref.html",
-       "=="
-      ]
-     ],
-     {}
-    ]
-   ],
-   "css/css-text-decor/text-decoration-width-scroll-001.html": [
-    [
-     "css/css-text-decor/text-decoration-width-scroll-001.html",
-     [
-      [
-       "/css/css-text-decor/reference/text-decoration-width-scroll-001-ref.html",
-       "=="
-      ]
-     ],
-     {}
-    ]
-   ],
-   "css/css-text-decor/text-decoration-width-underline-001.html": [
-    [
-     "css/css-text-decor/text-decoration-width-underline-001.html",
-     [
-      [
-       "/css/css-text-decor/reference/text-decoration-width-green-rect-ref.html",
-       "=="
-      ]
-     ],
-     {}
-    ]
-   ],
-   "css/css-text-decor/text-decoration-width-vertical-001.html": [
-    [
-     "css/css-text-decor/text-decoration-width-vertical-001.html",
-     [
-      [
-       "/css/css-text-decor/reference/text-decoration-width-vertical-green-rect-ref.html",
-       "=="
-      ]
-     ],
-     {}
-    ]
-   ],
-   "css/css-text-decor/text-decoration-width-vertical-002.html": [
-    [
-     "css/css-text-decor/text-decoration-width-vertical-002.html",
-     [
-      [
-       "/css/css-text-decor/reference/text-decoration-width-vertical-green-rect-ref.html",
-       "=="
-      ]
-     ],
-     {}
-    ]
-   ],
    "css/css-text-decor/text-emphasis-color-001.xht": [
     [
      "css/css-text-decor/text-emphasis-color-001.xht",
@@ -70063,6 +70075,30 @@
      {}
     ]
    ],
+   "css/css-text/text-transform/text-transform-fullwidth-006.html": [
+    [
+     "css/css-text/text-transform/text-transform-fullwidth-006.html",
+     [
+      [
+       "/css/css-text/text-transform/reference/text-transform-fullwidth-006-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-text/text-transform/text-transform-fullwidth-007.html": [
+    [
+     "css/css-text/text-transform/text-transform-fullwidth-007.html",
+     [
+      [
+       "/css/css-text/text-transform/reference/text-transform-fullwidth-007-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-text/text-transform/text-transform-lowercase-001.xht": [
     [
      "css/css-text/text-transform/text-transform-lowercase-001.xht",
@@ -71047,6 +71083,78 @@
      {}
     ]
    ],
+   "css/css-text/white-space/break-spaces-tab-001.html": [
+    [
+     "css/css-text/white-space/break-spaces-tab-001.html",
+     [
+      [
+       "/css/css-text/white-space/reference/pre-wrap-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-text/white-space/break-spaces-tab-002.html": [
+    [
+     "css/css-text/white-space/break-spaces-tab-002.html",
+     [
+      [
+       "/css/css-text/white-space/reference/pre-wrap-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-text/white-space/break-spaces-tab-003.html": [
+    [
+     "css/css-text/white-space/break-spaces-tab-003.html",
+     [
+      [
+       "/css/css-text/white-space/reference/break-spaces-tab-003-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-text/white-space/break-spaces-tab-004.html": [
+    [
+     "css/css-text/white-space/break-spaces-tab-004.html",
+     [
+      [
+       "/css/css-text/white-space/reference/break-spaces-tab-003-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-text/white-space/break-spaces-tab-005.html": [
+    [
+     "css/css-text/white-space/break-spaces-tab-005.html",
+     [
+      [
+       "/css/css-text/white-space/reference/break-spaces-tab-005-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-text/white-space/break-spaces-tab-006.html": [
+    [
+     "css/css-text/white-space/break-spaces-tab-006.html",
+     [
+      [
+       "/css/css-text/white-space/reference/break-spaces-tab-005-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-text/white-space/control-chars-000.html": [
     [
      "css/css-text/white-space/control-chars-000.html",
@@ -72187,6 +72295,78 @@
      {}
     ]
    ],
+   "css/css-text/white-space/pre-wrap-tab-001.html": [
+    [
+     "css/css-text/white-space/pre-wrap-tab-001.html",
+     [
+      [
+       "/css/css-text/white-space/reference/pre-wrap-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-text/white-space/pre-wrap-tab-002.html": [
+    [
+     "css/css-text/white-space/pre-wrap-tab-002.html",
+     [
+      [
+       "/css/css-text/white-space/reference/pre-wrap-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-text/white-space/pre-wrap-tab-003.html": [
+    [
+     "css/css-text/white-space/pre-wrap-tab-003.html",
+     [
+      [
+       "/css/css-text/white-space/reference/pre-wrap-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-text/white-space/pre-wrap-tab-004.html": [
+    [
+     "css/css-text/white-space/pre-wrap-tab-004.html",
+     [
+      [
+       "/css/css-text/white-space/reference/pre-wrap-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-text/white-space/pre-wrap-tab-005.html": [
+    [
+     "css/css-text/white-space/pre-wrap-tab-005.html",
+     [
+      [
+       "/css/css-text/white-space/reference/pre-wrap-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-text/white-space/pre-wrap-tab-006.html": [
+    [
+     "css/css-text/white-space/pre-wrap-tab-006.html",
+     [
+      [
+       "/css/css-text/white-space/reference/pre-wrap-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-text/white-space/tab-stop-threshold-001.html": [
     [
      "css/css-text/white-space/tab-stop-threshold-001.html",
@@ -125337,6 +125517,15 @@
    "content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html.headers": [
     []
    ],
+   "content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image-from-script.sub-expected.txt": [
+    []
+   ],
+   "content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image-from-script.sub-expected.txt": [
+    []
+   ],
+   "content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image.sub-expected.txt": [
+    []
+   ],
    "content-security-policy/securitypolicyviolation/support/inside-worker.sub.js": [
     []
    ],
@@ -138681,6 +138870,9 @@
    "css/css-multicol/multicol-count-computed-004-ref.xht": [
     []
    ],
+   "css/css-multicol/multicol-dynamic-add-001-ref.html": [
+    []
+   ],
    "css/css-multicol/multicol-fill-000-ref.xht": [
     []
    ],
@@ -140688,6 +140880,18 @@
    "css/css-text-decor/reference/text-decoration-style-recalc-ref.html": [
     []
    ],
+   "css/css-text-decor/reference/text-decoration-thickness-001-notref.html": [
+    []
+   ],
+   "css/css-text-decor/reference/text-decoration-thickness-green-rect-ref.html": [
+    []
+   ],
+   "css/css-text-decor/reference/text-decoration-thickness-scroll-001-ref.html": [
+    []
+   ],
+   "css/css-text-decor/reference/text-decoration-thickness-vertical-green-rect-ref.html": [
+    []
+   ],
    "css/css-text-decor/reference/text-decoration-underline-position-horizontal-ref.html": [
     []
    ],
@@ -140700,18 +140904,6 @@
    "css/css-text-decor/reference/text-decoration-underline-ref.html": [
     []
    ],
-   "css/css-text-decor/reference/text-decoration-width-001-notref.html": [
-    []
-   ],
-   "css/css-text-decor/reference/text-decoration-width-green-rect-ref.html": [
-    []
-   ],
-   "css/css-text-decor/reference/text-decoration-width-scroll-001-ref.html": [
-    []
-   ],
-   "css/css-text-decor/reference/text-decoration-width-vertical-green-rect-ref.html": [
-    []
-   ],
    "css/css-text-decor/reference/text-emphasis-color-001-ref.xht": [
     []
    ],
@@ -140799,6 +140991,15 @@
    "css/css-text-decor/text-decoration-serialization.tentative-expected.txt": [
     []
    ],
+   "css/css-text-decor/text-decoration-thickness-computed-expected.txt": [
+    []
+   ],
+   "css/css-text-decor/text-decoration-thickness-initial-expected.txt": [
+    []
+   ],
+   "css/css-text-decor/text-decoration-thickness-valid-expected.txt": [
+    []
+   ],
    "css/css-text-decor/text-decoration-width-initial-expected.txt": [
     []
    ],
@@ -142200,6 +142401,12 @@
    "css/css-text/text-transform/reference/text-transform-fullwidth-001-ref.xht": [
     []
    ],
+   "css/css-text/text-transform/reference/text-transform-fullwidth-006-ref.html": [
+    []
+   ],
+   "css/css-text/text-transform/reference/text-transform-fullwidth-007-ref.html": [
+    []
+   ],
    "css/css-text/text-transform/reference/text-transform-lowercase-001-ref.xht": [
     []
    ],
@@ -142383,6 +142590,12 @@
    "css/css-text/text-transform/text-transform-lowercase-002-ref.xht": [
     []
    ],
+   "css/css-text/white-space/reference/break-spaces-tab-003-ref.html": [
+    []
+   ],
+   "css/css-text/white-space/reference/break-spaces-tab-005-ref.html": [
+    []
+   ],
    "css/css-text/white-space/reference/control-chars-000-ref.html": [
     []
    ],
@@ -143922,6 +144135,9 @@
    "css/css-typed-om/the-stylepropertymap/properties/text-decoration-skip-expected.txt": [
     []
    ],
+   "css/css-typed-om/the-stylepropertymap/properties/text-decoration-thickness-expected.txt": [
+    []
+   ],
    "css/css-typed-om/the-stylepropertymap/properties/text-decoration-width-expected.txt": [
     []
    ],
@@ -158400,6 +158616,9 @@
    "html/semantics/embedded-content/the-img-element/intrinsicsize/intrinsicsize-without-unsized-media.tentative.https.sub.html.headers": [
     []
    ],
+   "html/semantics/embedded-content/the-img-element/invalid-src-expected.txt": [
+    []
+   ],
    "html/semantics/embedded-content/the-img-element/ismap/img-ismap-coordinates-iframe-after.html": [
     []
    ],
@@ -160968,7 +161187,7 @@
    "interfaces/xhr.idl": [
     []
    ],
-   "interfaces/xslt.idl": [
+   "interfaces/xslt.tentative.idl": [
     []
    ],
    "intersection-observer/META.yml": [
@@ -161088,6 +161307,9 @@
    "lint.whitelist": [
     []
    ],
+   "loading/lazyload/common.js": [
+    []
+   ],
    "loading/lazyload/resources/image.png": [
     []
    ],
@@ -207302,27 +207524,27 @@
      {}
     ]
    ],
-   "css/css-text-decor/text-decoration-width-computed.html": [
+   "css/css-text-decor/text-decoration-thickness-computed.html": [
     [
-     "css/css-text-decor/text-decoration-width-computed.html",
+     "css/css-text-decor/text-decoration-thickness-computed.html",
      {}
     ]
    ],
-   "css/css-text-decor/text-decoration-width-initial.html": [
+   "css/css-text-decor/text-decoration-thickness-initial.html": [
     [
-     "css/css-text-decor/text-decoration-width-initial.html",
+     "css/css-text-decor/text-decoration-thickness-initial.html",
      {}
     ]
    ],
-   "css/css-text-decor/text-decoration-width-invalid.html": [
+   "css/css-text-decor/text-decoration-thickness-invalid.html": [
     [
-     "css/css-text-decor/text-decoration-width-invalid.html",
+     "css/css-text-decor/text-decoration-thickness-invalid.html",
      {}
     ]
    ],
-   "css/css-text-decor/text-decoration-width-valid.html": [
+   "css/css-text-decor/text-decoration-thickness-valid.html": [
     [
-     "css/css-text-decor/text-decoration-width-valid.html",
+     "css/css-text-decor/text-decoration-thickness-valid.html",
      {}
     ]
    ],
@@ -211126,9 +211348,9 @@
      {}
     ]
    ],
-   "css/css-typed-om/the-stylepropertymap/properties/text-decoration-width.html": [
+   "css/css-typed-om/the-stylepropertymap/properties/text-decoration-thickness.html": [
     [
-     "css/css-typed-om/the-stylepropertymap/properties/text-decoration-width.html",
+     "css/css-typed-om/the-stylepropertymap/properties/text-decoration-thickness.html",
      {}
     ]
    ],
@@ -248343,6 +248565,18 @@
      {}
     ]
    ],
+   "loading/lazyload/original-base-url-applied-tentative.html": [
+    [
+     "loading/lazyload/original-base-url-applied-tentative.html",
+     {}
+    ]
+   ],
+   "loading/lazyload/original-referrer-policy-applied-tentative.sub.html": [
+    [
+     "loading/lazyload/original-referrer-policy-applied-tentative.sub.html",
+     {}
+    ]
+   ],
    "loading/preloader-css-import-no-quote.tentative.html": [
     [
      "loading/preloader-css-import-no-quote.tentative.html",
@@ -298758,6 +298992,12 @@
      {}
     ]
    ],
+   "webxr/xrWebGLLayer_framebuffer.https.html": [
+    [
+     "webxr/xrWebGLLayer_framebuffer.https.html",
+     {}
+    ]
+   ],
    "webxr/xrWebGLLayer_viewports.https.html": [
     [
      "webxr/xrWebGLLayer_viewports.https.html",
@@ -303813,9 +304053,9 @@
      {}
     ]
    ],
-   "xslt/idlharness.window.js": [
+   "xslt/idlharness.tentative.window.js": [
     [
-     "xslt/idlharness.window.html",
+     "xslt/idlharness.tentative.window.html",
      {
       "script_metadata": [
        [
@@ -322493,20 +322733,32 @@
    "551978ffb41d61d171ffa2c104b88598f0a0c0d8",
    "testharness"
   ],
+  "content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image-from-script.sub-expected.txt": [
+   "4f655bada84752fc9f7446c0402de1833137002f",
+   "support"
+  ],
   "content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image-from-script.sub.html": [
-   "65311c32ad6e27a744764800e43d5ddb47160e97",
+   "4c86845f4dbb1a4d56474b6aa2884dcc4a20c3f3",
    "testharness"
   ],
   "content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub.html": [
-   "03829fe8a3686f9ce9c484b1e3fb2bdd328cc12f",
+   "dcf52aa187c7fea6d94dd11ed002e3b924d26e56",
    "testharness"
   ],
+  "content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image-from-script.sub-expected.txt": [
+   "4f655bada84752fc9f7446c0402de1833137002f",
+   "support"
+  ],
   "content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image-from-script.sub.html": [
-   "0a7c2b43bff372ee4c1b9935306554068f07829f",
+   "978096f14f641907029d0198cac45ad6a7a9d4ef",
    "testharness"
   ],
+  "content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image.sub-expected.txt": [
+   "cc4ede641a55c6b9379f738fd0c99963f9eb8d3e",
+   "support"
+  ],
   "content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image.sub.html": [
-   "5dd82e6ddca482bdf6be75f53753465fad166c5b",
+   "6e0e6ddbede1aff3b1521cfad1aa789d9b80858f",
    "testharness"
   ],
   "content-security-policy/securitypolicyviolation/style-sample-no-opt-in.html": [
@@ -323166,11 +323418,11 @@
    "support"
   ],
   "cookie-store/cookieListItem_attributes.tentative.https.window.js": [
-   "3e7b02b1085ba3c7fe301a410129ba227bce7f8b",
+   "bf8f845f2b183202efc6405c510eb348db189894",
    "testharness"
   ],
   "cookie-store/cookieStore_delete_arguments.tentative.https.window.js": [
-   "8cfa03dd0540cdd46d144292279e557d257dd9c2",
+   "dc073d8eb60321bdf5b15d67af6989dc672f21b1",
    "testharness"
   ],
   "cookie-store/cookieStore_delete_basic.tentative.https.window.js": [
@@ -323182,47 +323434,47 @@
    "testharness"
   ],
   "cookie-store/cookieStore_event_basic.tentative.https.window.js": [
-   "7f6d2d919d496be7135bae0536841611d208afea",
+   "5f20947dbf1051bd14ce23f45e632290da2ed7c9",
    "testharness"
   ],
   "cookie-store/cookieStore_event_delete.tenative.https.window.js": [
-   "f84b2e067451d883b5819ae4d4b8648a38aba3b1",
+   "e8c6fc036a76863acf2d8b2b3660550715f1dc0d",
    "testharness"
   ],
   "cookie-store/cookieStore_event_overwrite.tentative.https.window.js": [
-   "2a5cb5d064f912eb8d6583427360afd280bb7a23",
+   "3acffea41c1d6a08e5aaf1ca944567347d174de0",
    "testharness"
   ],
   "cookie-store/cookieStore_getAll_arguments.tentative.https.window.js": [
-   "5106a6270cd9239cd34cd9f6a96c29a24dccab5b",
+   "a04aa8cd7ad65a56a56d3de53fa4d92192c7f05a",
    "testharness"
   ],
   "cookie-store/cookieStore_getAll_multiple.tentative.https.window.js": [
-   "78b3c56fdd38925d9c2da17454b5f1b8b969d999",
+   "c09f4fc5f5794d44b61159f6a18de85cd0c57da7",
    "testharness"
   ],
   "cookie-store/cookieStore_getAll_set_basic.tentative.https.window.js": [
-   "aa0a4ea9a03eaa96144ed62a6458ffbb183a97c6",
+   "dd2adabd22835d135198d7b5c3cdb5d18b7e27a5",
    "testharness"
   ],
   "cookie-store/cookieStore_get_arguments.tentative.https.window.js": [
-   "bb126864ff7623a4c51988834e24a3894dc8a5ee",
+   "e338dd1bdbd098373765dcc048425899c5cbe490",
    "testharness"
   ],
   "cookie-store/cookieStore_get_delete_basic.tentative.https.window.js": [
-   "fc9645d3e2e98063da8cf03ef50823af363c6b9c",
+   "5ebf09d34463250d2eeec80606b89a6ce46298e0",
    "testharness"
   ],
   "cookie-store/cookieStore_get_set_across_frames.tentative.https.html": [
-   "c2ef184940390348020aa7e8cdfd24b4a8b9d335",
+   "f7c737b422e559107bb210d0cea9267829e10ba7",
    "testharness"
   ],
   "cookie-store/cookieStore_get_set_across_origins.tentative.sub.https.html": [
-   "e8792612c4352dc1697a2d4efc8dbe6ab7092a7e",
+   "c67ef98bcc944dbfb815993734dcfae7dbd3eb9d",
    "testharness"
   ],
   "cookie-store/cookieStore_get_set_basic.tentative.https.window.js": [
-   "2a082de9d30927ec5ee152acdd76cde04ed730d5",
+   "deb7405f2ff0ddc29214a51b80878f7b17ce66fa",
    "testharness"
   ],
   "cookie-store/cookieStore_in_detached_frame.tentative.https.html": [
@@ -323230,7 +323482,7 @@
    "testharness"
   ],
   "cookie-store/cookieStore_set_arguments.tentative.https.window.js": [
-   "18f60ad974e1570365cc0d92c36cd55330d5b721",
+   "ddc9981c92ddf5d3b149249db1accd16dc476ec1",
    "testharness"
   ],
   "cookie-store/cookieStore_special_names.tentative.https.window.js": [
@@ -323342,11 +323594,11 @@
    "support"
   ],
   "cookie-store/serviceworker_cookieStore_cross_origin.tentative.https.sub.html": [
-   "abc431a4d628e28adc40d7c9636766c53c16cf4e",
+   "6879c5da926384b2be6969b5585c8e2a75539f75",
    "testharness"
   ],
   "cookie-store/serviceworker_cookieStore_subscriptions.js": [
-   "0c86a0cb090c1ea279341144922c8c93661977c2",
+   "41cbed01a5be61b6eafa739fe65a97464c34c13d",
    "support"
   ],
   "cookie-store/serviceworker_cookieStore_subscriptions.tentative.https.html": [
@@ -323354,7 +323606,7 @@
    "testharness"
   ],
   "cookie-store/serviceworker_cookieStore_subscriptions_basic.js": [
-   "5819fb5043834048a3712192b865467a5ca1b9c8",
+   "293969e5b8f86fac896b0fa75f632b31504a9a83",
    "support"
   ],
   "cookie-store/serviceworker_cookieStore_subscriptions_basic.tentative.https.html": [
@@ -323362,7 +323614,7 @@
    "testharness"
   ],
   "cookie-store/serviceworker_cookieStore_subscriptions_empty.js": [
-   "de521caddd8763b1d30e1c0bfcf2feea98e7bc06",
+   "b62318699740938134fc51ab4c42670ce8878aca",
    "support"
   ],
   "cookie-store/serviceworker_cookieStore_subscriptions_empty.tentative.https.html": [
@@ -323370,7 +323622,7 @@
    "testharness"
   ],
   "cookie-store/serviceworker_cookieStore_subscriptions_eventhandler_attribute.js": [
-   "551d2e1e1c795a3f80e856aee1290a8adc4a9fa2",
+   "31e644d50b2a922122cfaeaba4acf41db205ce07",
    "support"
   ],
   "cookie-store/serviceworker_cookieStore_subscriptions_eventhandler_attribute.tentative.https.html": [
@@ -323378,7 +323630,7 @@
    "testharness"
   ],
   "cookie-store/serviceworker_cookieStore_subscriptions_mismatch.js": [
-   "4b399eed782d8d128c2a5b93b1e94931358e9b6b",
+   "3d07c86492e1a860e97568edcdc277d460de7f6c",
    "support"
   ],
   "cookie-store/serviceworker_cookieStore_subscriptions_mismatch.tentative.https.html": [
@@ -365489,6 +365741,14 @@
    "6c94be98775661bea5c5fb698aae868b179be34a",
    "reftest"
   ],
+  "css/css-multicol/multicol-dynamic-add-001-ref.html": [
+   "380c746301ff9b871a40692ccacaac7da4d974e2",
+   "support"
+  ],
+  "css/css-multicol/multicol-dynamic-add-001.html": [
+   "ccc44add0b4d74d45ec2366f8ae3683c9645f96a",
+   "reftest"
+  ],
   "css/css-multicol/multicol-fill-000-ref.xht": [
    "c68a7a61d2de4a4ad8265fb557a88142eb01ab7c",
    "support"
@@ -367438,7 +367698,7 @@
    "support"
   ],
   "css/css-paint-api/background-image-alpha.https.html": [
-   "53d869d06079717637cc432cdcf46e35170c2216",
+   "7f1e31bf39bbc98bd6f37a99f7e660cda3590de0",
    "reftest"
   ],
   "css/css-paint-api/background-image-multiple-ref.html": [
@@ -367446,7 +367706,7 @@
    "support"
   ],
   "css/css-paint-api/background-image-multiple.https.html": [
-   "79ff8836c15c372155badcc4013d3d33dc039d18",
+   "51c928d2a67c74e173a9f815b3c97a8ec8a21059",
    "reftest"
   ],
   "css/css-paint-api/background-image-tiled-ref.html": [
@@ -367454,7 +367714,7 @@
    "support"
   ],
   "css/css-paint-api/background-image-tiled.https.html": [
-   "8498c82a355e41513c1b2521dfb489dcd4f6cd75",
+   "11647c9228c8fb2f10bf5e3aeb25967b40478c45",
    "reftest"
   ],
   "css/css-paint-api/geometry-background-image-001-ref.html": [
@@ -367462,7 +367722,7 @@
    "support"
   ],
   "css/css-paint-api/geometry-background-image-001.https.html": [
-   "601d4187b091aa08be5e133a56ffe24bcbb1f8df",
+   "eb7f6716ada1bdea3761b4d164e9b2ca7ea35f98",
    "reftest"
   ],
   "css/css-paint-api/geometry-background-image-002-ref.html": [
@@ -367470,7 +367730,7 @@
    "support"
   ],
   "css/css-paint-api/geometry-background-image-002.https.html": [
-   "1d57073bf20660f2cc7faab9184ace78967e097e",
+   "e636aa73b3b2e519c2a6c12457a6434b38036ea0",
    "reftest"
   ],
   "css/css-paint-api/geometry-background-image-tiled-001-ref.html": [
@@ -367478,7 +367738,7 @@
    "support"
   ],
   "css/css-paint-api/geometry-background-image-tiled-001.https.html": [
-   "8e28b54b36df37845bb4a6dc95b27872ddbe2ee3",
+   "51373a528e4ca46b0adcf665e28cc3dc1aa793bc",
    "reftest"
   ],
   "css/css-paint-api/geometry-background-image-tiled-002-ref.html": [
@@ -367486,7 +367746,7 @@
    "support"
   ],
   "css/css-paint-api/geometry-background-image-tiled-002.https.html": [
-   "9248e38641eb80efb5566b5750616fda8527aa34",
+   "d55761b47cd362827bf828e03d6a8f94dd309431",
    "reftest"
   ],
   "css/css-paint-api/geometry-background-image-tiled-003-ref.html": [
@@ -367494,7 +367754,7 @@
    "support"
   ],
   "css/css-paint-api/geometry-background-image-tiled-003.https.html": [
-   "5b6b6c7c65a1bcea71ae8bc69f171d0e22b1e1d6",
+   "6d5bdd2fa539979f4069e42cd9582c2d13fba445",
    "reftest"
   ],
   "css/css-paint-api/geometry-border-image-001-ref.html": [
@@ -367502,7 +367762,7 @@
    "support"
   ],
   "css/css-paint-api/geometry-border-image-001.https.html": [
-   "3fb4643cd472dd7e1beaee5cf32c75499a1d02bb",
+   "ff7f56e299ddd2a0206d7a25d0d930afb616c0f0",
    "reftest"
   ],
   "css/css-paint-api/geometry-border-image-002-ref.html": [
@@ -367510,7 +367770,7 @@
    "support"
   ],
   "css/css-paint-api/geometry-border-image-002.https.html": [
-   "26e24bb0146b015a84dae57db5d4a2398ce00a8e",
+   "d6e47f049071416302a250c019b110d7dcaa8071",
    "reftest"
   ],
   "css/css-paint-api/geometry-border-image-003-ref.html": [
@@ -367518,7 +367778,7 @@
    "support"
   ],
   "css/css-paint-api/geometry-border-image-003.https.html": [
-   "a26f2b7d10980b5f6d7d709c131b37cbc61add0d",
+   "36af043cc5fe9e2ebe0dc94855b3b1def55f28aa",
    "reftest"
   ],
   "css/css-paint-api/geometry-border-image-004-ref.html": [
@@ -367526,7 +367786,7 @@
    "support"
   ],
   "css/css-paint-api/geometry-border-image-004.https.html": [
-   "60db7ff4bc59abd8133a38a1f92f8cc2e9054b7d",
+   "0f483cd5d19acf4923e60a9f59f55b2bd1e2d0d0",
    "reftest"
   ],
   "css/css-paint-api/geometry-with-float-size-ref.html": [
@@ -367534,7 +367794,7 @@
    "support"
   ],
   "css/css-paint-api/geometry-with-float-size.https.html": [
-   "65477e4b3bf369d511113cbe81d04531281edc4c",
+   "8cd90c84318dff22e3099af7ef042f92f5b96506",
    "reftest"
   ],
   "css/css-paint-api/hidpi/canvas-transform-ref.html": [
@@ -367542,7 +367802,7 @@
    "support"
   ],
   "css/css-paint-api/hidpi/canvas-transform.https.html": [
-   "d160a8673c21d17e58ca20eb437c22cd76c97104",
+   "6dc57abaf777c15ca3a868c03eee9e3c0559677c",
    "reftest"
   ],
   "css/css-paint-api/hidpi/device-pixel-ratio-ref.html": [
@@ -367550,7 +367810,7 @@
    "support"
   ],
   "css/css-paint-api/hidpi/device-pixel-ratio.https.html": [
-   "46a9aa28f2f8876a06751fcdd26399c915dd1c1c",
+   "f9516e5ccf95dd96f32e770bd132cdc9ebe1e6f4",
    "reftest"
   ],
   "css/css-paint-api/idlharness-expected.txt": [
@@ -367558,7 +367818,7 @@
    "support"
   ],
   "css/css-paint-api/idlharness.html": [
-   "c9675ab0412bb955d7a8653e7d28884a6953800b",
+   "aad04a17cc4c660084fa196cb85da5d88b8560d4",
    "testharness"
   ],
   "css/css-paint-api/invalid-image-constructor-error-ref.html": [
@@ -367566,7 +367826,7 @@
    "support"
   ],
   "css/css-paint-api/invalid-image-constructor-error.https.html": [
-   "439ff8b4e5a3c050a350349b37aad5c350dd2bbd",
+   "8facde43f57cec2bcd75efe25fee58d4c70ead62",
    "reftest"
   ],
   "css/css-paint-api/invalid-image-paint-error-ref.html": [
@@ -367574,7 +367834,7 @@
    "support"
   ],
   "css/css-paint-api/invalid-image-paint-error.https.html": [
-   "2806ad9204853ab67cf90bd664382bb2cf2a8e67",
+   "17c283e35caae2a69e9c748fe19a8dd53b894e35",
    "reftest"
   ],
   "css/css-paint-api/invalid-image-pending-script-ref.html": [
@@ -367582,7 +367842,7 @@
    "support"
   ],
   "css/css-paint-api/invalid-image-pending-script.https.html": [
-   "4347a00a499ff49d96051bb3fcfdcc42ba41999f",
+   "20a61eff41b68e8f756de2f3fe81bd20e736c92c",
    "reftest"
   ],
   "css/css-paint-api/overdraw-ref.html": [
@@ -367590,7 +367850,7 @@
    "support"
   ],
   "css/css-paint-api/overdraw.https.html": [
-   "5be26f7e0a877e9835cd11563c28392281c84cc1",
+   "8d3dc72f9315884c342013d50f3936804a0747fe",
    "reftest"
   ],
   "css/css-paint-api/paint-arguments-ref.html": [
@@ -367598,7 +367858,7 @@
    "support"
   ],
   "css/css-paint-api/paint-arguments.https.html": [
-   "abfb2a68e4be069055336585b4573dcfee1dd121",
+   "615027c8fe393c2109bb99bc6bb1c2f36d104f9e",
    "reftest"
   ],
   "css/css-paint-api/paint-function-arguments-ref.html": [
@@ -367606,7 +367866,7 @@
    "support"
   ],
   "css/css-paint-api/paint-function-arguments.https.html": [
-   "d87b0b80a61d2f5edcd5e5d7227dfecd9f580ae3",
+   "3a1e579f5ecbe324d48a6e0cb4d94a77cb4361d3",
    "reftest"
   ],
   "css/css-paint-api/paint2d-composite-ref.html": [
@@ -367614,7 +367874,7 @@
    "support"
   ],
   "css/css-paint-api/paint2d-composite.https.html": [
-   "80e94e45a8cddafe8b81a9a48ef16b4e0a03f586",
+   "edf8a766fabedaac61f2de9607ebde01e0d86c5b",
    "reftest"
   ],
   "css/css-paint-api/paint2d-filter-ref.html": [
@@ -367622,7 +367882,7 @@
    "support"
   ],
   "css/css-paint-api/paint2d-filter.https.html": [
-   "d0c45395757c971c9a6c1c0895b7599191596c95",
+   "9d598c7a9689fccd3fcf140f912f58233f734b14",
    "reftest"
   ],
   "css/css-paint-api/paint2d-gradient-ref.html": [
@@ -367630,7 +367890,7 @@
    "support"
   ],
   "css/css-paint-api/paint2d-gradient.https.html": [
-   "892a7919f1f73b65992e1ffbd5a0654de715075d",
+   "1887f52b06b1033d183ef6506f92cf9fe0d69773",
    "reftest"
   ],
   "css/css-paint-api/paint2d-image-ref.html": [
@@ -367638,7 +367898,7 @@
    "support"
   ],
   "css/css-paint-api/paint2d-image.https.html": [
-   "6fce4b6898b86d4b4eeddf9c3d3660941ebc5512",
+   "71074df796d36a1d97a4598b62cdcc04fff390a3",
    "reftest"
   ],
   "css/css-paint-api/paint2d-paths-ref.html": [
@@ -367646,7 +367906,7 @@
    "support"
   ],
   "css/css-paint-api/paint2d-paths.https.html": [
-   "091f548cb30fd84e5af3dc22c310a4d165e6bccc",
+   "0e04168fcb1aae5bc555873b795dc448d476551b",
    "reftest"
   ],
   "css/css-paint-api/paint2d-rects-ref.html": [
@@ -367654,7 +367914,7 @@
    "support"
   ],
   "css/css-paint-api/paint2d-rects.https.html": [
-   "24942727d5ab14da8895587c9e0120ec9d0a6a14",
+   "9279aa2a870b81052360a9feadab4e406070bd3d",
    "reftest"
   ],
   "css/css-paint-api/paint2d-shadows-ref.html": [
@@ -367662,7 +367922,7 @@
    "support"
   ],
   "css/css-paint-api/paint2d-shadows.https.html": [
-   "98dcfbce2997598d371481c422d412ad403f794f",
+   "b641dab8860f87264cd7b23f170ba693d894af62",
    "reftest"
   ],
   "css/css-paint-api/paint2d-transform-ref.html": [
@@ -367670,75 +367930,75 @@
    "support"
   ],
   "css/css-paint-api/paint2d-transform.https.html": [
-   "c91b500a46f1d30e7a717ec9542462180e3de20f",
+   "d052b8c5543344ba3629c4723e5d05912cfc86dd",
    "reftest"
   ],
   "css/css-paint-api/parse-input-arguments-001.https.html": [
-   "4356ce61f4aa5b277c6caf228e44dcbf3e6245c8",
+   "486f379dd7b27e70fd734d62e7de45fd8ca9ab5e",
    "reftest"
   ],
   "css/css-paint-api/parse-input-arguments-002.https.html": [
-   "b1b50e04045fb05ad7f967a7db26f86dcf5d36b7",
+   "5c7b3aca048d05f8535e6d182b9c5350595464ea",
    "reftest"
   ],
   "css/css-paint-api/parse-input-arguments-003.https.html": [
-   "3b1b0014f78a3ed0908273f0dc72b714f32c9aab",
+   "81904ee6f7b132fe6a58cd12d84e43b95cee625b",
    "reftest"
   ],
   "css/css-paint-api/parse-input-arguments-004.https.html": [
-   "138a7908682a348b3a76f1244a68cae42cf3f2f2",
+   "9bf264b0d5fc21225c9f7ae8c887b61237b3f882",
    "reftest"
   ],
   "css/css-paint-api/parse-input-arguments-005.https.html": [
-   "0c5e539381bd8bc9295bfa54db070c2e6b9e2ac2",
+   "24769f472c5b88b3b311a8d5e46e13ca3aaf6609",
    "reftest"
   ],
   "css/css-paint-api/parse-input-arguments-006.https.html": [
-   "e99ab05a88d9fb6d8dff1a8a7dff880bc6bf0728",
+   "a6fcc16c5da9e135eebe3b4f53194f7fbe867fd2",
    "reftest"
   ],
   "css/css-paint-api/parse-input-arguments-007.https.html": [
-   "53f245bce483e2074266793cec6d17c4f26ebadb",
+   "462cfb601069597977dabe25c806ee1af095a554",
    "reftest"
   ],
   "css/css-paint-api/parse-input-arguments-008.https.html": [
-   "e6b863c641c0a201851c1910da158db377292217",
+   "d5c18b0905d76948428a3e874eccf7bda6ac944e",
    "reftest"
   ],
   "css/css-paint-api/parse-input-arguments-009.https.html": [
-   "b23191ae34015c9a4fb7b3a4f711228b57b98b34",
+   "7cfdf91eb02a2d2f293f52cc3a8256243757557f",
    "reftest"
   ],
   "css/css-paint-api/parse-input-arguments-010.https.html": [
-   "e98b431648932559400e721a0414a3955403b50a",
+   "142ca0c5d5d6b291f126d83554aa9ccec6aaa194",
    "reftest"
   ],
   "css/css-paint-api/parse-input-arguments-011.https.html": [
-   "b9d54bf413d79a13b89decb578d17834a7649799",
+   "23eb9d3c9f98f4e2a67728be32897bf59b87a1aa",
    "reftest"
   ],
   "css/css-paint-api/parse-input-arguments-012.https.html": [
-   "14eebeb635a73feb7303c178818f1e02df3d854d",
+   "fa2c6b5f56053373e3be5d48e8ca0840b090ee8f",
    "reftest"
   ],
   "css/css-paint-api/parse-input-arguments-013.https.html": [
-   "37e3eb435ec38d8204b1c194a5da23f447aced5c",
+   "adc1c03cfe66f4ce6fe75c4a59ca4708f7115059",
    "reftest"
   ],
   "css/css-paint-api/parse-input-arguments-014.https.html": [
-   "690e488b9177a2a482becc4ce38b48a264a1d6c8",
+   "d041ae316f7a3ea2c853828d6845716c36c13c85",
    "reftest"
   ],
   "css/css-paint-api/parse-input-arguments-015.https.html": [
-   "fba76712466694e70e1a14c6ccd8e7f273ab981f",
+   "8ebe3e7c4d15fb653d890127eece81e1049df38f",
    "reftest"
   ],
   "css/css-paint-api/parse-input-arguments-016.https.html": [
-   "31cca45facab4fb2c312f57f0c42b3e361d4baef",
+   "ccd0595faa514a877eb2ff0f7d9a8980b9a5b971",
    "reftest"
   ],
   "css/css-paint-api/parse-input-arguments-017.https.html": [
-   "0d14fe74c21f4223e183f70cc95704945a0c8828",
+   "476e29ff12f0d75940ee5dfb5ac4079e43a7ae04",
    "reftest"
   ],
   "css/css-paint-api/parse-input-arguments-018-ref.html": [
@@ -367746,23 +368006,23 @@
    "support"
   ],
   "css/css-paint-api/parse-input-arguments-018.https.html": [
-   "541332ae777c330431f6712570fd99d9707230b6",
+   "e6a31cbdd41899f2d4a548a7af39e97c44140380",
    "reftest"
   ],
   "css/css-paint-api/parse-input-arguments-019.https.html": [
-   "707a0c6ebe05ea32a9ced7bf24b62dc7fb5e9dfe",
+   "309ec800eacfde6302add112ecd94275f394dc1a",
    "reftest"
   ],
   "css/css-paint-api/parse-input-arguments-020.https.html": [
-   "fe8dbad27bdf56eeb10a51f259e00d44062945e1",
+   "7e00b64123d5621c226b104ccec133b83f10fa6e",
    "reftest"
   ],
   "css/css-paint-api/parse-input-arguments-021.https.html": [
-   "0c3a596236fc3c7a8dd1bb72d0bd62efa2f80f14",
+   "8fa043a8cdead2ebbbb83f69fe708acac05127b1",
    "reftest"
   ],
   "css/css-paint-api/parse-input-arguments-022.https.html": [
-   "50aaa6b3c9420f1220d38c407aec84be46afaafe",
+   "2ff27d7a4af5d4905a76ca53228b3cc619c05ecf",
    "reftest"
   ],
   "css/css-paint-api/parse-input-arguments-ref.html": [
@@ -367770,127 +368030,127 @@
    "support"
   ],
   "css/css-paint-api/registered-property-interpolation-001.https.html": [
-   "c6e93029f101625de917394b314aecc3138ce1ec",
+   "5aaed62542f1231ab866b8c245424f8b676b0aeb",
    "reftest"
   ],
   "css/css-paint-api/registered-property-interpolation-002.https.html": [
-   "cfa9a618a1f10146fd61f357d6be3367e07b2cb6",
+   "80b2c9339d70772bbf0468e2ff1e14c3ec088279",
    "reftest"
   ],
   "css/css-paint-api/registered-property-interpolation-003.https.html": [
-   "314d0c082efca3073dc2d69e37f010e01f6d83b2",
+   "683ed403fb8b7a519b06c0b2c6d8564cb5830053",
    "reftest"
   ],
   "css/css-paint-api/registered-property-interpolation-004.https.html": [
-   "430326a0663281678dc6133a9d0b7cf6889352e3",
+   "9602e902eca44eb704a8f3977c9f4416ad7aab7e",
    "reftest"
   ],
   "css/css-paint-api/registered-property-interpolation-005.https.html": [
-   "807a0509289f3bea13ad8021f6e06c33c1552736",
+   "35d6ccbf3d4bc3d9278a733f7e21ab44734b2d08",
    "reftest"
   ],
   "css/css-paint-api/registered-property-interpolation-006.https.html": [
-   "45859a514a339231bf515546e494f1de5ce127bb",
+   "a8cfdead0f7b6d4d358c56f4126780452e827e4e",
    "reftest"
   ],
   "css/css-paint-api/registered-property-interpolation-007.https.html": [
-   "b3f4f1f1bba24ccdc265fb6e6c8f1a375ee8803e",
+   "77b80b51e67ac275aeff76baf93d0c0e8fca6ef8",
    "reftest"
   ],
   "css/css-paint-api/registered-property-interpolation-008.https.html": [
-   "45eb90960812cb1adb2537beb3068b90e5dbfd8e",
+   "1ec166614e13ccda26fd066cd1ed3c5134792e48",
    "reftest"
   ],
   "css/css-paint-api/registered-property-interpolation-009.https.html": [
-   "e45881244b2a211d2f5e5d9dfe867c13b55fac3d",
+   "e7a5e37c641f060458b128a4bb53e00f2ca63532",
    "reftest"
   ],
   "css/css-paint-api/registered-property-interpolation-010.https.html": [
-   "d4d1b038e24d45e5f6941e3f7a7eb1facefe58f0",
+   "ee3a0f1b3217677a5a6d7049d0b85939ed271174",
    "reftest"
   ],
   "css/css-paint-api/registered-property-invalidation-001.https.html": [
-   "26da7e2eeffac331266d8c5c8fc1754884b06d72",
+   "133b9238e6ceef161f99b99711839cf791c908b8",
    "reftest"
   ],
   "css/css-paint-api/registered-property-invalidation-002.https.html": [
-   "0aab051a4c492cd25b4b96fbee78029c2f12921a",
+   "aadbfec42c8c89a9fa9b9a77d86f36fd36b0cbe3",
    "reftest"
   ],
   "css/css-paint-api/registered-property-stylemap.https.html": [
-   "2305afb37df44abf4b9807bbe08c1ce0f7a1631c",
+   "4a6b4db521af8ddff57dd4ecaf9f9c35c5a4cc6b",
    "reftest"
   ],
   "css/css-paint-api/registered-property-value-001.https.html": [
-   "f915dacb168a6252ace394cbe64426614b4fae16",
+   "970e1f3e5ed9ec422d50a9f71d935d5970b3eb12",
    "reftest"
   ],
   "css/css-paint-api/registered-property-value-002.https.html": [
-   "7d62b0b2f65d3c7169ac0ccd338eb16ca9566e1a",
+   "6019151b10575afda778fc27117877d879c8839a",
    "reftest"
   ],
   "css/css-paint-api/registered-property-value-003.https.html": [
-   "b22f18dde7c1281dea657bd89321a305e955b89d",
+   "b9c3bf3fd90422d3293dd30e4074c5b1dd66ee52",
    "reftest"
   ],
   "css/css-paint-api/registered-property-value-004.https.html": [
-   "d67603f9fe8e0cd0969836d5c0748c304fdc6375",
+   "e04be69f80c27ee8ad83acdb5b4c0c4f23efaa0d",
    "reftest"
   ],
   "css/css-paint-api/registered-property-value-005.https.html": [
-   "71cda9a3766f50aee0995f9bd37cb410c1919b95",
+   "bfecd0c56b8d538671540b9c229c7df585df1d31",
    "reftest"
   ],
   "css/css-paint-api/registered-property-value-006.https.html": [
-   "aa03edf25f77907ef38b2320b51b535cf40985dd",
+   "7176b67d4bb8bf99a8bc3bfc559912424b449826",
    "reftest"
   ],
   "css/css-paint-api/registered-property-value-007.https.html": [
-   "61256cd11cff21c31b95aeb31e8807d84b804b88",
+   "309fe969b6bd31a9f1c3212d92dedca8203b0942",
    "reftest"
   ],
   "css/css-paint-api/registered-property-value-008.https.html": [
-   "06a18bd022cb7fc0dd47163ba5fdfeec6aab0b6d",
+   "db72408d77b9c7fe10142b1f83c9e98f38b219f3",
    "reftest"
   ],
   "css/css-paint-api/registered-property-value-009.https.html": [
-   "2ce2a0d56bd6a8bf230c5bae4790c633c34643c6",
+   "a2c2e9a8cd561ef588f98a08031ad50961f59c07",
    "reftest"
   ],
   "css/css-paint-api/registered-property-value-010.https.html": [
-   "53aef81e8e85c5aba8d88dbbee69689807735ffd",
+   "332a22a1b9d9d1c3c0f117c4804e19ff73b2c670",
    "reftest"
   ],
   "css/css-paint-api/registered-property-value-011.https.html": [
-   "d5dc351f7fafcfe7636b426fb3cc262128826ed5",
+   "a596a5d55fd936921edc4661cdd9680950e2eebb",
    "reftest"
   ],
   "css/css-paint-api/registered-property-value-012.https.html": [
-   "827877a51c4dd60c69056acfc0235a53a01fd91d",
+   "80c1e6ed37c5b8d4c611d534dbe4e4c6cbaf286c",
    "reftest"
   ],
   "css/css-paint-api/registered-property-value-013.https.html": [
-   "e37cd556f80c4c02bdbcf5dc7905189b9e7265c3",
+   "7af03929d843cf5a201ff33bd3f57b1f790bd2e0",
    "reftest"
   ],
   "css/css-paint-api/registered-property-value-014.https.html": [
-   "f42160fabe108b1d2238f5514d535be14c943d92",
+   "0ca1eca13ed3d4b1e2da165e827799f6ef968925",
    "reftest"
   ],
   "css/css-paint-api/registered-property-value-015.https.html": [
-   "5b00b53c2a09a98dd762deb5f550ff26882c939b",
+   "d7ba26b852c15a2e4df11a071e042b7f1c523aa0",
    "reftest"
   ],
   "css/css-paint-api/registered-property-value-016.https.html": [
-   "1ec2e1b5ab031a4c5842c190a081a7c4de14091f",
+   "609f00f6d0067efb6fdc44a9b54b104375303924",
    "reftest"
   ],
   "css/css-paint-api/registered-property-value-017.https.html": [
-   "1ec2e1b5ab031a4c5842c190a081a7c4de14091f",
+   "609f00f6d0067efb6fdc44a9b54b104375303924",
    "reftest"
   ],
   "css/css-paint-api/registered-property-value-018.https.html": [
-   "6be2cb8a228e34c0771c9e59b69409edf402feee",
+   "1f9876b6b502484c1821e559fc038d1050718d0b",
    "reftest"
   ],
   "css/css-paint-api/resources/html5.png": [
@@ -367906,7 +368166,7 @@
    "support"
   ],
   "css/css-paint-api/style-background-image.https.html": [
-   "13204cf709f284920428bbc73f55b746597e0dc2",
+   "8e5f2f81547f0305ff230198f1b0300c838adfde",
    "reftest"
   ],
   "css/css-paint-api/style-before-pseudo-ref.html": [
@@ -367914,7 +368174,7 @@
    "support"
   ],
   "css/css-paint-api/style-before-pseudo.https.html": [
-   "f7e2a164f177afb60baf72ef14e74b4c331c1f39",
+   "017b23a6caf66219a2b5912ce6eb9316cd0adfe5",
    "reftest"
   ],
   "css/css-paint-api/style-first-letter-pseudo-ref.html": [
@@ -367922,7 +368182,7 @@
    "support"
   ],
   "css/css-paint-api/style-first-letter-pseudo.https.html": [
-   "02b114560fd894eaacb9387d517de1bad7665423",
+   "d3c31a0508dc86aa0da95815ff2448bc2e074caf",
    "reftest"
   ],
   "css/css-paint-api/valid-image-after-load-ref.html": [
@@ -367930,7 +368190,7 @@
    "support"
   ],
   "css/css-paint-api/valid-image-after-load.https.html": [
-   "44612f98ffd50d0c2431662e6a325297dfc387a7",
+   "c1bf8e85548656b60145c4d54437b10a2f07880e",
    "reftest"
   ],
   "css/css-paint-api/valid-image-before-load-ref.html": [
@@ -367938,7 +368198,7 @@
    "support"
   ],
   "css/css-paint-api/valid-image-before-load.https.html": [
-   "7738d9dd115d1a3bdcd922c797d5aee65e06bf84",
+   "b58dfa114ea8327dbce264b44c87a4c92d2b3eb9",
    "reftest"
   ],
   "css/css-parser-api/META.yml": [
@@ -368830,7 +369090,7 @@
    "testharness"
   ],
   "css/css-properties-values-api/unit-cycles.html": [
-   "c26e1cda1f6842655e7e0158d6a934e470f486ae",
+   "5301b6fcc77b1b7885ef7602410e4f4586391b4f",
    "testharness"
   ],
   "css/css-properties-values-api/url-resolution.html": [
@@ -373209,6 +373469,22 @@
    "30592b44cec51eb7f0835c7abc9aaafe7458ceff",
    "support"
   ],
+  "css/css-text-decor/reference/text-decoration-thickness-001-notref.html": [
+   "f876afa68c655535017fe5a6e6feff0ce1df4045",
+   "support"
+  ],
+  "css/css-text-decor/reference/text-decoration-thickness-green-rect-ref.html": [
+   "14d1219001c85dcf785e648db81ca5d6fc6d4301",
+   "support"
+  ],
+  "css/css-text-decor/reference/text-decoration-thickness-scroll-001-ref.html": [
+   "394811468fea2d4e7daaffad19742cd8e206a8bd",
+   "support"
+  ],
+  "css/css-text-decor/reference/text-decoration-thickness-vertical-green-rect-ref.html": [
+   "8955e8469aa6cd3d63a34e9376b3f6c135f01e85",
+   "support"
+  ],
   "css/css-text-decor/reference/text-decoration-underline-position-horizontal-ref.html": [
    "be9155bbcf82bec1011de42ed5054ca8d1da72de",
    "support"
@@ -373225,22 +373501,6 @@
    "2370054a8fbd5cb8c00bfb95401129d01de38d00",
    "support"
   ],
-  "css/css-text-decor/reference/text-decoration-width-001-notref.html": [
-   "53a87c014d7dff7a33c2cbf042c181173a351618",
-   "support"
-  ],
-  "css/css-text-decor/reference/text-decoration-width-green-rect-ref.html": [
-   "7bc3865a8619ccfb6f5e621b8443d6680f9f2739",
-   "support"
-  ],
-  "css/css-text-decor/reference/text-decoration-width-scroll-001-ref.html": [
-   "dd4868417ba51bfa0b7d86ed4a2f2c3526acb9e5",
-   "support"
-  ],
-  "css/css-text-decor/reference/text-decoration-width-vertical-green-rect-ref.html": [
-   "ec7db180dc2c29e82ebb4f2565faf6eeb9b8720c",
-   "support"
-  ],
   "css/css-text-decor/reference/text-emphasis-color-001-ref.xht": [
    "8380c197b326fa184369094e75c7748fff209ee2",
    "support"
@@ -373625,6 +373885,62 @@
    "d4538e7c7b45356d08cf5dc90273b6aee77c49fa",
    "reftest"
   ],
+  "css/css-text-decor/text-decoration-thickness-001.html": [
+   "8f314793f2634406c8ad5d3fa268bf56eb864406",
+   "reftest"
+  ],
+  "css/css-text-decor/text-decoration-thickness-computed-expected.txt": [
+   "bf1fb8e0a97f384beb854a574c43bf3ff9fc688e",
+   "support"
+  ],
+  "css/css-text-decor/text-decoration-thickness-computed.html": [
+   "99e693afb5a395f3aa4af59a735054ce3559069c",
+   "testharness"
+  ],
+  "css/css-text-decor/text-decoration-thickness-initial-expected.txt": [
+   "b0c8c34fda852543cdd19201474c6defa3b1b8f0",
+   "support"
+  ],
+  "css/css-text-decor/text-decoration-thickness-initial.html": [
+   "4c4ca9cc9ab972f61bd9cc6dc87f03e29d027241",
+   "testharness"
+  ],
+  "css/css-text-decor/text-decoration-thickness-invalid.html": [
+   "656fa3bba2aee70381eb1c0e82e963f9f4bea502",
+   "testharness"
+  ],
+  "css/css-text-decor/text-decoration-thickness-linethrough-001.html": [
+   "37e954b2b8769e882420a49ef0adf42a8b4b096e",
+   "reftest"
+  ],
+  "css/css-text-decor/text-decoration-thickness-overline-001.html": [
+   "325811c96fd45463cc4802232fc6e5f5df6fd652",
+   "reftest"
+  ],
+  "css/css-text-decor/text-decoration-thickness-scroll-001.html": [
+   "acc829dc66d75e776dbe4ca5ad2976576c5c3241",
+   "reftest"
+  ],
+  "css/css-text-decor/text-decoration-thickness-underline-001.html": [
+   "020f849f4cf2d1ffcee7ba494384fc8f5425b876",
+   "reftest"
+  ],
+  "css/css-text-decor/text-decoration-thickness-valid-expected.txt": [
+   "6af800675323579069a86823ff176348484bd29c",
+   "support"
+  ],
+  "css/css-text-decor/text-decoration-thickness-valid.html": [
+   "d05c892674844691ec23bcad1bf4dbd8ab53981c",
+   "testharness"
+  ],
+  "css/css-text-decor/text-decoration-thickness-vertical-001.html": [
+   "f04f1b52f95fb307043519c8da9ec34ad978a5f2",
+   "reftest"
+  ],
+  "css/css-text-decor/text-decoration-thickness-vertical-002.html": [
+   "70421c507b71e5e0e9775fa73ab5f8671912b80b",
+   "reftest"
+  ],
   "css/css-text-decor/text-decoration-underline-position-horizontal.html": [
    "e4d495e722e43414e562c315c530c285d7bc6356",
    "reftest"
@@ -373685,54 +374001,10 @@
    "904460a7bfeef5a35261641422a5fde2dd07dce4",
    "visual"
   ],
-  "css/css-text-decor/text-decoration-width-001.html": [
-   "ab6dfcadeb1ae1ab967efb85d23470b90a26aefe",
-   "reftest"
-  ],
-  "css/css-text-decor/text-decoration-width-computed.html": [
-   "0e00240141ea45ac95e8778474df3472afaf766c",
-   "testharness"
-  ],
   "css/css-text-decor/text-decoration-width-initial-expected.txt": [
    "cd582e81b24d0c96c7213f01d9f77df284a2b2b0",
    "support"
   ],
-  "css/css-text-decor/text-decoration-width-initial.html": [
-   "ee47af0f115d29705b2cb485af63ecec67b5645e",
-   "testharness"
-  ],
-  "css/css-text-decor/text-decoration-width-invalid.html": [
-   "e89fe47ff2d567db6eae913a49d3abe2d62eaa7c",
-   "testharness"
-  ],
-  "css/css-text-decor/text-decoration-width-linethrough-001.html": [
-   "cc48da15a7a7f07c2efb51868d38a02222420ebd",
-   "reftest"
-  ],
-  "css/css-text-decor/text-decoration-width-overline-001.html": [
-   "21eb18b7ab28defcdd5921b3730f11f48bbe848c",
-   "reftest"
-  ],
-  "css/css-text-decor/text-decoration-width-scroll-001.html": [
-   "f203bf10c2d67c664a263694c5f6ac69771edc42",
-   "reftest"
-  ],
-  "css/css-text-decor/text-decoration-width-underline-001.html": [
-   "97ecc73a4a9119056720daa25e6dc32aefd45012",
-   "reftest"
-  ],
-  "css/css-text-decor/text-decoration-width-valid.html": [
-   "583ebb0d3cf52d5af73da39f979e2c1d90ffa8ea",
-   "testharness"
-  ],
-  "css/css-text-decor/text-decoration-width-vertical-001.html": [
-   "5b4ab5e74dd8b7efa572e4858c7a1d616d62b8e8",
-   "reftest"
-  ],
-  "css/css-text-decor/text-decoration-width-vertical-002.html": [
-   "cbe4b1f8374c4617b43ef288906e6dd5f1a1e347",
-   "reftest"
-  ],
   "css/css-text-decor/text-emphasis-color-001.xht": [
    "b60f03591ed067b8a8411cdad2ea8bcd222a37fc",
    "reftest"
@@ -378353,6 +378625,14 @@
    "9525b994a8f0c296bc703b19baf91bef4f84c686",
    "support"
   ],
+  "css/css-text/text-transform/reference/text-transform-fullwidth-006-ref.html": [
+   "3d2f9c7be2236666bd680a09c834668616fde44d",
+   "support"
+  ],
+  "css/css-text/text-transform/reference/text-transform-fullwidth-007-ref.html": [
+   "b8fc5662bd83d9f29aabadbd4eb973e91621f1ed",
+   "support"
+  ],
   "css/css-text/text-transform/reference/text-transform-lowercase-001-ref.xht": [
    "3d6eb4af8ac5aeb7fd54e1b2e2aec325886ddca0",
    "support"
@@ -378701,6 +378981,14 @@
    "a1e1c12270146490f983fa02c1b21b923434e844",
    "support"
   ],
+  "css/css-text/text-transform/text-transform-fullwidth-006.html": [
+   "b0a509758ed56ca4051e1df079c4d758352764c3",
+   "reftest"
+  ],
+  "css/css-text/text-transform/text-transform-fullwidth-007.html": [
+   "6e081544a193949b217530b49f71eadfe2800be4",
+   "reftest"
+  ],
   "css/css-text/text-transform/text-transform-lowercase-001.xht": [
    "dc3fadf64caf5786123250da2cc50187ec693d2b",
    "reftest"
@@ -379037,6 +379325,30 @@
    "828058f53dd811d4dbea0b7e0d56ab5a940725c6",
    "reftest"
   ],
+  "css/css-text/white-space/break-spaces-tab-001.html": [
+   "4b01a60395a6c1133c7af8af957dd70859db4823",
+   "reftest"
+  ],
+  "css/css-text/white-space/break-spaces-tab-002.html": [
+   "d86918b75fbef27e6cee5d11c844fd971bee595f",
+   "reftest"
+  ],
+  "css/css-text/white-space/break-spaces-tab-003.html": [
+   "0d762a426aa323547c5e18daa36b1f55a715e7fc",
+   "reftest"
+  ],
+  "css/css-text/white-space/break-spaces-tab-004.html": [
+   "4ccbdd0f21ae4232effc200784dcbe4f3373ea21",
+   "reftest"
+  ],
+  "css/css-text/white-space/break-spaces-tab-005.html": [
+   "b5cf3f33ec2bb582bb3f322eeed7c45b426f0936",
+   "reftest"
+  ],
+  "css/css-text/white-space/break-spaces-tab-006.html": [
+   "85d821a3e4d476e6fdfe74a7a2f9134ffb2629a3",
+   "reftest"
+  ],
   "css/css-text/white-space/control-chars-000.html": [
    "b038fe9a90d3b8b9cb3bde7fd46396c7121688c9",
    "reftest"
@@ -379421,6 +379733,38 @@
    "ab2759fdc7b094fa9f4012b557abc27fb6bf8ffd",
    "reftest"
   ],
+  "css/css-text/white-space/pre-wrap-tab-001.html": [
+   "e57da83e9fb7e28e7ddba5a091be1331eb804c7a",
+   "reftest"
+  ],
+  "css/css-text/white-space/pre-wrap-tab-002.html": [
+   "11ec850940856258d6b5f96b5d6bed05181910b3",
+   "reftest"
+  ],
+  "css/css-text/white-space/pre-wrap-tab-003.html": [
+   "a54debe80a24b6a1ac660a1c131494a7f4c6b2bd",
+   "reftest"
+  ],
+  "css/css-text/white-space/pre-wrap-tab-004.html": [
+   "22c3ec45c68d5cf508fe326b1395cef22a4f1e23",
+   "reftest"
+  ],
+  "css/css-text/white-space/pre-wrap-tab-005.html": [
+   "993aa92e370b708855aa883591e13251f9015364",
+   "reftest"
+  ],
+  "css/css-text/white-space/pre-wrap-tab-006.html": [
+   "a4c7f3d3ebd9ae73a494769b18f046185672030c",
+   "reftest"
+  ],
+  "css/css-text/white-space/reference/break-spaces-tab-003-ref.html": [
+   "52a8c491cca2da9426e318d2e36786d05fe74e06",
+   "support"
+  ],
+  "css/css-text/white-space/reference/break-spaces-tab-005-ref.html": [
+   "798e35fd660b9d1e9681c7de01cb0efc923e6aa6",
+   "support"
+  ],
   "css/css-text/white-space/reference/control-chars-000-ref.html": [
    "9d5fcb27147a8c53e410d08511cb5035b612f80c",
    "support"
@@ -388045,14 +388389,18 @@
    "956c6e578b098d1c5a69f8228cb85434b1d048ee",
    "testharness"
   ],
+  "css/css-typed-om/the-stylepropertymap/properties/text-decoration-thickness-expected.txt": [
+   "8bcb9e996b18b4d66155c0b86b526beddfc28753",
+   "support"
+  ],
+  "css/css-typed-om/the-stylepropertymap/properties/text-decoration-thickness.html": [
+   "903ca8603fb882e19c0ecfc6760a64495e6361dd",
+   "testharness"
+  ],
   "css/css-typed-om/the-stylepropertymap/properties/text-decoration-width-expected.txt": [
    "ea49214f78331eaad031a754b5c5d2fe45b8392d",
    "support"
   ],
-  "css/css-typed-om/the-stylepropertymap/properties/text-decoration-width.html": [
-   "43aeb165645d10bea23db42055453001223f0f3e",
-   "testharness"
-  ],
   "css/css-typed-om/the-stylepropertymap/properties/text-decoration.html": [
    "e9a9827c13d08b26fd3910e4f59a6d80cc941bf3",
    "testharness"
@@ -429230,7 +429578,7 @@
    "support"
   ],
   "html/semantics/embedded-content/media-elements/track/track-element/resources/captions-fast.vtt": [
-   "cd138fd32af8056e968e7571cd0ab2fe6f02c68d",
+   "7fe5b1241a2261a001b3b903528eb275ae5cb0c3",
    "support"
   ],
   "html/semantics/embedded-content/media-elements/track/track-element/resources/captions-gaps.vtt": [
@@ -431441,8 +431789,12 @@
    "4fbf3f5adddbcb8ec95fc0e2192f4da841e93b8c",
    "support"
   ],
+  "html/semantics/embedded-content/the-img-element/invalid-src-expected.txt": [
+   "4b8f9770143f1120cc6b2842593d6b59e151589d",
+   "support"
+  ],
   "html/semantics/embedded-content/the-img-element/invalid-src.html": [
-   "49e956565cc7c386cf548eab37097a9b995d4f1b",
+   "c3c57ee3c0a05019be4db6650eeefdd53648401e",
    "testharness"
   ],
   "html/semantics/embedded-content/the-img-element/ismap/img-ismap-coordinates-iframe-after.html": [
@@ -439862,7 +440214,7 @@
    "support"
   ],
   "interfaces/webrtc.idl": [
-   "83f009fed5346c978deb90b29f3bcc0260e21f58",
+   "faccd6f47d37443c0d5df63ce71a1f68ebc07bc2",
    "support"
   ],
   "interfaces/webusb.idl": [
@@ -439885,7 +440237,7 @@
    "27660bfd573b6dbd38f7c52b514fab9f4bd52996",
    "support"
   ],
-  "interfaces/xslt.idl": [
+  "interfaces/xslt.tentative.idl": [
    "e97d8b000441bf7c700d377f20f74b44831cffa3",
    "support"
   ],
@@ -440417,6 +440769,10 @@
    "02b1bb0c78f9765257a35aed076701e2f0aa757e",
    "support"
   ],
+  "loading/lazyload/common.js": [
+   "f5013fc288f58b71a14d01269db14385dd80c8a5",
+   "support"
+  ],
   "loading/lazyload/iframe-loading-eager.tentative.html": [
    "26209332ff5a0c4af64e0ae4893f1c396a111ce1",
    "testharness"
@@ -440433,6 +440789,14 @@
    "5920eb1882df0a69e0d23c26433bf1b28b9275e9",
    "testharness"
   ],
+  "loading/lazyload/original-base-url-applied-tentative.html": [
+   "06f9c257ee9e1b10c626e4a36c826a41506dea89",
+   "testharness"
+  ],
+  "loading/lazyload/original-referrer-policy-applied-tentative.sub.html": [
+   "2ffbc821c66a256765f00773afcef5ed94ac5a44",
+   "testharness"
+  ],
   "loading/lazyload/resources/image.png": [
    "b712825093805d1052b01047b1dbb102f0af8f0f",
    "support"
@@ -454278,7 +454642,7 @@
    "testharness"
   ],
   "preload/subresource-integrity-expected.txt": [
-   "a75402793bea0d8be381eba5afccfcd2435d9722",
+   "fc8970bae9b42146cd19fb0ea36cb3f832e9bdd7",
    "support"
   ],
   "preload/subresource-integrity.html": [
@@ -469702,7 +470066,7 @@
    "testharness"
   ],
   "sms/interceptor.https.html": [
-   "b7e8fd53bff98c6c64554149e0cd71c5f1f45686",
+   "86b21922284f946a16bcd295a87851bee7569f9a",
    "testharness"
   ],
   "sms/resources/iframe.html": [
@@ -469714,7 +470078,7 @@
    "testharness"
   ],
   "sms/sms_provider.js": [
-   "6a54e47b24111f075cb88262a5ffd3dea75a994d",
+   "4506135551c771d056dc202f06a4c00a7c31089f",
    "support"
   ],
   "sms/sms_receiver.idl": [
@@ -482214,7 +482578,7 @@
    "wdspec"
   ],
   "webdriver/tests/perform_actions/pointer_contextmenu.py": [
-   "c64c51252a5a4a5be3464fe92e0ced0a81a486a1",
+   "fda3f18bbc1c9cdcede30abe74f6d4e2f297d48f",
    "wdspec"
   ],
   "webdriver/tests/perform_actions/pointer_dblclick.py": [
@@ -483278,11 +483642,11 @@
    "testharness"
   ],
   "webrtc/RTCPeerConnection-getStats.https-expected.txt": [
-   "14a75b02d80a4b43a5ef3e21e668f66d9466b117",
+   "9586b70e9d4defa07e31d3893635b6d5dd25b192",
    "support"
   ],
   "webrtc/RTCPeerConnection-getStats.https.html": [
-   "c2c4e8e37176ce13447c1c8238aa6243f9aea130",
+   "a42086a3733c2f46d85d8659059d9b18cef9845f",
    "testharness"
   ],
   "webrtc/RTCPeerConnection-getTransceivers.html": [
@@ -488609,8 +488973,12 @@
    "956edba98365d90eb180ad3c9697dae098bd25db",
    "testharness"
   ],
+  "webxr/xrWebGLLayer_framebuffer.https.html": [
+   "7c4ff17c2547995afbf561850faaf92b6aa5e56f",
+   "testharness"
+  ],
   "webxr/xrWebGLLayer_viewports.https.html": [
-   "9553a445e43153b716d55c7f2be606dd548b808e",
+   "8cfccff3c01dedb41db4f26563824ce0cdb65ad3",
    "testharness"
   ],
   "workers/META.yml": [
@@ -490974,7 +491342,7 @@
    "testharness"
   ],
   "xhr/getallresponseheaders-expected.txt": [
-   "04b1beca8eddc2c1329533b951335d58e04a0346",
+   "69617d196a6c6c8843d6dd55ec5bb6137a39d8b0",
    "support"
   ],
   "xhr/getallresponseheaders-status.htm": [
@@ -490982,7 +491350,7 @@
    "testharness"
   ],
   "xhr/getallresponseheaders.htm": [
-   "72e27a5947c1e00ce1edeedf21a9db83c42832fa",
+   "759d6b68a1f337cac59aed0e9a800e433b68d1b6",
    "testharness"
   ],
   "xhr/getresponseheader-case-insensitive.htm": [
@@ -491510,7 +491878,7 @@
    "support"
   ],
   "xhr/resources/headers.asis": [
-   "d25fe52efeb5427b126c3b375b4bb00090836382",
+   "69273ac87fea6974688d610910899e077a377b0f",
    "support"
   ],
   "xhr/resources/headers.py": [
@@ -492297,8 +492665,8 @@
    "7a2bf3622554937bf483a3b3afa9f16187fdabf6",
    "support"
   ],
-  "xslt/idlharness.window.js": [
-   "51b0cd3dbac772f85d50debdf414a5726875b7d4",
+  "xslt/idlharness.tentative.window.js": [
+   "1da8db8cb208aa278527bbe9192944b68e19340b",
    "testharness"
   ],
   "xslt/transformToFragment.tentative.window-expected.txt": [
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image-from-script.sub-expected.txt b/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image-from-script.sub-expected.txt
new file mode 100644
index 0000000..4f655ba
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image-from-script.sub-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Non-redirected cross-origin URLs are not stripped. Failed to construct 'URL': Invalid URL
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image-from-script.sub.html b/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image-from-script.sub.html
index 65311c3..4c86845 100644
--- a/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image-from-script.sub.html
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image-from-script.sub.html
@@ -15,8 +15,8 @@
         assert_equals(e.effectiveDirective, "img-src");
         assert_equals(e.originalPolicy, "img-src \'none\'");
         assert_equals(e.disposition, "enforce");
-        assert_equals(e.sourceFile, "");
-        assert_equals(e.lineNumber, 0);
+        assert_equals(new URL(e.sourceFile).pathname, "/content-security-policy/support/inject-image.sub.js");
+        assert_equals(e.lineNumber, 2);
         assert_equals(e.columnNumber, 0);
         assert_equals(e.statusCode, 200);
       }));
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub.html b/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub.html
index 03829fe8..dcf52aa1 100644
--- a/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub.html
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub.html
@@ -15,9 +15,9 @@
         assert_equals(e.effectiveDirective, "img-src");
         assert_equals(e.originalPolicy, "img-src \'none\'");
         assert_equals(e.disposition, "enforce");
-        assert_equals(e.sourceFile, "");
-        assert_equals(e.lineNumber, 0);
-        assert_equals(e.columnNumber, 0);
+        assert_equals(new URL(e.sourceFile).pathname, "/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub.html");
+        assert_equals(e.lineNumber, 25);
+        assert_equals(e.columnNumber, 4);
         assert_equals(e.statusCode, 200);
       }));
     
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image-from-script.sub-expected.txt b/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image-from-script.sub-expected.txt
new file mode 100644
index 0000000..4f655ba
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image-from-script.sub-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Non-redirected cross-origin URLs are not stripped. Failed to construct 'URL': Invalid URL
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image-from-script.sub.html b/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image-from-script.sub.html
index 0a7c2b43..978096f14 100644
--- a/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image-from-script.sub.html
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image-from-script.sub.html
@@ -15,8 +15,8 @@
         assert_equals(e.effectiveDirective, "img-src");
         assert_equals(e.originalPolicy, "img-src \'none\'");
         assert_equals(e.disposition, "enforce");
-        assert_equals(e.sourceFile, "");
-        assert_equals(e.lineNumber, 0);
+        assert_equals(new URL(e.sourceFile).pathname, "/content-security-policy/support/inject-image.sub.js");
+        assert_equals(e.lineNumber, 2);
         assert_equals(e.columnNumber, 0);
         assert_equals(e.statusCode, 200);
       }));
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image.sub-expected.txt b/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image.sub-expected.txt
new file mode 100644
index 0000000..cc4ede6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image.sub-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Non-redirected same-origin URLs are not stripped. Failed to construct 'URL': Invalid URL
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image.sub.html b/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image.sub.html
index 5dd82e6d..6e0e6ddb 100644
--- a/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image.sub.html
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image.sub.html
@@ -15,9 +15,9 @@
         assert_equals(e.effectiveDirective, "img-src");
         assert_equals(e.originalPolicy, "img-src \'none\'");
         assert_equals(e.disposition, "enforce");
-        assert_equals(e.sourceFile, "");
-        assert_equals(e.lineNumber, 0);
-        assert_equals(e.columnNumber, 0);
+        assert_equals(new URL(e.sourceFile).pathname, "/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image.sub.html");
+        assert_equals(e.lineNumber, 25);
+        assert_equals(e.columnNumber, 4);
         assert_equals(e.statusCode, 200);
       }));
     
diff --git a/third_party/blink/web_tests/external/wpt/css/css-box/parsing/margin-computed.html b/third_party/blink/web_tests/external/wpt/css/css-box/parsing/margin-computed.html
new file mode 100644
index 0000000..f22f6cd
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-box/parsing/margin-computed.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS basic box model: getComputedStyle().margin</title>
+<link rel="help" href="https://drafts.csswg.org/css-box-3/#propdef-margin">
+<meta name="assert" content="margin computed value has absolute lengths.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<style>
+  #parent {
+    width: 200px;
+  }
+  #target {
+    width: 0px;
+    font-size: 40px;
+  }
+</style>
+</head>
+<body>
+<div id="parent">
+  <div id="target"></div>
+</div>
+<script>
+test_computed_value("margin", "10px");
+test_computed_value("margin", "10px 20px 30px 40px");
+test_computed_value("margin", "calc(0.5em + 10px)", "30px");
+test_computed_value("margin", "30%", "60px");
+
+test_computed_value("margin-top", "10px");
+test_computed_value("margin-right", "20px");
+test_computed_value("margin-bottom", "30px");
+test_computed_value("margin-left", "40px");
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-logical/parsing/block-size-computed.html b/third_party/blink/web_tests/external/wpt/css/css-logical/parsing/block-size-computed.html
new file mode 100644
index 0000000..de3a3c2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-logical/parsing/block-size-computed.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Logical Properties and Values: getComputedStyle().blockSize</title>
+<link rel="help" href="https://drafts.csswg.org/css-logical-1/#dimension-properties">
+<meta name="assert" content="block-size computed value is an absolute length.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<style>
+  #parent {
+    height: 300px;
+  }
+  #target {
+    width: 0px;
+    height: 0px;
+    font-size: 40px;
+  }
+  #child {
+    height: 80px;
+  }
+</style>
+</head>
+<body>
+<div id="parent">
+  <div id="target">
+    <div id="child">
+    </div>
+  </div>
+</div>
+<script>
+test_computed_value("block-size", "auto", "80px"); // child height
+
+test_computed_value("block-size", "10px");
+test_computed_value("block-size", "20%", "60px");
+test_computed_value("block-size", "calc(0.5em + 10px)", "30px");
+test_computed_value("block-size", "calc(-0.5em + 10px)", "0px");
+
+test_computed_value("block-size", "min-content", "80px"); // child height
+test_computed_value("block-size", "max-content", "80px");
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-logical/parsing/inline-size-computed.html b/third_party/blink/web_tests/external/wpt/css/css-logical/parsing/inline-size-computed.html
new file mode 100644
index 0000000..0f60165
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-logical/parsing/inline-size-computed.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Logical Properties and Values: getComputedStyle().inlineSize</title>
+<link rel="help" href="https://drafts.csswg.org/css-logical-1/#dimension-properties">
+<meta name="assert" content="inline-size computed value is an absolute length.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<style>
+  #parent {
+    width: 200px;
+  }
+  #target {
+    width: 0px;
+    height: 0px;
+    font-size: 40px;
+  }
+  #child {
+    width: 60px;
+  }
+</style>
+</head>
+<body>
+<div id="parent">
+  <div id="target">
+    <div id="child">
+    </div>
+  </div>
+</div>
+<script>
+test_computed_value("inline-size", "auto", "200px"); // parent width
+
+test_computed_value("inline-size", "10px");
+test_computed_value("inline-size", "20%", "40px");
+test_computed_value("inline-size", "calc(0.5em + 10px)", "30px");
+test_computed_value("inline-size", "calc(-0.5em + 10px)", "0px");
+
+test_computed_value("inline-size", "min-content", "60px"); // child width
+test_computed_value("inline-size", "max-content", "60px");
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-dynamic-add-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-dynamic-add-001-ref.html
new file mode 100644
index 0000000..380c746
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-dynamic-add-001-ref.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+  <meta charset="utf-8">
+  <title>CSS Multi-column Layout Test: Append a block to an empty inline element</title>
+  <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+
+  <style>
+  #column {
+    column-count: 3;
+    column-rule: 6px solid;
+    width: 400px;
+    outline: 1px solid black;
+  }
+  div {
+    height: 300px;
+    background-color: yellow;
+  }
+  </style>
+  <body>
+    <article id="column">
+      <span id="span"><div>block</div></span>
+    </article>
+  </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-dynamic-add-001.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-dynamic-add-001.html
new file mode 100644
index 0000000..ccc44ad
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-dynamic-add-001.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <meta charset="utf-8">
+  <title>CSS Multi-column Layout Test: Append a block to an empty inline element</title>
+  <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-multicol-1/#cf">
+  <link rel="help" href="https://www.w3.org/TR/CSS22/visuren.html#anonymous-block-level">
+  <link rel="match" href="multicol-dynamic-add-001-ref.html">
+  <meta name="assert" content="This test checks that the block appended into an inline element should perform correct block-in-inline splitting, and balance the block's height into three columns.">
+
+  <script>
+  function runTest() {
+    document.body.offsetHeight;
+
+    /* Append a block to the inline element. */
+    var block = document.createElement("div");
+    var text = document.createTextNode("block");
+    block.appendChild(text);
+
+    var span = document.getElementById("span");
+    span.appendChild(block);
+
+    document.documentElement.removeAttribute("class");
+  }
+  </script>
+
+  <style>
+  #column {
+    column-count: 3;
+    column-rule: 6px solid;
+    width: 400px;
+    outline: 1px solid black;
+  }
+  div {
+    height: 300px;
+    background-color: yellow;
+  }
+  </style>
+
+  <body onload="runTest();">
+    <article id="column">
+      <span id="span"><!-- block will be added here. --></span>
+    </article>
+  </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/reference/text-decoration-width-001-notref.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/reference/text-decoration-thickness-001-notref.html
similarity index 89%
rename from third_party/blink/web_tests/external/wpt/css/css-text-decor/reference/text-decoration-width-001-notref.html
rename to third_party/blink/web_tests/external/wpt/css/css-text-decor/reference/text-decoration-thickness-001-notref.html
index 53a87c0..f876afa 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text-decor/reference/text-decoration-width-001-notref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/reference/text-decoration-thickness-001-notref.html
@@ -2,7 +2,7 @@
 <html>
 <head>
     <meta charset="utf-8">
-    <title>Non-reference case for text-decoration-width</title>
+    <title>Non-reference case for text-decoration-thickness</title>
     <link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
     <style>
         #main {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/reference/text-decoration-width-green-rect-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/reference/text-decoration-thickness-green-rect-ref.html
similarity index 88%
rename from third_party/blink/web_tests/external/wpt/css/css-text-decor/reference/text-decoration-width-green-rect-ref.html
rename to third_party/blink/web_tests/external/wpt/css/css-text-decor/reference/text-decoration-thickness-green-rect-ref.html
index 7bc3865a..14d1219 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text-decor/reference/text-decoration-width-green-rect-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/reference/text-decoration-thickness-green-rect-ref.html
@@ -2,7 +2,7 @@
 <html>
 <head>
     <meta charset="utf-8">
-    <title>Reference case for text-decoration-width</title>
+    <title>Reference case for text-decoration-thickness</title>
     <link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
     <style>
         div{
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/reference/text-decoration-width-scroll-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/reference/text-decoration-thickness-scroll-001-ref.html
similarity index 87%
rename from third_party/blink/web_tests/external/wpt/css/css-text-decor/reference/text-decoration-width-scroll-001-ref.html
rename to third_party/blink/web_tests/external/wpt/css/css-text-decor/reference/text-decoration-thickness-scroll-001-ref.html
index dd48684..39481146 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text-decor/reference/text-decoration-width-scroll-001-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/reference/text-decoration-thickness-scroll-001-ref.html
@@ -2,7 +2,7 @@
 <html>
 <head>
     <meta charset="utf-8">
-    <title>Reference case for text-decoration-width</title>
+    <title>Reference case for text-decoration-thickness</title>
     <link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
     <style>
         #box{
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/reference/text-decoration-width-vertical-green-rect-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/reference/text-decoration-thickness-vertical-green-rect-ref.html
similarity index 85%
rename from third_party/blink/web_tests/external/wpt/css/css-text-decor/reference/text-decoration-width-vertical-green-rect-ref.html
rename to third_party/blink/web_tests/external/wpt/css/css-text-decor/reference/text-decoration-thickness-vertical-green-rect-ref.html
index ec7db180..8955e846 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text-decor/reference/text-decoration-width-vertical-green-rect-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/reference/text-decoration-thickness-vertical-green-rect-ref.html
@@ -2,7 +2,7 @@
 <html>
 <head>
     <meta charset="utf-8">
-    <title>Reference case for text-decoration-width</title>
+    <title>Reference case for text-decoration-thickness</title>
     <link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
     <style>
         #box{
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-001.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-001.html
similarity index 76%
rename from third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-001.html
rename to third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-001.html
index ab6dfca..8f314793 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-001.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-001.html
@@ -2,12 +2,12 @@
 <html>
 <head>
     <meta charset="utf-8">
-    <title>Test case for text-decoration-width</title>
-    <meta name="assert" content="text-decoration-width: should affect the underline thickness">
+    <title>Test case for text-decoration-thickness</title>
+    <meta name="assert" content="text-decoration-thickness: should affect the underline thickness">
     <link rel="author" title="Charlie Marlow" href="mailto:cmarlow@mozilla.com">
     <link rel="author" title="Mozilla" href="https://www.mozilla.org">
     <link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#text-decoration-width-property">
-    <link rel="mismatch" href="reference/text-decoration-width-001-notref.html">
+    <link rel="mismatch" href="reference/text-decoration-thickness-001-notref.html">
     <link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
     <style>
         #main {
@@ -21,7 +21,7 @@
             padding-right: 1em;
         }
         #rightbox {
-            text-decoration-width: 2em;
+            text-decoration-thickness: 2em;
         }
     </style>
 </head>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-computed-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-computed-expected.txt
new file mode 100644
index 0000000..bf1fb8e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-computed-expected.txt
@@ -0,0 +1,6 @@
+This is a testharness.js-based test.
+FAIL Property text-decoration-thickness value 'auto' computes to 'auto' assert_true: text-decoration-thickness doesn't seem to be supported in the computed style expected true got false
+FAIL Property text-decoration-thickness value 'from-font' computes to 'from-font' assert_true: text-decoration-thickness doesn't seem to be supported in the computed style expected true got false
+FAIL Property text-decoration-thickness value 'calc(10px - 8px)' computes to '2px' assert_true: text-decoration-thickness doesn't seem to be supported in the computed style expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-computed.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-computed.html
new file mode 100644
index 0000000..99e693a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-computed.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Text Decoration Test: parsing text-decoration-thickness computed values</title>
+<link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#text-decoration-width-property">
+<meta name="assert" content="text-decoration-thickness computed value is as specified.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value("text-decoration-thickness", "auto");
+test_computed_value("text-decoration-thickness", "from-font");
+test_computed_value("text-decoration-thickness", "calc(10px - 8px)", "2px");
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-initial-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-initial-expected.txt
new file mode 100644
index 0000000..b0c8c34
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-initial-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Initial value of text-decoration-thickness should be auto assert_equals: Must be set to value auto as initial value. expected (string) "auto" but got (undefined) undefined
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-initial.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-initial.html
similarity index 73%
rename from third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-initial.html
rename to third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-initial.html
index ee47af0f..4c4ca9cc 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-initial.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-initial.html
@@ -4,14 +4,14 @@
 <meta charset="utf-8">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
-<link rel="help" title="2.4 Text Decoration Width: the 'text-decoration-width' property"
+<link rel="help" title="2.4 Text Decoration Width: the 'text-decoration-thickness' property"
       href="https://drafts.csswg.org/css-text-decor-4/#text-decoration-width-property" />
 </head>
 <body>
 <script>
 test(function() {
-  assert_equals(getComputedStyle(document.body)["text-decoration-width"], "auto", "Must be set to value auto as initial value.");
-}, "Initial value of text-decoration-width should be auto");
+  assert_equals(getComputedStyle(document.body)["text-decoration-thickness"], "auto", "Must be set to value auto as initial value.");
+}, "Initial value of text-decoration-thickness should be auto");
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-invalid.html
new file mode 100644
index 0000000..656fa3bb
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-invalid.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Text Decoration Test: parsing text-decoration-thickness with invalid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#text-decoration-width-property">
+<meta name="assert" content="text-decoration-thickness supports the following values: auto | from-font | <length>">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_invalid_value("text-decoration-thickness", "otto");
+test_invalid_value("text-decoration-thickness", "asdlflj");
+test_invalid_value("text-decoration-thickness", "-10");
+test_invalid_value("text-decoration-thickness", "60002020");
+test_invalid_value("text-decoration-thickness", "!@#$%^&");
+test_invalid_value("text-decoration-thickness", "10e2");
+test_invalid_value("text-decoration-thickness", "from font");
+test_invalid_value("text-decoration-thickness", "10%");
+test_invalid_value("text-decoration-thickness", "-27%");
+test_invalid_value("text-decoration-thickness", "calc(40% - 20px)");
+test_invalid_value("text-decoration-thickness", "calc(100% - 40em)");
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-linethrough-001.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-linethrough-001.html
similarity index 78%
rename from third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-linethrough-001.html
rename to third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-linethrough-001.html
index cc48da1..37e954b 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-linethrough-001.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-linethrough-001.html
@@ -2,12 +2,12 @@
 <html>
 <head>
     <meta charset="utf-8">
-    <title>Test case for text-decoration-width</title>
-    <meta name="assert" content="text-decoration-width; the width of the decoration line is increased">
+    <title>Test case for text-decoration-thickness</title>
+    <meta name="assert" content="text-decoration-thickness; the width of the decoration line is increased">
     <link rel="author" title="Charlie Marlow" href="mailto:cmarlow@mozilla.com">
     <link rel="author" title="Mozilla" href="https://www.mozilla.org">
     <link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#text-decoration-width-property">
-    <link rel="match" href="reference/text-decoration-width-green-rect-ref.html">
+    <link rel="match" href="reference/text-decoration-thickness-green-rect-ref.html">
     <link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
     <style>
         div{
@@ -22,7 +22,7 @@
              * it will entirely cover the div's content-box (making it fully green) as long
              * as the line-through is approximately centered, vertically.
              */
-            text-decoration-width: 1.1em;
+            text-decoration-thickness: 1.1em;
         }
     </style>
 </head>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-overline-001.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-overline-001.html
similarity index 78%
rename from third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-overline-001.html
rename to third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-overline-001.html
index 21eb18b..325811c 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-overline-001.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-overline-001.html
@@ -2,12 +2,12 @@
 <html>
 <head>
     <meta charset="utf-8">
-    <title>Test case for text-decoration-width</title>
-    <meta name="assert" content="text-decoration-width: the width of the decoration line is increased">
+    <title>Test case for text-decoration-thickness</title>
+    <meta name="assert" content="text-decoration-thickness: the width of the decoration line is increased">
     <link rel="author" title="Charlie Marlow" href="mailto:cmarlow@mozilla.com">
     <link rel="author" title="Mozilla" href="https://www.mozilla.org">
     <link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#text-decoration-width-property">
-    <link rel="match" href="reference/text-decoration-width-green-rect-ref.html">
+    <link rel="match" href="reference/text-decoration-thickness-green-rect-ref.html">
     <link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
     <style>
         #box{
@@ -27,7 +27,7 @@
             top: 3em;
             text-decoration: green overline;
             text-decoration-skip-ink: none;
-            text-decoration-width: 4em;
+            text-decoration-thickness: 4em;
         }
     </style>
 </head>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-scroll-001.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-scroll-001.html
similarity index 78%
rename from third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-scroll-001.html
rename to third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-scroll-001.html
index f203bf1..acc829d 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-scroll-001.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-scroll-001.html
@@ -2,12 +2,12 @@
 <html>
 <head>
     <meta charset="utf-8">
-    <title>Test case for text-decoration-width</title>
-    <meta name="assert" content="text-decoration-width: increased width text decorations don't create scrollable overflow">
+    <title>Test case for text-decoration-thickness</title>
+    <meta name="assert" content="text-decoration-thickness: increased width text decorations don't create scrollable overflow">
     <link rel="author" title="Charlie Marlow" href="mailto:cmarlow@mozilla.com">
     <link rel="author" title="Mozilla" href="https://www.mozilla.org">
     <link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#text-decoration-width-property">
-    <link rel="match" href="reference/text-decoration-width-scroll-001-ref.html">
+    <link rel="match" href="reference/text-decoration-thickness-scroll-001-ref.html">
     <link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
     <style>
         #box{
@@ -29,7 +29,7 @@
             color: transparent;
             text-decoration: green underline;
             text-decoration-skip-ink: none;
-            text-decoration-width: 8em;
+            text-decoration-thickness: 8em;
         }
     </style>
 </head>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-underline-001.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-underline-001.html
similarity index 78%
rename from third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-underline-001.html
rename to third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-underline-001.html
index 97ecc73a..020f849f 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-underline-001.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-underline-001.html
@@ -2,12 +2,12 @@
 <html>
 <head>
     <meta charset="utf-8">
-    <title>Test case for text-decoration-width</title>
-    <meta name="assert" content="text-decoration-width: the width of the decoration line is increased">
+    <title>Test case for text-decoration-thickness</title>
+    <meta name="assert" content="text-decoration-thickness: the width of the decoration line is increased">
     <link rel="author" title="Charlie Marlow" href="mailto:cmarlow@mozilla.com">
     <link rel="author" title="Mozilla" href="https://www.mozilla.org">
     <link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#text-decoration-width-property">
-    <link rel="match" href="reference/text-decoration-width-green-rect-ref.html">
+    <link rel="match" href="reference/text-decoration-thickness-green-rect-ref.html">
     <link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
     <style>
         #box{
@@ -27,7 +27,7 @@
             bottom: 3em;
             text-decoration: green underline;
             text-decoration-skip-ink: none;
-            text-decoration-width: 4em;
+            text-decoration-thickness: 4em;
         }
     </style>
 </head>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-valid-expected.txt
new file mode 100644
index 0000000..6af8006
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-valid-expected.txt
@@ -0,0 +1,11 @@
+This is a testharness.js-based test.
+FAIL e.style['text-decoration-thickness'] = "auto" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['text-decoration-thickness'] = "from-font" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['text-decoration-thickness'] = "-10px" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['text-decoration-thickness'] = "2001em" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['text-decoration-thickness'] = "-49em" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['text-decoration-thickness'] = "53px" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['text-decoration-thickness'] = "calc(40em - 10px)" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['text-decoration-thickness'] = "calc(-50em + 13px)" should set the property value assert_not_equals: property should be set got disallowed value ""
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-valid.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-valid.html
new file mode 100644
index 0000000..d05c892
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-valid.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Text Decoration Test: parsing text-decoration-thickness longhands with valid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#text-decoration-width-property">
+<meta name="assert" content="text-decoration-thickness supports the following values: auto | from-font | <length>">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_valid_value("text-decoration-thickness", "auto");
+test_valid_value("text-decoration-thickness", "from-font");
+test_valid_value("text-decoration-thickness", "-10px");
+test_valid_value("text-decoration-thickness", "2001em");
+test_valid_value("text-decoration-thickness", "-49em");
+test_valid_value("text-decoration-thickness", "53px");
+test_valid_value("text-decoration-thickness", "calc(40em - 10px)");
+test_valid_value("text-decoration-thickness", "calc(-50em + 13px)");
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-vertical-001.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-vertical-001.html
similarity index 82%
rename from third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-vertical-001.html
rename to third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-vertical-001.html
index 5b4ab5e..f04f1b5 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-vertical-001.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-vertical-001.html
@@ -2,12 +2,12 @@
 <html>
 <head>
     <meta charset="utf-8">
-    <title>Test case for text-decoration-width</title>
-    <meta name="assert" content="text-decoration-width: the width of the decoration line is increased">
+    <title>Test case for text-decoration-thickness</title>
+    <meta name="assert" content="text-decoration-thickness: the width of the decoration line is increased">
     <link rel="author" title="Charlie Marlow" href="mailto:cmarlow@mozilla.com">
     <link rel="author" title="Mozilla" href="https://www.mozilla.org">
     <link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#text-decoration-width-property">
-    <link rel="match" href="reference/text-decoration-width-vertical-green-rect-ref.html">
+    <link rel="match" href="reference/text-decoration-thickness-vertical-green-rect-ref.html">
     <link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
     <style>
         #box{
@@ -34,7 +34,7 @@
             left: 1.3em;
             text-decoration: green underline;
             text-decoration-skip-ink: none;
-            text-decoration-width: 1.5em;
+            text-decoration-thickness: 1.5em;
         }
     </style>
 </head>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-vertical-002.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-vertical-002.html
similarity index 87%
rename from third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-vertical-002.html
rename to third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-vertical-002.html
index cbe4b1f..70421c50 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-vertical-002.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-thickness-vertical-002.html
@@ -2,12 +2,12 @@
 <html>
 <head>
     <meta charset="utf-8">
-    <title>Test case for text-decoration-width</title>
+    <title>Test case for text-decoration-thickness</title>
     <meta name="assert" content="text-decoration:width; the width of the decoration line is increased">
     <link rel="author" title="Charlie Marlow" href="mailto:cmarlow@mozilla.com">
     <link rel="author" title="Mozilla" href="https://www.mozilla.org">
     <link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#text-decoration-width-property">
-    <link rel="match" href="reference/text-decoration-width-vertical-green-rect-ref.html">
+    <link rel="match" href="reference/text-decoration-thickness-vertical-green-rect-ref.html">
     <link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
     <style>
         #box{
@@ -33,7 +33,7 @@
             right: 1em;
             text-decoration: green underline;
             text-decoration-skip-ink: none;
-            text-decoration-width: 1.2em;
+            text-decoration-thickness: 1.2em;
         }
     </style>
 </head>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-computed.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-computed.html
deleted file mode 100644
index 0e002401..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-computed.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="utf-8">
-<title>CSS Text Decoration Test: parsing text-decoration-width computed values</title>
-<link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#text-decoration-width-property">
-<meta name="assert" content="text-decoration-width computed value is as specified.">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/css/support/computed-testcommon.js"></script>
-</head>
-<body>
-<div id="target"></div>
-<script>
-test_computed_value("text-decoration-width", "auto");
-test_computed_value("text-decoration-width", "from-font");
-test_computed_value("text-decoration-width", "calc(10px - 8px)", "2px");
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-invalid.html
deleted file mode 100644
index e89fe47f..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-invalid.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="utf-8">
-<title>CSS Text Decoration Test: parsing text-decoration-width with invalid values</title>
-<link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#text-decoration-width-property">
-<meta name="assert" content="text-decoration-width supports the following values: auto | from-font | <length>">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/css/support/parsing-testcommon.js"></script>
-</head>
-<body>
-<script>
-test_invalid_value("text-decoration-width", "otto");
-test_invalid_value("text-decoration-width", "asdlflj");
-test_invalid_value("text-decoration-width", "-10");
-test_invalid_value("text-decoration-width", "60002020");
-test_invalid_value("text-decoration-width", "!@#$%^&");
-test_invalid_value("text-decoration-width", "10e2");
-test_invalid_value("text-decoration-width", "from font");
-test_invalid_value("text-decoration-width", "10%");
-test_invalid_value("text-decoration-width", "-27%");
-test_invalid_value("text-decoration-width", "calc(40% - 20px)");
-test_invalid_value("text-decoration-width", "calc(100% - 40em)");
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-valid.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-valid.html
deleted file mode 100644
index 583ebb0..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-width-valid.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="utf-8">
-<title>CSS Text Decoration Test: parsing text-decoration-width longhands with valid values</title>
-<link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#text-decoration-width-property">
-<meta name="assert" content="text-decoration-width supports the following values: auto | from-font | <length>">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/css/support/parsing-testcommon.js"></script>
-</head>
-<body>
-<script>
-test_valid_value("text-decoration-width", "auto");
-test_valid_value("text-decoration-width", "from-font");
-test_valid_value("text-decoration-width", "-10px");
-test_valid_value("text-decoration-width", "2001em");
-test_valid_value("text-decoration-width", "-49em");
-test_valid_value("text-decoration-width", "53px");
-test_valid_value("text-decoration-width", "calc(40em - 10px)");
-test_valid_value("text-decoration-width", "calc(-50em + 13px)");
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-transform/reference/text-transform-fullwidth-006-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-transform/reference/text-transform-fullwidth-006-ref.html
new file mode 100644
index 0000000..3d2f9c7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-transform/reference/text-transform-fullwidth-006-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Test Reference</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+div {
+  font: 50px/1 Ahem;
+  color: green;
+}
+</style>
+
+<p>Test passes if there are two green squares and no red.
+<div>x&#x3000;x</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-transform/reference/text-transform-fullwidth-007-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-transform/reference/text-transform-fullwidth-007-ref.html
new file mode 100644
index 0000000..b8fc5662
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-transform/reference/text-transform-fullwidth-007-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Test reference</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+div {
+  font: 50px/1 Ahem;
+  color: green;
+}
+</style>
+
+<p>Test passes if there are two green squares and no red.
+<div>x&#x3000;&#x3000;&#x3000;x</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-transform/text-transform-fullwidth-006.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-transform/text-transform-fullwidth-006.html
new file mode 100644
index 0000000..b0a5097
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-transform/text-transform-fullwidth-006.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text level 3 Test: text-transform:fullwidth and collapsed spaces</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<link rel="help" href="https://www.w3.org/TR/css-text-3/#text-transform-property">
+<link rel="match" href="reference/text-transform-fullwidth-006-ref.html">
+<meta name="assert" content="full-width does not transform collapsed U+0020 spaces to U+3000, only the remaining one after collapsing.">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+div { font: 50px/1 Ahem; }
+#test {
+  text-transform: fullwidth;
+  color: green;
+}
+#ref {
+  color: red;
+  position: absolute;
+  z-index: -1;
+}
+</style>
+
+<p>Test passes if there are two green squares and no red.
+<div id=ref>x&#x3000;x</div>
+<div id=test>x   x</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-transform/text-transform-fullwidth-007.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-transform/text-transform-fullwidth-007.html
new file mode 100644
index 0000000..6e081544
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-transform/text-transform-fullwidth-007.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text level 3 Test: text-transform:fullwidth and preserved spaces</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<link rel="help" href="https://www.w3.org/TR/css-text-3/#text-transform-property">
+<link rel="match" href="reference/text-transform-fullwidth-007-ref.html">
+<meta name="assert" content="full-width does transforms U+0020 spaces to U+3000 within preserved white space.">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+div { font: 50px/1 Ahem; }
+#test {
+  text-transform: fullwidth;
+  color: green;
+  white-space: pre-wrap;
+}
+#ref {
+  color: red;
+  position: absolute;
+  z-index: -1;
+}
+</style>
+
+<p>Test passes if there are two green squares and no red.
+<div id=ref>x&#x3000;&#x3000;&#x3000;x</div>
+<div id=test>x   x</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/break-spaces-tab-001.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/break-spaces-tab-001.html
new file mode 100644
index 0000000..4b01a60
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/break-spaces-tab-001.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text level 3 Test: wrapping opportunity after break-spaces tabs</title>
+<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-1">
+<link rel="match" href="reference/pre-wrap-001-ref.html">
+<meta name="assert" content="There is a wrapping opportunity at the end of a sequence of tabs with white-space:break-spaces">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+div {
+  font: 20px/1 Ahem;
+}
+#test {
+  white-space: break-spaces;
+  color: green;
+  width: 16ch;
+}
+#ref {
+  color: red;
+  position: absolute;
+  z-index:-1;
+}
+</style>
+
+<p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p>
+<div id=ref>XX<br>XX</div>
+<div id=test>XX&#x09;&#x09;XX</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/break-spaces-tab-002.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/break-spaces-tab-002.html
new file mode 100644
index 0000000..d86918b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/break-spaces-tab-002.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text level 3 Test: wrapping opportunity after break-spaces tabs and space</title>
+<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-1">
+<link rel="match" href="reference/pre-wrap-001-ref.html">
+<meta name="assert" content="There is a wrapping opportunity at the end of a sequence of tabs and spaces with white-space:break-spaces">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+div {
+  font: 20px/1 Ahem;
+}
+#test {
+  white-space: break-spaces;
+  color: green;
+  width: 16ch;
+}
+#ref {
+  color: red;
+  position: absolute;
+  z-index:-1;
+}
+</style>
+
+<p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p>
+<div id=ref>XX<br>XX</div>
+<div id=test>XX &#x09; &#x09;XX</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/break-spaces-tab-003.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/break-spaces-tab-003.html
new file mode 100644
index 0000000..0d762a4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/break-spaces-tab-003.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text level 3 Test: wrapping opportunity after each break-spaces tab</title>
+<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-1">
+<link rel="match" href="reference/break-spaces-tab-003-ref.html">
+<meta name="assert" content="There is a wrapping opportunity after each tab in a sequence with white-space:break-spaces.">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+div {
+  font: 20px/1 Ahem;
+}
+#test {
+  white-space: break-spaces;
+  color: green;
+  width: 1ch;
+}
+#ref {
+  color: red;
+  position: absolute;
+  z-index:-1;
+}
+</style>
+
+<p>Test passes if there are two <strong>filled green squares</strong> and <strong>no red</strong>.</p>
+<div id=ref>X<br><br><br><br><br>X</div>
+<div id=test>X&#x09;&#x09;&#x09;&#x09;&#x09;X</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/break-spaces-tab-004.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/break-spaces-tab-004.html
new file mode 100644
index 0000000..4ccbdd0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/break-spaces-tab-004.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text level 3 Test: wrapping opportunity after each break-spaces space and tab</title>
+<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-1">
+<link rel="match" href="reference/break-spaces-tab-003-ref.html">
+<meta name="assert" content="There is a wrapping opportunity after each tab and space in a sequence with white-space:break-spaces.">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+div {
+  font: 20px/1 Ahem;
+}
+#test {
+  white-space: pre-wrap;
+  color: green;
+  width: 2ch;
+}
+#ref {
+  color: red;
+  position: absolute;
+  z-index:-1;
+}
+</style>
+
+<p>Test passes if there are two <strong>filled green squares</strong> and <strong>no red</strong>.</p>
+<div id=ref>X<br><br><br><br><br>X</div>
+<div id=test>X&#x09;  &#x09;&#x09;X</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/break-spaces-tab-005.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/break-spaces-tab-005.html
new file mode 100644
index 0000000..b5cf3f3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/break-spaces-tab-005.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text level 3 Test: break-space tabs don't hang</title>
+<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-3">
+<link rel="match" href="reference/break-spaces-tab-005-ref.html">
+<meta name="assert" content="a sequence of break-spaces tabs at the end of a line does not hang.">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+div {
+  font: 20px/1 Ahem;
+}
+#test {
+  white-space: break-spaces;
+  color: green;
+  width: 2ch;
+}
+#ref {
+  white-space: pre;
+  width: 2ch;
+  background: red;
+  color: green;
+  position: absolute;
+  z-index:-1;
+}
+</style>
+
+<p>Test passes if there is a green rectangle and no red.
+<div id=ref> X<br> X<br>XX<br>XX<br>XX<br>XX<br>  </div>
+<div id=test>X<wbr>X&#x09;&#x09;&#x09;&#x09;&#x09;XX</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/break-spaces-tab-006.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/break-spaces-tab-006.html
new file mode 100644
index 0000000..85d821a3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/break-spaces-tab-006.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text level 3 Test: break-spaces tabs and spaces don't hang</title>
+<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-3">
+<link rel="match" href="reference/break-spaces-tab-005-ref.html">
+<meta name="assert" content="a sequence of break-spaces tabs and spaces at the end of a line does not hang, and can wrap after each tab or space.">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+div {
+  font: 20px/1 Ahem;
+}
+#test {
+  white-space: break-spaces;
+  color: green;
+  width: 2ch;
+}
+#ref {
+  white-space: pre;
+  width: 2ch;
+  background: red;
+  color: green;
+  position: absolute;
+  z-index:-1;
+}
+</style>
+
+<p>Test passes if there is a green rectangle and no red.
+<div id=ref> X<br> X<br>XX<br>XX<br>XX<br>XX<br>  </div>
+<div id=test>X<wbr>X&#x09;   &#x09;&#x09;XX</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-tab-001.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-tab-001.html
new file mode 100644
index 0000000..e57da83
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-tab-001.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text level 3 Test: wrapping opportunity after pre-wrap tabs</title>
+<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-1">
+<link rel="match" href="reference/pre-wrap-001-ref.html">
+<meta name="assert" content="There is a wrapping opportunity at the end of a sequence of tabs with white-space:pre-wrap">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+div {
+  font: 20px/1 Ahem;
+}
+#test {
+  white-space: pre-wrap;
+  color: green;
+  width: 16ch;
+}
+#ref {
+  color: red;
+  position: absolute;
+  z-index:-1;
+}
+</style>
+
+<p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p>
+<div id=ref>XX<br>XX</div>
+<div id=test>XX&#x09;&#x09;XX</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-tab-002.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-tab-002.html
new file mode 100644
index 0000000..11ec850
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-tab-002.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text level 3 Test: wrapping opportunity after pre-wrap tabs and spaces</title>
+<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-1">
+<link rel="match" href="reference/pre-wrap-001-ref.html">
+<meta name="assert" content="There is a wrapping opportunity at the end of a sequence of tabs and spaces with white-space:pre-wrap">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+div {
+  font: 20px/1 Ahem;
+}
+#test {
+  white-space: pre-wrap;
+  color: green;
+  width: 16ch;
+}
+#ref {
+  color: red;
+  position: absolute;
+  z-index:-1;
+}
+</style>
+
+<p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p>
+<div id=ref>XX<br>XX</div>
+<div id=test>XX &#x09; &#x09;XX</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-tab-003.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-tab-003.html
new file mode 100644
index 0000000..a54debe
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-tab-003.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text level 3 Test: no wrapping opportunity between pre-wrap tabs</title>
+<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-1">
+<link rel="match" href="reference/pre-wrap-001-ref.html">
+<meta name="assert" content="There is a wrapping opportunity at the end of a sequence of tabs with white-space:pre-wrap, but not between or before each tab.">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+div {
+  font: 20px/1 Ahem;
+}
+#test {
+  white-space: pre-wrap;
+  color: green;
+  width: 2ch;
+}
+#ref {
+  color: red;
+  position: absolute;
+  z-index:-1;
+}
+</style>
+
+<p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p>
+<div id=ref>XX<br>XX</div>
+<div id=test>XX&#x09;&#x09;XX</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-tab-004.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-tab-004.html
new file mode 100644
index 0000000..22c3ec4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-tab-004.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text level 3 Test: no wrapping opportunity between pre-wrap tabs and spaces</title>
+<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-1">
+<link rel="match" href="reference/pre-wrap-001-ref.html">
+<meta name="assert" content="There is a wrapping opportunity at the end of a sequence of tabs and spaces with white-space:pre-wrap, but not between or before each.">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+div {
+  font: 20px/1 Ahem;
+}
+#test {
+  white-space: pre-wrap;
+  color: green;
+  width: 2ch;
+}
+#ref {
+  color: red;
+  position: absolute;
+  z-index:-1;
+}
+</style>
+
+<p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p>
+<div id=ref>XX<br>XX</div>
+<div id=test>XX &#x09; &#x09;XX</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-tab-005.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-tab-005.html
new file mode 100644
index 0000000..993aa92e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-tab-005.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text level 3 Test: pre-wrap tabs hang</title>
+<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-3">
+<link rel="match" href="reference/pre-wrap-001-ref.html">
+<meta name="assert" content="a sequence of pre-wrap tabs at the end of a line hangs.">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+div {
+  font: 20px/1 Ahem;
+}
+#test {
+  white-space: pre-wrap;
+  color: green;
+  width: 2ch;
+}
+#ref {
+  color: red;
+  position: absolute;
+  z-index:-1;
+}
+</style>
+
+<p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p>
+<div id=ref>XX<br>XX</div>
+<div id=test>X<wbr>X&#x09;&#x09;XX</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-tab-006.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-tab-006.html
new file mode 100644
index 0000000..a4c7f3d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-tab-006.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text level 3 Test: pre-wrap tabs and spaces hang</title>
+<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-3">
+<link rel="match" href="reference/pre-wrap-001-ref.html">
+<meta name="assert" content="a sequence of pre-wrap tabs and spaces at the end of a line hangs.">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+div {
+  font: 20px/1 Ahem;
+}
+#test {
+  white-space: pre-wrap;
+  color: green;
+  width: 2ch;
+}
+#ref {
+  color: red;
+  position: absolute;
+  z-index:-1;
+}
+</style>
+
+<p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p>
+<div id=ref>XX<br>XX</div>
+<div id=test>X<wbr>X&#x09;  &#x09;&#x09; XX</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/break-spaces-tab-003-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/break-spaces-tab-003-ref.html
new file mode 100644
index 0000000..52a8c491
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/break-spaces-tab-003-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Test reference</title>
+<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+div {
+  font: 20px/1 Ahem;
+  color: green;
+}
+</style>
+
+<p>Test passes if there are two <strong>filled green squares</strong> and <strong>no red</strong>.</p>
+<div>X<br><br><br><br><br>X</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/break-spaces-tab-005-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/break-spaces-tab-005-ref.html
new file mode 100644
index 0000000..798e35f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/break-spaces-tab-005-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Test reference</title>
+<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+div {
+  font: 20px/1 Ahem;
+  white-space: break-spaces;
+  color: green;
+  white-space: pre;
+}
+</style>
+
+<p>Test passes if there is a green rectangle and no red.
+<div>XX<br>XX<br>XX<br>XX<br>XX<br>XX<br>XX</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/parsing/perspective-origin-computed.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/parsing/perspective-origin-computed.html
new file mode 100644
index 0000000..effeb29
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/parsing/perspective-origin-computed.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Transform Module Level 2: getComputedStyle().perspectiveOrigin</title>
+<link rel="help" href="https://drafts.csswg.org/css-transforms-2/#perspective-origin-property">
+<meta name="assert" content="perspective-origin computed value is a pair of absolute lengths">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<style>
+  #target {
+    width: 200px;
+    height: 300px;
+    font-size: 40px;
+  }
+</style>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value("perspective-origin", "10%", "20px 150px");
+test_computed_value("perspective-origin", "10% center", "20px 150px");
+test_computed_value("perspective-origin", "20% 30px", "40px 30px");
+test_computed_value("perspective-origin", "30px center", "30px 150px");
+test_computed_value("perspective-origin", "40px top", "40px 0px");
+test_computed_value("perspective-origin", "bottom 10% right 20%", "160px 270px");
+test_computed_value("perspective-origin", "bottom right", "200px 300px");
+test_computed_value("perspective-origin", "center", "100px 150px");
+test_computed_value("perspective-origin", "center 50px", "100px 50px");
+test_computed_value("perspective-origin", "center bottom", "100px 300px");
+test_computed_value("perspective-origin", "center center", "100px 150px");
+test_computed_value("perspective-origin", "center left", "0px 150px");
+test_computed_value("perspective-origin", "left", "0px 150px");
+test_computed_value("perspective-origin", "left 10px", "0px 10px");
+test_computed_value("perspective-origin", "left bottom", "0px 300px");
+test_computed_value("perspective-origin", "left center", "0px 150px");
+test_computed_value("perspective-origin", "right 40%", "200px 120px");
+test_computed_value("perspective-origin", "right 30% top -60px", "140px -60px");
+test_computed_value("perspective-origin", "top", "100px 0px");
+test_computed_value("perspective-origin", "right 20px bottom 30px", "180px 270px");
+
+test_computed_value("perspective-origin", "right calc(10px - 0.5em) top calc(10px - 0.5em)", "210px -10px");
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/parsing/perspective-origin-parsing-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/parsing/perspective-origin-invalid.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/css/css-transforms/parsing/perspective-origin-parsing-invalid.html
rename to third_party/blink/web_tests/external/wpt/css/css-transforms/parsing/perspective-origin-invalid.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/parsing/perspective-origin-parsing-valid.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/parsing/perspective-origin-valid.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/css/css-transforms/parsing/perspective-origin-parsing-valid.html
rename to third_party/blink/web_tests/external/wpt/css/css-transforms/parsing/perspective-origin-valid.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/parsing/transform-origin-computed.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/parsing/transform-origin-computed.html
new file mode 100644
index 0000000..696d89db
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/parsing/transform-origin-computed.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Transform Module Level 2: getComputedStyle().transformOrigin</title>
+<link rel="help" href="https://drafts.csswg.org/css-transforms-2/#transform-origin-property">
+<meta name="assert" content="transform-origin computed value is two or three absolute lengths">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<style>
+  #target {
+    width: 200px;
+    height: 300px;
+    font-size: 40px;
+  }
+</style>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value("transform-origin", "10%", "20px 150px");
+test_computed_value("transform-origin", "10% center", "20px 150px");
+test_computed_value("transform-origin", "20% 30px", "40px 30px");
+test_computed_value("transform-origin", "30px center", "30px 150px");
+test_computed_value("transform-origin", "40px top", "40px 0px");
+test_computed_value("transform-origin", "bottom right", "200px 300px");
+test_computed_value("transform-origin", "center", "100px 150px");
+test_computed_value("transform-origin", "center 50px", "100px 50px");
+test_computed_value("transform-origin", "center bottom", "100px 300px");
+test_computed_value("transform-origin", "center center", "100px 150px");
+test_computed_value("transform-origin", "center left", "0px 150px");
+test_computed_value("transform-origin", "left", "0px 150px");
+test_computed_value("transform-origin", "left 10px", "0px 10px");
+test_computed_value("transform-origin", "left bottom", "0px 300px");
+test_computed_value("transform-origin", "left center", "0px 150px");
+test_computed_value("transform-origin", "right 40%", "200px 120px");
+test_computed_value("transform-origin", "top", "100px 0px");
+
+test_computed_value("transform-origin", "-1px bottom 5px", "-1px 300px 5px");
+test_computed_value("transform-origin", "left center 6px", "0px 150px 6px");
+test_computed_value("transform-origin", "center top", "100px 0px");
+test_computed_value("transform-origin", "right bottom 7px", "200px 300px 7px");
+test_computed_value("transform-origin", "-1px -2px -3px");
+
+test_computed_value("transform-origin", "calc(-100% + 10px - 0.5em) calc(10px - 0.5em) calc(10px - 0.5em)", "-210px -10px -10px");
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/parsing/transform-origin-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/parsing/transform-origin-invalid.html
index 19a7c963..0dd1eea 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-transforms/parsing/transform-origin-invalid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/parsing/transform-origin-invalid.html
@@ -19,6 +19,10 @@
 test_invalid_value("transform-origin", "top 1px"); // Blink fails.
 test_invalid_value("transform-origin", "right left");
 test_invalid_value("transform-origin", "top bottom");
+
+test_invalid_value("transform-origin", "bottom 10% right 20%");
+test_invalid_value("transform-origin", "right 30% top -60px");
+test_invalid_value("transform-origin", "right 20px bottom 30px");
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/text-decoration-thickness-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/text-decoration-thickness-expected.txt
new file mode 100644
index 0000000..8bcb9e99
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/text-decoration-thickness-expected.txt
@@ -0,0 +1,15 @@
+This is a testharness.js-based test.
+FAIL Can set 'text-decoration-thickness' to CSS-wide keywords Failed to execute 'set' on 'StylePropertyMap': Invalid propertyName: text-decoration-thickness
+FAIL Can set 'text-decoration-thickness' to var() references Failed to execute 'set' on 'StylePropertyMap': Invalid propertyName: text-decoration-thickness
+FAIL Can set 'text-decoration-thickness' to the 'auto' keyword Failed to execute 'set' on 'StylePropertyMap': Invalid propertyName: text-decoration-thickness
+FAIL Can set 'text-decoration-thickness' to a length Failed to execute 'set' on 'StylePropertyMap': Invalid propertyName: text-decoration-thickness
+PASS Setting 'text-decoration-thickness' to a percent throws TypeError
+PASS Setting 'text-decoration-thickness' to a time throws TypeError
+PASS Setting 'text-decoration-thickness' to an angle throws TypeError
+PASS Setting 'text-decoration-thickness' to a flexible length throws TypeError
+PASS Setting 'text-decoration-thickness' to a number throws TypeError
+PASS Setting 'text-decoration-thickness' to a position throws TypeError
+PASS Setting 'text-decoration-thickness' to a URL throws TypeError
+PASS Setting 'text-decoration-thickness' to a transform throws TypeError
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/text-decoration-width.html b/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/text-decoration-thickness.html
similarity index 87%
rename from third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/text-decoration-width.html
rename to third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/text-decoration-thickness.html
index 43aeb16..903ca86 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/text-decoration-width.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/text-decoration-thickness.html
@@ -1,6 +1,6 @@
 <!doctype html>
 <meta charset="utf-8">
-<title>'text-decoration-width' property</title>
+<title>'text-decoration-thickness' property</title>
 <link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
 <link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
 <link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
@@ -13,7 +13,7 @@
 <script>
 'use strict';
 
-runPropertyTests('text-decoration-width', [
+runPropertyTests('text-decoration-thickness', [
   { syntax: 'auto' },
   {
     syntax: '<length>',
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/resources/captions-fast.vtt b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/resources/captions-fast.vtt
index cd138fd..7fe5b12 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/resources/captions-fast.vtt
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/resources/captions-fast.vtt
@@ -5,9 +5,9 @@
 Lorem
 
 2
-00:00:00.300 --> 00:00:00.700
+00:00:00.300 --> 00:00:01.300
 ipsum
 
 3
-00:00:01.200 --> 00:00:01.500
+00:00:01.800 --> 00:00:02.800
 dolor
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/webrtc.idl b/third_party/blink/web_tests/external/wpt/interfaces/webrtc.idl
index 83f009f..faccd6f 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/webrtc.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/webrtc.idl
@@ -4,133 +4,140 @@
 // Source: WebRTC 1.0: Real-time Communication Between Browsers (https://w3c.github.io/webrtc-pc/)
 
 dictionary RTCConfiguration {
-             sequence<RTCIceServer> iceServers;
-             RTCIceTransportPolicy iceTransportPolicy;
-             RTCBundlePolicy bundlePolicy;
-             RTCRtcpMuxPolicy rtcpMuxPolicy;
-             DOMString peerIdentity;
-             sequence<RTCCertificate> certificates;
-             [EnforceRange]
-             octet iceCandidatePoolSize = 0;
+  sequence<RTCIceServer> iceServers;
+  RTCIceTransportPolicy iceTransportPolicy;
+  RTCBundlePolicy bundlePolicy;
+  RTCRtcpMuxPolicy rtcpMuxPolicy;
+  DOMString peerIdentity;
+  sequence<RTCCertificate> certificates;
+  [EnforceRange] octet iceCandidatePoolSize = 0;
 };
 
 enum RTCIceCredentialType {
-    "password",
-    "oauth"
+  "password",
+  "oauth"
 };
 
 dictionary RTCOAuthCredential {
-    required DOMString macKey;
-    required DOMString accessToken;
+  required DOMString macKey;
+  required DOMString accessToken;
 };
 
 dictionary RTCIceServer {
-    required (DOMString or sequence<DOMString>) urls;
-             DOMString username;
-             (DOMString or RTCOAuthCredential) credential;
-             RTCIceCredentialType credentialType = "password";
+  required (DOMString or sequence<DOMString>) urls;
+  DOMString username;
+  (DOMString or RTCOAuthCredential) credential;
+  RTCIceCredentialType credentialType = "password";
 };
 
 enum RTCIceTransportPolicy {
-    "relay",
-    "all"
+  "relay",
+  "all"
 };
 
 enum RTCBundlePolicy {
-    "balanced",
-    "max-compat",
-    "max-bundle"
+  "balanced",
+  "max-compat",
+  "max-bundle"
 };
 
 enum RTCRtcpMuxPolicy {
-    // At risk due to lack of implementers' interest.
-    "negotiate",
-    "require"
+  // At risk due to lack of implementers' interest.
+  "negotiate",
+  "require"
 };
 
 dictionary RTCOfferAnswerOptions {
-             boolean voiceActivityDetection = true;
+  boolean voiceActivityDetection = true;
 };
 
 dictionary RTCOfferOptions : RTCOfferAnswerOptions {
-             boolean iceRestart = false;
+  boolean iceRestart = false;
 };
 
-dictionary RTCAnswerOptions : RTCOfferAnswerOptions {
-};
+dictionary RTCAnswerOptions : RTCOfferAnswerOptions {};
 
 enum RTCSignalingState {
-    "stable",
-    "have-local-offer",
-    "have-remote-offer",
-    "have-local-pranswer",
-    "have-remote-pranswer",
-    "closed"
+  "stable",
+  "have-local-offer",
+  "have-remote-offer",
+  "have-local-pranswer",
+  "have-remote-pranswer",
+  "closed"
 };
 
 enum RTCIceGatheringState {
-    "new",
-    "gathering",
-    "complete"
+  "new",
+  "gathering",
+  "complete"
 };
 
 enum RTCPeerConnectionState {
-    "closed",
-    "failed",
-    "disconnected",
-    "new",
-    "connecting",
-    "connected"
+  "closed",
+  "failed",
+  "disconnected",
+  "new",
+  "connecting",
+  "connected"
 };
 
 enum RTCIceConnectionState {
-    "closed",
-    "failed",
-    "disconnected",
-    "new",
-    "checking",
-    "completed",
-    "connected"
+  "closed",
+  "failed",
+  "disconnected",
+  "new",
+  "checking",
+  "completed",
+  "connected"
 };
 
-[ Constructor(optional RTCConfiguration configuration), Exposed=Window]
+[Exposed=Window, Constructor(optional RTCConfiguration configuration)]
 interface RTCPeerConnection : EventTarget {
-    Promise<RTCSessionDescriptionInit> createOffer(optional RTCOfferOptions options);
-    Promise<RTCSessionDescriptionInit> createAnswer(optional RTCAnswerOptions options);
-    Promise<void> setLocalDescription(RTCSessionDescriptionInit description);
-    readonly        attribute RTCSessionDescription? localDescription;
-    readonly        attribute RTCSessionDescription? currentLocalDescription;
-    readonly        attribute RTCSessionDescription? pendingLocalDescription;
-    Promise<void> setRemoteDescription(RTCSessionDescriptionInit description);
-    readonly        attribute RTCSessionDescription? remoteDescription;
-    readonly        attribute RTCSessionDescription? currentRemoteDescription;
-    readonly        attribute RTCSessionDescription? pendingRemoteDescription;
-    Promise<void> addIceCandidate(optional RTCIceCandidateInit candidate);
-    readonly        attribute RTCSignalingState signalingState;
-    readonly        attribute RTCIceGatheringState iceGatheringState;
-    readonly        attribute RTCIceConnectionState iceConnectionState;
-    readonly        attribute RTCPeerConnectionState connectionState;
-    readonly        attribute boolean? canTrickleIceCandidates;
-    void restartIce();
-    static sequence<RTCIceServer> getDefaultIceServers();
-    RTCConfiguration getConfiguration();
-    void setConfiguration(RTCConfiguration configuration);
-    void close();
-                    attribute EventHandler onnegotiationneeded;
-                    attribute EventHandler onicecandidate;
-                    attribute EventHandler onicecandidateerror;
-                    attribute EventHandler onsignalingstatechange;
-                    attribute EventHandler oniceconnectionstatechange;
-                    attribute EventHandler onicegatheringstatechange;
-                    attribute EventHandler onconnectionstatechange;
+  Promise<RTCSessionDescriptionInit> createOffer(optional RTCOfferOptions options);
+  Promise<RTCSessionDescriptionInit> createAnswer(optional RTCAnswerOptions options);
+  Promise<void> setLocalDescription(RTCSessionDescriptionInit description);
+  readonly attribute RTCSessionDescription? localDescription;
+  readonly attribute RTCSessionDescription? currentLocalDescription;
+  readonly attribute RTCSessionDescription? pendingLocalDescription;
+  Promise<void> setRemoteDescription(RTCSessionDescriptionInit description);
+  readonly attribute RTCSessionDescription? remoteDescription;
+  readonly attribute RTCSessionDescription? currentRemoteDescription;
+  readonly attribute RTCSessionDescription? pendingRemoteDescription;
+  Promise<void> addIceCandidate(optional RTCIceCandidateInit candidate);
+  readonly attribute RTCSignalingState signalingState;
+  readonly attribute RTCIceGatheringState iceGatheringState;
+  readonly attribute RTCIceConnectionState iceConnectionState;
+  readonly attribute RTCPeerConnectionState connectionState;
+  readonly attribute boolean? canTrickleIceCandidates;
+  void restartIce();
+  static sequence<RTCIceServer> getDefaultIceServers();
+  RTCConfiguration getConfiguration();
+  void setConfiguration(RTCConfiguration configuration);
+  void close();
+  attribute EventHandler onnegotiationneeded;
+  attribute EventHandler onicecandidate;
+  attribute EventHandler onicecandidateerror;
+  attribute EventHandler onsignalingstatechange;
+  attribute EventHandler oniceconnectionstatechange;
+  attribute EventHandler onicegatheringstatechange;
+  attribute EventHandler onconnectionstatechange;
 };
 
 partial interface RTCPeerConnection {
-    Promise<void> createOffer(RTCSessionDescriptionCallback successCallback, RTCPeerConnectionErrorCallback failureCallback, optional RTCOfferOptions options);
-    Promise<void> setLocalDescription(RTCSessionDescriptionInit description, VoidFunction successCallback, RTCPeerConnectionErrorCallback failureCallback);
-    Promise<void> createAnswer(RTCSessionDescriptionCallback successCallback, RTCPeerConnectionErrorCallback failureCallback);
-    Promise<void> setRemoteDescription(RTCSessionDescriptionInit description, VoidFunction successCallback, RTCPeerConnectionErrorCallback failureCallback);
-    Promise<void> addIceCandidate(RTCIceCandidateInit candidate, VoidFunction successCallback, RTCPeerConnectionErrorCallback failureCallback);
+  Promise<void> createOffer(RTCSessionDescriptionCallback successCallback,
+                            RTCPeerConnectionErrorCallback failureCallback,
+                            optional RTCOfferOptions options);
+  Promise<void> setLocalDescription(RTCSessionDescriptionInit description,
+                                    VoidFunction successCallback,
+                                    RTCPeerConnectionErrorCallback failureCallback);
+  Promise<void> createAnswer(RTCSessionDescriptionCallback successCallback,
+                             RTCPeerConnectionErrorCallback failureCallback);
+  Promise<void> setRemoteDescription(RTCSessionDescriptionInit description,
+                                     VoidFunction successCallback,
+                                     RTCPeerConnectionErrorCallback failureCallback);
+  Promise<void> addIceCandidate(RTCIceCandidateInit candidate,
+                                VoidFunction successCallback,
+                                RTCPeerConnectionErrorCallback failureCallback);
 };
 
 callback RTCPeerConnectionErrorCallback = void (DOMException error);
@@ -138,524 +145,530 @@
 callback RTCSessionDescriptionCallback = void (RTCSessionDescriptionInit description);
 
 partial dictionary RTCOfferOptions {
-            boolean offerToReceiveAudio;
-            boolean offerToReceiveVideo;
-          };
-
-enum RTCSdpType {
-    "offer",
-    "pranswer",
-    "answer",
-    "rollback"
+  boolean offerToReceiveAudio;
+  boolean offerToReceiveVideo;
 };
 
-[ Constructor(RTCSessionDescriptionInit descriptionInitDict), Exposed=Window]
+enum RTCSdpType {
+  "offer",
+  "pranswer",
+  "answer",
+  "rollback"
+};
+
+[Exposed=Window, Constructor(RTCSessionDescriptionInit descriptionInitDict)]
 interface RTCSessionDescription {
-    readonly        attribute RTCSdpType type;
-    readonly        attribute DOMString sdp;
-    [Default] object toJSON();
+  readonly attribute RTCSdpType type;
+  readonly attribute DOMString sdp;
+  [Default] object toJSON();
 };
 
 dictionary RTCSessionDescriptionInit {
-    required RTCSdpType type;
-             DOMString sdp = "";
+  required RTCSdpType type;
+  DOMString sdp = "";
 };
 
-[ Constructor(optional RTCIceCandidateInit candidateInitDict), Exposed=Window]
+[Exposed=Window, Constructor(optional RTCIceCandidateInit candidateInitDict)]
 interface RTCIceCandidate {
-    readonly        attribute DOMString candidate;
-    readonly        attribute DOMString? sdpMid;
-    readonly        attribute unsigned short? sdpMLineIndex;
-    readonly        attribute DOMString? foundation;
-    readonly        attribute RTCIceComponent? component;
-    readonly        attribute unsigned long? priority;
-    readonly        attribute DOMString? address;
-    readonly        attribute RTCIceProtocol? protocol;
-    readonly        attribute unsigned short? port;
-    readonly        attribute RTCIceCandidateType? type;
-    readonly        attribute RTCIceTcpCandidateType? tcpType;
-    readonly        attribute DOMString? relatedAddress;
-    readonly        attribute unsigned short? relatedPort;
-    readonly        attribute DOMString? usernameFragment;
-    RTCIceCandidateInit toJSON();
+  readonly attribute DOMString candidate;
+  readonly attribute DOMString? sdpMid;
+  readonly attribute unsigned short? sdpMLineIndex;
+  readonly attribute DOMString? foundation;
+  readonly attribute RTCIceComponent? component;
+  readonly attribute unsigned long? priority;
+  readonly attribute DOMString? address;
+  readonly attribute RTCIceProtocol? protocol;
+  readonly attribute unsigned short? port;
+  readonly attribute RTCIceCandidateType? type;
+  readonly attribute RTCIceTcpCandidateType? tcpType;
+  readonly attribute DOMString? relatedAddress;
+  readonly attribute unsigned short? relatedPort;
+  readonly attribute DOMString? usernameFragment;
+  RTCIceCandidateInit toJSON();
 };
 
 dictionary RTCIceCandidateInit {
-             DOMString candidate = "";
-             DOMString? sdpMid = null;
-             unsigned short? sdpMLineIndex = null;
-             DOMString? usernameFragment = null;
+  DOMString candidate = "";
+  DOMString? sdpMid = null;
+  unsigned short? sdpMLineIndex = null;
+  DOMString? usernameFragment = null;
 };
 
 enum RTCIceProtocol {
-    "udp",
-    "tcp"
+  "udp",
+  "tcp"
 };
 
 enum RTCIceTcpCandidateType {
-    "active",
-    "passive",
-    "so"
+  "active",
+  "passive",
+  "so"
 };
 
 enum RTCIceCandidateType {
-    "host",
-    "srflx",
-    "prflx",
-    "relay"
+  "host",
+  "srflx",
+  "prflx",
+  "relay"
 };
 
-[ Constructor(DOMString type, optional RTCPeerConnectionIceEventInit eventInitDict), Exposed=Window]
+[Exposed=Window,
+ Constructor(DOMString type, optional RTCPeerConnectionIceEventInit eventInitDict)]
 interface RTCPeerConnectionIceEvent : Event {
-    readonly        attribute RTCIceCandidate? candidate;
-    readonly        attribute DOMString? url;
+  readonly attribute RTCIceCandidate? candidate;
+  readonly attribute DOMString? url;
 };
 
 dictionary RTCPeerConnectionIceEventInit : EventInit {
-             RTCIceCandidate? candidate;
-             DOMString? url;
+  RTCIceCandidate? candidate;
+  DOMString? url;
 };
 
-[ Constructor(DOMString type, RTCPeerConnectionIceErrorEventInit eventInitDict), Exposed=Window]
+[Exposed=Window,
+ Constructor(DOMString type, RTCPeerConnectionIceErrorEventInit eventInitDict)]
 interface RTCPeerConnectionIceErrorEvent : Event {
-    readonly        attribute DOMString hostCandidate;
-    readonly        attribute DOMString url;
-    readonly        attribute unsigned short errorCode;
-    readonly        attribute USVString errorText;
+  readonly attribute DOMString hostCandidate;
+  readonly attribute DOMString url;
+  readonly attribute unsigned short errorCode;
+  readonly attribute USVString errorText;
 };
 
 dictionary RTCPeerConnectionIceErrorEventInit : EventInit {
-             DOMString hostCandidate;
-             DOMString url;
-             required unsigned short errorCode;
-             USVString statusText;
+  DOMString hostCandidate;
+  DOMString url;
+  required unsigned short errorCode;
+  USVString statusText;
 };
 
 enum RTCPriorityType {
-    "very-low",
-    "low",
-    "medium",
-    "high"
+  "very-low",
+  "low",
+  "medium",
+  "high"
 };
 
 partial interface RTCPeerConnection {
-    static Promise<RTCCertificate> generateCertificate(AlgorithmIdentifier keygenAlgorithm);
+  static Promise<RTCCertificate> generateCertificate(AlgorithmIdentifier keygenAlgorithm);
 };
 
 dictionary RTCCertificateExpiration {
-    [EnforceRange]
-    DOMTimeStamp expires;
+  [EnforceRange] DOMTimeStamp expires;
 };
 
-[Exposed=Window, Serializable] interface RTCCertificate {
-    readonly        attribute DOMTimeStamp expires;
-    static sequence<AlgorithmIdentifier> getSupportedAlgorithms();
-    sequence<RTCDtlsFingerprint> getFingerprints();
+[Exposed=Window, Serializable]
+interface RTCCertificate {
+  readonly attribute DOMTimeStamp expires;
+  static sequence<AlgorithmIdentifier> getSupportedAlgorithms();
+  sequence<RTCDtlsFingerprint> getFingerprints();
 };
 
 partial interface RTCPeerConnection {
-    sequence<RTCRtpSender> getSenders();
-    sequence<RTCRtpReceiver> getReceivers();
-    sequence<RTCRtpTransceiver> getTransceivers();
-    RTCRtpSender addTrack(MediaStreamTrack track, MediaStream... streams);
-    void removeTrack(RTCRtpSender sender);
-    RTCRtpTransceiver addTransceiver((MediaStreamTrack or DOMString) trackOrKind, optional RTCRtpTransceiverInit init);
-                    attribute EventHandler ontrack;
+  sequence<RTCRtpSender> getSenders();
+  sequence<RTCRtpReceiver> getReceivers();
+  sequence<RTCRtpTransceiver> getTransceivers();
+  RTCRtpSender addTrack(MediaStreamTrack track, MediaStream... streams);
+  void removeTrack(RTCRtpSender sender);
+  RTCRtpTransceiver addTransceiver((MediaStreamTrack or DOMString) trackOrKind,
+                                   optional RTCRtpTransceiverInit init);
+  attribute EventHandler ontrack;
 };
 
 dictionary RTCRtpTransceiverInit {
-             RTCRtpTransceiverDirection direction = "sendrecv";
-             sequence<MediaStream> streams = [];
-             sequence<RTCRtpEncodingParameters> sendEncodings = [];
+  RTCRtpTransceiverDirection direction = "sendrecv";
+  sequence<MediaStream> streams = [];
+  sequence<RTCRtpEncodingParameters> sendEncodings = [];
 };
 
 enum RTCRtpTransceiverDirection {
-    "sendrecv",
-    "sendonly",
-    "recvonly",
-    "inactive"
+  "sendrecv",
+  "sendonly",
+  "recvonly",
+  "inactive",
+  "stopped"
 };
 
-[Exposed=Window] interface RTCRtpSender {
-    readonly        attribute MediaStreamTrack? track;
-    readonly        attribute RTCDtlsTransport? transport;
-    readonly        attribute RTCDtlsTransport? rtcpTransport;
-    static RTCRtpCapabilities? getCapabilities(DOMString kind);
-    Promise<void> setParameters(RTCRtpSendParameters parameters);
-    RTCRtpSendParameters getParameters();
-    Promise<void> replaceTrack(MediaStreamTrack? withTrack);
-    void setStreams(MediaStream... streams);
-    Promise<RTCStatsReport> getStats();
+[Exposed=Window]
+interface RTCRtpSender {
+  readonly attribute MediaStreamTrack? track;
+  readonly attribute RTCDtlsTransport? transport;
+  readonly attribute RTCDtlsTransport? rtcpTransport;
+  static RTCRtpCapabilities? getCapabilities(DOMString kind);
+  Promise<void> setParameters(RTCRtpSendParameters parameters);
+  RTCRtpSendParameters getParameters();
+  Promise<void> replaceTrack(MediaStreamTrack? withTrack);
+  void setStreams(MediaStream... streams);
+  Promise<RTCStatsReport> getStats();
 };
 
 dictionary RTCRtpParameters {
-             required sequence<RTCRtpHeaderExtensionParameters> headerExtensions;
-             required RTCRtcpParameters rtcp;
-             required sequence<RTCRtpCodecParameters> codecs;
+  required sequence<RTCRtpHeaderExtensionParameters> headerExtensions;
+  required RTCRtcpParameters rtcp;
+  required sequence<RTCRtpCodecParameters> codecs;
 };
 
 dictionary RTCRtpSendParameters : RTCRtpParameters {
-             required DOMString transactionId;
-             required sequence<RTCRtpEncodingParameters> encodings;
-             RTCDegradationPreference degradationPreference = "balanced";
-             RTCPriorityType priority = "low";
+  required DOMString transactionId;
+  required sequence<RTCRtpEncodingParameters> encodings;
+  RTCDegradationPreference degradationPreference = "balanced";
+  RTCPriorityType priority = "low";
 };
 
 dictionary RTCRtpReceiveParameters : RTCRtpParameters {
-             required sequence<RTCRtpDecodingParameters> encodings;
+  required sequence<RTCRtpDecodingParameters> encodings;
 };
 
 dictionary RTCRtpCodingParameters {
-             DOMString rid;
+  DOMString rid;
 };
 
-dictionary RTCRtpDecodingParameters : RTCRtpCodingParameters {
-};
+dictionary RTCRtpDecodingParameters : RTCRtpCodingParameters {};
 
 dictionary RTCRtpEncodingParameters : RTCRtpCodingParameters {
-             octet codecPayloadType;
-             RTCDtxStatus dtx;
-             boolean active = true;
-             unsigned long ptime;
-             unsigned long maxBitrate;
-             double maxFramerate;
-             double scaleResolutionDownBy;
+  octet codecPayloadType;
+  RTCDtxStatus dtx;
+  boolean active = true;
+  unsigned long ptime;
+  unsigned long maxBitrate;
+  double maxFramerate;
+  double scaleResolutionDownBy;
 };
 
 enum RTCDtxStatus {
-         "disabled",
-         "enabled"
-         };
+  "disabled",
+  "enabled"
+};
 
 enum RTCDegradationPreference {
-    "maintain-framerate",
-    "maintain-resolution",
-    "balanced"
+  "maintain-framerate",
+  "maintain-resolution",
+  "balanced"
 };
 
 dictionary RTCRtcpParameters {
-             DOMString cname;
-             boolean reducedSize;
+  DOMString cname;
+  boolean reducedSize;
 };
 
 dictionary RTCRtpHeaderExtensionParameters {
-             required DOMString uri;
-             required unsigned short id;
-             boolean encrypted = false;
+  required DOMString uri;
+  required unsigned short id;
+  boolean encrypted = false;
 };
 
 dictionary RTCRtpCodecParameters {
-             required octet payloadType;
-             required DOMString mimeType;
-             required unsigned long clockRate;
-             unsigned short channels;
-             DOMString sdpFmtpLine;
+  required octet payloadType;
+  required DOMString mimeType;
+  required unsigned long clockRate;
+  unsigned short channels;
+  DOMString sdpFmtpLine;
 };
 
 dictionary RTCRtpCapabilities {
-             required sequence<RTCRtpCodecCapability> codecs;
-             required sequence<RTCRtpHeaderExtensionCapability> headerExtensions;
+  required sequence<RTCRtpCodecCapability> codecs;
+  required sequence<RTCRtpHeaderExtensionCapability> headerExtensions;
 };
 
 dictionary RTCRtpCodecCapability {
-             required DOMString mimeType;
-             required unsigned long clockRate;
-             unsigned short channels;
-             DOMString sdpFmtpLine;
+  required DOMString mimeType;
+  required unsigned long clockRate;
+  unsigned short channels;
+  DOMString sdpFmtpLine;
 };
 
 dictionary RTCRtpHeaderExtensionCapability {
-             DOMString uri;
+  DOMString uri;
 };
 
-[Exposed=Window] interface RTCRtpReceiver {
-    readonly        attribute MediaStreamTrack track;
-    readonly        attribute RTCDtlsTransport? transport;
-    readonly        attribute RTCDtlsTransport? rtcpTransport;
-    static RTCRtpCapabilities? getCapabilities(DOMString kind);
-    RTCRtpReceiveParameters getParameters();
-    sequence<RTCRtpContributingSource> getContributingSources();
-    sequence<RTCRtpSynchronizationSource> getSynchronizationSources();
-    Promise<RTCStatsReport> getStats();
+[Exposed=Window]
+interface RTCRtpReceiver {
+  readonly attribute MediaStreamTrack track;
+  readonly attribute RTCDtlsTransport? transport;
+  readonly attribute RTCDtlsTransport? rtcpTransport;
+  static RTCRtpCapabilities? getCapabilities(DOMString kind);
+  RTCRtpReceiveParameters getParameters();
+  sequence<RTCRtpContributingSource> getContributingSources();
+  sequence<RTCRtpSynchronizationSource> getSynchronizationSources();
+  Promise<RTCStatsReport> getStats();
 };
 
 dictionary RTCRtpContributingSource {
-    required DOMHighResTimeStamp timestamp;
-    required unsigned long source;
-             double audioLevel;
-    required unsigned long rtpTimestamp;
+  required DOMHighResTimeStamp timestamp;
+  required unsigned long source;
+  double audioLevel;
+  required unsigned long rtpTimestamp;
 };
 
 dictionary RTCRtpSynchronizationSource : RTCRtpContributingSource {
-    boolean voiceActivityFlag;
+  boolean voiceActivityFlag;
 };
 
-[Exposed=Window] interface RTCRtpTransceiver {
-    readonly        attribute DOMString? mid;
-    [SameObject]
-    readonly        attribute RTCRtpSender sender;
-    [SameObject]
-    readonly        attribute RTCRtpReceiver receiver;
-    readonly        attribute boolean stopped;
-                    attribute RTCRtpTransceiverDirection direction;
-    readonly        attribute RTCRtpTransceiverDirection? currentDirection;
-    void stop();
-    void setCodecPreferences(sequence<RTCRtpCodecCapability> codecs);
+[Exposed=Window]
+interface RTCRtpTransceiver {
+  readonly attribute DOMString? mid;
+  [SameObject] readonly attribute RTCRtpSender sender;
+  [SameObject] readonly attribute RTCRtpReceiver receiver;
+  attribute RTCRtpTransceiverDirection direction;
+  readonly attribute RTCRtpTransceiverDirection? currentDirection;
+  void stop();
+  void setCodecPreferences(sequence<RTCRtpCodecCapability> codecs);
 };
 
-[Exposed=Window] interface RTCDtlsTransport : EventTarget {
-    [SameObject]
-    readonly        attribute RTCIceTransport iceTransport;
-    readonly        attribute RTCDtlsTransportState state;
-    sequence<ArrayBuffer> getRemoteCertificates();
-                    attribute EventHandler onstatechange;
-                    attribute EventHandler onerror;
+[Exposed=Window]
+interface RTCDtlsTransport : EventTarget {
+  [SameObject] readonly attribute RTCIceTransport iceTransport;
+  readonly attribute RTCDtlsTransportState state;
+  sequence<ArrayBuffer> getRemoteCertificates();
+  attribute EventHandler onstatechange;
+  attribute EventHandler onerror;
 };
 
 enum RTCDtlsTransportState {
-    "new",
-    "connecting",
-    "connected",
-    "closed",
-    "failed"
+  "new",
+  "connecting",
+  "connected",
+  "closed",
+  "failed"
 };
 
 dictionary RTCDtlsFingerprint {
-             DOMString algorithm;
-             DOMString value;
+  DOMString algorithm;
+  DOMString value;
 };
 
-[Exposed=Window] interface RTCIceTransport : EventTarget {
-    readonly        attribute RTCIceRole role;
-    readonly        attribute RTCIceComponent component;
-    readonly        attribute RTCIceTransportState state;
-    readonly        attribute RTCIceGathererState gatheringState;
-    sequence<RTCIceCandidate> getLocalCandidates();
-    sequence<RTCIceCandidate> getRemoteCandidates();
-    RTCIceCandidatePair? getSelectedCandidatePair();
-    RTCIceParameters? getLocalParameters();
-    RTCIceParameters? getRemoteParameters();
-                    attribute EventHandler onstatechange;
-                    attribute EventHandler ongatheringstatechange;
-                    attribute EventHandler onselectedcandidatepairchange;
+[Exposed=Window]
+interface RTCIceTransport : EventTarget {
+  readonly attribute RTCIceRole role;
+  readonly attribute RTCIceComponent component;
+  readonly attribute RTCIceTransportState state;
+  readonly attribute RTCIceGathererState gatheringState;
+  sequence<RTCIceCandidate> getLocalCandidates();
+  sequence<RTCIceCandidate> getRemoteCandidates();
+  RTCIceCandidatePair? getSelectedCandidatePair();
+  RTCIceParameters? getLocalParameters();
+  RTCIceParameters? getRemoteParameters();
+  attribute EventHandler onstatechange;
+  attribute EventHandler ongatheringstatechange;
+  attribute EventHandler onselectedcandidatepairchange;
 };
 
 dictionary RTCIceParameters {
-             DOMString usernameFragment;
-             DOMString password;
+  DOMString usernameFragment;
+  DOMString password;
 };
 
 dictionary RTCIceCandidatePair {
-             RTCIceCandidate local;
-             RTCIceCandidate remote;
+  RTCIceCandidate local;
+  RTCIceCandidate remote;
 };
 
 enum RTCIceGathererState {
-    "new",
-    "gathering",
-    "complete"
+  "new",
+  "gathering",
+  "complete"
 };
 
 enum RTCIceTransportState {
-    "new",
-    "checking",
-    "connected",
-    "completed",
-    "disconnected",
-    "failed",
-    "closed"
+  "new",
+  "checking",
+  "connected",
+  "completed",
+  "disconnected",
+  "failed",
+  "closed"
 };
 
 enum RTCIceRole {
-    "unknown",
-    "controlling",
-    "controlled"
+  "unknown",
+  "controlling",
+  "controlled"
 };
 
 enum RTCIceComponent {
-    "rtp",
-    "rtcp"
+  "rtp",
+  "rtcp"
 };
 
-[ Constructor(DOMString type, RTCTrackEventInit eventInitDict), Exposed=Window]
+[Exposed=Window, Constructor(DOMString type, RTCTrackEventInit eventInitDict)]
 interface RTCTrackEvent : Event {
-    readonly        attribute RTCRtpReceiver receiver;
-    readonly        attribute MediaStreamTrack track;
-    [SameObject]
-    readonly        attribute FrozenArray<MediaStream> streams;
-    readonly        attribute RTCRtpTransceiver transceiver;
+  readonly attribute RTCRtpReceiver receiver;
+  readonly attribute MediaStreamTrack track;
+  [SameObject] readonly attribute FrozenArray<MediaStream> streams;
+  readonly attribute RTCRtpTransceiver transceiver;
 };
 
 dictionary RTCTrackEventInit : EventInit {
-    required RTCRtpReceiver receiver;
-    required MediaStreamTrack track;
-             sequence<MediaStream> streams = [];
-    required RTCRtpTransceiver transceiver;
+  required RTCRtpReceiver receiver;
+  required MediaStreamTrack track;
+  sequence<MediaStream> streams = [];
+  required RTCRtpTransceiver transceiver;
 };
 
 partial interface RTCPeerConnection {
-    readonly        attribute RTCSctpTransport? sctp;
-    RTCDataChannel createDataChannel(USVString label, optional RTCDataChannelInit dataChannelDict);
-                    attribute EventHandler ondatachannel;
+  readonly attribute RTCSctpTransport? sctp;
+  RTCDataChannel createDataChannel(USVString label,
+                                   optional RTCDataChannelInit dataChannelDict);
+  attribute EventHandler ondatachannel;
 };
 
-[Exposed=Window] interface RTCSctpTransport : EventTarget {
-    readonly        attribute RTCDtlsTransport transport;
-    readonly        attribute RTCSctpTransportState state;
-    readonly        attribute unrestricted double maxMessageSize;
-    readonly        attribute unsigned short? maxChannels;
-                    attribute EventHandler onstatechange;
+[Exposed=Window]
+interface RTCSctpTransport : EventTarget {
+  readonly attribute RTCDtlsTransport transport;
+  readonly attribute RTCSctpTransportState state;
+  readonly attribute unrestricted double maxMessageSize;
+  readonly attribute unsigned short? maxChannels;
+  attribute EventHandler onstatechange;
 };
 
 enum RTCSctpTransportState {
-    "connecting",
-    "connected",
-    "closed"
+  "connecting",
+  "connected",
+  "closed"
 };
 
-[Exposed=Window] interface RTCDataChannel : EventTarget {
-    readonly        attribute USVString label;
-    readonly        attribute boolean ordered;
-    readonly        attribute unsigned short? maxPacketLifeTime;
-    readonly        attribute unsigned short? maxRetransmits;
-    readonly        attribute USVString protocol;
-    readonly        attribute boolean negotiated;
-    readonly        attribute unsigned short? id;
-    readonly        attribute RTCPriorityType priority;
-    readonly        attribute RTCDataChannelState readyState;
-    readonly        attribute unsigned long bufferedAmount;
-                    [EnforceRange]
-                    attribute unsigned long bufferedAmountLowThreshold;
-                    attribute EventHandler onopen;
-                    attribute EventHandler onbufferedamountlow;
-                    attribute EventHandler onerror;
-                    attribute EventHandler onclose;
-    void close();
-                    attribute EventHandler onmessage;
-                    attribute DOMString binaryType;
-    void send(USVString data);
-    void send(Blob data);
-    void send(ArrayBuffer data);
-    void send(ArrayBufferView data);
+[Exposed=Window]
+interface RTCDataChannel : EventTarget {
+  readonly attribute USVString label;
+  readonly attribute boolean ordered;
+  readonly attribute unsigned short? maxPacketLifeTime;
+  readonly attribute unsigned short? maxRetransmits;
+  readonly attribute USVString protocol;
+  readonly attribute boolean negotiated;
+  readonly attribute unsigned short? id;
+  readonly attribute RTCPriorityType priority;
+  readonly attribute RTCDataChannelState readyState;
+  readonly attribute unsigned long bufferedAmount;
+  [EnforceRange] attribute unsigned long bufferedAmountLowThreshold;
+  attribute EventHandler onopen;
+  attribute EventHandler onbufferedamountlow;
+  attribute EventHandler onerror;
+  attribute EventHandler onclosing;
+  attribute EventHandler onclose;
+  void close();
+  attribute EventHandler onmessage;
+  attribute DOMString binaryType;
+  void send(USVString data);
+  void send(Blob data);
+  void send(ArrayBuffer data);
+  void send(ArrayBufferView data);
 };
 
 dictionary RTCDataChannelInit {
-             boolean ordered = true;
-             [EnforceRange]
-             unsigned short maxPacketLifeTime;
-             [EnforceRange]
-             unsigned short maxRetransmits;
-             USVString protocol = "";
-             boolean negotiated = false;
-             [EnforceRange]
-             unsigned short id;
-             RTCPriorityType priority = "low";
+  boolean ordered = true;
+  [EnforceRange] unsigned short maxPacketLifeTime;
+  [EnforceRange] unsigned short maxRetransmits;
+  USVString protocol = "";
+  boolean negotiated = false;
+  [EnforceRange] unsigned short id;
+  RTCPriorityType priority = "low";
 };
 
 enum RTCDataChannelState {
-    "connecting",
-    "open",
-    "closing",
-    "closed"
+  "connecting",
+  "open",
+  "closing",
+  "closed"
 };
 
-[ Constructor(DOMString type, RTCDataChannelEventInit eventInitDict), Exposed=Window]
+[Exposed=Window, Constructor(DOMString type, RTCDataChannelEventInit eventInitDict)]
 interface RTCDataChannelEvent : Event {
-    readonly        attribute RTCDataChannel channel;
+  readonly attribute RTCDataChannel channel;
 };
 
 dictionary RTCDataChannelEventInit : EventInit {
-             required RTCDataChannel channel;
+  required RTCDataChannel channel;
 };
 
 partial interface RTCRtpSender {
-    readonly        attribute RTCDTMFSender? dtmf;
+  readonly attribute RTCDTMFSender? dtmf;
 };
 
-[Exposed=Window] interface RTCDTMFSender : EventTarget {
-    void insertDTMF(DOMString tones, optional unsigned long duration = 100, optional unsigned long interToneGap = 70);
-                    attribute EventHandler ontonechange;
-    readonly        attribute boolean canInsertDTMF;
-    readonly        attribute DOMString toneBuffer;
+[Exposed=Window]
+interface RTCDTMFSender : EventTarget {
+  void insertDTMF(DOMString tones, optional unsigned long duration = 100, optional unsigned long interToneGap = 70);
+  attribute EventHandler ontonechange;
+  readonly attribute boolean canInsertDTMF;
+  readonly attribute DOMString toneBuffer;
 };
 
-[ Constructor(DOMString type, RTCDTMFToneChangeEventInit eventInitDict), Exposed=Window]
+[Exposed=Window,
+ Constructor(DOMString type, RTCDTMFToneChangeEventInit eventInitDict)]
 interface RTCDTMFToneChangeEvent : Event {
-    readonly        attribute DOMString tone;
+  readonly attribute DOMString tone;
 };
 
 dictionary RTCDTMFToneChangeEventInit : EventInit {
-             required DOMString tone;
+  required DOMString tone;
 };
 
 partial interface RTCPeerConnection {
-    Promise<RTCStatsReport> getStats(optional MediaStreamTrack? selector = null);
-    attribute EventHandler onstatsended;
-          };
+  Promise<RTCStatsReport> getStats(optional MediaStreamTrack? selector = null);
+  attribute EventHandler onstatsended;
+};
 
-[Exposed=Window] interface RTCStatsReport {
-    readonly maplike<DOMString, object>;
+[Exposed=Window]
+interface RTCStatsReport {
+  readonly maplike<DOMString, object>;
 };
 
 dictionary RTCStats {
-             required DOMHighResTimeStamp timestamp;
-             required RTCStatsType type;
-             required DOMString id;
+  required DOMHighResTimeStamp timestamp;
+  required RTCStatsType type;
+  required DOMString id;
 };
 
-[ Constructor(DOMString type, RTCStatsEventInit eventInitDict), Exposed=Window]
-          interface RTCStatsEvent : Event {
-            readonly attribute RTCStatsReport report;
-          };
+[Exposed=Window,
+ Constructor(DOMString type, RTCStatsEventInit eventInitDict)]
+interface RTCStatsEvent : Event {
+  readonly attribute RTCStatsReport report;
+};
 
 dictionary RTCStatsEventInit : EventInit {
-            required RTCStatsReport report;
-          };
+  required RTCStatsReport report;
+};
 
-[
-    Exposed=Window,
-    Constructor(RTCErrorInit init, optional DOMString message = "")] interface RTCError : DOMException {
-    readonly attribute RTCErrorDetailType errorDetail;
-    readonly attribute long? sdpLineNumber;
-    readonly attribute long? httpRequestStatusCode;
-    readonly attribute long? sctpCauseCode;
-    readonly attribute unsigned long? receivedAlert;
-    readonly attribute unsigned long? sentAlert;
+[Exposed=Window, Constructor(RTCErrorInit init, optional DOMString message = "")]
+interface RTCError : DOMException {
+  readonly attribute RTCErrorDetailType errorDetail;
+  readonly attribute long? sdpLineNumber;
+  readonly attribute long? httpRequestStatusCode;
+  readonly attribute long? sctpCauseCode;
+  readonly attribute unsigned long? receivedAlert;
+  readonly attribute unsigned long? sentAlert;
 };
 
 dictionary RTCErrorInit {
-    required RTCErrorDetailType errorDetail;
-    long sdpLineNumber;
-    long httpRequestStatusCode;
-    long sctpCauseCode;
-    unsigned long receivedAlert;
-    unsigned long sentAlert;
+  required RTCErrorDetailType errorDetail;
+  long sdpLineNumber;
+  long httpRequestStatusCode;
+  long sctpCauseCode;
+  unsigned long receivedAlert;
+  unsigned long sentAlert;
 };
 
 enum RTCErrorDetailType {
-              "data-channel-failure",
-              "dtls-failure",
-              "fingerprint-failure",
-              "idp-bad-script-failure",
-              "idp-execution-failure",
-              "idp-load-failure",
-              "idp-need-login",
-              "idp-timeout",
-              "idp-tls-failure",
-              "idp-token-expired",
-              "idp-token-invalid",
-              "sctp-failure",
-              "sdp-syntax-error",
-              "hardware-encoder-not-available",
-              "hardware-encoder-error"
-          };
+  "data-channel-failure",
+  "dtls-failure",
+  "fingerprint-failure",
+  "idp-bad-script-failure",
+  "idp-execution-failure",
+  "idp-load-failure",
+  "idp-need-login",
+  "idp-timeout",
+  "idp-tls-failure",
+  "idp-token-expired",
+  "idp-token-invalid",
+  "sctp-failure",
+  "sdp-syntax-error",
+  "hardware-encoder-not-available",
+  "hardware-encoder-error"
+};
 
-[
-    Exposed=Window,
-    Constructor(DOMString type, RTCErrorEventInit eventInitDict)] interface RTCErrorEvent : Event {
-    [SameObject] readonly attribute RTCError error;
+[Exposed=Window,
+ Constructor(DOMString type, RTCErrorEventInit eventInitDict)]
+interface RTCErrorEvent : Event {
+  [SameObject] readonly attribute RTCError error;
 };
 
 dictionary RTCErrorEventInit : EventInit {
-     required RTCError error;
+  required RTCError error;
 };
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/xslt.idl b/third_party/blink/web_tests/external/wpt/interfaces/xslt.tentative.idl
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/interfaces/xslt.idl
rename to third_party/blink/web_tests/external/wpt/interfaces/xslt.tentative.idl
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/update.https-expected.txt b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/update.https-expected.txt
index 2a9900e..8f751d02 100644
--- a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/update.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/update.https-expected.txt
@@ -1,8 +1,7 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = assert_throws: function "function() { throw e }" threw object "SecurityError: Failed to update a ServiceWorker: The script resource is behind a redirect, which is disallowed." ("SecurityError") expected object "TypeError" ("TypeError")
 PASS update() should succeed when new script is available.
 PASS update() should fail when mime type is invalid.
-PASS update() should fail when a response for the main script is redirect.
+FAIL update() should fail when a response for the main script is redirect. assert_throws: function "function() { throw e }" threw object "SecurityError: Failed to update a ServiceWorker: The script resource is behind a redirect, which is disallowed." ("SecurityError") expected object "TypeError" ("TypeError")
 PASS update() should fail when a new script contains a syntax error.
 PASS update() should resolve when the install event throws.
 PASS update() should fail when the pending uninstall flag is set.
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/update.https.html b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/update.https.html
index 7232419..7f5ec4a 100644
--- a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/update.https.html
+++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/update.https.html
@@ -75,7 +75,7 @@
       await prepare_ready_registration(t, 'bad_mime_type');
   t.add_cleanup(() => registration.unregister());
 
-  promise_rejects(t, 'SecurityError', registration.update());
+  await promise_rejects(t, 'SecurityError', registration.update());
   assert_active_only(registration, expected_url);
 }, 'update() should fail when mime type is invalid.');
 
@@ -84,7 +84,7 @@
       await prepare_ready_registration(t, 'redirect');
   t.add_cleanup(() => registration.unregister());
 
-  promise_rejects(t, new TypeError(), registration.update())
+  await promise_rejects(t, new TypeError(), registration.update());
   assert_active_only(registration, expected_url);
 }, 'update() should fail when a response for the main script is redirect.');
 
@@ -93,7 +93,7 @@
       await prepare_ready_registration(t, 'syntax_error');
   t.add_cleanup(() => registration.unregister());
 
-  promise_rejects(t, new TypeError(), registration.update());
+  await promise_rejects(t, new TypeError(), registration.update());
   assert_active_only(registration, expected_url);
 }, 'update() should fail when a new script contains a syntax error.');
 
@@ -117,7 +117,7 @@
   const frame = await with_iframe(SCOPE);
   t.add_cleanup(() => frame.remove());
 
-  promise_rejects(
+  await promise_rejects(
       t, new TypeError(),
       Promise.all([registration.unregister(), registration.update()]));
 }, 'update() should fail when the pending uninstall flag is set.')
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/perform_actions/pointer_contextmenu.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/perform_actions/pointer_contextmenu.py
index c64c512..fda3f18 100644
--- a/third_party/blink/web_tests/external/wpt/webdriver/tests/perform_actions/pointer_contextmenu.py
+++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/perform_actions/pointer_contextmenu.py
@@ -18,7 +18,7 @@
     outer = session.find.css("#outer", all=False)
     mouse_chain.click(element=outer)
     session.actions.perform([key_chain.dict, mouse_chain.dict])
-    if os == "windows":
+    if os != "mac":
         expected = [
             {"type": "mousemove"},
             {"type": "mousedown"},
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/idlharness.https.window-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/idlharness.https.window-expected.txt
index a9a7a01..1f26f0d 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/idlharness.https.window-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webrtc/idlharness.https.window-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 508 tests; 470 PASS, 38 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 508 tests; 468 PASS, 40 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS idl_test setup
 PASS Test driver for asyncInitCertificate
 PASS Test driver for asyncInitTransports
@@ -290,7 +290,6 @@
 PASS RTCRtpTransceiver interface: attribute mid
 PASS RTCRtpTransceiver interface: attribute sender
 PASS RTCRtpTransceiver interface: attribute receiver
-PASS RTCRtpTransceiver interface: attribute stopped
 PASS RTCRtpTransceiver interface: attribute direction
 PASS RTCRtpTransceiver interface: attribute currentDirection
 FAIL RTCRtpTransceiver interface: operation stop() assert_own_property: interface prototype object missing non-static operation expected property "stop" missing
@@ -300,7 +299,6 @@
 PASS RTCRtpTransceiver interface: new RTCPeerConnection().addTransceiver('audio') must inherit property "mid" with the proper type
 PASS RTCRtpTransceiver interface: new RTCPeerConnection().addTransceiver('audio') must inherit property "sender" with the proper type
 PASS RTCRtpTransceiver interface: new RTCPeerConnection().addTransceiver('audio') must inherit property "receiver" with the proper type
-PASS RTCRtpTransceiver interface: new RTCPeerConnection().addTransceiver('audio') must inherit property "stopped" with the proper type
 PASS RTCRtpTransceiver interface: new RTCPeerConnection().addTransceiver('audio') must inherit property "direction" with the proper type
 PASS RTCRtpTransceiver interface: new RTCPeerConnection().addTransceiver('audio') must inherit property "currentDirection" with the proper type
 FAIL RTCRtpTransceiver interface: new RTCPeerConnection().addTransceiver('audio') must inherit property "stop()" with the proper type assert_inherits: property "stop" not found in prototype chain
@@ -412,6 +410,7 @@
 PASS RTCDataChannel interface: attribute onopen
 PASS RTCDataChannel interface: attribute onbufferedamountlow
 PASS RTCDataChannel interface: attribute onerror
+FAIL RTCDataChannel interface: attribute onclosing assert_true: The prototype object must have a property "onclosing" expected true got false
 PASS RTCDataChannel interface: attribute onclose
 PASS RTCDataChannel interface: operation close()
 PASS RTCDataChannel interface: attribute onmessage
@@ -436,6 +435,7 @@
 PASS RTCDataChannel interface: new RTCPeerConnection().createDataChannel('') must inherit property "onopen" with the proper type
 PASS RTCDataChannel interface: new RTCPeerConnection().createDataChannel('') must inherit property "onbufferedamountlow" with the proper type
 PASS RTCDataChannel interface: new RTCPeerConnection().createDataChannel('') must inherit property "onerror" with the proper type
+FAIL RTCDataChannel interface: new RTCPeerConnection().createDataChannel('') must inherit property "onclosing" with the proper type assert_inherits: property "onclosing" not found in prototype chain
 PASS RTCDataChannel interface: new RTCPeerConnection().createDataChannel('') must inherit property "onclose" with the proper type
 PASS RTCDataChannel interface: new RTCPeerConnection().createDataChannel('') must inherit property "close()" with the proper type
 PASS RTCDataChannel interface: new RTCPeerConnection().createDataChannel('') must inherit property "onmessage" with the proper type
diff --git a/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_framebuffer.https.html b/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_framebuffer.https.html
new file mode 100644
index 0000000..7c4ff17
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_framebuffer.https.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/webxr_test_constants.js"></script>
+<script src="resources/webxr_util.js"></script>
+<canvas></canvas>
+
+<script>
+
+let immersiveTestName = "XRWebGLLayer reports a valid framebuffer for immersive sessions";
+let inlineTestName = "XRWebGLLayer reports a valid framebuffer for inline sessions";
+
+let fakeDeviceInitParams = TRACKED_IMMERSIVE_DEVICE;
+
+let testFunction = function(session, fakeDeviceController, t) {
+  return session.requestReferenceSpace('viewer')
+      .then((space) => new Promise((resolve) => {
+    function onFrame(time, xrFrame) {
+      let layer = xrFrame.session.renderState.baseLayer;
+      let gl = layer.context;
+
+      // The layer's framebuffer is a WebGL framebuffer
+      assert_not_equals(layer.framebuffer, null);
+      assert_true(layer.framebuffer instanceof WebGLFramebuffer);
+
+      // The XR framebuffer is not bound to the GL context by default.
+      assert_not_equals(layer.framebuffer, gl.getParameter(gl.FRAMEBUFFER_BINDING));
+
+      // The XR framebuffer can be bound to the GL context.
+      gl.bindFramebuffer(gl.FRAMEBUFFER, layer.framebuffer);
+      assert_equals(layer.framebuffer, gl.getParameter(gl.FRAMEBUFFER_BINDING));
+
+      // The XR framebuffer has a 2D texture
+      let attachment = gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE);
+      assert_equals(attachment, gl.TEXTURE);
+
+      // Check that each viewport fits inside the framebuffer dimensions
+      let viewer_pose = xrFrame.getViewerPose(space);
+      for (view of viewer_pose.views) {
+        let viewport = layer.getViewport(view);
+        assert_less_than_equal(viewport.x + viewport.width, layer.framebufferWidth);
+        assert_less_than_equal(viewport.y + viewport.height, layer.framebufferHeight);
+      }
+
+      // Finished test.
+      resolve();
+    }
+
+    session.requestAnimationFrame(onFrame);
+  }));
+};
+
+xr_session_promise_test(immersiveTestName, testFunction,
+  fakeDeviceInitParams, 'immersive-vr');
+xr_session_promise_test(inlineTestName, testFunction,
+  fakeDeviceInitParams, 'inline');
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_viewports.https.html b/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_viewports.https.html
index 9553a44..8cfccff 100644
--- a/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_viewports.https.html
+++ b/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_viewports.https.html
@@ -22,6 +22,8 @@
       let layer = xrFrame.session.renderState.baseLayer;
       for (view of viewer_pose.views) {
         let viewport = layer.getViewport(view);
+        let index = (view.eye === "right"? 1: 0);
+        let params = fakeDeviceInitParams.views[index];
 
         // Ensure the returned object is an XRViewport object
         assert_not_equals(viewport, null);
@@ -30,8 +32,20 @@
         // Ensure the viewport dimensions are valid
         assert_greater_than_equal(viewport.x, 0);
         assert_greater_than_equal(viewport.y, 0);
-        assert_greater_than_equal(viewport.width, 1);
-        assert_greater_than_equal(viewport.height, 1);
+        assert_equals(viewport.width, params.resolution.width);
+        assert_equals(viewport.height, params.resolution.height);
+
+        // Ensure none of the viewports overlap
+        for (other of viewer_pose.views) {
+          if (view !== other) {
+            let otherport = layer.getViewport(other);
+            let no_overlap = (viewport.x + viewport.width <= otherport.x) ||
+              (otherport.x + otherport.width <= viewport.x) ||
+              (viewport.y + viewport.height <= otherport.y) ||
+              (otherport.y + otherport.height <= viewport.y);
+            assert_true(no_overlap, "Overlap between viewport " + view.eye + " and " + other.eye);
+          }
+        }
       }
 
       // Finished test.
diff --git a/third_party/blink/web_tests/external/wpt/xhr/getallresponseheaders-expected.txt b/third_party/blink/web_tests/external/wpt/xhr/getallresponseheaders-expected.txt
index 04b1bec..69617d19 100644
--- a/third_party/blink/web_tests/external/wpt/xhr/getallresponseheaders-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/xhr/getallresponseheaders-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-FAIL XMLHttpRequest: getAllResponseHeaders() assert_equals: expected "also-here: Mr. PB\r\newok: lego\r\nfoo-test: 1, 2\r\n" but got "also-here: Mr. PB\r\nfoo-test: 1, 2\r\newok: lego\r\n"
+FAIL XMLHttpRequest: getAllResponseHeaders() assert_equals: expected "also-here: Mr. PB\r\newok: lego\r\nfoo-test: 1, 2\r\n__custom: token\r\n" but got "__custom: token\r\nalso-here: Mr. PB\r\nfoo-test: 1, 2\r\newok: lego\r\n"
 PASS XMLHttpRequest: getAllResponseHeaders() 1
 PASS XMLHttpRequest: getAllResponseHeaders() 2
 PASS XMLHttpRequest: getAllResponseHeaders() 3
diff --git a/third_party/blink/web_tests/external/wpt/xhr/getallresponseheaders.htm b/third_party/blink/web_tests/external/wpt/xhr/getallresponseheaders.htm
index 72e27a59..759d6b68 100644
--- a/third_party/blink/web_tests/external/wpt/xhr/getallresponseheaders.htm
+++ b/third_party/blink/web_tests/external/wpt/xhr/getallresponseheaders.htm
@@ -7,7 +7,7 @@
 async_test((t) => {
   const client = new XMLHttpRequest()
   client.onload = t.step_func_done(() => {
-    assert_equals(client.getAllResponseHeaders(), "also-here: Mr. PB\r\newok: lego\r\nfoo-test: 1, 2\r\n")
+    assert_equals(client.getAllResponseHeaders(), "also-here: Mr. PB\r\newok: lego\r\nfoo-test: 1, 2\r\n__custom: token\r\n")
   })
   client.onerror = t.unreached_func("unexpected error")
   client.open("GET", "resources/headers.asis")
diff --git a/third_party/blink/web_tests/external/wpt/xhr/resources/headers.asis b/third_party/blink/web_tests/external/wpt/xhr/resources/headers.asis
index d25fe52e..69273ac 100644
--- a/third_party/blink/web_tests/external/wpt/xhr/resources/headers.asis
+++ b/third_party/blink/web_tests/external/wpt/xhr/resources/headers.asis
@@ -1,5 +1,6 @@
 HTTP/1.1 200 YAYAYAYA
 foo-TEST: 1
 FOO-test: 2
+__Custom: token
 ALSO-here: Mr. PB
 ewok: lego
diff --git a/third_party/blink/web_tests/external/wpt/xslt/idlharness.window.js b/third_party/blink/web_tests/external/wpt/xslt/idlharness.tentative.window.js
similarity index 92%
rename from third_party/blink/web_tests/external/wpt/xslt/idlharness.window.js
rename to third_party/blink/web_tests/external/wpt/xslt/idlharness.tentative.window.js
index 51b0cd3..1da8db8c 100644
--- a/third_party/blink/web_tests/external/wpt/xslt/idlharness.window.js
+++ b/third_party/blink/web_tests/external/wpt/xslt/idlharness.tentative.window.js
@@ -4,7 +4,7 @@
 'use strict';
 
 idl_test(
-  ['xslt'],
+  ['xslt.tentative'],
   ['html'],
   async idlArray => {
     idlArray.add_objects({
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
index d076f51e..13ff447 100644
--- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
+++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
@@ -79,6 +79,7 @@
 PASS oldChildWindow.onanimationstart is newChildWindow.onanimationstart
 PASS oldChildWindow.onappinstalled is newChildWindow.onappinstalled
 PASS oldChildWindow.onauxclick is newChildWindow.onauxclick
+PASS oldChildWindow.onbeforeactivate is newChildWindow.onbeforeactivate
 PASS oldChildWindow.onbeforeinstallprompt is newChildWindow.onbeforeinstallprompt
 PASS oldChildWindow.onbeforeprint is newChildWindow.onbeforeprint
 PASS oldChildWindow.onbeforeunload is newChildWindow.onbeforeunload
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt
index 458db22..bcdb1a18 100644
--- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt
+++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt
@@ -41,6 +41,7 @@
 PASS childWindow.onanimationstart is null
 PASS childWindow.onappinstalled is null
 PASS childWindow.onauxclick is null
+PASS childWindow.onbeforeactivate is null
 PASS childWindow.onbeforeinstallprompt is null
 PASS childWindow.onbeforeprint is null
 PASS childWindow.onbeforeunload is null
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt
index c0e50e2f..3251446 100644
--- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt
+++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt
@@ -41,6 +41,7 @@
 PASS childWindow.onanimationstart is null
 PASS childWindow.onappinstalled is null
 PASS childWindow.onauxclick is null
+PASS childWindow.onbeforeactivate is null
 PASS childWindow.onbeforeinstallprompt is null
 PASS childWindow.onbeforeprint is null
 PASS childWindow.onbeforeunload is null
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub-expected.txt
new file mode 100644
index 0000000..4f655ba
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Non-redirected cross-origin URLs are not stripped. Failed to construct 'URL': Invalid URL
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/linux/virtual/not-omt-sw-fetch/external/wpt/xhr/getallresponseheaders-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/not-omt-sw-fetch/external/wpt/xhr/getallresponseheaders-expected.txt
new file mode 100644
index 0000000..69617d19
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/not-omt-sw-fetch/external/wpt/xhr/getallresponseheaders-expected.txt
@@ -0,0 +1,10 @@
+This is a testharness.js-based test.
+FAIL XMLHttpRequest: getAllResponseHeaders() assert_equals: expected "also-here: Mr. PB\r\newok: lego\r\nfoo-test: 1, 2\r\n__custom: token\r\n" but got "__custom: token\r\nalso-here: Mr. PB\r\nfoo-test: 1, 2\r\newok: lego\r\n"
+PASS XMLHttpRequest: getAllResponseHeaders() 1
+PASS XMLHttpRequest: getAllResponseHeaders() 2
+PASS XMLHttpRequest: getAllResponseHeaders() 3
+PASS XMLHttpRequest: getAllResponseHeaders() 4
+PASS XMLHttpRequest: getAllResponseHeaders() 5
+PASS XMLHttpRequest: getAllResponseHeaders() 6
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub-expected.txt
new file mode 100644
index 0000000..4f655ba
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Non-redirected cross-origin URLs are not stripped. Failed to construct 'URL': Invalid URL
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/not-omt-sw-fetch/external/wpt/xhr/getallresponseheaders-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/not-omt-sw-fetch/external/wpt/xhr/getallresponseheaders-expected.txt
new file mode 100644
index 0000000..69617d19
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/not-omt-sw-fetch/external/wpt/xhr/getallresponseheaders-expected.txt
@@ -0,0 +1,10 @@
+This is a testharness.js-based test.
+FAIL XMLHttpRequest: getAllResponseHeaders() assert_equals: expected "also-here: Mr. PB\r\newok: lego\r\nfoo-test: 1, 2\r\n__custom: token\r\n" but got "__custom: token\r\nalso-here: Mr. PB\r\nfoo-test: 1, 2\r\newok: lego\r\n"
+PASS XMLHttpRequest: getAllResponseHeaders() 1
+PASS XMLHttpRequest: getAllResponseHeaders() 2
+PASS XMLHttpRequest: getAllResponseHeaders() 3
+PASS XMLHttpRequest: getAllResponseHeaders() 4
+PASS XMLHttpRequest: getAllResponseHeaders() 5
+PASS XMLHttpRequest: getAllResponseHeaders() 6
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.11/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub-expected.txt
new file mode 100644
index 0000000..4f655ba
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.11/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Non-redirected cross-origin URLs are not stripped. Failed to construct 'URL': Invalid URL
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/not-omt-sw-fetch/external/wpt/xhr/getallresponseheaders-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/not-omt-sw-fetch/external/wpt/xhr/getallresponseheaders-expected.txt
new file mode 100644
index 0000000..69617d19
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/not-omt-sw-fetch/external/wpt/xhr/getallresponseheaders-expected.txt
@@ -0,0 +1,10 @@
+This is a testharness.js-based test.
+FAIL XMLHttpRequest: getAllResponseHeaders() assert_equals: expected "also-here: Mr. PB\r\newok: lego\r\nfoo-test: 1, 2\r\n__custom: token\r\n" but got "__custom: token\r\nalso-here: Mr. PB\r\nfoo-test: 1, 2\r\newok: lego\r\n"
+PASS XMLHttpRequest: getAllResponseHeaders() 1
+PASS XMLHttpRequest: getAllResponseHeaders() 2
+PASS XMLHttpRequest: getAllResponseHeaders() 3
+PASS XMLHttpRequest: getAllResponseHeaders() 4
+PASS XMLHttpRequest: getAllResponseHeaders() 5
+PASS XMLHttpRequest: getAllResponseHeaders() 6
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub-expected.txt
new file mode 100644
index 0000000..4f655ba
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Non-redirected cross-origin URLs are not stripped. Failed to construct 'URL': Invalid URL
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/not-omt-sw-fetch/external/wpt/xhr/getallresponseheaders-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/not-omt-sw-fetch/external/wpt/xhr/getallresponseheaders-expected.txt
new file mode 100644
index 0000000..69617d19
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/not-omt-sw-fetch/external/wpt/xhr/getallresponseheaders-expected.txt
@@ -0,0 +1,10 @@
+This is a testharness.js-based test.
+FAIL XMLHttpRequest: getAllResponseHeaders() assert_equals: expected "also-here: Mr. PB\r\newok: lego\r\nfoo-test: 1, 2\r\n__custom: token\r\n" but got "__custom: token\r\nalso-here: Mr. PB\r\nfoo-test: 1, 2\r\newok: lego\r\n"
+PASS XMLHttpRequest: getAllResponseHeaders() 1
+PASS XMLHttpRequest: getAllResponseHeaders() 2
+PASS XMLHttpRequest: getAllResponseHeaders() 3
+PASS XMLHttpRequest: getAllResponseHeaders() 4
+PASS XMLHttpRequest: getAllResponseHeaders() 5
+PASS XMLHttpRequest: getAllResponseHeaders() 6
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac-retina/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub-expected.txt b/third_party/blink/web_tests/platform/mac-retina/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub-expected.txt
new file mode 100644
index 0000000..4f655ba
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-retina/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Non-redirected cross-origin URLs are not stripped. Failed to construct 'URL': Invalid URL
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/not-omt-sw-fetch/external/wpt/xhr/getallresponseheaders-expected.txt b/third_party/blink/web_tests/platform/mac-retina/virtual/not-omt-sw-fetch/external/wpt/xhr/getallresponseheaders-expected.txt
new file mode 100644
index 0000000..69617d19
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-retina/virtual/not-omt-sw-fetch/external/wpt/xhr/getallresponseheaders-expected.txt
@@ -0,0 +1,10 @@
+This is a testharness.js-based test.
+FAIL XMLHttpRequest: getAllResponseHeaders() assert_equals: expected "also-here: Mr. PB\r\newok: lego\r\nfoo-test: 1, 2\r\n__custom: token\r\n" but got "__custom: token\r\nalso-here: Mr. PB\r\nfoo-test: 1, 2\r\newok: lego\r\n"
+PASS XMLHttpRequest: getAllResponseHeaders() 1
+PASS XMLHttpRequest: getAllResponseHeaders() 2
+PASS XMLHttpRequest: getAllResponseHeaders() 3
+PASS XMLHttpRequest: getAllResponseHeaders() 4
+PASS XMLHttpRequest: getAllResponseHeaders() 5
+PASS XMLHttpRequest: getAllResponseHeaders() 6
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub-expected.txt
new file mode 100644
index 0000000..4f655ba
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Non-redirected cross-origin URLs are not stripped. Failed to construct 'URL': Invalid URL
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac/virtual/not-omt-sw-fetch/external/wpt/xhr/getallresponseheaders-expected.txt b/third_party/blink/web_tests/platform/mac/virtual/not-omt-sw-fetch/external/wpt/xhr/getallresponseheaders-expected.txt
new file mode 100644
index 0000000..69617d19
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/virtual/not-omt-sw-fetch/external/wpt/xhr/getallresponseheaders-expected.txt
@@ -0,0 +1,10 @@
+This is a testharness.js-based test.
+FAIL XMLHttpRequest: getAllResponseHeaders() assert_equals: expected "also-here: Mr. PB\r\newok: lego\r\nfoo-test: 1, 2\r\n__custom: token\r\n" but got "__custom: token\r\nalso-here: Mr. PB\r\nfoo-test: 1, 2\r\newok: lego\r\n"
+PASS XMLHttpRequest: getAllResponseHeaders() 1
+PASS XMLHttpRequest: getAllResponseHeaders() 2
+PASS XMLHttpRequest: getAllResponseHeaders() 3
+PASS XMLHttpRequest: getAllResponseHeaders() 4
+PASS XMLHttpRequest: getAllResponseHeaders() 5
+PASS XMLHttpRequest: getAllResponseHeaders() 6
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub-expected.txt
new file mode 100644
index 0000000..4f655ba
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Non-redirected cross-origin URLs are not stripped. Failed to construct 'URL': Invalid URL
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win/virtual/not-omt-sw-fetch/external/wpt/xhr/getallresponseheaders-expected.txt b/third_party/blink/web_tests/platform/win/virtual/not-omt-sw-fetch/external/wpt/xhr/getallresponseheaders-expected.txt
new file mode 100644
index 0000000..69617d19
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/virtual/not-omt-sw-fetch/external/wpt/xhr/getallresponseheaders-expected.txt
@@ -0,0 +1,10 @@
+This is a testharness.js-based test.
+FAIL XMLHttpRequest: getAllResponseHeaders() assert_equals: expected "also-here: Mr. PB\r\newok: lego\r\nfoo-test: 1, 2\r\n__custom: token\r\n" but got "__custom: token\r\nalso-here: Mr. PB\r\nfoo-test: 1, 2\r\newok: lego\r\n"
+PASS XMLHttpRequest: getAllResponseHeaders() 1
+PASS XMLHttpRequest: getAllResponseHeaders() 2
+PASS XMLHttpRequest: getAllResponseHeaders() 3
+PASS XMLHttpRequest: getAllResponseHeaders() 4
+PASS XMLHttpRequest: getAllResponseHeaders() 5
+PASS XMLHttpRequest: getAllResponseHeaders() 6
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win7/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub-expected.txt b/third_party/blink/web_tests/platform/win7/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub-expected.txt
new file mode 100644
index 0000000..4f655ba
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win7/external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Non-redirected cross-origin URLs are not stripped. Failed to construct 'URL': Invalid URL
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win7/virtual/not-omt-sw-fetch/external/wpt/xhr/getallresponseheaders-expected.txt b/third_party/blink/web_tests/platform/win7/virtual/not-omt-sw-fetch/external/wpt/xhr/getallresponseheaders-expected.txt
new file mode 100644
index 0000000..69617d19
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win7/virtual/not-omt-sw-fetch/external/wpt/xhr/getallresponseheaders-expected.txt
@@ -0,0 +1,10 @@
+This is a testharness.js-based test.
+FAIL XMLHttpRequest: getAllResponseHeaders() assert_equals: expected "also-here: Mr. PB\r\newok: lego\r\nfoo-test: 1, 2\r\n__custom: token\r\n" but got "__custom: token\r\nalso-here: Mr. PB\r\nfoo-test: 1, 2\r\newok: lego\r\n"
+PASS XMLHttpRequest: getAllResponseHeaders() 1
+PASS XMLHttpRequest: getAllResponseHeaders() 2
+PASS XMLHttpRequest: getAllResponseHeaders() 3
+PASS XMLHttpRequest: getAllResponseHeaders() 4
+PASS XMLHttpRequest: getAllResponseHeaders() 5
+PASS XMLHttpRequest: getAllResponseHeaders() 6
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/idlharness.https.window-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/idlharness.https.window-expected.txt
index 6d048c6..52843dc 100644
--- a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/idlharness.https.window-expected.txt
+++ b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/idlharness.https.window-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 508 tests; 400 PASS, 108 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 508 tests; 399 PASS, 109 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS idl_test setup
 PASS Test driver for asyncInitCertificate
 FAIL Test driver for asyncInitTransports assert_unreached: Failed to run asyncInitTransports: Error: assert_true: Expect pc.sctp to be instance of RTCSctpTransport expected true got false Reached unreachable code
@@ -290,7 +290,6 @@
 PASS RTCRtpTransceiver interface: attribute mid
 PASS RTCRtpTransceiver interface: attribute sender
 PASS RTCRtpTransceiver interface: attribute receiver
-PASS RTCRtpTransceiver interface: attribute stopped
 PASS RTCRtpTransceiver interface: attribute direction
 PASS RTCRtpTransceiver interface: attribute currentDirection
 FAIL RTCRtpTransceiver interface: operation stop() assert_own_property: interface prototype object missing non-static operation expected property "stop" missing
@@ -300,7 +299,6 @@
 FAIL RTCRtpTransceiver interface: new RTCPeerConnection().addTransceiver('audio') must inherit property "mid" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'."
 FAIL RTCRtpTransceiver interface: new RTCPeerConnection().addTransceiver('audio') must inherit property "sender" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'."
 FAIL RTCRtpTransceiver interface: new RTCPeerConnection().addTransceiver('audio') must inherit property "receiver" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'."
-FAIL RTCRtpTransceiver interface: new RTCPeerConnection().addTransceiver('audio') must inherit property "stopped" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'."
 FAIL RTCRtpTransceiver interface: new RTCPeerConnection().addTransceiver('audio') must inherit property "direction" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'."
 FAIL RTCRtpTransceiver interface: new RTCPeerConnection().addTransceiver('audio') must inherit property "currentDirection" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'."
 FAIL RTCRtpTransceiver interface: new RTCPeerConnection().addTransceiver('audio') must inherit property "stop()" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'."
@@ -412,6 +410,7 @@
 PASS RTCDataChannel interface: attribute onopen
 PASS RTCDataChannel interface: attribute onbufferedamountlow
 PASS RTCDataChannel interface: attribute onerror
+FAIL RTCDataChannel interface: attribute onclosing assert_true: The prototype object must have a property "onclosing" expected true got false
 PASS RTCDataChannel interface: attribute onclose
 PASS RTCDataChannel interface: operation close()
 PASS RTCDataChannel interface: attribute onmessage
@@ -436,6 +435,7 @@
 PASS RTCDataChannel interface: new RTCPeerConnection().createDataChannel('') must inherit property "onopen" with the proper type
 PASS RTCDataChannel interface: new RTCPeerConnection().createDataChannel('') must inherit property "onbufferedamountlow" with the proper type
 PASS RTCDataChannel interface: new RTCPeerConnection().createDataChannel('') must inherit property "onerror" with the proper type
+FAIL RTCDataChannel interface: new RTCPeerConnection().createDataChannel('') must inherit property "onclosing" with the proper type assert_inherits: property "onclosing" not found in prototype chain
 PASS RTCDataChannel interface: new RTCPeerConnection().createDataChannel('') must inherit property "onclose" with the proper type
 PASS RTCDataChannel interface: new RTCPeerConnection().createDataChannel('') must inherit property "close()" with the proper type
 PASS RTCDataChannel interface: new RTCPeerConnection().createDataChannel('') must inherit property "onmessage" with the proper type
diff --git a/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt b/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt
index d6767a5..b7b764be 100644
--- a/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt
@@ -105,6 +105,7 @@
     property dataset
     property dir
     property dispatchEvent
+    property displayLock
     property draggable
     property enterKeyHint
     property firstChild
@@ -167,6 +168,7 @@
     property onabort
     property onactivateinvisible
     property onauxclick
+    property onbeforeactivate
     property onbeforecopy
     property onbeforecut
     property onbeforepaste
@@ -1291,6 +1293,7 @@
     property createShadowRoot
     property dataset
     property dispatchEvent
+    property displayLock
     property firstChild
     property firstElementChild
     property focus
@@ -1340,6 +1343,7 @@
     property onabort
     property onactivateinvisible
     property onauxclick
+    property onbeforeactivate
     property onbeforecopy
     property onbeforecut
     property onbeforepaste
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
index 6d756176..9df98cd0 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -503,6 +503,10 @@
     setter onchargingtimechange
     setter ondischargingtimechange
     setter onlevelchange
+interface BeforeActivateEvent : Event
+    attribute @@toStringTag
+    getter activatedElement
+    method constructor
 interface BeforeInstallPromptEvent : Event
     attribute @@toStringTag
     getter platforms
@@ -1534,6 +1538,14 @@
     getter beta
     getter gamma
     method constructor
+interface DisplayLockContext
+    attribute @@toStringTag
+    getter locked
+    method acquire
+    method commit
+    method constructor
+    method update
+    method updateAndCommit
 interface Document : Node
     attribute @@toStringTag
     attribute @@unscopables
@@ -1582,6 +1594,7 @@
     getter onabort
     getter onactivateinvisible
     getter onauxclick
+    getter onbeforeactivate
     getter onbeforecopy
     getter onbeforecut
     getter onbeforepaste
@@ -1772,6 +1785,7 @@
     setter onabort
     setter onactivateinvisible
     setter onauxclick
+    setter onbeforeactivate
     setter onbeforecopy
     setter onbeforecut
     setter onbeforepaste
@@ -1974,6 +1988,7 @@
     getter clientWidth
     getter computedName
     getter computedRole
+    getter displayLock
     getter firstElementChild
     getter id
     getter innerHTML
@@ -2740,6 +2755,7 @@
     getter onabort
     getter onactivateinvisible
     getter onauxclick
+    getter onbeforeactivate
     getter onblur
     getter oncancel
     getter oncanplay
@@ -2847,6 +2863,7 @@
     setter onabort
     setter onactivateinvisible
     setter onauxclick
+    setter onbeforeactivate
     setter onblur
     setter oncancel
     setter oncanplay
@@ -6323,6 +6340,7 @@
     getter onabort
     getter onactivateinvisible
     getter onauxclick
+    getter onbeforeactivate
     getter onblur
     getter oncancel
     getter oncanplay
@@ -6415,6 +6433,7 @@
     setter onabort
     setter onactivateinvisible
     setter onauxclick
+    setter onbeforeactivate
     setter onblur
     setter oncancel
     setter oncanplay
@@ -10998,6 +11017,7 @@
     getter onanimationstart
     getter onappinstalled
     getter onauxclick
+    getter onbeforeactivate
     getter onbeforeinstallprompt
     getter onbeforeprint
     getter onbeforeunload
@@ -11193,6 +11213,7 @@
     setter onanimationstart
     setter onappinstalled
     setter onauxclick
+    setter onbeforeactivate
     setter onbeforeinstallprompt
     setter onbeforeprint
     setter onbeforeunload
diff --git a/third_party/polymer/v1_0/css_strip_prefixes.py b/third_party/polymer/v1_0/css_strip_prefixes.py
index 868b93f..86b87a3 100644
--- a/third_party/polymer/v1_0/css_strip_prefixes.py
+++ b/third_party/polymer/v1_0/css_strip_prefixes.py
@@ -2,9 +2,11 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import argparse
 import fnmatch
 import os
 import re
+import sys
 
 # List of CSS properties to be removed.
 CSS_PROPERTIES_TO_REMOVE = [
@@ -84,14 +86,19 @@
   return any(pred(p) for p in CSS_PROPERTIES_TO_REMOVE)
 
 
-def main():
-  html_files = [os.path.join(dirpath, f)
-    for dirpath, dirnames, files in os.walk('components-chromium')
-    for f in fnmatch.filter(files, '*.html')]
+def main(argv):
+  parser = argparse.ArgumentParser('Strips CSS rules not needed by Chrome')
+  parser.add_argument(
+      '--file_extension', choices=['js', 'html'], required=True)
+  opts = parser.parse_args(sys.argv[1:])
 
-  for f in html_files:
+  files_to_process = [os.path.join(dirpath, f)
+    for dirpath, dirnames, files in os.walk('components-chromium')
+    for f in fnmatch.filter(files, '*.' + opts.file_extension)]
+
+  for f in files_to_process:
     ProcessFile(f)
 
 
 if __name__ == '__main__':
-  main()
+  main(sys.argv[1:])
diff --git a/third_party/polymer/v1_0/reproduce.sh b/third_party/polymer/v1_0/reproduce.sh
index a88ccd8..9b73718f 100755
--- a/third_party/polymer/v1_0/reproduce.sh
+++ b/third_party/polymer/v1_0/reproduce.sh
@@ -98,7 +98,7 @@
 fi
 
 echo 'Stripping unnecessary prefixed CSS rules...'
-python css_strip_prefixes.py
+python css_strip_prefixes.py --file_extension=html
 
 echo 'Generating -rgb versions of --google-* vars in paper-style/colors.html...'
 python rgbify_hex_vars.py --filter-prefix=google --replace \
diff --git a/third_party/polymer/v3_0/components-chromium/iron-collapse/iron-collapse.js b/third_party/polymer/v3_0/components-chromium/iron-collapse/iron-collapse.js
index f6d3af14..ad45d500 100644
--- a/third_party/polymer/v3_0/components-chromium/iron-collapse/iron-collapse.js
+++ b/third_party/polymer/v3_0/components-chromium/iron-collapse/iron-collapse.js
@@ -67,7 +67,6 @@
         display: block;
         transition-duration: var(--iron-collapse-transition-duration, 300ms);
         /* Safari 10 needs this property prefixed to correctly apply the custom property */
-        -webkit-transition-duration: var(--iron-collapse-transition-duration, 300ms);
         overflow: visible;
       }
 
diff --git a/third_party/polymer/v3_0/components-chromium/iron-flex-layout/iron-flex-layout-classes.js b/third_party/polymer/v3_0/components-chromium/iron-flex-layout/iron-flex-layout-classes.js
index 3e49e59..59c36a39 100644
--- a/third_party/polymer/v3_0/components-chromium/iron-flex-layout/iron-flex-layout-classes.js
+++ b/third_party/polymer/v3_0/components-chromium/iron-flex-layout/iron-flex-layout-classes.js
@@ -45,72 +45,49 @@
     <style>
       .layout.horizontal,
       .layout.vertical {
-        display: -ms-flexbox;
-        display: -webkit-flex;
         display: flex;
       }
 
       .layout.inline {
-        display: -ms-inline-flexbox;
-        display: -webkit-inline-flex;
         display: inline-flex;
       }
 
       .layout.horizontal {
-        -ms-flex-direction: row;
-        -webkit-flex-direction: row;
         flex-direction: row;
       }
 
       .layout.vertical {
-        -ms-flex-direction: column;
-        -webkit-flex-direction: column;
         flex-direction: column;
       }
 
       .layout.wrap {
-        -ms-flex-wrap: wrap;
-        -webkit-flex-wrap: wrap;
         flex-wrap: wrap;
       }
 
       .layout.no-wrap {
-        -ms-flex-wrap: nowrap;
-        -webkit-flex-wrap: nowrap;
         flex-wrap: nowrap;
       }
 
       .layout.center,
       .layout.center-center {
-        -ms-flex-align: center;
-        -webkit-align-items: center;
         align-items: center;
       }
 
       .layout.center-justified,
       .layout.center-center {
-        -ms-flex-pack: center;
-        -webkit-justify-content: center;
         justify-content: center;
       }
 
       .flex {
-        -ms-flex: 1 1 0.000000001px;
-        -webkit-flex: 1;
         flex: 1;
-        -webkit-flex-basis: 0.000000001px;
         flex-basis: 0.000000001px;
       }
 
       .flex-auto {
-        -ms-flex: 1 1 auto;
-        -webkit-flex: 1 1 auto;
         flex: 1 1 auto;
       }
 
       .flex-none {
-        -ms-flex: none;
-        -webkit-flex: none;
         flex: none;
       }
     </style>
@@ -122,26 +99,18 @@
     <style>
       .layout.horizontal-reverse,
       .layout.vertical-reverse {
-        display: -ms-flexbox;
-        display: -webkit-flex;
         display: flex;
       }
 
       .layout.horizontal-reverse {
-        -ms-flex-direction: row-reverse;
-        -webkit-flex-direction: row-reverse;
         flex-direction: row-reverse;
       }
 
       .layout.vertical-reverse {
-        -ms-flex-direction: column-reverse;
-        -webkit-flex-direction: column-reverse;
         flex-direction: column-reverse;
       }
 
       .layout.wrap-reverse {
-        -ms-flex-wrap: wrap-reverse;
-        -webkit-flex-wrap: wrap-reverse;
         flex-wrap: wrap-reverse;
       }
     </style>
@@ -155,27 +124,19 @@
        * Alignment in cross axis.
        */
       .layout.start {
-        -ms-flex-align: start;
-        -webkit-align-items: flex-start;
         align-items: flex-start;
       }
 
       .layout.center,
       .layout.center-center {
-        -ms-flex-align: center;
-        -webkit-align-items: center;
         align-items: center;
       }
 
       .layout.end {
-        -ms-flex-align: end;
-        -webkit-align-items: flex-end;
         align-items: flex-end;
       }
 
       .layout.baseline {
-        -ms-flex-align: baseline;
-        -webkit-align-items: baseline;
         align-items: baseline;
       }
 
@@ -183,33 +144,23 @@
        * Alignment in main axis.
        */
       .layout.start-justified {
-        -ms-flex-pack: start;
-        -webkit-justify-content: flex-start;
         justify-content: flex-start;
       }
 
       .layout.center-justified,
       .layout.center-center {
-        -ms-flex-pack: center;
-        -webkit-justify-content: center;
         justify-content: center;
       }
 
       .layout.end-justified {
-        -ms-flex-pack: end;
-        -webkit-justify-content: flex-end;
         justify-content: flex-end;
       }
 
       .layout.around-justified {
-        -ms-flex-pack: distribute;
-        -webkit-justify-content: space-around;
         justify-content: space-around;
       }
 
       .layout.justified {
-        -ms-flex-pack: justify;
-        -webkit-justify-content: space-between;
         justify-content: space-between;
       }
 
@@ -217,32 +168,22 @@
        * Self alignment.
        */
       .self-start {
-        -ms-align-self: flex-start;
-        -webkit-align-self: flex-start;
         align-self: flex-start;
       }
 
       .self-center {
-        -ms-align-self: center;
-        -webkit-align-self: center;
         align-self: center;
       }
 
       .self-end {
-        -ms-align-self: flex-end;
-        -webkit-align-self: flex-end;
         align-self: flex-end;
       }
 
       .self-stretch {
-        -ms-align-self: stretch;
-        -webkit-align-self: stretch;
         align-self: stretch;
       }
 
       .self-baseline {
-        -ms-align-self: baseline;
-        -webkit-align-self: baseline;
         align-self: baseline;
       }
 
@@ -250,37 +191,22 @@
        * multi-line alignment in main axis.
        */
       .layout.start-aligned {
-        -ms-flex-line-pack: start;  /* IE10 */
-        -ms-align-content: flex-start;
-        -webkit-align-content: flex-start;
         align-content: flex-start;
       }
 
       .layout.end-aligned {
-        -ms-flex-line-pack: end;  /* IE10 */
-        -ms-align-content: flex-end;
-        -webkit-align-content: flex-end;
         align-content: flex-end;
       }
 
       .layout.center-aligned {
-        -ms-flex-line-pack: center;  /* IE10 */
-        -ms-align-content: center;
-        -webkit-align-content: center;
         align-content: center;
       }
 
       .layout.between-aligned {
-        -ms-flex-line-pack: justify;  /* IE10 */
-        -ms-align-content: space-between;
-        -webkit-align-content: space-between;
         align-content: space-between;
       }
 
       .layout.around-aligned {
-        -ms-flex-line-pack: distribute;  /* IE10 */
-        -ms-align-content: space-around;
-        -webkit-align-content: space-around;
         align-content: space-around;
       }
     </style>
@@ -292,76 +218,51 @@
     <style>
       .flex,
       .flex-1 {
-        -ms-flex: 1 1 0.000000001px;
-        -webkit-flex: 1;
         flex: 1;
-        -webkit-flex-basis: 0.000000001px;
         flex-basis: 0.000000001px;
       }
 
       .flex-2 {
-        -ms-flex: 2;
-        -webkit-flex: 2;
         flex: 2;
       }
 
       .flex-3 {
-        -ms-flex: 3;
-        -webkit-flex: 3;
         flex: 3;
       }
 
       .flex-4 {
-        -ms-flex: 4;
-        -webkit-flex: 4;
         flex: 4;
       }
 
       .flex-5 {
-        -ms-flex: 5;
-        -webkit-flex: 5;
         flex: 5;
       }
 
       .flex-6 {
-        -ms-flex: 6;
-        -webkit-flex: 6;
         flex: 6;
       }
 
       .flex-7 {
-        -ms-flex: 7;
-        -webkit-flex: 7;
         flex: 7;
       }
 
       .flex-8 {
-        -ms-flex: 8;
-        -webkit-flex: 8;
         flex: 8;
       }
 
       .flex-9 {
-        -ms-flex: 9;
-        -webkit-flex: 9;
         flex: 9;
       }
 
       .flex-10 {
-        -ms-flex: 10;
-        -webkit-flex: 10;
         flex: 10;
       }
 
       .flex-11 {
-        -ms-flex: 11;
-        -webkit-flex: 11;
         flex: 11;
       }
 
       .flex-12 {
-        -ms-flex: 12;
-        -webkit-flex: 12;
         flex: 12;
       }
     </style>
diff --git a/third_party/polymer/v3_0/components-chromium/iron-flex-layout/iron-flex-layout.js b/third_party/polymer/v3_0/components-chromium/iron-flex-layout/iron-flex-layout.js
index a71a6135..37ca84e 100644
--- a/third_party/polymer/v3_0/components-chromium/iron-flex-layout/iron-flex-layout.js
+++ b/third_party/polymer/v3_0/components-chromium/iron-flex-layout/iron-flex-layout.js
@@ -86,202 +86,139 @@
     html {
 
       --layout: {
-        display: -ms-flexbox;
-        display: -webkit-flex;
         display: flex;
       };
 
       --layout-inline: {
-        display: -ms-inline-flexbox;
-        display: -webkit-inline-flex;
         display: inline-flex;
       };
 
       --layout-horizontal: {
         @apply --layout;
 
-        -ms-flex-direction: row;
-        -webkit-flex-direction: row;
         flex-direction: row;
       };
 
       --layout-horizontal-reverse: {
         @apply --layout;
 
-        -ms-flex-direction: row-reverse;
-        -webkit-flex-direction: row-reverse;
         flex-direction: row-reverse;
       };
 
       --layout-vertical: {
         @apply --layout;
 
-        -ms-flex-direction: column;
-        -webkit-flex-direction: column;
         flex-direction: column;
       };
 
       --layout-vertical-reverse: {
         @apply --layout;
 
-        -ms-flex-direction: column-reverse;
-        -webkit-flex-direction: column-reverse;
         flex-direction: column-reverse;
       };
 
       --layout-wrap: {
-        -ms-flex-wrap: wrap;
-        -webkit-flex-wrap: wrap;
         flex-wrap: wrap;
       };
 
       --layout-wrap-reverse: {
-        -ms-flex-wrap: wrap-reverse;
-        -webkit-flex-wrap: wrap-reverse;
         flex-wrap: wrap-reverse;
       };
 
       --layout-flex-auto: {
-        -ms-flex: 1 1 auto;
-        -webkit-flex: 1 1 auto;
         flex: 1 1 auto;
       };
 
       --layout-flex-none: {
-        -ms-flex: none;
-        -webkit-flex: none;
         flex: none;
       };
 
       --layout-flex: {
-        -ms-flex: 1 1 0.000000001px;
-        -webkit-flex: 1;
         flex: 1;
-        -webkit-flex-basis: 0.000000001px;
         flex-basis: 0.000000001px;
       };
 
       --layout-flex-2: {
-        -ms-flex: 2;
-        -webkit-flex: 2;
         flex: 2;
       };
 
       --layout-flex-3: {
-        -ms-flex: 3;
-        -webkit-flex: 3;
         flex: 3;
       };
 
       --layout-flex-4: {
-        -ms-flex: 4;
-        -webkit-flex: 4;
         flex: 4;
       };
 
       --layout-flex-5: {
-        -ms-flex: 5;
-        -webkit-flex: 5;
         flex: 5;
       };
 
       --layout-flex-6: {
-        -ms-flex: 6;
-        -webkit-flex: 6;
         flex: 6;
       };
 
       --layout-flex-7: {
-        -ms-flex: 7;
-        -webkit-flex: 7;
         flex: 7;
       };
 
       --layout-flex-8: {
-        -ms-flex: 8;
-        -webkit-flex: 8;
         flex: 8;
       };
 
       --layout-flex-9: {
-        -ms-flex: 9;
-        -webkit-flex: 9;
         flex: 9;
       };
 
       --layout-flex-10: {
-        -ms-flex: 10;
-        -webkit-flex: 10;
         flex: 10;
       };
 
       --layout-flex-11: {
-        -ms-flex: 11;
-        -webkit-flex: 11;
         flex: 11;
       };
 
       --layout-flex-12: {
-        -ms-flex: 12;
-        -webkit-flex: 12;
         flex: 12;
       };
 
       /* alignment in cross axis */
 
       --layout-start: {
-        -ms-flex-align: start;
-        -webkit-align-items: flex-start;
         align-items: flex-start;
       };
 
       --layout-center: {
-        -ms-flex-align: center;
-        -webkit-align-items: center;
         align-items: center;
       };
 
       --layout-end: {
-        -ms-flex-align: end;
-        -webkit-align-items: flex-end;
         align-items: flex-end;
       };
 
       --layout-baseline: {
-        -ms-flex-align: baseline;
-        -webkit-align-items: baseline;
         align-items: baseline;
       };
 
       /* alignment in main axis */
 
       --layout-start-justified: {
-        -ms-flex-pack: start;
-        -webkit-justify-content: flex-start;
         justify-content: flex-start;
       };
 
       --layout-center-justified: {
-        -ms-flex-pack: center;
-        -webkit-justify-content: center;
         justify-content: center;
       };
 
       --layout-end-justified: {
-        -ms-flex-pack: end;
-        -webkit-justify-content: flex-end;
         justify-content: flex-end;
       };
 
       --layout-around-justified: {
-        -ms-flex-pack: distribute;
-        -webkit-justify-content: space-around;
         justify-content: space-around;
       };
 
       --layout-justified: {
-        -ms-flex-pack: justify;
-        -webkit-justify-content: space-between;
         justify-content: space-between;
       };
 
@@ -293,69 +230,44 @@
       /* self alignment */
 
       --layout-self-start: {
-        -ms-align-self: flex-start;
-        -webkit-align-self: flex-start;
         align-self: flex-start;
       };
 
       --layout-self-center: {
-        -ms-align-self: center;
-        -webkit-align-self: center;
         align-self: center;
       };
 
       --layout-self-end: {
-        -ms-align-self: flex-end;
-        -webkit-align-self: flex-end;
         align-self: flex-end;
       };
 
       --layout-self-stretch: {
-        -ms-align-self: stretch;
-        -webkit-align-self: stretch;
         align-self: stretch;
       };
 
       --layout-self-baseline: {
-        -ms-align-self: baseline;
-        -webkit-align-self: baseline;
         align-self: baseline;
       };
 
       /* multi-line alignment in main axis */
 
       --layout-start-aligned: {
-        -ms-flex-line-pack: start;  /* IE10 */
-        -ms-align-content: flex-start;
-        -webkit-align-content: flex-start;
         align-content: flex-start;
       };
 
       --layout-end-aligned: {
-        -ms-flex-line-pack: end;  /* IE10 */
-        -ms-align-content: flex-end;
-        -webkit-align-content: flex-end;
         align-content: flex-end;
       };
 
       --layout-center-aligned: {
-        -ms-flex-line-pack: center;  /* IE10 */
-        -ms-align-content: center;
-        -webkit-align-content: center;
         align-content: center;
       };
 
       --layout-between-aligned: {
-        -ms-flex-line-pack: justify;  /* IE10 */
-        -ms-align-content: space-between;
-        -webkit-align-content: space-between;
         align-content: space-between;
       };
 
       --layout-around-aligned: {
-        -ms-flex-line-pack: distribute;  /* IE10 */
-        -ms-align-content: space-around;
-        -webkit-align-content: space-around;
         align-content: space-around;
       };
 
diff --git a/third_party/polymer/v3_0/components-chromium/paper-input/paper-input-container.js b/third_party/polymer/v3_0/components-chromium/paper-input/paper-input-container.js
index 2777784f..47dcb3e 100644
--- a/third_party/polymer/v3_0/components-chromium/paper-input/paper-input-container.js
+++ b/third_party/polymer/v3_0/components-chromium/paper-input/paper-input-container.js
@@ -197,18 +197,14 @@
         @apply --layout-fit;
         border-bottom: 2px solid var(--paper-input-container-focus-color, var(--primary-color));
 
-        -webkit-transform-origin: center center;
         transform-origin: center center;
-        -webkit-transform: scale3d(0,1,1);
         transform: scale3d(0,1,1);
 
         @apply --paper-input-container-underline-focus;
       }
 
       .underline.is-highlighted .focused-line {
-        -webkit-transform: none;
         transform: none;
-        -webkit-transition: -webkit-transform 0.25s;
         transition: transform 0.25s;
 
         @apply --paper-transition-easing;
@@ -216,9 +212,7 @@
 
       .underline.is-invalid .focused-line {
         border-color: var(--paper-input-container-invalid-color, var(--error-color));
-        -webkit-transform: none;
         transform: none;
-        -webkit-transition: -webkit-transform 0.25s;
         transition: transform 0.25s;
 
         @apply --paper-transition-easing;
@@ -256,9 +250,7 @@
         width: 100%;
         font: inherit;
         color: var(--paper-input-container-color, var(--secondary-text-color));
-        -webkit-transition: -webkit-transform 0.25s, width 0.25s;
         transition: transform 0.25s, width 0.25s;
-        -webkit-transform-origin: left top;
         transform-origin: left top;
         /* Fix for safari not focusing 0-height date/time inputs with -webkit-apperance: none; */
         min-height: 1px;
@@ -271,7 +263,6 @@
 
       .input-content.label-is-floating ::slotted(label),
       .input-content.label-is-floating ::slotted(.paper-input-label) {
-        -webkit-transform: translateY(-75%) scale(0.75);
         transform: translateY(-75%) scale(0.75);
 
         /* Since we scale to 75/100 of the size, we actually have 100/75 of the
@@ -285,7 +276,6 @@
       :host(:dir(rtl)) .input-content.label-is-floating ::slotted(.paper-input-label) {
         right: 0;
         left: auto;
-        -webkit-transform-origin: right top;
         transform-origin: right top;
       }
 
diff --git a/third_party/polymer/v3_0/components-chromium/paper-progress/paper-progress.js b/third_party/polymer/v3_0/components-chromium/paper-progress/paper-progress.js
index 53a221c..17ac1b7f 100644
--- a/third_party/polymer/v3_0/components-chromium/paper-progress/paper-progress.js
+++ b/third_party/polymer/v3_0/components-chromium/paper-progress/paper-progress.js
@@ -128,28 +128,22 @@
 
       :host(.transiting) #primaryProgress,
       :host(.transiting) #secondaryProgress {
-        -webkit-transition-property: -webkit-transform;
         transition-property: transform;
 
         /* Duration */
-        -webkit-transition-duration: var(--paper-progress-transition-duration, 0.08s);
         transition-duration: var(--paper-progress-transition-duration, 0.08s);
 
         /* Timing function */
-        -webkit-transition-timing-function: var(--paper-progress-transition-timing-function, ease);
         transition-timing-function: var(--paper-progress-transition-timing-function, ease);
 
         /* Delay */
-        -webkit-transition-delay: var(--paper-progress-transition-delay, 0s);
         transition-delay: var(--paper-progress-transition-delay, 0s);
       }
 
       #primaryProgress,
       #secondaryProgress {
         @apply --layout-fit;
-        -webkit-transform-origin: left center;
         transform-origin: left center;
-        -webkit-transform: scaleX(0);
         transform: scaleX(0);
         will-change: transform;
       }
@@ -171,50 +165,36 @@
       }
 
       :host(:not([disabled])) #primaryProgress.indeterminate {
-        -webkit-transform-origin: right center;
         transform-origin: right center;
-        -webkit-animation: indeterminate-bar var(--paper-progress-indeterminate-cycle-duration, 2s) linear infinite;
         animation: indeterminate-bar var(--paper-progress-indeterminate-cycle-duration, 2s) linear infinite;
       }
 
       :host(:not([disabled])) #primaryProgress.indeterminate::after {
         content: "";
-        -webkit-transform-origin: center center;
         transform-origin: center center;
 
-        -webkit-animation: indeterminate-splitter var(--paper-progress-indeterminate-cycle-duration, 2s) linear infinite;
         animation: indeterminate-splitter var(--paper-progress-indeterminate-cycle-duration, 2s) linear infinite;
       }
 
       @-webkit-keyframes indeterminate-bar {
         0% {
-          -webkit-transform: scaleX(1) translateX(-100%);
         }
         50% {
-          -webkit-transform: scaleX(1) translateX(0%);
         }
         75% {
-          -webkit-transform: scaleX(1) translateX(0%);
-          -webkit-animation-timing-function: cubic-bezier(.28,.62,.37,.91);
         }
         100% {
-          -webkit-transform: scaleX(0) translateX(0%);
         }
       }
 
       @-webkit-keyframes indeterminate-splitter {
         0% {
-          -webkit-transform: scaleX(.75) translateX(-125%);
         }
         30% {
-          -webkit-transform: scaleX(.75) translateX(-125%);
-          -webkit-animation-timing-function: cubic-bezier(.42,0,.6,.8);
         }
         90% {
-          -webkit-transform: scaleX(.75) translateX(125%);
         }
         100% {
-          -webkit-transform: scaleX(.75) translateX(125%);
         }
       }
 
diff --git a/third_party/polymer/v3_0/components-chromium/paper-spinner/paper-spinner-styles.js b/third_party/polymer/v3_0/components-chromium/paper-spinner/paper-spinner-styles.js
index 43b6553..1fe43d0 100644
--- a/third_party/polymer/v3_0/components-chromium/paper-spinner/paper-spinner-styles.js
+++ b/third_party/polymer/v3_0/components-chromium/paper-spinner/paper-spinner-styles.js
@@ -61,7 +61,6 @@
       }
 
       #spinnerContainer.active {
-        -webkit-animation: container-rotate var(--paper-spinner-container-rotation-duration) linear infinite;
         animation: container-rotate var(--paper-spinner-container-rotation-duration) linear infinite;
       }
 
@@ -107,10 +106,6 @@
        * seems).
        */
       .active .spinner-layer {
-        -webkit-animation-name: fill-unfill-rotate;
-        -webkit-animation-duration: var(--paper-spinner-full-cycle-duration);
-        -webkit-animation-timing-function: cubic-bezier(0.4, 0.0, 0.2, 1);
-        -webkit-animation-iteration-count: infinite;
         animation-name: fill-unfill-rotate;
         animation-duration: var(--paper-spinner-full-cycle-duration);
         animation-timing-function: cubic-bezier(0.4, 0.0, 0.2, 1);
@@ -119,22 +114,18 @@
       }
 
       .active .spinner-layer.layer-1 {
-        -webkit-animation-name: fill-unfill-rotate, layer-1-fade-in-out;
         animation-name: fill-unfill-rotate, layer-1-fade-in-out;
       }
 
       .active .spinner-layer.layer-2 {
-        -webkit-animation-name: fill-unfill-rotate, layer-2-fade-in-out;
         animation-name: fill-unfill-rotate, layer-2-fade-in-out;
       }
 
       .active .spinner-layer.layer-3 {
-        -webkit-animation-name: fill-unfill-rotate, layer-3-fade-in-out;
         animation-name: fill-unfill-rotate, layer-3-fade-in-out;
       }
 
       .active .spinner-layer.layer-4 {
-        -webkit-animation-name: fill-unfill-rotate, layer-4-fade-in-out;
         animation-name: fill-unfill-rotate, layer-4-fade-in-out;
       }
 
@@ -268,34 +259,27 @@
       .circle-clipper.left .circle {
         left: 0;
         border-right-color: transparent !important;
-        -webkit-transform: rotate(129deg);
         transform: rotate(129deg);
       }
 
       .circle-clipper.right .circle {
         left: -100%;
         border-left-color: transparent !important;
-        -webkit-transform: rotate(-129deg);
         transform: rotate(-129deg);
       }
 
       .active .gap-patch::after,
       .active .circle-clipper .circle {
-        -webkit-animation-duration: var(--paper-spinner-expand-contract-duration);
-        -webkit-animation-timing-function: cubic-bezier(0.4, 0.0, 0.2, 1);
-        -webkit-animation-iteration-count: infinite;
         animation-duration: var(--paper-spinner-expand-contract-duration);
         animation-timing-function: cubic-bezier(0.4, 0.0, 0.2, 1);
         animation-iteration-count: infinite;
       }
 
       .active .circle-clipper.left .circle {
-        -webkit-animation-name: left-spin;
         animation-name: left-spin;
       }
 
       .active .circle-clipper.right .circle {
-        -webkit-animation-name: right-spin;
         animation-name: right-spin;
       }
 
@@ -324,7 +308,6 @@
       }
 
       #spinnerContainer.cooldown {
-        -webkit-animation: container-rotate var(--paper-spinner-container-rotation-duration) linear infinite, fade-out var(--paper-spinner-cooldown-duration) cubic-bezier(0.4, 0.0, 0.2, 1);
         animation: container-rotate var(--paper-spinner-container-rotation-duration) linear infinite, fade-out var(--paper-spinner-cooldown-duration) cubic-bezier(0.4, 0.0, 0.2, 1);
       }
 
diff --git a/third_party/polymer/v3_0/components-chromium/paper-tooltip/paper-tooltip.js b/third_party/polymer/v3_0/components-chromium/paper-tooltip/paper-tooltip.js
index aaa6e15..853eee19 100644
--- a/third_party/polymer/v3_0/components-chromium/paper-tooltip/paper-tooltip.js
+++ b/third_party/polymer/v3_0/components-chromium/paper-tooltip/paper-tooltip.js
@@ -60,9 +60,6 @@
         position: absolute;
         outline: none;
         z-index: 1002;
-        -moz-user-select: none;
-        -ms-user-select: none;
-        -webkit-user-select: none;
         user-select: none;
         cursor: default;
       }
diff --git a/third_party/polymer/v3_0/reproduce.sh b/third_party/polymer/v3_0/reproduce.sh
index 38e74dc1..c3b4ef499 100755
--- a/third_party/polymer/v3_0/reproduce.sh
+++ b/third_party/polymer/v3_0/reproduce.sh
@@ -82,7 +82,9 @@
   echo
 fi
 
-# TODO css_strip_prefixes.py
+echo 'Stripping unnecessary prefixed CSS rules...'
+python ../v1_0/css_strip_prefixes.py --file_extension=js
+
 # TODO rgbify_hex_vars.py
 # TODO create components summary
 # TODO generate gn
diff --git a/tools/mb/mb.py b/tools/mb/mb.py
index 275fc61..1d1c2e1 100755
--- a/tools/mb/mb.py
+++ b/tools/mb/mb.py
@@ -108,7 +108,12 @@
       subp.add_argument('-v', '--verbose', action='store_true',
                         help='verbose logging')
 
-    parser = argparse.ArgumentParser(prog='mb')
+    parser = argparse.ArgumentParser(
+      prog='mb', description='mb (meta-build) is a python wrapper around GN. '
+                             'See the user guide in '
+                             '//tools/mb/docs/user_guide.md for detailed usage '
+                             'instructions.')
+
     subps = parser.add_subparsers()
 
     subp = subps.add_parser('analyze',
diff --git a/tools/memory/asan/blacklist_win.txt b/tools/memory/asan/blacklist_win.txt
index 9c9ee19..065d43a 100644
--- a/tools/memory/asan/blacklist_win.txt
+++ b/tools/memory/asan/blacklist_win.txt
@@ -41,5 +41,6 @@
 src:*registry_interception.cc
 src:*resolver_32.cc
 src:*sandbox_nt_util.cc
+src:*signed_interception.cc
 src:*sync_interception.cc
 ################################################################################
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index d029dd1..f17c789 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -12786,6 +12786,24 @@
   <int value="1" label="New key accelerator is used"/>
 </enum>
 
+<enum name="DesksCreationRemovalSource">
+  <int value="0" label="Button pressed"/>
+  <int value="1" label="Keyboard shortcut"/>
+</enum>
+
+<enum name="DesksMoveWindowFromActiveDeskSource">
+  <int value="0" label="Drag and drop"/>
+  <int value="1" label="Move-window-to-desk keyboard shortcut"/>
+</enum>
+
+<enum name="DesksSwitchSource">
+  <int value="0" label="New-desk keyboard shortcut"/>
+  <int value="1" label="Active desk was removed"/>
+  <int value="2" label="Desk-switch keyboard shortcut"/>
+  <int value="3" label="Mini_view button press"/>
+  <int value="4" label="Window on desk activated"/>
+</enum>
+
 <enum name="DesktopCaptureCounters">
   <int value="0" label="Screen capturer created."/>
   <int value="1" label="Window capturer created."/>
@@ -25025,6 +25043,13 @@
   <int value="2" label="Unable to open"/>
 </enum>
 
+<enum name="FileManagerFormatFileSystemType">
+  <int value="0" label="Unknown"/>
+  <int value="1" label="FAT32"/>
+  <int value="2" label="exFAT"/>
+  <int value="3" label="NTFS"/>
+</enum>
+
 <enum name="FileManagerListType">
   <int value="0" label="Uninitialized"/>
   <int value="1" label="List view (detail)"/>
@@ -42719,6 +42744,12 @@
   <int value="1" label="Shortcut customized"/>
 </enum>
 
+<enum name="NTPCustomizedShortcutSettings">
+  <int value="0" label="Most Visited is enabled"/>
+  <int value="1" label="Custom links is enabled"/>
+  <int value="2" label="Shortcuts are hidden"/>
+</enum>
+
 <enum name="NTPCustomizeLocalImageBackgroundAction">
   <int value="0" label="'Cancel' clicked in the 'Upload an image' dialog"/>
   <int value="1" label="'Done' clicked in the 'Upload an image' dialog"/>
@@ -42733,6 +42764,8 @@
       label="All custom shortcuts were restored (via menu or message pop-up)."/>
   <int value="5" label="A custom shortcut was added."/>
   <int value="6" label="A custom shortcut was updated."/>
+  <int value="7" label="The type of shortcuts displayed was changed."/>
+  <int value="8" label="The visibility of shortcuts was changed."/>
 </enum>
 
 <enum name="NtpFollowAction">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 785be82..4bea61c4 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -71,7 +71,6 @@
 <histogram name="Accessibility.AndroidServiceInfo"
     enum="AccessibilityAndroidServiceInfoEnum">
   <owner>dmazzoni@chromium.org</owner>
-  <owner>paulmiller@chromium.org</owner>
   <summary>
     Tracks flags and capabilities of enabled accessibility services. Recorded
     every time an Android web content view first creates a virtual view
@@ -3776,7 +3775,6 @@
   <obsolete>
     Removed from code July 2018. Variations in WebView has launched.
   </obsolete>
-  <owner>paulmiller@chromium.org</owner>
   <owner>changwan@chromium.org</owner>
   <summary>
     Indicates whether variations is enabled. We want to know how enabling
@@ -6231,6 +6229,83 @@
   </summary>
 </histogram>
 
+<histogram name="Ash.Desks.DesksCount" expires_after="M85">
+  <owner>afakhry@chromium.org</owner>
+  <summary>
+    Emitted when there's a change in the virtual desks count whether due to desk
+    creation or removal. Specifies the number or available desks.
+  </summary>
+</histogram>
+
+<histogram name="Ash.Desks.DesksSwitch" enum="DesksSwitchSource"
+    expires_after="M85">
+  <owner>afakhry@chromium.org</owner>
+  <summary>
+    Emitted when the active desk is changed to specify the source of this
+    action, i.e. whether due to new-desk shortcut, desk removed, window
+    activated, switch-desk shortcut, or a press on the desk mini_view.
+  </summary>
+</histogram>
+
+<histogram name="Ash.Desks.MoveWindowFromActiveDesk"
+    enum="DesksMoveWindowFromActiveDeskSource" expires_after="M85">
+  <owner>afakhry@chromium.org</owner>
+  <summary>
+    Emitted when a window is moved from the current active desk to another desk.
+    Specifies the source of this action, i.e. whether to window drag-and-drop,
+    or keyboard shortcut.
+  </summary>
+</histogram>
+
+<histogram name="Ash.Desks.NewDesk" enum="DesksCreationRemovalSource"
+    expires_after="M85">
+  <owner>afakhry@chromium.org</owner>
+  <summary>
+    Emitted when a virtual desk is created to specify the source of this action,
+    i.e. whether from the new-desk button, or keyboard shortcut.
+  </summary>
+</histogram>
+
+<histogram name="Ash.Desks.NumberOfWindowsOnDesk_1" expires_after="M85">
+  <owner>afakhry@chromium.org</owner>
+  <summary>
+    The number of windows on the first desk. Emitted when a desk is removed, or
+    a window is moved to another desk.
+  </summary>
+</histogram>
+
+<histogram name="Ash.Desks.NumberOfWindowsOnDesk_2" expires_after="M85">
+  <owner>afakhry@chromium.org</owner>
+  <summary>
+    The number of windows on the second desk. Emitted when a desk is removed, or
+    a window is moved to another desk.
+  </summary>
+</histogram>
+
+<histogram name="Ash.Desks.NumberOfWindowsOnDesk_3" expires_after="M85">
+  <owner>afakhry@chromium.org</owner>
+  <summary>
+    The number of windows on the third desk. Emitted when a desk is removed, or
+    a window is moved to another desk.
+  </summary>
+</histogram>
+
+<histogram name="Ash.Desks.NumberOfWindowsOnDesk_4" expires_after="M85">
+  <owner>afakhry@chromium.org</owner>
+  <summary>
+    The number of windows on the fourth desk. Emitted when a desk is removed, or
+    a window is moved to another desk.
+  </summary>
+</histogram>
+
+<histogram name="Ash.Desks.RemoveDesk" enum="DesksCreationRemovalSource">
+  <owner>afakhry@chromium.org</owner>
+  <summary>
+    Emitted when a virtual desk is removed to specify the source of this remove
+    operation, i.e. whether from the close-desk button, or keyboard shortcut.
+  </summary>
+</histogram>
+
 <histogram name="Ash.Desktop.TimeBetweenNavigateToTaskSwitches" units="seconds">
   <owner>bruthig@chromium.org</owner>
   <owner>tdanderson@chromium.org</owner>
@@ -11339,6 +11414,15 @@
   <summary>Whether the user changed autofilled field.</summary>
 </histogram>
 
+<histogram name="AutogeneratedTheme.ColorGenerationTime" units="ms"
+    expires_after="2019-12-31">
+  <owner>gayane@chromium.org</owner>
+  <summary>
+    Time that it takes to calculate all the theme properties for autogenerated
+    themes in ms.
+  </summary>
+</histogram>
+
 <histogram name="AutoScreenBrightness.AdapterDecisionAtUserChange.AlsDelta"
     units="count" expires_after="2019-12-31">
 <!-- Name completed by histogram_suffixes name="AlsBrightnessDirection" and name="AdapterDecision" -->
@@ -43957,6 +44041,15 @@
   </summary>
 </histogram>
 
+<histogram name="FileBrowser.FormatFileSystemType"
+    enum="FileManagerFormatFileSystemType" expires_after="2019-12-06">
+  <owner>austinct@chromium.org</owner>
+  <summary>
+    Chrome OS File Browser: this records the filesystem selected when formatting
+    an external drive.
+  </summary>
+</histogram>
+
 <histogram name="FileBrowser.HardUnpluggedAroundSuspend.TimeSinceResume"
     units="ms" expires_after="M79">
   <obsolete>
@@ -54734,7 +54827,12 @@
 </histogram>
 
 <histogram name="MachineLearningService.PeakPrivateMemoryKb" units="KB"
-    expires_after="2020-02-01">
+    expires_after="2019-07-18">
+  <obsolete>
+    Deprecated 07/2019 because we change to record total (shared+unshared)
+    memory rather than only private memory. Replaced by
+    MachineLearningService.PeakTotalMemoryKb.
+  </obsolete>
   <owner>alanlxl@chromium.org</owner>
   <owner>amoylan@chromium.org</owner>
   <summary>
@@ -54743,8 +54841,24 @@
   </summary>
 </histogram>
 
+<histogram name="MachineLearningService.PeakTotalMemoryKb" units="KB"
+    expires_after="2020-02-01">
+  <owner>alanlxl@chromium.org</owner>
+  <owner>amoylan@chromium.org</owner>
+  <owner>honglinyu@chromium.org</owner>
+  <summary>
+    Peak total (shared and non-shared) memory used by Chrome OS ML Service over
+    the last 24 hours. Sampled every 5 minutes, so may miss short-lived spikes.
+  </summary>
+</histogram>
+
 <histogram base="true" name="MachineLearningService.PrivateMemoryDeltaKb"
-    units="KB" expires_after="2020-02-01">
+    units="KB" expires_after="2019-07-18">
+  <obsolete>
+    Deprecated 07/2019 because we change to record total (shared+unshared)
+    memory rather than only private memory. Replaced by
+    MachineLearningService.TotalMemoryDeltaKb.
+  </obsolete>
 <!-- Name completed by histogram_suffixes
      name="MachineLearningServiceRequests" -->
 
@@ -54756,7 +54870,12 @@
 </histogram>
 
 <histogram name="MachineLearningService.PrivateMemoryKb" units="KB"
-    expires_after="2020-02-01">
+    expires_after="2019-07-18">
+  <obsolete>
+    Deprecated 07/2019 because we change to record total (shared+unshared)
+    memory rather than only private memory. Replaced by
+    MachineLearningService.TotalMemoryKb.
+  </obsolete>
   <owner>alanlxl@chromium.org</owner>
   <owner>amoylan@chromium.org</owner>
   <summary>
@@ -54765,6 +54884,27 @@
   </summary>
 </histogram>
 
+<histogram base="true" name="MachineLearningService.TotalMemoryDeltaKb"
+    units="KB" expires_after="2020-02-01">
+  <owner>amoylan@chromium.org</owner>
+  <owner>alanlxl@chromium.org</owner>
+  <owner>honglinyu@chromium.org</owner>
+  <summary>
+    Memory usage increase caused by one Chrome OS ML Service request.
+  </summary>
+</histogram>
+
+<histogram name="MachineLearningService.TotalMemoryKb" units="KB"
+    expires_after="2020-02-01">
+  <owner>alanlxl@chromium.org</owner>
+  <owner>amoylan@chromium.org</owner>
+  <owner>honglinyu@chromium.org</owner>
+  <summary>
+    Total (shared and non-shared) memory used by Chrome OS ML Service, sampled
+    every 5 minutes.
+  </summary>
+</histogram>
+
 <histogram name="ManagedUsers.ChromeOS.PasswordChange"
     enum="ManagedUserPasswordChange" expires_after="M77">
   <owner>achuith@chromium.org</owner>
@@ -82173,6 +82313,17 @@
   </summary>
 </histogram>
 
+<histogram name="NewTabPage.CustomizedShortcuts"
+    enum="NTPCustomizedShortcutSettings" expires_after="2020-07-20">
+  <owner>dbeam@chromium.org</owner>
+  <owner>yyushkina@chromium.org</owner>
+  <summary>
+    The New Tab Page shortcut settings that can be customized by the user,
+    including shortcut type (i.e. most visited vs custom links) and visibility;
+    logged per NTP load.
+  </summary>
+</histogram>
+
 <histogram name="NewTabPage.CustomizeLocalImageBackgroundAction"
     enum="NTPCustomizeLocalImageBackgroundAction" expires_after="M90">
   <owner>dbeam@chromium.org</owner>
@@ -93565,7 +93716,7 @@
 </histogram>
 
 <histogram name="PaintHolding.CommitTrigger" enum="PaintHoldingCommitTrigger"
-    expires_after="M78">
+    expires_after="M80">
   <owner>schenney@chromium.org</owner>
   <owner>paint-dev@chromium.org</owner>
   <summary>
@@ -93575,7 +93726,7 @@
 </histogram>
 
 <histogram name="PaintHolding.InputTiming" enum="PaintHoldingInputTiming"
-    expires_after="M78">
+    expires_after="M80">
   <owner>schenney@chromium.org</owner>
   <owner>paint-dev@chromium.org</owner>
   <summary>
@@ -144745,7 +144896,6 @@
 
 <histogram name="Variations.SeedLoadBlockingTime" units="ms"
     expires_after="M90">
-  <owner>paulmiller@chromium.org</owner>
   <owner>changwan@chromium.org</owner>
   <summary>
     Records the time spent blocking WebView startup to wait for the variations
@@ -144773,7 +144923,6 @@
   <obsolete>
     Deprecated 2019-06. See results on https://crbug.com/936172#c8.
   </obsolete>
-  <owner>paulmiller@chromium.org</owner>
   <owner>changwan@chromium.org</owner>
   <summary>
     Records the time spent loading the variations seed in WebView, specifically,
@@ -144787,7 +144936,6 @@
   <obsolete>
     Deprecated 2019-06. See results on https://crbug.com/936172#c8.
   </obsolete>
-  <owner>paulmiller@chromium.org</owner>
   <owner>changwan@chromium.org</owner>
   <summary>
     Records how long we would block WebView startup to wait for the variations
@@ -152221,7 +152369,6 @@
 <histogram name="WebView.ApiCall" enum="WebViewApiCall">
   <owner>changwan@chromium.org</owner>
   <owner>ntfschr@chromium.org</owner>
-  <owner>paulmiller@chromium.org</owner>
   <summary>Records calls to WebView APIs in WebViewChromium.</summary>
 </histogram>
 
@@ -159202,7 +159349,14 @@
   <suffix name="LoadModelResult"/>
   <affected-histogram name="MachineLearningService.CpuTimeMicrosec"/>
   <affected-histogram name="MachineLearningService.ElapsedTimeMicrosec"/>
-  <affected-histogram name="MachineLearningService.PrivateMemoryDeltaKb"/>
+  <affected-histogram name="MachineLearningService.PrivateMemoryDeltaKb">
+    <obsolete>
+      Deprecated 07/2019, because we change to record total (shared+unshared)
+      memory rather than only private memory. Replaced by
+      MachineLearningService.TotalMemoryDeltaKb.
+    </obsolete>
+  </affected-histogram>
+  <affected-histogram name="MachineLearningService.TotalMemoryDeltaKb"/>
 </histogram_suffixes>
 
 <histogram_suffixes name="MainFrameNavigation" separator="_">
@@ -167489,6 +167643,8 @@
       name="Apps.PaginationTransition.DragScroll.PresentationTime.MaxLatency"/>
   <affected-histogram name="Apps.StateTransition.AnimationSmoothness"/>
   <affected-histogram name="Apps.StateTransition.Drag.PresentationTime"/>
+  <affected-histogram
+      name="Apps.StateTransition.Drag.PresentationTime.MaxLatency"/>
   <affected-histogram name="Ash.Overview.AnimationSmoothness.Close"/>
   <affected-histogram name="Ash.Overview.WindowDrag.PresentationTime"/>
 </histogram_suffixes>
diff --git a/tools/perf/core/minidump_unittest.py b/tools/perf/core/minidump_unittest.py
index f6e5e9f..23cf7a7 100644
--- a/tools/perf/core/minidump_unittest.py
+++ b/tools/perf/core/minidump_unittest.py
@@ -90,7 +90,9 @@
   @decorators.Isolated
   # Disabled on Mac 10.12 (Sierra) due to it not getting a stack trace to
   # symbolize from the second crash.
-  @decorators.Disabled('chromeos', 'android', 'win7', 'sierra', 'linux')
+  # Test is flaky on 10.13 (HighSierra). See https://crbug.com/986644.
+  @decorators.Disabled('chromeos', 'android', 'win7', 'sierra', 'linux',
+                       'highsierra')
   def testMultipleCrashMinidumps(self):
     # Wait for the browser to restart fully before crashing
     self._LoadPageThenWait('var cat = "dog";', 'cat')
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml
index 88ba4233..07ecf93d 100644
--- a/tools/traffic_annotation/summary/annotations.xml
+++ b/tools/traffic_annotation/summary/annotations.xml
@@ -8,7 +8,7 @@
 -->
 
 <annotations>
- <item id="CRD_relay_session_request" hash_code="24058523" type="0" content_hash_code="36997811" os_list="linux,windows" file_path="remoting/protocol/port_allocator.cc"/>
+ <item id="CRD_relay_session_request" hash_code="24058523" type="0" deprecated="2019-07-22" content_hash_code="36997811" file_path=""/>
  <item id="accounts_image_fetcher" hash_code="98658519" type="0" content_hash_code="45432230" os_list="linux,windows" file_path="components/signin/internal/identity_manager/account_fetcher_service.cc"/>
  <item id="adb_client_socket" hash_code="87775794" type="0" content_hash_code="56654828" os_list="linux,windows" file_path="chrome/browser/devtools/device/adb/adb_client_socket.cc"/>
  <item id="affiliation_lookup" hash_code="111904019" type="0" content_hash_code="81061452" os_list="linux,windows" file_path="components/password_manager/core/browser/android_affiliation/affiliation_fetcher.cc"/>
diff --git a/ui/accelerated_widget_mac/ca_layer_tree_unittest_mac.mm b/ui/accelerated_widget_mac/ca_layer_tree_unittest_mac.mm
index 926d12b..19071de 100644
--- a/ui/accelerated_widget_mac/ca_layer_tree_unittest_mac.mm
+++ b/ui/accelerated_widget_mac/ca_layer_tree_unittest_mac.mm
@@ -461,6 +461,11 @@
                 [[clip_and_sorting_layer sublayers] objectAtIndex:0]);
       clip_and_sorting_rounded_layer =
           [[clip_and_sorting_layer sublayers] objectAtIndex:0];
+
+      // Under a 2.0 scale factor, the corner-radius should be halved.
+      EXPECT_EQ(properties.rounded_corner_bounds.GetSimpleRadius() / 2.0f,
+                [clip_and_sorting_rounded_layer cornerRadius]);
+
       EXPECT_EQ(1u, [[clip_and_sorting_rounded_layer sublayers] count]);
       EXPECT_NE(transform_layer,
                 [[clip_and_sorting_layer sublayers] objectAtIndex:0]);
@@ -566,7 +571,8 @@
       EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
       EXPECT_EQ(clip_and_sorting_rounded_layer,
                 [[clip_and_sorting_layer sublayers] objectAtIndex:0]);
-      EXPECT_EQ(properties.rounded_corner_bounds.GetSimpleRadius(),
+      // Under a 2.0 scale factor, the corer-radius should be halved.
+      EXPECT_EQ(properties.rounded_corner_bounds.GetSimpleRadius() / 2.0f,
                 [clip_and_sorting_rounded_layer cornerRadius]);
       EXPECT_TRUE([clip_and_sorting_rounded_layer masksToBounds]);
       EXPECT_EQ(transform_layer,
diff --git a/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm b/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm
index 787741d5..8cf753ed 100644
--- a/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm
+++ b/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm
@@ -662,7 +662,8 @@
                                    -dip_rounded_corner_bounds.y(), 0)];
 
       [rounded_corner_ca_layer
-          setCornerRadius:rounded_corner_bounds.GetSimpleRadius()];
+          setCornerRadius:rounded_corner_bounds.GetSimpleRadius() /
+                          scale_factor];
     }
   } else {
     [rounded_corner_ca_layer setMasksToBounds:false];
diff --git a/ui/accessibility/BUILD.gn b/ui/accessibility/BUILD.gn
index 99e228be..9323e4a 100644
--- a/ui/accessibility/BUILD.gn
+++ b/ui/accessibility/BUILD.gn
@@ -39,6 +39,7 @@
     "ax_action_data.h",
     "ax_action_handler.cc",
     "ax_action_handler.h",
+    "ax_action_target.h",
     "ax_active_popup.cc",
     "ax_active_popup.h",
     "ax_clipping_behavior.h",
@@ -99,6 +100,8 @@
     "ax_tree_source.h",
     "ax_tree_source_checker.h",
     "ax_tree_update.h",
+    "null_ax_action_target.cc",
+    "null_ax_action_target.h",
     "platform/ax_android_constants.cc",
     "platform/ax_android_constants.h",
     "platform/ax_platform_node.cc",
@@ -260,6 +263,7 @@
     "mojom/ax_tree_data_mojom_traits_unittest.cc",
     "mojom/ax_tree_id_mojom_traits_unittest.cc",
     "mojom/ax_tree_update_mojom_traits_unittest.cc",
+    "null_ax_action_target_unittest.cc",
     "platform/ax_fragment_root_win_unittest.cc",
     "platform/ax_platform_node_textchildprovider_win_unittest.cc",
     "platform/ax_platform_node_textprovider_win_unittest.cc",
diff --git a/ui/accessibility/ax_action_target.h b/ui/accessibility/ax_action_target.h
new file mode 100644
index 0000000..54bcd29
--- /dev/null
+++ b/ui/accessibility/ax_action_target.h
@@ -0,0 +1,62 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_ACCESSIBILITY_AX_ACTION_TARGET_H_
+#define UI_ACCESSIBILITY_AX_ACTION_TARGET_H_
+
+#include "ui/accessibility/ax_enums.mojom-shared.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace ui {
+
+// AXActionTarget is an abstract interface that can be used to carry out
+// accessibility actions on nodes from an AXTreeSource without knowing the
+// concrete class of that AXTreeSource.
+class AXActionTarget {
+ public:
+  virtual ~AXActionTarget() = default;
+
+  enum class Type { kNull, kBlink };
+  virtual Type GetType() const = 0;
+
+  virtual bool ClearAccessibilityFocus() const = 0;
+  virtual bool Click() const = 0;
+  virtual bool Decrement() const = 0;
+  virtual bool Increment() const = 0;
+  virtual bool Focus() const = 0;
+  virtual gfx::Rect GetRelativeBounds() const = 0;
+  virtual gfx::Point GetScrollOffset() const = 0;
+  virtual gfx::Point MinimumScrollOffset() const = 0;
+  virtual gfx::Point MaximumScrollOffset() const = 0;
+  virtual bool SetAccessibilityFocus() const = 0;
+  virtual void SetScrollOffset(const gfx::Point& point) const = 0;
+  virtual bool SetSelected(bool selected) const = 0;
+  virtual bool SetSelection(const AXActionTarget* anchor_object,
+                            int anchor_offset,
+                            const AXActionTarget* focus_object,
+                            int focus_offset) const = 0;
+  virtual bool SetSequentialFocusNavigationStartingPoint() const = 0;
+  virtual bool SetValue(const std::string& value) const = 0;
+  virtual bool ShowContextMenu() const = 0;
+  // Make this object visible by scrolling as many nested scrollable views as
+  // needed.
+  virtual bool ScrollToMakeVisible() const = 0;
+  // Same, but if the whole object can't be made visible, try for this subrect,
+  // in local coordinates.
+  virtual bool ScrollToMakeVisibleWithSubFocus(
+      const gfx::Rect& rect,
+      ax::mojom::ScrollAlignment horizontal_scroll_alignment,
+      ax::mojom::ScrollAlignment vertical_scroll_alignment) const = 0;
+  // Scroll this object to a given point in global coordinates of the top-level
+  // window.
+  virtual bool ScrollToGlobalPoint(const gfx::Point& point) const = 0;
+
+ protected:
+  AXActionTarget() = default;
+};
+
+}  // namespace ui
+
+#endif  // UI_ACCESSIBILITY_AX_ACTION_TARGET_H_
diff --git a/ui/accessibility/ax_tree_serializer.h b/ui/accessibility/ax_tree_serializer.h
index 0b83cfe..6aed3474 100644
--- a/ui/accessibility/ax_tree_serializer.h
+++ b/ui/accessibility/ax_tree_serializer.h
@@ -462,14 +462,12 @@
 template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
 void AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::
     DeleteClientSubtree(ClientTreeNode* client_node) {
-  if (client_node == client_root_) {
-    Reset();  // Do not try to reuse a bad root later.
-    return;
-  }
-  for (size_t i = 0; i < client_node->children.size(); ++i)
+  for (size_t i = 0; i < client_node->children.size(); ++i) {
+    client_id_map_.erase(client_node->children[i]->id);
     DeleteClientSubtree(client_node->children[i]);
-  client_id_map_.erase(client_node->id);
-  delete client_node;
+    delete client_node->children[i];
+  }
+  client_node->children.clear();
 }
 
 template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
@@ -533,8 +531,7 @@
 
     // There shouldn't be any reparenting because we've already handled it
     // above. If this happens, reset and return an error.
-
-    ClientTreeNode* client_child = ClientTreeNodeById(new_child_id);
+    ClientTreeNode* client_child = client_id_map_[new_child_id];
     if (client_child && client_child->parent != client_node) {
       DVLOG(1) << "Reparenting detected";
       Reset();
@@ -555,7 +552,9 @@
     ClientTreeNode* old_child = old_children[i];
     int old_child_id = old_child->id;
     if (new_child_ids.find(old_child_id) == new_child_ids.end()) {
+      client_id_map_.erase(old_child_id);
       DeleteClientSubtree(old_child);
+      delete old_child;
     } else {
       client_child_id_map[old_child_id] = old_child;
     }
@@ -594,10 +593,8 @@
 
     new_child_ids.erase(child_id);
     actual_serialized_node_child_ids.push_back(child_id);
-    ClientTreeNode* reused_child = nullptr;
-    if (client_child_id_map.find(child_id) != client_child_id_map.end())
-      reused_child = ClientTreeNodeById(child_id);
-    if (reused_child) {
+    if (client_child_id_map.find(child_id) != client_child_id_map.end()) {
+      ClientTreeNode* reused_child = client_child_id_map[child_id];
       client_node->children.push_back(reused_child);
       const bool ignored_state_changed =
           reused_child->ignored !=
diff --git a/ui/accessibility/null_ax_action_target.cc b/ui/accessibility/null_ax_action_target.cc
new file mode 100644
index 0000000..7612803
--- /dev/null
+++ b/ui/accessibility/null_ax_action_target.cc
@@ -0,0 +1,93 @@
+// 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 "ui/accessibility/null_ax_action_target.h"
+
+namespace ui {
+
+AXActionTarget::Type NullAXActionTarget::GetType() const {
+  return AXActionTarget::Type::kNull;
+}
+
+bool NullAXActionTarget::ClearAccessibilityFocus() const {
+  return false;
+}
+
+bool NullAXActionTarget::Click() const {
+  return false;
+}
+
+bool NullAXActionTarget::Decrement() const {
+  return false;
+}
+
+bool NullAXActionTarget::Increment() const {
+  return false;
+}
+
+bool NullAXActionTarget::Focus() const {
+  return false;
+}
+
+gfx::Rect NullAXActionTarget::GetRelativeBounds() const {
+  return gfx::Rect();
+}
+
+gfx::Point NullAXActionTarget::GetScrollOffset() const {
+  return gfx::Point();
+}
+
+gfx::Point NullAXActionTarget::MinimumScrollOffset() const {
+  return gfx::Point();
+}
+
+gfx::Point NullAXActionTarget::MaximumScrollOffset() const {
+  return gfx::Point();
+}
+
+bool NullAXActionTarget::SetAccessibilityFocus() const {
+  return false;
+}
+
+void NullAXActionTarget::SetScrollOffset(const gfx::Point& point) const {}
+
+bool NullAXActionTarget::SetSelected(bool selected) const {
+  return false;
+}
+
+bool NullAXActionTarget::SetSelection(const AXActionTarget* anchor_object,
+                                      int anchor_offset,
+                                      const AXActionTarget* focus_object,
+                                      int focus_offset) const {
+  return false;
+}
+
+bool NullAXActionTarget::SetSequentialFocusNavigationStartingPoint() const {
+  return false;
+}
+
+bool NullAXActionTarget::SetValue(const std::string& value) const {
+  return false;
+}
+
+bool NullAXActionTarget::ShowContextMenu() const {
+  return false;
+}
+
+bool NullAXActionTarget::ScrollToMakeVisible() const {
+  return false;
+}
+
+bool NullAXActionTarget::ScrollToMakeVisibleWithSubFocus(
+    const gfx::Rect& rect,
+    ax::mojom::ScrollAlignment horizontal_scroll_alignment,
+    ax::mojom::ScrollAlignment vertical_scroll_alignment) const {
+  return false;
+}
+
+bool NullAXActionTarget::ScrollToGlobalPoint(const gfx::Point& point) const {
+  return false;
+}
+
+}  // namespace ui
diff --git a/ui/accessibility/null_ax_action_target.h b/ui/accessibility/null_ax_action_target.h
new file mode 100644
index 0000000..6f5f987
--- /dev/null
+++ b/ui/accessibility/null_ax_action_target.h
@@ -0,0 +1,51 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_ACCESSIBILITY_NULL_AX_ACTION_TARGET_H_
+#define UI_ACCESSIBILITY_NULL_AX_ACTION_TARGET_H_
+
+#include "ui/accessibility/ax_action_target.h"
+#include "ui/accessibility/ax_export.h"
+
+namespace ui {
+
+// A do-nothing action target.
+class AX_EXPORT NullAXActionTarget : public AXActionTarget {
+ public:
+  NullAXActionTarget() = default;
+  ~NullAXActionTarget() override = default;
+
+ protected:
+  // AXActionTarget overrides.
+  Type GetType() const override;
+  bool ClearAccessibilityFocus() const override;
+  bool Click() const override;
+  bool Decrement() const override;
+  bool Increment() const override;
+  bool Focus() const override;
+  gfx::Rect GetRelativeBounds() const override;
+  gfx::Point GetScrollOffset() const override;
+  gfx::Point MinimumScrollOffset() const override;
+  gfx::Point MaximumScrollOffset() const override;
+  bool SetAccessibilityFocus() const override;
+  void SetScrollOffset(const gfx::Point& point) const override;
+  bool SetSelected(bool selected) const override;
+  bool SetSelection(const AXActionTarget* anchor_object,
+                    int anchor_offset,
+                    const AXActionTarget* focus_object,
+                    int focus_offset) const override;
+  bool SetSequentialFocusNavigationStartingPoint() const override;
+  bool SetValue(const std::string& value) const override;
+  bool ShowContextMenu() const override;
+  bool ScrollToMakeVisible() const override;
+  bool ScrollToMakeVisibleWithSubFocus(
+      const gfx::Rect& rect,
+      ax::mojom::ScrollAlignment horizontal_scroll_alignment,
+      ax::mojom::ScrollAlignment vertical_scroll_alignment) const override;
+  bool ScrollToGlobalPoint(const gfx::Point& point) const override;
+};
+
+}  // namespace ui
+
+#endif  // UI_ACCESSIBILITY_NULL_AX_ACTION_TARGET_H_
diff --git a/ui/accessibility/null_ax_action_target_unittest.cc b/ui/accessibility/null_ax_action_target_unittest.cc
new file mode 100644
index 0000000..bd037c8
--- /dev/null
+++ b/ui/accessibility/null_ax_action_target_unittest.cc
@@ -0,0 +1,37 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/accessibility/null_ax_action_target.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ui {
+
+TEST(NullAXActionTargetTest, TestMethods) {
+  std::unique_ptr<AXActionTarget> action_target =
+      std::make_unique<NullAXActionTarget>();
+
+  EXPECT_EQ(AXActionTarget::Type::kNull, action_target->GetType());
+  EXPECT_FALSE(action_target->ClearAccessibilityFocus());
+  EXPECT_FALSE(action_target->Click());
+  EXPECT_FALSE(action_target->Decrement());
+  EXPECT_FALSE(action_target->Increment());
+  EXPECT_FALSE(action_target->Focus());
+  EXPECT_EQ(gfx::Rect(), action_target->GetRelativeBounds());
+  EXPECT_EQ(gfx::Point(), action_target->GetScrollOffset());
+  EXPECT_EQ(gfx::Point(), action_target->MinimumScrollOffset());
+  EXPECT_EQ(gfx::Point(), action_target->MaximumScrollOffset());
+  EXPECT_FALSE(action_target->SetAccessibilityFocus());
+  EXPECT_FALSE(action_target->SetSelected(false));
+  EXPECT_FALSE(action_target->SetSelection(nullptr, 0, nullptr, 0));
+  EXPECT_FALSE(action_target->SetSequentialFocusNavigationStartingPoint());
+  EXPECT_FALSE(action_target->SetValue(""));
+  EXPECT_FALSE(action_target->ShowContextMenu());
+  EXPECT_FALSE(action_target->ScrollToMakeVisible());
+  EXPECT_FALSE(action_target->ScrollToMakeVisibleWithSubFocus(
+      gfx::Rect(), ax::mojom::ScrollAlignment::kScrollAlignmentCenter,
+      ax::mojom::ScrollAlignment::kScrollAlignmentCenter));
+  EXPECT_FALSE(action_target->ScrollToGlobalPoint(gfx::Point()));
+}
+
+}  // namespace ui
diff --git a/ui/aura/client/drag_drop_client.h b/ui/aura/client/drag_drop_client.h
index 8de8940..3d08256 100644
--- a/ui/aura/client/drag_drop_client.h
+++ b/ui/aura/client/drag_drop_client.h
@@ -5,6 +5,8 @@
 #ifndef UI_AURA_CLIENT_DRAG_DROP_CLIENT_H_
 #define UI_AURA_CLIENT_DRAG_DROP_CLIENT_H_
 
+#include <memory>
+
 #include "ui/aura/aura_export.h"
 #include "ui/base/dragdrop/drag_drop_types.h"
 #include "ui/gfx/native_widget_types.h"
diff --git a/ui/aura/client/drag_drop_delegate.h b/ui/aura/client/drag_drop_delegate.h
index 304b1a6..82a2dc6 100644
--- a/ui/aura/client/drag_drop_delegate.h
+++ b/ui/aura/client/drag_drop_delegate.h
@@ -5,6 +5,8 @@
 #ifndef UI_AURA_CLIENT_DRAG_DROP_DELEGATE_H_
 #define UI_AURA_CLIENT_DRAG_DROP_DELEGATE_H_
 
+#include <memory>
+
 #include "ui/aura/aura_export.h"
 #include "ui/aura/window.h"
 #include "ui/base/dragdrop/os_exchange_data.h"
diff --git a/ui/base/clipboard/clipboard.cc b/ui/base/clipboard/clipboard.cc
index e043f0f..289580d6 100644
--- a/ui/base/clipboard/clipboard.cc
+++ b/ui/base/clipboard/clipboard.cc
@@ -128,7 +128,7 @@
         WriteHTML(&(params[0].front()), params[0].size(),
                   &(params[1].front()), params[1].size());
       } else if (params.size() == 1) {
-        WriteHTML(&(params[0].front()), params[0].size(), NULL, 0);
+        WriteHTML(&(params[0].front()), params[0].size(), nullptr, 0);
       }
       break;
 
diff --git a/ui/base/clipboard/clipboard_aura.cc b/ui/base/clipboard/clipboard_aura.cc
index fef0e33..055c489b 100644
--- a/ui/base/clipboard/clipboard_aura.cc
+++ b/ui/base/clipboard/clipboard_aura.cc
@@ -176,11 +176,11 @@
     return sequence_number_;
   }
 
-  // Returns the data currently on the top of the clipboard stack, NULL if the
-  // clipboard stack is empty.
+  // Returns the data currently on the top of the clipboard stack, nullptr if
+  // the clipboard stack is empty.
   const ClipboardData* GetData() const {
     if (data_list_.empty())
-      return NULL;
+      return nullptr;
     return data_list_.front().get();
   }
 
diff --git a/ui/base/clipboard/clipboard_aurax11.cc b/ui/base/clipboard/clipboard_aurax11.cc
index 6d4a46c..55bc8738 100644
--- a/ui/base/clipboard/clipboard_aurax11.cc
+++ b/ui/base/clipboard/clipboard_aurax11.cc
@@ -274,7 +274,7 @@
                               InputOnly,
                               CopyFromParent,  // visual
                               0,
-                              NULL)),
+                              nullptr)),
       selection_requestor_(x_display_, x_window_, this),
       clipboard_owner_(x_display_, x_window_, gfx::GetAtom(kClipboard)),
       primary_owner_(x_display_, x_window_, XA_PRIMARY) {
@@ -396,7 +396,7 @@
       for (const auto& text_atom : types) {
         ::Atom type = x11::None;
         if (selection_requestor_.PerformBlockingConvertSelection(
-                selection_name, text_atom, NULL, NULL, &type) &&
+                selection_name, text_atom, nullptr, nullptr, &type) &&
             type == text_atom) {
           out.push_back(text_atom);
         }
diff --git a/ui/base/clipboard/clipboard_mac.mm b/ui/base/clipboard/clipboard_mac.mm
index dffa16e8..e03003e0e 100644
--- a/ui/base/clipboard/clipboard_mac.mm
+++ b/ui/base/clipboard/clipboard_mac.mm
@@ -345,7 +345,8 @@
   NSPasteboard* pb = GetPasteboard();
   [pb addTypes:@[ NSTIFFPboardType ] owner:nil];
   NSData* tiff_data = [image TIFFRepresentation];
-  LOG_IF(ERROR, tiff_data == NULL) << "Failed to allocate image for clipboard";
+  LOG_IF(ERROR, tiff_data == nullptr)
+      << "Failed to allocate image for clipboard";
   if (tiff_data) {
     [pb setData:tiff_data forType:NSTIFFPboardType];
   }
diff --git a/ui/base/clipboard/clipboard_test_template.h b/ui/base/clipboard/clipboard_test_template.h
index 1e7047c..700839dc 100644
--- a/ui/base/clipboard/clipboard_test_template.h
+++ b/ui/base/clipboard/clipboard_test_template.h
@@ -645,7 +645,7 @@
 void HtmlTestHelper(const std::string& cf_html,
                     const std::string& expected_html) {
   std::string html;
-  ClipboardUtil::CFHtmlToHtml(cf_html, &html, NULL);
+  ClipboardUtil::CFHtmlToHtml(cf_html, &html, nullptr);
   EXPECT_EQ(html, expected_html);
 }
 
diff --git a/ui/base/clipboard/clipboard_util_win.cc b/ui/base/clipboard/clipboard_util_win.cc
index 77c4bb45..5563b655 100644
--- a/ui/base/clipboard/clipboard_util_win.cc
+++ b/ui/base/clipboard/clipboard_util_win.cc
@@ -855,8 +855,8 @@
   size_t fragment_start = std::string::npos;
   size_t fragment_end = std::string::npos;
 
-  ClipboardUtil::CFHtmlExtractMetadata(
-      cf_html, base_url, NULL, &fragment_start, &fragment_end);
+  ClipboardUtil::CFHtmlExtractMetadata(cf_html, base_url, nullptr,
+                                       &fragment_start, &fragment_end);
 
   if (html &&
       fragment_start != std::string::npos &&
diff --git a/ui/base/clipboard/clipboard_win.cc b/ui/base/clipboard/clipboard_win.cc
index b37e7c2e..82bdc4e 100644
--- a/ui/base/clipboard/clipboard_win.cc
+++ b/ui/base/clipboard/clipboard_win.cc
@@ -453,7 +453,7 @@
                           false, 0, &dst_bits);
 
   {
-    base::win::ScopedCreateDC hdc(CreateCompatibleDC(NULL));
+    base::win::ScopedCreateDC hdc(CreateCompatibleDC(nullptr));
     HBITMAP old_hbitmap =
         static_cast<HBITMAP>(SelectObject(hdc.Get(), dst_hbitmap));
     ::SetDIBitsToDevice(hdc.Get(), 0, 0, bitmap->bmiHeader.biWidth,
@@ -565,9 +565,8 @@
 
   ::EmptyClipboard();
 
-  for (ObjectMap::const_iterator iter = objects.begin(); iter != objects.end();
-       ++iter) {
-    DispatchObject(static_cast<ObjectType>(iter->first), iter->second);
+  for (const auto& object : objects) {
+    DispatchObject(static_cast<ObjectType>(object.first), object.second);
   }
 }
 
@@ -616,14 +615,14 @@
 }
 
 void ClipboardWin::WriteWebSmartPaste() {
-  DCHECK(clipboard_owner_->hwnd() != NULL);
+  DCHECK(clipboard_owner_->hwnd() != nullptr);
   ::SetClipboardData(
       ClipboardFormatType::GetWebKitSmartPasteType().ToFormatEtc().cfFormat,
-      NULL);
+      nullptr);
 }
 
 void ClipboardWin::WriteBitmap(const SkBitmap& in_bitmap) {
-  HDC dc = ::GetDC(NULL);
+  HDC dc = ::GetDC(nullptr);
 
   SkBitmap bitmap;
   // Either points bitmap at in_bitmap, or allocates and converts pixels.
@@ -651,7 +650,7 @@
   // https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createdibsection)
   void* bits;
   HBITMAP source_hbitmap =
-      ::CreateDIBSection(dc, &bm_info, DIB_RGB_COLORS, &bits, NULL, 0);
+      ::CreateDIBSection(dc, &bm_info, DIB_RGB_COLORS, &bits, nullptr, 0);
 
   if (bits && source_hbitmap) {
     // Copy the bitmap out of shared memory and into GDI
@@ -663,7 +662,7 @@
   }
 
   ::DeleteObject(source_hbitmap);
-  ::ReleaseDC(NULL, dc);
+  ::ReleaseDC(nullptr, dc);
 }
 
 void ClipboardWin::WriteData(const ClipboardFormatType& format,
@@ -686,9 +685,9 @@
   // For this reason, we create a new bitmap, copy the bits over, and then
   // write that to the clipboard.
 
-  HDC dc = ::GetDC(NULL);
-  HDC compatible_dc = ::CreateCompatibleDC(NULL);
-  HDC source_dc = ::CreateCompatibleDC(NULL);
+  HDC dc = ::GetDC(nullptr);
+  HDC compatible_dc = ::CreateCompatibleDC(nullptr);
+  HDC source_dc = ::CreateCompatibleDC(nullptr);
 
   // This is the HBITMAP we will eventually write to the clipboard
   HBITMAP hbitmap = ::CreateCompatibleBitmap(dc, size.width(), size.height());
@@ -696,7 +695,7 @@
     // Failed to create the bitmap
     ::DeleteDC(compatible_dc);
     ::DeleteDC(source_dc);
-    ::ReleaseDC(NULL, dc);
+    ::ReleaseDC(nullptr, dc);
     return;
   }
 
@@ -724,13 +723,13 @@
   ::DeleteObject(old_source);
   ::DeleteDC(compatible_dc);
   ::DeleteDC(source_dc);
-  ::ReleaseDC(NULL, dc);
+  ::ReleaseDC(nullptr, dc);
 
   WriteToClipboard(CF_BITMAP, hbitmap);
 }
 
 void ClipboardWin::WriteToClipboard(unsigned int format, HANDLE handle) {
-  DCHECK(clipboard_owner_->hwnd() != NULL);
+  DCHECK(clipboard_owner_->hwnd() != nullptr);
   if (handle && !::SetClipboardData(format, handle)) {
     DCHECK(ERROR_CLIPBOARD_NOT_OPEN != GetLastError());
     FreeData(format, handle);
@@ -739,9 +738,9 @@
 
 HWND ClipboardWin::GetClipboardWindow() const {
   if (!clipboard_owner_)
-    return NULL;
+    return nullptr;
 
-  if (clipboard_owner_->hwnd() == NULL)
+  if (clipboard_owner_->hwnd() == nullptr)
     clipboard_owner_->Create(base::Bind(&ClipboardOwnerWndProc));
 
   return clipboard_owner_->hwnd();
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager.css b/ui/file_manager/file_manager/foreground/css/file_manager.css
index a4cb0d2..4d80fe6f 100644
--- a/ui/file_manager/file_manager/foreground/css/file_manager.css
+++ b/ui/file_manager/file_manager/foreground/css/file_manager.css
@@ -173,7 +173,7 @@
 .ejectable > span.label {
   left: 48px;
   position: absolute;
-  width: calc(100% - 48px - 40px);
+  width: calc(100% - 48px - 40px - 3px);
 }
 
 #directory-tree .tree-row .rename-placeholder {
@@ -228,7 +228,7 @@
   flex: none;
   height: 40px;
   position: absolute;
-  right: 0;
+  right: 3px;
   width: 40px;
   z-index: 1;  /* Make sure the icon is on upper layer than paper-ripple. */
 }
diff --git a/ui/gl/BUILD.gn b/ui/gl/BUILD.gn
index b1855bfe..fd72f31 100644
--- a/ui/gl/BUILD.gn
+++ b/ui/gl/BUILD.gn
@@ -307,6 +307,7 @@
       "gl_wgl_api_implementation.h",
       "swap_chain_presenter.cc",
       "swap_chain_presenter.h",
+      "vsync_observer.h",
       "vsync_provider_win.cc",
       "vsync_provider_win.h",
       "vsync_thread_win.cc",
diff --git a/ui/gl/direct_composition_child_surface_win.cc b/ui/gl/direct_composition_child_surface_win.cc
index 15cfd1fa..06721e59 100644
--- a/ui/gl/direct_composition_child_surface_win.cc
+++ b/ui/gl/direct_composition_child_surface_win.cc
@@ -107,7 +107,9 @@
   return base::FeatureList::IsEnabled(features::kSwapChainFrameStatistics);
 }
 
-DirectCompositionChildSurfaceWin::DirectCompositionChildSurfaceWin() {}
+DirectCompositionChildSurfaceWin::DirectCompositionChildSurfaceWin(
+    gfx::VSyncProvider* vsync_provider)
+    : vsync_provider_(vsync_provider) {}
 
 DirectCompositionChildSurfaceWin::~DirectCompositionChildSurfaceWin() {
   Destroy();
@@ -258,6 +260,8 @@
   bool succeeded = ReleaseDrawTexture(false /* will_discard */);
 
   if (UseSwapChainFrameStatistics()) {
+    vsync_provider_->GetVSyncParametersIfAvailable(&last_vsync_time_,
+                                                   &last_vsync_interval_);
     CheckPendingFrames();
     // Enqueue callback after retiring previous callbacks so that it's called
     // after SwapBuffers() returns.
@@ -503,17 +507,6 @@
   return true;
 }
 
-void DirectCompositionChildSurfaceWin::UpdateVSyncParameters(
-    base::TimeTicks vsync_time,
-    base::TimeDelta vsync_interval) {
-  last_vsync_time_ = vsync_time;
-  last_vsync_interval_ = vsync_interval;
-}
-
-bool DirectCompositionChildSurfaceWin::HasPendingFrames() const {
-  return !pending_frames_.empty();
-}
-
 void DirectCompositionChildSurfaceWin::CheckPendingFrames() {
   DCHECK(UseSwapChainFrameStatistics());
 
diff --git a/ui/gl/direct_composition_child_surface_win.h b/ui/gl/direct_composition_child_surface_win.h
index 34a847f..3f84f9fa02 100644
--- a/ui/gl/direct_composition_child_surface_win.h
+++ b/ui/gl/direct_composition_child_surface_win.h
@@ -12,11 +12,15 @@
 
 #include "ui/gl/gl_surface_egl.h"
 
+namespace gfx {
+class VSyncProvider;
+}  // namespace gfx
+
 namespace gl {
 
 class DirectCompositionChildSurfaceWin : public GLSurfaceEGL {
  public:
-  DirectCompositionChildSurfaceWin();
+  explicit DirectCompositionChildSurfaceWin(gfx::VSyncProvider* vsync_provider);
 
   static bool UseSwapChainFrameStatistics();
 
@@ -40,11 +44,6 @@
               bool has_alpha) override;
   bool SetEnableDCLayers(bool enable) override;
 
-  void UpdateVSyncParameters(base::TimeTicks vsync_time,
-                             base::TimeDelta vsync_interval);
-  bool HasPendingFrames() const;
-  void CheckPendingFrames();
-
   const Microsoft::WRL::ComPtr<IDCompositionSurface>& dcomp_surface() const {
     return dcomp_surface_;
   }
@@ -76,6 +75,7 @@
     // Presentation callback enqueued in SwapBuffers().
     PresentationCallback callback;
   };
+  void CheckPendingFrames();
   void EnqueuePendingFrame(PresentationCallback callback);
   void ClearPendingFrames();
 
@@ -109,6 +109,7 @@
   // be called on the device.
   uint64_t dcomp_surface_serial_ = 0;
 
+  gfx::VSyncProvider* const vsync_provider_;
   base::TimeTicks last_vsync_time_;
   base::TimeDelta last_vsync_interval_ = base::TimeDelta::FromSecondsD(1. / 60);
 
diff --git a/ui/gl/direct_composition_surface_win.cc b/ui/gl/direct_composition_surface_win.cc
index 0522acc8..22587ec 100644
--- a/ui/gl/direct_composition_surface_win.cc
+++ b/ui/gl/direct_composition_surface_win.cc
@@ -172,15 +172,14 @@
     : GLSurfaceEGL(),
       child_window_(parent_window),
       task_runner_(base::ThreadTaskRunnerHandle::Get()),
-      root_surface_(new DirectCompositionChildSurfaceWin()),
+      root_surface_(new DirectCompositionChildSurfaceWin(vsync_provider.get())),
       layer_tree_(std::make_unique<DCLayerTree>(
           settings.disable_nv12_dynamic_textures,
           settings.disable_larger_than_screen_overlays)),
-      vsync_provider_(std::move(vsync_provider)),
-      vsync_callback_(std::move(vsync_callback)),
       presentation_helper_(
-          std::make_unique<GLSurfacePresentationHelper>(vsync_provider_.get())),
-      weak_ptr_factory_(this) {}
+          std::make_unique<GLSurfacePresentationHelper>(vsync_provider.get())),
+      vsync_provider_(std::move(vsync_provider)),
+      vsync_callback_(std::move(vsync_callback)) {}
 
 DirectCompositionSurfaceWin::~DirectCompositionSurfaceWin() {
   Destroy();
@@ -396,27 +395,17 @@
   if (!root_surface_->Initialize(GLSurfaceFormat()))
     return false;
 
-  if (root_surface_->UseSwapChainFrameStatistics()) {
-    // Save weak ptr on main thread before any use on vsync thread.
-    main_thread_vsync_callback_ = base::BindRepeating(
-        &DirectCompositionSurfaceWin::HandleVSyncOnMainThread,
-        weak_ptr_factory_.GetWeakPtr());
-  }
-
-  if ((SupportsGpuVSync() && vsync_callback_) || main_thread_vsync_callback_) {
-    vsync_thread_ = std::make_unique<VSyncThreadWin>(
-        window_, d3d11_device_,
-        base::BindRepeating(
-            &DirectCompositionSurfaceWin::HandleVSyncOnVSyncThread,
-            base::Unretained(this)));
-  }
+  if (SupportsGpuVSync() && vsync_callback_)
+    vsync_thread_ = VSyncThreadWin::GetInstance();
 
   return true;
 }
 
 void DirectCompositionSurfaceWin::Destroy() {
-  // Destroy vsync thread because joining it could issue callbacks.
-  vsync_thread_ = nullptr;
+  if (vsync_thread_) {
+    vsync_thread_->RemoveObserver(this);
+    vsync_thread_ = nullptr;
+  }
   // Destroy presentation helper first because its dtor calls GetHandle.
   presentation_helper_ = nullptr;
   root_surface_->Destroy();
@@ -459,14 +448,11 @@
     callback.Reset();
   }
 
-  gfx::SwapResult swap_result = root_surface_->SwapBuffers(std::move(callback));
-
-  if (swap_result == gfx::SwapResult::SWAP_ACK &&
+  gfx::SwapResult swap_result;
+  if (root_surface_->SwapBuffers(std::move(callback)) ==
+          gfx::SwapResult::SWAP_ACK &&
       layer_tree_->CommitAndClearPendingOverlays(root_surface_.get())) {
-    if (vsync_thread_) {
-      vsync_thread_->SetEnabled(root_surface_->HasPendingFrames() ||
-                                vsync_callback_enabled_);
-    }
+    swap_result = gfx::SwapResult::SWAP_ACK;
   } else {
     swap_result = gfx::SwapResult::SWAP_FAILED;
   }
@@ -547,34 +533,17 @@
 
 void DirectCompositionSurfaceWin::SetGpuVSyncEnabled(bool enabled) {
   DCHECK(vsync_thread_);
-  if (vsync_callback_enabled_ == enabled)
-    return;
-  vsync_callback_enabled_ = enabled;
-  vsync_thread_->SetEnabled(root_surface_->HasPendingFrames() ||
-                            vsync_callback_enabled_);
-}
-
-void DirectCompositionSurfaceWin::HandleVSyncOnVSyncThread(
-    base::TimeTicks vsync_time,
-    base::TimeDelta vsync_interval) {
-  if (vsync_callback_)
-    vsync_callback_.Run(vsync_time, vsync_interval);
-
-  if (main_thread_vsync_callback_) {
-    task_runner_->PostTask(
-        FROM_HERE, base::BindOnce(main_thread_vsync_callback_, vsync_time,
-                                  vsync_interval));
+  if (enabled) {
+    vsync_thread_->AddObserver(this);
+  } else {
+    vsync_thread_->RemoveObserver(this);
   }
 }
 
-void DirectCompositionSurfaceWin::HandleVSyncOnMainThread(
-    base::TimeTicks vsync_time,
-    base::TimeDelta vsync_interval) {
-  // Check pending frames in root surface in case client stops issuing swaps.
-  root_surface_->UpdateVSyncParameters(vsync_time, vsync_interval);
-  root_surface_->CheckPendingFrames();
-  vsync_thread_->SetEnabled(root_surface_->HasPendingFrames() ||
-                            vsync_callback_enabled_);
+void DirectCompositionSurfaceWin::OnVSync(base::TimeTicks vsync_time,
+                                          base::TimeDelta interval) {
+  DCHECK(vsync_callback_);
+  vsync_callback_.Run(vsync_time, interval);
 }
 
 scoped_refptr<base::TaskRunner>
diff --git a/ui/gl/direct_composition_surface_win.h b/ui/gl/direct_composition_surface_win.h
index 1c65a78..62c07e1 100644
--- a/ui/gl/direct_composition_surface_win.h
+++ b/ui/gl/direct_composition_surface_win.h
@@ -16,6 +16,7 @@
 #include "ui/gl/child_window_win.h"
 #include "ui/gl/gl_export.h"
 #include "ui/gl/gl_surface_egl.h"
+#include "ui/gl/vsync_observer.h"
 
 namespace gl {
 class DCLayerTree;
@@ -23,7 +24,8 @@
 class GLSurfacePresentationHelper;
 class VSyncThreadWin;
 
-class GL_EXPORT DirectCompositionSurfaceWin : public GLSurfaceEGL {
+class GL_EXPORT DirectCompositionSurfaceWin : public GLSurfaceEGL,
+                                              public VSyncObserver {
  public:
   using VSyncCallback =
       base::RepeatingCallback<void(base::TimeTicks, base::TimeDelta)>;
@@ -105,7 +107,6 @@
   gfx::Vector2d GetDrawOffset() const override;
   bool SupportsGpuVSync() const override;
   void SetGpuVSyncEnabled(bool enabled) override;
-
   // This schedules an overlay plane to be displayed on the next SwapBuffers
   // or PostSubBuffer call. Overlay planes must be scheduled before every swap
   // to remain in the layer tree. This surface's backbuffer doesn't have to be
@@ -113,6 +114,9 @@
   // tree at z-order 0.
   bool ScheduleDCLayer(const ui::DCRendererLayerParams& params) override;
 
+  // VSyncObserver implementation.
+  void OnVSync(base::TimeTicks vsync_time, base::TimeDelta interval) override;
+
   HWND window() const { return window_; }
 
   scoped_refptr<base::TaskRunner> GetWindowTaskRunnerForTesting();
@@ -127,33 +131,21 @@
   ~DirectCompositionSurfaceWin() override;
 
  private:
-  void HandleVSyncOnVSyncThread(base::TimeTicks vsync_time,
-                                base::TimeDelta vsync_interval);
-
-  void HandleVSyncOnMainThread(base::TimeTicks vsync_time,
-                               base::TimeDelta vsync_interval);
-
   HWND window_ = nullptr;
   ChildWindowWin child_window_;
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
 
   scoped_refptr<DirectCompositionChildSurfaceWin> root_surface_;
   std::unique_ptr<DCLayerTree> layer_tree_;
-
-  std::unique_ptr<VSyncThreadWin> vsync_thread_;
-  std::unique_ptr<gfx::VSyncProvider> vsync_provider_;
-
-  const VSyncCallback vsync_callback_;
-  bool vsync_callback_enabled_ = false;
-
   std::unique_ptr<GLSurfacePresentationHelper> presentation_helper_;
 
+  std::unique_ptr<gfx::VSyncProvider> vsync_provider_;
+  const VSyncCallback vsync_callback_;
+  VSyncThreadWin* vsync_thread_;
+
   Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device_;
   Microsoft::WRL::ComPtr<IDCompositionDevice2> dcomp_device_;
 
-  VSyncCallback main_thread_vsync_callback_;
-  base::WeakPtrFactory<DirectCompositionSurfaceWin> weak_ptr_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(DirectCompositionSurfaceWin);
 };
 
diff --git a/ui/gl/vsync_observer.h b/ui/gl/vsync_observer.h
new file mode 100644
index 0000000..5d0fe964
--- /dev/null
+++ b/ui/gl/vsync_observer.h
@@ -0,0 +1,20 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GL_VSYNC_OBSERVER_H_
+#define UI_GL_VSYNC_OBSERVER_H_
+
+namespace gl {
+class GL_EXPORT VSyncObserver {
+ public:
+  // Called on vsync thread.
+  virtual void OnVSync(base::TimeTicks vsync_time,
+                       base::TimeDelta interval) = 0;
+
+ protected:
+  virtual ~VSyncObserver() {}
+};
+}  // namespace gl
+
+#endif  // UI_GL_VSYNC_OBSERVER_H_
diff --git a/ui/gl/vsync_thread_win.cc b/ui/gl/vsync_thread_win.cc
index a9e341573..9502606 100644
--- a/ui/gl/vsync_thread_win.cc
+++ b/ui/gl/vsync_thread_win.cc
@@ -5,6 +5,10 @@
 #include "ui/gl/vsync_thread_win.h"
 
 #include "base/bind.h"
+#include "base/memory/singleton.h"
+#include "base/stl_util.h"
+#include "ui/gl/gl_angle_util_win.h"
+#include "ui/gl/vsync_observer.h"
 
 namespace gl {
 namespace {
@@ -43,45 +47,51 @@
 }
 }  // namespace
 
-VSyncThreadWin::VSyncThreadWin(
-    HWND window,
-    Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device,
-    VSyncCallback callback)
+// static
+VSyncThreadWin* VSyncThreadWin::GetInstance() {
+  return base::Singleton<VSyncThreadWin>::get();
+}
+
+VSyncThreadWin::VSyncThreadWin()
     : vsync_thread_("GpuVSyncThread"),
-      window_(window),
-      d3d11_device_(std::move(d3d11_device)),
-      callback_(std::move(callback)) {
-  DCHECK(window_);
-  DCHECK(callback_);
+      d3d11_device_(QueryD3D11DeviceObjectFromANGLE()) {
+  DCHECK(d3d11_device_);
   base::Thread::Options options;
-  // Inherit priority from GPU main thread which depends on finch flags.
-  options.priority = base::PlatformThread::GetCurrentThreadPriority();
+  options.priority = base::ThreadPriority::DISPLAY;
   vsync_thread_.StartWithOptions(std::move(options));
 }
 
 VSyncThreadWin::~VSyncThreadWin() {
-  SetEnabled(false);
+  {
+    base::AutoLock auto_lock(lock_);
+    observers_.clear();
+  }
   vsync_thread_.Stop();
 }
 
-void VSyncThreadWin::SetEnabled(bool enabled) {
+void VSyncThreadWin::AddObserver(VSyncObserver* obs) {
   base::AutoLock auto_lock(lock_);
-  if (enabled_ == enabled)
-    return;
-  enabled_ = enabled;
-  if (enabled_ && !started_) {
-    started_ = true;
+  observers_.insert(obs);
+  if (is_idle_) {
+    is_idle_ = false;
     vsync_thread_.task_runner()->PostTask(
         FROM_HERE,
         base::BindOnce(&VSyncThreadWin::WaitForVSync, base::Unretained(this)));
   }
 }
 
+void VSyncThreadWin::RemoveObserver(VSyncObserver* obs) {
+  base::AutoLock auto_lock(lock_);
+  observers_.erase(obs);
+}
+
 void VSyncThreadWin::WaitForVSync() {
-  HMONITOR monitor = MonitorFromWindow(window_, MONITOR_DEFAULTTONEAREST);
-  if (window_monitor_ != monitor) {
-    window_monitor_ = monitor;
-    window_output_ = DXGIOutputFromMonitor(monitor, d3d11_device_);
+  // From Raymond Chen's blog "How do I get a handle to the primary monitor?"
+  // https://devblogs.microsoft.com/oldnewthing/20141106-00/?p=43683
+  HMONITOR monitor = MonitorFromWindow(nullptr, MONITOR_DEFAULTTOPRIMARY);
+  if (primary_monitor_ != monitor) {
+    primary_monitor_ = monitor;
+    primary_output_ = DXGIOutputFromMonitor(monitor, d3d11_device_);
   }
 
   base::TimeDelta interval = base::TimeDelta::FromSecondsD(1.0 / 60);
@@ -102,13 +112,13 @@
 
   base::TimeTicks wait_for_vblank_start_time = base::TimeTicks::Now();
   bool wait_for_vblank_succeeded =
-      window_output_ && SUCCEEDED(window_output_->WaitForVBlank());
+      primary_output_ && SUCCEEDED(primary_output_->WaitForVBlank());
 
   // WaitForVBlank returns very early instead of waiting until vblank when the
   // monitor goes to sleep.  We use 1ms as a threshold for the duration of
   // WaitForVBlank and fallback to Sleep() if it returns before that.  This
   // could happen during normal operation for the first call after the vsync
-  // callback is enabled, but it shouldn't happen often.
+  // thread becomes non-idle, but it shouldn't happen often.
   const auto kVBlankIntervalThreshold = base::TimeDelta::FromMilliseconds(1);
   base::TimeDelta wait_for_vblank_elapsed_time =
       base::TimeTicks::Now() - wait_for_vblank_start_time;
@@ -119,17 +129,15 @@
   }
 
   base::AutoLock auto_lock(lock_);
-  DCHECK(started_);
-  if (enabled_) {
+  if (!observers_.empty()) {
     vsync_thread_.task_runner()->PostTask(
         FROM_HERE,
         base::BindOnce(&VSyncThreadWin::WaitForVSync, base::Unretained(this)));
-    // Release lock before running callback to guard against any reentracny
-    // deadlock.
-    base::AutoUnlock auto_unlock(lock_);
-    callback_.Run(base::TimeTicks::Now(), interval);
+    base::TimeTicks vsync_time = base::TimeTicks::Now();
+    for (auto* obs : observers_)
+      obs->OnVSync(vsync_time, interval);
   } else {
-    started_ = false;
+    is_idle_ = true;
   }
 }
 
diff --git a/ui/gl/vsync_thread_win.h b/ui/gl/vsync_thread_win.h
index f540f75..d148353 100644
--- a/ui/gl/vsync_thread_win.h
+++ b/ui/gl/vsync_thread_win.h
@@ -9,48 +9,53 @@
 #include <windows.h>
 #include <wrl/client.h>
 
+#include "base/containers/flat_set.h"
 #include "base/threading/thread.h"
 #include "ui/gl/gl_export.h"
 
-namespace gl {
+namespace base {
+template <typename T>
+struct DefaultSingletonTraits;
+}  // namespace base
 
-// Helper class that manages a thread for calling IDXGIOutput::WaitForVBlank()
-// for the output corresponding to the given |window|, and runs |callback| on
-// the same thread.  The callback can be enabled or disabled via SetEnabled().
-// This is used by DirectCompositionSurfaceWin to plumb vsync signal back to the
-// display compositor's BeginFrameSource.
+namespace gl {
+class VSyncObserver;
+// Helper singleton that wraps a thread for calling IDXGIOutput::WaitForVBlank()
+// for the primary monitor, and notifies observers on the same thread. Observers
+// can be added or removed on the main thread, and the vsync thread goes to
+// sleep if there are no observers. This is used by DirectCompositionSurfaceWin
+// to plumb vsync signal back to the display compositor's BeginFrameSource.
 class GL_EXPORT VSyncThreadWin {
  public:
-  using VSyncCallback =
-      base::RepeatingCallback<void(base::TimeTicks, base::TimeDelta)>;
-  VSyncThreadWin(HWND window,
-                 Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device,
-                 VSyncCallback callback);
-  ~VSyncThreadWin();
+  static VSyncThreadWin* GetInstance();
 
-  void SetEnabled(bool enabled);
+  // These methods are not rentrancy safe, and shouldn't be called inside
+  // VSyncObserver::OnVSync.  It's safe to assume that these can be called only
+  // from the main thread.
+  void AddObserver(VSyncObserver* obs);
+  void RemoveObserver(VSyncObserver* obs);
 
  private:
+  friend struct base::DefaultSingletonTraits<VSyncThreadWin>;
+
+  VSyncThreadWin();
+  ~VSyncThreadWin();
+
   void WaitForVSync();
 
   base::Thread vsync_thread_;
 
   // Used on vsync thread only after initialization.
-  const HWND window_;
   const Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device_;
-  const VSyncCallback callback_;
-
-  // Used on vsync thread exclusively.
-  HMONITOR window_monitor_ = nullptr;
-  Microsoft::WRL::ComPtr<IDXGIOutput> window_output_;
+  HMONITOR primary_monitor_ = nullptr;
+  Microsoft::WRL::ComPtr<IDXGIOutput> primary_output_;
 
   base::Lock lock_;
-  bool GUARDED_BY(lock_) enabled_ = false;
-  bool GUARDED_BY(lock_) started_ = false;
+  bool GUARDED_BY(lock_) is_idle_ = true;
+  base::flat_set<VSyncObserver*> GUARDED_BY(lock_) observers_;
 
   DISALLOW_COPY_AND_ASSIGN(VSyncThreadWin);
 };
-
 }  // namespace gl
 
 #endif  // UI_GL_VSYNC_THREAD_WIN_H_
diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc
index 8aa0da1..354216c 100644
--- a/ui/views/controls/menu/menu_controller.cc
+++ b/ui/views/controls/menu/menu_controller.cc
@@ -982,7 +982,7 @@
     if (menu_item)
       over_empty_menu = true;
   }
-  MenuDelegate::DropPosition drop_position = MenuDelegate::DROP_NONE;
+  MenuDelegate::DropPosition drop_position = MenuDelegate::DropPosition::kNone;
   int drop_operation = ui::DragDropTypes::DRAG_NONE;
   if (menu_item) {
     gfx::Point menu_item_loc(event.location());
@@ -993,16 +993,16 @@
       if (menu_item->HasSubmenu() &&
           (menu_item_loc.y() > kDropBetweenPixels &&
            menu_item_loc.y() < (menu_item_height - kDropBetweenPixels))) {
-        drop_position = MenuDelegate::DROP_ON;
+        drop_position = MenuDelegate::DropPosition::kOn;
       } else {
         drop_position = (menu_item_loc.y() < menu_item_height / 2)
-                            ? MenuDelegate::DROP_BEFORE
-                            : MenuDelegate::DROP_AFTER;
+                            ? MenuDelegate::DropPosition::kBefore
+                            : MenuDelegate::DropPosition::kAfter;
       }
       query_menu_item = menu_item;
     } else {
       query_menu_item = menu_item->GetParentMenuItem();
-      drop_position = MenuDelegate::DROP_ON;
+      drop_position = MenuDelegate::DropPosition::kOn;
     }
     drop_operation = menu_item->GetDelegate()->GetDropOperation(
         query_menu_item, event, &drop_position);
@@ -1011,7 +1011,7 @@
     SetSelection(menu_item, menu_item->HasSubmenu() ? SELECTION_OPEN_SUBMENU
                                                     : SELECTION_DEFAULT);
 
-    if (drop_position == MenuDelegate::DROP_NONE ||
+    if (drop_position == MenuDelegate::DropPosition::kNone ||
         drop_operation == ui::DragDropTypes::DRAG_NONE)
       menu_item = nullptr;
   } else {
@@ -1027,7 +1027,7 @@
 
   if (drop_target_) {
     StopShowTimer();
-    SetDropMenuItem(nullptr, MenuDelegate::DROP_NONE);
+    SetDropMenuItem(nullptr, MenuDelegate::DropPosition::kNone);
   }
 }
 
@@ -1075,14 +1075,14 @@
   UpdateScrolling(part);
 
   // Do this to force the selection to hide.
-  SetDropMenuItem(source->GetMenuItemAt(0), MenuDelegate::DROP_NONE);
+  SetDropMenuItem(source->GetMenuItemAt(0), MenuDelegate::DropPosition::kNone);
 
   StopCancelAllTimer();
 }
 
 void MenuController::OnDragExitedScrollButton(SubmenuView* source) {
   StartCancelAllTimer();
-  SetDropMenuItem(nullptr, MenuDelegate::DROP_NONE);
+  SetDropMenuItem(nullptr, MenuDelegate::DropPosition::kNone);
   StopScrolling();
 }
 
@@ -2757,7 +2757,7 @@
 
   if (drop_target_) {
     drop_target_->GetParentMenuItem()->GetSubmenu()->SetDropMenuItem(
-        nullptr, MenuDelegate::DROP_NONE);
+        nullptr, MenuDelegate::DropPosition::kNone);
   }
   drop_target_ = new_target;
   drop_position_ = new_position;
diff --git a/ui/views/controls/menu/menu_controller.h b/ui/views/controls/menu/menu_controller.h
index 9a8de1d9..1b12cd5 100644
--- a/ui/views/controls/menu/menu_controller.h
+++ b/ui/views/controls/menu/menu_controller.h
@@ -678,7 +678,8 @@
 
   // Drop target.
   MenuItemView* drop_target_ = nullptr;
-  MenuDelegate::DropPosition drop_position_ = MenuDelegate::DROP_UNKNOWN;
+  MenuDelegate::DropPosition drop_position_ =
+      MenuDelegate::DropPosition::kUnknow;
 
   // Owner of child windows.
   // WARNING: this may be NULL.
@@ -702,7 +703,7 @@
   // continually processing whether we can drop, we cache the coordinates.
   bool valid_drop_coordinates_ = false;
   gfx::Point drop_pt_;
-  int last_drop_operation_ = MenuDelegate::DROP_UNKNOWN;
+  int last_drop_operation_ = ui::DragDropTypes::DRAG_NONE;
 
   // If true, we're in the middle of invoking ShowAt on a submenu.
   bool showing_submenu_ = false;
diff --git a/ui/views/controls/menu/menu_controller_unittest.cc b/ui/views/controls/menu/menu_controller_unittest.cc
index c458d54..ce0b8a3 100644
--- a/ui/views/controls/menu/menu_controller_unittest.cc
+++ b/ui/views/controls/menu/menu_controller_unittest.cc
@@ -1291,7 +1291,7 @@
   SubmenuView* source = menu_item()->GetSubmenu();
   MenuItemView* target = source->GetMenuItemAt(0);
 
-  SetDropMenuItem(target, MenuDelegate::DropPosition::DROP_AFTER);
+  SetDropMenuItem(target, MenuDelegate::DropPosition::kAfter);
 
   ui::OSExchangeData drop_data;
   gfx::PointF location(target->origin());
diff --git a/ui/views/controls/menu/menu_delegate.h b/ui/views/controls/menu/menu_delegate.h
index 921aef2..bdbd9c7e 100644
--- a/ui/views/controls/menu/menu_delegate.h
+++ b/ui/views/controls/menu/menu_delegate.h
@@ -45,20 +45,20 @@
  public:
   // Used during drag and drop to indicate where the drop indicator should
   // be rendered.
-  enum DropPosition {
-    DROP_UNKNOWN = -1,
+  enum class DropPosition {
+    kUnknow = -1,
 
     // Indicates a drop is not allowed here.
-    DROP_NONE,
+    kNone,
 
     // Indicates the drop should occur before the item.
-    DROP_BEFORE,
+    kBefore,
 
     // Indicates the drop should occur after the item.
-    DROP_AFTER,
+    kAfter,
 
     // Indicates the drop should occur on the item.
-    DROP_ON
+    kOn
   };
 
   // Used when indicating the style for a given label.
diff --git a/ui/views/controls/menu/submenu_view.cc b/ui/views/controls/menu/submenu_view.cc
index 0713d6e2..ecdc432e 100644
--- a/ui/views/controls/menu/submenu_view.cc
+++ b/ui/views/controls/menu/submenu_view.cc
@@ -38,7 +38,7 @@
     : parent_menu_item_(parent),
       host_(nullptr),
       drop_item_(nullptr),
-      drop_position_(MenuDelegate::DROP_NONE),
+      drop_position_(MenuDelegate::DropPosition::kNone),
       scroll_view_container_(nullptr),
       max_minor_text_width_(0),
       minimum_preferred_width_(0),
@@ -213,12 +213,12 @@
   bool paint_drop_indicator = false;
   if (drop_item_) {
     switch (drop_position_) {
-      case MenuDelegate::DROP_NONE:
-      case MenuDelegate::DROP_ON:
+      case MenuDelegate::DropPosition::kNone:
+      case MenuDelegate::DropPosition::kOn:
         break;
-      case MenuDelegate::DROP_UNKNOWN:
-      case MenuDelegate::DROP_BEFORE:
-      case MenuDelegate::DROP_AFTER:
+      case MenuDelegate::DropPosition::kUnknow:
+      case MenuDelegate::DropPosition::kBefore:
+      case MenuDelegate::DropPosition::kAfter:
         paint_drop_indicator = true;
         break;
     }
@@ -455,7 +455,8 @@
   // Something is being dropped on one of this menus items. Show the
   // selection if the drop is on the passed in item and the drop position is
   // ON.
-  return (drop_item_ == item && drop_position_ == MenuDelegate::DROP_ON);
+  return (drop_item_ == item &&
+          drop_position_ == MenuDelegate::DropPosition::kOn);
 }
 
 MenuScrollViewContainer* SubmenuView::GetScrollViewContainer() {
@@ -489,9 +490,9 @@
   if (item == nullptr)
     return;
 
-  if (position == MenuDelegate::DROP_ON) {
+  if (position == MenuDelegate::DropPosition::kOn) {
     item->SchedulePaint();
-  } else if (position != MenuDelegate::DROP_NONE) {
+  } else if (position != MenuDelegate::DropPosition::kNone) {
     SchedulePaintInRect(CalculateDropIndicatorBounds(item, position));
   }
 }
@@ -499,15 +500,15 @@
 gfx::Rect SubmenuView::CalculateDropIndicatorBounds(
     MenuItemView* item,
     MenuDelegate::DropPosition position) {
-  DCHECK(position != MenuDelegate::DROP_NONE);
+  DCHECK(position != MenuDelegate::DropPosition::kNone);
   gfx::Rect item_bounds = item->bounds();
   switch (position) {
-    case MenuDelegate::DROP_BEFORE:
+    case MenuDelegate::DropPosition::kBefore:
       item_bounds.Offset(0, -kDropIndicatorHeight / 2);
       item_bounds.set_height(kDropIndicatorHeight);
       return item_bounds;
 
-    case MenuDelegate::DROP_AFTER:
+    case MenuDelegate::DropPosition::kAfter:
       item_bounds.Offset(0, item_bounds.height() - kDropIndicatorHeight / 2);
       item_bounds.set_height(kDropIndicatorHeight);
       return item_bounds;
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index af4e728..c2b79810 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -281,6 +281,7 @@
   cursor_view_.layer()->SetColor(GetTextColor());
   // |cursor_view_| is owned by Textfield view.
   cursor_view_.set_owned_by_client();
+  cursor_view_.GetViewAccessibility().OverrideIsIgnored(true);
   AddChildView(&cursor_view_);
   GetRenderText()->SetFontList(GetDefaultFontList());
   UpdateBorder();
diff --git a/ui/views/drag_utils.h b/ui/views/drag_utils.h
index d8c1be0..1604d9ec 100644
--- a/ui/views/drag_utils.h
+++ b/ui/views/drag_utils.h
@@ -5,6 +5,8 @@
 #ifndef UI_VIEWS_DRAG_UTILS_H_
 #define UI_VIEWS_DRAG_UTILS_H_
 
+#include <memory>
+
 #include "ui/base/dragdrop/drag_drop_types.h"
 #include "ui/base/dragdrop/os_exchange_data.h"
 #include "ui/gfx/native_widget_types.h"
diff --git a/ui/webui/resources/cr_elements/cr_page_host_style_css.html b/ui/webui/resources/cr_elements/cr_page_host_style_css.html
index f3fadca..be8e9c5 100644
--- a/ui/webui/resources/cr_elements/cr_page_host_style_css.html
+++ b/ui/webui/resources/cr_elements/cr_page_host_style_css.html
@@ -12,7 +12,7 @@
   <template>
     <style>
       :host {
-        color: var(--cr-primary-text);
+        color: var(--cr-primary-text-color);
         line-height: 154%; /* Apply 20px default line-height to all text. */
         overflow: hidden; /* Prevent double scroll bar bugs. */
         user-select: text;